@digilogiclabs/platform-core 1.0.0 → 1.1.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/adapters/postgres/PostgresDatabase.ts","../src/adapters/supabase/SupabaseDatabase.ts","../src/adapters/redis/RedisCache.ts","../src/adapters/upstash/UpstashCache.ts","../src/adapters/supabase-storage/SupabaseStorage.ts","../src/adapters/s3/S3Storage.ts","../src/adapters/smtp/SmtpEmail.ts","../src/adapters/resend/ResendEmail.ts","../src/adapters/bullmq/BullMQQueue.ts","../src/adapters/opentelemetry/OpenTelemetryTracing.ts","../src/interfaces/IHealth.ts","../src/interfaces/ILogger.ts","../src/interfaces/IMetrics.ts","../src/interfaces/ISecrets.ts","../src/interfaces/ITracing.ts","../src/config.ts","../src/adapters/memory/MemoryDatabase.ts","../src/adapters/memory/MemoryCache.ts","../src/adapters/memory/MemoryStorage.ts","../src/adapters/memory/MemoryEmail.ts","../src/adapters/memory/MemoryQueue.ts","../src/adapters/console/ConsoleEmail.ts","../src/factory.ts","../src/middleware/chain.ts","../src/middleware/builtin.ts","../src/hooks/registry.ts","../src/resilience/retry.ts","../src/resilience/circuit-breaker.ts","../src/resilience/timeout.ts","../src/resilience/bulkhead.ts","../src/resilience/fallback.ts","../src/http/health.ts","../src/http/metrics.ts","../src/adapters/supabase/index.ts","../src/adapters/postgres/index.ts","../src/adapters/upstash/index.ts","../src/adapters/redis/index.ts","../src/adapters/s3/index.ts","../src/adapters/supabase-storage/index.ts","../src/adapters/resend/index.ts","../src/adapters/smtp/index.ts","../src/adapters/bullmq/index.ts","../src/migrations/Migrator.ts","../src/migrations/helpers.ts"],"sourcesContent":["/**\r\n * PostgreSQL Direct Database Adapter\r\n *\r\n * Production implementation using pg (node-postgres) for direct PostgreSQL connections.\r\n * Provides true ACID transaction support, connection pooling, and prepared statements.\r\n *\r\n * This adapter is vendor-agnostic - works with any PostgreSQL-compatible database:\r\n * - PostgreSQL (self-hosted or managed)\r\n * - Amazon RDS PostgreSQL\r\n * - Azure Database for PostgreSQL\r\n * - Google Cloud SQL for PostgreSQL\r\n * - CockroachDB (PostgreSQL wire protocol)\r\n * - YugabyteDB\r\n * - Neon, Supabase (direct connection, not REST)\r\n */\r\n\r\nimport type { Pool, PoolClient, PoolConfig, QueryResult as PgQueryResult } from 'pg';\r\nimport { IDatabase, IQueryBuilder, QueryResult } from '../../interfaces/IDatabase';\r\n\r\nexport interface PostgresConfig {\r\n /** Connection string (postgresql://user:pass@host:port/database) */\r\n connectionString?: string;\r\n\r\n /** Host name */\r\n host?: string;\r\n\r\n /** Port number */\r\n port?: number;\r\n\r\n /** Database name */\r\n database?: string;\r\n\r\n /** Username */\r\n user?: string;\r\n\r\n /** Password */\r\n password?: string;\r\n\r\n /** SSL configuration */\r\n ssl?: boolean | { rejectUnauthorized?: boolean; ca?: string };\r\n\r\n /** Maximum number of connections in pool */\r\n max?: number;\r\n\r\n /** Idle timeout in milliseconds */\r\n idleTimeoutMillis?: number;\r\n\r\n /** Connection timeout in milliseconds */\r\n connectionTimeoutMillis?: number;\r\n\r\n /** Statement timeout in milliseconds (0 = no limit) */\r\n statementTimeout?: number;\r\n\r\n /** Query timeout in milliseconds (0 = no limit) */\r\n queryTimeout?: number;\r\n\r\n /** Application name for connection identification */\r\n applicationName?: string;\r\n}\r\n\r\n/**\r\n * Convert our config to pg pool config\r\n */\r\nfunction toPoolConfig(config: PostgresConfig): PoolConfig {\r\n const poolConfig: PoolConfig = {};\r\n\r\n if (config.connectionString) {\r\n poolConfig.connectionString = config.connectionString;\r\n } else {\r\n poolConfig.host = config.host;\r\n poolConfig.port = config.port;\r\n poolConfig.database = config.database;\r\n poolConfig.user = config.user;\r\n poolConfig.password = config.password;\r\n }\r\n\r\n if (config.ssl !== undefined) {\r\n poolConfig.ssl = config.ssl;\r\n }\r\n\r\n poolConfig.max = config.max ?? 10;\r\n poolConfig.idleTimeoutMillis = config.idleTimeoutMillis ?? 30000;\r\n poolConfig.connectionTimeoutMillis = config.connectionTimeoutMillis ?? 10000;\r\n poolConfig.application_name = config.applicationName ?? 'platform-core';\r\n\r\n // Statement timeout\r\n if (config.statementTimeout) {\r\n poolConfig.statement_timeout = config.statementTimeout;\r\n }\r\n\r\n // Query timeout\r\n if (config.queryTimeout) {\r\n poolConfig.query_timeout = config.queryTimeout;\r\n }\r\n\r\n return poolConfig;\r\n}\r\n\r\nexport class PostgresDatabase implements IDatabase {\r\n private pool: Pool;\r\n private config: PostgresConfig;\r\n\r\n constructor(pool: Pool, config: PostgresConfig = {}) {\r\n this.pool = pool;\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create a PostgresDatabase from configuration\r\n */\r\n static async create(config: PostgresConfig): Promise<PostgresDatabase> {\r\n // Dynamic import to keep pg as optional peer dependency\r\n const { Pool } = await import('pg');\r\n const poolConfig = toPoolConfig(config);\r\n const pool = new Pool(poolConfig);\r\n\r\n // Test connection\r\n const client = await pool.connect();\r\n client.release();\r\n\r\n return new PostgresDatabase(pool, config);\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<PostgresDatabase> {\r\n const config: PostgresConfig = {\r\n connectionString: process.env.DATABASE_URL,\r\n host: process.env.POSTGRES_HOST ?? process.env.PGHOST,\r\n port: parseInt(process.env.POSTGRES_PORT ?? process.env.PGPORT ?? '5432', 10),\r\n database: process.env.POSTGRES_DATABASE ?? process.env.PGDATABASE,\r\n user: process.env.POSTGRES_USER ?? process.env.PGUSER,\r\n password: process.env.POSTGRES_PASSWORD ?? process.env.PGPASSWORD,\r\n max: parseInt(process.env.POSTGRES_POOL_MAX ?? '10', 10),\r\n ssl:\r\n process.env.POSTGRES_SSL === 'true'\r\n ? { rejectUnauthorized: process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== 'false' }\r\n : undefined,\r\n applicationName: process.env.POSTGRES_APP_NAME ?? 'platform-core',\r\n };\r\n\r\n return PostgresDatabase.create(config);\r\n }\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new PostgresQueryBuilder<T>(this.pool, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n try {\r\n const result: PgQueryResult = await this.pool.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Execute a function within a database transaction.\r\n * Provides true ACID guarantees - either all operations succeed or all are rolled back.\r\n */\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n const client = await this.pool.connect();\r\n\r\n try {\r\n await client.query('BEGIN');\r\n\r\n // Create a transaction-scoped database instance\r\n const txDatabase = new TransactionDatabase(client);\r\n\r\n const result = await fn(txDatabase);\r\n\r\n await client.query('COMMIT');\r\n return result;\r\n } catch (error) {\r\n await client.query('ROLLBACK');\r\n throw error;\r\n } finally {\r\n client.release();\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.pool.query('SELECT 1 as health');\r\n return result.rows.length > 0;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.pool.end();\r\n }\r\n\r\n /**\r\n * Get pool statistics for monitoring\r\n */\r\n getPoolStats(): {\r\n totalCount: number;\r\n idleCount: number;\r\n waitingCount: number;\r\n } {\r\n return {\r\n totalCount: this.pool.totalCount,\r\n idleCount: this.pool.idleCount,\r\n waitingCount: this.pool.waitingCount,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transaction-scoped database that uses a single client connection\r\n */\r\nclass TransactionDatabase implements IDatabase {\r\n constructor(private client: PoolClient) {}\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new PostgresQueryBuilder<T>(this.client, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n try {\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n // Nested transaction using savepoint\r\n const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2)}`;\r\n\r\n try {\r\n await this.client.query(`SAVEPOINT ${savepointName}`);\r\n const result = await fn(this);\r\n await this.client.query(`RELEASE SAVEPOINT ${savepointName}`);\r\n return result;\r\n } catch (error) {\r\n await this.client.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);\r\n throw error;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n await this.client.query('SELECT 1');\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Transaction database doesn't own the client, so don't close\r\n }\r\n}\r\n\r\n/**\r\n * PostgreSQL Query Builder\r\n */\r\nclass PostgresQueryBuilder<T = unknown> implements IQueryBuilder<T> {\r\n private client: Pool | PoolClient;\r\n private tableName: string;\r\n private _select: string[] = ['*'];\r\n private _where: Array<{ column: string; operator: string; value: unknown }> = [];\r\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\r\n private _orderBy: { column: string; direction: 'asc' | 'desc' } | null = null;\r\n private _limit: number | null = null;\r\n private _offset: number = 0;\r\n private _insertData: Partial<T>[] | null = null;\r\n private _updateData: Partial<T> | null = null;\r\n private _deleteFlag: boolean = false;\r\n private _returning: string[] = ['*'];\r\n\r\n constructor(client: Pool | PoolClient, tableName: string) {\r\n this.client = client;\r\n this.tableName = this.escapeIdentifier(tableName);\r\n }\r\n\r\n select(columns?: string | string[]): IQueryBuilder<T> {\r\n if (columns) {\r\n this._select = Array.isArray(columns) ? columns : [columns];\r\n }\r\n return this;\r\n }\r\n\r\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\r\n this._insertData = Array.isArray(data) ? data : [data];\r\n return this;\r\n }\r\n\r\n update(data: Partial<T>): IQueryBuilder<T> {\r\n this._updateData = data;\r\n return this;\r\n }\r\n\r\n delete(): IQueryBuilder<T> {\r\n this._deleteFlag = true;\r\n return this;\r\n }\r\n\r\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\r\n this._where.push({ column, operator, value });\r\n return this;\r\n }\r\n\r\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\r\n this._whereIn.push({ column, values });\r\n return this;\r\n }\r\n\r\n orderBy(column: string, direction: 'asc' | 'desc' = 'asc'): IQueryBuilder<T> {\r\n this._orderBy = { column, direction };\r\n return this;\r\n }\r\n\r\n limit(count: number): IQueryBuilder<T> {\r\n this._limit = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): IQueryBuilder<T> {\r\n this._offset = count;\r\n return this;\r\n }\r\n\r\n async single(): Promise<{ data: T | null; error?: Error }> {\r\n this._limit = 1;\r\n const result = await this.execute();\r\n\r\n if (result.error) {\r\n return { data: null, error: result.error };\r\n }\r\n\r\n return { data: result.data[0] ?? null };\r\n }\r\n\r\n async execute(): Promise<QueryResult<T>> {\r\n try {\r\n if (this._insertData) {\r\n return await this.executeInsert();\r\n }\r\n\r\n if (this._updateData) {\r\n return await this.executeUpdate();\r\n }\r\n\r\n if (this._deleteFlag) {\r\n return await this.executeDelete();\r\n }\r\n\r\n return await this.executeSelect();\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n private async executeSelect(): Promise<QueryResult<T>> {\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SELECT clause\r\n const selectClause = this._select.map((col) => this.escapeIdentifier(col)).join(', ');\r\n let sql = `SELECT ${selectClause} FROM ${this.tableName}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n // Build ORDER BY\r\n if (this._orderBy) {\r\n sql += ` ORDER BY ${this.escapeIdentifier(this._orderBy.column)} ${this._orderBy.direction.toUpperCase()}`;\r\n }\r\n\r\n // Build LIMIT and OFFSET\r\n if (this._limit !== null) {\r\n sql += ` LIMIT $${paramIndex++}`;\r\n params.push(this._limit);\r\n }\r\n\r\n if (this._offset > 0) {\r\n sql += ` OFFSET $${paramIndex++}`;\r\n params.push(this._offset);\r\n }\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeInsert(): Promise<QueryResult<T>> {\r\n if (!this._insertData || this._insertData.length === 0) {\r\n return { data: [] };\r\n }\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Get all unique columns from the data\r\n const columns = new Set<string>();\r\n for (const row of this._insertData) {\r\n Object.keys(row as object).forEach((key) => columns.add(key));\r\n }\r\n const columnList = Array.from(columns);\r\n\r\n // Build column list\r\n const columnClause = columnList.map((col) => this.escapeIdentifier(col)).join(', ');\r\n\r\n // Build values\r\n const valueRows: string[] = [];\r\n for (const row of this._insertData) {\r\n const rowValues: string[] = [];\r\n for (const col of columnList) {\r\n rowValues.push(`$${paramIndex++}`);\r\n params.push((row as Record<string, unknown>)[col] ?? null);\r\n }\r\n valueRows.push(`(${rowValues.join(', ')})`);\r\n }\r\n\r\n const sql = `INSERT INTO ${this.tableName} (${columnClause}) VALUES ${valueRows.join(', ')} RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeUpdate(): Promise<QueryResult<T>> {\r\n if (!this._updateData) {\r\n return { data: [] };\r\n }\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SET clause\r\n const setClauses: string[] = [];\r\n for (const [key, value] of Object.entries(this._updateData as object)) {\r\n setClauses.push(`${this.escapeIdentifier(key)} = $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n let sql = `UPDATE ${this.tableName} SET ${setClauses.join(', ')}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n sql += ` RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeDelete(): Promise<QueryResult<T>> {\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n let sql = `DELETE FROM ${this.tableName}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n sql += ` RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private escapeIdentifier(identifier: string): string {\r\n // Handle special cases\r\n if (identifier === '*') return '*';\r\n\r\n // Handle schema.table notation\r\n if (identifier.includes('.')) {\r\n return identifier\r\n .split('.')\r\n .map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`)\r\n .join('.');\r\n }\r\n\r\n // Escape identifier with double quotes\r\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n\r\n private mapOperator(operator: string): string {\r\n switch (operator.toLowerCase()) {\r\n case '=':\r\n case '==':\r\n return '=';\r\n case '!=':\r\n case '<>':\r\n return '<>';\r\n case '<':\r\n return '<';\r\n case '<=':\r\n return '<=';\r\n case '>':\r\n return '>';\r\n case '>=':\r\n return '>=';\r\n case 'like':\r\n return 'LIKE';\r\n case 'ilike':\r\n return 'ILIKE';\r\n case 'is':\r\n return 'IS';\r\n case 'is not':\r\n return 'IS NOT';\r\n default:\r\n return '=';\r\n }\r\n }\r\n}\r\n","/**\r\n * Supabase Database Adapter\r\n * Production implementation using Supabase as the database provider\r\n */\r\n\r\nimport type { SupabaseClient } from '@supabase/supabase-js';\r\nimport { IDatabase, IQueryBuilder, QueryResult } from '../../interfaces/IDatabase';\r\n\r\nexport interface SupabaseDatabaseConfig {\r\n url: string;\r\n anonKey: string;\r\n serviceRoleKey?: string;\r\n}\r\n\r\nexport class SupabaseDatabase implements IDatabase {\r\n private client: SupabaseClient;\r\n\r\n constructor(client: SupabaseClient) {\r\n this.client = client;\r\n }\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new SupabaseQueryBuilder<T>(this.client, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n // Supabase RPC for raw SQL requires a database function\r\n // This is a limitation - prefer using from() for queries\r\n console.warn('SupabaseDatabase.raw() requires an RPC function. Consider using from() instead.');\r\n return { data: [] };\r\n }\r\n\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n // Supabase REST API doesn't support true transactions\r\n // Operations run sequentially but not atomically\r\n console.warn('Supabase REST API does not support true transactions. Operations are not atomic.');\r\n return fn(this);\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n // Try a simple query to check connectivity\r\n const { error } = await this.client.from('_health_check').select('*').limit(1);\r\n // Table may not exist, but connection worked if no network error\r\n // PGRST116 = table not found, which is OK for health check\r\n return !error || error.code === 'PGRST116';\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Supabase client doesn't need explicit closing\r\n }\r\n}\r\n\r\nclass SupabaseQueryBuilder<T = unknown> implements IQueryBuilder<T> {\r\n private client: SupabaseClient;\r\n private tableName: string;\r\n private _select: string = '*';\r\n private _where: Array<{ column: string; operator: string; value: unknown }> = [];\r\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\r\n private _orderBy: { column: string; direction: 'asc' | 'desc' } | null = null;\r\n private _limit: number | null = null;\r\n private _offset: number = 0;\r\n private _insertData: Partial<T>[] | null = null;\r\n private _updateData: Partial<T> | null = null;\r\n private _deleteFlag: boolean = false;\r\n\r\n constructor(client: SupabaseClient, tableName: string) {\r\n this.client = client;\r\n this.tableName = tableName;\r\n }\r\n\r\n select(columns?: string | string[]): IQueryBuilder<T> {\r\n if (columns) {\r\n this._select = Array.isArray(columns) ? columns.join(', ') : columns;\r\n }\r\n return this;\r\n }\r\n\r\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\r\n this._insertData = Array.isArray(data) ? data : [data];\r\n return this;\r\n }\r\n\r\n update(data: Partial<T>): IQueryBuilder<T> {\r\n this._updateData = data;\r\n return this;\r\n }\r\n\r\n delete(): IQueryBuilder<T> {\r\n this._deleteFlag = true;\r\n return this;\r\n }\r\n\r\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\r\n this._where.push({ column, operator, value });\r\n return this;\r\n }\r\n\r\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\r\n this._whereIn.push({ column, values });\r\n return this;\r\n }\r\n\r\n orderBy(column: string, direction: 'asc' | 'desc' = 'asc'): IQueryBuilder<T> {\r\n this._orderBy = { column, direction };\r\n return this;\r\n }\r\n\r\n limit(count: number): IQueryBuilder<T> {\r\n this._limit = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): IQueryBuilder<T> {\r\n this._offset = count;\r\n return this;\r\n }\r\n\r\n async single(): Promise<{ data: T | null; error?: Error }> {\r\n const query = this.buildSelectQuery().limit(1).single();\r\n const { data, error } = await query;\r\n\r\n if (error && error.code !== 'PGRST116') {\r\n return { data: null, error: new Error(error.message) };\r\n }\r\n\r\n return { data: data as T | null };\r\n }\r\n\r\n async execute(): Promise<QueryResult<T>> {\r\n // Handle insert\r\n if (this._insertData) {\r\n const { data, error } = await this.client\r\n .from(this.tableName)\r\n .insert(this._insertData as Record<string, unknown>[])\r\n .select();\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n return { data: (data || []) as T[] };\r\n }\r\n\r\n // Handle update\r\n if (this._updateData) {\r\n let query = this.client\r\n .from(this.tableName)\r\n .update(this._updateData as Record<string, unknown>);\r\n\r\n query = this.applyFilters(query);\r\n const { data, error } = await query.select();\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n return { data: (data || []) as T[], count: data?.length };\r\n }\r\n\r\n // Handle delete\r\n if (this._deleteFlag) {\r\n let query = this.client.from(this.tableName).delete();\r\n query = this.applyFilters(query);\r\n const { data, error } = await query.select();\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n return { data: (data || []) as T[], count: data?.length };\r\n }\r\n\r\n // Handle select\r\n const query = this.buildSelectQuery();\r\n const { data, error, count } = await query;\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n\r\n return { data: (data || []) as T[], count: count ?? undefined };\r\n }\r\n\r\n private buildSelectQuery() {\r\n let query = this.client.from(this.tableName).select(this._select);\r\n\r\n // Apply where conditions\r\n query = this.applyFilters(query);\r\n\r\n // Apply ordering\r\n if (this._orderBy) {\r\n query = query.order(this._orderBy.column, { ascending: this._orderBy.direction === 'asc' });\r\n }\r\n\r\n // Apply pagination\r\n if (this._limit !== null) {\r\n query = query.limit(this._limit);\r\n }\r\n\r\n if (this._offset > 0) {\r\n query = query.range(this._offset, this._offset + (this._limit || 1000) - 1);\r\n }\r\n\r\n return query;\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private applyFilters(query: any): any {\r\n let result = query;\r\n\r\n // Apply where conditions\r\n for (const { column, operator, value } of this._where) {\r\n result = this.applyOperator(result, column, operator, value);\r\n }\r\n\r\n // Apply whereIn conditions\r\n for (const { column, values } of this._whereIn) {\r\n result = result.in(column, values);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private applyOperator(query: any, column: string, operator: string, value: unknown): any {\r\n switch (operator) {\r\n case '=':\r\n case '==':\r\n return query.eq(column, value);\r\n case '!=':\r\n case '<>':\r\n return query.neq(column, value);\r\n case '<':\r\n return query.lt(column, value);\r\n case '<=':\r\n return query.lte(column, value);\r\n case '>':\r\n return query.gt(column, value);\r\n case '>=':\r\n return query.gte(column, value);\r\n case 'like':\r\n return query.like(column, value as string);\r\n case 'ilike':\r\n return query.ilike(column, value as string);\r\n case 'is':\r\n return query.is(column, value);\r\n case 'is not':\r\n return query.not(column, 'is', value);\r\n default:\r\n return query.eq(column, value);\r\n }\r\n }\r\n}\r\n","/**\r\n * Redis Direct Cache Adapter\r\n *\r\n * Production implementation using ioredis for direct Redis connections.\r\n * Provides lower latency than REST-based solutions, true pub/sub support,\r\n * and full Redis command set.\r\n *\r\n * This adapter is vendor-agnostic - works with any Redis-compatible server:\r\n * - Redis (self-hosted or managed)\r\n * - Amazon ElastiCache for Redis\r\n * - Azure Cache for Redis\r\n * - Google Cloud Memorystore for Redis\r\n * - Redis Enterprise\r\n * - KeyDB\r\n * - DragonflyDB\r\n */\r\n\r\nimport type { Redis as IORedis, RedisOptions as IORedisOptions } from 'ioredis';\r\nimport { ICache } from '../../interfaces/ICache';\r\n\r\nexport interface RedisConfig {\r\n /** Connection URL (redis://user:pass@host:port/db) */\r\n url?: string;\r\n\r\n /** Host name */\r\n host?: string;\r\n\r\n /** Port number */\r\n port?: number;\r\n\r\n /** Password */\r\n password?: string;\r\n\r\n /** Database number (0-15) */\r\n db?: number;\r\n\r\n /** Username (Redis 6+) */\r\n username?: string;\r\n\r\n /** Connection name for identification */\r\n name?: string;\r\n\r\n /** Key prefix for namespacing */\r\n keyPrefix?: string;\r\n\r\n /** Enable TLS */\r\n tls?: boolean | { rejectUnauthorized?: boolean; ca?: string };\r\n\r\n /** Connection timeout in milliseconds */\r\n connectTimeout?: number;\r\n\r\n /** Command timeout in milliseconds */\r\n commandTimeout?: number;\r\n\r\n /** Keep alive timeout */\r\n keepAlive?: number;\r\n\r\n /** Max retries per request */\r\n maxRetriesPerRequest?: number;\r\n\r\n /** Enable auto-reconnect */\r\n autoReconnect?: boolean;\r\n\r\n /** Lazy connect (don't connect until first command) */\r\n lazyConnect?: boolean;\r\n\r\n /** Enable offline queue */\r\n enableOfflineQueue?: boolean;\r\n\r\n /** Sentinel configuration for HA */\r\n sentinel?: {\r\n sentinels: Array<{ host: string; port: number }>;\r\n name: string;\r\n password?: string;\r\n };\r\n\r\n /** Cluster configuration */\r\n cluster?: {\r\n nodes: Array<{ host: string; port: number }>;\r\n options?: {\r\n scaleReads?: 'master' | 'slave' | 'all';\r\n maxRedirections?: number;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Convert our config to ioredis options\r\n */\r\nfunction toIORedisOptions(config: RedisConfig): IORedisOptions | string {\r\n if (config.url) {\r\n return config.url;\r\n }\r\n\r\n const options: IORedisOptions = {};\r\n\r\n if (config.host) options.host = config.host;\r\n if (config.port) options.port = config.port;\r\n if (config.password) options.password = config.password;\r\n if (config.db !== undefined) options.db = config.db;\r\n if (config.username) options.username = config.username;\r\n if (config.name) options.name = config.name;\r\n if (config.keyPrefix) options.keyPrefix = config.keyPrefix;\r\n if (config.connectTimeout) options.connectTimeout = config.connectTimeout;\r\n if (config.commandTimeout) options.commandTimeout = config.commandTimeout;\r\n if (config.keepAlive) options.keepAlive = config.keepAlive;\r\n if (config.maxRetriesPerRequest !== undefined) {\r\n options.maxRetriesPerRequest = config.maxRetriesPerRequest;\r\n }\r\n if (config.lazyConnect) options.lazyConnect = config.lazyConnect;\r\n if (config.enableOfflineQueue !== undefined) {\r\n options.enableOfflineQueue = config.enableOfflineQueue;\r\n }\r\n\r\n // TLS configuration\r\n if (config.tls) {\r\n if (typeof config.tls === 'boolean') {\r\n options.tls = {};\r\n } else {\r\n options.tls = {\r\n rejectUnauthorized: config.tls.rejectUnauthorized,\r\n ca: config.tls.ca ? [config.tls.ca] : undefined,\r\n };\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nexport class RedisCache implements ICache {\r\n private client: IORedis;\r\n private subscriberClient: IORedis | null = null;\r\n private config: RedisConfig;\r\n private subscriptions: Map<string, Set<(message: string) => void>> = new Map();\r\n\r\n constructor(client: IORedis, config: RedisConfig = {}) {\r\n this.client = client;\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create a RedisCache from configuration\r\n */\r\n static async create(config: RedisConfig): Promise<RedisCache> {\r\n // Dynamic import to keep ioredis as optional peer dependency\r\n const { default: Redis } = await import('ioredis');\r\n\r\n let client: IORedis;\r\n\r\n if (config.cluster) {\r\n // Cluster mode\r\n const { Cluster } = await import('ioredis');\r\n client = new Cluster(config.cluster.nodes, {\r\n scaleReads: config.cluster.options?.scaleReads ?? 'master',\r\n maxRedirections: config.cluster.options?.maxRedirections ?? 16,\r\n redisOptions: {\r\n password: config.password,\r\n ...(config.tls ? { tls: typeof config.tls === 'boolean' ? {} : config.tls } : {}),\r\n },\r\n }) as unknown as IORedis;\r\n } else if (config.sentinel) {\r\n // Sentinel mode (HA)\r\n client = new Redis({\r\n sentinels: config.sentinel.sentinels,\r\n name: config.sentinel.name,\r\n password: config.password,\r\n sentinelPassword: config.sentinel.password,\r\n ...(config.tls ? { tls: typeof config.tls === 'boolean' ? {} : config.tls } : {}),\r\n });\r\n } else {\r\n // Standard mode\r\n const options = toIORedisOptions(config);\r\n client = typeof options === 'string' ? new Redis(options) : new Redis(options);\r\n }\r\n\r\n // Wait for connection (unless lazy connect)\r\n if (!config.lazyConnect) {\r\n await new Promise<void>((resolve, reject) => {\r\n if (client.status === 'ready') {\r\n resolve();\r\n } else {\r\n client.once('ready', resolve);\r\n client.once('error', reject);\r\n }\r\n });\r\n }\r\n\r\n return new RedisCache(client, config);\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<RedisCache> {\r\n const config: RedisConfig = {\r\n url: process.env.REDIS_URL,\r\n host: process.env.REDIS_HOST,\r\n port: parseInt(process.env.REDIS_PORT ?? '6379', 10),\r\n password: process.env.REDIS_PASSWORD,\r\n db: process.env.REDIS_DB ? parseInt(process.env.REDIS_DB, 10) : undefined,\r\n keyPrefix: process.env.REDIS_KEY_PREFIX,\r\n tls: process.env.REDIS_TLS === 'true',\r\n };\r\n\r\n return RedisCache.create(config);\r\n }\r\n\r\n async get<T = unknown>(key: string): Promise<T | null> {\r\n const value = await this.client.get(key);\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n try {\r\n return JSON.parse(value) as T;\r\n } catch {\r\n // If not JSON, return as string (cast to T)\r\n return value as unknown as T;\r\n }\r\n }\r\n\r\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\r\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\r\n\r\n if (ttl) {\r\n await this.client.setex(key, ttl, serialized);\r\n } else {\r\n await this.client.set(key, serialized);\r\n }\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n await this.client.del(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n const result = await this.client.exists(key);\r\n return result > 0;\r\n }\r\n\r\n async deletePattern(pattern: string): Promise<number> {\r\n const keys: string[] = [];\r\n let cursor = '0';\r\n\r\n // Use SCAN for safe iteration in production\r\n do {\r\n const result = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\r\n cursor = result[0];\r\n keys.push(...result[1]);\r\n } while (cursor !== '0');\r\n\r\n if (keys.length === 0) {\r\n return 0;\r\n }\r\n\r\n // Delete in batches for efficiency\r\n const batchSize = 1000;\r\n let deleted = 0;\r\n\r\n for (let i = 0; i < keys.length; i += batchSize) {\r\n const batch = keys.slice(i, i + batchSize);\r\n deleted += await this.client.del(...batch);\r\n }\r\n\r\n return deleted;\r\n }\r\n\r\n async mget<T = unknown>(keys: string[]): Promise<(T | null)[]> {\r\n if (keys.length === 0) {\r\n return [];\r\n }\r\n\r\n const values = await this.client.mget(...keys);\r\n\r\n return values.map((value) => {\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n try {\r\n return JSON.parse(value) as T;\r\n } catch {\r\n return value as unknown as T;\r\n }\r\n });\r\n }\r\n\r\n async mset<T = unknown>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void> {\r\n if (entries.length === 0) {\r\n return;\r\n }\r\n\r\n // Group entries by TTL\r\n const noTtl: Array<{ key: string; value: T }> = [];\r\n const withTtl: Array<{ key: string; value: T; ttl: number }> = [];\r\n\r\n for (const entry of entries) {\r\n if (entry.ttl) {\r\n withTtl.push(entry as { key: string; value: T; ttl: number });\r\n } else {\r\n noTtl.push(entry);\r\n }\r\n }\r\n\r\n // Use pipeline for atomicity and performance\r\n const pipeline = this.client.pipeline();\r\n\r\n // MSET for entries without TTL\r\n if (noTtl.length > 0) {\r\n const args: string[] = [];\r\n for (const entry of noTtl) {\r\n args.push(entry.key);\r\n args.push(typeof entry.value === 'string' ? entry.value : JSON.stringify(entry.value));\r\n }\r\n pipeline.mset(...args);\r\n }\r\n\r\n // SETEX for entries with TTL\r\n for (const entry of withTtl) {\r\n const value = typeof entry.value === 'string' ? entry.value : JSON.stringify(entry.value);\r\n pipeline.setex(entry.key, entry.ttl, value);\r\n }\r\n\r\n await pipeline.exec();\r\n }\r\n\r\n async incr(key: string, by: number = 1): Promise<number> {\r\n return await this.client.incrby(key, by);\r\n }\r\n\r\n async publish(channel: string, message: string): Promise<void> {\r\n await this.client.publish(channel, message);\r\n }\r\n\r\n async subscribe(channel: string, callback: (message: string) => void): Promise<() => void> {\r\n // Create a dedicated subscriber client if needed\r\n if (!this.subscriberClient) {\r\n const { default: Redis } = await import('ioredis');\r\n const options = toIORedisOptions(this.config);\r\n this.subscriberClient =\r\n typeof options === 'string' ? new Redis(options) : new Redis(options);\r\n\r\n // Set up message handler\r\n this.subscriberClient.on('message', (ch: string, message: string) => {\r\n const callbacks = this.subscriptions.get(ch);\r\n if (callbacks) {\r\n for (const cb of callbacks) {\r\n try {\r\n cb(message);\r\n } catch (error) {\r\n console.error(`Error in subscription callback for channel ${ch}:`, error);\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Track subscription\r\n if (!this.subscriptions.has(channel)) {\r\n this.subscriptions.set(channel, new Set());\r\n await this.subscriberClient.subscribe(channel);\r\n }\r\n this.subscriptions.get(channel)!.add(callback);\r\n\r\n // Return unsubscribe function\r\n return async () => {\r\n const callbacks = this.subscriptions.get(channel);\r\n if (callbacks) {\r\n callbacks.delete(callback);\r\n if (callbacks.size === 0) {\r\n this.subscriptions.delete(channel);\r\n await this.subscriberClient?.unsubscribe(channel);\r\n }\r\n }\r\n };\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.client.ping();\r\n return result === 'PONG';\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this.subscriberClient) {\r\n await this.subscriberClient.quit();\r\n this.subscriberClient = null;\r\n }\r\n await this.client.quit();\r\n this.subscriptions.clear();\r\n }\r\n\r\n /**\r\n * Get connection info for monitoring\r\n */\r\n getConnectionInfo(): {\r\n status: string;\r\n host?: string;\r\n port?: number;\r\n } {\r\n return {\r\n status: this.client.status,\r\n host: this.config.host,\r\n port: this.config.port,\r\n };\r\n }\r\n\r\n /**\r\n * Execute arbitrary Redis command\r\n */\r\n async command<T = unknown>(command: string, ...args: unknown[]): Promise<T> {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n return await (this.client as any).call(command, ...args);\r\n }\r\n\r\n /**\r\n * Get TTL of a key\r\n */\r\n async ttl(key: string): Promise<number> {\r\n return await this.client.ttl(key);\r\n }\r\n\r\n /**\r\n * Set expiry on an existing key\r\n */\r\n async expire(key: string, seconds: number): Promise<boolean> {\r\n const result = await this.client.expire(key, seconds);\r\n return result === 1;\r\n }\r\n\r\n /**\r\n * Get all keys matching a pattern (use with caution in production)\r\n */\r\n async keys(pattern: string): Promise<string[]> {\r\n const keys: string[] = [];\r\n let cursor = '0';\r\n\r\n do {\r\n const result = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\r\n cursor = result[0];\r\n keys.push(...result[1]);\r\n } while (cursor !== '0');\r\n\r\n return keys;\r\n }\r\n}\r\n","/**\r\n * Upstash Redis Cache Adapter\r\n * Production implementation using Upstash Redis REST API\r\n */\r\n\r\nimport type { Redis } from '@upstash/redis';\r\nimport { ICache } from '../../interfaces/ICache';\r\n\r\nexport interface UpstashCacheConfig {\r\n url: string;\r\n token: string;\r\n}\r\n\r\nexport class UpstashCache implements ICache {\r\n private client: Redis;\r\n\r\n constructor(client: Redis) {\r\n this.client = client;\r\n }\r\n\r\n async get<T = unknown>(key: string): Promise<T | null> {\r\n const value = await this.client.get<T>(key);\r\n return value ?? null;\r\n }\r\n\r\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\r\n if (ttl) {\r\n await this.client.set(key, value, { ex: ttl });\r\n } else {\r\n await this.client.set(key, value);\r\n }\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n await this.client.del(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n const result = await this.client.exists(key);\r\n return result > 0;\r\n }\r\n\r\n async deletePattern(pattern: string): Promise<number> {\r\n // Upstash SCAN + DEL for pattern deletion\r\n const keys: string[] = [];\r\n let cursor: string | number = 0;\r\n\r\n do {\r\n const result: [string | number, string[]] = await this.client.scan(cursor, { match: pattern, count: 100 });\r\n cursor = result[0];\r\n keys.push(...result[1]);\r\n } while (cursor !== 0 && cursor !== '0');\r\n\r\n if (keys.length === 0) {\r\n return 0;\r\n }\r\n\r\n const deleted = await this.client.del(...keys);\r\n return deleted;\r\n }\r\n\r\n async mget<T = unknown>(keys: string[]): Promise<(T | null)[]> {\r\n if (keys.length === 0) {\r\n return [];\r\n }\r\n const results = await this.client.mget<(T | null)[]>(...keys);\r\n return results;\r\n }\r\n\r\n async mset<T = unknown>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void> {\r\n if (entries.length === 0) {\r\n return;\r\n }\r\n\r\n // Use pipeline for better performance\r\n const pipeline = this.client.pipeline();\r\n\r\n for (const entry of entries) {\r\n if (entry.ttl) {\r\n pipeline.set(entry.key, entry.value, { ex: entry.ttl });\r\n } else {\r\n pipeline.set(entry.key, entry.value);\r\n }\r\n }\r\n\r\n await pipeline.exec();\r\n }\r\n\r\n async incr(key: string, by: number = 1): Promise<number> {\r\n return await this.client.incrby(key, by);\r\n }\r\n\r\n async publish(channel: string, message: string): Promise<void> {\r\n await this.client.publish(channel, message);\r\n }\r\n\r\n async subscribe(channel: string, callback: (message: string) => void): Promise<() => void> {\r\n // Upstash REST API doesn't support subscriptions natively\r\n // Would need WebSocket or polling implementation\r\n console.warn(\r\n 'UpstashCache.subscribe() is not supported via REST API. ' +\r\n 'Use a direct Redis connection or implement polling for pub/sub functionality.'\r\n );\r\n return () => {};\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.client.ping();\r\n return result === 'PONG';\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Upstash REST client doesn't need explicit closing\r\n }\r\n}\r\n","/**\r\n * Supabase Storage Adapter\r\n *\r\n * Production implementation using Supabase Storage for file management.\r\n * Provides vendor-agnostic file storage via Supabase's storage buckets.\r\n *\r\n * Features:\r\n * - Simple bucket-based file storage\r\n * - Automatic public URL generation\r\n * - Signed URL support for private files\r\n * - Built-in CDN caching\r\n */\r\n\r\nimport type { SupabaseClient } from '@supabase/supabase-js';\r\nimport { IStorage, StorageFile, UploadOptions } from '../../interfaces/IStorage';\r\n\r\nexport interface SupabaseStorageConfig {\r\n /** Supabase project URL */\r\n url: string;\r\n\r\n /** Supabase API key (anon or service role) */\r\n apiKey: string;\r\n\r\n /** Default bucket name */\r\n bucket: string;\r\n\r\n /** Whether the bucket is public */\r\n publicBucket?: boolean;\r\n\r\n /** Default signed URL expiry in seconds */\r\n signedUrlExpiry?: number;\r\n}\r\n\r\nexport class SupabaseStorage implements IStorage {\r\n private client: SupabaseClient;\r\n private bucket: string;\r\n private publicBucket: boolean;\r\n private signedUrlExpiry: number;\r\n\r\n constructor(client: SupabaseClient, config: { bucket: string; publicBucket?: boolean; signedUrlExpiry?: number }) {\r\n this.client = client;\r\n this.bucket = config.bucket;\r\n this.publicBucket = config.publicBucket ?? false;\r\n this.signedUrlExpiry = config.signedUrlExpiry ?? 3600;\r\n }\r\n\r\n /**\r\n * Create a SupabaseStorage adapter from configuration\r\n */\r\n static async create(config: SupabaseStorageConfig): Promise<SupabaseStorage> {\r\n const { createClient } = await import('@supabase/supabase-js');\r\n const client = createClient(config.url, config.apiKey);\r\n\r\n return new SupabaseStorage(client, {\r\n bucket: config.bucket,\r\n publicBucket: config.publicBucket,\r\n signedUrlExpiry: config.signedUrlExpiry,\r\n });\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<SupabaseStorage> {\r\n const url = process.env.SUPABASE_URL;\r\n const apiKey = process.env.SUPABASE_SERVICE_ROLE_KEY ?? process.env.SUPABASE_ANON_KEY;\r\n const bucket = process.env.SUPABASE_STORAGE_BUCKET ?? 'uploads';\r\n\r\n if (!url || !apiKey) {\r\n throw new Error('SUPABASE_URL and SUPABASE_ANON_KEY are required');\r\n }\r\n\r\n return SupabaseStorage.create({\r\n url,\r\n apiKey,\r\n bucket,\r\n publicBucket: process.env.SUPABASE_STORAGE_PUBLIC === 'true',\r\n signedUrlExpiry: process.env.SUPABASE_SIGNED_URL_EXPIRY\r\n ? parseInt(process.env.SUPABASE_SIGNED_URL_EXPIRY, 10)\r\n : undefined,\r\n });\r\n }\r\n\r\n async upload(key: string, data: Buffer | Blob | ReadableStream, options?: UploadOptions): Promise<{ url: string }> {\r\n // Convert ReadableStream to Buffer if needed\r\n let content: Buffer | Blob;\r\n if (data instanceof ReadableStream) {\r\n const chunks: Uint8Array[] = [];\r\n const reader = data.getReader();\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n chunks.push(value);\r\n }\r\n content = Buffer.concat(chunks);\r\n } else {\r\n content = data;\r\n }\r\n\r\n const { data: uploadData, error } = await this.client.storage.from(this.bucket).upload(key, content, {\r\n contentType: options?.contentType,\r\n upsert: true,\r\n });\r\n\r\n if (error) {\r\n throw new Error(`Failed to upload file: ${error.message}`);\r\n }\r\n\r\n const url = await this.getUrl(key);\r\n return { url };\r\n }\r\n\r\n async download(path: string): Promise<Buffer> {\r\n const { data, error } = await this.client.storage.from(this.bucket).download(path);\r\n\r\n if (error) {\r\n throw new Error(`Failed to download file: ${error.message}`);\r\n }\r\n\r\n // Convert Blob to Buffer\r\n const arrayBuffer = await data.arrayBuffer();\r\n return Buffer.from(arrayBuffer);\r\n }\r\n\r\n async delete(path: string): Promise<void> {\r\n const { error } = await this.client.storage.from(this.bucket).remove([path]);\r\n\r\n if (error) {\r\n throw new Error(`Failed to delete file: ${error.message}`);\r\n }\r\n }\r\n\r\n async deleteMany(paths: string[]): Promise<void> {\r\n const { error } = await this.client.storage.from(this.bucket).remove(paths);\r\n\r\n if (error) {\r\n throw new Error(`Failed to delete files: ${error.message}`);\r\n }\r\n }\r\n\r\n async getMetadata(path: string): Promise<StorageFile | null> {\r\n // Supabase doesn't have a direct getMetadata method, so we need to list and find\r\n const dir = this.getDirectory(path);\r\n const filename = this.getFilename(path);\r\n\r\n const { data, error } = await this.client.storage.from(this.bucket).list(dir, {\r\n limit: 1000,\r\n search: filename,\r\n });\r\n\r\n if (error || !data) {\r\n return null;\r\n }\r\n\r\n const file = data.find((f) => f.name === filename);\r\n if (!file || !file.id) {\r\n return null;\r\n }\r\n\r\n return {\r\n key: path,\r\n size: (file.metadata?.size as number) ?? 0,\r\n contentType: file.metadata?.mimetype as string | undefined,\r\n lastModified: file.updated_at ? new Date(file.updated_at) : undefined,\r\n };\r\n }\r\n\r\n async exists(path: string): Promise<boolean> {\r\n const { data, error } = await this.client.storage.from(this.bucket).list(this.getDirectory(path), {\r\n limit: 1,\r\n search: this.getFilename(path),\r\n });\r\n\r\n if (error) {\r\n return false;\r\n }\r\n\r\n return data.some((file) => file.name === this.getFilename(path));\r\n }\r\n\r\n async list(prefix?: string): Promise<StorageFile[]> {\r\n const folder = prefix ?? '';\r\n const { data, error } = await this.client.storage.from(this.bucket).list(folder, {\r\n limit: 1000,\r\n });\r\n\r\n if (error) {\r\n throw new Error(`Failed to list files: ${error.message}`);\r\n }\r\n\r\n const files: StorageFile[] = [];\r\n\r\n for (const item of data) {\r\n if (item.id) {\r\n // It's a file (folders don't have an id)\r\n const filePath = folder ? `${folder}/${item.name}` : item.name;\r\n files.push({\r\n key: filePath,\r\n size: (item.metadata?.size as number) ?? 0,\r\n contentType: item.metadata?.mimetype as string | undefined,\r\n lastModified: item.updated_at ? new Date(item.updated_at) : undefined,\r\n });\r\n }\r\n }\r\n\r\n return files;\r\n }\r\n\r\n async getSignedUrl(path: string, expiresIn?: number): Promise<string> {\r\n const { data, error } = await this.client.storage\r\n .from(this.bucket)\r\n .createSignedUrl(path, expiresIn ?? this.signedUrlExpiry);\r\n\r\n if (error) {\r\n throw new Error(`Failed to create signed URL: ${error.message}`);\r\n }\r\n\r\n return data.signedUrl;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n // Try to list files (limited to 1) to verify access\r\n const { error } = await this.client.storage.from(this.bucket).list('', { limit: 1 });\r\n return !error;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Get URL for a file (public URL or signed URL based on bucket config)\r\n */\r\n private async getUrl(path: string): Promise<string> {\r\n if (this.publicBucket) {\r\n const { data } = this.client.storage.from(this.bucket).getPublicUrl(path);\r\n return data.publicUrl;\r\n }\r\n\r\n return this.getSignedUrl(path);\r\n }\r\n\r\n /**\r\n * Get directory from path\r\n */\r\n private getDirectory(path: string): string {\r\n const lastSlash = path.lastIndexOf('/');\r\n return lastSlash > 0 ? path.substring(0, lastSlash) : '';\r\n }\r\n\r\n /**\r\n * Get filename from path\r\n */\r\n private getFilename(path: string): string {\r\n const lastSlash = path.lastIndexOf('/');\r\n return lastSlash > 0 ? path.substring(lastSlash + 1) : path;\r\n }\r\n\r\n /**\r\n * Get storage bucket info\r\n */\r\n getBucketInfo(): { bucket: string; publicBucket: boolean } {\r\n return {\r\n bucket: this.bucket,\r\n publicBucket: this.publicBucket,\r\n };\r\n }\r\n\r\n /**\r\n * Copy file to new location\r\n */\r\n async copy(sourcePath: string, destPath: string): Promise<{ key: string; url: string }> {\r\n const { data, error } = await this.client.storage.from(this.bucket).copy(sourcePath, destPath);\r\n\r\n if (error) {\r\n throw new Error(`Failed to copy file: ${error.message}`);\r\n }\r\n\r\n return {\r\n key: destPath,\r\n url: await this.getUrl(destPath),\r\n };\r\n }\r\n\r\n /**\r\n * Move file to new location\r\n */\r\n async move(sourcePath: string, destPath: string): Promise<{ key: string; url: string }> {\r\n const { data, error } = await this.client.storage.from(this.bucket).move(sourcePath, destPath);\r\n\r\n if (error) {\r\n throw new Error(`Failed to move file: ${error.message}`);\r\n }\r\n\r\n return {\r\n key: destPath,\r\n url: await this.getUrl(destPath),\r\n };\r\n }\r\n}\r\n","/**\r\n * S3 Storage Adapter\r\n * Production implementation using AWS S3 (compatible with MinIO, R2, etc.)\r\n */\r\n\r\nimport type { S3Client } from '@aws-sdk/client-s3';\r\nimport type { getSignedUrl as GetSignedUrlFn } from '@aws-sdk/s3-request-presigner';\r\nimport { IStorage, StorageFile, UploadOptions } from '../../interfaces/IStorage';\r\n\r\nexport interface S3StorageConfig {\r\n endpoint?: string;\r\n region: string;\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n bucket: string;\r\n forcePathStyle?: boolean;\r\n publicUrl?: string;\r\n}\r\n\r\nexport class S3Storage implements IStorage {\r\n private client: S3Client;\r\n private bucket: string;\r\n private publicUrl?: string;\r\n private signedUrlFn: typeof GetSignedUrlFn;\r\n\r\n constructor(\r\n client: S3Client,\r\n bucket: string,\r\n getSignedUrlFn: typeof GetSignedUrlFn,\r\n publicUrl?: string\r\n ) {\r\n this.client = client;\r\n this.bucket = bucket;\r\n this.signedUrlFn = getSignedUrlFn;\r\n this.publicUrl = publicUrl;\r\n }\r\n\r\n async upload(\r\n key: string,\r\n data: Buffer | Blob | ReadableStream,\r\n options?: UploadOptions\r\n ): Promise<{ url: string }> {\r\n // Convert Blob to Buffer if needed\r\n let body: Buffer | ReadableStream;\r\n if (data instanceof Blob) {\r\n body = Buffer.from(await data.arrayBuffer());\r\n } else {\r\n body = data;\r\n }\r\n\r\n const { PutObjectCommand: PutCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new PutCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n Body: body as Buffer,\r\n ContentType: options?.contentType,\r\n Metadata: options?.metadata,\r\n ACL: options?.public ? 'public-read' : undefined,\r\n })\r\n );\r\n\r\n // Return the URL\r\n const url = this.publicUrl\r\n ? `${this.publicUrl}/${key}`\r\n : await this.createSignedUrl(key);\r\n\r\n return { url };\r\n }\r\n\r\n async download(key: string): Promise<Buffer> {\r\n const { GetObjectCommand: GetCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const response = await this.client.send(\r\n new GetCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n\r\n const stream = response.Body;\r\n if (!stream) {\r\n throw new Error('Empty response body');\r\n }\r\n\r\n // Convert stream to buffer\r\n const chunks: Uint8Array[] = [];\r\n for await (const chunk of stream as AsyncIterable<Uint8Array>) {\r\n chunks.push(chunk);\r\n }\r\n return Buffer.concat(chunks);\r\n }\r\n\r\n async getSignedUrl(key: string, expiresIn: number = 3600): Promise<string> {\r\n return this.createSignedUrl(key, expiresIn);\r\n }\r\n\r\n private async createSignedUrl(key: string, expiresIn: number = 3600): Promise<string> {\r\n const { GetObjectCommand: GetCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const command = new GetCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n });\r\n\r\n return this.signedUrlFn(this.client, command, { expiresIn });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const { DeleteObjectCommand: DeleteCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new DeleteCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n if (keys.length === 0) {\r\n return;\r\n }\r\n\r\n const { DeleteObjectsCommand: DeleteManyCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new DeleteManyCmd({\r\n Bucket: this.bucket,\r\n Delete: {\r\n Objects: keys.map((key) => ({ Key: key })),\r\n },\r\n })\r\n );\r\n }\r\n\r\n async list(prefix?: string): Promise<StorageFile[]> {\r\n const { ListObjectsV2Command: ListCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const files: StorageFile[] = [];\r\n let continuationToken: string | undefined;\r\n\r\n do {\r\n const response = await this.client.send(\r\n new ListCmd({\r\n Bucket: this.bucket,\r\n Prefix: prefix,\r\n ContinuationToken: continuationToken,\r\n })\r\n );\r\n\r\n if (response.Contents) {\r\n for (const item of response.Contents) {\r\n files.push({\r\n key: item.Key!,\r\n size: item.Size!,\r\n lastModified: item.LastModified,\r\n etag: item.ETag,\r\n });\r\n }\r\n }\r\n\r\n continuationToken = response.NextContinuationToken;\r\n } while (continuationToken);\r\n\r\n return files;\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n try {\r\n const { HeadObjectCommand: HeadCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new HeadCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async getMetadata(key: string): Promise<StorageFile | null> {\r\n try {\r\n const { HeadObjectCommand: HeadCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const response = await this.client.send(\r\n new HeadCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n\r\n return {\r\n key,\r\n size: response.ContentLength!,\r\n contentType: response.ContentType,\r\n lastModified: response.LastModified,\r\n etag: response.ETag,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const { ListObjectsV2Command: ListCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new ListCmd({\r\n Bucket: this.bucket,\r\n MaxKeys: 1,\r\n })\r\n );\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n","/**\r\n * SMTP Email Adapter\r\n *\r\n * Production implementation using nodemailer for direct SMTP connections.\r\n * Provides vendor-agnostic email sending via standard SMTP protocol.\r\n *\r\n * Compatible with any SMTP server:\r\n * - Self-hosted mail servers (Postfix, Sendmail)\r\n * - Gmail SMTP\r\n * - Amazon SES (SMTP interface)\r\n * - SendGrid SMTP\r\n * - Mailgun SMTP\r\n * - Microsoft 365 SMTP\r\n * - Any standard SMTP relay\r\n */\r\n\r\nimport type { Transporter } from 'nodemailer';\r\nimport type SMTPTransport from 'nodemailer/lib/smtp-transport';\r\nimport { IEmail, EmailMessage, EmailResult, EmailAddress } from '../../interfaces/IEmail';\r\n\r\nexport interface SmtpConfig {\r\n /** SMTP host */\r\n host: string;\r\n\r\n /** SMTP port (typically 25, 465, or 587) */\r\n port: number;\r\n\r\n /** Use TLS/SSL */\r\n secure?: boolean;\r\n\r\n /** SMTP username */\r\n username?: string;\r\n\r\n /** SMTP password */\r\n password?: string;\r\n\r\n /** Default from address */\r\n from?: string;\r\n\r\n /** Connection timeout in milliseconds */\r\n connectionTimeout?: number;\r\n\r\n /** Socket timeout in milliseconds */\r\n socketTimeout?: number;\r\n\r\n /** Enable debug logging */\r\n debug?: boolean;\r\n\r\n /** Reject unauthorized certificates */\r\n rejectUnauthorized?: boolean;\r\n}\r\n\r\n/**\r\n * Convert EmailAddress to string format for nodemailer\r\n */\r\nfunction formatAddress(address: EmailAddress | string | undefined): string | undefined {\r\n if (!address) return undefined;\r\n if (typeof address === 'string') return address;\r\n return address.name ? `${address.name} <${address.email}>` : address.email;\r\n}\r\n\r\n/**\r\n * Convert EmailAddress or EmailAddress[] to nodemailer format\r\n */\r\nfunction formatRecipients(addresses: EmailAddress | EmailAddress[]): string | string[] {\r\n if (Array.isArray(addresses)) {\r\n return addresses.map((addr) => formatAddress(addr)!);\r\n }\r\n return formatAddress(addresses)!;\r\n}\r\n\r\nexport class SmtpEmail implements IEmail {\r\n private transporter: Transporter<SMTPTransport.SentMessageInfo> | null = null;\r\n private config: SmtpConfig;\r\n\r\n constructor(config: SmtpConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create an SmtpEmail adapter from configuration\r\n */\r\n static async create(config: SmtpConfig): Promise<SmtpEmail> {\r\n const adapter = new SmtpEmail(config);\r\n await adapter.initialize();\r\n return adapter;\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<SmtpEmail> {\r\n const config: SmtpConfig = {\r\n host: process.env.SMTP_HOST ?? 'localhost',\r\n port: parseInt(process.env.SMTP_PORT ?? '587', 10),\r\n secure: process.env.SMTP_SECURE === 'true',\r\n username: process.env.SMTP_USERNAME ?? process.env.SMTP_USER,\r\n password: process.env.SMTP_PASSWORD ?? process.env.SMTP_PASS,\r\n from: process.env.EMAIL_FROM ?? process.env.SMTP_FROM,\r\n debug: process.env.SMTP_DEBUG === 'true',\r\n };\r\n\r\n return SmtpEmail.create(config);\r\n }\r\n\r\n /**\r\n * Initialize the SMTP transporter\r\n */\r\n private async initialize(): Promise<void> {\r\n const nodemailer = await import('nodemailer');\r\n\r\n const options: SMTPTransport.Options = {\r\n host: this.config.host,\r\n port: this.config.port,\r\n secure: this.config.secure ?? this.config.port === 465,\r\n connectionTimeout: this.config.connectionTimeout ?? 10000,\r\n socketTimeout: this.config.socketTimeout ?? 30000,\r\n debug: this.config.debug,\r\n logger: this.config.debug,\r\n };\r\n\r\n // Authentication\r\n if (this.config.username && this.config.password) {\r\n options.auth = {\r\n user: this.config.username,\r\n pass: this.config.password,\r\n };\r\n }\r\n\r\n // TLS options\r\n if (this.config.rejectUnauthorized !== undefined) {\r\n options.tls = {\r\n rejectUnauthorized: this.config.rejectUnauthorized,\r\n };\r\n }\r\n\r\n this.transporter = nodemailer.createTransport(options);\r\n }\r\n\r\n async send(message: EmailMessage): Promise<EmailResult> {\r\n if (!this.transporter) {\r\n await this.initialize();\r\n }\r\n\r\n try {\r\n const mailOptions = {\r\n from: formatAddress(message.from) ?? this.config.from,\r\n to: formatRecipients(message.to),\r\n subject: message.subject,\r\n text: message.text,\r\n html: message.html,\r\n replyTo: formatAddress(message.replyTo),\r\n attachments: message.attachments?.map((att) => ({\r\n filename: att.filename,\r\n content: att.content,\r\n contentType: att.contentType,\r\n })),\r\n headers: message.headers,\r\n };\r\n\r\n const result = await this.transporter!.sendMail(mailOptions);\r\n\r\n return {\r\n id: result.messageId ?? `smtp_${Date.now()}`,\r\n success: true,\r\n };\r\n } catch (error) {\r\n return {\r\n id: `smtp_error_${Date.now()}`,\r\n success: false,\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\r\n // Send sequentially to avoid overwhelming SMTP server\r\n const results: EmailResult[] = [];\r\n for (const msg of messages) {\r\n const result = await this.send(msg);\r\n results.push(result);\r\n }\r\n return results;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n if (!this.transporter) {\r\n try {\r\n await this.initialize();\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n try {\r\n await this.transporter!.verify();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Close the transporter and release connections\r\n */\r\n async close(): Promise<void> {\r\n if (this.transporter) {\r\n this.transporter.close();\r\n this.transporter = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get transporter info for debugging\r\n */\r\n getTransporterInfo(): { host: string; port: number; secure: boolean } {\r\n return {\r\n host: this.config.host,\r\n port: this.config.port,\r\n secure: this.config.secure ?? false,\r\n };\r\n }\r\n}\r\n","/**\r\n * Resend Email Adapter\r\n * Production implementation using Resend for transactional emails\r\n */\r\n\r\nimport type { Resend } from 'resend';\r\nimport { IEmail, EmailMessage, EmailResult, EmailAddress } from '../../interfaces/IEmail';\r\n\r\nexport interface ResendEmailConfig {\r\n apiKey: string;\r\n defaultFrom?: string;\r\n}\r\n\r\nexport class ResendEmail implements IEmail {\r\n private client: Resend;\r\n private defaultFrom: string;\r\n\r\n constructor(client: Resend, defaultFrom?: string) {\r\n this.client = client;\r\n this.defaultFrom = defaultFrom || 'noreply@example.com';\r\n }\r\n\r\n async send(message: EmailMessage): Promise<EmailResult> {\r\n try {\r\n const to = this.formatAddresses(message.to);\r\n const from = message.from\r\n ? this.formatAddress(message.from)\r\n : this.defaultFrom;\r\n\r\n // Build email options - use type assertion for complex Resend types\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const emailOptions: any = {\r\n from,\r\n to,\r\n subject: message.subject,\r\n };\r\n\r\n if (message.html) emailOptions.html = message.html;\r\n if (message.text) emailOptions.text = message.text;\r\n if (message.replyTo) emailOptions.replyTo = this.formatAddress(message.replyTo);\r\n if (message.headers) emailOptions.headers = message.headers;\r\n if (message.tags) emailOptions.tags = message.tags.map((tag) => ({ name: tag, value: tag }));\r\n if (message.attachments) {\r\n emailOptions.attachments = message.attachments.map((a) => ({\r\n filename: a.filename,\r\n content: typeof a.content === 'string' ? a.content : a.content.toString('base64'),\r\n contentType: a.contentType,\r\n }));\r\n }\r\n\r\n const { data, error } = await this.client.emails.send(emailOptions);\r\n\r\n if (error) {\r\n return {\r\n id: '',\r\n success: false,\r\n error: new Error(error.message),\r\n };\r\n }\r\n\r\n return {\r\n id: data?.id || '',\r\n success: true,\r\n };\r\n } catch (err) {\r\n return {\r\n id: '',\r\n success: false,\r\n error: err instanceof Error ? err : new Error('Unknown error'),\r\n };\r\n }\r\n }\r\n\r\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\r\n // Resend has batch send but we'll use sequential for reliability\r\n const results: EmailResult[] = [];\r\n\r\n for (const message of messages) {\r\n const result = await this.send(message);\r\n results.push(result);\r\n\r\n // Basic rate limiting - 100ms between emails\r\n await new Promise((resolve) => setTimeout(resolve, 100));\r\n }\r\n\r\n return results;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n // Check connectivity by listing domains\r\n const { error } = await this.client.domains.list();\r\n return !error;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n private formatAddress(address: EmailAddress): string {\r\n if (address.name) {\r\n return `${address.name} <${address.email}>`;\r\n }\r\n return address.email;\r\n }\r\n\r\n private formatAddresses(addresses: EmailAddress | EmailAddress[]): string[] {\r\n const list = Array.isArray(addresses) ? addresses : [addresses];\r\n return list.map((addr) => this.formatAddress(addr));\r\n }\r\n}\r\n","/**\r\n * BullMQ Queue Adapter\r\n * Production queue implementation using BullMQ (Redis-backed)\r\n */\r\n\r\nimport type { IQueue, Job, JobOptions } from '../../interfaces/IQueue';\r\n\r\nexport interface BullMQConfig {\r\n /** Redis connection URL */\r\n redisUrl?: string;\r\n /** Redis host */\r\n host?: string;\r\n /** Redis port */\r\n port?: number;\r\n /** Redis password */\r\n password?: string;\r\n /** Redis database number */\r\n db?: number;\r\n /** Queue name */\r\n queueName: string;\r\n /** Default job options */\r\n defaultJobOptions?: JobOptions;\r\n}\r\n\r\n// Internal types to avoid BullMQ's complex generic constraints\r\ninterface BullMQJobInternal {\r\n id?: string;\r\n name: string;\r\n data: unknown;\r\n attemptsMade: number;\r\n progress: number | object;\r\n timestamp: number;\r\n remove(): Promise<void>;\r\n}\r\n\r\ninterface BullMQQueueInternal {\r\n add(name: string, data: unknown, opts?: object): Promise<BullMQJobInternal>;\r\n addBulk(jobs: Array<{ name: string; data: unknown; opts?: object }>): Promise<BullMQJobInternal[]>;\r\n getJob(id: string): Promise<BullMQJobInternal | undefined>;\r\n getWaitingCount(): Promise<number>;\r\n getActiveCount(): Promise<number>;\r\n getCompletedCount(): Promise<number>;\r\n getFailedCount(): Promise<number>;\r\n getDelayedCount(): Promise<number>;\r\n pause(): Promise<void>;\r\n resume(): Promise<void>;\r\n close(): Promise<void>;\r\n}\r\n\r\ninterface BullMQWorkerInternal {\r\n on(event: string, handler: (...args: unknown[]) => void): void;\r\n close(): Promise<void>;\r\n}\r\n\r\n/**\r\n * BullMQ Queue Adapter\r\n * Requires: pnpm add bullmq ioredis\r\n */\r\nexport class BullMQQueue<T = unknown> implements IQueue<T> {\r\n private queue: BullMQQueueInternal | null = null;\r\n private worker: BullMQWorkerInternal | null = null;\r\n private config: BullMQConfig;\r\n private initialized = false;\r\n\r\n constructor(config: BullMQConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Initialize the queue (called lazily on first use)\r\n */\r\n private async ensureInitialized(): Promise<void> {\r\n if (this.initialized) return;\r\n\r\n const { Queue } = await import('bullmq');\r\n\r\n const connection = this.getConnectionConfig();\r\n\r\n this.queue = new Queue(this.config.queueName, {\r\n connection,\r\n defaultJobOptions: this.config.defaultJobOptions ? {\r\n attempts: this.config.defaultJobOptions.attempts,\r\n backoff: this.config.defaultJobOptions.backoff,\r\n delay: this.config.defaultJobOptions.delay,\r\n priority: this.config.defaultJobOptions.priority,\r\n removeOnComplete: this.config.defaultJobOptions.removeOnComplete,\r\n removeOnFail: this.config.defaultJobOptions.removeOnFail,\r\n } : undefined,\r\n }) as unknown as BullMQQueueInternal;\r\n\r\n this.initialized = true;\r\n }\r\n\r\n private getConnectionConfig() {\r\n if (this.config.redisUrl) {\r\n return { url: this.config.redisUrl };\r\n }\r\n return {\r\n host: this.config.host || 'localhost',\r\n port: this.config.port || 6379,\r\n password: this.config.password,\r\n db: this.config.db,\r\n };\r\n }\r\n\r\n async add(name: string, data: T, options?: JobOptions): Promise<Job<T>> {\r\n await this.ensureInitialized();\r\n\r\n const bullmqJob = await this.queue!.add(name, data, {\r\n attempts: options?.attempts,\r\n backoff: options?.backoff,\r\n delay: options?.delay,\r\n priority: options?.priority,\r\n removeOnComplete: options?.removeOnComplete,\r\n removeOnFail: options?.removeOnFail,\r\n });\r\n\r\n return this.mapJob(bullmqJob);\r\n }\r\n\r\n async addBulk(jobs: Array<{ name: string; data: T; options?: JobOptions }>): Promise<Job<T>[]> {\r\n await this.ensureInitialized();\r\n\r\n const bullmqJobs = await this.queue!.addBulk(\r\n jobs.map(job => ({\r\n name: job.name,\r\n data: job.data,\r\n opts: job.options ? {\r\n attempts: job.options.attempts,\r\n backoff: job.options.backoff,\r\n delay: job.options.delay,\r\n priority: job.options.priority,\r\n removeOnComplete: job.options.removeOnComplete,\r\n removeOnFail: job.options.removeOnFail,\r\n } : undefined,\r\n }))\r\n );\r\n\r\n return bullmqJobs.map(job => this.mapJob(job));\r\n }\r\n\r\n process(handler: (job: Job<T>) => Promise<unknown>): void {\r\n // Start worker asynchronously\r\n this.startWorker(handler).catch(err => {\r\n console.error('Failed to start BullMQ worker:', err);\r\n });\r\n }\r\n\r\n private async startWorker(handler: (job: Job<T>) => Promise<unknown>): Promise<void> {\r\n const { Worker } = await import('bullmq');\r\n\r\n const connection = this.getConnectionConfig();\r\n\r\n const worker = new Worker(\r\n this.config.queueName,\r\n async (bullmqJob) => {\r\n const job = this.mapJob(bullmqJob as unknown as BullMQJobInternal);\r\n return handler(job);\r\n },\r\n { connection }\r\n );\r\n\r\n this.worker = worker as unknown as BullMQWorkerInternal;\r\n\r\n worker.on('completed', () => {\r\n // Job completed successfully\r\n });\r\n\r\n worker.on('failed', (job, err) => {\r\n console.error(`Job ${job?.id} failed:`, err);\r\n });\r\n }\r\n\r\n async getJob(id: string): Promise<Job<T> | null> {\r\n await this.ensureInitialized();\r\n\r\n const bullmqJob = await this.queue!.getJob(id);\r\n if (!bullmqJob) return null;\r\n\r\n return this.mapJob(bullmqJob);\r\n }\r\n\r\n async removeJob(id: string): Promise<void> {\r\n await this.ensureInitialized();\r\n\r\n const job = await this.queue!.getJob(id);\r\n if (job) {\r\n await job.remove();\r\n }\r\n }\r\n\r\n async pause(): Promise<void> {\r\n await this.ensureInitialized();\r\n await this.queue!.pause();\r\n }\r\n\r\n async resume(): Promise<void> {\r\n await this.ensureInitialized();\r\n await this.queue!.resume();\r\n }\r\n\r\n async getStats(): Promise<{\r\n waiting: number;\r\n active: number;\r\n completed: number;\r\n failed: number;\r\n delayed: number;\r\n }> {\r\n await this.ensureInitialized();\r\n\r\n const [waiting, active, completed, failed, delayed] = await Promise.all([\r\n this.queue!.getWaitingCount(),\r\n this.queue!.getActiveCount(),\r\n this.queue!.getCompletedCount(),\r\n this.queue!.getFailedCount(),\r\n this.queue!.getDelayedCount(),\r\n ]);\r\n\r\n return { waiting, active, completed, failed, delayed };\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n await this.ensureInitialized();\r\n // Try to get queue stats as a health check\r\n await this.queue!.getWaitingCount();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this.worker) {\r\n await this.worker.close();\r\n this.worker = null;\r\n }\r\n if (this.queue) {\r\n await this.queue.close();\r\n this.queue = null;\r\n }\r\n this.initialized = false;\r\n }\r\n\r\n private mapJob(bullmqJob: BullMQJobInternal): Job<T> {\r\n return {\r\n id: bullmqJob.id || '',\r\n name: bullmqJob.name,\r\n data: bullmqJob.data as T,\r\n attemptsMade: bullmqJob.attemptsMade,\r\n progress: typeof bullmqJob.progress === 'number' ? bullmqJob.progress : 0,\r\n timestamp: bullmqJob.timestamp,\r\n };\r\n }\r\n}\r\n","/**\r\n * OpenTelemetry Tracing Adapter\r\n *\r\n * Production-ready distributed tracing using OpenTelemetry SDK.\r\n * Exports traces to OTLP-compatible backends (Jaeger, Grafana Tempo, etc.)\r\n */\r\n\r\nimport type {\r\n ITracing,\r\n ISpan,\r\n SpanOptions,\r\n SpanContext,\r\n SpanStatus,\r\n SpanKind,\r\n} from '../../interfaces/ITracing';\r\n\r\n// OpenTelemetry types (dynamically imported)\r\ntype OtelSpan = import('@opentelemetry/api').Span;\r\ntype OtelTracer = import('@opentelemetry/api').Tracer;\r\ntype OtelSpanKind = import('@opentelemetry/api').SpanKind;\r\ntype OtelSpanStatusCode = import('@opentelemetry/api').SpanStatusCode;\r\ntype NodeTracerProvider = import('@opentelemetry/sdk-trace-node').NodeTracerProvider;\r\ntype OTLPTraceExporter = import('@opentelemetry/exporter-trace-otlp-http').OTLPTraceExporter;\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CONFIGURATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface OpenTelemetryConfig {\r\n /** Service name for traces */\r\n serviceName: string;\r\n\r\n /** Service version */\r\n serviceVersion?: string;\r\n\r\n /** Environment (dev, staging, production) */\r\n environment?: string;\r\n\r\n /** OTLP endpoint (e.g., http://localhost:4318/v1/traces) */\r\n endpoint?: string;\r\n\r\n /** Exporter type */\r\n exporterType?: 'otlp-http' | 'otlp-grpc' | 'console';\r\n\r\n /** Sampling rate (0.0 to 1.0) */\r\n sampleRate?: number;\r\n\r\n /** Additional resource attributes */\r\n resourceAttributes?: Record<string, string>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// SPAN WRAPPER\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nclass OpenTelemetrySpan implements ISpan {\r\n private _name: string;\r\n private otelSpan: OtelSpan;\r\n private spanContext: SpanContext;\r\n private SpanStatusCode: typeof OtelSpanStatusCode;\r\n\r\n constructor(\r\n name: string,\r\n otelSpan: OtelSpan,\r\n SpanStatusCode: typeof OtelSpanStatusCode\r\n ) {\r\n this._name = name;\r\n this.otelSpan = otelSpan;\r\n this.SpanStatusCode = SpanStatusCode;\r\n\r\n const ctx = otelSpan.spanContext();\r\n this.spanContext = {\r\n traceId: ctx.traceId,\r\n spanId: ctx.spanId,\r\n traceFlags: ctx.traceFlags,\r\n traceState: ctx.traceState?.serialize(),\r\n };\r\n }\r\n\r\n get name(): string {\r\n return this._name;\r\n }\r\n\r\n get context(): SpanContext {\r\n return this.spanContext;\r\n }\r\n\r\n get isRecording(): boolean {\r\n return this.otelSpan.isRecording();\r\n }\r\n\r\n setAttribute(key: string, value: string | number | boolean): this {\r\n this.otelSpan.setAttribute(key, value);\r\n return this;\r\n }\r\n\r\n setAttributes(attributes: Record<string, string | number | boolean>): this {\r\n this.otelSpan.setAttributes(attributes);\r\n return this;\r\n }\r\n\r\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): this {\r\n this.otelSpan.addEvent(name, attributes);\r\n return this;\r\n }\r\n\r\n setStatus(status: SpanStatus): this {\r\n let code: OtelSpanStatusCode;\r\n switch (status.code) {\r\n case 'ok':\r\n code = this.SpanStatusCode.OK;\r\n break;\r\n case 'error':\r\n code = this.SpanStatusCode.ERROR;\r\n break;\r\n default:\r\n code = this.SpanStatusCode.UNSET;\r\n }\r\n this.otelSpan.setStatus({ code, message: status.message });\r\n return this;\r\n }\r\n\r\n recordException(exception: Error, attributes?: Record<string, string | number | boolean>): this {\r\n this.otelSpan.recordException(exception, attributes);\r\n this.setStatus({ code: 'error', message: exception.message });\r\n return this;\r\n }\r\n\r\n updateName(name: string): this {\r\n this._name = name;\r\n this.otelSpan.updateName(name);\r\n return this;\r\n }\r\n\r\n end(endTime?: number): void {\r\n this.otelSpan.end(endTime);\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// OPENTELEMETRY TRACING ADAPTER\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport class OpenTelemetryTracing implements ITracing {\r\n private tracer: OtelTracer;\r\n private provider: NodeTracerProvider;\r\n private currentSpan: OpenTelemetrySpan | undefined;\r\n private api: typeof import('@opentelemetry/api');\r\n private SpanStatusCode: typeof OtelSpanStatusCode;\r\n private OtelSpanKind: typeof OtelSpanKind;\r\n\r\n private constructor(\r\n tracer: OtelTracer,\r\n provider: NodeTracerProvider,\r\n api: typeof import('@opentelemetry/api'),\r\n SpanStatusCode: typeof OtelSpanStatusCode,\r\n OtelSpanKind: typeof OtelSpanKind\r\n ) {\r\n this.tracer = tracer;\r\n this.provider = provider;\r\n this.api = api;\r\n this.SpanStatusCode = SpanStatusCode;\r\n this.OtelSpanKind = OtelSpanKind;\r\n }\r\n\r\n /**\r\n * Create an OpenTelemetry tracing instance\r\n */\r\n static async create(config: OpenTelemetryConfig): Promise<OpenTelemetryTracing> {\r\n // Dynamic imports for optional dependencies\r\n const api = await import('@opentelemetry/api');\r\n const { NodeTracerProvider } = await import('@opentelemetry/sdk-trace-node');\r\n const { Resource } = await import('@opentelemetry/resources');\r\n const { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION, ATTR_DEPLOYMENT_ENVIRONMENT_NAME } = await import(\r\n '@opentelemetry/semantic-conventions'\r\n );\r\n const { BatchSpanProcessor, ConsoleSpanExporter } = await import('@opentelemetry/sdk-trace-base');\r\n\r\n // Build resource attributes\r\n const resourceAttributes: Record<string, string> = {\r\n [ATTR_SERVICE_NAME]: config.serviceName,\r\n ...config.resourceAttributes,\r\n };\r\n\r\n if (config.serviceVersion) {\r\n resourceAttributes[ATTR_SERVICE_VERSION] = config.serviceVersion;\r\n }\r\n\r\n if (config.environment) {\r\n resourceAttributes[ATTR_DEPLOYMENT_ENVIRONMENT_NAME] = config.environment;\r\n }\r\n\r\n // Create provider with resource\r\n const provider = new NodeTracerProvider({\r\n resource: new Resource(resourceAttributes),\r\n });\r\n\r\n // Create exporter based on configuration\r\n let exporter;\r\n switch (config.exporterType) {\r\n case 'otlp-grpc': {\r\n const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-grpc');\r\n exporter = new OTLPTraceExporter({\r\n url: config.endpoint,\r\n });\r\n break;\r\n }\r\n case 'console':\r\n exporter = new ConsoleSpanExporter();\r\n break;\r\n case 'otlp-http':\r\n default: {\r\n const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http');\r\n exporter = new OTLPTraceExporter({\r\n url: config.endpoint || 'http://localhost:4318/v1/traces',\r\n });\r\n break;\r\n }\r\n }\r\n\r\n // Add batch processor\r\n provider.addSpanProcessor(new BatchSpanProcessor(exporter));\r\n\r\n // Register provider\r\n provider.register();\r\n\r\n // Get tracer\r\n const tracer = api.trace.getTracer(config.serviceName, config.serviceVersion);\r\n\r\n return new OpenTelemetryTracing(\r\n tracer,\r\n provider,\r\n api,\r\n api.SpanStatusCode,\r\n api.SpanKind\r\n );\r\n }\r\n\r\n private mapSpanKind(kind?: SpanKind): OtelSpanKind {\r\n switch (kind) {\r\n case 'server':\r\n return this.OtelSpanKind.SERVER;\r\n case 'client':\r\n return this.OtelSpanKind.CLIENT;\r\n case 'producer':\r\n return this.OtelSpanKind.PRODUCER;\r\n case 'consumer':\r\n return this.OtelSpanKind.CONSUMER;\r\n case 'internal':\r\n default:\r\n return this.OtelSpanKind.INTERNAL;\r\n }\r\n }\r\n\r\n startSpan(name: string, options?: SpanOptions): ISpan {\r\n const otelSpan = this.tracer.startSpan(name, {\r\n kind: this.mapSpanKind(options?.kind),\r\n attributes: options?.attributes,\r\n startTime: options?.startTime,\r\n });\r\n\r\n const span = new OpenTelemetrySpan(name, otelSpan, this.SpanStatusCode);\r\n this.currentSpan = span;\r\n\r\n return span;\r\n }\r\n\r\n getCurrentSpan(): ISpan | undefined {\r\n const activeSpan = this.api.trace.getActiveSpan();\r\n if (activeSpan) {\r\n return new OpenTelemetrySpan('', activeSpan, this.SpanStatusCode);\r\n }\r\n return this.currentSpan;\r\n }\r\n\r\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T {\r\n const span = this.startSpan(name, options);\r\n const otelSpan = this.tracer.startSpan(name, {\r\n kind: this.mapSpanKind(options?.kind),\r\n attributes: options?.attributes,\r\n });\r\n\r\n return this.api.context.with(this.api.trace.setSpan(this.api.context.active(), otelSpan), () => {\r\n try {\r\n const result = fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n otelSpan.end();\r\n }\r\n });\r\n }\r\n\r\n async withSpanAsync<T>(name: string, fn: (span: ISpan) => Promise<T>, options?: SpanOptions): Promise<T> {\r\n const span = this.startSpan(name, options);\r\n const otelSpan = this.tracer.startSpan(name, {\r\n kind: this.mapSpanKind(options?.kind),\r\n attributes: options?.attributes,\r\n });\r\n\r\n return this.api.context.with(this.api.trace.setSpan(this.api.context.active(), otelSpan), async () => {\r\n try {\r\n const result = await fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n otelSpan.end();\r\n }\r\n });\r\n }\r\n\r\n instrument<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => TReturn,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => TReturn {\r\n return (...args: TArgs) => this.withSpan(name, () => fn(...args), options);\r\n }\r\n\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => Promise<TReturn> {\r\n return (...args: TArgs) => this.withSpanAsync(name, () => fn(...args), options);\r\n }\r\n\r\n extractContext(headers: Record<string, string | string[] | undefined>): SpanContext | undefined {\r\n // Use W3C Trace Context propagation\r\n const traceparent = headers['traceparent'];\r\n if (!traceparent || typeof traceparent !== 'string') return undefined;\r\n\r\n // Parse W3C Trace Context format: version-traceId-spanId-flags\r\n const parts = traceparent.split('-');\r\n if (parts.length !== 4 || parts[0] !== '00') return undefined;\r\n\r\n const traceId = parts[1];\r\n const spanId = parts[2];\r\n const traceFlags = parseInt(parts[3]!, 16);\r\n\r\n if (!traceId || traceId.length !== 32 || !spanId || spanId.length !== 16) {\r\n return undefined;\r\n }\r\n\r\n return {\r\n traceId,\r\n spanId,\r\n traceFlags,\r\n traceState: headers['tracestate'] as string | undefined,\r\n };\r\n }\r\n\r\n injectContext(headers: Record<string, string>): void {\r\n const activeSpan = this.api.trace.getActiveSpan();\r\n if (activeSpan) {\r\n const ctx = activeSpan.spanContext();\r\n headers['traceparent'] = `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, '0')}`;\r\n if (ctx.traceState) {\r\n headers['tracestate'] = ctx.traceState.serialize();\r\n }\r\n } else if (this.currentSpan) {\r\n const ctx = this.currentSpan.context;\r\n headers['traceparent'] = `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, '0')}`;\r\n if (ctx.traceState) {\r\n headers['tracestate'] = ctx.traceState;\r\n }\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n // OpenTelemetry is considered healthy if the provider is registered\r\n return true;\r\n }\r\n\r\n async flush(): Promise<void> {\r\n await this.provider.forceFlush();\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.provider.shutdown();\r\n }\r\n}\r\n","/**\r\n * Health Check Interface\r\n * Standardizes health check behavior across all adapters\r\n */\r\n\r\n/**\r\n * Result of a single health check\r\n */\r\nexport interface HealthCheckResult {\r\n /** Overall health status */\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n /** Time taken to perform the check in milliseconds */\r\n latencyMs: number;\r\n /** When the check was performed */\r\n timestamp: Date;\r\n /** Optional message with details */\r\n message?: string;\r\n /** Additional details about the health check */\r\n details?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Aggregated health result for the entire platform\r\n */\r\nexport interface PlatformHealthResult {\r\n /** Overall platform status */\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n /** When the check was performed */\r\n timestamp: Date;\r\n /** Individual service health results */\r\n services: {\r\n database: HealthCheckResult;\r\n cache: HealthCheckResult;\r\n storage: HealthCheckResult;\r\n email: HealthCheckResult;\r\n queue: HealthCheckResult;\r\n };\r\n /** Summary counts */\r\n summary: {\r\n total: number;\r\n healthy: number;\r\n degraded: number;\r\n unhealthy: number;\r\n };\r\n}\r\n\r\n/**\r\n * Interface for services that support health checks\r\n */\r\nexport interface IHealth {\r\n /**\r\n * Perform a health check on the service\r\n * @returns Promise resolving to health check result\r\n */\r\n healthCheck(): Promise<HealthCheckResult>;\r\n}\r\n\r\n/**\r\n * Interface for services that support simple boolean health checks\r\n * (Legacy support - prefer IHealth for new implementations)\r\n */\r\nexport interface IHealthCheckable {\r\n /**\r\n * Simple health check returning boolean\r\n * @returns Promise resolving to true if healthy\r\n */\r\n healthCheck(): Promise<boolean>;\r\n}\r\n\r\n/**\r\n * Helper to convert boolean health check to HealthCheckResult\r\n */\r\nexport function toHealthCheckResult(\r\n healthy: boolean,\r\n latencyMs: number,\r\n message?: string\r\n): HealthCheckResult {\r\n return {\r\n status: healthy ? 'healthy' : 'unhealthy',\r\n latencyMs,\r\n timestamp: new Date(),\r\n message,\r\n };\r\n}\r\n\r\n/**\r\n * Helper to perform a timed health check\r\n */\r\nexport async function timedHealthCheck<T>(\r\n fn: () => Promise<T>,\r\n successCheck: (result: T) => boolean = () => true\r\n): Promise<HealthCheckResult> {\r\n const start = Date.now();\r\n try {\r\n const result = await fn();\r\n const healthy = successCheck(result);\r\n return {\r\n status: healthy ? 'healthy' : 'degraded',\r\n latencyMs: Date.now() - start,\r\n timestamp: new Date(),\r\n };\r\n } catch (error) {\r\n return {\r\n status: 'unhealthy',\r\n latencyMs: Date.now() - start,\r\n timestamp: new Date(),\r\n message: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n}\r\n","/**\r\n * Logger Interface\r\n * Standardizes logging across the platform\r\n */\r\n\r\n/**\r\n * Log levels in order of severity\r\n */\r\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\r\n\r\n/**\r\n * Metadata that can be attached to log entries\r\n */\r\nexport interface LogMeta {\r\n /** Error object if logging an error */\r\n error?: Error;\r\n /** Duration in milliseconds (for timing operations) */\r\n duration?: number;\r\n /** Request ID for tracing */\r\n requestId?: string;\r\n /** User ID if applicable */\r\n userId?: string;\r\n /** Any additional key-value pairs */\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * A structured log entry\r\n */\r\nexport interface LogEntry {\r\n /** Log level */\r\n level: LogLevel;\r\n /** Log message */\r\n message: string;\r\n /** When the log was created */\r\n timestamp: Date;\r\n /** Optional metadata */\r\n meta?: LogMeta;\r\n /** Logger context (e.g., service name) */\r\n context?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Logger interface for structured logging\r\n */\r\nexport interface ILogger {\r\n /**\r\n * Log a debug message (for development/troubleshooting)\r\n */\r\n debug(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Log an informational message\r\n */\r\n info(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Log a warning message\r\n */\r\n warn(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Log an error message\r\n */\r\n error(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Create a child logger with additional context\r\n * @param context Additional context to include in all logs from this child\r\n */\r\n child(context: Record<string, unknown>): ILogger;\r\n}\r\n\r\n/**\r\n * Configuration options for loggers\r\n */\r\nexport interface LoggerConfig {\r\n /** Minimum level to log */\r\n level?: LogLevel;\r\n /** Whether to pretty print (for development) */\r\n pretty?: boolean;\r\n /** Service name to include in logs */\r\n service?: string;\r\n /** Environment name */\r\n environment?: string;\r\n}\r\n\r\n/**\r\n * Console logger implementation (for development)\r\n */\r\nexport class ConsoleLogger implements ILogger {\r\n private context: Record<string, unknown>;\r\n private level: LogLevel;\r\n\r\n private static levelPriority: Record<LogLevel, number> = {\r\n debug: 0,\r\n info: 1,\r\n warn: 2,\r\n error: 3,\r\n };\r\n\r\n constructor(config: LoggerConfig = {}) {\r\n this.context = {\r\n service: config.service,\r\n environment: config.environment,\r\n };\r\n this.level = config.level || 'info';\r\n }\r\n\r\n private shouldLog(level: LogLevel): boolean {\r\n return ConsoleLogger.levelPriority[level] >= ConsoleLogger.levelPriority[this.level];\r\n }\r\n\r\n private log(level: LogLevel, message: string, meta?: LogMeta): void {\r\n if (!this.shouldLog(level)) return;\r\n\r\n const entry: LogEntry = {\r\n level,\r\n message,\r\n timestamp: new Date(),\r\n meta,\r\n context: this.context,\r\n };\r\n\r\n const prefix = `[${entry.timestamp.toISOString()}] [${level.toUpperCase()}]`;\r\n const contextStr = Object.keys(this.context).length > 0\r\n ? ` [${Object.entries(this.context).map(([k, v]) => `${k}=${v}`).join(' ')}]`\r\n : '';\r\n\r\n switch (level) {\r\n case 'debug':\r\n console.debug(`${prefix}${contextStr} ${message}`, meta || '');\r\n break;\r\n case 'info':\r\n console.info(`${prefix}${contextStr} ${message}`, meta || '');\r\n break;\r\n case 'warn':\r\n console.warn(`${prefix}${contextStr} ${message}`, meta || '');\r\n break;\r\n case 'error':\r\n console.error(`${prefix}${contextStr} ${message}`, meta || '');\r\n if (meta?.error) {\r\n console.error(meta.error);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n debug(message: string, meta?: LogMeta): void {\r\n this.log('debug', message, meta);\r\n }\r\n\r\n info(message: string, meta?: LogMeta): void {\r\n this.log('info', message, meta);\r\n }\r\n\r\n warn(message: string, meta?: LogMeta): void {\r\n this.log('warn', message, meta);\r\n }\r\n\r\n error(message: string, meta?: LogMeta): void {\r\n this.log('error', message, meta);\r\n }\r\n\r\n child(context: Record<string, unknown>): ILogger {\r\n const childLogger = new ConsoleLogger({ level: this.level });\r\n childLogger.context = { ...this.context, ...context };\r\n return childLogger;\r\n }\r\n}\r\n\r\n/**\r\n * No-op logger for testing or when logging is disabled\r\n */\r\nexport class NoopLogger implements ILogger {\r\n debug(): void {}\r\n info(): void {}\r\n warn(): void {}\r\n error(): void {}\r\n child(): ILogger {\r\n return this;\r\n }\r\n}\r\n","/**\r\n * Metrics Interface\r\n *\r\n * Provides observability through counters, gauges, histograms, and timers.\r\n */\r\n\r\n/**\r\n * Tags for metrics (key-value pairs for dimensions)\r\n */\r\nexport type MetricTags = Record<string, string | number | boolean>;\r\n\r\n/**\r\n * Metrics interface for observability\r\n */\r\nexport interface IMetrics {\r\n /**\r\n * Increment a counter by a value (default 1)\r\n *\r\n * @example\r\n * metrics.increment('api.requests', 1, { method: 'GET', path: '/users' })\r\n */\r\n increment(name: string, value?: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Decrement a counter by a value (default 1)\r\n *\r\n * @example\r\n * metrics.decrement('active.connections', 1, { server: 'api-1' })\r\n */\r\n decrement(name: string, value?: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Set a gauge to a specific value\r\n *\r\n * @example\r\n * metrics.gauge('queue.size', 42, { queue: 'emails' })\r\n */\r\n gauge(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Record a value in a histogram (for distributions)\r\n *\r\n * @example\r\n * metrics.histogram('response.size', 1024, { endpoint: '/api/users' })\r\n */\r\n histogram(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Record a timing value in milliseconds\r\n *\r\n * @example\r\n * metrics.timing('db.query.duration', 42, { table: 'users' })\r\n */\r\n timing(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Start a timer and return a function to stop it\r\n *\r\n * @example\r\n * const stop = metrics.startTimer('api.request.duration', { method: 'GET' })\r\n * // ... do work ...\r\n * stop() // Records the duration\r\n */\r\n startTimer(name: string, tags?: MetricTags): () => void;\r\n\r\n /**\r\n * Record a distribution value (similar to histogram but for Datadog)\r\n *\r\n * @example\r\n * metrics.distribution('payment.amount', 99.99, { currency: 'USD' })\r\n */\r\n distribution?(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Record a set value (count unique elements)\r\n *\r\n * @example\r\n * metrics.set('unique.users', 'user-123')\r\n */\r\n set?(name: string, value: string | number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Flush all pending metrics to the backend\r\n */\r\n flush(): Promise<void>;\r\n\r\n /**\r\n * Close the metrics client\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n/**\r\n * Memory-based metrics implementation for testing\r\n */\r\nexport class MemoryMetrics implements IMetrics {\r\n private counters: Map<string, { value: number; tags: MetricTags }[]> = new Map();\r\n private gauges: Map<string, { value: number; tags: MetricTags; timestamp: number }> = new Map();\r\n private histograms: Map<string, { values: number[]; tags: MetricTags }[]> = new Map();\r\n private timings: Map<string, { values: number[]; tags: MetricTags }[]> = new Map();\r\n private sets: Map<string, Set<string | number>> = new Map();\r\n\r\n increment(name: string, value = 1, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n const existing = this.counters.get(key);\r\n\r\n if (existing && existing[0]) {\r\n existing[0].value += value;\r\n } else {\r\n this.counters.set(key, [{ value, tags }]);\r\n }\r\n }\r\n\r\n decrement(name: string, value = 1, tags: MetricTags = {}): void {\r\n this.increment(name, -value, tags);\r\n }\r\n\r\n gauge(name: string, value: number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n this.gauges.set(key, { value, tags, timestamp: Date.now() });\r\n }\r\n\r\n histogram(name: string, value: number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n const existing = this.histograms.get(key);\r\n\r\n if (existing && existing[0]) {\r\n existing[0].values.push(value);\r\n } else {\r\n this.histograms.set(key, [{ values: [value], tags }]);\r\n }\r\n }\r\n\r\n timing(name: string, value: number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n const existing = this.timings.get(key);\r\n\r\n if (existing && existing[0]) {\r\n existing[0].values.push(value);\r\n } else {\r\n this.timings.set(key, [{ values: [value], tags }]);\r\n }\r\n }\r\n\r\n startTimer(name: string, tags: MetricTags = {}): () => void {\r\n const start = Date.now();\r\n return () => {\r\n const duration = Date.now() - start;\r\n this.timing(name, duration, tags);\r\n };\r\n }\r\n\r\n distribution(name: string, value: number, tags: MetricTags = {}): void {\r\n this.histogram(name, value, tags);\r\n }\r\n\r\n set(name: string, value: string | number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n let existing = this.sets.get(key);\r\n\r\n if (!existing) {\r\n existing = new Set();\r\n this.sets.set(key, existing);\r\n }\r\n\r\n existing.add(value);\r\n }\r\n\r\n async flush(): Promise<void> {\r\n // No-op for memory implementation\r\n }\r\n\r\n async close(): Promise<void> {\r\n // No-op for memory implementation\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // Test helpers\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Get counter value\r\n */\r\n getCounter(name: string, tags: MetricTags = {}): number {\r\n const key = this.createKey(name, tags);\r\n const data = this.counters.get(key);\r\n return data?.[0]?.value ?? 0;\r\n }\r\n\r\n /**\r\n * Get gauge value\r\n */\r\n getGauge(name: string, tags: MetricTags = {}): number | undefined {\r\n const key = this.createKey(name, tags);\r\n return this.gauges.get(key)?.value;\r\n }\r\n\r\n /**\r\n * Get histogram values\r\n */\r\n getHistogram(name: string, tags: MetricTags = {}): number[] {\r\n const key = this.createKey(name, tags);\r\n return this.histograms.get(key)?.[0]?.values ?? [];\r\n }\r\n\r\n /**\r\n * Get timing values\r\n */\r\n getTiming(name: string, tags: MetricTags = {}): number[] {\r\n const key = this.createKey(name, tags);\r\n return this.timings.get(key)?.[0]?.values ?? [];\r\n }\r\n\r\n /**\r\n * Get set size\r\n */\r\n getSetSize(name: string, tags: MetricTags = {}): number {\r\n const key = this.createKey(name, tags);\r\n return this.sets.get(key)?.size ?? 0;\r\n }\r\n\r\n /**\r\n * Get all metrics as a summary\r\n */\r\n getSummary(): MetricsSummary {\r\n const summary: MetricsSummary = {\r\n counters: {},\r\n gauges: {},\r\n histograms: {},\r\n timings: {},\r\n sets: {},\r\n };\r\n\r\n for (const [key, data] of this.counters) {\r\n const first = data[0];\r\n if (first) {\r\n summary.counters[key] = first.value;\r\n }\r\n }\r\n\r\n for (const [key, data] of this.gauges) {\r\n summary.gauges[key] = data.value;\r\n }\r\n\r\n for (const [key, data] of this.histograms) {\r\n const first = data[0];\r\n if (first) {\r\n const values = first.values;\r\n summary.histograms[key] = {\r\n count: values.length,\r\n sum: values.reduce((a, b) => a + b, 0),\r\n min: Math.min(...values),\r\n max: Math.max(...values),\r\n avg: values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0,\r\n };\r\n }\r\n }\r\n\r\n for (const [key, data] of this.timings) {\r\n const first = data[0];\r\n if (first) {\r\n const values = first.values;\r\n summary.timings[key] = {\r\n count: values.length,\r\n sum: values.reduce((a, b) => a + b, 0),\r\n min: Math.min(...values),\r\n max: Math.max(...values),\r\n avg: values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0,\r\n p50: this.percentile(values, 50),\r\n p95: this.percentile(values, 95),\r\n p99: this.percentile(values, 99),\r\n };\r\n }\r\n }\r\n\r\n for (const [key, data] of this.sets) {\r\n summary.sets[key] = data.size;\r\n }\r\n\r\n return summary;\r\n }\r\n\r\n /**\r\n * Reset all metrics\r\n */\r\n reset(): void {\r\n this.counters.clear();\r\n this.gauges.clear();\r\n this.histograms.clear();\r\n this.timings.clear();\r\n this.sets.clear();\r\n }\r\n\r\n private createKey(name: string, tags: MetricTags): string {\r\n const tagStr = Object.entries(tags)\r\n .sort(([a], [b]) => a.localeCompare(b))\r\n .map(([k, v]) => `${k}:${v}`)\r\n .join(',');\r\n return tagStr ? `${name}|${tagStr}` : name;\r\n }\r\n\r\n private percentile(values: number[], p: number): number {\r\n if (values.length === 0) return 0;\r\n\r\n const sorted = [...values].sort((a, b) => a - b);\r\n const index = Math.ceil((p / 100) * sorted.length) - 1;\r\n const safeIndex = Math.max(0, index);\r\n return sorted[safeIndex] ?? 0;\r\n }\r\n}\r\n\r\n/**\r\n * No-op metrics implementation\r\n */\r\nexport class NoopMetrics implements IMetrics {\r\n increment(): void {}\r\n decrement(): void {}\r\n gauge(): void {}\r\n histogram(): void {}\r\n timing(): void {}\r\n startTimer(): () => void {\r\n return () => {};\r\n }\r\n distribution(): void {}\r\n set(): void {}\r\n async flush(): Promise<void> {}\r\n async close(): Promise<void> {}\r\n}\r\n\r\n/**\r\n * Summary of all metrics\r\n */\r\nexport interface MetricsSummary {\r\n counters: Record<string, number>;\r\n gauges: Record<string, number>;\r\n histograms: Record<string, HistogramStats>;\r\n timings: Record<string, TimingStats>;\r\n sets: Record<string, number>;\r\n}\r\n\r\n/**\r\n * Histogram statistics\r\n */\r\nexport interface HistogramStats {\r\n count: number;\r\n sum: number;\r\n min: number;\r\n max: number;\r\n avg: number;\r\n}\r\n\r\n/**\r\n * Timing statistics\r\n */\r\nexport interface TimingStats extends HistogramStats {\r\n p50: number;\r\n p95: number;\r\n p99: number;\r\n}\r\n\r\n/**\r\n * Create a scoped metrics instance with a prefix\r\n */\r\nexport function createScopedMetrics(\r\n metrics: IMetrics,\r\n prefix: string,\r\n defaultTags: MetricTags = {}\r\n): IMetrics {\r\n const prefixedName = (name: string) => `${prefix}.${name}`;\r\n const mergedTags = (tags?: MetricTags) => ({ ...defaultTags, ...tags });\r\n\r\n return {\r\n increment(name, value, tags) {\r\n metrics.increment(prefixedName(name), value, mergedTags(tags));\r\n },\r\n decrement(name, value, tags) {\r\n metrics.decrement(prefixedName(name), value, mergedTags(tags));\r\n },\r\n gauge(name, value, tags) {\r\n metrics.gauge(prefixedName(name), value, mergedTags(tags));\r\n },\r\n histogram(name, value, tags) {\r\n metrics.histogram(prefixedName(name), value, mergedTags(tags));\r\n },\r\n timing(name, value, tags) {\r\n metrics.timing(prefixedName(name), value, mergedTags(tags));\r\n },\r\n startTimer(name, tags) {\r\n return metrics.startTimer(prefixedName(name), mergedTags(tags));\r\n },\r\n distribution(name, value, tags) {\r\n metrics.distribution?.(prefixedName(name), value, mergedTags(tags));\r\n },\r\n set(name, value, tags) {\r\n metrics.set?.(prefixedName(name), value, mergedTags(tags));\r\n },\r\n flush: () => metrics.flush(),\r\n close: () => metrics.close(),\r\n };\r\n}\r\n","/**\r\n * Secrets Management Interface\r\n *\r\n * Provides a vendor-agnostic abstraction for secrets management.\r\n * Supports various backends: Environment variables, HashiCorp Vault,\r\n * AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, etc.\r\n */\r\n\r\n/**\r\n * Secret metadata\r\n */\r\nexport interface SecretMetadata {\r\n /** Secret version or ETag */\r\n version?: string;\r\n\r\n /** Creation timestamp */\r\n createdAt?: Date;\r\n\r\n /** Last updated timestamp */\r\n updatedAt?: Date;\r\n\r\n /** Expiration timestamp */\r\n expiresAt?: Date;\r\n\r\n /** Custom tags/labels */\r\n tags?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Secret with metadata\r\n */\r\nexport interface Secret<T = string> {\r\n /** Secret key/name */\r\n key: string;\r\n\r\n /** Secret value */\r\n value: T;\r\n\r\n /** Secret metadata */\r\n metadata?: SecretMetadata;\r\n}\r\n\r\n/**\r\n * Options for getting secrets\r\n */\r\nexport interface GetSecretOptions {\r\n /** Specific version to retrieve */\r\n version?: string;\r\n\r\n /** Include metadata in response */\r\n includeMetadata?: boolean;\r\n\r\n /** Cache TTL in seconds (0 = no cache) */\r\n cacheTtl?: number;\r\n}\r\n\r\n/**\r\n * Options for setting secrets\r\n */\r\nexport interface SetSecretOptions {\r\n /** Expiration timestamp */\r\n expiresAt?: Date;\r\n\r\n /** Custom tags/labels */\r\n tags?: Record<string, string>;\r\n\r\n /** Description */\r\n description?: string;\r\n}\r\n\r\n/**\r\n * Options for rotating secrets\r\n */\r\nexport interface RotateSecretOptions {\r\n /** Custom rotation function */\r\n rotationFn?: () => Promise<string>;\r\n\r\n /** Rotation period in days */\r\n rotationPeriodDays?: number;\r\n\r\n /** Keep previous version count */\r\n keepPreviousVersions?: number;\r\n}\r\n\r\n/**\r\n * Result of a rotation operation\r\n */\r\nexport interface RotationResult {\r\n /** New secret value */\r\n newValue: string;\r\n\r\n /** Previous secret value (for rollback) */\r\n previousValue?: string;\r\n\r\n /** New version identifier */\r\n newVersion: string;\r\n\r\n /** Previous version identifier */\r\n previousVersion?: string;\r\n}\r\n\r\n/**\r\n * Secrets Management Interface\r\n */\r\nexport interface ISecrets {\r\n /**\r\n * Get a secret value by key\r\n */\r\n get(key: string, options?: GetSecretOptions): Promise<string | null>;\r\n\r\n /**\r\n * Get a secret with metadata\r\n */\r\n getWithMetadata(key: string, options?: GetSecretOptions): Promise<Secret | null>;\r\n\r\n /**\r\n * Get multiple secrets at once\r\n */\r\n mget(keys: string[]): Promise<Map<string, string | null>>;\r\n\r\n /**\r\n * Set a secret value\r\n */\r\n set(key: string, value: string, options?: SetSecretOptions): Promise<void>;\r\n\r\n /**\r\n * Delete a secret\r\n */\r\n delete(key: string): Promise<void>;\r\n\r\n /**\r\n * Check if a secret exists\r\n */\r\n exists(key: string): Promise<boolean>;\r\n\r\n /**\r\n * List all secret keys (optionally filtered by prefix)\r\n */\r\n list(prefix?: string): Promise<string[]>;\r\n\r\n /**\r\n * Rotate a secret (generate new value)\r\n */\r\n rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult>;\r\n\r\n /**\r\n * Get all versions of a secret\r\n */\r\n getVersions(key: string): Promise<SecretMetadata[]>;\r\n\r\n /**\r\n * Health check\r\n */\r\n healthCheck(): Promise<boolean>;\r\n}\r\n\r\n/**\r\n * Environment Variables Secrets Adapter\r\n * Simple implementation using process.env - suitable for development\r\n * and containerized deployments with injected secrets\r\n */\r\nexport class EnvSecrets implements ISecrets {\r\n private prefix: string;\r\n private cache: Map<string, { value: string; expiresAt: number }> = new Map();\r\n\r\n constructor(options: { prefix?: string } = {}) {\r\n this.prefix = options.prefix ?? '';\r\n }\r\n\r\n private getEnvKey(key: string): string {\r\n const normalizedKey = key.toUpperCase().replace(/[.-]/g, '_');\r\n return this.prefix ? `${this.prefix}_${normalizedKey}` : normalizedKey;\r\n }\r\n\r\n async get(key: string, options?: GetSecretOptions): Promise<string | null> {\r\n // Check cache first\r\n if (options?.cacheTtl) {\r\n const cached = this.cache.get(key);\r\n if (cached && cached.expiresAt > Date.now()) {\r\n return cached.value;\r\n }\r\n }\r\n\r\n const envKey = this.getEnvKey(key);\r\n const value = process.env[envKey] ?? null;\r\n\r\n // Cache if requested\r\n if (value && options?.cacheTtl) {\r\n this.cache.set(key, {\r\n value,\r\n expiresAt: Date.now() + options.cacheTtl * 1000,\r\n });\r\n }\r\n\r\n return value;\r\n }\r\n\r\n async getWithMetadata(key: string, options?: GetSecretOptions): Promise<Secret | null> {\r\n const value = await this.get(key, options);\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n return {\r\n key,\r\n value,\r\n metadata: {\r\n // Environment variables don't have native metadata\r\n createdAt: undefined,\r\n updatedAt: undefined,\r\n },\r\n };\r\n }\r\n\r\n async mget(keys: string[]): Promise<Map<string, string | null>> {\r\n const result = new Map<string, string | null>();\r\n for (const key of keys) {\r\n result.set(key, await this.get(key));\r\n }\r\n return result;\r\n }\r\n\r\n async set(key: string, value: string, _options?: SetSecretOptions): Promise<void> {\r\n const envKey = this.getEnvKey(key);\r\n process.env[envKey] = value;\r\n\r\n // Update cache\r\n this.cache.delete(key);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const envKey = this.getEnvKey(key);\r\n delete process.env[envKey];\r\n this.cache.delete(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n const envKey = this.getEnvKey(key);\r\n return process.env[envKey] !== undefined;\r\n }\r\n\r\n async list(prefix?: string): Promise<string[]> {\r\n const keys: string[] = [];\r\n const envPrefix = this.prefix ? `${this.prefix}_` : '';\r\n const searchPrefix = prefix\r\n ? `${envPrefix}${prefix.toUpperCase().replace(/[.-]/g, '_')}`\r\n : envPrefix;\r\n\r\n for (const key of Object.keys(process.env)) {\r\n if (key.startsWith(searchPrefix || '')) {\r\n // Convert back to normalized key format\r\n const normalizedKey = key\r\n .slice(envPrefix.length)\r\n .toLowerCase()\r\n .replace(/_/g, '-');\r\n keys.push(normalizedKey);\r\n }\r\n }\r\n\r\n return keys;\r\n }\r\n\r\n async rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult> {\r\n const previousValue = await this.get(key);\r\n\r\n // Generate new value\r\n const newValue = options?.rotationFn\r\n ? await options.rotationFn()\r\n : this.generateSecureValue();\r\n\r\n await this.set(key, newValue);\r\n\r\n return {\r\n newValue,\r\n previousValue: previousValue ?? undefined,\r\n newVersion: 'current',\r\n previousVersion: previousValue ? 'previous' : undefined,\r\n };\r\n }\r\n\r\n async getVersions(_key: string): Promise<SecretMetadata[]> {\r\n // Environment variables don't support versioning\r\n return [];\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n // Environment is always available\r\n return true;\r\n }\r\n\r\n private generateSecureValue(length: number = 32): string {\r\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';\r\n let result = '';\r\n const randomValues = new Uint32Array(length);\r\n crypto.getRandomValues(randomValues);\r\n for (let i = 0; i < length; i++) {\r\n result += chars[randomValues[i]! % chars.length];\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear the internal cache\r\n */\r\n clearCache(): void {\r\n this.cache.clear();\r\n }\r\n}\r\n\r\n/**\r\n * Memory-based Secrets Adapter\r\n * For testing purposes only - stores secrets in memory\r\n */\r\nexport class MemorySecrets implements ISecrets {\r\n private secrets: Map<string, Secret> = new Map();\r\n private versions: Map<string, SecretMetadata[]> = new Map();\r\n\r\n async get(key: string, _options?: GetSecretOptions): Promise<string | null> {\r\n const secret = this.secrets.get(key);\r\n if (!secret) {\r\n return null;\r\n }\r\n\r\n // Check expiration\r\n if (secret.metadata?.expiresAt && secret.metadata.expiresAt < new Date()) {\r\n await this.delete(key);\r\n return null;\r\n }\r\n\r\n return secret.value;\r\n }\r\n\r\n async getWithMetadata(key: string, options?: GetSecretOptions): Promise<Secret | null> {\r\n const value = await this.get(key, options);\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n return this.secrets.get(key) ?? null;\r\n }\r\n\r\n async mget(keys: string[]): Promise<Map<string, string | null>> {\r\n const result = new Map<string, string | null>();\r\n for (const key of keys) {\r\n result.set(key, await this.get(key));\r\n }\r\n return result;\r\n }\r\n\r\n async set(key: string, value: string, options?: SetSecretOptions): Promise<void> {\r\n const now = new Date();\r\n const version = `v${Date.now()}`;\r\n\r\n // Store version history\r\n const currentSecret = this.secrets.get(key);\r\n if (currentSecret?.metadata) {\r\n const history = this.versions.get(key) ?? [];\r\n history.push(currentSecret.metadata);\r\n this.versions.set(key, history);\r\n }\r\n\r\n this.secrets.set(key, {\r\n key,\r\n value,\r\n metadata: {\r\n version,\r\n createdAt: currentSecret?.metadata?.createdAt ?? now,\r\n updatedAt: now,\r\n expiresAt: options?.expiresAt,\r\n tags: options?.tags,\r\n },\r\n });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.secrets.delete(key);\r\n this.versions.delete(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n return this.secrets.has(key);\r\n }\r\n\r\n async list(prefix?: string): Promise<string[]> {\r\n const keys: string[] = [];\r\n for (const key of this.secrets.keys()) {\r\n if (!prefix || key.startsWith(prefix)) {\r\n keys.push(key);\r\n }\r\n }\r\n return keys;\r\n }\r\n\r\n async rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult> {\r\n const currentSecret = this.secrets.get(key);\r\n const previousValue = currentSecret?.value;\r\n const previousVersion = currentSecret?.metadata?.version;\r\n\r\n // Generate new value\r\n const newValue = options?.rotationFn\r\n ? await options.rotationFn()\r\n : this.generateSecureValue();\r\n\r\n await this.set(key, newValue);\r\n const newVersion = this.secrets.get(key)?.metadata?.version ?? 'unknown';\r\n\r\n return {\r\n newValue,\r\n previousValue,\r\n newVersion,\r\n previousVersion,\r\n };\r\n }\r\n\r\n async getVersions(key: string): Promise<SecretMetadata[]> {\r\n const current = this.secrets.get(key)?.metadata;\r\n const history = this.versions.get(key) ?? [];\r\n\r\n if (current) {\r\n return [...history, current];\r\n }\r\n\r\n return history;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n private generateSecureValue(length: number = 32): string {\r\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';\r\n let result = '';\r\n for (let i = 0; i < length; i++) {\r\n result += chars[Math.floor(Math.random() * chars.length)];\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear all secrets (for testing)\r\n */\r\n clear(): void {\r\n this.secrets.clear();\r\n this.versions.clear();\r\n }\r\n\r\n /**\r\n * Get count of secrets (for testing)\r\n */\r\n get size(): number {\r\n return this.secrets.size;\r\n }\r\n}\r\n","/**\r\n * Distributed Tracing Interface\r\n *\r\n * Provides vendor-agnostic distributed tracing for observability.\r\n * Supports OpenTelemetry, Jaeger, Zipkin, and custom implementations.\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport type SpanKind = 'internal' | 'server' | 'client' | 'producer' | 'consumer';\r\n\r\nexport type SpanStatusCode = 'unset' | 'ok' | 'error';\r\n\r\nexport interface SpanStatus {\r\n code: SpanStatusCode;\r\n message?: string;\r\n}\r\n\r\nexport interface SpanContext {\r\n traceId: string;\r\n spanId: string;\r\n traceFlags: number;\r\n traceState?: string;\r\n}\r\n\r\nexport interface SpanOptions {\r\n /** Type of span */\r\n kind?: SpanKind;\r\n\r\n /** Initial attributes */\r\n attributes?: Record<string, string | number | boolean>;\r\n\r\n /** Parent span (for manual context propagation) */\r\n parent?: ISpan;\r\n\r\n /** Links to other spans */\r\n links?: SpanContext[];\r\n\r\n /** Start time (defaults to now) */\r\n startTime?: number;\r\n}\r\n\r\nexport interface SpanEvent {\r\n name: string;\r\n timestamp: number;\r\n attributes?: Record<string, string | number | boolean>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// SPAN INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface ISpan {\r\n /** Span name */\r\n readonly name: string;\r\n\r\n /** Span context (trace ID, span ID) */\r\n readonly context: SpanContext;\r\n\r\n /** Whether the span is recording */\r\n readonly isRecording: boolean;\r\n\r\n /**\r\n * Set a single attribute\r\n */\r\n setAttribute(key: string, value: string | number | boolean): this;\r\n\r\n /**\r\n * Set multiple attributes\r\n */\r\n setAttributes(attributes: Record<string, string | number | boolean>): this;\r\n\r\n /**\r\n * Add an event to the span\r\n */\r\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): this;\r\n\r\n /**\r\n * Set the span status\r\n */\r\n setStatus(status: SpanStatus): this;\r\n\r\n /**\r\n * Record an exception\r\n */\r\n recordException(exception: Error, attributes?: Record<string, string | number | boolean>): this;\r\n\r\n /**\r\n * Update the span name\r\n */\r\n updateName(name: string): this;\r\n\r\n /**\r\n * End the span (required to export)\r\n */\r\n end(endTime?: number): void;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TRACING INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface ITracing {\r\n /**\r\n * Create and start a new span\r\n */\r\n startSpan(name: string, options?: SpanOptions): ISpan;\r\n\r\n /**\r\n * Get the currently active span\r\n */\r\n getCurrentSpan(): ISpan | undefined;\r\n\r\n /**\r\n * Execute a function within a span context\r\n */\r\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T;\r\n\r\n /**\r\n * Execute an async function within a span context\r\n */\r\n withSpanAsync<T>(name: string, fn: (span: ISpan) => Promise<T>, options?: SpanOptions): Promise<T>;\r\n\r\n /**\r\n * Instrument a function with automatic span creation\r\n */\r\n instrument<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => TReturn,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => TReturn;\r\n\r\n /**\r\n * Instrument an async function with automatic span creation\r\n */\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => Promise<TReturn>;\r\n\r\n /**\r\n * Extract trace context from headers (for incoming requests)\r\n */\r\n extractContext(headers: Record<string, string | string[] | undefined>): SpanContext | undefined;\r\n\r\n /**\r\n * Inject trace context into headers (for outgoing requests)\r\n */\r\n injectContext(headers: Record<string, string>): void;\r\n\r\n /**\r\n * Check if tracing is enabled and healthy\r\n */\r\n healthCheck(): Promise<boolean>;\r\n\r\n /**\r\n * Flush pending spans to the exporter\r\n */\r\n flush(): Promise<void>;\r\n\r\n /**\r\n * Shutdown the tracer\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TRACING CONFIGURATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface TracingConfig {\r\n /** Enable tracing */\r\n enabled: boolean;\r\n\r\n /** Service name for traces */\r\n serviceName: string;\r\n\r\n /** Service version */\r\n serviceVersion?: string;\r\n\r\n /** Environment (dev, staging, production) */\r\n environment?: string;\r\n\r\n /** Sampling rate (0.0 to 1.0) */\r\n sampleRate?: number;\r\n\r\n /** Exporter type */\r\n exporter?: 'console' | 'otlp' | 'jaeger' | 'zipkin' | 'none';\r\n\r\n /** Exporter endpoint */\r\n endpoint?: string;\r\n\r\n /** Additional resource attributes */\r\n resourceAttributes?: Record<string, string>;\r\n\r\n /** Propagation format */\r\n propagation?: 'w3c' | 'b3' | 'jaeger';\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// MEMORY TRACING (For Testing)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nclass MemorySpan implements ISpan {\r\n readonly name: string;\r\n readonly context: SpanContext;\r\n readonly isRecording: boolean = true;\r\n\r\n private _attributes: Record<string, string | number | boolean> = {};\r\n private _events: SpanEvent[] = [];\r\n private _status: SpanStatus = { code: 'unset' };\r\n private _endTime?: number;\r\n private _startTime: number;\r\n\r\n constructor(name: string, traceId: string, parentSpanId?: string) {\r\n this.name = name;\r\n this._startTime = Date.now();\r\n this.context = {\r\n traceId,\r\n spanId: this.generateSpanId(),\r\n traceFlags: 1,\r\n };\r\n }\r\n\r\n private generateSpanId(): string {\r\n return Math.random().toString(16).substring(2, 18).padStart(16, '0');\r\n }\r\n\r\n setAttribute(key: string, value: string | number | boolean): this {\r\n this._attributes[key] = value;\r\n return this;\r\n }\r\n\r\n setAttributes(attributes: Record<string, string | number | boolean>): this {\r\n Object.assign(this._attributes, attributes);\r\n return this;\r\n }\r\n\r\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): this {\r\n this._events.push({ name, timestamp: Date.now(), attributes });\r\n return this;\r\n }\r\n\r\n setStatus(status: SpanStatus): this {\r\n this._status = status;\r\n return this;\r\n }\r\n\r\n recordException(exception: Error, attributes?: Record<string, string | number | boolean>): this {\r\n this.addEvent('exception', {\r\n 'exception.type': exception.name,\r\n 'exception.message': exception.message,\r\n 'exception.stacktrace': exception.stack || '',\r\n ...attributes,\r\n });\r\n this.setStatus({ code: 'error', message: exception.message });\r\n return this;\r\n }\r\n\r\n updateName(name: string): this {\r\n (this as { name: string }).name = name;\r\n return this;\r\n }\r\n\r\n end(endTime?: number): void {\r\n this._endTime = endTime ?? Date.now();\r\n }\r\n\r\n // Testing helpers\r\n getAttributes(): Record<string, string | number | boolean> {\r\n return { ...this._attributes };\r\n }\r\n\r\n getEvents(): SpanEvent[] {\r\n return [...this._events];\r\n }\r\n\r\n getStatus(): SpanStatus {\r\n return { ...this._status };\r\n }\r\n\r\n getDuration(): number | undefined {\r\n return this._endTime ? this._endTime - this._startTime : undefined;\r\n }\r\n\r\n isEnded(): boolean {\r\n return this._endTime !== undefined;\r\n }\r\n}\r\n\r\nexport class MemoryTracing implements ITracing {\r\n private spans: MemorySpan[] = [];\r\n private currentSpan: MemorySpan | undefined;\r\n private traceId: string;\r\n\r\n constructor() {\r\n this.traceId = this.generateTraceId();\r\n }\r\n\r\n private generateTraceId(): string {\r\n return Math.random().toString(16).substring(2, 34).padStart(32, '0');\r\n }\r\n\r\n startSpan(name: string, options?: SpanOptions): ISpan {\r\n const span = new MemorySpan(name, this.traceId, this.currentSpan?.context.spanId);\r\n\r\n if (options?.attributes) {\r\n span.setAttributes(options.attributes);\r\n }\r\n\r\n this.spans.push(span);\r\n this.currentSpan = span;\r\n\r\n return span;\r\n }\r\n\r\n getCurrentSpan(): ISpan | undefined {\r\n return this.currentSpan;\r\n }\r\n\r\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T {\r\n const span = this.startSpan(name, options);\r\n try {\r\n const result = fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n }\r\n }\r\n\r\n async withSpanAsync<T>(name: string, fn: (span: ISpan) => Promise<T>, options?: SpanOptions): Promise<T> {\r\n const span = this.startSpan(name, options);\r\n try {\r\n const result = await fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n }\r\n }\r\n\r\n instrument<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => TReturn,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => TReturn {\r\n return (...args: TArgs) => this.withSpan(name, () => fn(...args), options);\r\n }\r\n\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => Promise<TReturn> {\r\n return (...args: TArgs) => this.withSpanAsync(name, () => fn(...args), options);\r\n }\r\n\r\n extractContext(headers: Record<string, string | string[] | undefined>): SpanContext | undefined {\r\n const traceparent = headers['traceparent'];\r\n if (!traceparent || typeof traceparent !== 'string') return undefined;\r\n\r\n // Parse W3C Trace Context format: version-traceId-spanId-flags\r\n const parts = traceparent.split('-');\r\n if (parts.length !== 4) return undefined;\r\n\r\n return {\r\n traceId: parts[1]!,\r\n spanId: parts[2]!,\r\n traceFlags: parseInt(parts[3]!, 16),\r\n };\r\n }\r\n\r\n injectContext(headers: Record<string, string>): void {\r\n if (this.currentSpan) {\r\n const ctx = this.currentSpan.context;\r\n headers['traceparent'] = `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, '0')}`;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async flush(): Promise<void> {\r\n // No-op for memory implementation\r\n }\r\n\r\n async close(): Promise<void> {\r\n this.spans = [];\r\n this.currentSpan = undefined;\r\n }\r\n\r\n // Testing helpers\r\n getSpans(): MemorySpan[] {\r\n return [...this.spans];\r\n }\r\n\r\n getCompletedSpans(): MemorySpan[] {\r\n return this.spans.filter((s) => s.isEnded());\r\n }\r\n\r\n clear(): void {\r\n this.spans = [];\r\n this.currentSpan = undefined;\r\n this.traceId = this.generateTraceId();\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// NOOP TRACING (Disabled)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nclass NoopSpan implements ISpan {\r\n readonly name: string = '';\r\n readonly context: SpanContext = { traceId: '', spanId: '', traceFlags: 0 };\r\n readonly isRecording: boolean = false;\r\n\r\n setAttribute(): this {\r\n return this;\r\n }\r\n setAttributes(): this {\r\n return this;\r\n }\r\n addEvent(): this {\r\n return this;\r\n }\r\n setStatus(): this {\r\n return this;\r\n }\r\n recordException(): this {\r\n return this;\r\n }\r\n updateName(): this {\r\n return this;\r\n }\r\n end(): void {}\r\n}\r\n\r\nexport class NoopTracing implements ITracing {\r\n private noopSpan = new NoopSpan();\r\n\r\n startSpan(): ISpan {\r\n return this.noopSpan;\r\n }\r\n\r\n getCurrentSpan(): ISpan | undefined {\r\n return undefined;\r\n }\r\n\r\n withSpan<T>(_name: string, fn: (span: ISpan) => T): T {\r\n return fn(this.noopSpan);\r\n }\r\n\r\n async withSpanAsync<T>(_name: string, fn: (span: ISpan) => Promise<T>): Promise<T> {\r\n return fn(this.noopSpan);\r\n }\r\n\r\n instrument<TArgs extends unknown[], TReturn>(\r\n _name: string,\r\n fn: (...args: TArgs) => TReturn\r\n ): (...args: TArgs) => TReturn {\r\n return fn;\r\n }\r\n\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n _name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>\r\n ): (...args: TArgs) => Promise<TReturn> {\r\n return fn;\r\n }\r\n\r\n extractContext(): SpanContext | undefined {\r\n return undefined;\r\n }\r\n\r\n injectContext(): void {}\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async flush(): Promise<void> {}\r\n\r\n async close(): Promise<void> {}\r\n}\r\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(['memory', 'postgres', 'supabase']);\nexport const CacheProviderSchema = z.enum(['memory', 'redis', 'upstash']);\nexport const StorageProviderSchema = z.enum(['memory', 's3', 'minio', 'r2', 'supabase']);\nexport const EmailProviderSchema = z.enum(['memory', 'console', 'smtp', 'resend']);\nexport const QueueProviderSchema = z.enum(['memory', 'bullmq']);\nexport const TracingProviderSchema = z.enum(['noop', 'memory', 'otlp']);\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error']);\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.string().optional().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.string().optional().describe('Supabase service role key'),\n poolSize: z.number().int().min(1).max(100).default(10).describe('Connection pool size'),\n connectionTimeout: z.number().int().min(1000).max(60000).default(5000).describe('Connection timeout in ms'),\n ssl: z.union([z.boolean(), z.object({ rejectUnauthorized: z.boolean().optional() })]).optional().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: '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.number().int().min(0).default(3600).describe('Default TTL in seconds'),\n keyPrefix: z.string().default('').describe('Prefix for all cache keys'),\n maxRetries: z.number().int().min(0).max(10).default(3).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: '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.string().url().optional().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.string().url().optional().describe('Public URL for accessing files'),\n forcePathStyle: z.boolean().default(false).describe('Use path-style URLs (required for MinIO)'),\n signedUrlExpiry: z.number().int().min(60).max(604800).default(3600).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.number().int().min(1).max(100).default(10).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.string().url().optional().describe('Redis connection URL for BullMQ'),\n queueName: z.string().default('platform-jobs').describe('Default queue name'),\n concurrency: z.number().int().min(1).max(100).default(5).describe('Worker concurrency'),\n maxRetries: z.number().int().min(0).max(10).default(3).describe('Max job retries'),\n retryDelay: z.number().int().min(0).default(1000).describe('Retry delay in ms'),\n removeOnComplete: z.boolean().default(true).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\n// ═══════════════════════════════════════════════════════════════\n// RESILIENCE CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const RetryConfigSchema = z.object({\n enabled: z.boolean().default(true).describe('Enable retry for failed operations'),\n maxAttempts: z.number().int().min(1).max(10).default(3).describe('Maximum retry attempts'),\n baseDelay: z.number().int().min(0).max(10000).default(100).describe('Base delay in ms'),\n maxDelay: z.number().int().min(0).max(60000).default(5000).describe('Maximum delay in ms'),\n backoffMultiplier: z.number().min(1).max(5).default(2).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.number().int().min(1).max(100).default(5).describe('Failures before opening circuit'),\n resetTimeout: z.number().int().min(1000).max(300000).default(30000).describe('Reset timeout in ms'),\n halfOpenRequests: z.number().int().min(1).max(10).default(3).describe('Requests allowed in half-open state'),\n monitorInterval: z.number().int().min(1000).max(60000).default(10000).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.number().int().min(100).max(300000).default(30000).describe('Default timeout in ms'),\n database: z.number().int().min(100).max(300000).default(10000).describe('Database operation timeout'),\n cache: z.number().int().min(100).max(60000).default(5000).describe('Cache operation timeout'),\n storage: z.number().int().min(100).max(600000).default(60000).describe('Storage operation timeout'),\n email: z.number().int().min(100).max(120000).default(30000).describe('Email operation timeout'),\n queue: z.number().int().min(100).max(60000).default(10000).describe('Queue operation timeout'),\n});\n\nexport const BulkheadConfigSchema = z.object({\n enabled: z.boolean().default(false).describe('Enable bulkhead isolation'),\n maxConcurrent: z.number().int().min(1).max(1000).default(10).describe('Maximum concurrent operations'),\n maxQueued: z.number().int().min(0).max(10000).default(100).describe('Maximum queued operations'),\n timeout: z.number().int().min(0).max(300000).default(30000).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.enum(['json', 'pretty']).default('json').describe('Log output format'),\n includeTimestamp: z.boolean().default(true).describe('Include timestamp in logs'),\n includeCorrelationId: z.boolean().default(true).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.record(z.string()).default({}).describe('Default tags for all metrics'),\n flushInterval: z.number().int().min(1000).max(60000).default(10000).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.string().optional().describe('Environment (dev, staging, production)'),\n sampleRate: z.number().min(0).max(1).default(1).describe('Trace sampling rate'),\n propagateContext: z.boolean().default(true).describe('Propagate trace context to downstream services'),\n endpoint: z.string().url().optional().describe('OTLP exporter endpoint'),\n exporterType: z.enum(['otlp-http', 'otlp-grpc', 'console']).default('otlp-http').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 // 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 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>;\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: process.env.PLATFORM_DB_PROVIDER || process.env.DATABASE_PROVIDER || '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 ? parseInt(process.env.DATABASE_POOL_SIZE) : undefined,\n connectionTimeout: process.env.DATABASE_TIMEOUT ? parseInt(process.env.DATABASE_TIMEOUT) : undefined,\n },\n cache: {\n provider: process.env.PLATFORM_CACHE_PROVIDER || process.env.CACHE_PROVIDER || '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 ? parseInt(process.env.CACHE_DEFAULT_TTL) : undefined,\n keyPrefix: process.env.CACHE_KEY_PREFIX,\n },\n storage: {\n provider: process.env.PLATFORM_STORAGE_PROVIDER || process.env.STORAGE_PROVIDER || '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: 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 ? parseInt(process.env.S3_SIGNED_URL_EXPIRY) : undefined,\n },\n email: {\n provider: process.env.PLATFORM_EMAIL_PROVIDER || process.env.EMAIL_PROVIDER || '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: process.env.PLATFORM_QUEUE_PROVIDER || process.env.QUEUE_PROVIDER || 'memory',\n redisUrl: process.env.REDIS_URL,\n queueName: process.env.QUEUE_NAME,\n concurrency: process.env.QUEUE_CONCURRENCY ? parseInt(process.env.QUEUE_CONCURRENCY) : undefined,\n maxRetries: process.env.QUEUE_MAX_RETRIES ? parseInt(process.env.QUEUE_MAX_RETRIES) : undefined,\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: (process.env.LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error') || '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: (process.env.TRACING_PROVIDER as 'noop' | 'memory' | 'otlp') || '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 ? parseFloat(process.env.TRACING_SAMPLE_RATE) : undefined,\n endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.TRACING_ENDPOINT,\n exporterType: (process.env.OTEL_EXPORTER_TYPE as 'otlp-http' | 'otlp-grpc' | '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 * Memory Database Adapter\n * In-memory implementation for testing\n */\n\nimport { IDatabase, IQueryBuilder, QueryResult } 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>(sql: string, params?: unknown[]): 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 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 = { ...item, ...this._updateData, updated_at: new Date().toISOString() };\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 string | number | null;\n const bVal = (b as Record<string, unknown>)[column] as string | number | null;\n if (aVal === null || aVal === undefined) return direction === 'asc' ? 1 : -1;\n if (bVal === null || bVal === undefined) 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>> = 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>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void> {\n await Promise.all(entries.map(({ key, value, ttl }) => this.set(key, value, ttl)));\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(channel: string, callback: (message: string) => void): 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 { IStorage, StorageFile, UploadOptions } from \"../../interfaces/IStorage\";\n\nexport class MemoryStorage implements IStorage {\n private files = new Map<string, { data: Buffer; contentType?: string }>();\n \n async upload(key: string, data: Buffer | Blob | ReadableStream, options?: UploadOptions) { \n this.files.set(key, { data: Buffer.from(\"mock\"), contentType: options?.contentType }); \n return { url: \"memory://\" + key }; \n }\n async download(key: string) { return this.files.get(key)?.data || Buffer.from(\"\"); }\n async getSignedUrl(key: string) { return \"memory://\" + key; }\n async delete(key: string) { this.files.delete(key); }\n async deleteMany(keys: string[]) { keys.forEach(k => this.files.delete(k)); }\n async list(prefix?: string): Promise<StorageFile[]> { return []; }\n async exists(key: string) { return this.files.has(key); }\n async getMetadata(key: string) { return null; }\n async healthCheck() { return true; }\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() { return true; }\n \n // Test helpers\n getSentEmails(): EmailMessage[] { return this.sentEmails; }\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","// Memory Queue - stub implementation\nimport { IQueue, Job, JobOptions } from \"../../interfaces/IQueue\";\n\nexport class MemoryQueue<T = unknown> implements IQueue<T> {\n private jobs: Job<T>[] = [];\n private handlers: Array<(job: Job<T>) => Promise<unknown>> = [];\n \n async add(name: string, data: T, options?: JobOptions): Promise<Job<T>> {\n const job: Job<T> = { id: \"job_\" + this.jobs.length, name, data, attemptsMade: 0, progress: 0, timestamp: Date.now() };\n this.jobs.push(job);\n this.handlers.forEach(h => h(job));\n return job;\n }\n \n async addBulk(jobs: Array<{ name: string; data: T; options?: JobOptions }>) {\n return Promise.all(jobs.map(j => this.add(j.name, j.data, j.options)));\n }\n \n process(handler: (job: Job<T>) => Promise<unknown>) { this.handlers.push(handler); }\n async getJob(id: string) { return this.jobs.find(j => j.id === id) || null; }\n async removeJob(id: string) { this.jobs = this.jobs.filter(j => j.id !== id); }\n async pause() {}\n async resume() {}\n async getStats() { return { waiting: 0, active: 0, completed: this.jobs.length, failed: 0, delayed: 0 }; }\n async healthCheck() { return true; }\n async close() { this.jobs = []; }\n\n /**\n * Clear all jobs (for testing)\n */\n clear(): void {\n this.jobs = [];\n this.handlers = [];\n }\n\n /**\n * Get all jobs (for testing)\n */\n getJobs(): Job<T>[] {\n return this.jobs;\n }\n\n /**\n * Get pending jobs (for testing)\n */\n getPendingJobs(): Job<T>[] {\n return this.jobs.filter(j => j.progress < 100);\n }\n\n /**\n * Get number of jobs (for testing)\n */\n get size(): number {\n return this.jobs.length;\n }\n}\n","/**\r\n * Console Email Adapter\r\n * Development implementation that logs emails to console instead of sending\r\n */\r\n\r\nimport { IEmail, EmailMessage, EmailResult, EmailAddress } from '../../interfaces/IEmail';\r\n\r\nexport class ConsoleEmail implements IEmail {\r\n private sentEmails: EmailMessage[] = [];\r\n\r\n async send(message: EmailMessage): Promise<EmailResult> {\r\n const id = `console_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\r\n\r\n console.log('\\n' + '='.repeat(60));\r\n console.log('📧 EMAIL SENT (Console Adapter)');\r\n console.log('='.repeat(60));\r\n console.log(`ID: ${id}`);\r\n console.log(`To: ${this.formatAddresses(message.to)}`);\r\n console.log(`From: ${message.from ? this.formatAddress(message.from) : '(default)'}`);\r\n console.log(`Subject: ${message.subject}`);\r\n\r\n if (message.replyTo) {\r\n console.log(`Reply-To: ${this.formatAddress(message.replyTo)}`);\r\n }\r\n\r\n if (message.tags && message.tags.length > 0) {\r\n console.log(`Tags: ${message.tags.join(', ')}`);\r\n }\r\n\r\n if (message.attachments && message.attachments.length > 0) {\r\n console.log(`Attachments: ${message.attachments.map((a) => a.filename).join(', ')}`);\r\n }\r\n\r\n console.log('-'.repeat(60));\r\n\r\n if (message.text) {\r\n console.log('TEXT BODY:');\r\n console.log(message.text.slice(0, 500) + (message.text.length > 500 ? '\\n...(truncated)' : ''));\r\n }\r\n\r\n if (message.html) {\r\n console.log('HTML BODY: [HTML content - ' + message.html.length + ' chars]');\r\n }\r\n\r\n console.log('='.repeat(60) + '\\n');\r\n\r\n this.sentEmails.push(message);\r\n\r\n return {\r\n id,\r\n success: true,\r\n };\r\n }\r\n\r\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\r\n const results: EmailResult[] = [];\r\n\r\n for (const message of messages) {\r\n results.push(await this.send(message));\r\n }\r\n\r\n return results;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n /**\r\n * Get all sent emails (for testing)\r\n */\r\n getSentEmails(): EmailMessage[] {\r\n return [...this.sentEmails];\r\n }\r\n\r\n /**\r\n * Clear sent emails (for testing)\r\n */\r\n clearSentEmails(): void {\r\n this.sentEmails = [];\r\n }\r\n\r\n private formatAddress(address: EmailAddress): string {\r\n if (address.name) {\r\n return `${address.name} <${address.email}>`;\r\n }\r\n return address.email;\r\n }\r\n\r\n private formatAddresses(addresses: EmailAddress | EmailAddress[]): string {\r\n const list = Array.isArray(addresses) ? addresses : [addresses];\r\n return list.map((addr) => this.formatAddress(addr)).join(', ');\r\n }\r\n}\r\n","/**\n * Platform Factory\n * Create a platform instance with configured adapters\n */\n\nimport { IPlatform, PlatformHealthStatus, IDatabase, ICache, IStorage, IEmail, IQueue, ILogger, IMetrics, ITracing } 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/**\n * Create a database adapter based on configuration\n */\nasync function createDatabaseAdapter(config: PlatformConfig): Promise<IDatabase> {\n switch (config.database.provider) {\n case 'postgres': {\n const connectionString = config.database.connectionString || config.database.url || process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error('PostgreSQL requires DATABASE_URL, url, or connectionString configuration');\n }\n const { PostgresDatabase } = 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('Supabase requires SUPABASE_URL and SUPABASE_ANON_KEY environment variables');\n }\n const { createClient } = await import('@supabase/supabase-js');\n const { SupabaseDatabase } = await import('./adapters/supabase/SupabaseDatabase');\n const client = createClient(\n config.database.supabaseUrl,\n config.database.supabaseServiceRoleKey || 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('Upstash requires UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN environment variables');\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 = config.database.supabaseServiceRoleKey || config.database.supabaseAnonKey || process.env.SUPABASE_ANON_KEY;\n const bucket = config.storage.bucket || process.env.SUPABASE_STORAGE_BUCKET || 'uploads';\n\n if (!url || !apiKey) {\n throw new Error('Supabase storage requires SUPABASE_URL and SUPABASE_ANON_KEY');\n }\n\n const { SupabaseStorage } = 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 (!config.storage.accessKey || !config.storage.secretKey || !config.storage.bucket) {\n throw new Error('S3 requires S3_ACCESS_KEY, S3_SECRET_KEY, and S3_BUCKET environment variables');\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: config.storage.forcePathStyle || config.storage.provider === 'minio',\n });\n\n return new S3Storage(client, config.storage.bucket, getSignedUrl, config.storage.publicUrl);\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('SMTP requires host and port configuration (SMTP_HOST, SMTP_PORT)');\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 } = 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 a platform instance (async version)\n */\nexport async function createPlatformAsync(config?: Partial<PlatformConfig>): Promise<IPlatform> {\n const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();\n\n const [db, cache, storage, email, queue, tracing] = await Promise.all([\n createDatabaseAdapter(finalConfig),\n createCacheAdapter(finalConfig),\n createStorageAdapter(finalConfig),\n createEmailAdapter(finalConfig),\n createQueueAdapter(finalConfig),\n createTracingAdapter(finalConfig),\n ]);\n\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n\n return createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing);\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' && finalConfig.email.provider !== 'console') ||\n finalConfig.observability.tracing.provider === 'otlp';\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 = finalConfig.email.provider === 'console' ? new ConsoleEmail() : new MemoryEmail();\n const queue = new MemoryQueue();\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n const tracing = finalConfig.observability.tracing.provider === 'memory'\n ? new MemoryTracing()\n : new NoopTracing();\n\n return createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing);\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): IPlatform {\n return {\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n\n async healthCheck(): Promise<PlatformHealthStatus> {\n const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth, tracingHealth] = 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: dbHealth && cacheHealth && storageHealth && emailHealth && queueHealth && 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([db.close(), cache.close(), queue.close(), tracing.close()]);\n },\n };\n}\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): 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 * Middleware Chain Implementation\r\n */\r\n\r\nimport { randomUUID } from 'crypto';\r\nimport type { Middleware, MiddlewareChain, MiddlewareChainOptions, MiddlewareContext } from './types';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\nimport type { ILogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Create a new middleware chain\r\n */\r\nexport function createMiddlewareChain(options: MiddlewareChainOptions = {}): MiddlewareChain {\r\n const middlewares: Middleware[] = [];\r\n const logger = options.logger ?? new NoopLogger();\r\n const generateCorrelationId = options.generateCorrelationId ?? (() => randomUUID());\r\n\r\n function sortMiddleware(): void {\r\n middlewares.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));\r\n }\r\n\r\n const chain: MiddlewareChain = {\r\n use<TArgs = unknown, TResult = unknown>(middleware: Middleware<TArgs, TResult>): MiddlewareChain {\r\n // Remove existing middleware with same name\r\n const existingIndex = middlewares.findIndex((m) => m.name === middleware.name);\r\n if (existingIndex !== -1) {\r\n middlewares.splice(existingIndex, 1);\r\n }\r\n\r\n middlewares.push(middleware as Middleware);\r\n sortMiddleware();\r\n return chain;\r\n },\r\n\r\n remove(name: string): MiddlewareChain {\r\n const index = middlewares.findIndex((m) => m.name === name);\r\n if (index !== -1) {\r\n middlewares.splice(index, 1);\r\n }\r\n return chain;\r\n },\r\n\r\n async execute<TArgs, TResult>(\r\n partialCtx: Omit<MiddlewareContext<TArgs, TResult>, 'metadata' | 'skip' | 'cachedResult'>,\r\n operation: () => Promise<TResult>\r\n ): Promise<TResult> {\r\n const ctx: MiddlewareContext<TArgs, TResult> = {\r\n ...partialCtx,\r\n metadata: new Map(),\r\n skip: false,\r\n cachedResult: undefined,\r\n };\r\n\r\n // Execute before hooks\r\n for (const middleware of middlewares) {\r\n if (middleware.before) {\r\n try {\r\n await middleware.before(ctx);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Middleware ${middleware.name} before hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n\r\n if (ctx.skip) {\r\n break;\r\n }\r\n }\r\n\r\n // Return cached result if set\r\n if (ctx.cachedResult !== undefined) {\r\n ctx.result = ctx.cachedResult;\r\n ctx.duration = Date.now() - ctx.startTime;\r\n\r\n // Still run after hooks for cached results\r\n for (const middleware of middlewares) {\r\n if (middleware.after) {\r\n try {\r\n await middleware.after(ctx);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Middleware ${middleware.name} after hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return ctx.cachedResult;\r\n }\r\n\r\n // Execute the actual operation\r\n try {\r\n const result = await operation();\r\n ctx.result = result;\r\n ctx.duration = Date.now() - ctx.startTime;\r\n\r\n // Execute after hooks\r\n for (const middleware of middlewares) {\r\n if (middleware.after) {\r\n try {\r\n await middleware.after(ctx);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Middleware ${middleware.name} after hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n } catch (err) {\r\n ctx.error = err instanceof Error ? err : new Error(String(err));\r\n ctx.duration = Date.now() - ctx.startTime;\r\n\r\n // Execute error hooks\r\n for (const middleware of middlewares) {\r\n if (middleware.onError) {\r\n try {\r\n await middleware.onError(ctx, ctx.error);\r\n } catch (hookErr) {\r\n const error = hookErr instanceof Error ? hookErr : new Error(String(hookErr));\r\n logger.error(`Middleware ${middleware.name} onError hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n }\r\n\r\n throw ctx.error;\r\n }\r\n },\r\n\r\n getMiddleware(): Middleware[] {\r\n return [...middlewares];\r\n },\r\n };\r\n\r\n return chain;\r\n}\r\n\r\n/**\r\n * Create a context for middleware execution\r\n */\r\nexport function createMiddlewareContext<TArgs = unknown, TResult = unknown>(\r\n service: MiddlewareContext['service'],\r\n operation: string,\r\n args: TArgs,\r\n logger: ILogger,\r\n options: {\r\n correlationId?: string;\r\n tenantId?: string;\r\n } = {}\r\n): Omit<MiddlewareContext<TArgs, TResult>, 'metadata' | 'skip' | 'cachedResult'> {\r\n return {\r\n service,\r\n operation,\r\n args,\r\n logger,\r\n startTime: Date.now(),\r\n correlationId: options.correlationId ?? randomUUID(),\r\n tenantId: options.tenantId,\r\n };\r\n}\r\n","/**\r\n * Built-in Middleware Implementations\r\n */\r\n\r\nimport type { Middleware, MiddlewareContext } from './types';\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport type { IMetrics } from '../interfaces/IMetrics';\r\n\r\n/**\r\n * Logging middleware - logs all operations with timing\r\n */\r\nexport function createLoggingMiddleware(logger: ILogger): Middleware {\r\n return {\r\n name: 'logging',\r\n priority: 10,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n logger.debug(`Starting ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n tenantId: ctx.tenantId,\r\n args: sanitizeArgs(ctx.args),\r\n });\r\n },\r\n\r\n after(ctx: MiddlewareContext): void {\r\n logger.info(`Completed ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n duration: ctx.duration,\r\n success: true,\r\n });\r\n },\r\n\r\n onError(ctx: MiddlewareContext, error: Error): void {\r\n logger.error(`Failed ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n duration: ctx.duration,\r\n error,\r\n });\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Metrics middleware - records timing and counters\r\n */\r\nexport function createMetricsMiddleware(metrics: IMetrics): Middleware {\r\n return {\r\n name: 'metrics',\r\n priority: 20,\r\n\r\n after(ctx: MiddlewareContext): void {\r\n metrics.timing(`platform.${ctx.service}.duration`, ctx.duration ?? 0, {\r\n operation: ctx.operation,\r\n success: 'true',\r\n });\r\n\r\n metrics.increment(`platform.${ctx.service}.requests`, 1, {\r\n operation: ctx.operation,\r\n status: 'success',\r\n });\r\n },\r\n\r\n onError(ctx: MiddlewareContext): void {\r\n metrics.timing(`platform.${ctx.service}.duration`, ctx.duration ?? 0, {\r\n operation: ctx.operation,\r\n success: 'false',\r\n });\r\n\r\n metrics.increment(`platform.${ctx.service}.requests`, 1, {\r\n operation: ctx.operation,\r\n status: 'error',\r\n });\r\n\r\n metrics.increment(`platform.${ctx.service}.errors`, 1, {\r\n operation: ctx.operation,\r\n });\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Slow query logging middleware\r\n */\r\nexport function createSlowQueryMiddleware(\r\n logger: ILogger,\r\n thresholdMs: number = 1000\r\n): Middleware {\r\n return {\r\n name: 'slow-query',\r\n priority: 15,\r\n\r\n after(ctx: MiddlewareContext): void {\r\n if (ctx.duration && ctx.duration > thresholdMs) {\r\n logger.warn(`Slow operation detected: ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n duration: ctx.duration,\r\n threshold: thresholdMs,\r\n args: sanitizeArgs(ctx.args),\r\n });\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Tenant isolation middleware - ensures tenant context is set\r\n */\r\nexport function createTenantMiddleware(\r\n options: {\r\n required?: boolean;\r\n headerName?: string;\r\n } = {}\r\n): Middleware {\r\n const { required = false } = options;\r\n\r\n return {\r\n name: 'tenant',\r\n priority: 5,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n if (required && !ctx.tenantId) {\r\n throw new Error('Tenant context required but not provided');\r\n }\r\n\r\n if (ctx.tenantId) {\r\n ctx.metadata.set('tenantId', ctx.tenantId);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Request ID middleware - ensures correlation ID exists\r\n */\r\nexport function createRequestIdMiddleware(): Middleware {\r\n return {\r\n name: 'request-id',\r\n priority: 1,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n ctx.metadata.set('correlationId', ctx.correlationId);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Timeout middleware - enforces operation timeout\r\n */\r\nexport function createTimeoutMiddleware(timeoutMs: number): Middleware {\r\n return {\r\n name: 'timeout',\r\n priority: 2,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n ctx.metadata.set('timeout', timeoutMs);\r\n ctx.metadata.set('timeoutStart', Date.now());\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Cache middleware - caches results of read operations\r\n */\r\nexport function createCacheMiddleware(\r\n cache: { get: (key: string) => Promise<unknown>; set: (key: string, value: unknown, ttl?: number) => Promise<void> },\r\n options: {\r\n ttl?: number;\r\n keyPrefix?: string;\r\n cacheableOperations?: string[];\r\n } = {}\r\n): Middleware {\r\n const {\r\n ttl = 300,\r\n keyPrefix = 'middleware:cache:',\r\n cacheableOperations = ['get', 'query', 'find', 'list'],\r\n } = options;\r\n\r\n function isCacheable(operation: string): boolean {\r\n return cacheableOperations.some((op) => operation.toLowerCase().includes(op));\r\n }\r\n\r\n function getCacheKey(ctx: MiddlewareContext): string {\r\n const argsHash = JSON.stringify(ctx.args);\r\n return `${keyPrefix}${ctx.service}:${ctx.operation}:${argsHash}`;\r\n }\r\n\r\n return {\r\n name: 'cache',\r\n priority: 50,\r\n\r\n async before(ctx: MiddlewareContext): Promise<void> {\r\n if (!isCacheable(ctx.operation)) return;\r\n\r\n const key = getCacheKey(ctx);\r\n const cached = await cache.get(key);\r\n\r\n if (cached !== null) {\r\n ctx.cachedResult = cached;\r\n ctx.metadata.set('cacheHit', true);\r\n ctx.logger.debug('Cache hit', { key, operation: ctx.operation });\r\n } else {\r\n ctx.metadata.set('cacheHit', false);\r\n }\r\n },\r\n\r\n async after(ctx: MiddlewareContext): Promise<void> {\r\n if (!isCacheable(ctx.operation)) return;\r\n if (ctx.metadata.get('cacheHit')) return;\r\n\r\n const key = getCacheKey(ctx);\r\n await cache.set(key, ctx.result, ttl);\r\n ctx.logger.debug('Cache set', { key, operation: ctx.operation, ttl });\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Rate Limiting Error\r\n */\r\nexport class RateLimitError extends Error {\r\n override readonly name = 'RateLimitError';\r\n readonly retryAfter: number;\r\n readonly limit: number;\r\n readonly remaining: number;\r\n readonly resetAt: Date;\r\n\r\n constructor(\r\n message: string,\r\n options: { retryAfter: number; limit: number; remaining: number; resetAt: Date }\r\n ) {\r\n super(message);\r\n this.retryAfter = options.retryAfter;\r\n this.limit = options.limit;\r\n this.remaining = options.remaining;\r\n this.resetAt = options.resetAt;\r\n }\r\n}\r\n\r\n/**\r\n * Rate limit info for responses\r\n */\r\nexport interface RateLimitInfo {\r\n limit: number;\r\n remaining: number;\r\n resetAt: Date;\r\n}\r\n\r\n/**\r\n * Rate limiter storage interface\r\n */\r\nexport interface RateLimiterStorage {\r\n /**\r\n * Get current count and increment\r\n * Returns: [currentCount, resetAt timestamp]\r\n */\r\n increment(key: string, windowMs: number): Promise<[number, number]>;\r\n\r\n /**\r\n * Get current state without incrementing\r\n */\r\n get(key: string): Promise<{ count: number; resetAt: number } | null>;\r\n}\r\n\r\n/**\r\n * In-memory rate limiter storage\r\n */\r\nexport class MemoryRateLimiterStorage implements RateLimiterStorage {\r\n private windows: Map<string, { count: number; resetAt: number }> = new Map();\r\n private cleanupInterval: NodeJS.Timeout | null = null;\r\n\r\n constructor(options: { cleanupIntervalMs?: number } = {}) {\r\n const cleanupIntervalMs = options.cleanupIntervalMs ?? 60000;\r\n\r\n // Periodic cleanup of expired windows\r\n this.cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, window] of this.windows) {\r\n if (window.resetAt < now) {\r\n this.windows.delete(key);\r\n }\r\n }\r\n }, cleanupIntervalMs);\r\n\r\n // Prevent interval from keeping process alive\r\n if (this.cleanupInterval.unref) {\r\n this.cleanupInterval.unref();\r\n }\r\n }\r\n\r\n async increment(key: string, windowMs: number): Promise<[number, number]> {\r\n const now = Date.now();\r\n let window = this.windows.get(key);\r\n\r\n // Check if window expired\r\n if (!window || window.resetAt < now) {\r\n window = { count: 0, resetAt: now + windowMs };\r\n this.windows.set(key, window);\r\n }\r\n\r\n window.count++;\r\n return [window.count, window.resetAt];\r\n }\r\n\r\n async get(key: string): Promise<{ count: number; resetAt: number } | null> {\r\n const window = this.windows.get(key);\r\n if (!window || window.resetAt < Date.now()) {\r\n return null;\r\n }\r\n return window;\r\n }\r\n\r\n /**\r\n * Clear all windows (for testing)\r\n */\r\n clear(): void {\r\n this.windows.clear();\r\n }\r\n\r\n /**\r\n * Stop cleanup interval\r\n */\r\n stop(): void {\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Rate limiting algorithm types\r\n */\r\nexport type RateLimitAlgorithm = 'fixed-window' | 'sliding-window' | 'token-bucket';\r\n\r\n/**\r\n * Rate limiting options\r\n */\r\nexport interface RateLimitOptions {\r\n /** Maximum requests per window */\r\n limit: number;\r\n\r\n /** Time window in milliseconds */\r\n windowMs: number;\r\n\r\n /** Storage backend (defaults to memory) */\r\n storage?: RateLimiterStorage;\r\n\r\n /** Key generator function */\r\n keyGenerator?: (ctx: MiddlewareContext) => string;\r\n\r\n /** Skip rate limiting for certain requests */\r\n skip?: (ctx: MiddlewareContext) => boolean;\r\n\r\n /** Handler for rate limit exceeded */\r\n onRateLimited?: (ctx: MiddlewareContext, info: RateLimitInfo) => void;\r\n\r\n /** Whether to throw error or just log (defaults to throw) */\r\n throwOnLimit?: boolean;\r\n\r\n /** Custom message for rate limit error */\r\n message?: string;\r\n\r\n /** Headers to set with rate limit info */\r\n setHeaders?: boolean;\r\n}\r\n\r\n/**\r\n * Rate limiting middleware\r\n * Prevents abuse by limiting request frequency\r\n */\r\nexport function createRateLimitMiddleware(options: RateLimitOptions): Middleware {\r\n const {\r\n limit,\r\n windowMs,\r\n storage = new MemoryRateLimiterStorage(),\r\n keyGenerator = defaultKeyGenerator,\r\n skip,\r\n onRateLimited,\r\n throwOnLimit = true,\r\n message = 'Too many requests, please try again later',\r\n } = options;\r\n\r\n return {\r\n name: 'rate-limit',\r\n priority: 3, // Run early, after request-id and timeout\r\n\r\n async before(ctx: MiddlewareContext): Promise<void> {\r\n // Check if we should skip\r\n if (skip?.(ctx)) {\r\n ctx.metadata.set('rateLimitSkipped', true);\r\n return;\r\n }\r\n\r\n const key = `ratelimit:${keyGenerator(ctx)}`;\r\n const [count, resetAtMs] = await storage.increment(key, windowMs);\r\n const resetAt = new Date(resetAtMs);\r\n const remaining = Math.max(0, limit - count);\r\n const retryAfter = Math.ceil((resetAtMs - Date.now()) / 1000);\r\n\r\n // Store rate limit info in metadata for headers\r\n const info: RateLimitInfo = { limit, remaining, resetAt };\r\n ctx.metadata.set('rateLimit', info);\r\n\r\n if (count > limit) {\r\n onRateLimited?.(ctx, info);\r\n\r\n ctx.logger.warn('Rate limit exceeded', {\r\n correlationId: ctx.correlationId,\r\n tenantId: ctx.tenantId,\r\n key,\r\n count,\r\n limit,\r\n resetAt,\r\n });\r\n\r\n if (throwOnLimit) {\r\n throw new RateLimitError(message, { retryAfter, limit, remaining, resetAt });\r\n }\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Default key generator - uses tenant, service, and operation\r\n */\r\nfunction defaultKeyGenerator(ctx: MiddlewareContext): string {\r\n const parts = [ctx.service, ctx.operation];\r\n\r\n if (ctx.tenantId) {\r\n parts.unshift(ctx.tenantId);\r\n }\r\n\r\n return parts.join(':');\r\n}\r\n\r\n/**\r\n * Create an IP-based rate limiter key generator\r\n */\r\nexport function createIpKeyGenerator(\r\n getIp: (ctx: MiddlewareContext) => string | undefined\r\n): (ctx: MiddlewareContext) => string {\r\n return (ctx: MiddlewareContext) => {\r\n const ip = getIp(ctx) ?? 'unknown';\r\n return `ip:${ip}:${ctx.service}:${ctx.operation}`;\r\n };\r\n}\r\n\r\n/**\r\n * Create a user-based rate limiter key generator\r\n */\r\nexport function createUserKeyGenerator(\r\n getUserId: (ctx: MiddlewareContext) => string | undefined\r\n): (ctx: MiddlewareContext) => string {\r\n return (ctx: MiddlewareContext) => {\r\n const userId = getUserId(ctx) ?? 'anonymous';\r\n return `user:${userId}:${ctx.service}:${ctx.operation}`;\r\n };\r\n}\r\n\r\n/**\r\n * Sliding window rate limiter options\r\n */\r\nexport interface SlidingWindowRateLimitOptions extends Omit<RateLimitOptions, 'algorithm'> {\r\n /** Number of sub-windows (more = more accurate, more memory) */\r\n precision?: number;\r\n}\r\n\r\n/**\r\n * Token bucket rate limiter options\r\n */\r\nexport interface TokenBucketOptions {\r\n /** Bucket capacity (max tokens) */\r\n capacity: number;\r\n\r\n /** Token refill rate per second */\r\n refillRate: number;\r\n\r\n /** Storage backend */\r\n storage?: RateLimiterStorage;\r\n\r\n /** Key generator function */\r\n keyGenerator?: (ctx: MiddlewareContext) => string;\r\n\r\n /** Skip rate limiting for certain requests */\r\n skip?: (ctx: MiddlewareContext) => boolean;\r\n\r\n /** Whether to throw error or just log */\r\n throwOnLimit?: boolean;\r\n\r\n /** Custom message for rate limit error */\r\n message?: string;\r\n}\r\n\r\n/**\r\n * Pre-configured rate limit presets\r\n */\r\nexport const RateLimitPresets = {\r\n /** Standard API rate limit: 100 req/min */\r\n standard: { limit: 100, windowMs: 60 * 1000 },\r\n\r\n /** Strict rate limit: 10 req/min */\r\n strict: { limit: 10, windowMs: 60 * 1000 },\r\n\r\n /** Relaxed rate limit: 1000 req/min */\r\n relaxed: { limit: 1000, windowMs: 60 * 1000 },\r\n\r\n /** Burst protection: 50 req/sec */\r\n burst: { limit: 50, windowMs: 1000 },\r\n\r\n /** Auth rate limit: 5 attempts/15 min */\r\n auth: { limit: 5, windowMs: 15 * 60 * 1000 },\r\n\r\n /** Expensive operations: 10 req/hour */\r\n expensive: { limit: 10, windowMs: 60 * 60 * 1000 },\r\n} as const;\r\n\r\n/**\r\n * Sanitize args for logging (remove sensitive data)\r\n */\r\nfunction sanitizeArgs(args: unknown): unknown {\r\n if (args === null || args === undefined) return args;\r\n\r\n if (typeof args !== 'object') return args;\r\n\r\n if (Array.isArray(args)) {\r\n return args.map(sanitizeArgs);\r\n }\r\n\r\n const sanitized: Record<string, unknown> = {};\r\n const sensitiveKeys = ['password', 'token', 'secret', 'key', 'authorization', 'credential'];\r\n\r\n for (const [key, value] of Object.entries(args as Record<string, unknown>)) {\r\n if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk))) {\r\n sanitized[key] = '[REDACTED]';\r\n } else if (typeof value === 'object' && value !== null) {\r\n sanitized[key] = sanitizeArgs(value);\r\n } else {\r\n sanitized[key] = value;\r\n }\r\n }\r\n\r\n return sanitized;\r\n}\r\n","/**\r\n * Hook Registry Implementation\r\n */\r\n\r\nimport type { PlatformHooks, HookRegistry } from './types';\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Create a hook registry\r\n */\r\nexport function createHookRegistry(logger: ILogger = new NoopLogger()): HookRegistry {\r\n let hooks: PlatformHooks = {};\r\n\r\n const registry: HookRegistry = {\r\n register(newHooks: Partial<PlatformHooks>): void {\r\n hooks = { ...hooks, ...newHooks };\r\n logger.debug('Hooks registered', {\r\n hookNames: Object.keys(newHooks),\r\n });\r\n },\r\n\r\n clear(): void {\r\n hooks = {};\r\n logger.debug('Hooks cleared');\r\n },\r\n\r\n async execute<K extends keyof PlatformHooks>(\r\n hookName: K,\r\n ...args: Parameters<NonNullable<PlatformHooks[K]>>\r\n ): Promise<void> {\r\n const hook = hooks[hookName];\r\n\r\n if (!hook) {\r\n return;\r\n }\r\n\r\n try {\r\n // @ts-expect-error - TypeScript can't infer the correct function signature\r\n await hook(...args);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Hook ${String(hookName)} failed`, {\r\n error,\r\n hookName: String(hookName),\r\n });\r\n // Don't throw - hooks should not break the main flow\r\n }\r\n },\r\n\r\n getHooks(): PlatformHooks {\r\n return { ...hooks };\r\n },\r\n };\r\n\r\n return registry;\r\n}\r\n\r\n/**\r\n * Compose multiple hook registries\r\n */\r\nexport function composeHookRegistries(...registries: HookRegistry[]): HookRegistry {\r\n const logger = new NoopLogger();\r\n\r\n return {\r\n register(hooks: Partial<PlatformHooks>): void {\r\n registries.forEach((r) => r.register(hooks));\r\n },\r\n\r\n clear(): void {\r\n registries.forEach((r) => r.clear());\r\n },\r\n\r\n async execute<K extends keyof PlatformHooks>(\r\n hookName: K,\r\n ...args: Parameters<NonNullable<PlatformHooks[K]>>\r\n ): Promise<void> {\r\n for (const registry of registries) {\r\n await registry.execute(hookName, ...args);\r\n }\r\n },\r\n\r\n getHooks(): PlatformHooks {\r\n return registries.reduce((acc, r) => ({ ...acc, ...r.getHooks() }), {} as PlatformHooks);\r\n },\r\n };\r\n}\r\n","/**\r\n * Retry Pattern Implementation\r\n *\r\n * Provides configurable retry logic with exponential backoff and jitter.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Options for retry behavior\r\n */\r\nexport interface RetryOptions {\r\n /**\r\n * Maximum number of retry attempts\r\n * @default 3\r\n */\r\n maxAttempts: number;\r\n\r\n /**\r\n * Initial delay between retries in milliseconds\r\n * @default 100\r\n */\r\n baseDelay: number;\r\n\r\n /**\r\n * Maximum delay between retries in milliseconds\r\n * @default 10000\r\n */\r\n maxDelay: number;\r\n\r\n /**\r\n * Multiplier for exponential backoff\r\n * @default 2\r\n */\r\n backoffMultiplier: number;\r\n\r\n /**\r\n * Whether to add random jitter to delays\r\n * @default true\r\n */\r\n jitter: boolean;\r\n\r\n /**\r\n * Maximum jitter in milliseconds\r\n * @default 100\r\n */\r\n maxJitter: number;\r\n\r\n /**\r\n * Function to determine if error is retryable\r\n * @default All errors are retryable\r\n */\r\n retryIf?: (error: Error) => boolean;\r\n\r\n /**\r\n * Function to determine if error is non-retryable\r\n * Takes precedence over retryIf\r\n */\r\n abortIf?: (error: Error) => boolean;\r\n\r\n /**\r\n * Callback on each retry attempt\r\n */\r\n onRetry?: (error: Error, attempt: number, delay: number) => void;\r\n\r\n /**\r\n * Logger for retry operations\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Default retry options\r\n */\r\nexport const DEFAULT_RETRY_OPTIONS: RetryOptions = {\r\n maxAttempts: 3,\r\n baseDelay: 100,\r\n maxDelay: 10000,\r\n backoffMultiplier: 2,\r\n jitter: true,\r\n maxJitter: 100,\r\n};\r\n\r\n/**\r\n * Result of a retry operation\r\n */\r\nexport interface RetryResult<T> {\r\n /** Whether the operation succeeded */\r\n success: boolean;\r\n\r\n /** The result if successful */\r\n result?: T;\r\n\r\n /** The final error if all attempts failed */\r\n error?: Error;\r\n\r\n /** Number of attempts made */\r\n attempts: number;\r\n\r\n /** Total time spent in milliseconds */\r\n totalTime: number;\r\n}\r\n\r\n/**\r\n * Sleep for specified milliseconds\r\n */\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Calculate delay for a given attempt\r\n */\r\nfunction calculateDelay(attempt: number, options: RetryOptions): number {\r\n // Exponential backoff\r\n let delay = options.baseDelay * Math.pow(options.backoffMultiplier, attempt - 1);\r\n\r\n // Cap at max delay\r\n delay = Math.min(delay, options.maxDelay);\r\n\r\n // Add jitter\r\n if (options.jitter) {\r\n const jitter = Math.random() * options.maxJitter;\r\n delay += jitter;\r\n }\r\n\r\n return Math.floor(delay);\r\n}\r\n\r\n/**\r\n * Execute a function with retry logic\r\n */\r\nexport async function withRetry<T>(\r\n fn: () => Promise<T>,\r\n options: Partial<RetryOptions> = {}\r\n): Promise<T> {\r\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\r\n const logger = opts.logger ?? new NoopLogger();\r\n\r\n let lastError: Error | undefined;\r\n let delay = opts.baseDelay;\r\n\r\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (error) {\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Check if error is non-retryable\r\n if (opts.abortIf?.(lastError)) {\r\n logger.debug('Retry aborted - non-retryable error', {\r\n attempt,\r\n error: lastError,\r\n });\r\n throw lastError;\r\n }\r\n\r\n // Check if error is retryable\r\n if (opts.retryIf && !opts.retryIf(lastError)) {\r\n logger.debug('Retry aborted - error not retryable', {\r\n attempt,\r\n error: lastError,\r\n });\r\n throw lastError;\r\n }\r\n\r\n // If this was the last attempt, throw\r\n if (attempt >= opts.maxAttempts) {\r\n logger.warn('All retry attempts exhausted', {\r\n attempts: attempt,\r\n error: lastError,\r\n });\r\n throw lastError;\r\n }\r\n\r\n // Calculate delay for next attempt\r\n delay = calculateDelay(attempt, opts);\r\n\r\n logger.debug('Retrying operation', {\r\n attempt,\r\n maxAttempts: opts.maxAttempts,\r\n delay,\r\n error: lastError,\r\n });\r\n\r\n // Call retry callback\r\n opts.onRetry?.(lastError, attempt, delay);\r\n\r\n // Wait before next attempt\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n // This should never happen, but TypeScript needs it\r\n throw lastError ?? new Error('Retry failed with no error');\r\n}\r\n\r\n/**\r\n * Execute with retry and return detailed result\r\n */\r\nexport async function withRetryResult<T>(\r\n fn: () => Promise<T>,\r\n options: Partial<RetryOptions> = {}\r\n): Promise<RetryResult<T>> {\r\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\r\n const startTime = Date.now();\r\n\r\n let attempts = 0;\r\n let lastError: Error | undefined;\r\n let delay = opts.baseDelay;\r\n\r\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\r\n attempts = attempt;\r\n\r\n try {\r\n const result = await fn();\r\n return {\r\n success: true,\r\n result,\r\n attempts,\r\n totalTime: Date.now() - startTime,\r\n };\r\n } catch (error) {\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (opts.abortIf?.(lastError)) {\r\n break;\r\n }\r\n\r\n if (opts.retryIf && !opts.retryIf(lastError)) {\r\n break;\r\n }\r\n\r\n if (attempt >= opts.maxAttempts) {\r\n break;\r\n }\r\n\r\n delay = calculateDelay(attempt, opts);\r\n opts.onRetry?.(lastError, attempt, delay);\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n return {\r\n success: false,\r\n error: lastError,\r\n attempts,\r\n totalTime: Date.now() - startTime,\r\n };\r\n}\r\n\r\n/**\r\n * Create a retryable version of a function\r\n */\r\nexport function retryable<TArgs extends unknown[], TResult>(\r\n fn: (...args: TArgs) => Promise<TResult>,\r\n options: Partial<RetryOptions> = {}\r\n): (...args: TArgs) => Promise<TResult> {\r\n return (...args: TArgs) => withRetry(() => fn(...args), options);\r\n}\r\n\r\n/**\r\n * Common retry predicates\r\n */\r\nexport const RetryPredicates = {\r\n /**\r\n * Retry on network errors\r\n */\r\n networkErrors: (error: Error): boolean => {\r\n const networkErrorCodes = [\r\n 'ECONNRESET',\r\n 'ECONNREFUSED',\r\n 'ETIMEDOUT',\r\n 'ENOTFOUND',\r\n 'EAI_AGAIN',\r\n 'EHOSTUNREACH',\r\n 'ENETUNREACH',\r\n ];\r\n\r\n const errorCode = (error as NodeJS.ErrnoException).code;\r\n if (errorCode && networkErrorCodes.includes(errorCode)) {\r\n return true;\r\n }\r\n\r\n // Check for common network error messages\r\n const message = error.message.toLowerCase();\r\n return (\r\n message.includes('network') ||\r\n message.includes('timeout') ||\r\n message.includes('connection') ||\r\n message.includes('socket')\r\n );\r\n },\r\n\r\n /**\r\n * Retry on HTTP 5xx errors\r\n */\r\n serverErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode !== undefined && statusCode >= 500 && statusCode < 600;\r\n },\r\n\r\n /**\r\n * Retry on HTTP 429 (rate limit) errors\r\n */\r\n rateLimitErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode === 429;\r\n },\r\n\r\n /**\r\n * Retry on database deadlock errors\r\n */\r\n deadlockErrors: (error: Error): boolean => {\r\n const message = error.message.toLowerCase();\r\n return message.includes('deadlock') || message.includes('lock wait timeout');\r\n },\r\n\r\n /**\r\n * Never retry on authentication errors\r\n */\r\n authenticationErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode === 401 || statusCode === 403;\r\n },\r\n\r\n /**\r\n * Never retry on validation errors\r\n */\r\n validationErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode === 400 || statusCode === 422;\r\n },\r\n};\r\n\r\n/**\r\n * Common retry configurations\r\n */\r\nexport const RetryConfigs = {\r\n /**\r\n * Fast retry for quick failures\r\n */\r\n fast: {\r\n maxAttempts: 3,\r\n baseDelay: 50,\r\n maxDelay: 500,\r\n backoffMultiplier: 2,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Standard retry configuration\r\n */\r\n standard: {\r\n maxAttempts: 3,\r\n baseDelay: 100,\r\n maxDelay: 5000,\r\n backoffMultiplier: 2,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Aggressive retry for critical operations\r\n */\r\n aggressive: {\r\n maxAttempts: 5,\r\n baseDelay: 200,\r\n maxDelay: 30000,\r\n backoffMultiplier: 2,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Conservative retry for rate-limited APIs\r\n */\r\n rateLimited: {\r\n maxAttempts: 3,\r\n baseDelay: 1000,\r\n maxDelay: 60000,\r\n backoffMultiplier: 3,\r\n jitter: true,\r\n maxJitter: 500,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Database retry configuration\r\n */\r\n database: {\r\n maxAttempts: 3,\r\n baseDelay: 100,\r\n maxDelay: 5000,\r\n backoffMultiplier: 2,\r\n retryIf: (error: Error) =>\r\n RetryPredicates.networkErrors(error) || RetryPredicates.deadlockErrors(error),\r\n abortIf: RetryPredicates.validationErrors,\r\n } as Partial<RetryOptions>,\r\n};\r\n","/**\r\n * Circuit Breaker Pattern Implementation\r\n *\r\n * Prevents cascading failures by temporarily blocking calls to a failing service.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Circuit breaker states\r\n */\r\nexport type CircuitState = 'closed' | 'open' | 'half-open';\r\n\r\n/**\r\n * Options for circuit breaker behavior\r\n */\r\nexport interface CircuitBreakerOptions {\r\n /**\r\n * Name of the circuit (for logging)\r\n */\r\n name: string;\r\n\r\n /**\r\n * Number of failures before opening the circuit\r\n * @default 5\r\n */\r\n failureThreshold: number;\r\n\r\n /**\r\n * Time in milliseconds before attempting to close the circuit\r\n * @default 30000\r\n */\r\n resetTimeout: number;\r\n\r\n /**\r\n * Number of successful requests needed in half-open state to close the circuit\r\n * @default 3\r\n */\r\n successThreshold: number;\r\n\r\n /**\r\n * Time window in milliseconds for counting failures\r\n * @default 60000\r\n */\r\n failureWindow: number;\r\n\r\n /**\r\n * Function to determine if error should trip the circuit\r\n * @default All errors trip the circuit\r\n */\r\n shouldTrip?: (error: Error) => boolean;\r\n\r\n /**\r\n * Callback when circuit state changes\r\n */\r\n onStateChange?: (from: CircuitState, to: CircuitState) => void;\r\n\r\n /**\r\n * Callback when circuit opens\r\n */\r\n onOpen?: (failures: number, lastError: Error) => void;\r\n\r\n /**\r\n * Callback when circuit closes\r\n */\r\n onClose?: () => void;\r\n\r\n /**\r\n * Callback when request is rejected due to open circuit\r\n */\r\n onReject?: (state: CircuitState) => void;\r\n\r\n /**\r\n * Logger for circuit breaker events\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Default circuit breaker options\r\n */\r\nexport const DEFAULT_CIRCUIT_BREAKER_OPTIONS: Omit<CircuitBreakerOptions, 'name'> = {\r\n failureThreshold: 5,\r\n resetTimeout: 30000,\r\n successThreshold: 3,\r\n failureWindow: 60000,\r\n};\r\n\r\n/**\r\n * Error thrown when circuit is open\r\n */\r\nexport class CircuitOpenError extends Error {\r\n override readonly name = 'CircuitOpenError';\r\n readonly circuitName: string;\r\n readonly state: CircuitState;\r\n readonly nextAttemptAt: Date;\r\n\r\n constructor(circuitName: string, state: CircuitState, resetTimeout: number) {\r\n super(`Circuit \"${circuitName}\" is ${state}. Retry after ${resetTimeout}ms.`);\r\n this.circuitName = circuitName;\r\n this.state = state;\r\n this.nextAttemptAt = new Date(Date.now() + resetTimeout);\r\n }\r\n}\r\n\r\n/**\r\n * Circuit breaker statistics\r\n */\r\nexport interface CircuitBreakerStats {\r\n state: CircuitState;\r\n failures: number;\r\n successes: number;\r\n lastFailure?: Date;\r\n lastSuccess?: Date;\r\n lastStateChange?: Date;\r\n totalRequests: number;\r\n rejectedRequests: number;\r\n}\r\n\r\n/**\r\n * Circuit breaker implementation\r\n */\r\nexport class CircuitBreaker {\r\n private state: CircuitState = 'closed';\r\n private failures: number = 0;\r\n private successes: number = 0;\r\n private failureTimestamps: number[] = [];\r\n private lastFailure?: Date;\r\n private lastSuccess?: Date;\r\n private lastStateChange?: Date;\r\n private lastOpenedAt?: Date;\r\n private totalRequests: number = 0;\r\n private rejectedRequests: number = 0;\r\n private lastError?: Error;\r\n private readonly options: CircuitBreakerOptions;\r\n private readonly logger: ILogger;\r\n\r\n constructor(options: CircuitBreakerOptions) {\r\n this.options = {\r\n ...DEFAULT_CIRCUIT_BREAKER_OPTIONS,\r\n ...options,\r\n };\r\n this.logger = options.logger ?? new NoopLogger();\r\n }\r\n\r\n /**\r\n * Execute a function with circuit breaker protection\r\n */\r\n async execute<T>(fn: () => Promise<T>): Promise<T> {\r\n this.totalRequests++;\r\n\r\n // Check if circuit allows the request\r\n if (!this.canExecute()) {\r\n this.rejectedRequests++;\r\n this.options.onReject?.(this.state);\r\n\r\n throw new CircuitOpenError(\r\n this.options.name,\r\n this.state,\r\n this.getRemainingTimeout()\r\n );\r\n }\r\n\r\n try {\r\n const result = await fn();\r\n this.onSuccess();\r\n return result;\r\n } catch (error) {\r\n this.onFailure(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Check if circuit allows execution\r\n */\r\n canExecute(): boolean {\r\n switch (this.state) {\r\n case 'closed':\r\n return true;\r\n\r\n case 'open':\r\n // Check if reset timeout has passed\r\n if (this.shouldAttemptReset()) {\r\n this.transitionTo('half-open');\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'half-open':\r\n // Allow limited requests in half-open state\r\n return true;\r\n\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Record a successful execution\r\n */\r\n private onSuccess(): void {\r\n this.lastSuccess = new Date();\r\n this.successes++;\r\n\r\n switch (this.state) {\r\n case 'half-open':\r\n // Check if we've had enough successes to close\r\n if (this.successes >= this.options.successThreshold) {\r\n this.transitionTo('closed');\r\n }\r\n break;\r\n\r\n case 'closed':\r\n // Reset failure count on success\r\n this.failures = 0;\r\n this.failureTimestamps = [];\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Record a failed execution\r\n */\r\n private onFailure(error: Error): void {\r\n // Check if this error should trip the circuit\r\n if (this.options.shouldTrip && !this.options.shouldTrip(error)) {\r\n return;\r\n }\r\n\r\n this.lastError = error;\r\n this.lastFailure = new Date();\r\n this.failures++;\r\n\r\n const now = Date.now();\r\n this.failureTimestamps.push(now);\r\n\r\n // Remove old failures outside the window\r\n const windowStart = now - this.options.failureWindow;\r\n this.failureTimestamps = this.failureTimestamps.filter((ts) => ts > windowStart);\r\n\r\n switch (this.state) {\r\n case 'closed':\r\n // Check if we've hit the failure threshold\r\n if (this.failureTimestamps.length >= this.options.failureThreshold) {\r\n this.transitionTo('open');\r\n this.options.onOpen?.(this.failures, error);\r\n }\r\n break;\r\n\r\n case 'half-open':\r\n // Any failure in half-open state reopens the circuit\r\n this.transitionTo('open');\r\n this.options.onOpen?.(this.failures, error);\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Transition to a new state\r\n */\r\n private transitionTo(newState: CircuitState): void {\r\n const oldState = this.state;\r\n\r\n if (oldState === newState) return;\r\n\r\n this.state = newState;\r\n this.lastStateChange = new Date();\r\n\r\n this.logger.info(`Circuit \"${this.options.name}\" state change`, {\r\n from: oldState,\r\n to: newState,\r\n failures: this.failures,\r\n successes: this.successes,\r\n });\r\n\r\n this.options.onStateChange?.(oldState, newState);\r\n\r\n switch (newState) {\r\n case 'open':\r\n this.lastOpenedAt = new Date();\r\n this.successes = 0;\r\n break;\r\n\r\n case 'half-open':\r\n this.successes = 0;\r\n break;\r\n\r\n case 'closed':\r\n this.failures = 0;\r\n this.failureTimestamps = [];\r\n this.successes = 0;\r\n this.options.onClose?.();\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Check if reset timeout has passed\r\n */\r\n private shouldAttemptReset(): boolean {\r\n if (!this.lastOpenedAt) return true;\r\n\r\n const elapsed = Date.now() - this.lastOpenedAt.getTime();\r\n return elapsed >= this.options.resetTimeout;\r\n }\r\n\r\n /**\r\n * Get remaining time until reset attempt\r\n */\r\n private getRemainingTimeout(): number {\r\n if (!this.lastOpenedAt) return 0;\r\n\r\n const elapsed = Date.now() - this.lastOpenedAt.getTime();\r\n return Math.max(0, this.options.resetTimeout - elapsed);\r\n }\r\n\r\n /**\r\n * Get current circuit state\r\n */\r\n getState(): CircuitState {\r\n return this.state;\r\n }\r\n\r\n /**\r\n * Get circuit breaker statistics\r\n */\r\n getStats(): CircuitBreakerStats {\r\n return {\r\n state: this.state,\r\n failures: this.failures,\r\n successes: this.successes,\r\n lastFailure: this.lastFailure,\r\n lastSuccess: this.lastSuccess,\r\n lastStateChange: this.lastStateChange,\r\n totalRequests: this.totalRequests,\r\n rejectedRequests: this.rejectedRequests,\r\n };\r\n }\r\n\r\n /**\r\n * Manually reset the circuit to closed state\r\n */\r\n reset(): void {\r\n this.transitionTo('closed');\r\n }\r\n\r\n /**\r\n * Manually trip the circuit to open state\r\n */\r\n trip(): void {\r\n this.transitionTo('open');\r\n }\r\n\r\n /**\r\n * Check if circuit is open\r\n */\r\n isOpen(): boolean {\r\n return this.state === 'open';\r\n }\r\n\r\n /**\r\n * Check if circuit is closed\r\n */\r\n isClosed(): boolean {\r\n return this.state === 'closed';\r\n }\r\n\r\n /**\r\n * Check if circuit is half-open\r\n */\r\n isHalfOpen(): boolean {\r\n return this.state === 'half-open';\r\n }\r\n}\r\n\r\n/**\r\n * Create a circuit breaker\r\n */\r\nexport function createCircuitBreaker(options: CircuitBreakerOptions): CircuitBreaker {\r\n return new CircuitBreaker(options);\r\n}\r\n\r\n/**\r\n * Circuit breaker registry for managing multiple circuits\r\n */\r\nexport class CircuitBreakerRegistry {\r\n private circuits: Map<string, CircuitBreaker> = new Map();\r\n private readonly logger: ILogger;\r\n private readonly defaultOptions: Partial<CircuitBreakerOptions>;\r\n\r\n constructor(\r\n options: {\r\n logger?: ILogger;\r\n defaults?: Partial<CircuitBreakerOptions>;\r\n } = {}\r\n ) {\r\n this.logger = options.logger ?? new NoopLogger();\r\n this.defaultOptions = options.defaults ?? {};\r\n }\r\n\r\n /**\r\n * Get or create a circuit breaker\r\n */\r\n get(name: string, options?: Partial<CircuitBreakerOptions>): CircuitBreaker {\r\n let circuit = this.circuits.get(name);\r\n\r\n if (!circuit) {\r\n circuit = new CircuitBreaker({\r\n ...DEFAULT_CIRCUIT_BREAKER_OPTIONS,\r\n ...this.defaultOptions,\r\n ...options,\r\n name,\r\n logger: options?.logger ?? this.logger,\r\n });\r\n this.circuits.set(name, circuit);\r\n }\r\n\r\n return circuit;\r\n }\r\n\r\n /**\r\n * Execute with a named circuit breaker\r\n */\r\n async execute<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n options?: Partial<CircuitBreakerOptions>\r\n ): Promise<T> {\r\n const circuit = this.get(name, options);\r\n return circuit.execute(fn);\r\n }\r\n\r\n /**\r\n * Get all circuit statistics\r\n */\r\n getAllStats(): Record<string, CircuitBreakerStats> {\r\n const stats: Record<string, CircuitBreakerStats> = {};\r\n\r\n for (const [name, circuit] of this.circuits) {\r\n stats[name] = circuit.getStats();\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n /**\r\n * Reset all circuits\r\n */\r\n resetAll(): void {\r\n for (const circuit of this.circuits.values()) {\r\n circuit.reset();\r\n }\r\n }\r\n\r\n /**\r\n * Clear all circuits\r\n */\r\n clear(): void {\r\n this.circuits.clear();\r\n }\r\n}\r\n","/**\r\n * Timeout Pattern Implementation\r\n *\r\n * Enforces time limits on operations to prevent hanging.\r\n */\r\n\r\n/**\r\n * Error thrown when operation times out\r\n */\r\nexport class TimeoutError extends Error {\r\n override readonly name = 'TimeoutError';\r\n readonly operation: string;\r\n readonly timeout: number;\r\n\r\n constructor(operation: string, timeout: number) {\r\n super(`Operation \"${operation}\" timed out after ${timeout}ms`);\r\n this.operation = operation;\r\n this.timeout = timeout;\r\n }\r\n}\r\n\r\n/**\r\n * Options for timeout behavior\r\n */\r\nexport interface TimeoutOptions {\r\n /**\r\n * Timeout in milliseconds\r\n */\r\n timeout: number;\r\n\r\n /**\r\n * Operation name (for error messages)\r\n */\r\n operation?: string;\r\n\r\n /**\r\n * Whether to abort the operation on timeout (if supported)\r\n */\r\n abortOnTimeout?: boolean;\r\n}\r\n\r\n/**\r\n * Execute a function with a timeout\r\n */\r\nexport async function withTimeout<T>(\r\n fn: () => Promise<T>,\r\n options: TimeoutOptions | number\r\n): Promise<T> {\r\n const opts: TimeoutOptions =\r\n typeof options === 'number' ? { timeout: options } : options;\r\n\r\n const { timeout, operation = 'unknown', abortOnTimeout = false } = opts;\r\n\r\n return new Promise<T>((resolve, reject) => {\r\n let timeoutId: NodeJS.Timeout | undefined;\r\n let settled = false;\r\n\r\n // Create abort controller if needed\r\n const abortController = abortOnTimeout ? new AbortController() : undefined;\r\n\r\n // Set up timeout\r\n timeoutId = setTimeout(() => {\r\n if (!settled) {\r\n settled = true;\r\n abortController?.abort();\r\n reject(new TimeoutError(operation, timeout));\r\n }\r\n }, timeout);\r\n\r\n // Execute the function\r\n fn()\r\n .then((result) => {\r\n if (!settled) {\r\n settled = true;\r\n clearTimeout(timeoutId);\r\n resolve(result);\r\n }\r\n })\r\n .catch((error) => {\r\n if (!settled) {\r\n settled = true;\r\n clearTimeout(timeoutId);\r\n reject(error);\r\n }\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Create a timeout-wrapped version of a function\r\n */\r\nexport function withTimeoutWrapper<TArgs extends unknown[], TResult>(\r\n fn: (...args: TArgs) => Promise<TResult>,\r\n options: TimeoutOptions | number\r\n): (...args: TArgs) => Promise<TResult> {\r\n return (...args: TArgs) =>\r\n withTimeout(() => fn(...args), options);\r\n}\r\n\r\n/**\r\n * Race a promise against a timeout\r\n */\r\nexport async function raceTimeout<T>(\r\n promise: Promise<T>,\r\n timeout: number,\r\n operation?: string\r\n): Promise<T> {\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n setTimeout(() => {\r\n reject(new TimeoutError(operation ?? 'promise', timeout));\r\n }, timeout);\r\n });\r\n\r\n return Promise.race([promise, timeoutPromise]);\r\n}\r\n\r\n/**\r\n * Default timeouts for different operations\r\n */\r\nexport const DefaultTimeouts = {\r\n /** Quick operations like cache lookups */\r\n fast: 1000,\r\n\r\n /** Standard database queries */\r\n database: 5000,\r\n\r\n /** API calls to external services */\r\n api: 10000,\r\n\r\n /** File uploads/downloads */\r\n storage: 30000,\r\n\r\n /** Email sending */\r\n email: 15000,\r\n\r\n /** Long-running background jobs */\r\n job: 300000,\r\n};\r\n","/**\r\n * Bulkhead Pattern Implementation\r\n *\r\n * Isolates failures by limiting concurrent operations.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Options for bulkhead behavior\r\n */\r\nexport interface BulkheadOptions {\r\n /**\r\n * Name of the bulkhead (for logging)\r\n */\r\n name: string;\r\n\r\n /**\r\n * Maximum concurrent executions allowed\r\n * @default 10\r\n */\r\n maxConcurrent: number;\r\n\r\n /**\r\n * Maximum queue size for waiting requests\r\n * @default 100\r\n */\r\n maxQueue: number;\r\n\r\n /**\r\n * Timeout for queued requests in milliseconds\r\n * @default 30000\r\n */\r\n queueTimeout: number;\r\n\r\n /**\r\n * Callback when execution is rejected\r\n */\r\n onReject?: (reason: 'concurrent' | 'queue' | 'timeout') => void;\r\n\r\n /**\r\n * Logger for bulkhead events\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Default bulkhead options\r\n */\r\nexport const DEFAULT_BULKHEAD_OPTIONS: Omit<BulkheadOptions, 'name'> = {\r\n maxConcurrent: 10,\r\n maxQueue: 100,\r\n queueTimeout: 30000,\r\n};\r\n\r\n/**\r\n * Error thrown when bulkhead rejects a request\r\n */\r\nexport class BulkheadRejectedError extends Error {\r\n override readonly name = 'BulkheadRejectedError';\r\n readonly bulkheadName: string;\r\n readonly reason: 'concurrent' | 'queue' | 'timeout';\r\n\r\n constructor(bulkheadName: string, reason: 'concurrent' | 'queue' | 'timeout') {\r\n const messages = {\r\n concurrent: `Bulkhead \"${bulkheadName}\" rejected: max concurrent limit reached`,\r\n queue: `Bulkhead \"${bulkheadName}\" rejected: queue is full`,\r\n timeout: `Bulkhead \"${bulkheadName}\" rejected: queue timeout exceeded`,\r\n };\r\n super(messages[reason]);\r\n this.bulkheadName = bulkheadName;\r\n this.reason = reason;\r\n }\r\n}\r\n\r\n/**\r\n * Bulkhead statistics\r\n */\r\nexport interface BulkheadStats {\r\n activeCalls: number;\r\n queuedCalls: number;\r\n maxConcurrent: number;\r\n maxQueue: number;\r\n totalExecutions: number;\r\n rejectedCalls: number;\r\n availableSlots: number;\r\n availableQueueSlots: number;\r\n}\r\n\r\n/**\r\n * Queued request\r\n */\r\ninterface QueuedRequest<T> {\r\n fn: () => Promise<T>;\r\n resolve: (value: T) => void;\r\n reject: (error: Error) => void;\r\n enqueuedAt: number;\r\n timeoutId?: NodeJS.Timeout;\r\n}\r\n\r\n/**\r\n * Bulkhead implementation\r\n */\r\nexport class Bulkhead {\r\n private activeCalls = 0;\r\n private queue: QueuedRequest<unknown>[] = [];\r\n private totalExecutions = 0;\r\n private rejectedCalls = 0;\r\n private readonly options: Required<Omit<BulkheadOptions, 'onReject' | 'logger'>> &\r\n Pick<BulkheadOptions, 'onReject'>;\r\n private readonly logger: ILogger;\r\n\r\n constructor(options: BulkheadOptions) {\r\n this.options = {\r\n ...DEFAULT_BULKHEAD_OPTIONS,\r\n ...options,\r\n };\r\n this.logger = options.logger ?? new NoopLogger();\r\n }\r\n\r\n /**\r\n * Execute a function with bulkhead protection\r\n */\r\n async execute<T>(fn: () => Promise<T>): Promise<T> {\r\n this.totalExecutions++;\r\n\r\n // Check if we can execute immediately\r\n if (this.activeCalls < this.options.maxConcurrent) {\r\n return this.runExecution(fn);\r\n }\r\n\r\n // Check if queue is full\r\n if (this.queue.length >= this.options.maxQueue) {\r\n this.rejectedCalls++;\r\n this.options.onReject?.('queue');\r\n throw new BulkheadRejectedError(this.options.name, 'queue');\r\n }\r\n\r\n // Queue the request\r\n return this.queueExecution(fn);\r\n }\r\n\r\n /**\r\n * Run an execution immediately\r\n */\r\n private async runExecution<T>(fn: () => Promise<T>): Promise<T> {\r\n this.activeCalls++;\r\n\r\n try {\r\n const result = await fn();\r\n return result;\r\n } finally {\r\n this.activeCalls--;\r\n this.processQueue();\r\n }\r\n }\r\n\r\n /**\r\n * Queue a request for later execution\r\n */\r\n private queueExecution<T>(fn: () => Promise<T>): Promise<T> {\r\n return new Promise<T>((resolve, reject) => {\r\n const request: QueuedRequest<T> = {\r\n fn,\r\n resolve,\r\n reject,\r\n enqueuedAt: Date.now(),\r\n };\r\n\r\n // Set up timeout\r\n request.timeoutId = setTimeout(() => {\r\n const index = this.queue.indexOf(request as QueuedRequest<unknown>);\r\n if (index !== -1) {\r\n this.queue.splice(index, 1);\r\n this.rejectedCalls++;\r\n this.options.onReject?.('timeout');\r\n reject(new BulkheadRejectedError(this.options.name, 'timeout'));\r\n }\r\n }, this.options.queueTimeout);\r\n\r\n this.queue.push(request as QueuedRequest<unknown>);\r\n\r\n this.logger.debug(`Request queued in bulkhead \"${this.options.name}\"`, {\r\n queueSize: this.queue.length,\r\n activeCalls: this.activeCalls,\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Process queued requests\r\n */\r\n private processQueue(): void {\r\n while (this.activeCalls < this.options.maxConcurrent && this.queue.length > 0) {\r\n const request = this.queue.shift();\r\n if (!request) break;\r\n\r\n // Clear timeout\r\n if (request.timeoutId) {\r\n clearTimeout(request.timeoutId);\r\n }\r\n\r\n // Run the execution\r\n this.activeCalls++;\r\n\r\n request\r\n .fn()\r\n .then((result) => {\r\n request.resolve(result);\r\n })\r\n .catch((error) => {\r\n request.reject(error);\r\n })\r\n .finally(() => {\r\n this.activeCalls--;\r\n this.processQueue();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Get bulkhead statistics\r\n */\r\n getStats(): BulkheadStats {\r\n return {\r\n activeCalls: this.activeCalls,\r\n queuedCalls: this.queue.length,\r\n maxConcurrent: this.options.maxConcurrent,\r\n maxQueue: this.options.maxQueue,\r\n totalExecutions: this.totalExecutions,\r\n rejectedCalls: this.rejectedCalls,\r\n availableSlots: Math.max(0, this.options.maxConcurrent - this.activeCalls),\r\n availableQueueSlots: Math.max(0, this.options.maxQueue - this.queue.length),\r\n };\r\n }\r\n\r\n /**\r\n * Check if bulkhead is at capacity\r\n */\r\n isAtCapacity(): boolean {\r\n return this.activeCalls >= this.options.maxConcurrent;\r\n }\r\n\r\n /**\r\n * Check if queue is full\r\n */\r\n isQueueFull(): boolean {\r\n return this.queue.length >= this.options.maxQueue;\r\n }\r\n\r\n /**\r\n * Drain the queue (reject all pending)\r\n */\r\n drain(): void {\r\n for (const request of this.queue) {\r\n if (request.timeoutId) {\r\n clearTimeout(request.timeoutId);\r\n }\r\n request.reject(new BulkheadRejectedError(this.options.name, 'queue'));\r\n }\r\n this.queue = [];\r\n }\r\n}\r\n\r\n/**\r\n * Create a bulkhead\r\n */\r\nexport function createBulkhead(options: BulkheadOptions): Bulkhead {\r\n return new Bulkhead(options);\r\n}\r\n\r\n/**\r\n * Bulkhead registry for managing multiple bulkheads\r\n */\r\nexport class BulkheadRegistry {\r\n private bulkheads: Map<string, Bulkhead> = new Map();\r\n private readonly logger: ILogger;\r\n private readonly defaultOptions: Partial<BulkheadOptions>;\r\n\r\n constructor(\r\n options: {\r\n logger?: ILogger;\r\n defaults?: Partial<BulkheadOptions>;\r\n } = {}\r\n ) {\r\n this.logger = options.logger ?? new NoopLogger();\r\n this.defaultOptions = options.defaults ?? {};\r\n }\r\n\r\n /**\r\n * Get or create a bulkhead\r\n */\r\n get(name: string, options?: Partial<BulkheadOptions>): Bulkhead {\r\n let bulkhead = this.bulkheads.get(name);\r\n\r\n if (!bulkhead) {\r\n bulkhead = new Bulkhead({\r\n ...DEFAULT_BULKHEAD_OPTIONS,\r\n ...this.defaultOptions,\r\n ...options,\r\n name,\r\n logger: options?.logger ?? this.logger,\r\n });\r\n this.bulkheads.set(name, bulkhead);\r\n }\r\n\r\n return bulkhead;\r\n }\r\n\r\n /**\r\n * Execute with a named bulkhead\r\n */\r\n async execute<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n options?: Partial<BulkheadOptions>\r\n ): Promise<T> {\r\n const bulkhead = this.get(name, options);\r\n return bulkhead.execute(fn);\r\n }\r\n\r\n /**\r\n * Get all bulkhead statistics\r\n */\r\n getAllStats(): Record<string, BulkheadStats> {\r\n const stats: Record<string, BulkheadStats> = {};\r\n\r\n for (const [name, bulkhead] of this.bulkheads) {\r\n stats[name] = bulkhead.getStats();\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n /**\r\n * Drain all bulkheads\r\n */\r\n drainAll(): void {\r\n for (const bulkhead of this.bulkheads.values()) {\r\n bulkhead.drain();\r\n }\r\n }\r\n\r\n /**\r\n * Clear all bulkheads\r\n */\r\n clear(): void {\r\n this.drainAll();\r\n this.bulkheads.clear();\r\n }\r\n}\r\n","/**\r\n * Fallback Pattern Implementation\r\n *\r\n * Provides fallback strategies when primary operations fail.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Fallback options\r\n */\r\nexport interface FallbackOptions<T> {\r\n /**\r\n * Static fallback value\r\n */\r\n value?: T;\r\n\r\n /**\r\n * Fallback function (called with the error)\r\n */\r\n fallbackFn?: (error: Error) => T | Promise<T>;\r\n\r\n /**\r\n * Cache the fallback result\r\n */\r\n cache?: boolean;\r\n\r\n /**\r\n * Cache TTL in milliseconds\r\n */\r\n cacheTTL?: number;\r\n\r\n /**\r\n * Callback when fallback is used\r\n */\r\n onFallback?: (error: Error, fallbackValue: T) => void;\r\n\r\n /**\r\n * Errors to ignore (not trigger fallback)\r\n */\r\n ignoreErrors?: (error: Error) => boolean;\r\n\r\n /**\r\n * Logger for fallback events\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Result of a fallback operation\r\n */\r\nexport interface FallbackResult<T> {\r\n /** The result value */\r\n value: T;\r\n\r\n /** Whether fallback was used */\r\n usedFallback: boolean;\r\n\r\n /** The original error (if fallback was used) */\r\n error?: Error;\r\n\r\n /** Whether the value came from cache */\r\n cached?: boolean;\r\n}\r\n\r\n/**\r\n * Execute with fallback\r\n */\r\nexport async function withFallback<T>(\r\n fn: () => Promise<T>,\r\n options: FallbackOptions<T>\r\n): Promise<T> {\r\n const logger = options.logger ?? new NoopLogger();\r\n\r\n try {\r\n return await fn();\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Check if we should ignore this error\r\n if (options.ignoreErrors?.(err)) {\r\n throw err;\r\n }\r\n\r\n logger.warn('Operation failed, using fallback', {\r\n error: err,\r\n });\r\n\r\n // Get fallback value\r\n let fallbackValue: T;\r\n\r\n if (options.fallbackFn) {\r\n fallbackValue = await options.fallbackFn(err);\r\n } else if (options.value !== undefined) {\r\n fallbackValue = options.value;\r\n } else {\r\n // No fallback defined, rethrow\r\n throw err;\r\n }\r\n\r\n options.onFallback?.(err, fallbackValue);\r\n\r\n return fallbackValue;\r\n }\r\n}\r\n\r\n/**\r\n * Execute with fallback and return detailed result\r\n */\r\nexport async function withFallbackResult<T>(\r\n fn: () => Promise<T>,\r\n options: FallbackOptions<T>\r\n): Promise<FallbackResult<T>> {\r\n const logger = options.logger ?? new NoopLogger();\r\n\r\n try {\r\n const value = await fn();\r\n return {\r\n value,\r\n usedFallback: false,\r\n };\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (options.ignoreErrors?.(err)) {\r\n throw err;\r\n }\r\n\r\n logger.warn('Operation failed, using fallback', {\r\n error: err,\r\n });\r\n\r\n let fallbackValue: T;\r\n\r\n if (options.fallbackFn) {\r\n fallbackValue = await options.fallbackFn(err);\r\n } else if (options.value !== undefined) {\r\n fallbackValue = options.value;\r\n } else {\r\n throw err;\r\n }\r\n\r\n options.onFallback?.(err, fallbackValue);\r\n\r\n return {\r\n value: fallbackValue,\r\n usedFallback: true,\r\n error: err,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create a cached fallback\r\n */\r\nexport function createCachedFallback<T>(\r\n options: {\r\n getValue: () => Promise<T>;\r\n cacheTTL?: number;\r\n logger?: ILogger;\r\n }\r\n): () => Promise<T> {\r\n const { getValue, cacheTTL = 60000 } = options;\r\n const logger = options.logger ?? new NoopLogger();\r\n\r\n let cachedValue: T | undefined;\r\n let cachedAt: number | undefined;\r\n let refreshing = false;\r\n\r\n return async (): Promise<T> => {\r\n // Return cached value if valid\r\n if (cachedValue !== undefined && cachedAt !== undefined) {\r\n const age = Date.now() - cachedAt;\r\n if (age < cacheTTL) {\r\n return cachedValue;\r\n }\r\n\r\n // Cache expired, try to refresh in background\r\n if (!refreshing) {\r\n refreshing = true;\r\n getValue()\r\n .then((value) => {\r\n cachedValue = value;\r\n cachedAt = Date.now();\r\n })\r\n .catch((err) => {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.warn('Failed to refresh cached fallback', {\r\n error,\r\n });\r\n })\r\n .finally(() => {\r\n refreshing = false;\r\n });\r\n }\r\n\r\n // Return stale cache while refreshing\r\n return cachedValue;\r\n }\r\n\r\n // No cache, get fresh value\r\n const value = await getValue();\r\n cachedValue = value;\r\n cachedAt = Date.now();\r\n return value;\r\n };\r\n}\r\n\r\n/**\r\n * Fallback chain - try multiple fallbacks in order\r\n */\r\nexport async function withFallbackChain<T>(\r\n primary: () => Promise<T>,\r\n fallbacks: Array<() => Promise<T>>,\r\n options: {\r\n logger?: ILogger;\r\n onFallback?: (index: number, error: Error) => void;\r\n } = {}\r\n): Promise<T> {\r\n const logger = options.logger ?? new NoopLogger();\r\n const allFns = [primary, ...fallbacks];\r\n\r\n for (let i = 0; i < allFns.length; i++) {\r\n try {\r\n const fn = allFns[i];\r\n if (!fn) continue;\r\n return await fn();\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (i < allFns.length - 1) {\r\n logger.warn(`Fallback ${i} failed, trying next`, {\r\n index: i,\r\n error: err,\r\n });\r\n options.onFallback?.(i, err);\r\n } else {\r\n // Last fallback failed\r\n throw err;\r\n }\r\n }\r\n }\r\n\r\n // This should never happen\r\n throw new Error('All fallbacks exhausted');\r\n}\r\n\r\n/**\r\n * Common fallback strategies\r\n */\r\nexport const FallbackStrategies = {\r\n /**\r\n * Return empty array\r\n */\r\n emptyArray: <T>(): FallbackOptions<T[]> => ({\r\n value: [],\r\n }),\r\n\r\n /**\r\n * Return null\r\n */\r\n nullable: <T>(): FallbackOptions<T | null> => ({\r\n value: null,\r\n }),\r\n\r\n /**\r\n * Return default value\r\n */\r\n defaultValue: <T>(value: T): FallbackOptions<T> => ({\r\n value,\r\n }),\r\n\r\n /**\r\n * Return cached value from a cache function\r\n */\r\n fromCache: <T>(\r\n getCached: () => Promise<T | null>,\r\n defaultValue: T\r\n ): FallbackOptions<T> => ({\r\n fallbackFn: async () => {\r\n const cached = await getCached();\r\n return cached ?? defaultValue;\r\n },\r\n }),\r\n\r\n /**\r\n * Degrade gracefully with partial data\r\n */\r\n degrade: <T>(\r\n getDegraded: (error: Error) => T\r\n ): FallbackOptions<T> => ({\r\n fallbackFn: getDegraded,\r\n }),\r\n};\r\n","/**\r\n * Health Check HTTP Endpoints\r\n *\r\n * Provides standardized health check endpoints for Kubernetes probes\r\n * and monitoring systems.\r\n *\r\n * Endpoints:\r\n * - /health/live - Liveness probe (is the process alive?)\r\n * - /health/ready - Readiness probe (can it serve traffic?)\r\n * - /health/startup - Startup probe (has it finished initializing?)\r\n * - /health - Detailed health status for dashboards\r\n */\r\n\r\nimport { IPlatform, PlatformHealthStatus } from '../interfaces';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport type HealthStatus = 'healthy' | 'degraded' | 'unhealthy';\r\n\r\nexport interface LivenessResponse {\r\n status: 'ok' | 'error';\r\n}\r\n\r\nexport interface ReadinessResponse {\r\n status: 'ok' | 'error';\r\n checks: {\r\n database: boolean;\r\n cache: boolean;\r\n storage: boolean;\r\n email: boolean;\r\n queue: boolean;\r\n };\r\n}\r\n\r\nexport interface StartupResponse {\r\n status: 'ok' | 'error';\r\n ready: boolean;\r\n}\r\n\r\nexport interface ServiceHealth {\r\n status: HealthStatus;\r\n latencyMs?: number;\r\n message?: string;\r\n lastChecked?: string;\r\n}\r\n\r\nexport interface DetailedHealthResponse {\r\n status: HealthStatus;\r\n version: string;\r\n environment: string;\r\n uptime: number;\r\n uptimeFormatted: string;\r\n timestamp: string;\r\n services: {\r\n database: ServiceHealth;\r\n cache: ServiceHealth;\r\n storage: ServiceHealth;\r\n email: ServiceHealth;\r\n queue: ServiceHealth;\r\n };\r\n system?: {\r\n memoryUsage: {\r\n heapUsed: number;\r\n heapTotal: number;\r\n external: number;\r\n rss: number;\r\n };\r\n cpuUsage?: {\r\n user: number;\r\n system: number;\r\n };\r\n };\r\n}\r\n\r\nexport interface HealthEndpoints {\r\n /**\r\n * Liveness probe - is the process alive?\r\n * Returns 200 if alive, 503 if dead.\r\n * K8s will restart the pod if this fails.\r\n */\r\n live(): Promise<LivenessResponse>;\r\n\r\n /**\r\n * Readiness probe - can it serve traffic?\r\n * Returns 200 if ready, 503 if not ready.\r\n * K8s will remove from load balancer if this fails.\r\n */\r\n ready(): Promise<ReadinessResponse>;\r\n\r\n /**\r\n * Startup probe - has it finished initializing?\r\n * Returns 200 when startup is complete.\r\n * K8s waits for this before starting liveness/readiness probes.\r\n */\r\n startup(): Promise<StartupResponse>;\r\n\r\n /**\r\n * Detailed health status for monitoring dashboards.\r\n * Includes service-level health, latencies, and system metrics.\r\n */\r\n detailed(): Promise<DetailedHealthResponse>;\r\n\r\n /**\r\n * Mark startup as complete (call after initialization)\r\n */\r\n markStartupComplete(): void;\r\n\r\n /**\r\n * Get raw health status for custom integrations\r\n */\r\n getRawStatus(): Promise<PlatformHealthStatus>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// IMPLEMENTATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface HealthEndpointsOptions {\r\n /** Application version */\r\n version?: string;\r\n\r\n /** Environment name */\r\n environment?: string;\r\n\r\n /** Include system metrics in detailed response */\r\n includeSystemMetrics?: boolean;\r\n\r\n /** Custom health checks to include */\r\n customChecks?: Record<string, () => Promise<boolean>>;\r\n\r\n /** Timeout for individual health checks (ms) */\r\n checkTimeout?: number;\r\n}\r\n\r\nexport function createHealthEndpoints(\r\n platform: IPlatform,\r\n options: HealthEndpointsOptions = {}\r\n): HealthEndpoints {\r\n const {\r\n version = process.env.npm_package_version || process.env.APP_VERSION || 'unknown',\r\n environment = process.env.NODE_ENV || 'development',\r\n includeSystemMetrics = true,\r\n customChecks = {},\r\n checkTimeout = 5000,\r\n } = options;\r\n\r\n const startTime = Date.now();\r\n let startupComplete = false;\r\n let lastHealthCheck: PlatformHealthStatus | null = null;\r\n let lastCheckTime = 0;\r\n\r\n // Cache health check results for 1 second to avoid hammering services\r\n const CACHE_TTL = 1000;\r\n\r\n async function getCachedHealth(): Promise<PlatformHealthStatus> {\r\n const now = Date.now();\r\n if (lastHealthCheck && now - lastCheckTime < CACHE_TTL) {\r\n return lastHealthCheck;\r\n }\r\n\r\n lastHealthCheck = await withTimeout(platform.healthCheck(), checkTimeout);\r\n lastCheckTime = now;\r\n return lastHealthCheck;\r\n }\r\n\r\n async function checkServiceWithLatency(\r\n checkFn: () => Promise<boolean>\r\n ): Promise<ServiceHealth> {\r\n const start = Date.now();\r\n try {\r\n const healthy = await withTimeout(checkFn(), checkTimeout);\r\n return {\r\n status: healthy ? 'healthy' : 'unhealthy',\r\n latencyMs: Date.now() - start,\r\n lastChecked: new Date().toISOString(),\r\n };\r\n } catch (error) {\r\n return {\r\n status: 'unhealthy',\r\n latencyMs: Date.now() - start,\r\n message: error instanceof Error ? error.message : 'Unknown error',\r\n lastChecked: new Date().toISOString(),\r\n };\r\n }\r\n }\r\n\r\n function formatUptime(ms: number): string {\r\n const seconds = Math.floor(ms / 1000);\r\n const minutes = Math.floor(seconds / 60);\r\n const hours = Math.floor(minutes / 60);\r\n const days = Math.floor(hours / 24);\r\n\r\n if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`;\r\n if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;\r\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\r\n return `${seconds}s`;\r\n }\r\n\r\n function getSystemMetrics() {\r\n if (!includeSystemMetrics) return undefined;\r\n\r\n const memoryUsage = process.memoryUsage();\r\n\r\n return {\r\n memoryUsage: {\r\n heapUsed: memoryUsage.heapUsed,\r\n heapTotal: memoryUsage.heapTotal,\r\n external: memoryUsage.external,\r\n rss: memoryUsage.rss,\r\n },\r\n };\r\n }\r\n\r\n return {\r\n async live(): Promise<LivenessResponse> {\r\n // Liveness is simple - if we can respond, we're alive\r\n return { status: 'ok' };\r\n },\r\n\r\n async ready(): Promise<ReadinessResponse> {\r\n try {\r\n const health = await getCachedHealth();\r\n\r\n // Run custom checks\r\n const customResults: Record<string, boolean> = {};\r\n for (const [name, check] of Object.entries(customChecks)) {\r\n try {\r\n customResults[name] = await withTimeout(check(), checkTimeout);\r\n } catch {\r\n customResults[name] = false;\r\n }\r\n }\r\n\r\n const allCustomHealthy = Object.values(customResults).every(Boolean);\r\n\r\n return {\r\n status: health.healthy && allCustomHealthy ? 'ok' : 'error',\r\n checks: {\r\n database: health.services.database,\r\n cache: health.services.cache,\r\n storage: health.services.storage,\r\n email: health.services.email,\r\n queue: health.services.queue,\r\n ...customResults,\r\n },\r\n };\r\n } catch {\r\n return {\r\n status: 'error',\r\n checks: {\r\n database: false,\r\n cache: false,\r\n storage: false,\r\n email: false,\r\n queue: false,\r\n },\r\n };\r\n }\r\n },\r\n\r\n async startup(): Promise<StartupResponse> {\r\n if (startupComplete) {\r\n return { status: 'ok', ready: true };\r\n }\r\n\r\n // Check if all services are ready\r\n try {\r\n const health = await getCachedHealth();\r\n if (health.healthy) {\r\n startupComplete = true;\r\n return { status: 'ok', ready: true };\r\n }\r\n } catch {\r\n // Not ready yet\r\n }\r\n\r\n return { status: 'error', ready: false };\r\n },\r\n\r\n async detailed(): Promise<DetailedHealthResponse> {\r\n const uptime = Date.now() - startTime;\r\n\r\n // Get individual service health with latencies\r\n const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth] = await Promise.all([\r\n checkServiceWithLatency(() => platform.db.healthCheck()),\r\n checkServiceWithLatency(() => platform.cache.healthCheck()),\r\n checkServiceWithLatency(() => platform.storage.healthCheck()),\r\n checkServiceWithLatency(() => platform.email.healthCheck()),\r\n checkServiceWithLatency(() => platform.queue.healthCheck()),\r\n ]);\r\n\r\n const services = {\r\n database: dbHealth,\r\n cache: cacheHealth,\r\n storage: storageHealth,\r\n email: emailHealth,\r\n queue: queueHealth,\r\n };\r\n\r\n // Determine overall status\r\n const statuses = Object.values(services).map((s) => s.status);\r\n let overallStatus: HealthStatus = 'healthy';\r\n\r\n if (statuses.some((s) => s === 'unhealthy')) {\r\n overallStatus = 'unhealthy';\r\n } else if (statuses.some((s) => s === 'degraded')) {\r\n overallStatus = 'degraded';\r\n }\r\n\r\n return {\r\n status: overallStatus,\r\n version,\r\n environment,\r\n uptime,\r\n uptimeFormatted: formatUptime(uptime),\r\n timestamp: new Date().toISOString(),\r\n services,\r\n system: getSystemMetrics(),\r\n };\r\n },\r\n\r\n markStartupComplete(): void {\r\n startupComplete = true;\r\n },\r\n\r\n async getRawStatus(): Promise<PlatformHealthStatus> {\r\n return getCachedHealth();\r\n },\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nasync function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {\r\n let timeoutHandle: ReturnType<typeof setTimeout>;\r\n\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n timeoutHandle = setTimeout(() => {\r\n reject(new Error(`Health check timed out after ${timeoutMs}ms`));\r\n }, timeoutMs);\r\n });\r\n\r\n try {\r\n return await Promise.race([promise, timeoutPromise]);\r\n } finally {\r\n clearTimeout(timeoutHandle!);\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HTTP HANDLER FACTORIES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Create Express-compatible health route handlers\r\n */\r\nexport function createExpressHealthHandlers(endpoints: HealthEndpoints) {\r\n return {\r\n live: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.live();\r\n res.status(result.status === 'ok' ? 200 : 503).json(result);\r\n },\r\n\r\n ready: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.ready();\r\n res.status(result.status === 'ok' ? 200 : 503).json(result);\r\n },\r\n\r\n startup: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.startup();\r\n res.status(result.status === 'ok' ? 200 : 503).json(result);\r\n },\r\n\r\n detailed: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.detailed();\r\n const statusCode = result.status === 'healthy' ? 200 : result.status === 'degraded' ? 200 : 503;\r\n res.status(statusCode).json(result);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Create a simple HTTP server for health checks (standalone, no framework)\r\n */\r\nexport async function createHealthServer(\r\n endpoints: HealthEndpoints,\r\n port: number = 8080\r\n): Promise<{ close: () => Promise<void> }> {\r\n const http = await import('http');\r\n\r\n const server = http.createServer(async (req, res) => {\r\n const url = req.url || '/';\r\n\r\n res.setHeader('Content-Type', 'application/json');\r\n\r\n try {\r\n let result: unknown;\r\n let statusCode = 200;\r\n\r\n switch (url) {\r\n case '/health/live':\r\n case '/healthz':\r\n result = await endpoints.live();\r\n statusCode = (result as LivenessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/ready':\r\n case '/readyz':\r\n result = await endpoints.ready();\r\n statusCode = (result as ReadinessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/startup':\r\n case '/startupz':\r\n result = await endpoints.startup();\r\n statusCode = (result as StartupResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health':\r\n case '/':\r\n result = await endpoints.detailed();\r\n const detailed = result as DetailedHealthResponse;\r\n statusCode = detailed.status === 'healthy' ? 200 : detailed.status === 'degraded' ? 200 : 503;\r\n break;\r\n\r\n default:\r\n res.writeHead(404);\r\n res.end(JSON.stringify({ error: 'Not found' }));\r\n return;\r\n }\r\n\r\n res.writeHead(statusCode);\r\n res.end(JSON.stringify(result));\r\n } catch (error) {\r\n res.writeHead(500);\r\n res.end(JSON.stringify({ error: 'Internal server error' }));\r\n }\r\n });\r\n\r\n return new Promise((resolve) => {\r\n server.listen(port, () => {\r\n resolve({\r\n close: () =>\r\n new Promise<void>((res) => {\r\n server.close(() => res());\r\n }),\r\n });\r\n });\r\n });\r\n}\r\n","/**\r\n * Prometheus Metrics HTTP Endpoint\r\n *\r\n * Provides a /metrics endpoint that exports metrics in Prometheus text format.\r\n * This enables scraping by Prometheus, Grafana Agent, or other compatible systems.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createMetricsEndpoint } from '@digilogiclabs/platform-core';\r\n *\r\n * const metricsEndpoint = createMetricsEndpoint(platform.metrics, {\r\n * prefix: 'myapp',\r\n * defaultLabels: { service: 'api', environment: 'production' },\r\n * });\r\n *\r\n * // Get Prometheus format output\r\n * const prometheusText = metricsEndpoint.getPrometheusMetrics();\r\n *\r\n * // Or use the built-in server\r\n * const server = await createMetricsServer(metricsEndpoint, 9090);\r\n * ```\r\n */\r\n\r\nimport { IMetrics, MemoryMetrics, MetricsSummary } from '../interfaces/IMetrics';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface MetricsEndpointOptions {\r\n /** Prefix for all metric names */\r\n prefix?: string;\r\n\r\n /** Default labels to add to all metrics */\r\n defaultLabels?: Record<string, string>;\r\n\r\n /** Include process metrics (memory, cpu, etc.) */\r\n includeProcessMetrics?: boolean;\r\n\r\n /** Include Node.js event loop metrics */\r\n includeEventLoopMetrics?: boolean;\r\n\r\n /** Histogram buckets for timing metrics */\r\n histogramBuckets?: number[];\r\n}\r\n\r\nexport interface MetricsEndpoint {\r\n /**\r\n * Get metrics in Prometheus text exposition format\r\n */\r\n getPrometheusMetrics(): string;\r\n\r\n /**\r\n * Get metrics as JSON (for debugging)\r\n */\r\n getJsonMetrics(): MetricsSummary;\r\n\r\n /**\r\n * Record a custom metric\r\n */\r\n recordMetric(type: 'counter' | 'gauge' | 'histogram', name: string, value: number, labels?: Record<string, string>): void;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PROMETHEUS FORMAT HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction sanitizeMetricName(name: string): string {\r\n // Prometheus metric names must match [a-zA-Z_:][a-zA-Z0-9_:]*\r\n return name\r\n .replace(/[.-]/g, '_')\r\n .replace(/[^a-zA-Z0-9_:]/g, '')\r\n .replace(/^([0-9])/, '_$1');\r\n}\r\n\r\nfunction formatLabels(labels: Record<string, string>): string {\r\n const entries = Object.entries(labels);\r\n if (entries.length === 0) return '';\r\n\r\n const formatted = entries\r\n .map(([key, value]) => `${sanitizeMetricName(key)}=\"${escapeLabel(value)}\"`)\r\n .join(',');\r\n\r\n return `{${formatted}}`;\r\n}\r\n\r\nfunction escapeLabel(value: string): string {\r\n return value\r\n .replace(/\\\\/g, '\\\\\\\\')\r\n .replace(/\"/g, '\\\\\"')\r\n .replace(/\\n/g, '\\\\n');\r\n}\r\n\r\nfunction parseMetricKey(key: string): { name: string; labels: Record<string, string> } {\r\n const pipeIndex = key.indexOf('|');\r\n if (pipeIndex === -1) {\r\n return { name: key, labels: {} };\r\n }\r\n\r\n const name = key.substring(0, pipeIndex);\r\n const labelString = key.substring(pipeIndex + 1);\r\n\r\n const labels: Record<string, string> = {};\r\n for (const pair of labelString.split(',')) {\r\n const colonIndex = pair.indexOf(':');\r\n if (colonIndex !== -1) {\r\n const labelKey = pair.substring(0, colonIndex);\r\n const labelValue = pair.substring(colonIndex + 1);\r\n labels[labelKey] = labelValue;\r\n }\r\n }\r\n\r\n return { name, labels };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PROCESS METRICS COLLECTOR\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\ninterface ProcessMetrics {\r\n memoryHeapUsed: number;\r\n memoryHeapTotal: number;\r\n memoryExternal: number;\r\n memoryRss: number;\r\n uptimeSeconds: number;\r\n cpuUserSeconds?: number;\r\n cpuSystemSeconds?: number;\r\n}\r\n\r\nfunction collectProcessMetrics(): ProcessMetrics {\r\n const memoryUsage = process.memoryUsage();\r\n\r\n return {\r\n memoryHeapUsed: memoryUsage.heapUsed,\r\n memoryHeapTotal: memoryUsage.heapTotal,\r\n memoryExternal: memoryUsage.external,\r\n memoryRss: memoryUsage.rss,\r\n uptimeSeconds: process.uptime(),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// IMPLEMENTATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport function createMetricsEndpoint(\r\n metrics: IMetrics,\r\n options: MetricsEndpointOptions = {}\r\n): MetricsEndpoint {\r\n const {\r\n prefix = '',\r\n defaultLabels = {},\r\n includeProcessMetrics = true,\r\n histogramBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],\r\n } = options;\r\n\r\n const prefixName = (name: string) => (prefix ? `${prefix}_${name}` : name);\r\n\r\n function buildPrometheusOutput(summary: MetricsSummary): string {\r\n const lines: string[] = [];\r\n\r\n // Process metrics\r\n if (includeProcessMetrics) {\r\n const processMetrics = collectProcessMetrics();\r\n const processLabels = formatLabels(defaultLabels);\r\n\r\n lines.push('# HELP process_heap_bytes Node.js heap memory usage in bytes');\r\n lines.push('# TYPE process_heap_bytes gauge');\r\n lines.push(`process_heap_bytes${processLabels} ${processMetrics.memoryHeapUsed}`);\r\n\r\n lines.push('# HELP process_heap_total_bytes Node.js total heap size in bytes');\r\n lines.push('# TYPE process_heap_total_bytes gauge');\r\n lines.push(`process_heap_total_bytes${processLabels} ${processMetrics.memoryHeapTotal}`);\r\n\r\n lines.push('# HELP process_memory_rss_bytes Process resident set size in bytes');\r\n lines.push('# TYPE process_memory_rss_bytes gauge');\r\n lines.push(`process_memory_rss_bytes${processLabels} ${processMetrics.memoryRss}`);\r\n\r\n lines.push('# HELP process_uptime_seconds Process uptime in seconds');\r\n lines.push('# TYPE process_uptime_seconds counter');\r\n lines.push(`process_uptime_seconds${processLabels} ${processMetrics.uptimeSeconds}`);\r\n\r\n lines.push('');\r\n }\r\n\r\n // Counters\r\n for (const [key, value] of Object.entries(summary.counters)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name));\r\n const allLabels = { ...defaultLabels, ...labels };\r\n const labelStr = formatLabels(allLabels);\r\n\r\n lines.push(`# HELP ${metricName} Counter metric`);\r\n lines.push(`# TYPE ${metricName} counter`);\r\n lines.push(`${metricName}${labelStr} ${value}`);\r\n lines.push('');\r\n }\r\n\r\n // Gauges\r\n for (const [key, value] of Object.entries(summary.gauges)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name));\r\n const allLabels = { ...defaultLabels, ...labels };\r\n const labelStr = formatLabels(allLabels);\r\n\r\n lines.push(`# HELP ${metricName} Gauge metric`);\r\n lines.push(`# TYPE ${metricName} gauge`);\r\n lines.push(`${metricName}${labelStr} ${value}`);\r\n lines.push('');\r\n }\r\n\r\n // Histograms (with buckets)\r\n for (const [key, stats] of Object.entries(summary.histograms)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name));\r\n const allLabels = { ...defaultLabels, ...labels };\r\n\r\n lines.push(`# HELP ${metricName} Histogram metric`);\r\n lines.push(`# TYPE ${metricName} histogram`);\r\n\r\n // Note: MemoryMetrics doesn't track individual values for histogram buckets,\r\n // so we output summary statistics instead\r\n const labelStr = formatLabels(allLabels);\r\n lines.push(`${metricName}_count${labelStr} ${stats.count}`);\r\n lines.push(`${metricName}_sum${labelStr} ${stats.sum}`);\r\n lines.push('');\r\n }\r\n\r\n // Timings (as histograms with percentiles as summary)\r\n for (const [key, stats] of Object.entries(summary.timings)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name) + '_seconds');\r\n const allLabels = { ...defaultLabels, ...labels };\r\n\r\n lines.push(`# HELP ${metricName} Timing histogram (converted to seconds)`);\r\n lines.push(`# TYPE ${metricName} summary`);\r\n\r\n // Convert milliseconds to seconds for Prometheus convention\r\n const sumSeconds = stats.sum / 1000;\r\n const p50Seconds = stats.p50 / 1000;\r\n const p95Seconds = stats.p95 / 1000;\r\n const p99Seconds = stats.p99 / 1000;\r\n\r\n const p50Labels = { ...allLabels, quantile: '0.5' };\r\n const p95Labels = { ...allLabels, quantile: '0.95' };\r\n const p99Labels = { ...allLabels, quantile: '0.99' };\r\n\r\n lines.push(`${metricName}${formatLabels(p50Labels)} ${p50Seconds}`);\r\n lines.push(`${metricName}${formatLabels(p95Labels)} ${p95Seconds}`);\r\n lines.push(`${metricName}${formatLabels(p99Labels)} ${p99Seconds}`);\r\n lines.push(`${metricName}_count${formatLabels(allLabels)} ${stats.count}`);\r\n lines.push(`${metricName}_sum${formatLabels(allLabels)} ${sumSeconds}`);\r\n lines.push('');\r\n }\r\n\r\n // Sets (as gauge with cardinality)\r\n for (const [key, value] of Object.entries(summary.sets)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name) + '_cardinality');\r\n const allLabels = { ...defaultLabels, ...labels };\r\n const labelStr = formatLabels(allLabels);\r\n\r\n lines.push(`# HELP ${metricName} Set cardinality (unique values)`);\r\n lines.push(`# TYPE ${metricName} gauge`);\r\n lines.push(`${metricName}${labelStr} ${value}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n');\r\n }\r\n\r\n return {\r\n getPrometheusMetrics(): string {\r\n // Get summary from MemoryMetrics if available\r\n if (metrics instanceof MemoryMetrics) {\r\n const summary = metrics.getSummary();\r\n return buildPrometheusOutput(summary);\r\n }\r\n\r\n // For other implementations, return just process metrics\r\n if (includeProcessMetrics) {\r\n const processMetrics = collectProcessMetrics();\r\n const processLabels = formatLabels(defaultLabels);\r\n\r\n return [\r\n '# HELP process_heap_bytes Node.js heap memory usage in bytes',\r\n '# TYPE process_heap_bytes gauge',\r\n `process_heap_bytes${processLabels} ${processMetrics.memoryHeapUsed}`,\r\n '',\r\n '# HELP process_heap_total_bytes Node.js total heap size in bytes',\r\n '# TYPE process_heap_total_bytes gauge',\r\n `process_heap_total_bytes${processLabels} ${processMetrics.memoryHeapTotal}`,\r\n '',\r\n '# HELP process_memory_rss_bytes Process resident set size in bytes',\r\n '# TYPE process_memory_rss_bytes gauge',\r\n `process_memory_rss_bytes${processLabels} ${processMetrics.memoryRss}`,\r\n '',\r\n '# HELP process_uptime_seconds Process uptime in seconds',\r\n '# TYPE process_uptime_seconds counter',\r\n `process_uptime_seconds${processLabels} ${processMetrics.uptimeSeconds}`,\r\n '',\r\n ].join('\\n');\r\n }\r\n\r\n return '';\r\n },\r\n\r\n getJsonMetrics(): MetricsSummary {\r\n if (metrics instanceof MemoryMetrics) {\r\n return metrics.getSummary();\r\n }\r\n\r\n return {\r\n counters: {},\r\n gauges: {},\r\n histograms: {},\r\n timings: {},\r\n sets: {},\r\n };\r\n },\r\n\r\n recordMetric(\r\n type: 'counter' | 'gauge' | 'histogram',\r\n name: string,\r\n value: number,\r\n labels: Record<string, string> = {}\r\n ): void {\r\n switch (type) {\r\n case 'counter':\r\n metrics.increment(name, value, labels);\r\n break;\r\n case 'gauge':\r\n metrics.gauge(name, value, labels);\r\n break;\r\n case 'histogram':\r\n metrics.histogram(name, value, labels);\r\n break;\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HTTP HANDLER FACTORIES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Create Express-compatible metrics handler\r\n */\r\nexport function createExpressMetricsHandler(endpoint: MetricsEndpoint) {\r\n return (_req: unknown, res: {\r\n setHeader: (name: string, value: string) => void;\r\n status: (code: number) => { send: (data: string) => void }\r\n }) => {\r\n res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\r\n res.status(200).send(endpoint.getPrometheusMetrics());\r\n };\r\n}\r\n\r\n/**\r\n * Create a standalone HTTP server for metrics (no framework required)\r\n */\r\nexport async function createMetricsServer(\r\n endpoint: MetricsEndpoint,\r\n port: number = 9090\r\n): Promise<{ close: () => Promise<void>; port: number }> {\r\n const http = await import('http');\r\n\r\n const server = http.createServer((req, res) => {\r\n const url = req.url || '/';\r\n\r\n if (url === '/metrics' || url === '/') {\r\n res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\r\n res.writeHead(200);\r\n res.end(endpoint.getPrometheusMetrics());\r\n } else if (url === '/metrics.json') {\r\n res.setHeader('Content-Type', 'application/json');\r\n res.writeHead(200);\r\n res.end(JSON.stringify(endpoint.getJsonMetrics(), null, 2));\r\n } else {\r\n res.writeHead(404);\r\n res.end('Not found');\r\n }\r\n });\r\n\r\n return new Promise((resolve) => {\r\n server.listen(port, () => {\r\n resolve({\r\n port,\r\n close: () =>\r\n new Promise<void>((res) => {\r\n server.close(() => res());\r\n }),\r\n });\r\n });\r\n });\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// COMBINED HEALTH + METRICS SERVER\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nimport type { HealthEndpoints, DetailedHealthResponse, LivenessResponse, ReadinessResponse, StartupResponse } from './health';\r\n\r\n/**\r\n * Create a combined server that serves both health and metrics endpoints\r\n *\r\n * Endpoints:\r\n * - /health/live, /healthz - Liveness probe\r\n * - /health/ready, /readyz - Readiness probe\r\n * - /health/startup, /startupz - Startup probe\r\n * - /health - Detailed health\r\n * - /metrics - Prometheus metrics\r\n * - /metrics.json - JSON metrics (debugging)\r\n */\r\nexport async function createObservabilityServer(\r\n healthEndpoints: HealthEndpoints,\r\n metricsEndpoint: MetricsEndpoint,\r\n port: number = 8080\r\n): Promise<{ close: () => Promise<void>; port: number }> {\r\n const http = await import('http');\r\n\r\n const server = http.createServer(async (req, res) => {\r\n const url = req.url || '/';\r\n\r\n try {\r\n // Metrics endpoints\r\n if (url === '/metrics') {\r\n res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\r\n res.writeHead(200);\r\n res.end(metricsEndpoint.getPrometheusMetrics());\r\n return;\r\n }\r\n\r\n if (url === '/metrics.json') {\r\n res.setHeader('Content-Type', 'application/json');\r\n res.writeHead(200);\r\n res.end(JSON.stringify(metricsEndpoint.getJsonMetrics(), null, 2));\r\n return;\r\n }\r\n\r\n // Health endpoints\r\n res.setHeader('Content-Type', 'application/json');\r\n\r\n let result: unknown;\r\n let statusCode = 200;\r\n\r\n switch (url) {\r\n case '/health/live':\r\n case '/healthz':\r\n result = await healthEndpoints.live();\r\n statusCode = (result as LivenessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/ready':\r\n case '/readyz':\r\n result = await healthEndpoints.ready();\r\n statusCode = (result as ReadinessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/startup':\r\n case '/startupz':\r\n result = await healthEndpoints.startup();\r\n statusCode = (result as StartupResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health':\r\n case '/':\r\n result = await healthEndpoints.detailed();\r\n const detailed = result as DetailedHealthResponse;\r\n statusCode = detailed.status === 'healthy' ? 200 : detailed.status === 'degraded' ? 200 : 503;\r\n break;\r\n\r\n default:\r\n res.writeHead(404);\r\n res.end(JSON.stringify({ error: 'Not found' }));\r\n return;\r\n }\r\n\r\n res.writeHead(statusCode);\r\n res.end(JSON.stringify(result));\r\n } catch (error) {\r\n res.setHeader('Content-Type', 'application/json');\r\n res.writeHead(500);\r\n res.end(JSON.stringify({ error: 'Internal server error' }));\r\n }\r\n });\r\n\r\n return new Promise((resolve) => {\r\n server.listen(port, () => {\r\n resolve({\r\n port,\r\n close: () =>\r\n new Promise<void>((res) => {\r\n server.close(() => res());\r\n }),\r\n });\r\n });\r\n });\r\n}\r\n","export { SupabaseDatabase, type SupabaseDatabaseConfig } from './SupabaseDatabase';\r\n","/**\r\n * PostgreSQL Database Adapter\r\n *\r\n * Direct PostgreSQL connection with true transaction support.\r\n */\r\n\r\nexport { PostgresDatabase, type PostgresConfig } from './PostgresDatabase';\r\n","export { UpstashCache, type UpstashCacheConfig } from './UpstashCache';\r\n","/**\r\n * Redis Direct Cache Adapter\r\n *\r\n * Direct Redis connection with full feature support including pub/sub.\r\n */\r\n\r\nexport { RedisCache, type RedisConfig } from './RedisCache';\r\n","export { S3Storage, type S3StorageConfig } from './S3Storage';\r\n","/**\r\n * Supabase Storage Adapter\r\n *\r\n * File storage via Supabase Storage buckets.\r\n */\r\n\r\nexport { SupabaseStorage, type SupabaseStorageConfig } from './SupabaseStorage';\r\n","export { ResendEmail, type ResendEmailConfig } from './ResendEmail';\r\n","/**\r\n * SMTP Email Adapter\r\n *\r\n * Standard SMTP email sending via nodemailer.\r\n */\r\n\r\nexport { SmtpEmail, type SmtpConfig } from './SmtpEmail';\r\n","export { BullMQQueue, type BullMQConfig } from './BullMQQueue';\r\n","/**\r\n * Database Migrator\r\n *\r\n * Enterprise-grade database migration system supporting:\r\n * - PostgreSQL (primary)\r\n * - Memory database (for testing)\r\n * - Transaction-safe migrations\r\n * - Concurrent execution locking\r\n * - Checksum validation\r\n * - Dry-run mode\r\n */\r\n\r\nimport type {\r\n IMigrator,\r\n Migration,\r\n MigrationRecord,\r\n MigrationResult,\r\n MigrationStatus,\r\n MigratorConfig,\r\n IMigrationDatabase,\r\n} from '../interfaces/IMigration';\r\n\r\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string } = {\r\n tableName: '_migrations',\r\n schema: 'public',\r\n lockTimeout: 60,\r\n validateChecksums: true,\r\n migrationsDir: undefined,\r\n};\r\n\r\n/**\r\n * Generate a checksum for migration content\r\n */\r\nfunction generateChecksum(content: string): string {\r\n // Simple hash for checksum - in production you might use crypto\r\n let hash = 0;\r\n for (let i = 0; i < content.length; i++) {\r\n const char = content.charCodeAt(i);\r\n hash = (hash << 5) - hash + char;\r\n hash = hash & hash; // Convert to 32-bit integer\r\n }\r\n return Math.abs(hash).toString(16).padStart(8, '0');\r\n}\r\n\r\n/**\r\n * Sort migrations by version\r\n */\r\nfunction sortMigrations(migrations: Migration[]): Migration[] {\r\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\r\n}\r\n\r\nexport class Migrator implements IMigrator {\r\n private db: IMigrationDatabase;\r\n private config: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string };\r\n private migrations: Migration[] = [];\r\n private initialized = false;\r\n private locked = false;\r\n\r\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\r\n this.db = db;\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Get the fully qualified migration table name\r\n */\r\n private get tableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\r\n }\r\n\r\n /**\r\n * Get the lock table name\r\n */\r\n private get lockTableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\r\n }\r\n\r\n /**\r\n * Initialize migration tracking tables\r\n */\r\n private async initialize(): Promise<void> {\r\n if (this.initialized) return;\r\n\r\n // Create schema if not exists\r\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\r\n\r\n // Create migrations tracking table\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\r\n version VARCHAR(255) PRIMARY KEY,\r\n name VARCHAR(255) NOT NULL,\r\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\r\n execution_time INTEGER NOT NULL,\r\n checksum VARCHAR(64)\r\n )\r\n `);\r\n\r\n // Create lock table for concurrent safety\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\r\n id INTEGER PRIMARY KEY DEFAULT 1,\r\n locked_at TIMESTAMP WITH TIME ZONE,\r\n locked_by VARCHAR(255),\r\n CONSTRAINT single_row CHECK (id = 1)\r\n )\r\n `);\r\n\r\n // Insert initial lock row if not exists\r\n await this.db.raw(`\r\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\r\n VALUES (1, NULL, NULL)\r\n ON CONFLICT (id) DO NOTHING\r\n `);\r\n\r\n this.initialized = true;\r\n }\r\n\r\n /**\r\n * Acquire migration lock\r\n */\r\n async lock(): Promise<boolean> {\r\n await this.initialize();\r\n\r\n const lockId = `${process.pid}-${Date.now()}`;\r\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\r\n\r\n // Try to acquire lock (only if not locked or lock expired)\r\n const result = await this.db.raw<{ locked_at: Date | null }>(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\r\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\r\n RETURNING locked_at\r\n `,\r\n [lockId, lockTimeout]\r\n );\r\n\r\n if (result.data.length > 0) {\r\n this.locked = true;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Release migration lock\r\n */\r\n async unlock(): Promise<void> {\r\n if (!this.locked) return;\r\n\r\n await this.db.raw(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = NULL, locked_by = NULL\r\n WHERE id = 1\r\n `\r\n );\r\n\r\n this.locked = false;\r\n }\r\n\r\n /**\r\n * Add migrations to the migrator\r\n */\r\n addMigrations(migrations: Migration[]): void {\r\n for (const migration of migrations) {\r\n // Generate checksum if not provided\r\n if (!migration.checksum) {\r\n const content =\r\n typeof migration.up === 'string' ? migration.up : migration.up.toString();\r\n migration.checksum = generateChecksum(content);\r\n }\r\n\r\n // Avoid duplicates\r\n if (!this.migrations.find((m) => m.version === migration.version)) {\r\n this.migrations.push(migration);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Load migrations from directory\r\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\r\n */\r\n async loadMigrations(dir: string): Promise<void> {\r\n // Dynamic import for Node.js file system\r\n const { readdir, readFile } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n const files = await readdir(dir);\r\n const migrationFiles = files.filter(\r\n (f) => f.match(/^\\d+_.*\\.(ts|js|sql)$/)\r\n );\r\n\r\n for (const file of migrationFiles) {\r\n const filePath = join(dir, file);\r\n const [version, ...nameParts] = file.replace(/\\.(ts|js|sql)$/, '').split('_');\r\n const name = nameParts.join('_');\r\n\r\n if (file.endsWith('.sql')) {\r\n // SQL file - parse UP and DOWN sections\r\n const content = await readFile(filePath, 'utf-8');\r\n const [up, down] = this.parseSqlMigration(content);\r\n\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up,\r\n down,\r\n },\r\n ]);\r\n } else {\r\n // TypeScript/JavaScript file - import the module\r\n const module = await import(filePath);\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up: module.up,\r\n down: module.down,\r\n transactional: module.transactional,\r\n },\r\n ]);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL migration file with -- UP and -- DOWN sections\r\n */\r\n private parseSqlMigration(content: string): [string, string] {\r\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\r\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\r\n\r\n const up = upMatch?.[1]?.trim() ?? content.trim();\r\n const down = downMatch?.[1]?.trim() ?? '';\r\n\r\n return [up, down];\r\n }\r\n\r\n /**\r\n * Get current migration status\r\n */\r\n async status(): Promise<MigrationStatus> {\r\n await this.initialize();\r\n\r\n // Get applied migrations\r\n const result = await this.db.raw<{\r\n version: string;\r\n name: string;\r\n applied_at: Date;\r\n execution_time: number;\r\n checksum: string | null;\r\n }>(\r\n `SELECT version, name, applied_at, execution_time, checksum\r\n FROM ${this.tableName}\r\n ORDER BY version ASC`\r\n );\r\n\r\n const applied: MigrationRecord[] = result.data.map((row) => ({\r\n version: row.version,\r\n name: row.name,\r\n appliedAt: new Date(row.applied_at),\r\n executionTime: row.execution_time,\r\n checksum: row.checksum ?? undefined,\r\n }));\r\n\r\n const appliedVersions = new Set(applied.map((m) => m.version));\r\n const sortedMigrations = sortMigrations(this.migrations);\r\n\r\n const pending = sortedMigrations.filter(\r\n (m) => !appliedVersions.has(m.version)\r\n );\r\n\r\n return {\r\n applied,\r\n pending,\r\n currentVersion: applied.length > 0 ? applied[applied.length - 1]!.version : null,\r\n latestVersion:\r\n sortedMigrations.length > 0\r\n ? sortedMigrations[sortedMigrations.length - 1]!.version\r\n : null,\r\n };\r\n }\r\n\r\n /**\r\n * Run all pending migrations (or up to a specific version)\r\n */\r\n async up(options: { dryRun?: boolean; to?: string } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, to } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n let pending = status.pending;\r\n\r\n // Filter to specific version if requested\r\n if (to) {\r\n const targetIndex = pending.findIndex((m) => m.version === to);\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${to} not found in pending migrations`);\r\n }\r\n pending = pending.slice(0, targetIndex + 1);\r\n }\r\n\r\n for (const migration of pending) {\r\n const result = await this.runMigration(migration, 'up', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break; // Stop on first failure\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback migrations\r\n */\r\n async down(options: { dryRun?: boolean; steps?: number } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, steps = 1 } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n\r\n // Get the last N applied migrations (in reverse order)\r\n const toRollback = status.applied.slice(-steps).reverse();\r\n\r\n for (const record of toRollback) {\r\n const migration = this.migrations.find((m) => m.version === record.version);\r\n if (!migration) {\r\n throw new Error(\r\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`\r\n );\r\n }\r\n\r\n const result = await this.runMigration(migration, 'down', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break;\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback all migrations and re-run them\r\n */\r\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const downResults = await this.down({\r\n dryRun: options.dryRun,\r\n steps: status.applied.length,\r\n });\r\n\r\n // Only proceed with up if all downs succeeded\r\n if (downResults.every((r) => r.success)) {\r\n const upResults = await this.up({ dryRun: options.dryRun });\r\n return [...downResults, ...upResults];\r\n }\r\n\r\n return downResults;\r\n }\r\n\r\n /**\r\n * Migrate to a specific version\r\n */\r\n async goto(version: string, options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const currentVersion = status.currentVersion;\r\n const results: MigrationResult[] = [];\r\n\r\n // If already at target, nothing to do\r\n if (currentVersion === version) {\r\n return results;\r\n }\r\n\r\n // Determine direction\r\n const isUp = !currentVersion || version > currentVersion;\r\n\r\n if (isUp) {\r\n return this.up({ ...options, to: version });\r\n } else {\r\n // Find how many steps down we need to go\r\n const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);\r\n const targetIndex = status.applied.findIndex((m) => m.version === version);\r\n\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${version} not found in applied migrations`);\r\n }\r\n\r\n const steps = currentIndex - targetIndex;\r\n return this.down({ ...options, steps });\r\n }\r\n }\r\n\r\n /**\r\n * Run a single migration\r\n */\r\n private async runMigration(\r\n migration: Migration,\r\n direction: 'up' | 'down',\r\n dryRun: boolean\r\n ): Promise<MigrationResult> {\r\n const startTime = Date.now();\r\n const action = direction === 'up' ? migration.up : migration.down;\r\n\r\n try {\r\n if (dryRun) {\r\n // Just simulate - don't actually run\r\n return {\r\n migration,\r\n success: true,\r\n executionTime: 0,\r\n dryRun: true,\r\n };\r\n }\r\n\r\n const transactional = migration.transactional !== false;\r\n const runAction = async (db: IMigrationDatabase) => {\r\n if (typeof action === 'string') {\r\n const result = await db.raw(action);\r\n if (result.error) {\r\n throw result.error;\r\n }\r\n } else {\r\n await action(db);\r\n }\r\n };\r\n\r\n if (transactional) {\r\n await this.db.transaction(async (tx) => {\r\n await runAction(tx);\r\n });\r\n } else {\r\n await runAction(this.db);\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n\r\n // Update tracking table\r\n if (direction === 'up') {\r\n await this.db.raw(\r\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\r\n VALUES ($1, $2, $3, $4)`,\r\n [migration.version, migration.name, executionTime, migration.checksum]\r\n );\r\n } else {\r\n await this.db.raw(\r\n `DELETE FROM ${this.tableName} WHERE version = $1`,\r\n [migration.version]\r\n );\r\n }\r\n\r\n return {\r\n migration,\r\n success: true,\r\n executionTime,\r\n dryRun: false,\r\n };\r\n } catch (error) {\r\n return {\r\n migration,\r\n success: false,\r\n executionTime: Date.now() - startTime,\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n dryRun: false,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Create a new migration file\r\n */\r\n async create(name: string): Promise<string> {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n if (!this.config.migrationsDir) {\r\n throw new Error('migrationsDir must be configured to create migrations');\r\n }\r\n\r\n // Ensure directory exists\r\n await mkdir(this.config.migrationsDir, { recursive: true });\r\n\r\n // Generate version timestamp\r\n const now = new Date();\r\n const version = [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n\r\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();\r\n const fileName = `${version}_${safeName}.sql`;\r\n const filePath = join(this.config.migrationsDir, fileName);\r\n\r\n const template = `-- Migration: ${name}\r\n-- Version: ${version}\r\n-- Created: ${now.toISOString()}\r\n\r\n-- UP\r\n-- Add your forward migration SQL here\r\n\r\n\r\n-- DOWN\r\n-- Add your rollback migration SQL here\r\n\r\n`;\r\n\r\n await writeFile(filePath, template, 'utf-8');\r\n\r\n return filePath;\r\n }\r\n\r\n /**\r\n * Validate migration integrity\r\n */\r\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\r\n const errors: string[] = [];\r\n const status = await this.status();\r\n\r\n if (!this.config.validateChecksums) {\r\n return { valid: true, errors };\r\n }\r\n\r\n for (const applied of status.applied) {\r\n const migration = this.migrations.find((m) => m.version === applied.version);\r\n\r\n if (!migration) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`\r\n );\r\n continue;\r\n }\r\n\r\n if (applied.checksum && migration.checksum !== applied.checksum) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n }\r\n}\r\n","/**\r\n * Migration Helper Functions\r\n *\r\n * Utilities for creating migrations in a type-safe and convenient way.\r\n */\r\n\r\nimport type { Migration, IMigrationDatabase } from '../interfaces/IMigration';\r\n\r\n/**\r\n * Create a SQL-based migration\r\n *\r\n * @example\r\n * ```typescript\r\n * export default sqlMigration({\r\n * version: '20240101000000',\r\n * name: 'create_users',\r\n * up: `\r\n * CREATE TABLE users (\r\n * id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\r\n * email VARCHAR(255) UNIQUE NOT NULL,\r\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\r\n * )\r\n * `,\r\n * down: `DROP TABLE users`\r\n * });\r\n * ```\r\n */\r\nexport function sqlMigration(migration: {\r\n version: string;\r\n name: string;\r\n up: string;\r\n down: string;\r\n transactional?: boolean;\r\n}): Migration {\r\n return {\r\n version: migration.version,\r\n name: migration.name,\r\n up: migration.up,\r\n down: migration.down,\r\n transactional: migration.transactional,\r\n };\r\n}\r\n\r\n/**\r\n * Create a function-based migration for complex logic\r\n *\r\n * @example\r\n * ```typescript\r\n * export default createMigration({\r\n * version: '20240102000000',\r\n * name: 'seed_initial_data',\r\n * up: async (db) => {\r\n * await db.raw(`INSERT INTO users (email) VALUES ('admin@example.com')`);\r\n * await db.raw(`INSERT INTO settings (key, value) VALUES ('version', '1.0.0')`);\r\n * },\r\n * down: async (db) => {\r\n * await db.raw(`DELETE FROM settings WHERE key = 'version'`);\r\n * await db.raw(`DELETE FROM users WHERE email = 'admin@example.com'`);\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport function createMigration(migration: {\r\n version: string;\r\n name: string;\r\n up: (db: IMigrationDatabase) => Promise<void>;\r\n down: (db: IMigrationDatabase) => Promise<void>;\r\n transactional?: boolean;\r\n}): Migration {\r\n return {\r\n version: migration.version,\r\n name: migration.name,\r\n up: migration.up,\r\n down: migration.down,\r\n transactional: migration.transactional,\r\n };\r\n}\r\n\r\n/**\r\n * Type-safe migration definition with inference\r\n * Useful for defining migrations in separate files\r\n *\r\n * @example\r\n * ```typescript\r\n * // migrations/20240101000000_create_users.ts\r\n * export const migration = defineMigration({\r\n * version: '20240101000000',\r\n * name: 'create_users',\r\n * up: 'CREATE TABLE users (...)',\r\n * down: 'DROP TABLE users'\r\n * });\r\n *\r\n * // Or with functions\r\n * export const migration = defineMigration({\r\n * version: '20240102000000',\r\n * name: 'complex_migration',\r\n * up: async (db) => { ... },\r\n * down: async (db) => { ... }\r\n * });\r\n * ```\r\n */\r\nexport function defineMigration<\r\n T extends {\r\n version: string;\r\n name: string;\r\n up: string | ((db: IMigrationDatabase) => Promise<void>);\r\n down: string | ((db: IMigrationDatabase) => Promise<void>);\r\n transactional?: boolean;\r\n }\r\n>(migration: T): Migration {\r\n return migration;\r\n}\r\n\r\n/**\r\n * Generate a version timestamp for new migrations\r\n *\r\n * @example\r\n * ```typescript\r\n * const version = generateVersion(); // '20240315143052'\r\n * ```\r\n */\r\nexport function generateVersion(): string {\r\n const now = new Date();\r\n return [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n}\r\n\r\n/**\r\n * Common SQL snippets for migrations\r\n */\r\nexport const SQL = {\r\n /**\r\n * Create updated_at trigger function (PostgreSQL)\r\n */\r\n createUpdatedAtFunction: `\r\n CREATE OR REPLACE FUNCTION update_updated_at_column()\r\n RETURNS TRIGGER AS $$\r\n BEGIN\r\n NEW.updated_at = CURRENT_TIMESTAMP;\r\n RETURN NEW;\r\n END;\r\n $$ language 'plpgsql';\r\n `,\r\n\r\n /**\r\n * Create an updated_at trigger for a table\r\n */\r\n createUpdatedAtTrigger: (tableName: string) => `\r\n CREATE TRIGGER update_${tableName}_updated_at\r\n BEFORE UPDATE ON \"${tableName}\"\r\n FOR EACH ROW\r\n EXECUTE FUNCTION update_updated_at_column();\r\n `,\r\n\r\n /**\r\n * Drop an updated_at trigger\r\n */\r\n dropUpdatedAtTrigger: (tableName: string) => `\r\n DROP TRIGGER IF EXISTS update_${tableName}_updated_at ON \"${tableName}\";\r\n `,\r\n\r\n /**\r\n * Standard timestamp columns\r\n */\r\n timestampColumns: `\r\n created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,\r\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL\r\n `,\r\n\r\n /**\r\n * UUID primary key with default\r\n */\r\n uuidPrimaryKey: `id UUID PRIMARY KEY DEFAULT gen_random_uuid()`,\r\n\r\n /**\r\n * Enable UUID extension\r\n */\r\n enableUuidExtension: `CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"`,\r\n\r\n /**\r\n * Enable pgcrypto for gen_random_uuid()\r\n */\r\n enablePgCrypto: `CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"`,\r\n};\r\n"],"mappings":"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","names":["data","error","query","PostgresDatabase","SupabaseDatabase","RedisCache","UpstashCache","SupabaseStorage","S3Storage","SmtpEmail","ResendEmail","BullMQQueue","OpenTelemetryTracing","value","withTimeout"]}
1
+ {"version":3,"sources":["../src/adapters/postgres/PostgresDatabase.ts","../src/adapters/supabase/SupabaseDatabase.ts","../src/adapters/redis/RedisCache.ts","../src/adapters/upstash/UpstashCache.ts","../src/adapters/supabase-storage/SupabaseStorage.ts","../src/adapters/s3/S3Storage.ts","../src/adapters/smtp/SmtpEmail.ts","../src/adapters/resend/ResendEmail.ts","../src/adapters/bullmq/BullMQQueue.ts","../src/adapters/opentelemetry/OpenTelemetryTracing.ts","../src/interfaces/IQueue.ts","../src/interfaces/IHealth.ts","../src/interfaces/ILogger.ts","../src/interfaces/IMetrics.ts","../src/interfaces/ISecrets.ts","../src/interfaces/ITracing.ts","../src/interfaces/IErrorReporter.ts","../src/interfaces/IAuditLog.ts","../src/interfaces/IScheduler.ts","../src/interfaces/IWebhook.ts","../src/interfaces/INotification.ts","../src/config.ts","../src/adapters/memory/MemoryDatabase.ts","../src/adapters/memory/MemoryCache.ts","../src/adapters/memory/MemoryStorage.ts","../src/adapters/memory/MemoryEmail.ts","../src/context/CorrelationContext.ts","../src/adapters/memory/MemoryQueue.ts","../src/adapters/console/ConsoleEmail.ts","../src/factory.ts","../src/middleware/chain.ts","../src/middleware/builtin.ts","../src/hooks/registry.ts","../src/resilience/retry.ts","../src/resilience/circuit-breaker.ts","../src/resilience/timeout.ts","../src/resilience/bulkhead.ts","../src/resilience/fallback.ts","../src/http/health.ts","../src/http/metrics.ts","../src/adapters/memory/MemoryErrorReporter.ts","../src/adapters/memory/MemoryAuditLog.ts","../src/adapters/memory/MemoryWebhook.ts","../src/adapters/memory/MemoryNotification.ts","../src/adapters/supabase/index.ts","../src/adapters/postgres/index.ts","../src/adapters/upstash/index.ts","../src/adapters/redis/index.ts","../src/adapters/s3/index.ts","../src/adapters/supabase-storage/index.ts","../src/adapters/resend/index.ts","../src/adapters/smtp/index.ts","../src/adapters/bullmq/index.ts","../src/adapters/database/DatabaseAuditLog.ts","../src/adapters/database/DatabaseErrorReporter.ts","../src/adapters/scheduler/QueueScheduler.ts","../src/adapters/webhook/HttpWebhook.ts","../src/migrations/Migrator.ts","../src/migrations/helpers.ts"],"sourcesContent":["/**\r\n * PostgreSQL Direct Database Adapter\r\n *\r\n * Production implementation using pg (node-postgres) for direct PostgreSQL connections.\r\n * Provides true ACID transaction support, connection pooling, and prepared statements.\r\n *\r\n * This adapter is vendor-agnostic - works with any PostgreSQL-compatible database:\r\n * - PostgreSQL (self-hosted or managed)\r\n * - Amazon RDS PostgreSQL\r\n * - Azure Database for PostgreSQL\r\n * - Google Cloud SQL for PostgreSQL\r\n * - CockroachDB (PostgreSQL wire protocol)\r\n * - YugabyteDB\r\n * - Neon, Supabase (direct connection, not REST)\r\n */\r\n\r\nimport type { Pool, PoolClient, PoolConfig, QueryResult as PgQueryResult } from 'pg';\r\nimport { IDatabase, IQueryBuilder, QueryResult } from '../../interfaces/IDatabase';\r\n\r\nexport interface PostgresConfig {\r\n /** Connection string (postgresql://user:pass@host:port/database) */\r\n connectionString?: string;\r\n\r\n /** Host name */\r\n host?: string;\r\n\r\n /** Port number */\r\n port?: number;\r\n\r\n /** Database name */\r\n database?: string;\r\n\r\n /** Username */\r\n user?: string;\r\n\r\n /** Password */\r\n password?: string;\r\n\r\n /** SSL configuration */\r\n ssl?: boolean | { rejectUnauthorized?: boolean; ca?: string };\r\n\r\n /** Maximum number of connections in pool */\r\n max?: number;\r\n\r\n /** Idle timeout in milliseconds */\r\n idleTimeoutMillis?: number;\r\n\r\n /** Connection timeout in milliseconds */\r\n connectionTimeoutMillis?: number;\r\n\r\n /** Statement timeout in milliseconds (0 = no limit) */\r\n statementTimeout?: number;\r\n\r\n /** Query timeout in milliseconds (0 = no limit) */\r\n queryTimeout?: number;\r\n\r\n /** Application name for connection identification */\r\n applicationName?: string;\r\n}\r\n\r\n/**\r\n * Convert our config to pg pool config\r\n */\r\nfunction toPoolConfig(config: PostgresConfig): PoolConfig {\r\n const poolConfig: PoolConfig = {};\r\n\r\n if (config.connectionString) {\r\n poolConfig.connectionString = config.connectionString;\r\n } else {\r\n poolConfig.host = config.host;\r\n poolConfig.port = config.port;\r\n poolConfig.database = config.database;\r\n poolConfig.user = config.user;\r\n poolConfig.password = config.password;\r\n }\r\n\r\n if (config.ssl !== undefined) {\r\n poolConfig.ssl = config.ssl;\r\n }\r\n\r\n poolConfig.max = config.max ?? 10;\r\n poolConfig.idleTimeoutMillis = config.idleTimeoutMillis ?? 30000;\r\n poolConfig.connectionTimeoutMillis = config.connectionTimeoutMillis ?? 10000;\r\n poolConfig.application_name = config.applicationName ?? 'platform-core';\r\n\r\n // Statement timeout\r\n if (config.statementTimeout) {\r\n poolConfig.statement_timeout = config.statementTimeout;\r\n }\r\n\r\n // Query timeout\r\n if (config.queryTimeout) {\r\n poolConfig.query_timeout = config.queryTimeout;\r\n }\r\n\r\n return poolConfig;\r\n}\r\n\r\nexport class PostgresDatabase implements IDatabase {\r\n private pool: Pool;\r\n private config: PostgresConfig;\r\n\r\n constructor(pool: Pool, config: PostgresConfig = {}) {\r\n this.pool = pool;\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create a PostgresDatabase from configuration\r\n */\r\n static async create(config: PostgresConfig): Promise<PostgresDatabase> {\r\n // Dynamic import to keep pg as optional peer dependency\r\n const { Pool } = await import('pg');\r\n const poolConfig = toPoolConfig(config);\r\n const pool = new Pool(poolConfig);\r\n\r\n // Test connection\r\n const client = await pool.connect();\r\n client.release();\r\n\r\n return new PostgresDatabase(pool, config);\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<PostgresDatabase> {\r\n const config: PostgresConfig = {\r\n connectionString: process.env.DATABASE_URL,\r\n host: process.env.POSTGRES_HOST ?? process.env.PGHOST,\r\n port: parseInt(process.env.POSTGRES_PORT ?? process.env.PGPORT ?? '5432', 10),\r\n database: process.env.POSTGRES_DATABASE ?? process.env.PGDATABASE,\r\n user: process.env.POSTGRES_USER ?? process.env.PGUSER,\r\n password: process.env.POSTGRES_PASSWORD ?? process.env.PGPASSWORD,\r\n max: parseInt(process.env.POSTGRES_POOL_MAX ?? '10', 10),\r\n ssl:\r\n process.env.POSTGRES_SSL === 'true'\r\n ? { rejectUnauthorized: process.env.POSTGRES_SSL_REJECT_UNAUTHORIZED !== 'false' }\r\n : undefined,\r\n applicationName: process.env.POSTGRES_APP_NAME ?? 'platform-core',\r\n };\r\n\r\n return PostgresDatabase.create(config);\r\n }\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new PostgresQueryBuilder<T>(this.pool, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n try {\r\n const result: PgQueryResult = await this.pool.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Execute a function within a database transaction.\r\n * Provides true ACID guarantees - either all operations succeed or all are rolled back.\r\n */\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n const client = await this.pool.connect();\r\n\r\n try {\r\n await client.query('BEGIN');\r\n\r\n // Create a transaction-scoped database instance\r\n const txDatabase = new TransactionDatabase(client);\r\n\r\n const result = await fn(txDatabase);\r\n\r\n await client.query('COMMIT');\r\n return result;\r\n } catch (error) {\r\n await client.query('ROLLBACK');\r\n throw error;\r\n } finally {\r\n client.release();\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.pool.query('SELECT 1 as health');\r\n return result.rows.length > 0;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.pool.end();\r\n }\r\n\r\n /**\r\n * Get pool statistics for monitoring\r\n */\r\n getPoolStats(): {\r\n totalCount: number;\r\n idleCount: number;\r\n waitingCount: number;\r\n } {\r\n return {\r\n totalCount: this.pool.totalCount,\r\n idleCount: this.pool.idleCount,\r\n waitingCount: this.pool.waitingCount,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Transaction-scoped database that uses a single client connection\r\n */\r\nclass TransactionDatabase implements IDatabase {\r\n constructor(private client: PoolClient) {}\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new PostgresQueryBuilder<T>(this.client, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n try {\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n // Nested transaction using savepoint\r\n const savepointName = `sp_${Date.now()}_${Math.random().toString(36).slice(2)}`;\r\n\r\n try {\r\n await this.client.query(`SAVEPOINT ${savepointName}`);\r\n const result = await fn(this);\r\n await this.client.query(`RELEASE SAVEPOINT ${savepointName}`);\r\n return result;\r\n } catch (error) {\r\n await this.client.query(`ROLLBACK TO SAVEPOINT ${savepointName}`);\r\n throw error;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n await this.client.query('SELECT 1');\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Transaction database doesn't own the client, so don't close\r\n }\r\n}\r\n\r\n/**\r\n * PostgreSQL Query Builder\r\n */\r\nclass PostgresQueryBuilder<T = unknown> implements IQueryBuilder<T> {\r\n private client: Pool | PoolClient;\r\n private tableName: string;\r\n private _select: string[] = ['*'];\r\n private _where: Array<{ column: string; operator: string; value: unknown }> = [];\r\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\r\n private _orderBy: { column: string; direction: 'asc' | 'desc' } | null = null;\r\n private _limit: number | null = null;\r\n private _offset: number = 0;\r\n private _insertData: Partial<T>[] | null = null;\r\n private _updateData: Partial<T> | null = null;\r\n private _deleteFlag: boolean = false;\r\n private _returning: string[] = ['*'];\r\n\r\n constructor(client: Pool | PoolClient, tableName: string) {\r\n this.client = client;\r\n this.tableName = this.escapeIdentifier(tableName);\r\n }\r\n\r\n select(columns?: string | string[]): IQueryBuilder<T> {\r\n if (columns) {\r\n this._select = Array.isArray(columns) ? columns : [columns];\r\n }\r\n return this;\r\n }\r\n\r\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\r\n this._insertData = Array.isArray(data) ? data : [data];\r\n return this;\r\n }\r\n\r\n update(data: Partial<T>): IQueryBuilder<T> {\r\n this._updateData = data;\r\n return this;\r\n }\r\n\r\n delete(): IQueryBuilder<T> {\r\n this._deleteFlag = true;\r\n return this;\r\n }\r\n\r\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\r\n this._where.push({ column, operator, value });\r\n return this;\r\n }\r\n\r\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\r\n this._whereIn.push({ column, values });\r\n return this;\r\n }\r\n\r\n orderBy(column: string, direction: 'asc' | 'desc' = 'asc'): IQueryBuilder<T> {\r\n this._orderBy = { column, direction };\r\n return this;\r\n }\r\n\r\n limit(count: number): IQueryBuilder<T> {\r\n this._limit = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): IQueryBuilder<T> {\r\n this._offset = count;\r\n return this;\r\n }\r\n\r\n async single(): Promise<{ data: T | null; error?: Error }> {\r\n this._limit = 1;\r\n const result = await this.execute();\r\n\r\n if (result.error) {\r\n return { data: null, error: result.error };\r\n }\r\n\r\n return { data: result.data[0] ?? null };\r\n }\r\n\r\n async execute(): Promise<QueryResult<T>> {\r\n try {\r\n if (this._insertData) {\r\n return await this.executeInsert();\r\n }\r\n\r\n if (this._updateData) {\r\n return await this.executeUpdate();\r\n }\r\n\r\n if (this._deleteFlag) {\r\n return await this.executeDelete();\r\n }\r\n\r\n return await this.executeSelect();\r\n } catch (error) {\r\n return {\r\n data: [],\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n private async executeSelect(): Promise<QueryResult<T>> {\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SELECT clause\r\n const selectClause = this._select.map((col) => this.escapeIdentifier(col)).join(', ');\r\n let sql = `SELECT ${selectClause} FROM ${this.tableName}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n // Build ORDER BY\r\n if (this._orderBy) {\r\n sql += ` ORDER BY ${this.escapeIdentifier(this._orderBy.column)} ${this._orderBy.direction.toUpperCase()}`;\r\n }\r\n\r\n // Build LIMIT and OFFSET\r\n if (this._limit !== null) {\r\n sql += ` LIMIT $${paramIndex++}`;\r\n params.push(this._limit);\r\n }\r\n\r\n if (this._offset > 0) {\r\n sql += ` OFFSET $${paramIndex++}`;\r\n params.push(this._offset);\r\n }\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeInsert(): Promise<QueryResult<T>> {\r\n if (!this._insertData || this._insertData.length === 0) {\r\n return { data: [] };\r\n }\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Get all unique columns from the data\r\n const columns = new Set<string>();\r\n for (const row of this._insertData) {\r\n Object.keys(row as object).forEach((key) => columns.add(key));\r\n }\r\n const columnList = Array.from(columns);\r\n\r\n // Build column list\r\n const columnClause = columnList.map((col) => this.escapeIdentifier(col)).join(', ');\r\n\r\n // Build values\r\n const valueRows: string[] = [];\r\n for (const row of this._insertData) {\r\n const rowValues: string[] = [];\r\n for (const col of columnList) {\r\n rowValues.push(`$${paramIndex++}`);\r\n params.push((row as Record<string, unknown>)[col] ?? null);\r\n }\r\n valueRows.push(`(${rowValues.join(', ')})`);\r\n }\r\n\r\n const sql = `INSERT INTO ${this.tableName} (${columnClause}) VALUES ${valueRows.join(', ')} RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeUpdate(): Promise<QueryResult<T>> {\r\n if (!this._updateData) {\r\n return { data: [] };\r\n }\r\n\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n // Build SET clause\r\n const setClauses: string[] = [];\r\n for (const [key, value] of Object.entries(this._updateData as object)) {\r\n setClauses.push(`${this.escapeIdentifier(key)} = $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n let sql = `UPDATE ${this.tableName} SET ${setClauses.join(', ')}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n sql += ` RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private async executeDelete(): Promise<QueryResult<T>> {\r\n const params: unknown[] = [];\r\n let paramIndex = 1;\r\n\r\n let sql = `DELETE FROM ${this.tableName}`;\r\n\r\n // Build WHERE clause\r\n const whereClauses: string[] = [];\r\n\r\n for (const { column, operator, value } of this._where) {\r\n whereClauses.push(`${this.escapeIdentifier(column)} ${this.mapOperator(operator)} $${paramIndex++}`);\r\n params.push(value);\r\n }\r\n\r\n for (const { column, values } of this._whereIn) {\r\n const placeholders = values.map(() => `$${paramIndex++}`).join(', ');\r\n whereClauses.push(`${this.escapeIdentifier(column)} IN (${placeholders})`);\r\n params.push(...values);\r\n }\r\n\r\n if (whereClauses.length > 0) {\r\n sql += ` WHERE ${whereClauses.join(' AND ')}`;\r\n }\r\n\r\n sql += ` RETURNING ${this._returning.join(', ')}`;\r\n\r\n const result = await this.client.query(sql, params);\r\n return {\r\n data: result.rows as T[],\r\n count: result.rowCount ?? undefined,\r\n };\r\n }\r\n\r\n private escapeIdentifier(identifier: string): string {\r\n // Handle special cases\r\n if (identifier === '*') return '*';\r\n\r\n // Handle schema.table notation\r\n if (identifier.includes('.')) {\r\n return identifier\r\n .split('.')\r\n .map((part) => `\"${part.replace(/\"/g, '\"\"')}\"`)\r\n .join('.');\r\n }\r\n\r\n // Escape identifier with double quotes\r\n return `\"${identifier.replace(/\"/g, '\"\"')}\"`;\r\n }\r\n\r\n private mapOperator(operator: string): string {\r\n switch (operator.toLowerCase()) {\r\n case '=':\r\n case '==':\r\n return '=';\r\n case '!=':\r\n case '<>':\r\n return '<>';\r\n case '<':\r\n return '<';\r\n case '<=':\r\n return '<=';\r\n case '>':\r\n return '>';\r\n case '>=':\r\n return '>=';\r\n case 'like':\r\n return 'LIKE';\r\n case 'ilike':\r\n return 'ILIKE';\r\n case 'is':\r\n return 'IS';\r\n case 'is not':\r\n return 'IS NOT';\r\n default:\r\n return '=';\r\n }\r\n }\r\n}\r\n","/**\r\n * Supabase Database Adapter\r\n * Production implementation using Supabase as the database provider\r\n */\r\n\r\nimport type { SupabaseClient } from '@supabase/supabase-js';\r\nimport { IDatabase, IQueryBuilder, QueryResult } from '../../interfaces/IDatabase';\r\n\r\nexport interface SupabaseDatabaseConfig {\r\n url: string;\r\n anonKey: string;\r\n serviceRoleKey?: string;\r\n}\r\n\r\nexport class SupabaseDatabase implements IDatabase {\r\n private client: SupabaseClient;\r\n\r\n constructor(client: SupabaseClient) {\r\n this.client = client;\r\n }\r\n\r\n from<T = unknown>(table: string): IQueryBuilder<T> {\r\n return new SupabaseQueryBuilder<T>(this.client, table);\r\n }\r\n\r\n async raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>> {\r\n // Supabase RPC for raw SQL requires a database function\r\n // This is a limitation - prefer using from() for queries\r\n console.warn('SupabaseDatabase.raw() requires an RPC function. Consider using from() instead.');\r\n return { data: [] };\r\n }\r\n\r\n async transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T> {\r\n // Supabase REST API doesn't support true transactions\r\n // Operations run sequentially but not atomically\r\n console.warn('Supabase REST API does not support true transactions. Operations are not atomic.');\r\n return fn(this);\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n // Try a simple query to check connectivity\r\n const { error } = await this.client.from('_health_check').select('*').limit(1);\r\n // Table may not exist, but connection worked if no network error\r\n // PGRST116 = table not found, which is OK for health check\r\n return !error || error.code === 'PGRST116';\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Supabase client doesn't need explicit closing\r\n }\r\n}\r\n\r\nclass SupabaseQueryBuilder<T = unknown> implements IQueryBuilder<T> {\r\n private client: SupabaseClient;\r\n private tableName: string;\r\n private _select: string = '*';\r\n private _where: Array<{ column: string; operator: string; value: unknown }> = [];\r\n private _whereIn: Array<{ column: string; values: unknown[] }> = [];\r\n private _orderBy: { column: string; direction: 'asc' | 'desc' } | null = null;\r\n private _limit: number | null = null;\r\n private _offset: number = 0;\r\n private _insertData: Partial<T>[] | null = null;\r\n private _updateData: Partial<T> | null = null;\r\n private _deleteFlag: boolean = false;\r\n\r\n constructor(client: SupabaseClient, tableName: string) {\r\n this.client = client;\r\n this.tableName = tableName;\r\n }\r\n\r\n select(columns?: string | string[]): IQueryBuilder<T> {\r\n if (columns) {\r\n this._select = Array.isArray(columns) ? columns.join(', ') : columns;\r\n }\r\n return this;\r\n }\r\n\r\n insert(data: Partial<T> | Partial<T>[]): IQueryBuilder<T> {\r\n this._insertData = Array.isArray(data) ? data : [data];\r\n return this;\r\n }\r\n\r\n update(data: Partial<T>): IQueryBuilder<T> {\r\n this._updateData = data;\r\n return this;\r\n }\r\n\r\n delete(): IQueryBuilder<T> {\r\n this._deleteFlag = true;\r\n return this;\r\n }\r\n\r\n where(column: string, operator: string, value: unknown): IQueryBuilder<T> {\r\n this._where.push({ column, operator, value });\r\n return this;\r\n }\r\n\r\n whereIn(column: string, values: unknown[]): IQueryBuilder<T> {\r\n this._whereIn.push({ column, values });\r\n return this;\r\n }\r\n\r\n orderBy(column: string, direction: 'asc' | 'desc' = 'asc'): IQueryBuilder<T> {\r\n this._orderBy = { column, direction };\r\n return this;\r\n }\r\n\r\n limit(count: number): IQueryBuilder<T> {\r\n this._limit = count;\r\n return this;\r\n }\r\n\r\n offset(count: number): IQueryBuilder<T> {\r\n this._offset = count;\r\n return this;\r\n }\r\n\r\n async single(): Promise<{ data: T | null; error?: Error }> {\r\n const query = this.buildSelectQuery().limit(1).single();\r\n const { data, error } = await query;\r\n\r\n if (error && error.code !== 'PGRST116') {\r\n return { data: null, error: new Error(error.message) };\r\n }\r\n\r\n return { data: data as T | null };\r\n }\r\n\r\n async execute(): Promise<QueryResult<T>> {\r\n // Handle insert\r\n if (this._insertData) {\r\n const { data, error } = await this.client\r\n .from(this.tableName)\r\n .insert(this._insertData as Record<string, unknown>[])\r\n .select();\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n return { data: (data || []) as T[] };\r\n }\r\n\r\n // Handle update\r\n if (this._updateData) {\r\n let query = this.client\r\n .from(this.tableName)\r\n .update(this._updateData as Record<string, unknown>);\r\n\r\n query = this.applyFilters(query);\r\n const { data, error } = await query.select();\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n return { data: (data || []) as T[], count: data?.length };\r\n }\r\n\r\n // Handle delete\r\n if (this._deleteFlag) {\r\n let query = this.client.from(this.tableName).delete();\r\n query = this.applyFilters(query);\r\n const { data, error } = await query.select();\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n return { data: (data || []) as T[], count: data?.length };\r\n }\r\n\r\n // Handle select\r\n const query = this.buildSelectQuery();\r\n const { data, error, count } = await query;\r\n\r\n if (error) {\r\n return { data: [], error: new Error(error.message) };\r\n }\r\n\r\n return { data: (data || []) as T[], count: count ?? undefined };\r\n }\r\n\r\n private buildSelectQuery() {\r\n let query = this.client.from(this.tableName).select(this._select);\r\n\r\n // Apply where conditions\r\n query = this.applyFilters(query);\r\n\r\n // Apply ordering\r\n if (this._orderBy) {\r\n query = query.order(this._orderBy.column, { ascending: this._orderBy.direction === 'asc' });\r\n }\r\n\r\n // Apply pagination\r\n if (this._limit !== null) {\r\n query = query.limit(this._limit);\r\n }\r\n\r\n if (this._offset > 0) {\r\n query = query.range(this._offset, this._offset + (this._limit || 1000) - 1);\r\n }\r\n\r\n return query;\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private applyFilters(query: any): any {\r\n let result = query;\r\n\r\n // Apply where conditions\r\n for (const { column, operator, value } of this._where) {\r\n result = this.applyOperator(result, column, operator, value);\r\n }\r\n\r\n // Apply whereIn conditions\r\n for (const { column, values } of this._whereIn) {\r\n result = result.in(column, values);\r\n }\r\n\r\n return result;\r\n }\r\n\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n private applyOperator(query: any, column: string, operator: string, value: unknown): any {\r\n switch (operator) {\r\n case '=':\r\n case '==':\r\n return query.eq(column, value);\r\n case '!=':\r\n case '<>':\r\n return query.neq(column, value);\r\n case '<':\r\n return query.lt(column, value);\r\n case '<=':\r\n return query.lte(column, value);\r\n case '>':\r\n return query.gt(column, value);\r\n case '>=':\r\n return query.gte(column, value);\r\n case 'like':\r\n return query.like(column, value as string);\r\n case 'ilike':\r\n return query.ilike(column, value as string);\r\n case 'is':\r\n return query.is(column, value);\r\n case 'is not':\r\n return query.not(column, 'is', value);\r\n default:\r\n return query.eq(column, value);\r\n }\r\n }\r\n}\r\n","/**\r\n * Redis Direct Cache Adapter\r\n *\r\n * Production implementation using ioredis for direct Redis connections.\r\n * Provides lower latency than REST-based solutions, true pub/sub support,\r\n * and full Redis command set.\r\n *\r\n * This adapter is vendor-agnostic - works with any Redis-compatible server:\r\n * - Redis (self-hosted or managed)\r\n * - Amazon ElastiCache for Redis\r\n * - Azure Cache for Redis\r\n * - Google Cloud Memorystore for Redis\r\n * - Redis Enterprise\r\n * - KeyDB\r\n * - DragonflyDB\r\n */\r\n\r\nimport type { Redis as IORedis, RedisOptions as IORedisOptions } from 'ioredis';\r\nimport { ICache } from '../../interfaces/ICache';\r\n\r\nexport interface RedisConfig {\r\n /** Connection URL (redis://user:pass@host:port/db) */\r\n url?: string;\r\n\r\n /** Host name */\r\n host?: string;\r\n\r\n /** Port number */\r\n port?: number;\r\n\r\n /** Password */\r\n password?: string;\r\n\r\n /** Database number (0-15) */\r\n db?: number;\r\n\r\n /** Username (Redis 6+) */\r\n username?: string;\r\n\r\n /** Connection name for identification */\r\n name?: string;\r\n\r\n /** Key prefix for namespacing */\r\n keyPrefix?: string;\r\n\r\n /** Enable TLS */\r\n tls?: boolean | { rejectUnauthorized?: boolean; ca?: string };\r\n\r\n /** Connection timeout in milliseconds */\r\n connectTimeout?: number;\r\n\r\n /** Command timeout in milliseconds */\r\n commandTimeout?: number;\r\n\r\n /** Keep alive timeout */\r\n keepAlive?: number;\r\n\r\n /** Max retries per request */\r\n maxRetriesPerRequest?: number;\r\n\r\n /** Enable auto-reconnect */\r\n autoReconnect?: boolean;\r\n\r\n /** Lazy connect (don't connect until first command) */\r\n lazyConnect?: boolean;\r\n\r\n /** Enable offline queue */\r\n enableOfflineQueue?: boolean;\r\n\r\n /** Sentinel configuration for HA */\r\n sentinel?: {\r\n sentinels: Array<{ host: string; port: number }>;\r\n name: string;\r\n password?: string;\r\n };\r\n\r\n /** Cluster configuration */\r\n cluster?: {\r\n nodes: Array<{ host: string; port: number }>;\r\n options?: {\r\n scaleReads?: 'master' | 'slave' | 'all';\r\n maxRedirections?: number;\r\n };\r\n };\r\n}\r\n\r\n/**\r\n * Convert our config to ioredis options\r\n */\r\nfunction toIORedisOptions(config: RedisConfig): IORedisOptions | string {\r\n if (config.url) {\r\n return config.url;\r\n }\r\n\r\n const options: IORedisOptions = {};\r\n\r\n if (config.host) options.host = config.host;\r\n if (config.port) options.port = config.port;\r\n if (config.password) options.password = config.password;\r\n if (config.db !== undefined) options.db = config.db;\r\n if (config.username) options.username = config.username;\r\n if (config.name) options.name = config.name;\r\n if (config.keyPrefix) options.keyPrefix = config.keyPrefix;\r\n if (config.connectTimeout) options.connectTimeout = config.connectTimeout;\r\n if (config.commandTimeout) options.commandTimeout = config.commandTimeout;\r\n if (config.keepAlive) options.keepAlive = config.keepAlive;\r\n if (config.maxRetriesPerRequest !== undefined) {\r\n options.maxRetriesPerRequest = config.maxRetriesPerRequest;\r\n }\r\n if (config.lazyConnect) options.lazyConnect = config.lazyConnect;\r\n if (config.enableOfflineQueue !== undefined) {\r\n options.enableOfflineQueue = config.enableOfflineQueue;\r\n }\r\n\r\n // TLS configuration\r\n if (config.tls) {\r\n if (typeof config.tls === 'boolean') {\r\n options.tls = {};\r\n } else {\r\n options.tls = {\r\n rejectUnauthorized: config.tls.rejectUnauthorized,\r\n ca: config.tls.ca ? [config.tls.ca] : undefined,\r\n };\r\n }\r\n }\r\n\r\n return options;\r\n}\r\n\r\nexport class RedisCache implements ICache {\r\n private client: IORedis;\r\n private subscriberClient: IORedis | null = null;\r\n private config: RedisConfig;\r\n private subscriptions: Map<string, Set<(message: string) => void>> = new Map();\r\n\r\n constructor(client: IORedis, config: RedisConfig = {}) {\r\n this.client = client;\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create a RedisCache from configuration\r\n */\r\n static async create(config: RedisConfig): Promise<RedisCache> {\r\n // Dynamic import to keep ioredis as optional peer dependency\r\n const { default: Redis } = await import('ioredis');\r\n\r\n let client: IORedis;\r\n\r\n if (config.cluster) {\r\n // Cluster mode\r\n const { Cluster } = await import('ioredis');\r\n client = new Cluster(config.cluster.nodes, {\r\n scaleReads: config.cluster.options?.scaleReads ?? 'master',\r\n maxRedirections: config.cluster.options?.maxRedirections ?? 16,\r\n redisOptions: {\r\n password: config.password,\r\n ...(config.tls ? { tls: typeof config.tls === 'boolean' ? {} : config.tls } : {}),\r\n },\r\n }) as unknown as IORedis;\r\n } else if (config.sentinel) {\r\n // Sentinel mode (HA)\r\n client = new Redis({\r\n sentinels: config.sentinel.sentinels,\r\n name: config.sentinel.name,\r\n password: config.password,\r\n sentinelPassword: config.sentinel.password,\r\n ...(config.tls ? { tls: typeof config.tls === 'boolean' ? {} : config.tls } : {}),\r\n });\r\n } else {\r\n // Standard mode\r\n const options = toIORedisOptions(config);\r\n client = typeof options === 'string' ? new Redis(options) : new Redis(options);\r\n }\r\n\r\n // Wait for connection (unless lazy connect)\r\n if (!config.lazyConnect) {\r\n await new Promise<void>((resolve, reject) => {\r\n if (client.status === 'ready') {\r\n resolve();\r\n } else {\r\n client.once('ready', resolve);\r\n client.once('error', reject);\r\n }\r\n });\r\n }\r\n\r\n return new RedisCache(client, config);\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<RedisCache> {\r\n const config: RedisConfig = {\r\n url: process.env.REDIS_URL,\r\n host: process.env.REDIS_HOST,\r\n port: parseInt(process.env.REDIS_PORT ?? '6379', 10),\r\n password: process.env.REDIS_PASSWORD,\r\n db: process.env.REDIS_DB ? parseInt(process.env.REDIS_DB, 10) : undefined,\r\n keyPrefix: process.env.REDIS_KEY_PREFIX,\r\n tls: process.env.REDIS_TLS === 'true',\r\n };\r\n\r\n return RedisCache.create(config);\r\n }\r\n\r\n async get<T = unknown>(key: string): Promise<T | null> {\r\n const value = await this.client.get(key);\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n try {\r\n return JSON.parse(value) as T;\r\n } catch {\r\n // If not JSON, return as string (cast to T)\r\n return value as unknown as T;\r\n }\r\n }\r\n\r\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\r\n const serialized = typeof value === 'string' ? value : JSON.stringify(value);\r\n\r\n if (ttl) {\r\n await this.client.setex(key, ttl, serialized);\r\n } else {\r\n await this.client.set(key, serialized);\r\n }\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n await this.client.del(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n const result = await this.client.exists(key);\r\n return result > 0;\r\n }\r\n\r\n async deletePattern(pattern: string): Promise<number> {\r\n const keys: string[] = [];\r\n let cursor = '0';\r\n\r\n // Use SCAN for safe iteration in production\r\n do {\r\n const result = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\r\n cursor = result[0];\r\n keys.push(...result[1]);\r\n } while (cursor !== '0');\r\n\r\n if (keys.length === 0) {\r\n return 0;\r\n }\r\n\r\n // Delete in batches for efficiency\r\n const batchSize = 1000;\r\n let deleted = 0;\r\n\r\n for (let i = 0; i < keys.length; i += batchSize) {\r\n const batch = keys.slice(i, i + batchSize);\r\n deleted += await this.client.del(...batch);\r\n }\r\n\r\n return deleted;\r\n }\r\n\r\n async mget<T = unknown>(keys: string[]): Promise<(T | null)[]> {\r\n if (keys.length === 0) {\r\n return [];\r\n }\r\n\r\n const values = await this.client.mget(...keys);\r\n\r\n return values.map((value) => {\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n try {\r\n return JSON.parse(value) as T;\r\n } catch {\r\n return value as unknown as T;\r\n }\r\n });\r\n }\r\n\r\n async mset<T = unknown>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void> {\r\n if (entries.length === 0) {\r\n return;\r\n }\r\n\r\n // Group entries by TTL\r\n const noTtl: Array<{ key: string; value: T }> = [];\r\n const withTtl: Array<{ key: string; value: T; ttl: number }> = [];\r\n\r\n for (const entry of entries) {\r\n if (entry.ttl) {\r\n withTtl.push(entry as { key: string; value: T; ttl: number });\r\n } else {\r\n noTtl.push(entry);\r\n }\r\n }\r\n\r\n // Use pipeline for atomicity and performance\r\n const pipeline = this.client.pipeline();\r\n\r\n // MSET for entries without TTL\r\n if (noTtl.length > 0) {\r\n const args: string[] = [];\r\n for (const entry of noTtl) {\r\n args.push(entry.key);\r\n args.push(typeof entry.value === 'string' ? entry.value : JSON.stringify(entry.value));\r\n }\r\n pipeline.mset(...args);\r\n }\r\n\r\n // SETEX for entries with TTL\r\n for (const entry of withTtl) {\r\n const value = typeof entry.value === 'string' ? entry.value : JSON.stringify(entry.value);\r\n pipeline.setex(entry.key, entry.ttl, value);\r\n }\r\n\r\n await pipeline.exec();\r\n }\r\n\r\n async incr(key: string, by: number = 1): Promise<number> {\r\n return await this.client.incrby(key, by);\r\n }\r\n\r\n async publish(channel: string, message: string): Promise<void> {\r\n await this.client.publish(channel, message);\r\n }\r\n\r\n async subscribe(channel: string, callback: (message: string) => void): Promise<() => void> {\r\n // Create a dedicated subscriber client if needed\r\n if (!this.subscriberClient) {\r\n const { default: Redis } = await import('ioredis');\r\n const options = toIORedisOptions(this.config);\r\n this.subscriberClient =\r\n typeof options === 'string' ? new Redis(options) : new Redis(options);\r\n\r\n // Set up message handler\r\n this.subscriberClient.on('message', (ch: string, message: string) => {\r\n const callbacks = this.subscriptions.get(ch);\r\n if (callbacks) {\r\n for (const cb of callbacks) {\r\n try {\r\n cb(message);\r\n } catch (error) {\r\n console.error(`Error in subscription callback for channel ${ch}:`, error);\r\n }\r\n }\r\n }\r\n });\r\n }\r\n\r\n // Track subscription\r\n if (!this.subscriptions.has(channel)) {\r\n this.subscriptions.set(channel, new Set());\r\n await this.subscriberClient.subscribe(channel);\r\n }\r\n this.subscriptions.get(channel)!.add(callback);\r\n\r\n // Return unsubscribe function\r\n return async () => {\r\n const callbacks = this.subscriptions.get(channel);\r\n if (callbacks) {\r\n callbacks.delete(callback);\r\n if (callbacks.size === 0) {\r\n this.subscriptions.delete(channel);\r\n await this.subscriberClient?.unsubscribe(channel);\r\n }\r\n }\r\n };\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.client.ping();\r\n return result === 'PONG';\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this.subscriberClient) {\r\n await this.subscriberClient.quit();\r\n this.subscriberClient = null;\r\n }\r\n await this.client.quit();\r\n this.subscriptions.clear();\r\n }\r\n\r\n /**\r\n * Get connection info for monitoring\r\n */\r\n getConnectionInfo(): {\r\n status: string;\r\n host?: string;\r\n port?: number;\r\n } {\r\n return {\r\n status: this.client.status,\r\n host: this.config.host,\r\n port: this.config.port,\r\n };\r\n }\r\n\r\n /**\r\n * Execute arbitrary Redis command\r\n */\r\n async command<T = unknown>(command: string, ...args: unknown[]): Promise<T> {\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n return await (this.client as any).call(command, ...args);\r\n }\r\n\r\n /**\r\n * Get TTL of a key\r\n */\r\n async ttl(key: string): Promise<number> {\r\n return await this.client.ttl(key);\r\n }\r\n\r\n /**\r\n * Set expiry on an existing key\r\n */\r\n async expire(key: string, seconds: number): Promise<boolean> {\r\n const result = await this.client.expire(key, seconds);\r\n return result === 1;\r\n }\r\n\r\n /**\r\n * Get all keys matching a pattern (use with caution in production)\r\n */\r\n async keys(pattern: string): Promise<string[]> {\r\n const keys: string[] = [];\r\n let cursor = '0';\r\n\r\n do {\r\n const result = await this.client.scan(cursor, 'MATCH', pattern, 'COUNT', 100);\r\n cursor = result[0];\r\n keys.push(...result[1]);\r\n } while (cursor !== '0');\r\n\r\n return keys;\r\n }\r\n}\r\n","/**\r\n * Upstash Redis Cache Adapter\r\n * Production implementation using Upstash Redis REST API\r\n */\r\n\r\nimport type { Redis } from '@upstash/redis';\r\nimport { ICache } from '../../interfaces/ICache';\r\n\r\nexport interface UpstashCacheConfig {\r\n url: string;\r\n token: string;\r\n}\r\n\r\nexport class UpstashCache implements ICache {\r\n private client: Redis;\r\n\r\n constructor(client: Redis) {\r\n this.client = client;\r\n }\r\n\r\n async get<T = unknown>(key: string): Promise<T | null> {\r\n const value = await this.client.get<T>(key);\r\n return value ?? null;\r\n }\r\n\r\n async set<T = unknown>(key: string, value: T, ttl?: number): Promise<void> {\r\n if (ttl) {\r\n await this.client.set(key, value, { ex: ttl });\r\n } else {\r\n await this.client.set(key, value);\r\n }\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n await this.client.del(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n const result = await this.client.exists(key);\r\n return result > 0;\r\n }\r\n\r\n async deletePattern(pattern: string): Promise<number> {\r\n // Upstash SCAN + DEL for pattern deletion\r\n const keys: string[] = [];\r\n let cursor: string | number = 0;\r\n\r\n do {\r\n const result: [string | number, string[]] = await this.client.scan(cursor, { match: pattern, count: 100 });\r\n cursor = result[0];\r\n keys.push(...result[1]);\r\n } while (cursor !== 0 && cursor !== '0');\r\n\r\n if (keys.length === 0) {\r\n return 0;\r\n }\r\n\r\n const deleted = await this.client.del(...keys);\r\n return deleted;\r\n }\r\n\r\n async mget<T = unknown>(keys: string[]): Promise<(T | null)[]> {\r\n if (keys.length === 0) {\r\n return [];\r\n }\r\n const results = await this.client.mget<(T | null)[]>(...keys);\r\n return results;\r\n }\r\n\r\n async mset<T = unknown>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void> {\r\n if (entries.length === 0) {\r\n return;\r\n }\r\n\r\n // Use pipeline for better performance\r\n const pipeline = this.client.pipeline();\r\n\r\n for (const entry of entries) {\r\n if (entry.ttl) {\r\n pipeline.set(entry.key, entry.value, { ex: entry.ttl });\r\n } else {\r\n pipeline.set(entry.key, entry.value);\r\n }\r\n }\r\n\r\n await pipeline.exec();\r\n }\r\n\r\n async incr(key: string, by: number = 1): Promise<number> {\r\n return await this.client.incrby(key, by);\r\n }\r\n\r\n async publish(channel: string, message: string): Promise<void> {\r\n await this.client.publish(channel, message);\r\n }\r\n\r\n async subscribe(channel: string, callback: (message: string) => void): Promise<() => void> {\r\n // Upstash REST API doesn't support subscriptions natively\r\n // Would need WebSocket or polling implementation\r\n console.warn(\r\n 'UpstashCache.subscribe() is not supported via REST API. ' +\r\n 'Use a direct Redis connection or implement polling for pub/sub functionality.'\r\n );\r\n return () => {};\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const result = await this.client.ping();\r\n return result === 'PONG';\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Upstash REST client doesn't need explicit closing\r\n }\r\n}\r\n","/**\r\n * Supabase Storage Adapter\r\n *\r\n * Production implementation using Supabase Storage for file management.\r\n * Provides vendor-agnostic file storage via Supabase's storage buckets.\r\n *\r\n * Features:\r\n * - Simple bucket-based file storage\r\n * - Automatic public URL generation\r\n * - Signed URL support for private files\r\n * - Built-in CDN caching\r\n */\r\n\r\nimport type { SupabaseClient } from '@supabase/supabase-js';\r\nimport { IStorage, StorageFile, UploadOptions } from '../../interfaces/IStorage';\r\n\r\nexport interface SupabaseStorageConfig {\r\n /** Supabase project URL */\r\n url: string;\r\n\r\n /** Supabase API key (anon or service role) */\r\n apiKey: string;\r\n\r\n /** Default bucket name */\r\n bucket: string;\r\n\r\n /** Whether the bucket is public */\r\n publicBucket?: boolean;\r\n\r\n /** Default signed URL expiry in seconds */\r\n signedUrlExpiry?: number;\r\n}\r\n\r\nexport class SupabaseStorage implements IStorage {\r\n private client: SupabaseClient;\r\n private bucket: string;\r\n private publicBucket: boolean;\r\n private signedUrlExpiry: number;\r\n\r\n constructor(client: SupabaseClient, config: { bucket: string; publicBucket?: boolean; signedUrlExpiry?: number }) {\r\n this.client = client;\r\n this.bucket = config.bucket;\r\n this.publicBucket = config.publicBucket ?? false;\r\n this.signedUrlExpiry = config.signedUrlExpiry ?? 3600;\r\n }\r\n\r\n /**\r\n * Create a SupabaseStorage adapter from configuration\r\n */\r\n static async create(config: SupabaseStorageConfig): Promise<SupabaseStorage> {\r\n const { createClient } = await import('@supabase/supabase-js');\r\n const client = createClient(config.url, config.apiKey);\r\n\r\n return new SupabaseStorage(client, {\r\n bucket: config.bucket,\r\n publicBucket: config.publicBucket,\r\n signedUrlExpiry: config.signedUrlExpiry,\r\n });\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<SupabaseStorage> {\r\n const url = process.env.SUPABASE_URL;\r\n const apiKey = process.env.SUPABASE_SERVICE_ROLE_KEY ?? process.env.SUPABASE_ANON_KEY;\r\n const bucket = process.env.SUPABASE_STORAGE_BUCKET ?? 'uploads';\r\n\r\n if (!url || !apiKey) {\r\n throw new Error('SUPABASE_URL and SUPABASE_ANON_KEY are required');\r\n }\r\n\r\n return SupabaseStorage.create({\r\n url,\r\n apiKey,\r\n bucket,\r\n publicBucket: process.env.SUPABASE_STORAGE_PUBLIC === 'true',\r\n signedUrlExpiry: process.env.SUPABASE_SIGNED_URL_EXPIRY\r\n ? parseInt(process.env.SUPABASE_SIGNED_URL_EXPIRY, 10)\r\n : undefined,\r\n });\r\n }\r\n\r\n async upload(key: string, data: Buffer | Blob | ReadableStream, options?: UploadOptions): Promise<{ url: string }> {\r\n // Convert ReadableStream to Buffer if needed\r\n let content: Buffer | Blob;\r\n if (data instanceof ReadableStream) {\r\n const chunks: Uint8Array[] = [];\r\n const reader = data.getReader();\r\n while (true) {\r\n const { done, value } = await reader.read();\r\n if (done) break;\r\n chunks.push(value);\r\n }\r\n content = Buffer.concat(chunks);\r\n } else {\r\n content = data;\r\n }\r\n\r\n const { data: uploadData, error } = await this.client.storage.from(this.bucket).upload(key, content, {\r\n contentType: options?.contentType,\r\n upsert: true,\r\n });\r\n\r\n if (error) {\r\n throw new Error(`Failed to upload file: ${error.message}`);\r\n }\r\n\r\n const url = await this.getUrl(key);\r\n return { url };\r\n }\r\n\r\n async download(path: string): Promise<Buffer> {\r\n const { data, error } = await this.client.storage.from(this.bucket).download(path);\r\n\r\n if (error) {\r\n throw new Error(`Failed to download file: ${error.message}`);\r\n }\r\n\r\n // Convert Blob to Buffer\r\n const arrayBuffer = await data.arrayBuffer();\r\n return Buffer.from(arrayBuffer);\r\n }\r\n\r\n async delete(path: string): Promise<void> {\r\n const { error } = await this.client.storage.from(this.bucket).remove([path]);\r\n\r\n if (error) {\r\n throw new Error(`Failed to delete file: ${error.message}`);\r\n }\r\n }\r\n\r\n async deleteMany(paths: string[]): Promise<void> {\r\n const { error } = await this.client.storage.from(this.bucket).remove(paths);\r\n\r\n if (error) {\r\n throw new Error(`Failed to delete files: ${error.message}`);\r\n }\r\n }\r\n\r\n async getMetadata(path: string): Promise<StorageFile | null> {\r\n // Supabase doesn't have a direct getMetadata method, so we need to list and find\r\n const dir = this.getDirectory(path);\r\n const filename = this.getFilename(path);\r\n\r\n const { data, error } = await this.client.storage.from(this.bucket).list(dir, {\r\n limit: 1000,\r\n search: filename,\r\n });\r\n\r\n if (error || !data) {\r\n return null;\r\n }\r\n\r\n const file = data.find((f) => f.name === filename);\r\n if (!file || !file.id) {\r\n return null;\r\n }\r\n\r\n return {\r\n key: path,\r\n size: (file.metadata?.size as number) ?? 0,\r\n contentType: file.metadata?.mimetype as string | undefined,\r\n lastModified: file.updated_at ? new Date(file.updated_at) : undefined,\r\n };\r\n }\r\n\r\n async exists(path: string): Promise<boolean> {\r\n const { data, error } = await this.client.storage.from(this.bucket).list(this.getDirectory(path), {\r\n limit: 1,\r\n search: this.getFilename(path),\r\n });\r\n\r\n if (error) {\r\n return false;\r\n }\r\n\r\n return data.some((file) => file.name === this.getFilename(path));\r\n }\r\n\r\n async list(prefix?: string): Promise<StorageFile[]> {\r\n const folder = prefix ?? '';\r\n const { data, error } = await this.client.storage.from(this.bucket).list(folder, {\r\n limit: 1000,\r\n });\r\n\r\n if (error) {\r\n throw new Error(`Failed to list files: ${error.message}`);\r\n }\r\n\r\n const files: StorageFile[] = [];\r\n\r\n for (const item of data) {\r\n if (item.id) {\r\n // It's a file (folders don't have an id)\r\n const filePath = folder ? `${folder}/${item.name}` : item.name;\r\n files.push({\r\n key: filePath,\r\n size: (item.metadata?.size as number) ?? 0,\r\n contentType: item.metadata?.mimetype as string | undefined,\r\n lastModified: item.updated_at ? new Date(item.updated_at) : undefined,\r\n });\r\n }\r\n }\r\n\r\n return files;\r\n }\r\n\r\n async getSignedUrl(path: string, expiresIn?: number): Promise<string> {\r\n const { data, error } = await this.client.storage\r\n .from(this.bucket)\r\n .createSignedUrl(path, expiresIn ?? this.signedUrlExpiry);\r\n\r\n if (error) {\r\n throw new Error(`Failed to create signed URL: ${error.message}`);\r\n }\r\n\r\n return data.signedUrl;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n // Try to list files (limited to 1) to verify access\r\n const { error } = await this.client.storage.from(this.bucket).list('', { limit: 1 });\r\n return !error;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Get URL for a file (public URL or signed URL based on bucket config)\r\n */\r\n private async getUrl(path: string): Promise<string> {\r\n if (this.publicBucket) {\r\n const { data } = this.client.storage.from(this.bucket).getPublicUrl(path);\r\n return data.publicUrl;\r\n }\r\n\r\n return this.getSignedUrl(path);\r\n }\r\n\r\n /**\r\n * Get directory from path\r\n */\r\n private getDirectory(path: string): string {\r\n const lastSlash = path.lastIndexOf('/');\r\n return lastSlash > 0 ? path.substring(0, lastSlash) : '';\r\n }\r\n\r\n /**\r\n * Get filename from path\r\n */\r\n private getFilename(path: string): string {\r\n const lastSlash = path.lastIndexOf('/');\r\n return lastSlash > 0 ? path.substring(lastSlash + 1) : path;\r\n }\r\n\r\n /**\r\n * Get storage bucket info\r\n */\r\n getBucketInfo(): { bucket: string; publicBucket: boolean } {\r\n return {\r\n bucket: this.bucket,\r\n publicBucket: this.publicBucket,\r\n };\r\n }\r\n\r\n /**\r\n * Copy file to new location\r\n */\r\n async copy(sourcePath: string, destPath: string): Promise<{ key: string; url: string }> {\r\n const { data, error } = await this.client.storage.from(this.bucket).copy(sourcePath, destPath);\r\n\r\n if (error) {\r\n throw new Error(`Failed to copy file: ${error.message}`);\r\n }\r\n\r\n return {\r\n key: destPath,\r\n url: await this.getUrl(destPath),\r\n };\r\n }\r\n\r\n /**\r\n * Move file to new location\r\n */\r\n async move(sourcePath: string, destPath: string): Promise<{ key: string; url: string }> {\r\n const { data, error } = await this.client.storage.from(this.bucket).move(sourcePath, destPath);\r\n\r\n if (error) {\r\n throw new Error(`Failed to move file: ${error.message}`);\r\n }\r\n\r\n return {\r\n key: destPath,\r\n url: await this.getUrl(destPath),\r\n };\r\n }\r\n}\r\n","/**\r\n * S3 Storage Adapter\r\n * Production implementation using AWS S3 (compatible with MinIO, R2, etc.)\r\n */\r\n\r\nimport type { S3Client } from '@aws-sdk/client-s3';\r\nimport type { getSignedUrl as GetSignedUrlFn } from '@aws-sdk/s3-request-presigner';\r\nimport { IStorage, StorageFile, UploadOptions } from '../../interfaces/IStorage';\r\n\r\nexport interface S3StorageConfig {\r\n endpoint?: string;\r\n region: string;\r\n accessKeyId: string;\r\n secretAccessKey: string;\r\n bucket: string;\r\n forcePathStyle?: boolean;\r\n publicUrl?: string;\r\n}\r\n\r\nexport class S3Storage implements IStorage {\r\n private client: S3Client;\r\n private bucket: string;\r\n private publicUrl?: string;\r\n private signedUrlFn: typeof GetSignedUrlFn;\r\n\r\n constructor(\r\n client: S3Client,\r\n bucket: string,\r\n getSignedUrlFn: typeof GetSignedUrlFn,\r\n publicUrl?: string\r\n ) {\r\n this.client = client;\r\n this.bucket = bucket;\r\n this.signedUrlFn = getSignedUrlFn;\r\n this.publicUrl = publicUrl;\r\n }\r\n\r\n async upload(\r\n key: string,\r\n data: Buffer | Blob | ReadableStream,\r\n options?: UploadOptions\r\n ): Promise<{ url: string }> {\r\n // Convert Blob to Buffer if needed\r\n let body: Buffer | ReadableStream;\r\n if (data instanceof Blob) {\r\n body = Buffer.from(await data.arrayBuffer());\r\n } else {\r\n body = data;\r\n }\r\n\r\n const { PutObjectCommand: PutCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new PutCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n Body: body as Buffer,\r\n ContentType: options?.contentType,\r\n Metadata: options?.metadata,\r\n ACL: options?.public ? 'public-read' : undefined,\r\n })\r\n );\r\n\r\n // Return the URL\r\n const url = this.publicUrl\r\n ? `${this.publicUrl}/${key}`\r\n : await this.createSignedUrl(key);\r\n\r\n return { url };\r\n }\r\n\r\n async download(key: string): Promise<Buffer> {\r\n const { GetObjectCommand: GetCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const response = await this.client.send(\r\n new GetCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n\r\n const stream = response.Body;\r\n if (!stream) {\r\n throw new Error('Empty response body');\r\n }\r\n\r\n // Convert stream to buffer\r\n const chunks: Uint8Array[] = [];\r\n for await (const chunk of stream as AsyncIterable<Uint8Array>) {\r\n chunks.push(chunk);\r\n }\r\n return Buffer.concat(chunks);\r\n }\r\n\r\n async getSignedUrl(key: string, expiresIn: number = 3600): Promise<string> {\r\n return this.createSignedUrl(key, expiresIn);\r\n }\r\n\r\n private async createSignedUrl(key: string, expiresIn: number = 3600): Promise<string> {\r\n const { GetObjectCommand: GetCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const command = new GetCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n });\r\n\r\n return this.signedUrlFn(this.client, command, { expiresIn });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const { DeleteObjectCommand: DeleteCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new DeleteCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n }\r\n\r\n async deleteMany(keys: string[]): Promise<void> {\r\n if (keys.length === 0) {\r\n return;\r\n }\r\n\r\n const { DeleteObjectsCommand: DeleteManyCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new DeleteManyCmd({\r\n Bucket: this.bucket,\r\n Delete: {\r\n Objects: keys.map((key) => ({ Key: key })),\r\n },\r\n })\r\n );\r\n }\r\n\r\n async list(prefix?: string): Promise<StorageFile[]> {\r\n const { ListObjectsV2Command: ListCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const files: StorageFile[] = [];\r\n let continuationToken: string | undefined;\r\n\r\n do {\r\n const response = await this.client.send(\r\n new ListCmd({\r\n Bucket: this.bucket,\r\n Prefix: prefix,\r\n ContinuationToken: continuationToken,\r\n })\r\n );\r\n\r\n if (response.Contents) {\r\n for (const item of response.Contents) {\r\n files.push({\r\n key: item.Key!,\r\n size: item.Size!,\r\n lastModified: item.LastModified,\r\n etag: item.ETag,\r\n });\r\n }\r\n }\r\n\r\n continuationToken = response.NextContinuationToken;\r\n } while (continuationToken);\r\n\r\n return files;\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n try {\r\n const { HeadObjectCommand: HeadCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new HeadCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async getMetadata(key: string): Promise<StorageFile | null> {\r\n try {\r\n const { HeadObjectCommand: HeadCmd } = await import('@aws-sdk/client-s3');\r\n\r\n const response = await this.client.send(\r\n new HeadCmd({\r\n Bucket: this.bucket,\r\n Key: key,\r\n })\r\n );\r\n\r\n return {\r\n key,\r\n size: response.ContentLength!,\r\n contentType: response.ContentType,\r\n lastModified: response.LastModified,\r\n etag: response.ETag,\r\n };\r\n } catch {\r\n return null;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n const { ListObjectsV2Command: ListCmd } = await import('@aws-sdk/client-s3');\r\n\r\n await this.client.send(\r\n new ListCmd({\r\n Bucket: this.bucket,\r\n MaxKeys: 1,\r\n })\r\n );\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n}\r\n","/**\r\n * SMTP Email Adapter\r\n *\r\n * Production implementation using nodemailer for direct SMTP connections.\r\n * Provides vendor-agnostic email sending via standard SMTP protocol.\r\n *\r\n * Compatible with any SMTP server:\r\n * - Self-hosted mail servers (Postfix, Sendmail)\r\n * - Gmail SMTP\r\n * - Amazon SES (SMTP interface)\r\n * - SendGrid SMTP\r\n * - Mailgun SMTP\r\n * - Microsoft 365 SMTP\r\n * - Any standard SMTP relay\r\n */\r\n\r\nimport type { Transporter } from 'nodemailer';\r\nimport type SMTPTransport from 'nodemailer/lib/smtp-transport';\r\nimport { IEmail, EmailMessage, EmailResult, EmailAddress } from '../../interfaces/IEmail';\r\n\r\nexport interface SmtpConfig {\r\n /** SMTP host */\r\n host: string;\r\n\r\n /** SMTP port (typically 25, 465, or 587) */\r\n port: number;\r\n\r\n /** Use TLS/SSL */\r\n secure?: boolean;\r\n\r\n /** SMTP username */\r\n username?: string;\r\n\r\n /** SMTP password */\r\n password?: string;\r\n\r\n /** Default from address */\r\n from?: string;\r\n\r\n /** Connection timeout in milliseconds */\r\n connectionTimeout?: number;\r\n\r\n /** Socket timeout in milliseconds */\r\n socketTimeout?: number;\r\n\r\n /** Enable debug logging */\r\n debug?: boolean;\r\n\r\n /** Reject unauthorized certificates */\r\n rejectUnauthorized?: boolean;\r\n}\r\n\r\n/**\r\n * Convert EmailAddress to string format for nodemailer\r\n */\r\nfunction formatAddress(address: EmailAddress | string | undefined): string | undefined {\r\n if (!address) return undefined;\r\n if (typeof address === 'string') return address;\r\n return address.name ? `${address.name} <${address.email}>` : address.email;\r\n}\r\n\r\n/**\r\n * Convert EmailAddress or EmailAddress[] to nodemailer format\r\n */\r\nfunction formatRecipients(addresses: EmailAddress | EmailAddress[]): string | string[] {\r\n if (Array.isArray(addresses)) {\r\n return addresses.map((addr) => formatAddress(addr)!);\r\n }\r\n return formatAddress(addresses)!;\r\n}\r\n\r\nexport class SmtpEmail implements IEmail {\r\n private transporter: Transporter<SMTPTransport.SentMessageInfo> | null = null;\r\n private config: SmtpConfig;\r\n\r\n constructor(config: SmtpConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Create an SmtpEmail adapter from configuration\r\n */\r\n static async create(config: SmtpConfig): Promise<SmtpEmail> {\r\n const adapter = new SmtpEmail(config);\r\n await adapter.initialize();\r\n return adapter;\r\n }\r\n\r\n /**\r\n * Create from environment variables\r\n */\r\n static async fromEnv(): Promise<SmtpEmail> {\r\n const config: SmtpConfig = {\r\n host: process.env.SMTP_HOST ?? 'localhost',\r\n port: parseInt(process.env.SMTP_PORT ?? '587', 10),\r\n secure: process.env.SMTP_SECURE === 'true',\r\n username: process.env.SMTP_USERNAME ?? process.env.SMTP_USER,\r\n password: process.env.SMTP_PASSWORD ?? process.env.SMTP_PASS,\r\n from: process.env.EMAIL_FROM ?? process.env.SMTP_FROM,\r\n debug: process.env.SMTP_DEBUG === 'true',\r\n };\r\n\r\n return SmtpEmail.create(config);\r\n }\r\n\r\n /**\r\n * Initialize the SMTP transporter\r\n */\r\n private async initialize(): Promise<void> {\r\n const nodemailer = await import('nodemailer');\r\n\r\n const options: SMTPTransport.Options = {\r\n host: this.config.host,\r\n port: this.config.port,\r\n secure: this.config.secure ?? this.config.port === 465,\r\n connectionTimeout: this.config.connectionTimeout ?? 10000,\r\n socketTimeout: this.config.socketTimeout ?? 30000,\r\n debug: this.config.debug,\r\n logger: this.config.debug,\r\n };\r\n\r\n // Authentication\r\n if (this.config.username && this.config.password) {\r\n options.auth = {\r\n user: this.config.username,\r\n pass: this.config.password,\r\n };\r\n }\r\n\r\n // TLS options\r\n if (this.config.rejectUnauthorized !== undefined) {\r\n options.tls = {\r\n rejectUnauthorized: this.config.rejectUnauthorized,\r\n };\r\n }\r\n\r\n this.transporter = nodemailer.createTransport(options);\r\n }\r\n\r\n async send(message: EmailMessage): Promise<EmailResult> {\r\n if (!this.transporter) {\r\n await this.initialize();\r\n }\r\n\r\n try {\r\n const mailOptions = {\r\n from: formatAddress(message.from) ?? this.config.from,\r\n to: formatRecipients(message.to),\r\n subject: message.subject,\r\n text: message.text,\r\n html: message.html,\r\n replyTo: formatAddress(message.replyTo),\r\n attachments: message.attachments?.map((att) => ({\r\n filename: att.filename,\r\n content: att.content,\r\n contentType: att.contentType,\r\n })),\r\n headers: message.headers,\r\n };\r\n\r\n const result = await this.transporter!.sendMail(mailOptions);\r\n\r\n return {\r\n id: result.messageId ?? `smtp_${Date.now()}`,\r\n success: true,\r\n };\r\n } catch (error) {\r\n return {\r\n id: `smtp_error_${Date.now()}`,\r\n success: false,\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n };\r\n }\r\n }\r\n\r\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\r\n // Send sequentially to avoid overwhelming SMTP server\r\n const results: EmailResult[] = [];\r\n for (const msg of messages) {\r\n const result = await this.send(msg);\r\n results.push(result);\r\n }\r\n return results;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n if (!this.transporter) {\r\n try {\r\n await this.initialize();\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n try {\r\n await this.transporter!.verify();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Close the transporter and release connections\r\n */\r\n async close(): Promise<void> {\r\n if (this.transporter) {\r\n this.transporter.close();\r\n this.transporter = null;\r\n }\r\n }\r\n\r\n /**\r\n * Get transporter info for debugging\r\n */\r\n getTransporterInfo(): { host: string; port: number; secure: boolean } {\r\n return {\r\n host: this.config.host,\r\n port: this.config.port,\r\n secure: this.config.secure ?? false,\r\n };\r\n }\r\n}\r\n","/**\r\n * Resend Email Adapter\r\n * Production implementation using Resend for transactional emails\r\n */\r\n\r\nimport type { Resend } from 'resend';\r\nimport { IEmail, EmailMessage, EmailResult, EmailAddress } from '../../interfaces/IEmail';\r\n\r\nexport interface ResendEmailConfig {\r\n apiKey: string;\r\n defaultFrom?: string;\r\n}\r\n\r\nexport class ResendEmail implements IEmail {\r\n private client: Resend;\r\n private defaultFrom: string;\r\n\r\n constructor(client: Resend, defaultFrom?: string) {\r\n this.client = client;\r\n this.defaultFrom = defaultFrom || 'noreply@example.com';\r\n }\r\n\r\n async send(message: EmailMessage): Promise<EmailResult> {\r\n try {\r\n const to = this.formatAddresses(message.to);\r\n const from = message.from\r\n ? this.formatAddress(message.from)\r\n : this.defaultFrom;\r\n\r\n // Build email options - use type assertion for complex Resend types\r\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\r\n const emailOptions: any = {\r\n from,\r\n to,\r\n subject: message.subject,\r\n };\r\n\r\n if (message.html) emailOptions.html = message.html;\r\n if (message.text) emailOptions.text = message.text;\r\n if (message.replyTo) emailOptions.replyTo = this.formatAddress(message.replyTo);\r\n if (message.headers) emailOptions.headers = message.headers;\r\n if (message.tags) emailOptions.tags = message.tags.map((tag) => ({ name: tag, value: tag }));\r\n if (message.attachments) {\r\n emailOptions.attachments = message.attachments.map((a) => ({\r\n filename: a.filename,\r\n content: typeof a.content === 'string' ? a.content : a.content.toString('base64'),\r\n contentType: a.contentType,\r\n }));\r\n }\r\n\r\n const { data, error } = await this.client.emails.send(emailOptions);\r\n\r\n if (error) {\r\n return {\r\n id: '',\r\n success: false,\r\n error: new Error(error.message),\r\n };\r\n }\r\n\r\n return {\r\n id: data?.id || '',\r\n success: true,\r\n };\r\n } catch (err) {\r\n return {\r\n id: '',\r\n success: false,\r\n error: err instanceof Error ? err : new Error('Unknown error'),\r\n };\r\n }\r\n }\r\n\r\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\r\n // Resend has batch send but we'll use sequential for reliability\r\n const results: EmailResult[] = [];\r\n\r\n for (const message of messages) {\r\n const result = await this.send(message);\r\n results.push(result);\r\n\r\n // Basic rate limiting - 100ms between emails\r\n await new Promise((resolve) => setTimeout(resolve, 100));\r\n }\r\n\r\n return results;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n // Check connectivity by listing domains\r\n const { error } = await this.client.domains.list();\r\n return !error;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n private formatAddress(address: EmailAddress): string {\r\n if (address.name) {\r\n return `${address.name} <${address.email}>`;\r\n }\r\n return address.email;\r\n }\r\n\r\n private formatAddresses(addresses: EmailAddress | EmailAddress[]): string[] {\r\n const list = Array.isArray(addresses) ? addresses : [addresses];\r\n return list.map((addr) => this.formatAddress(addr));\r\n }\r\n}\r\n","/**\r\n * BullMQ Queue Adapter\r\n *\r\n * Production queue implementation using BullMQ (Redis-backed).\r\n * Self-hosted, no cloud lock-in - only requires Redis.\r\n *\r\n * Features:\r\n * - Retry with exponential backoff\r\n * - Cron/recurring jobs\r\n * - Job events\r\n * - Dead letter queue (failed jobs)\r\n * - Concurrency control\r\n * - Progress tracking\r\n */\r\n\r\nimport type {\r\n IQueue,\r\n Job,\r\n JobOptions,\r\n JobState,\r\n QueueStats,\r\n RepeatOptions,\r\n JobEventType,\r\n JobEventHandler,\r\n JobEvent,\r\n} from '../../interfaces/IQueue';\r\n\r\nexport interface BullMQConfig {\r\n /** Redis connection URL */\r\n redisUrl?: string;\r\n /** Redis host */\r\n host?: string;\r\n /** Redis port */\r\n port?: number;\r\n /** Redis password */\r\n password?: string;\r\n /** Redis database number */\r\n db?: number;\r\n /** Queue name */\r\n queueName: string;\r\n /** Default job options */\r\n defaultJobOptions?: JobOptions;\r\n /** Default worker concurrency */\r\n concurrency?: number;\r\n}\r\n\r\n// Internal types to avoid BullMQ's complex generic constraints\r\ninterface BullMQJobInternal {\r\n id?: string;\r\n name: string;\r\n data: unknown;\r\n attemptsMade: number;\r\n progress: number | object;\r\n timestamp: number;\r\n processedOn?: number;\r\n finishedOn?: number;\r\n failedReason?: string;\r\n opts?: {\r\n repeat?: { key?: string };\r\n };\r\n remove(): Promise<void>;\r\n retry(state?: string): Promise<void>;\r\n updateProgress(progress: number): Promise<void>;\r\n getState(): Promise<string>;\r\n}\r\n\r\ninterface BullMQQueueInternal {\r\n name: string;\r\n add(name: string, data: unknown, opts?: object): Promise<BullMQJobInternal>;\r\n addBulk(jobs: Array<{ name: string; data: unknown; opts?: object }>): Promise<BullMQJobInternal[]>;\r\n getJob(id: string): Promise<BullMQJobInternal | undefined>;\r\n getJobs(types: string[], start?: number, end?: number): Promise<BullMQJobInternal[]>;\r\n getWaitingCount(): Promise<number>;\r\n getActiveCount(): Promise<number>;\r\n getCompletedCount(): Promise<number>;\r\n getFailedCount(): Promise<number>;\r\n getDelayedCount(): Promise<number>;\r\n pause(): Promise<void>;\r\n resume(): Promise<void>;\r\n close(): Promise<void>;\r\n clean(grace: number, limit: number, type: string): Promise<string[]>;\r\n obliterate(opts?: { force?: boolean }): Promise<void>;\r\n}\r\n\r\ninterface BullMQWorkerInternal {\r\n on(event: string, handler: (...args: unknown[]) => void): void;\r\n off(event: string, handler: (...args: unknown[]) => void): void;\r\n close(): Promise<void>;\r\n}\r\n\r\n// Map our JobState to BullMQ state strings\r\nconst stateMap: Record<JobState, string> = {\r\n waiting: 'waiting',\r\n active: 'active',\r\n completed: 'completed',\r\n failed: 'failed',\r\n delayed: 'delayed',\r\n};\r\n\r\nconst reverseStateMap: Record<string, JobState> = {\r\n waiting: 'waiting',\r\n wait: 'waiting',\r\n active: 'active',\r\n completed: 'completed',\r\n failed: 'failed',\r\n delayed: 'delayed',\r\n};\r\n\r\n/**\r\n * BullMQ Queue Adapter\r\n * Requires: pnpm add bullmq ioredis\r\n */\r\nexport class BullMQQueue<T = unknown> implements IQueue<T> {\r\n private queue: BullMQQueueInternal | null = null;\r\n private worker: BullMQWorkerInternal | null = null;\r\n private config: BullMQConfig;\r\n private initialized = false;\r\n private eventHandlers: Map<JobEventType, Set<JobEventHandler<T>>> = new Map();\r\n\r\n constructor(config: BullMQConfig) {\r\n this.config = config;\r\n }\r\n\r\n /**\r\n * Initialize the queue (called lazily on first use)\r\n */\r\n private async ensureInitialized(): Promise<void> {\r\n if (this.initialized) return;\r\n\r\n const { Queue } = await import('bullmq');\r\n\r\n const connection = this.getConnectionConfig();\r\n\r\n this.queue = new Queue(this.config.queueName, {\r\n connection,\r\n defaultJobOptions: this.config.defaultJobOptions ? {\r\n attempts: this.config.defaultJobOptions.attempts,\r\n backoff: this.config.defaultJobOptions.backoff,\r\n delay: this.config.defaultJobOptions.delay,\r\n priority: this.config.defaultJobOptions.priority,\r\n removeOnComplete: this.config.defaultJobOptions.removeOnComplete,\r\n removeOnFail: this.config.defaultJobOptions.removeOnFail,\r\n } : undefined,\r\n }) as unknown as BullMQQueueInternal;\r\n\r\n this.initialized = true;\r\n }\r\n\r\n private getConnectionConfig() {\r\n if (this.config.redisUrl) {\r\n return { url: this.config.redisUrl };\r\n }\r\n return {\r\n host: this.config.host || 'localhost',\r\n port: this.config.port || 6379,\r\n password: this.config.password,\r\n db: this.config.db,\r\n };\r\n }\r\n\r\n async add(name: string, data: T, options?: JobOptions): Promise<Job<T>> {\r\n await this.ensureInitialized();\r\n\r\n // Store metadata in job data wrapper if present\r\n const jobData = options?.metadata || options?.correlationId\r\n ? { __data: data, __metadata: options.metadata, __correlationId: options.correlationId }\r\n : data;\r\n\r\n const bullmqJob = await this.queue!.add(name, jobData, {\r\n jobId: options?.jobId,\r\n attempts: options?.attempts,\r\n backoff: options?.backoff,\r\n delay: options?.delay,\r\n priority: options?.priority,\r\n removeOnComplete: options?.removeOnComplete,\r\n removeOnFail: options?.removeOnFail,\r\n repeat: options?.repeat\r\n ? {\r\n every: options.repeat.every,\r\n pattern: options.repeat.cron,\r\n tz: options.repeat.tz,\r\n limit: options.repeat.limit,\r\n }\r\n : undefined,\r\n });\r\n\r\n return this.mapJob(bullmqJob);\r\n }\r\n\r\n async addBulk(jobs: Array<{ name: string; data: T; options?: JobOptions }>): Promise<Job<T>[]> {\r\n await this.ensureInitialized();\r\n\r\n const bullmqJobs = await this.queue!.addBulk(\r\n jobs.map(job => ({\r\n name: job.name,\r\n data: job.data,\r\n opts: job.options ? {\r\n attempts: job.options.attempts,\r\n backoff: job.options.backoff,\r\n delay: job.options.delay,\r\n priority: job.options.priority,\r\n removeOnComplete: job.options.removeOnComplete,\r\n removeOnFail: job.options.removeOnFail,\r\n } : undefined,\r\n }))\r\n );\r\n\r\n return bullmqJobs.map(job => this.mapJob(job));\r\n }\r\n\r\n process(\r\n handler: (job: Job<T>) => Promise<unknown>,\r\n options?: { concurrency?: number }\r\n ): void {\r\n // Start worker asynchronously\r\n this.startWorker(handler, options?.concurrency).catch((err) => {\r\n console.error('Failed to start BullMQ worker:', err);\r\n });\r\n }\r\n\r\n private async startWorker(\r\n handler: (job: Job<T>) => Promise<unknown>,\r\n concurrency?: number\r\n ): Promise<void> {\r\n const { Worker } = await import('bullmq');\r\n\r\n const connection = this.getConnectionConfig();\r\n\r\n const worker = new Worker(\r\n this.config.queueName,\r\n async (bullmqJob) => {\r\n const job = this.mapJob(bullmqJob as unknown as BullMQJobInternal);\r\n return handler(job);\r\n },\r\n {\r\n connection,\r\n concurrency: concurrency ?? this.config.concurrency ?? 1,\r\n }\r\n );\r\n\r\n this.worker = worker as unknown as BullMQWorkerInternal;\r\n\r\n // Emit events to our handlers\r\n worker.on('completed', (bullmqJob) => {\r\n if (bullmqJob) {\r\n this.emitEvent('completed', bullmqJob as unknown as BullMQJobInternal);\r\n }\r\n });\r\n\r\n worker.on('failed', (bullmqJob, err) => {\r\n if (bullmqJob) {\r\n this.emitEvent('failed', bullmqJob as unknown as BullMQJobInternal, err as Error);\r\n }\r\n });\r\n\r\n worker.on('progress', (bullmqJob, progress) => {\r\n if (bullmqJob) {\r\n this.emitEvent('progress', bullmqJob as unknown as BullMQJobInternal, undefined, progress as number);\r\n }\r\n });\r\n\r\n worker.on('active', (bullmqJob) => {\r\n if (bullmqJob) {\r\n this.emitEvent('active', bullmqJob as unknown as BullMQJobInternal);\r\n }\r\n });\r\n\r\n worker.on('stalled', (jobId) => {\r\n // Stalled events don't have the full job, emit with minimal info\r\n this.emitEventById('stalled', jobId);\r\n });\r\n }\r\n\r\n private emitEvent(\r\n type: JobEventType,\r\n bullmqJob: BullMQJobInternal,\r\n error?: Error,\r\n progress?: number\r\n ): void {\r\n const handlers = this.eventHandlers.get(type);\r\n if (!handlers || handlers.size === 0) return;\r\n\r\n const event: JobEvent<T> = {\r\n type,\r\n job: this.mapJob(bullmqJob),\r\n timestamp: Date.now(),\r\n error,\r\n progress,\r\n };\r\n\r\n for (const handler of handlers) {\r\n try {\r\n handler(event);\r\n } catch {\r\n // Ignore handler errors\r\n }\r\n }\r\n }\r\n\r\n private emitEventById(type: JobEventType, jobId: string): void {\r\n const handlers = this.eventHandlers.get(type);\r\n if (!handlers || handlers.size === 0) return;\r\n\r\n // Create minimal event for stalled jobs\r\n const event: JobEvent<T> = {\r\n type,\r\n job: {\r\n id: jobId,\r\n name: '',\r\n data: {} as T,\r\n attemptsMade: 0,\r\n progress: 0,\r\n timestamp: Date.now(),\r\n },\r\n timestamp: Date.now(),\r\n };\r\n\r\n for (const handler of handlers) {\r\n try {\r\n handler(event);\r\n } catch {\r\n // Ignore handler errors\r\n }\r\n }\r\n }\r\n\r\n async getJob(id: string): Promise<Job<T> | null> {\r\n await this.ensureInitialized();\r\n\r\n const bullmqJob = await this.queue!.getJob(id);\r\n if (!bullmqJob) return null;\r\n\r\n return this.mapJob(bullmqJob);\r\n }\r\n\r\n async removeJob(id: string): Promise<void> {\r\n await this.ensureInitialized();\r\n\r\n const job = await this.queue!.getJob(id);\r\n if (job) {\r\n await job.remove();\r\n }\r\n }\r\n\r\n async pause(): Promise<void> {\r\n await this.ensureInitialized();\r\n await this.queue!.pause();\r\n }\r\n\r\n async resume(): Promise<void> {\r\n await this.ensureInitialized();\r\n await this.queue!.resume();\r\n }\r\n\r\n async getStats(): Promise<{\r\n waiting: number;\r\n active: number;\r\n completed: number;\r\n failed: number;\r\n delayed: number;\r\n }> {\r\n await this.ensureInitialized();\r\n\r\n const [waiting, active, completed, failed, delayed] = await Promise.all([\r\n this.queue!.getWaitingCount(),\r\n this.queue!.getActiveCount(),\r\n this.queue!.getCompletedCount(),\r\n this.queue!.getFailedCount(),\r\n this.queue!.getDelayedCount(),\r\n ]);\r\n\r\n return { waiting, active, completed, failed, delayed };\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n await this.ensureInitialized();\r\n // Try to get queue stats as a health check\r\n await this.queue!.getWaitingCount();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n if (this.worker) {\r\n await this.worker.close();\r\n this.worker = null;\r\n }\r\n if (this.queue) {\r\n await this.queue.close();\r\n this.queue = null;\r\n }\r\n this.initialized = false;\r\n this.eventHandlers.clear();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // OPTIONAL METHODS (new in enhanced interface)\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async addRecurring(\r\n name: string,\r\n data: T,\r\n repeat: RepeatOptions,\r\n options?: Omit<JobOptions, 'repeat'>\r\n ): Promise<Job<T>> {\r\n return this.add(name, data, {\r\n ...options,\r\n repeat,\r\n });\r\n }\r\n\r\n async getJobs(\r\n state: JobState | JobState[],\r\n start: number = 0,\r\n end: number = -1\r\n ): Promise<Job<T>[]> {\r\n await this.ensureInitialized();\r\n\r\n const states = Array.isArray(state) ? state : [state];\r\n const bullmqStates = states.map((s) => stateMap[s]);\r\n\r\n const bullmqJobs = await this.queue!.getJobs(bullmqStates, start, end === -1 ? undefined : end);\r\n return bullmqJobs.map((job) => this.mapJob(job));\r\n }\r\n\r\n async getFailedJobs(start: number = 0, end: number = -1): Promise<Job<T>[]> {\r\n return this.getJobs('failed', start, end);\r\n }\r\n\r\n async retryJob(id: string): Promise<void> {\r\n await this.ensureInitialized();\r\n\r\n const job = await this.queue!.getJob(id);\r\n if (job) {\r\n await job.retry('failed');\r\n }\r\n }\r\n\r\n async replayAllFailed(): Promise<number> {\r\n await this.ensureInitialized();\r\n\r\n const failedJobs = await this.queue!.getJobs(['failed']);\r\n let count = 0;\r\n\r\n for (const job of failedJobs) {\r\n try {\r\n await job.retry('failed');\r\n count++;\r\n } catch {\r\n // Job may have been removed or already retried\r\n }\r\n }\r\n\r\n return count;\r\n }\r\n\r\n async updateProgress(id: string, progress: number): Promise<void> {\r\n await this.ensureInitialized();\r\n\r\n const job = await this.queue!.getJob(id);\r\n if (job) {\r\n await job.updateProgress(Math.min(100, Math.max(0, progress)));\r\n }\r\n }\r\n\r\n async clean(grace: number, limit: number, state: JobState): Promise<string[]> {\r\n await this.ensureInitialized();\r\n return this.queue!.clean(grace, limit, stateMap[state]);\r\n }\r\n\r\n async obliterate(options?: { force?: boolean }): Promise<void> {\r\n await this.ensureInitialized();\r\n await this.queue!.obliterate(options);\r\n }\r\n\r\n on(event: JobEventType, handler: JobEventHandler<T>): void {\r\n if (!this.eventHandlers.has(event)) {\r\n this.eventHandlers.set(event, new Set());\r\n }\r\n this.eventHandlers.get(event)!.add(handler);\r\n }\r\n\r\n off(event: JobEventType, handler: JobEventHandler<T>): void {\r\n const handlers = this.eventHandlers.get(event);\r\n if (handlers) {\r\n handlers.delete(handler);\r\n }\r\n }\r\n\r\n getName(): string {\r\n return this.config.queueName;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private mapJob(bullmqJob: BullMQJobInternal): Job<T> {\r\n // Extract metadata if wrapped\r\n const rawData = bullmqJob.data;\r\n let data: T;\r\n let correlationId: string | undefined;\r\n let metadata: Record<string, unknown> | undefined;\r\n\r\n if (\r\n rawData &&\r\n typeof rawData === 'object' &&\r\n '__data' in (rawData as Record<string, unknown>)\r\n ) {\r\n const wrapped = rawData as {\r\n __data: T;\r\n __correlationId?: string;\r\n __metadata?: Record<string, unknown>;\r\n };\r\n data = wrapped.__data;\r\n correlationId = wrapped.__correlationId;\r\n metadata = wrapped.__metadata;\r\n } else {\r\n data = rawData as T;\r\n }\r\n\r\n return {\r\n id: bullmqJob.id || '',\r\n name: bullmqJob.name,\r\n data,\r\n attemptsMade: bullmqJob.attemptsMade,\r\n progress: typeof bullmqJob.progress === 'number' ? bullmqJob.progress : 0,\r\n timestamp: bullmqJob.timestamp,\r\n processedOn: bullmqJob.processedOn,\r\n finishedOn: bullmqJob.finishedOn,\r\n failedReason: bullmqJob.failedReason,\r\n correlationId,\r\n metadata,\r\n };\r\n }\r\n\r\n private async getJobState(bullmqJob: BullMQJobInternal): Promise<JobState> {\r\n const state = await bullmqJob.getState();\r\n return reverseStateMap[state] || 'waiting';\r\n }\r\n}\r\n","/**\r\n * OpenTelemetry Tracing Adapter\r\n *\r\n * Production-ready distributed tracing using OpenTelemetry SDK.\r\n * Exports traces to OTLP-compatible backends (Jaeger, Grafana Tempo, etc.)\r\n */\r\n\r\nimport type {\r\n ITracing,\r\n ISpan,\r\n SpanOptions,\r\n SpanContext,\r\n SpanStatus,\r\n SpanKind,\r\n} from '../../interfaces/ITracing';\r\n\r\n// OpenTelemetry types (dynamically imported)\r\ntype OtelSpan = import('@opentelemetry/api').Span;\r\ntype OtelTracer = import('@opentelemetry/api').Tracer;\r\ntype OtelApi = typeof import('@opentelemetry/api');\r\ntype NodeTracerProvider = import('@opentelemetry/sdk-trace-node').NodeTracerProvider;\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CONFIGURATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface OpenTelemetryConfig {\r\n /** Service name for traces */\r\n serviceName: string;\r\n\r\n /** Service version */\r\n serviceVersion?: string;\r\n\r\n /** Environment (dev, staging, production) */\r\n environment?: string;\r\n\r\n /** OTLP endpoint (e.g., http://localhost:4318/v1/traces) */\r\n endpoint?: string;\r\n\r\n /** Exporter type */\r\n exporterType?: 'otlp-http' | 'otlp-grpc' | 'console';\r\n\r\n /** Sampling rate (0.0 to 1.0) */\r\n sampleRate?: number;\r\n\r\n /** Additional resource attributes */\r\n resourceAttributes?: Record<string, string>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// SPAN WRAPPER\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nclass OpenTelemetrySpan implements ISpan {\r\n private _name: string;\r\n private otelSpan: OtelSpan;\r\n private spanContext: SpanContext;\r\n private api: OtelApi;\r\n\r\n constructor(name: string, otelSpan: OtelSpan, api: OtelApi) {\r\n this._name = name;\r\n this.otelSpan = otelSpan;\r\n this.api = api;\r\n\r\n const ctx = otelSpan.spanContext();\r\n this.spanContext = {\r\n traceId: ctx.traceId,\r\n spanId: ctx.spanId,\r\n traceFlags: ctx.traceFlags,\r\n traceState: ctx.traceState?.serialize(),\r\n };\r\n }\r\n\r\n get name(): string {\r\n return this._name;\r\n }\r\n\r\n get context(): SpanContext {\r\n return this.spanContext;\r\n }\r\n\r\n get isRecording(): boolean {\r\n return this.otelSpan.isRecording();\r\n }\r\n\r\n setAttribute(key: string, value: string | number | boolean): this {\r\n this.otelSpan.setAttribute(key, value);\r\n return this;\r\n }\r\n\r\n setAttributes(attributes: Record<string, string | number | boolean>): this {\r\n this.otelSpan.setAttributes(attributes);\r\n return this;\r\n }\r\n\r\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): this {\r\n this.otelSpan.addEvent(name, attributes);\r\n return this;\r\n }\r\n\r\n setStatus(status: SpanStatus): this {\r\n let code: import('@opentelemetry/api').SpanStatusCode;\r\n switch (status.code) {\r\n case 'ok':\r\n code = this.api.SpanStatusCode.OK;\r\n break;\r\n case 'error':\r\n code = this.api.SpanStatusCode.ERROR;\r\n break;\r\n default:\r\n code = this.api.SpanStatusCode.UNSET;\r\n }\r\n this.otelSpan.setStatus({ code, message: status.message });\r\n return this;\r\n }\r\n\r\n recordException(exception: Error, attributes?: Record<string, string | number | boolean>): this {\r\n // recordException takes (exception, time?), so we just record the exception\r\n // If attributes are provided, add them as an event instead\r\n this.otelSpan.recordException(exception);\r\n if (attributes) {\r\n this.otelSpan.addEvent('exception.attributes', attributes);\r\n }\r\n this.setStatus({ code: 'error', message: exception.message });\r\n return this;\r\n }\r\n\r\n updateName(name: string): this {\r\n this._name = name;\r\n this.otelSpan.updateName(name);\r\n return this;\r\n }\r\n\r\n end(endTime?: number): void {\r\n this.otelSpan.end(endTime);\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// OPENTELEMETRY TRACING ADAPTER\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport class OpenTelemetryTracing implements ITracing {\r\n private tracer: OtelTracer;\r\n private provider: NodeTracerProvider;\r\n private currentSpan: OpenTelemetrySpan | undefined;\r\n private api: OtelApi;\r\n\r\n private constructor(tracer: OtelTracer, provider: NodeTracerProvider, api: OtelApi) {\r\n this.tracer = tracer;\r\n this.provider = provider;\r\n this.api = api;\r\n }\r\n\r\n /**\r\n * Create an OpenTelemetry tracing instance\r\n */\r\n static async create(config: OpenTelemetryConfig): Promise<OpenTelemetryTracing> {\r\n // Dynamic imports for optional dependencies\r\n const api = await import('@opentelemetry/api');\r\n const { NodeTracerProvider } = await import('@opentelemetry/sdk-trace-node');\r\n const { Resource } = await import('@opentelemetry/resources');\r\n const semconv = await import('@opentelemetry/semantic-conventions');\r\n const { BatchSpanProcessor, ConsoleSpanExporter } = await import('@opentelemetry/sdk-trace-base');\r\n\r\n // Semantic conventions attribute names (compatible with different versions)\r\n const ATTR_SERVICE_NAME: string =\r\n semconv.ATTR_SERVICE_NAME ?? semconv.SEMRESATTRS_SERVICE_NAME ?? 'service.name';\r\n const ATTR_SERVICE_VERSION: string =\r\n semconv.ATTR_SERVICE_VERSION ?? semconv.SEMRESATTRS_SERVICE_VERSION ?? 'service.version';\r\n const ATTR_DEPLOYMENT_ENVIRONMENT: string =\r\n ((semconv as Record<string, unknown>).ATTR_DEPLOYMENT_ENVIRONMENT_NAME as string) ??\r\n semconv.SEMRESATTRS_DEPLOYMENT_ENVIRONMENT ??\r\n 'deployment.environment';\r\n\r\n // Build resource attributes\r\n const resourceAttributes: Record<string, string> = {\r\n [ATTR_SERVICE_NAME]: config.serviceName,\r\n ...config.resourceAttributes,\r\n };\r\n\r\n if (config.serviceVersion) {\r\n resourceAttributes[ATTR_SERVICE_VERSION] = config.serviceVersion;\r\n }\r\n\r\n if (config.environment) {\r\n resourceAttributes[ATTR_DEPLOYMENT_ENVIRONMENT] = config.environment;\r\n }\r\n\r\n // Create provider with resource\r\n const provider = new NodeTracerProvider({\r\n resource: new Resource(resourceAttributes),\r\n });\r\n\r\n // Create exporter based on configuration\r\n let exporter;\r\n switch (config.exporterType) {\r\n case 'otlp-grpc': {\r\n const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-grpc');\r\n exporter = new OTLPTraceExporter({\r\n url: config.endpoint,\r\n });\r\n break;\r\n }\r\n case 'console':\r\n exporter = new ConsoleSpanExporter();\r\n break;\r\n case 'otlp-http':\r\n default: {\r\n const { OTLPTraceExporter } = await import('@opentelemetry/exporter-trace-otlp-http');\r\n exporter = new OTLPTraceExporter({\r\n url: config.endpoint || 'http://localhost:4318/v1/traces',\r\n });\r\n break;\r\n }\r\n }\r\n\r\n // Add batch processor\r\n provider.addSpanProcessor(new BatchSpanProcessor(exporter));\r\n\r\n // Register provider\r\n provider.register();\r\n\r\n // Get tracer\r\n const tracer = api.trace.getTracer(config.serviceName, config.serviceVersion);\r\n\r\n return new OpenTelemetryTracing(tracer, provider, api);\r\n }\r\n\r\n private mapSpanKind(kind?: SpanKind): import('@opentelemetry/api').SpanKind {\r\n switch (kind) {\r\n case 'server':\r\n return this.api.SpanKind.SERVER;\r\n case 'client':\r\n return this.api.SpanKind.CLIENT;\r\n case 'producer':\r\n return this.api.SpanKind.PRODUCER;\r\n case 'consumer':\r\n return this.api.SpanKind.CONSUMER;\r\n case 'internal':\r\n default:\r\n return this.api.SpanKind.INTERNAL;\r\n }\r\n }\r\n\r\n startSpan(name: string, options?: SpanOptions): ISpan {\r\n const otelSpan = this.tracer.startSpan(name, {\r\n kind: this.mapSpanKind(options?.kind),\r\n attributes: options?.attributes,\r\n startTime: options?.startTime,\r\n });\r\n\r\n const span = new OpenTelemetrySpan(name, otelSpan, this.api);\r\n this.currentSpan = span;\r\n\r\n return span;\r\n }\r\n\r\n getCurrentSpan(): ISpan | undefined {\r\n const activeSpan = this.api.trace.getActiveSpan();\r\n if (activeSpan) {\r\n return new OpenTelemetrySpan('', activeSpan, this.api);\r\n }\r\n return this.currentSpan;\r\n }\r\n\r\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T {\r\n const span = this.startSpan(name, options);\r\n const otelSpan = this.tracer.startSpan(name, {\r\n kind: this.mapSpanKind(options?.kind),\r\n attributes: options?.attributes,\r\n });\r\n\r\n return this.api.context.with(this.api.trace.setSpan(this.api.context.active(), otelSpan), () => {\r\n try {\r\n const result = fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n otelSpan.end();\r\n }\r\n });\r\n }\r\n\r\n async withSpanAsync<T>(name: string, fn: (span: ISpan) => Promise<T>, options?: SpanOptions): Promise<T> {\r\n const span = this.startSpan(name, options);\r\n const otelSpan = this.tracer.startSpan(name, {\r\n kind: this.mapSpanKind(options?.kind),\r\n attributes: options?.attributes,\r\n });\r\n\r\n return this.api.context.with(this.api.trace.setSpan(this.api.context.active(), otelSpan), async () => {\r\n try {\r\n const result = await fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n otelSpan.end();\r\n }\r\n });\r\n }\r\n\r\n instrument<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => TReturn,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => TReturn {\r\n return (...args: TArgs) => this.withSpan(name, () => fn(...args), options);\r\n }\r\n\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => Promise<TReturn> {\r\n return (...args: TArgs) => this.withSpanAsync(name, () => fn(...args), options);\r\n }\r\n\r\n extractContext(headers: Record<string, string | string[] | undefined>): SpanContext | undefined {\r\n // Use W3C Trace Context propagation\r\n const traceparent = headers['traceparent'];\r\n if (!traceparent || typeof traceparent !== 'string') return undefined;\r\n\r\n // Parse W3C Trace Context format: version-traceId-spanId-flags\r\n const parts = traceparent.split('-');\r\n if (parts.length !== 4 || parts[0] !== '00') return undefined;\r\n\r\n const traceId = parts[1];\r\n const spanId = parts[2];\r\n const traceFlags = parseInt(parts[3]!, 16);\r\n\r\n if (!traceId || traceId.length !== 32 || !spanId || spanId.length !== 16) {\r\n return undefined;\r\n }\r\n\r\n return {\r\n traceId,\r\n spanId,\r\n traceFlags,\r\n traceState: headers['tracestate'] as string | undefined,\r\n };\r\n }\r\n\r\n injectContext(headers: Record<string, string>): void {\r\n const activeSpan = this.api.trace.getActiveSpan();\r\n if (activeSpan) {\r\n const ctx = activeSpan.spanContext();\r\n headers['traceparent'] = `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, '0')}`;\r\n if (ctx.traceState) {\r\n headers['tracestate'] = ctx.traceState.serialize();\r\n }\r\n } else if (this.currentSpan) {\r\n const ctx = this.currentSpan.context;\r\n headers['traceparent'] = `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, '0')}`;\r\n if (ctx.traceState) {\r\n headers['tracestate'] = ctx.traceState;\r\n }\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n // OpenTelemetry is considered healthy if the provider is registered\r\n return true;\r\n }\r\n\r\n async flush(): Promise<void> {\r\n await this.provider.forceFlush();\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.provider.shutdown();\r\n }\r\n}\r\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 = 'waiting' | 'active' | 'completed' | 'failed' | '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 = 'completed' | 'failed' | 'progress' | 'active' | '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> = (event: JobEvent<T>) => 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(jobs: Array<{ name: string; data: T; options?: JobOptions }>): 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?(state: JobState | JobState[], start?: number, end?: number): 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\n/**\n * Calculate exponential backoff delay\n */\nexport function calculateBackoff(attempt: number, options: BackoffOptions): 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 = Math.random().toString(36).substring(2, 10);\n return `job_${timestamp}_${random}`;\n}\n","/**\r\n * Health Check Interface\r\n * Standardizes health check behavior across all adapters\r\n */\r\n\r\n/**\r\n * Result of a single health check\r\n */\r\nexport interface HealthCheckResult {\r\n /** Overall health status */\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n /** Time taken to perform the check in milliseconds */\r\n latencyMs: number;\r\n /** When the check was performed */\r\n timestamp: Date;\r\n /** Optional message with details */\r\n message?: string;\r\n /** Additional details about the health check */\r\n details?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Aggregated health result for the entire platform\r\n */\r\nexport interface PlatformHealthResult {\r\n /** Overall platform status */\r\n status: 'healthy' | 'degraded' | 'unhealthy';\r\n /** When the check was performed */\r\n timestamp: Date;\r\n /** Individual service health results */\r\n services: {\r\n database: HealthCheckResult;\r\n cache: HealthCheckResult;\r\n storage: HealthCheckResult;\r\n email: HealthCheckResult;\r\n queue: HealthCheckResult;\r\n };\r\n /** Summary counts */\r\n summary: {\r\n total: number;\r\n healthy: number;\r\n degraded: number;\r\n unhealthy: number;\r\n };\r\n}\r\n\r\n/**\r\n * Interface for services that support health checks\r\n */\r\nexport interface IHealth {\r\n /**\r\n * Perform a health check on the service\r\n * @returns Promise resolving to health check result\r\n */\r\n healthCheck(): Promise<HealthCheckResult>;\r\n}\r\n\r\n/**\r\n * Interface for services that support simple boolean health checks\r\n * (Legacy support - prefer IHealth for new implementations)\r\n */\r\nexport interface IHealthCheckable {\r\n /**\r\n * Simple health check returning boolean\r\n * @returns Promise resolving to true if healthy\r\n */\r\n healthCheck(): Promise<boolean>;\r\n}\r\n\r\n/**\r\n * Helper to convert boolean health check to HealthCheckResult\r\n */\r\nexport function toHealthCheckResult(\r\n healthy: boolean,\r\n latencyMs: number,\r\n message?: string\r\n): HealthCheckResult {\r\n return {\r\n status: healthy ? 'healthy' : 'unhealthy',\r\n latencyMs,\r\n timestamp: new Date(),\r\n message,\r\n };\r\n}\r\n\r\n/**\r\n * Helper to perform a timed health check\r\n */\r\nexport async function timedHealthCheck<T>(\r\n fn: () => Promise<T>,\r\n successCheck: (result: T) => boolean = () => true\r\n): Promise<HealthCheckResult> {\r\n const start = Date.now();\r\n try {\r\n const result = await fn();\r\n const healthy = successCheck(result);\r\n return {\r\n status: healthy ? 'healthy' : 'degraded',\r\n latencyMs: Date.now() - start,\r\n timestamp: new Date(),\r\n };\r\n } catch (error) {\r\n return {\r\n status: 'unhealthy',\r\n latencyMs: Date.now() - start,\r\n timestamp: new Date(),\r\n message: error instanceof Error ? error.message : 'Unknown error',\r\n };\r\n }\r\n}\r\n","/**\r\n * Logger Interface\r\n * Standardizes logging across the platform\r\n */\r\n\r\n/**\r\n * Log levels in order of severity\r\n */\r\nexport type LogLevel = 'debug' | 'info' | 'warn' | 'error';\r\n\r\n/**\r\n * Metadata that can be attached to log entries\r\n */\r\nexport interface LogMeta {\r\n /** Error object if logging an error */\r\n error?: Error;\r\n /** Duration in milliseconds (for timing operations) */\r\n duration?: number;\r\n /** Request ID for tracing */\r\n requestId?: string;\r\n /** User ID if applicable */\r\n userId?: string;\r\n /** Any additional key-value pairs */\r\n [key: string]: unknown;\r\n}\r\n\r\n/**\r\n * A structured log entry\r\n */\r\nexport interface LogEntry {\r\n /** Log level */\r\n level: LogLevel;\r\n /** Log message */\r\n message: string;\r\n /** When the log was created */\r\n timestamp: Date;\r\n /** Optional metadata */\r\n meta?: LogMeta;\r\n /** Logger context (e.g., service name) */\r\n context?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Logger interface for structured logging\r\n */\r\nexport interface ILogger {\r\n /**\r\n * Log a debug message (for development/troubleshooting)\r\n */\r\n debug(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Log an informational message\r\n */\r\n info(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Log a warning message\r\n */\r\n warn(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Log an error message\r\n */\r\n error(message: string, meta?: LogMeta): void;\r\n\r\n /**\r\n * Create a child logger with additional context\r\n * @param context Additional context to include in all logs from this child\r\n */\r\n child(context: Record<string, unknown>): ILogger;\r\n}\r\n\r\n/**\r\n * Configuration options for loggers\r\n */\r\nexport interface LoggerConfig {\r\n /** Minimum level to log */\r\n level?: LogLevel;\r\n /** Whether to pretty print (for development) */\r\n pretty?: boolean;\r\n /** Service name to include in logs */\r\n service?: string;\r\n /** Environment name */\r\n environment?: string;\r\n}\r\n\r\n/**\r\n * Console logger implementation (for development)\r\n */\r\nexport class ConsoleLogger implements ILogger {\r\n private context: Record<string, unknown>;\r\n private level: LogLevel;\r\n\r\n private static levelPriority: Record<LogLevel, number> = {\r\n debug: 0,\r\n info: 1,\r\n warn: 2,\r\n error: 3,\r\n };\r\n\r\n constructor(config: LoggerConfig = {}) {\r\n this.context = {\r\n service: config.service,\r\n environment: config.environment,\r\n };\r\n this.level = config.level || 'info';\r\n }\r\n\r\n private shouldLog(level: LogLevel): boolean {\r\n return ConsoleLogger.levelPriority[level] >= ConsoleLogger.levelPriority[this.level];\r\n }\r\n\r\n private log(level: LogLevel, message: string, meta?: LogMeta): void {\r\n if (!this.shouldLog(level)) return;\r\n\r\n const entry: LogEntry = {\r\n level,\r\n message,\r\n timestamp: new Date(),\r\n meta,\r\n context: this.context,\r\n };\r\n\r\n const prefix = `[${entry.timestamp.toISOString()}] [${level.toUpperCase()}]`;\r\n const contextStr = Object.keys(this.context).length > 0\r\n ? ` [${Object.entries(this.context).map(([k, v]) => `${k}=${v}`).join(' ')}]`\r\n : '';\r\n\r\n switch (level) {\r\n case 'debug':\r\n console.debug(`${prefix}${contextStr} ${message}`, meta || '');\r\n break;\r\n case 'info':\r\n console.info(`${prefix}${contextStr} ${message}`, meta || '');\r\n break;\r\n case 'warn':\r\n console.warn(`${prefix}${contextStr} ${message}`, meta || '');\r\n break;\r\n case 'error':\r\n console.error(`${prefix}${contextStr} ${message}`, meta || '');\r\n if (meta?.error) {\r\n console.error(meta.error);\r\n }\r\n break;\r\n }\r\n }\r\n\r\n debug(message: string, meta?: LogMeta): void {\r\n this.log('debug', message, meta);\r\n }\r\n\r\n info(message: string, meta?: LogMeta): void {\r\n this.log('info', message, meta);\r\n }\r\n\r\n warn(message: string, meta?: LogMeta): void {\r\n this.log('warn', message, meta);\r\n }\r\n\r\n error(message: string, meta?: LogMeta): void {\r\n this.log('error', message, meta);\r\n }\r\n\r\n child(context: Record<string, unknown>): ILogger {\r\n const childLogger = new ConsoleLogger({ level: this.level });\r\n childLogger.context = { ...this.context, ...context };\r\n return childLogger;\r\n }\r\n}\r\n\r\n/**\r\n * No-op logger for testing or when logging is disabled\r\n */\r\nexport class NoopLogger implements ILogger {\r\n debug(): void {}\r\n info(): void {}\r\n warn(): void {}\r\n error(): void {}\r\n child(): ILogger {\r\n return this;\r\n }\r\n}\r\n","/**\r\n * Metrics Interface\r\n *\r\n * Provides observability through counters, gauges, histograms, and timers.\r\n */\r\n\r\n/**\r\n * Tags for metrics (key-value pairs for dimensions)\r\n */\r\nexport type MetricTags = Record<string, string | number | boolean>;\r\n\r\n/**\r\n * Metrics interface for observability\r\n */\r\nexport interface IMetrics {\r\n /**\r\n * Increment a counter by a value (default 1)\r\n *\r\n * @example\r\n * metrics.increment('api.requests', 1, { method: 'GET', path: '/users' })\r\n */\r\n increment(name: string, value?: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Decrement a counter by a value (default 1)\r\n *\r\n * @example\r\n * metrics.decrement('active.connections', 1, { server: 'api-1' })\r\n */\r\n decrement(name: string, value?: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Set a gauge to a specific value\r\n *\r\n * @example\r\n * metrics.gauge('queue.size', 42, { queue: 'emails' })\r\n */\r\n gauge(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Record a value in a histogram (for distributions)\r\n *\r\n * @example\r\n * metrics.histogram('response.size', 1024, { endpoint: '/api/users' })\r\n */\r\n histogram(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Record a timing value in milliseconds\r\n *\r\n * @example\r\n * metrics.timing('db.query.duration', 42, { table: 'users' })\r\n */\r\n timing(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Start a timer and return a function to stop it\r\n *\r\n * @example\r\n * const stop = metrics.startTimer('api.request.duration', { method: 'GET' })\r\n * // ... do work ...\r\n * stop() // Records the duration\r\n */\r\n startTimer(name: string, tags?: MetricTags): () => void;\r\n\r\n /**\r\n * Record a distribution value (similar to histogram but for Datadog)\r\n *\r\n * @example\r\n * metrics.distribution('payment.amount', 99.99, { currency: 'USD' })\r\n */\r\n distribution?(name: string, value: number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Record a set value (count unique elements)\r\n *\r\n * @example\r\n * metrics.set('unique.users', 'user-123')\r\n */\r\n set?(name: string, value: string | number, tags?: MetricTags): void;\r\n\r\n /**\r\n * Flush all pending metrics to the backend\r\n */\r\n flush(): Promise<void>;\r\n\r\n /**\r\n * Close the metrics client\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n/**\r\n * Memory-based metrics implementation for testing\r\n */\r\nexport class MemoryMetrics implements IMetrics {\r\n private counters: Map<string, { value: number; tags: MetricTags }[]> = new Map();\r\n private gauges: Map<string, { value: number; tags: MetricTags; timestamp: number }> = new Map();\r\n private histograms: Map<string, { values: number[]; tags: MetricTags }[]> = new Map();\r\n private timings: Map<string, { values: number[]; tags: MetricTags }[]> = new Map();\r\n private sets: Map<string, Set<string | number>> = new Map();\r\n\r\n increment(name: string, value = 1, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n const existing = this.counters.get(key);\r\n\r\n if (existing && existing[0]) {\r\n existing[0].value += value;\r\n } else {\r\n this.counters.set(key, [{ value, tags }]);\r\n }\r\n }\r\n\r\n decrement(name: string, value = 1, tags: MetricTags = {}): void {\r\n this.increment(name, -value, tags);\r\n }\r\n\r\n gauge(name: string, value: number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n this.gauges.set(key, { value, tags, timestamp: Date.now() });\r\n }\r\n\r\n histogram(name: string, value: number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n const existing = this.histograms.get(key);\r\n\r\n if (existing && existing[0]) {\r\n existing[0].values.push(value);\r\n } else {\r\n this.histograms.set(key, [{ values: [value], tags }]);\r\n }\r\n }\r\n\r\n timing(name: string, value: number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n const existing = this.timings.get(key);\r\n\r\n if (existing && existing[0]) {\r\n existing[0].values.push(value);\r\n } else {\r\n this.timings.set(key, [{ values: [value], tags }]);\r\n }\r\n }\r\n\r\n startTimer(name: string, tags: MetricTags = {}): () => void {\r\n const start = Date.now();\r\n return () => {\r\n const duration = Date.now() - start;\r\n this.timing(name, duration, tags);\r\n };\r\n }\r\n\r\n distribution(name: string, value: number, tags: MetricTags = {}): void {\r\n this.histogram(name, value, tags);\r\n }\r\n\r\n set(name: string, value: string | number, tags: MetricTags = {}): void {\r\n const key = this.createKey(name, tags);\r\n let existing = this.sets.get(key);\r\n\r\n if (!existing) {\r\n existing = new Set();\r\n this.sets.set(key, existing);\r\n }\r\n\r\n existing.add(value);\r\n }\r\n\r\n async flush(): Promise<void> {\r\n // No-op for memory implementation\r\n }\r\n\r\n async close(): Promise<void> {\r\n // No-op for memory implementation\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // Test helpers\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Get counter value\r\n */\r\n getCounter(name: string, tags: MetricTags = {}): number {\r\n const key = this.createKey(name, tags);\r\n const data = this.counters.get(key);\r\n return data?.[0]?.value ?? 0;\r\n }\r\n\r\n /**\r\n * Get gauge value\r\n */\r\n getGauge(name: string, tags: MetricTags = {}): number | undefined {\r\n const key = this.createKey(name, tags);\r\n return this.gauges.get(key)?.value;\r\n }\r\n\r\n /**\r\n * Get histogram values\r\n */\r\n getHistogram(name: string, tags: MetricTags = {}): number[] {\r\n const key = this.createKey(name, tags);\r\n return this.histograms.get(key)?.[0]?.values ?? [];\r\n }\r\n\r\n /**\r\n * Get timing values\r\n */\r\n getTiming(name: string, tags: MetricTags = {}): number[] {\r\n const key = this.createKey(name, tags);\r\n return this.timings.get(key)?.[0]?.values ?? [];\r\n }\r\n\r\n /**\r\n * Get set size\r\n */\r\n getSetSize(name: string, tags: MetricTags = {}): number {\r\n const key = this.createKey(name, tags);\r\n return this.sets.get(key)?.size ?? 0;\r\n }\r\n\r\n /**\r\n * Get all metrics as a summary\r\n */\r\n getSummary(): MetricsSummary {\r\n const summary: MetricsSummary = {\r\n counters: {},\r\n gauges: {},\r\n histograms: {},\r\n timings: {},\r\n sets: {},\r\n };\r\n\r\n for (const [key, data] of this.counters) {\r\n const first = data[0];\r\n if (first) {\r\n summary.counters[key] = first.value;\r\n }\r\n }\r\n\r\n for (const [key, data] of this.gauges) {\r\n summary.gauges[key] = data.value;\r\n }\r\n\r\n for (const [key, data] of this.histograms) {\r\n const first = data[0];\r\n if (first) {\r\n const values = first.values;\r\n summary.histograms[key] = {\r\n count: values.length,\r\n sum: values.reduce((a, b) => a + b, 0),\r\n min: Math.min(...values),\r\n max: Math.max(...values),\r\n avg: values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0,\r\n };\r\n }\r\n }\r\n\r\n for (const [key, data] of this.timings) {\r\n const first = data[0];\r\n if (first) {\r\n const values = first.values;\r\n summary.timings[key] = {\r\n count: values.length,\r\n sum: values.reduce((a, b) => a + b, 0),\r\n min: Math.min(...values),\r\n max: Math.max(...values),\r\n avg: values.length > 0 ? values.reduce((a, b) => a + b, 0) / values.length : 0,\r\n p50: this.percentile(values, 50),\r\n p95: this.percentile(values, 95),\r\n p99: this.percentile(values, 99),\r\n };\r\n }\r\n }\r\n\r\n for (const [key, data] of this.sets) {\r\n summary.sets[key] = data.size;\r\n }\r\n\r\n return summary;\r\n }\r\n\r\n /**\r\n * Reset all metrics\r\n */\r\n reset(): void {\r\n this.counters.clear();\r\n this.gauges.clear();\r\n this.histograms.clear();\r\n this.timings.clear();\r\n this.sets.clear();\r\n }\r\n\r\n private createKey(name: string, tags: MetricTags): string {\r\n const tagStr = Object.entries(tags)\r\n .sort(([a], [b]) => a.localeCompare(b))\r\n .map(([k, v]) => `${k}:${v}`)\r\n .join(',');\r\n return tagStr ? `${name}|${tagStr}` : name;\r\n }\r\n\r\n private percentile(values: number[], p: number): number {\r\n if (values.length === 0) return 0;\r\n\r\n const sorted = [...values].sort((a, b) => a - b);\r\n const index = Math.ceil((p / 100) * sorted.length) - 1;\r\n const safeIndex = Math.max(0, index);\r\n return sorted[safeIndex] ?? 0;\r\n }\r\n}\r\n\r\n/**\r\n * No-op metrics implementation\r\n */\r\nexport class NoopMetrics implements IMetrics {\r\n increment(): void {}\r\n decrement(): void {}\r\n gauge(): void {}\r\n histogram(): void {}\r\n timing(): void {}\r\n startTimer(): () => void {\r\n return () => {};\r\n }\r\n distribution(): void {}\r\n set(): void {}\r\n async flush(): Promise<void> {}\r\n async close(): Promise<void> {}\r\n}\r\n\r\n/**\r\n * Summary of all metrics\r\n */\r\nexport interface MetricsSummary {\r\n counters: Record<string, number>;\r\n gauges: Record<string, number>;\r\n histograms: Record<string, HistogramStats>;\r\n timings: Record<string, TimingStats>;\r\n sets: Record<string, number>;\r\n}\r\n\r\n/**\r\n * Histogram statistics\r\n */\r\nexport interface HistogramStats {\r\n count: number;\r\n sum: number;\r\n min: number;\r\n max: number;\r\n avg: number;\r\n}\r\n\r\n/**\r\n * Timing statistics\r\n */\r\nexport interface TimingStats extends HistogramStats {\r\n p50: number;\r\n p95: number;\r\n p99: number;\r\n}\r\n\r\n/**\r\n * Create a scoped metrics instance with a prefix\r\n */\r\nexport function createScopedMetrics(\r\n metrics: IMetrics,\r\n prefix: string,\r\n defaultTags: MetricTags = {}\r\n): IMetrics {\r\n const prefixedName = (name: string) => `${prefix}.${name}`;\r\n const mergedTags = (tags?: MetricTags) => ({ ...defaultTags, ...tags });\r\n\r\n return {\r\n increment(name, value, tags) {\r\n metrics.increment(prefixedName(name), value, mergedTags(tags));\r\n },\r\n decrement(name, value, tags) {\r\n metrics.decrement(prefixedName(name), value, mergedTags(tags));\r\n },\r\n gauge(name, value, tags) {\r\n metrics.gauge(prefixedName(name), value, mergedTags(tags));\r\n },\r\n histogram(name, value, tags) {\r\n metrics.histogram(prefixedName(name), value, mergedTags(tags));\r\n },\r\n timing(name, value, tags) {\r\n metrics.timing(prefixedName(name), value, mergedTags(tags));\r\n },\r\n startTimer(name, tags) {\r\n return metrics.startTimer(prefixedName(name), mergedTags(tags));\r\n },\r\n distribution(name, value, tags) {\r\n metrics.distribution?.(prefixedName(name), value, mergedTags(tags));\r\n },\r\n set(name, value, tags) {\r\n metrics.set?.(prefixedName(name), value, mergedTags(tags));\r\n },\r\n flush: () => metrics.flush(),\r\n close: () => metrics.close(),\r\n };\r\n}\r\n","/**\r\n * Secrets Management Interface\r\n *\r\n * Provides a vendor-agnostic abstraction for secrets management.\r\n * Supports various backends: Environment variables, HashiCorp Vault,\r\n * AWS Secrets Manager, Azure Key Vault, GCP Secret Manager, etc.\r\n */\r\n\r\n/**\r\n * Secret metadata\r\n */\r\nexport interface SecretMetadata {\r\n /** Secret version or ETag */\r\n version?: string;\r\n\r\n /** Creation timestamp */\r\n createdAt?: Date;\r\n\r\n /** Last updated timestamp */\r\n updatedAt?: Date;\r\n\r\n /** Expiration timestamp */\r\n expiresAt?: Date;\r\n\r\n /** Custom tags/labels */\r\n tags?: Record<string, string>;\r\n}\r\n\r\n/**\r\n * Secret with metadata\r\n */\r\nexport interface Secret<T = string> {\r\n /** Secret key/name */\r\n key: string;\r\n\r\n /** Secret value */\r\n value: T;\r\n\r\n /** Secret metadata */\r\n metadata?: SecretMetadata;\r\n}\r\n\r\n/**\r\n * Options for getting secrets\r\n */\r\nexport interface GetSecretOptions {\r\n /** Specific version to retrieve */\r\n version?: string;\r\n\r\n /** Include metadata in response */\r\n includeMetadata?: boolean;\r\n\r\n /** Cache TTL in seconds (0 = no cache) */\r\n cacheTtl?: number;\r\n}\r\n\r\n/**\r\n * Options for setting secrets\r\n */\r\nexport interface SetSecretOptions {\r\n /** Expiration timestamp */\r\n expiresAt?: Date;\r\n\r\n /** Custom tags/labels */\r\n tags?: Record<string, string>;\r\n\r\n /** Description */\r\n description?: string;\r\n}\r\n\r\n/**\r\n * Options for rotating secrets\r\n */\r\nexport interface RotateSecretOptions {\r\n /** Custom rotation function */\r\n rotationFn?: () => Promise<string>;\r\n\r\n /** Rotation period in days */\r\n rotationPeriodDays?: number;\r\n\r\n /** Keep previous version count */\r\n keepPreviousVersions?: number;\r\n}\r\n\r\n/**\r\n * Result of a rotation operation\r\n */\r\nexport interface RotationResult {\r\n /** New secret value */\r\n newValue: string;\r\n\r\n /** Previous secret value (for rollback) */\r\n previousValue?: string;\r\n\r\n /** New version identifier */\r\n newVersion: string;\r\n\r\n /** Previous version identifier */\r\n previousVersion?: string;\r\n}\r\n\r\n/**\r\n * Secrets Management Interface\r\n */\r\nexport interface ISecrets {\r\n /**\r\n * Get a secret value by key\r\n */\r\n get(key: string, options?: GetSecretOptions): Promise<string | null>;\r\n\r\n /**\r\n * Get a secret with metadata\r\n */\r\n getWithMetadata(key: string, options?: GetSecretOptions): Promise<Secret | null>;\r\n\r\n /**\r\n * Get multiple secrets at once\r\n */\r\n mget(keys: string[]): Promise<Map<string, string | null>>;\r\n\r\n /**\r\n * Set a secret value\r\n */\r\n set(key: string, value: string, options?: SetSecretOptions): Promise<void>;\r\n\r\n /**\r\n * Delete a secret\r\n */\r\n delete(key: string): Promise<void>;\r\n\r\n /**\r\n * Check if a secret exists\r\n */\r\n exists(key: string): Promise<boolean>;\r\n\r\n /**\r\n * List all secret keys (optionally filtered by prefix)\r\n */\r\n list(prefix?: string): Promise<string[]>;\r\n\r\n /**\r\n * Rotate a secret (generate new value)\r\n */\r\n rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult>;\r\n\r\n /**\r\n * Get all versions of a secret\r\n */\r\n getVersions(key: string): Promise<SecretMetadata[]>;\r\n\r\n /**\r\n * Health check\r\n */\r\n healthCheck(): Promise<boolean>;\r\n}\r\n\r\n/**\r\n * Environment Variables Secrets Adapter\r\n * Simple implementation using process.env - suitable for development\r\n * and containerized deployments with injected secrets\r\n */\r\nexport class EnvSecrets implements ISecrets {\r\n private prefix: string;\r\n private cache: Map<string, { value: string; expiresAt: number }> = new Map();\r\n\r\n constructor(options: { prefix?: string } = {}) {\r\n this.prefix = options.prefix ?? '';\r\n }\r\n\r\n private getEnvKey(key: string): string {\r\n const normalizedKey = key.toUpperCase().replace(/[.-]/g, '_');\r\n return this.prefix ? `${this.prefix}_${normalizedKey}` : normalizedKey;\r\n }\r\n\r\n async get(key: string, options?: GetSecretOptions): Promise<string | null> {\r\n // Check cache first\r\n if (options?.cacheTtl) {\r\n const cached = this.cache.get(key);\r\n if (cached && cached.expiresAt > Date.now()) {\r\n return cached.value;\r\n }\r\n }\r\n\r\n const envKey = this.getEnvKey(key);\r\n const value = process.env[envKey] ?? null;\r\n\r\n // Cache if requested\r\n if (value && options?.cacheTtl) {\r\n this.cache.set(key, {\r\n value,\r\n expiresAt: Date.now() + options.cacheTtl * 1000,\r\n });\r\n }\r\n\r\n return value;\r\n }\r\n\r\n async getWithMetadata(key: string, options?: GetSecretOptions): Promise<Secret | null> {\r\n const value = await this.get(key, options);\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n return {\r\n key,\r\n value,\r\n metadata: {\r\n // Environment variables don't have native metadata\r\n createdAt: undefined,\r\n updatedAt: undefined,\r\n },\r\n };\r\n }\r\n\r\n async mget(keys: string[]): Promise<Map<string, string | null>> {\r\n const result = new Map<string, string | null>();\r\n for (const key of keys) {\r\n result.set(key, await this.get(key));\r\n }\r\n return result;\r\n }\r\n\r\n async set(key: string, value: string, _options?: SetSecretOptions): Promise<void> {\r\n const envKey = this.getEnvKey(key);\r\n process.env[envKey] = value;\r\n\r\n // Update cache\r\n this.cache.delete(key);\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n const envKey = this.getEnvKey(key);\r\n delete process.env[envKey];\r\n this.cache.delete(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n const envKey = this.getEnvKey(key);\r\n return process.env[envKey] !== undefined;\r\n }\r\n\r\n async list(prefix?: string): Promise<string[]> {\r\n const keys: string[] = [];\r\n const envPrefix = this.prefix ? `${this.prefix}_` : '';\r\n const searchPrefix = prefix\r\n ? `${envPrefix}${prefix.toUpperCase().replace(/[.-]/g, '_')}`\r\n : envPrefix;\r\n\r\n for (const key of Object.keys(process.env)) {\r\n if (key.startsWith(searchPrefix || '')) {\r\n // Convert back to normalized key format\r\n const normalizedKey = key\r\n .slice(envPrefix.length)\r\n .toLowerCase()\r\n .replace(/_/g, '-');\r\n keys.push(normalizedKey);\r\n }\r\n }\r\n\r\n return keys;\r\n }\r\n\r\n async rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult> {\r\n const previousValue = await this.get(key);\r\n\r\n // Generate new value\r\n const newValue = options?.rotationFn\r\n ? await options.rotationFn()\r\n : this.generateSecureValue();\r\n\r\n await this.set(key, newValue);\r\n\r\n return {\r\n newValue,\r\n previousValue: previousValue ?? undefined,\r\n newVersion: 'current',\r\n previousVersion: previousValue ? 'previous' : undefined,\r\n };\r\n }\r\n\r\n async getVersions(_key: string): Promise<SecretMetadata[]> {\r\n // Environment variables don't support versioning\r\n return [];\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n // Environment is always available\r\n return true;\r\n }\r\n\r\n private generateSecureValue(length: number = 32): string {\r\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';\r\n let result = '';\r\n const randomValues = new Uint32Array(length);\r\n crypto.getRandomValues(randomValues);\r\n for (let i = 0; i < length; i++) {\r\n result += chars[randomValues[i]! % chars.length];\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear the internal cache\r\n */\r\n clearCache(): void {\r\n this.cache.clear();\r\n }\r\n}\r\n\r\n/**\r\n * Memory-based Secrets Adapter\r\n * For testing purposes only - stores secrets in memory\r\n */\r\nexport class MemorySecrets implements ISecrets {\r\n private secrets: Map<string, Secret> = new Map();\r\n private versions: Map<string, SecretMetadata[]> = new Map();\r\n\r\n async get(key: string, _options?: GetSecretOptions): Promise<string | null> {\r\n const secret = this.secrets.get(key);\r\n if (!secret) {\r\n return null;\r\n }\r\n\r\n // Check expiration\r\n if (secret.metadata?.expiresAt && secret.metadata.expiresAt < new Date()) {\r\n await this.delete(key);\r\n return null;\r\n }\r\n\r\n return secret.value;\r\n }\r\n\r\n async getWithMetadata(key: string, options?: GetSecretOptions): Promise<Secret | null> {\r\n const value = await this.get(key, options);\r\n if (value === null) {\r\n return null;\r\n }\r\n\r\n return this.secrets.get(key) ?? null;\r\n }\r\n\r\n async mget(keys: string[]): Promise<Map<string, string | null>> {\r\n const result = new Map<string, string | null>();\r\n for (const key of keys) {\r\n result.set(key, await this.get(key));\r\n }\r\n return result;\r\n }\r\n\r\n async set(key: string, value: string, options?: SetSecretOptions): Promise<void> {\r\n const now = new Date();\r\n const version = `v${Date.now()}`;\r\n\r\n // Store version history\r\n const currentSecret = this.secrets.get(key);\r\n if (currentSecret?.metadata) {\r\n const history = this.versions.get(key) ?? [];\r\n history.push(currentSecret.metadata);\r\n this.versions.set(key, history);\r\n }\r\n\r\n this.secrets.set(key, {\r\n key,\r\n value,\r\n metadata: {\r\n version,\r\n createdAt: currentSecret?.metadata?.createdAt ?? now,\r\n updatedAt: now,\r\n expiresAt: options?.expiresAt,\r\n tags: options?.tags,\r\n },\r\n });\r\n }\r\n\r\n async delete(key: string): Promise<void> {\r\n this.secrets.delete(key);\r\n this.versions.delete(key);\r\n }\r\n\r\n async exists(key: string): Promise<boolean> {\r\n return this.secrets.has(key);\r\n }\r\n\r\n async list(prefix?: string): Promise<string[]> {\r\n const keys: string[] = [];\r\n for (const key of this.secrets.keys()) {\r\n if (!prefix || key.startsWith(prefix)) {\r\n keys.push(key);\r\n }\r\n }\r\n return keys;\r\n }\r\n\r\n async rotate(key: string, options?: RotateSecretOptions): Promise<RotationResult> {\r\n const currentSecret = this.secrets.get(key);\r\n const previousValue = currentSecret?.value;\r\n const previousVersion = currentSecret?.metadata?.version;\r\n\r\n // Generate new value\r\n const newValue = options?.rotationFn\r\n ? await options.rotationFn()\r\n : this.generateSecureValue();\r\n\r\n await this.set(key, newValue);\r\n const newVersion = this.secrets.get(key)?.metadata?.version ?? 'unknown';\r\n\r\n return {\r\n newValue,\r\n previousValue,\r\n newVersion,\r\n previousVersion,\r\n };\r\n }\r\n\r\n async getVersions(key: string): Promise<SecretMetadata[]> {\r\n const current = this.secrets.get(key)?.metadata;\r\n const history = this.versions.get(key) ?? [];\r\n\r\n if (current) {\r\n return [...history, current];\r\n }\r\n\r\n return history;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n private generateSecureValue(length: number = 32): string {\r\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*';\r\n let result = '';\r\n for (let i = 0; i < length; i++) {\r\n result += chars[Math.floor(Math.random() * chars.length)];\r\n }\r\n return result;\r\n }\r\n\r\n /**\r\n * Clear all secrets (for testing)\r\n */\r\n clear(): void {\r\n this.secrets.clear();\r\n this.versions.clear();\r\n }\r\n\r\n /**\r\n * Get count of secrets (for testing)\r\n */\r\n get size(): number {\r\n return this.secrets.size;\r\n }\r\n}\r\n","/**\r\n * Distributed Tracing Interface\r\n *\r\n * Provides vendor-agnostic distributed tracing for observability.\r\n * Supports OpenTelemetry, Jaeger, Zipkin, and custom implementations.\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport type SpanKind = 'internal' | 'server' | 'client' | 'producer' | 'consumer';\r\n\r\nexport type SpanStatusCode = 'unset' | 'ok' | 'error';\r\n\r\nexport interface SpanStatus {\r\n code: SpanStatusCode;\r\n message?: string;\r\n}\r\n\r\nexport interface SpanContext {\r\n traceId: string;\r\n spanId: string;\r\n traceFlags: number;\r\n traceState?: string;\r\n}\r\n\r\nexport interface SpanOptions {\r\n /** Type of span */\r\n kind?: SpanKind;\r\n\r\n /** Initial attributes */\r\n attributes?: Record<string, string | number | boolean>;\r\n\r\n /** Parent span (for manual context propagation) */\r\n parent?: ISpan;\r\n\r\n /** Links to other spans */\r\n links?: SpanContext[];\r\n\r\n /** Start time (defaults to now) */\r\n startTime?: number;\r\n}\r\n\r\nexport interface SpanEvent {\r\n name: string;\r\n timestamp: number;\r\n attributes?: Record<string, string | number | boolean>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// SPAN INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface ISpan {\r\n /** Span name */\r\n readonly name: string;\r\n\r\n /** Span context (trace ID, span ID) */\r\n readonly context: SpanContext;\r\n\r\n /** Whether the span is recording */\r\n readonly isRecording: boolean;\r\n\r\n /**\r\n * Set a single attribute\r\n */\r\n setAttribute(key: string, value: string | number | boolean): this;\r\n\r\n /**\r\n * Set multiple attributes\r\n */\r\n setAttributes(attributes: Record<string, string | number | boolean>): this;\r\n\r\n /**\r\n * Add an event to the span\r\n */\r\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): this;\r\n\r\n /**\r\n * Set the span status\r\n */\r\n setStatus(status: SpanStatus): this;\r\n\r\n /**\r\n * Record an exception\r\n */\r\n recordException(exception: Error, attributes?: Record<string, string | number | boolean>): this;\r\n\r\n /**\r\n * Update the span name\r\n */\r\n updateName(name: string): this;\r\n\r\n /**\r\n * End the span (required to export)\r\n */\r\n end(endTime?: number): void;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TRACING INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface ITracing {\r\n /**\r\n * Create and start a new span\r\n */\r\n startSpan(name: string, options?: SpanOptions): ISpan;\r\n\r\n /**\r\n * Get the currently active span\r\n */\r\n getCurrentSpan(): ISpan | undefined;\r\n\r\n /**\r\n * Execute a function within a span context\r\n */\r\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T;\r\n\r\n /**\r\n * Execute an async function within a span context\r\n */\r\n withSpanAsync<T>(name: string, fn: (span: ISpan) => Promise<T>, options?: SpanOptions): Promise<T>;\r\n\r\n /**\r\n * Instrument a function with automatic span creation\r\n */\r\n instrument<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => TReturn,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => TReturn;\r\n\r\n /**\r\n * Instrument an async function with automatic span creation\r\n */\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => Promise<TReturn>;\r\n\r\n /**\r\n * Extract trace context from headers (for incoming requests)\r\n */\r\n extractContext(headers: Record<string, string | string[] | undefined>): SpanContext | undefined;\r\n\r\n /**\r\n * Inject trace context into headers (for outgoing requests)\r\n */\r\n injectContext(headers: Record<string, string>): void;\r\n\r\n /**\r\n * Check if tracing is enabled and healthy\r\n */\r\n healthCheck(): Promise<boolean>;\r\n\r\n /**\r\n * Flush pending spans to the exporter\r\n */\r\n flush(): Promise<void>;\r\n\r\n /**\r\n * Shutdown the tracer\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TRACING CONFIGURATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface TracingConfig {\r\n /** Enable tracing */\r\n enabled: boolean;\r\n\r\n /** Service name for traces */\r\n serviceName: string;\r\n\r\n /** Service version */\r\n serviceVersion?: string;\r\n\r\n /** Environment (dev, staging, production) */\r\n environment?: string;\r\n\r\n /** Sampling rate (0.0 to 1.0) */\r\n sampleRate?: number;\r\n\r\n /** Exporter type */\r\n exporter?: 'console' | 'otlp' | 'jaeger' | 'zipkin' | 'none';\r\n\r\n /** Exporter endpoint */\r\n endpoint?: string;\r\n\r\n /** Additional resource attributes */\r\n resourceAttributes?: Record<string, string>;\r\n\r\n /** Propagation format */\r\n propagation?: 'w3c' | 'b3' | 'jaeger';\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// MEMORY TRACING (For Testing)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nclass MemorySpan implements ISpan {\r\n readonly name: string;\r\n readonly context: SpanContext;\r\n readonly isRecording: boolean = true;\r\n\r\n private _attributes: Record<string, string | number | boolean> = {};\r\n private _events: SpanEvent[] = [];\r\n private _status: SpanStatus = { code: 'unset' };\r\n private _endTime?: number;\r\n private _startTime: number;\r\n\r\n constructor(name: string, traceId: string, parentSpanId?: string) {\r\n this.name = name;\r\n this._startTime = Date.now();\r\n this.context = {\r\n traceId,\r\n spanId: this.generateSpanId(),\r\n traceFlags: 1,\r\n };\r\n }\r\n\r\n private generateSpanId(): string {\r\n return Math.random().toString(16).substring(2, 18).padStart(16, '0');\r\n }\r\n\r\n setAttribute(key: string, value: string | number | boolean): this {\r\n this._attributes[key] = value;\r\n return this;\r\n }\r\n\r\n setAttributes(attributes: Record<string, string | number | boolean>): this {\r\n Object.assign(this._attributes, attributes);\r\n return this;\r\n }\r\n\r\n addEvent(name: string, attributes?: Record<string, string | number | boolean>): this {\r\n this._events.push({ name, timestamp: Date.now(), attributes });\r\n return this;\r\n }\r\n\r\n setStatus(status: SpanStatus): this {\r\n this._status = status;\r\n return this;\r\n }\r\n\r\n recordException(exception: Error, attributes?: Record<string, string | number | boolean>): this {\r\n this.addEvent('exception', {\r\n 'exception.type': exception.name,\r\n 'exception.message': exception.message,\r\n 'exception.stacktrace': exception.stack || '',\r\n ...attributes,\r\n });\r\n this.setStatus({ code: 'error', message: exception.message });\r\n return this;\r\n }\r\n\r\n updateName(name: string): this {\r\n (this as { name: string }).name = name;\r\n return this;\r\n }\r\n\r\n end(endTime?: number): void {\r\n this._endTime = endTime ?? Date.now();\r\n }\r\n\r\n // Testing helpers\r\n getAttributes(): Record<string, string | number | boolean> {\r\n return { ...this._attributes };\r\n }\r\n\r\n getEvents(): SpanEvent[] {\r\n return [...this._events];\r\n }\r\n\r\n getStatus(): SpanStatus {\r\n return { ...this._status };\r\n }\r\n\r\n getDuration(): number | undefined {\r\n return this._endTime ? this._endTime - this._startTime : undefined;\r\n }\r\n\r\n isEnded(): boolean {\r\n return this._endTime !== undefined;\r\n }\r\n}\r\n\r\nexport class MemoryTracing implements ITracing {\r\n private spans: MemorySpan[] = [];\r\n private currentSpan: MemorySpan | undefined;\r\n private traceId: string;\r\n\r\n constructor() {\r\n this.traceId = this.generateTraceId();\r\n }\r\n\r\n private generateTraceId(): string {\r\n return Math.random().toString(16).substring(2, 34).padStart(32, '0');\r\n }\r\n\r\n startSpan(name: string, options?: SpanOptions): ISpan {\r\n const span = new MemorySpan(name, this.traceId, this.currentSpan?.context.spanId);\r\n\r\n if (options?.attributes) {\r\n span.setAttributes(options.attributes);\r\n }\r\n\r\n this.spans.push(span);\r\n this.currentSpan = span;\r\n\r\n return span;\r\n }\r\n\r\n getCurrentSpan(): ISpan | undefined {\r\n return this.currentSpan;\r\n }\r\n\r\n withSpan<T>(name: string, fn: (span: ISpan) => T, options?: SpanOptions): T {\r\n const span = this.startSpan(name, options);\r\n try {\r\n const result = fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n }\r\n }\r\n\r\n async withSpanAsync<T>(name: string, fn: (span: ISpan) => Promise<T>, options?: SpanOptions): Promise<T> {\r\n const span = this.startSpan(name, options);\r\n try {\r\n const result = await fn(span);\r\n span.setStatus({ code: 'ok' });\r\n return result;\r\n } catch (error) {\r\n span.recordException(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n } finally {\r\n span.end();\r\n }\r\n }\r\n\r\n instrument<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => TReturn,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => TReturn {\r\n return (...args: TArgs) => this.withSpan(name, () => fn(...args), options);\r\n }\r\n\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n options?: SpanOptions\r\n ): (...args: TArgs) => Promise<TReturn> {\r\n return (...args: TArgs) => this.withSpanAsync(name, () => fn(...args), options);\r\n }\r\n\r\n extractContext(headers: Record<string, string | string[] | undefined>): SpanContext | undefined {\r\n const traceparent = headers['traceparent'];\r\n if (!traceparent || typeof traceparent !== 'string') return undefined;\r\n\r\n // Parse W3C Trace Context format: version-traceId-spanId-flags\r\n const parts = traceparent.split('-');\r\n if (parts.length !== 4) return undefined;\r\n\r\n return {\r\n traceId: parts[1]!,\r\n spanId: parts[2]!,\r\n traceFlags: parseInt(parts[3]!, 16),\r\n };\r\n }\r\n\r\n injectContext(headers: Record<string, string>): void {\r\n if (this.currentSpan) {\r\n const ctx = this.currentSpan.context;\r\n headers['traceparent'] = `00-${ctx.traceId}-${ctx.spanId}-${ctx.traceFlags.toString(16).padStart(2, '0')}`;\r\n }\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async flush(): Promise<void> {\r\n // No-op for memory implementation\r\n }\r\n\r\n async close(): Promise<void> {\r\n this.spans = [];\r\n this.currentSpan = undefined;\r\n }\r\n\r\n // Testing helpers\r\n getSpans(): MemorySpan[] {\r\n return [...this.spans];\r\n }\r\n\r\n getCompletedSpans(): MemorySpan[] {\r\n return this.spans.filter((s) => s.isEnded());\r\n }\r\n\r\n clear(): void {\r\n this.spans = [];\r\n this.currentSpan = undefined;\r\n this.traceId = this.generateTraceId();\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// NOOP TRACING (Disabled)\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nclass NoopSpan implements ISpan {\r\n readonly name: string = '';\r\n readonly context: SpanContext = { traceId: '', spanId: '', traceFlags: 0 };\r\n readonly isRecording: boolean = false;\r\n\r\n setAttribute(): this {\r\n return this;\r\n }\r\n setAttributes(): this {\r\n return this;\r\n }\r\n addEvent(): this {\r\n return this;\r\n }\r\n setStatus(): this {\r\n return this;\r\n }\r\n recordException(): this {\r\n return this;\r\n }\r\n updateName(): this {\r\n return this;\r\n }\r\n end(): void {}\r\n}\r\n\r\nexport class NoopTracing implements ITracing {\r\n private noopSpan = new NoopSpan();\r\n\r\n startSpan(): ISpan {\r\n return this.noopSpan;\r\n }\r\n\r\n getCurrentSpan(): ISpan | undefined {\r\n return undefined;\r\n }\r\n\r\n withSpan<T>(_name: string, fn: (span: ISpan) => T): T {\r\n return fn(this.noopSpan);\r\n }\r\n\r\n async withSpanAsync<T>(_name: string, fn: (span: ISpan) => Promise<T>): Promise<T> {\r\n return fn(this.noopSpan);\r\n }\r\n\r\n instrument<TArgs extends unknown[], TReturn>(\r\n _name: string,\r\n fn: (...args: TArgs) => TReturn\r\n ): (...args: TArgs) => TReturn {\r\n return fn;\r\n }\r\n\r\n instrumentAsync<TArgs extends unknown[], TReturn>(\r\n _name: string,\r\n fn: (...args: TArgs) => Promise<TReturn>\r\n ): (...args: TArgs) => Promise<TReturn> {\r\n return fn;\r\n }\r\n\r\n extractContext(): SpanContext | undefined {\r\n return undefined;\r\n }\r\n\r\n injectContext(): void {}\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async flush(): Promise<void> {}\r\n\r\n async close(): Promise<void> {}\r\n}\r\n","/**\r\n * Error Reporter Interface\r\n *\r\n * Provides a vendor-agnostic way to report and track errors.\r\n * Self-hosted by default with optional external integrations.\r\n *\r\n * Design Principles:\r\n * - Self-hostable: Console, File, Memory adapters included\r\n * - No cloud lock-in: External services (Sentry, GlitchTip) are optional\r\n * - Correlation-aware: Integrates with CorrelationContext\r\n * - Zero external costs: Works without any external service\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// ERROR CONTEXT & METADATA\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface ErrorContext {\r\n /** Unique error ID */\r\n errorId?: string;\r\n /** Trace ID for distributed tracing */\r\n traceId?: string;\r\n /** Correlation ID for request/job tracking */\r\n correlationId?: string;\r\n /** Request ID */\r\n requestId?: string;\r\n /** User ID if authenticated */\r\n userId?: string;\r\n /** Tenant ID for multi-tenant apps */\r\n tenantId?: string;\r\n /** Operation/endpoint that failed */\r\n operation?: string;\r\n /** Environment (dev, staging, production) */\r\n environment?: string;\r\n /** Service/component name */\r\n service?: string;\r\n /** Release/version */\r\n release?: string;\r\n /** Additional tags for filtering */\r\n tags?: Record<string, string>;\r\n /** Extra contextual data */\r\n extra?: Record<string, unknown>;\r\n}\r\n\r\nexport interface ErrorReport {\r\n /** Unique report ID */\r\n id: string;\r\n /** Error message */\r\n message: string;\r\n /** Error name/type */\r\n name: string;\r\n /** Stack trace */\r\n stack?: string;\r\n /** Context at time of error */\r\n context: ErrorContext;\r\n /** Severity level */\r\n level: ErrorLevel;\r\n /** Timestamp */\r\n timestamp: number;\r\n /** Whether error was handled */\r\n handled: boolean;\r\n /** Fingerprint for grouping similar errors */\r\n fingerprint?: string[];\r\n /** Breadcrumbs/trail leading to error */\r\n breadcrumbs?: Breadcrumb[];\r\n}\r\n\r\nexport type ErrorLevel = 'fatal' | 'error' | 'warning' | 'info' | 'debug';\r\n\r\nexport interface Breadcrumb {\r\n /** Category (http, navigation, user, etc.) */\r\n category: string;\r\n /** Breadcrumb message */\r\n message: string;\r\n /** Severity level */\r\n level?: ErrorLevel;\r\n /** Timestamp */\r\n timestamp: number;\r\n /** Additional data */\r\n data?: Record<string, unknown>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// ERROR REPORTER OPTIONS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface CaptureOptions {\r\n /** Override error level */\r\n level?: ErrorLevel;\r\n /** Additional context */\r\n context?: Partial<ErrorContext>;\r\n /** Custom fingerprint for grouping */\r\n fingerprint?: string[];\r\n /** Mark as handled/unhandled */\r\n handled?: boolean;\r\n /** Additional tags */\r\n tags?: Record<string, string>;\r\n /** Extra data */\r\n extra?: Record<string, unknown>;\r\n}\r\n\r\nexport interface ErrorReporterConfig {\r\n /** Service/application name */\r\n serviceName: string;\r\n /** Environment */\r\n environment?: string;\r\n /** Release version */\r\n release?: string;\r\n /** Default tags */\r\n defaultTags?: Record<string, string>;\r\n /** Maximum breadcrumbs to keep */\r\n maxBreadcrumbs?: number;\r\n /** Whether to capture unhandled errors */\r\n captureUnhandled?: boolean;\r\n /** Sample rate (0.0 to 1.0) */\r\n sampleRate?: number;\r\n /** Filter errors before reporting */\r\n beforeSend?: (report: ErrorReport) => ErrorReport | null;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// ERROR REPORTER INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface IErrorReporter {\r\n /**\r\n * Capture and report an error\r\n */\r\n captureError(error: Error, options?: CaptureOptions): string;\r\n\r\n /**\r\n * Capture a message (non-error event)\r\n */\r\n captureMessage(message: string, options?: CaptureOptions): string;\r\n\r\n /**\r\n * Add a breadcrumb to the trail\r\n */\r\n addBreadcrumb(breadcrumb: Omit<Breadcrumb, 'timestamp'>): void;\r\n\r\n /**\r\n * Set user context for future errors\r\n */\r\n setUser(user: { id?: string; email?: string; username?: string } | null): void;\r\n\r\n /**\r\n * Set extra context for future errors\r\n */\r\n setContext(name: string, context: Record<string, unknown> | null): void;\r\n\r\n /**\r\n * Set a tag for future errors\r\n */\r\n setTag(key: string, value: string): void;\r\n\r\n /**\r\n * Get recent error reports (for self-hosted review)\r\n */\r\n getReports(options?: { limit?: number; level?: ErrorLevel }): ErrorReport[];\r\n\r\n /**\r\n * Clear stored reports\r\n */\r\n clearReports(): void;\r\n\r\n /**\r\n * Flush pending reports (for async reporters)\r\n */\r\n flush(timeout?: number): Promise<boolean>;\r\n\r\n /**\r\n * Close the reporter\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPER FUNCTIONS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Generate unique error ID\r\n */\r\nexport function generateErrorId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `err_${timestamp}_${random}`;\r\n}\r\n\r\n/**\r\n * Generate fingerprint from error\r\n */\r\nexport function generateFingerprint(error: Error): string[] {\r\n const fingerprint: string[] = [];\r\n\r\n // Error type\r\n fingerprint.push(error.name || 'Error');\r\n\r\n // First line of stack (file:line:column)\r\n if (error.stack) {\r\n const stackLines = error.stack.split('\\n');\r\n const firstFrame = stackLines[1]?.trim();\r\n if (firstFrame) {\r\n // Extract file:line:col pattern\r\n const match = firstFrame.match(/at\\s+(?:.*?\\s+\\()?(.+?):(\\d+):(\\d+)\\)?$/);\r\n if (match) {\r\n fingerprint.push(`${match[1]}:${match[2]}`);\r\n }\r\n }\r\n }\r\n\r\n // Message without variable parts (numbers, uuids)\r\n const normalizedMessage = error.message\r\n .replace(/\\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\\b/gi, '<uuid>')\r\n .replace(/\\b\\d+\\b/g, '<number>');\r\n fingerprint.push(normalizedMessage);\r\n\r\n return fingerprint;\r\n}\r\n\r\n/**\r\n * Create error report from Error object\r\n */\r\nexport function createErrorReport(\r\n error: Error,\r\n context: ErrorContext,\r\n options?: CaptureOptions\r\n): ErrorReport {\r\n return {\r\n id: generateErrorId(),\r\n message: error.message,\r\n name: error.name || 'Error',\r\n stack: error.stack,\r\n context: {\r\n ...context,\r\n ...options?.context,\r\n tags: { ...context.tags, ...options?.tags },\r\n extra: { ...context.extra, ...options?.extra },\r\n },\r\n level: options?.level ?? 'error',\r\n timestamp: Date.now(),\r\n handled: options?.handled ?? true,\r\n fingerprint: options?.fingerprint ?? generateFingerprint(error),\r\n breadcrumbs: [],\r\n };\r\n}\r\n","/**\r\n * Audit Log Interface\r\n *\r\n * Provides immutable, compliance-ready audit trail logging.\r\n * Self-hosted, no external dependencies.\r\n *\r\n * Features:\r\n * - Immutable event logging (append-only)\r\n * - Correlation with trace/request context\r\n * - Query and filtering capabilities\r\n * - Retention policy support\r\n * - Tamper detection via checksums\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Categories of audit events\r\n */\r\nexport type AuditCategory =\r\n | 'authentication' // Login, logout, token refresh\r\n | 'authorization' // Permission checks, access denied\r\n | 'data_access' // Read operations on sensitive data\r\n | 'data_mutation' // Create, update, delete operations\r\n | 'admin_action' // Administrative operations\r\n | 'security' // Security-related events\r\n | 'system' // System events (startup, shutdown)\r\n | 'billing' // Payment, subscription events\r\n | 'integration' // External API calls\r\n | 'custom'; // Custom application events\r\n\r\n/**\r\n * Outcome of the audited action\r\n */\r\nexport type AuditOutcome = 'success' | 'failure' | 'denied' | 'error';\r\n\r\n/**\r\n * Actor who performed the action\r\n */\r\nexport interface AuditActor {\r\n /** Actor type */\r\n type: 'user' | 'service' | 'system' | 'anonymous';\r\n /** Actor ID (user ID, service name, etc.) */\r\n id?: string;\r\n /** Display name */\r\n name?: string;\r\n /** Email if applicable */\r\n email?: string;\r\n /** IP address */\r\n ip?: string;\r\n /** User agent */\r\n userAgent?: string;\r\n /** Session ID */\r\n sessionId?: string;\r\n}\r\n\r\n/**\r\n * Target of the audited action\r\n */\r\nexport interface AuditTarget {\r\n /** Target type (e.g., 'user', 'document', 'setting') */\r\n type: string;\r\n /** Target ID */\r\n id?: string;\r\n /** Human-readable name */\r\n name?: string;\r\n /** Additional target attributes */\r\n attributes?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Audit event structure\r\n */\r\nexport interface AuditEvent {\r\n /** Unique event ID (generated if not provided) */\r\n id?: string;\r\n /** Event timestamp (ISO 8601) */\r\n timestamp?: string;\r\n /** Event category */\r\n category: AuditCategory;\r\n /** Action performed (e.g., 'user.login', 'document.delete') */\r\n action: string;\r\n /** Action outcome */\r\n outcome: AuditOutcome;\r\n /** Actor who performed the action */\r\n actor: AuditActor;\r\n /** Target of the action */\r\n target?: AuditTarget;\r\n /** Additional event data */\r\n data?: Record<string, unknown>;\r\n /** Changes made (for mutations) */\r\n changes?: {\r\n before?: Record<string, unknown>;\r\n after?: Record<string, unknown>;\r\n };\r\n /** Error details if outcome is 'error' or 'failure' */\r\n error?: {\r\n code?: string;\r\n message?: string;\r\n stack?: string;\r\n };\r\n /** Correlation context */\r\n context?: {\r\n traceId?: string;\r\n correlationId?: string;\r\n requestId?: string;\r\n tenantId?: string;\r\n environment?: string;\r\n service?: string;\r\n };\r\n /** Event checksum for tamper detection */\r\n checksum?: string;\r\n}\r\n\r\n/**\r\n * Stored audit event (includes all generated fields)\r\n */\r\nexport interface StoredAuditEvent extends Required<Pick<AuditEvent, 'id' | 'timestamp'>> {\r\n id: string;\r\n timestamp: string;\r\n category: AuditCategory;\r\n action: string;\r\n outcome: AuditOutcome;\r\n actor: AuditActor;\r\n target?: AuditTarget;\r\n data?: Record<string, unknown>;\r\n changes?: {\r\n before?: Record<string, unknown>;\r\n after?: Record<string, unknown>;\r\n };\r\n error?: {\r\n code?: string;\r\n message?: string;\r\n stack?: string;\r\n };\r\n context?: {\r\n traceId?: string;\r\n correlationId?: string;\r\n requestId?: string;\r\n tenantId?: string;\r\n environment?: string;\r\n service?: string;\r\n };\r\n checksum: string;\r\n /** Sequence number for ordering */\r\n sequence: number;\r\n}\r\n\r\n/**\r\n * Query filter for audit events\r\n */\r\nexport interface AuditQuery {\r\n /** Filter by category */\r\n category?: AuditCategory | AuditCategory[];\r\n /** Filter by action (supports wildcards: 'user.*') */\r\n action?: string | string[];\r\n /** Filter by outcome */\r\n outcome?: AuditOutcome | AuditOutcome[];\r\n /** Filter by actor ID */\r\n actorId?: string;\r\n /** Filter by actor type */\r\n actorType?: AuditActor['type'];\r\n /** Filter by target type */\r\n targetType?: string;\r\n /** Filter by target ID */\r\n targetId?: string;\r\n /** Filter by tenant ID */\r\n tenantId?: string;\r\n /** Filter by trace ID */\r\n traceId?: string;\r\n /** Filter by correlation ID */\r\n correlationId?: string;\r\n /** Start time (inclusive) */\r\n from?: Date | string;\r\n /** End time (inclusive) */\r\n to?: Date | string;\r\n /** Search in data fields (JSON path queries) */\r\n dataQuery?: Record<string, unknown>;\r\n /** Pagination: offset */\r\n offset?: number;\r\n /** Pagination: limit (default 100, max 1000) */\r\n limit?: number;\r\n /** Sort order */\r\n orderBy?: 'timestamp' | 'sequence';\r\n /** Sort direction */\r\n order?: 'asc' | 'desc';\r\n}\r\n\r\n/**\r\n * Query result with pagination info\r\n */\r\nexport interface AuditQueryResult {\r\n /** Matching events */\r\n events: StoredAuditEvent[];\r\n /** Total count (for pagination) */\r\n total: number;\r\n /** Has more results */\r\n hasMore: boolean;\r\n /** Query execution time (ms) */\r\n executionTime: number;\r\n}\r\n\r\n/**\r\n * Retention policy configuration\r\n */\r\nexport interface AuditRetentionPolicy {\r\n /** Days to retain events (0 = forever) */\r\n retentionDays: number;\r\n /** Categories exempt from retention policy */\r\n exemptCategories?: AuditCategory[];\r\n /** Archive before deletion */\r\n archiveBeforeDelete?: boolean;\r\n}\r\n\r\n/**\r\n * Audit log statistics\r\n */\r\nexport interface AuditStats {\r\n /** Total events */\r\n total: number;\r\n /** Events by category */\r\n byCategory: Record<AuditCategory, number>;\r\n /** Events by outcome */\r\n byOutcome: Record<AuditOutcome, number>;\r\n /** Oldest event timestamp */\r\n oldestEvent?: string;\r\n /** Newest event timestamp */\r\n newestEvent?: string;\r\n /** Storage size in bytes (if available) */\r\n storageBytes?: number;\r\n}\r\n\r\n/**\r\n * Configuration for audit log\r\n */\r\nexport interface AuditLogConfig {\r\n /** Service name for context */\r\n serviceName: string;\r\n /** Environment (development, staging, production) */\r\n environment?: string;\r\n /** Retention policy */\r\n retention?: AuditRetentionPolicy;\r\n /** Enable checksum verification */\r\n enableChecksums?: boolean;\r\n /** Custom ID generator */\r\n idGenerator?: () => string;\r\n /** Automatically include correlation context */\r\n autoCorrelation?: boolean;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Audit Log Interface\r\n *\r\n * Provides immutable, queryable audit trail for compliance and security.\r\n */\r\nexport interface IAuditLog {\r\n /**\r\n * Log an audit event\r\n * @param event - The audit event to log\r\n * @returns The stored event with generated fields\r\n */\r\n log(event: AuditEvent): Promise<StoredAuditEvent>;\r\n\r\n /**\r\n * Log multiple events atomically\r\n * @param events - Events to log\r\n * @returns Stored events\r\n */\r\n logBatch(events: AuditEvent[]): Promise<StoredAuditEvent[]>;\r\n\r\n /**\r\n * Query audit events\r\n * @param query - Query filters\r\n * @returns Query result with events and pagination info\r\n */\r\n query(query: AuditQuery): Promise<AuditQueryResult>;\r\n\r\n /**\r\n * Get a single event by ID\r\n * @param id - Event ID\r\n * @returns The event or null if not found\r\n */\r\n getEvent(id: string): Promise<StoredAuditEvent | null>;\r\n\r\n /**\r\n * Verify event integrity (checksum validation)\r\n * @param id - Event ID\r\n * @returns True if event is valid, false if tampered\r\n */\r\n verifyIntegrity(id: string): Promise<boolean>;\r\n\r\n /**\r\n * Get audit statistics\r\n * @returns Statistics about the audit log\r\n */\r\n getStats(): Promise<AuditStats>;\r\n\r\n /**\r\n * Apply retention policy (delete old events)\r\n * @param policy - Retention policy to apply (uses config if not provided)\r\n * @returns Number of events deleted\r\n */\r\n applyRetention(policy?: AuditRetentionPolicy): Promise<number>;\r\n\r\n /**\r\n * Export events for archival\r\n * @param query - Filter events to export\r\n * @returns Events in exportable format\r\n */\r\n export(query: AuditQuery): Promise<StoredAuditEvent[]>;\r\n\r\n /**\r\n * Health check\r\n * @returns True if audit log is operational\r\n */\r\n healthCheck(): Promise<boolean>;\r\n\r\n /**\r\n * Close connections and cleanup\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Generate a unique audit event ID\r\n */\r\nexport function generateAuditId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `aud_${timestamp}${random}`;\r\n}\r\n\r\n/**\r\n * Generate checksum for audit event (SHA-256 hash of canonical JSON)\r\n */\r\nexport function generateChecksum(event: Omit<AuditEvent, 'checksum'>): string {\r\n // Create canonical representation (sorted keys, no whitespace)\r\n const canonical = JSON.stringify(event, Object.keys(event).sort());\r\n\r\n // Simple hash for browser/Node compatibility\r\n // In production, use crypto.subtle or crypto.createHash\r\n let hash = 0;\r\n for (let i = 0; i < canonical.length; i++) {\r\n const char = canonical.charCodeAt(i);\r\n hash = ((hash << 5) - hash) + char;\r\n hash = hash & hash; // Convert to 32-bit integer\r\n }\r\n\r\n // Convert to hex and pad\r\n const hex = Math.abs(hash).toString(16).padStart(8, '0');\r\n return `sha256:${hex}${Date.now().toString(16)}`;\r\n}\r\n\r\n/**\r\n * Verify if an action matches a pattern (supports wildcards)\r\n * @example matchAction('user.login', 'user.*') // true\r\n * @example matchAction('user.login', 'user.login') // true\r\n * @example matchAction('user.login', 'admin.*') // false\r\n */\r\nexport function matchAction(action: string, pattern: string): boolean {\r\n if (pattern === '*') return true;\r\n if (pattern === action) return true;\r\n\r\n if (pattern.endsWith('.*')) {\r\n const prefix = pattern.slice(0, -2);\r\n return action.startsWith(prefix + '.');\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Create a standardized audit event for common actions\r\n */\r\nexport const AuditEvents = {\r\n /** User authentication events */\r\n auth: {\r\n login: (actor: AuditActor, outcome: AuditOutcome, data?: Record<string, unknown>): AuditEvent => ({\r\n category: 'authentication',\r\n action: 'auth.login',\r\n outcome,\r\n actor,\r\n data,\r\n }),\r\n logout: (actor: AuditActor): AuditEvent => ({\r\n category: 'authentication',\r\n action: 'auth.logout',\r\n outcome: 'success',\r\n actor,\r\n }),\r\n tokenRefresh: (actor: AuditActor, outcome: AuditOutcome): AuditEvent => ({\r\n category: 'authentication',\r\n action: 'auth.token_refresh',\r\n outcome,\r\n actor,\r\n }),\r\n passwordChange: (actor: AuditActor, outcome: AuditOutcome): AuditEvent => ({\r\n category: 'authentication',\r\n action: 'auth.password_change',\r\n outcome,\r\n actor,\r\n }),\r\n mfaEnabled: (actor: AuditActor): AuditEvent => ({\r\n category: 'authentication',\r\n action: 'auth.mfa_enabled',\r\n outcome: 'success',\r\n actor,\r\n }),\r\n },\r\n\r\n /** Data access events */\r\n data: {\r\n read: (actor: AuditActor, target: AuditTarget, outcome: AuditOutcome = 'success'): AuditEvent => ({\r\n category: 'data_access',\r\n action: 'data.read',\r\n outcome,\r\n actor,\r\n target,\r\n }),\r\n create: (actor: AuditActor, target: AuditTarget, data?: Record<string, unknown>): AuditEvent => ({\r\n category: 'data_mutation',\r\n action: 'data.create',\r\n outcome: 'success',\r\n actor,\r\n target,\r\n changes: { after: data },\r\n }),\r\n update: (actor: AuditActor, target: AuditTarget, before?: Record<string, unknown>, after?: Record<string, unknown>): AuditEvent => ({\r\n category: 'data_mutation',\r\n action: 'data.update',\r\n outcome: 'success',\r\n actor,\r\n target,\r\n changes: { before, after },\r\n }),\r\n delete: (actor: AuditActor, target: AuditTarget, data?: Record<string, unknown>): AuditEvent => ({\r\n category: 'data_mutation',\r\n action: 'data.delete',\r\n outcome: 'success',\r\n actor,\r\n target,\r\n changes: { before: data },\r\n }),\r\n },\r\n\r\n /** Admin actions */\r\n admin: {\r\n settingChange: (actor: AuditActor, setting: string, before: unknown, after: unknown): AuditEvent => ({\r\n category: 'admin_action',\r\n action: 'admin.setting_change',\r\n outcome: 'success',\r\n actor,\r\n target: { type: 'setting', id: setting },\r\n changes: { before: { value: before }, after: { value: after } },\r\n }),\r\n userSuspend: (actor: AuditActor, targetUserId: string, reason?: string): AuditEvent => ({\r\n category: 'admin_action',\r\n action: 'admin.user_suspend',\r\n outcome: 'success',\r\n actor,\r\n target: { type: 'user', id: targetUserId },\r\n data: { reason },\r\n }),\r\n },\r\n\r\n /** Security events */\r\n security: {\r\n accessDenied: (actor: AuditActor, resource: string, reason?: string): AuditEvent => ({\r\n category: 'security',\r\n action: 'security.access_denied',\r\n outcome: 'denied',\r\n actor,\r\n target: { type: 'resource', id: resource },\r\n data: { reason },\r\n }),\r\n rateLimited: (actor: AuditActor, endpoint: string): AuditEvent => ({\r\n category: 'security',\r\n action: 'security.rate_limited',\r\n outcome: 'denied',\r\n actor,\r\n target: { type: 'endpoint', id: endpoint },\r\n }),\r\n suspiciousActivity: (actor: AuditActor, description: string, data?: Record<string, unknown>): AuditEvent => ({\r\n category: 'security',\r\n action: 'security.suspicious_activity',\r\n outcome: 'failure',\r\n actor,\r\n data: { description, ...data },\r\n }),\r\n },\r\n\r\n /** Billing events */\r\n billing: {\r\n subscriptionCreated: (actor: AuditActor, subscriptionId: string, plan: string): AuditEvent => ({\r\n category: 'billing',\r\n action: 'billing.subscription_created',\r\n outcome: 'success',\r\n actor,\r\n target: { type: 'subscription', id: subscriptionId },\r\n data: { plan },\r\n }),\r\n paymentProcessed: (actor: AuditActor, paymentId: string, amount: number, currency: string): AuditEvent => ({\r\n category: 'billing',\r\n action: 'billing.payment_processed',\r\n outcome: 'success',\r\n actor,\r\n target: { type: 'payment', id: paymentId },\r\n data: { amount, currency },\r\n }),\r\n paymentFailed: (actor: AuditActor, paymentId: string, reason: string): AuditEvent => ({\r\n category: 'billing',\r\n action: 'billing.payment_failed',\r\n outcome: 'failure',\r\n actor,\r\n target: { type: 'payment', id: paymentId },\r\n error: { message: reason },\r\n }),\r\n },\r\n};\r\n","/**\r\n * Scheduler Interface\r\n *\r\n * Job scheduling abstraction for cron-based and one-time scheduled tasks.\r\n * Built on top of IQueue for execution, providing:\r\n * - Cron-based recurring jobs\r\n * - One-time scheduled jobs\r\n * - Job management (pause, resume, cancel)\r\n * - Schedule status and history\r\n *\r\n * Self-hosted, no external dependencies beyond IQueue.\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Cron expression type (standard 5-field or 6-field with seconds)\r\n * @example '0 * * * *' - Every hour\r\n * @example '0 9 * * 1-5' - 9 AM on weekdays\r\n * @example '0 0 1 * *' - First day of every month\r\n */\r\nexport type CronExpression = string;\r\n\r\n/**\r\n * Schedule state\r\n */\r\nexport type ScheduleState = 'active' | 'paused' | 'completed' | 'cancelled';\r\n\r\n/**\r\n * Scheduled job definition\r\n */\r\nexport interface ScheduledJob<T = unknown> {\r\n /** Unique schedule ID */\r\n id: string;\r\n /** Schedule name (for display/identification) */\r\n name: string;\r\n /** Job description */\r\n description?: string;\r\n /** Cron expression for recurring jobs */\r\n cron?: CronExpression;\r\n /** Specific run time for one-time jobs (ISO 8601) */\r\n runAt?: string;\r\n /** Timezone for cron interpretation (default: UTC) */\r\n timezone?: string;\r\n /** Job data to pass to handler */\r\n data: T;\r\n /** Schedule state */\r\n state: ScheduleState;\r\n /** Creation timestamp */\r\n createdAt: string;\r\n /** Last modification timestamp */\r\n updatedAt: string;\r\n /** Next scheduled run time (ISO 8601) */\r\n nextRun?: string;\r\n /** Last run time (ISO 8601) */\r\n lastRun?: string;\r\n /** Last run result */\r\n lastResult?: 'success' | 'failure';\r\n /** Last run error message */\r\n lastError?: string;\r\n /** Total run count */\r\n runCount: number;\r\n /** Total failure count */\r\n failureCount: number;\r\n /** Maximum run count (0 = unlimited) */\r\n maxRuns?: number;\r\n /** Tags for organization */\r\n tags?: string[];\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Schedule creation options\r\n */\r\nexport interface CreateScheduleOptions<T = unknown> {\r\n /** Unique ID (generated if not provided) */\r\n id?: string;\r\n /** Schedule name */\r\n name: string;\r\n /** Description */\r\n description?: string;\r\n /** Cron expression (for recurring) */\r\n cron?: CronExpression;\r\n /** Run at specific time (for one-time) */\r\n runAt?: Date | string;\r\n /** Timezone (default: UTC) */\r\n timezone?: string;\r\n /** Job data */\r\n data: T;\r\n /** Maximum runs (0 = unlimited, default for recurring) */\r\n maxRuns?: number;\r\n /** Tags */\r\n tags?: string[];\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n /** Start in paused state */\r\n paused?: boolean;\r\n}\r\n\r\n/**\r\n * Schedule update options\r\n */\r\nexport interface UpdateScheduleOptions<T = unknown> {\r\n /** Update cron expression */\r\n cron?: CronExpression;\r\n /** Update run at time */\r\n runAt?: Date | string;\r\n /** Update timezone */\r\n timezone?: string;\r\n /** Update job data */\r\n data?: T;\r\n /** Update max runs */\r\n maxRuns?: number;\r\n /** Update tags */\r\n tags?: string[];\r\n /** Update metadata */\r\n metadata?: Record<string, unknown>;\r\n /** Update description */\r\n description?: string;\r\n}\r\n\r\n/**\r\n * Schedule query options\r\n */\r\nexport interface ScheduleQuery {\r\n /** Filter by state */\r\n state?: ScheduleState | ScheduleState[];\r\n /** Filter by tags (any match) */\r\n tags?: string[];\r\n /** Filter by name pattern (supports wildcards) */\r\n name?: string;\r\n /** Include schedules with next run before this time */\r\n nextRunBefore?: Date | string;\r\n /** Include schedules with next run after this time */\r\n nextRunAfter?: Date | string;\r\n /** Pagination: offset */\r\n offset?: number;\r\n /** Pagination: limit */\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Schedule execution history entry\r\n */\r\nexport interface ScheduleExecution {\r\n /** Execution ID */\r\n id: string;\r\n /** Schedule ID */\r\n scheduleId: string;\r\n /** Start time */\r\n startedAt: string;\r\n /** End time */\r\n completedAt?: string;\r\n /** Duration in ms */\r\n duration?: number;\r\n /** Result */\r\n result: 'success' | 'failure' | 'running';\r\n /** Error message */\r\n error?: string;\r\n /** Job ID (from queue) */\r\n jobId?: string;\r\n}\r\n\r\n/**\r\n * Scheduler statistics\r\n */\r\nexport interface SchedulerStats {\r\n /** Total schedules */\r\n total: number;\r\n /** Active schedules */\r\n active: number;\r\n /** Paused schedules */\r\n paused: number;\r\n /** Completed schedules */\r\n completed: number;\r\n /** Cancelled schedules */\r\n cancelled: number;\r\n /** Executions in last 24 hours */\r\n executionsLast24h: number;\r\n /** Failures in last 24 hours */\r\n failuresLast24h: number;\r\n /** Next scheduled execution */\r\n nextExecution?: string;\r\n}\r\n\r\n/**\r\n * Job handler function\r\n */\r\nexport type ScheduleHandler<T = unknown> = (\r\n job: ScheduledJob<T>,\r\n context: ScheduleContext\r\n) => Promise<void>;\r\n\r\n/**\r\n * Context passed to schedule handler\r\n */\r\nexport interface ScheduleContext {\r\n /** Execution ID */\r\n executionId: string;\r\n /** Schedule ID */\r\n scheduleId: string;\r\n /** Scheduled run time */\r\n scheduledAt: string;\r\n /** Actual run time */\r\n startedAt: string;\r\n /** Report progress */\r\n progress: (percent: number) => void;\r\n /** Log message */\r\n log: (message: string, level?: 'info' | 'warn' | 'error') => void;\r\n}\r\n\r\n/**\r\n * Scheduler configuration\r\n */\r\nexport interface SchedulerConfig {\r\n /** Default timezone for schedules */\r\n defaultTimezone?: string;\r\n /** Default max retries for failed jobs */\r\n defaultRetries?: number;\r\n /** Check interval for upcoming jobs (ms, default 60000) */\r\n checkInterval?: number;\r\n /** How far ahead to look for jobs (ms, default 300000) */\r\n lookAheadWindow?: number;\r\n /** Execution history retention (days, default 30) */\r\n historyRetentionDays?: number;\r\n /** Maximum concurrent executions */\r\n maxConcurrency?: number;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Scheduler Interface\r\n *\r\n * Provides job scheduling on top of queue infrastructure.\r\n */\r\nexport interface IScheduler {\r\n /**\r\n * Create a new schedule\r\n */\r\n create<T>(options: CreateScheduleOptions<T>): Promise<ScheduledJob<T>>;\r\n\r\n /**\r\n * Get a schedule by ID\r\n */\r\n get<T>(id: string): Promise<ScheduledJob<T> | null>;\r\n\r\n /**\r\n * Update an existing schedule\r\n */\r\n update<T>(id: string, options: UpdateScheduleOptions<T>): Promise<ScheduledJob<T>>;\r\n\r\n /**\r\n * Delete a schedule\r\n */\r\n delete(id: string): Promise<void>;\r\n\r\n /**\r\n * Pause a schedule (stop future executions)\r\n */\r\n pause(id: string): Promise<void>;\r\n\r\n /**\r\n * Resume a paused schedule\r\n */\r\n resume(id: string): Promise<void>;\r\n\r\n /**\r\n * Trigger immediate execution of a schedule\r\n */\r\n trigger(id: string): Promise<string>; // Returns execution ID\r\n\r\n /**\r\n * List schedules with optional filters\r\n */\r\n list<T>(query?: ScheduleQuery): Promise<ScheduledJob<T>[]>;\r\n\r\n /**\r\n * Get execution history for a schedule\r\n */\r\n getHistory(scheduleId: string, limit?: number): Promise<ScheduleExecution[]>;\r\n\r\n /**\r\n * Register a handler for schedules\r\n */\r\n handle<T>(name: string, handler: ScheduleHandler<T>): void;\r\n\r\n /**\r\n * Start the scheduler (begin processing)\r\n */\r\n start(): Promise<void>;\r\n\r\n /**\r\n * Stop the scheduler (stop processing)\r\n */\r\n stop(): Promise<void>;\r\n\r\n /**\r\n * Get scheduler statistics\r\n */\r\n getStats(): Promise<SchedulerStats>;\r\n\r\n /**\r\n * Health check\r\n */\r\n healthCheck(): Promise<boolean>;\r\n\r\n /**\r\n * Close and cleanup\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Generate schedule ID\r\n */\r\nexport function generateScheduleId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 8);\r\n return `sch_${timestamp}${random}`;\r\n}\r\n\r\n/**\r\n * Parse cron expression and get next run time\r\n * Simple implementation for common patterns\r\n */\r\nexport function getNextCronRun(cron: CronExpression, after: Date = new Date(), timezone?: string): Date | null {\r\n // This is a simplified cron parser\r\n // In production, use a library like 'cron-parser' or 'croner'\r\n const parts = cron.trim().split(/\\s+/);\r\n if (parts.length < 5 || parts.length > 6) {\r\n return null;\r\n }\r\n\r\n // For now, return next minute as placeholder\r\n // Real implementation would properly parse cron\r\n const next = new Date(after);\r\n next.setSeconds(0, 0);\r\n next.setMinutes(next.getMinutes() + 1);\r\n return next;\r\n}\r\n\r\n/**\r\n * Check if a cron expression is valid\r\n */\r\nexport function isValidCron(cron: CronExpression): boolean {\r\n const parts = cron.trim().split(/\\s+/);\r\n return parts.length >= 5 && parts.length <= 6;\r\n}\r\n\r\n/**\r\n * Common cron expressions\r\n */\r\nexport const CronPresets = {\r\n /** Every minute */\r\n everyMinute: '* * * * *',\r\n /** Every 5 minutes */\r\n every5Minutes: '*/5 * * * *',\r\n /** Every 15 minutes */\r\n every15Minutes: '*/15 * * * *',\r\n /** Every 30 minutes */\r\n every30Minutes: '*/30 * * * *',\r\n /** Every hour */\r\n hourly: '0 * * * *',\r\n /** Every day at midnight */\r\n daily: '0 0 * * *',\r\n /** Every day at 9 AM */\r\n dailyAt9AM: '0 9 * * *',\r\n /** Every Monday at 9 AM */\r\n weeklyMonday: '0 9 * * 1',\r\n /** First day of month at midnight */\r\n monthly: '0 0 1 * *',\r\n /** Every weekday at 9 AM */\r\n weekdays: '0 9 * * 1-5',\r\n /** Every weekend at 10 AM */\r\n weekends: '0 10 * * 0,6',\r\n} as const;\r\n\r\n/**\r\n * Describe a cron expression in human-readable format\r\n */\r\nexport function describeCron(cron: CronExpression): string {\r\n // Simple descriptions for common patterns\r\n const presetDescriptions: Record<string, string> = {\r\n '* * * * *': 'Every minute',\r\n '*/5 * * * *': 'Every 5 minutes',\r\n '*/15 * * * *': 'Every 15 minutes',\r\n '*/30 * * * *': 'Every 30 minutes',\r\n '0 * * * *': 'Every hour',\r\n '0 0 * * *': 'Every day at midnight',\r\n '0 9 * * *': 'Every day at 9:00 AM',\r\n '0 9 * * 1': 'Every Monday at 9:00 AM',\r\n '0 0 1 * *': 'First day of every month',\r\n '0 9 * * 1-5': 'Weekdays at 9:00 AM',\r\n '0 10 * * 0,6': 'Weekends at 10:00 AM',\r\n };\r\n\r\n return presetDescriptions[cron] ?? `Cron: ${cron}`;\r\n}\r\n","/**\r\n * Webhook Interface\r\n *\r\n * Platform abstraction for webhook management.\r\n * Self-hosted, no vendor lock-in.\r\n *\r\n * Supports both:\r\n * - Outbound webhooks (sending events to external systems)\r\n * - Inbound webhooks (receiving events from external systems)\r\n *\r\n * Features:\r\n * - Signature verification (HMAC-SHA256, etc.)\r\n * - Automatic retries with exponential backoff\r\n * - Event filtering\r\n * - Delivery tracking and history\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Webhook state\r\n */\r\nexport type WebhookState = 'active' | 'paused' | 'disabled' | 'failed';\r\n\r\n/**\r\n * Delivery status\r\n */\r\nexport type DeliveryStatus = 'pending' | 'success' | 'failed' | 'skipped';\r\n\r\n/**\r\n * Signature algorithm\r\n */\r\nexport type SignatureAlgorithm = 'sha256' | 'sha512' | 'sha1';\r\n\r\n/**\r\n * Registered webhook endpoint\r\n */\r\nexport interface WebhookEndpoint {\r\n /** Unique identifier */\r\n id: string;\r\n /** Human-readable name */\r\n name: string;\r\n /** Description */\r\n description?: string;\r\n /** Target URL for delivery */\r\n url: string;\r\n /** Secret for signature verification */\r\n secret: string;\r\n /** Signature algorithm */\r\n signatureAlgorithm: SignatureAlgorithm;\r\n /** Header name for signature */\r\n signatureHeader: string;\r\n /** Events this webhook subscribes to (glob patterns supported) */\r\n events: string[];\r\n /** Current state */\r\n state: WebhookState;\r\n /** Custom headers to include */\r\n headers?: Record<string, string>;\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n /** Tags for organization */\r\n tags?: string[];\r\n /** Created timestamp */\r\n createdAt: string;\r\n /** Last updated timestamp */\r\n updatedAt: string;\r\n /** Last delivery attempt */\r\n lastDeliveryAt?: string;\r\n /** Last successful delivery */\r\n lastSuccessAt?: string;\r\n /** Consecutive failures */\r\n failureCount: number;\r\n /** Total deliveries */\r\n totalDeliveries: number;\r\n /** Successful deliveries */\r\n successfulDeliveries: number;\r\n}\r\n\r\n/**\r\n * Webhook event to send\r\n */\r\nexport interface WebhookEvent<T = unknown> {\r\n /** Event type (e.g., 'user.created', 'order.completed') */\r\n type: string;\r\n /** Event payload */\r\n payload: T;\r\n /** Optional event ID (auto-generated if not provided) */\r\n id?: string;\r\n /** Timestamp (ISO 8601, auto-generated if not provided) */\r\n timestamp?: string;\r\n /** Correlation ID for tracing */\r\n correlationId?: string;\r\n /** Source of the event */\r\n source?: string;\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Delivery attempt record\r\n */\r\nexport interface DeliveryAttempt {\r\n /** Attempt ID */\r\n id: string;\r\n /** Webhook endpoint ID */\r\n endpointId: string;\r\n /** Event ID */\r\n eventId: string;\r\n /** Event type */\r\n eventType: string;\r\n /** Attempt number (1-based) */\r\n attemptNumber: number;\r\n /** Status */\r\n status: DeliveryStatus;\r\n /** HTTP status code */\r\n statusCode?: number;\r\n /** Response body (truncated) */\r\n responseBody?: string;\r\n /** Response headers */\r\n responseHeaders?: Record<string, string>;\r\n /** Request duration in ms */\r\n duration?: number;\r\n /** Error message if failed */\r\n error?: string;\r\n /** Timestamp */\r\n timestamp: string;\r\n /** Next retry timestamp (if scheduled) */\r\n nextRetryAt?: string;\r\n}\r\n\r\n/**\r\n * Delivery record\r\n */\r\nexport interface WebhookDelivery {\r\n /** Unique delivery ID */\r\n id: string;\r\n /** Webhook endpoint ID */\r\n endpointId: string;\r\n /** Event ID */\r\n eventId: string;\r\n /** Event type */\r\n eventType: string;\r\n /** Event payload (JSON string) */\r\n payload: string;\r\n /** Final status */\r\n status: DeliveryStatus;\r\n /** Total attempts */\r\n attempts: number;\r\n /** All attempt records */\r\n attemptHistory: DeliveryAttempt[];\r\n /** Created timestamp */\r\n createdAt: string;\r\n /** Completed timestamp */\r\n completedAt?: string;\r\n}\r\n\r\n/**\r\n * Options for creating a webhook endpoint\r\n */\r\nexport interface CreateWebhookOptions {\r\n /** Optional custom ID */\r\n id?: string;\r\n /** Human-readable name */\r\n name: string;\r\n /** Description */\r\n description?: string;\r\n /** Target URL */\r\n url: string;\r\n /** Secret for signatures (auto-generated if not provided) */\r\n secret?: string;\r\n /** Signature algorithm (default: sha256) */\r\n signatureAlgorithm?: SignatureAlgorithm;\r\n /** Signature header name (default: X-Webhook-Signature) */\r\n signatureHeader?: string;\r\n /** Events to subscribe to */\r\n events: string[];\r\n /** Custom headers */\r\n headers?: Record<string, string>;\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n /** Tags */\r\n tags?: string[];\r\n /** Start as paused */\r\n paused?: boolean;\r\n}\r\n\r\n/**\r\n * Options for updating a webhook endpoint\r\n */\r\nexport interface UpdateWebhookOptions {\r\n /** Name */\r\n name?: string;\r\n /** Description */\r\n description?: string;\r\n /** URL */\r\n url?: string;\r\n /** Rotate secret */\r\n rotateSecret?: boolean;\r\n /** Events */\r\n events?: string[];\r\n /** Headers */\r\n headers?: Record<string, string>;\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n /** Tags */\r\n tags?: string[];\r\n}\r\n\r\n/**\r\n * Query options for webhooks\r\n */\r\nexport interface WebhookQuery {\r\n /** Filter by state */\r\n state?: WebhookState | WebhookState[];\r\n /** Filter by events (match any) */\r\n events?: string[];\r\n /** Filter by tags (match any) */\r\n tags?: string[];\r\n /** Filter by name pattern */\r\n name?: string;\r\n /** Pagination offset */\r\n offset?: number;\r\n /** Pagination limit */\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Query options for deliveries\r\n */\r\nexport interface DeliveryQuery {\r\n /** Filter by endpoint ID */\r\n endpointId?: string;\r\n /** Filter by event type */\r\n eventType?: string;\r\n /** Filter by status */\r\n status?: DeliveryStatus | DeliveryStatus[];\r\n /** Filter by date range - from */\r\n from?: Date | string;\r\n /** Filter by date range - to */\r\n to?: Date | string;\r\n /** Pagination offset */\r\n offset?: number;\r\n /** Pagination limit */\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Webhook statistics\r\n */\r\nexport interface WebhookStats {\r\n /** Total endpoints */\r\n totalEndpoints: number;\r\n /** Active endpoints */\r\n activeEndpoints: number;\r\n /** Paused endpoints */\r\n pausedEndpoints: number;\r\n /** Failed endpoints (in failure state) */\r\n failedEndpoints: number;\r\n /** Deliveries in last 24h */\r\n deliveriesLast24h: number;\r\n /** Successful deliveries in last 24h */\r\n successLast24h: number;\r\n /** Failed deliveries in last 24h */\r\n failuresLast24h: number;\r\n /** Average delivery time in ms */\r\n avgDeliveryTime: number;\r\n}\r\n\r\n/**\r\n * Inbound webhook verification result\r\n */\r\nexport interface VerificationResult {\r\n /** Whether signature is valid */\r\n valid: boolean;\r\n /** Parsed payload if valid */\r\n payload?: unknown;\r\n /** Error message if invalid */\r\n error?: string;\r\n}\r\n\r\n/**\r\n * Inbound webhook handler context\r\n */\r\nexport interface InboundWebhookContext {\r\n /** Raw body */\r\n rawBody: string | Buffer;\r\n /** Signature header value */\r\n signature: string;\r\n /** Request headers */\r\n headers: Record<string, string>;\r\n /** Request method */\r\n method: string;\r\n /** Request path */\r\n path: string;\r\n /** Query params */\r\n query?: Record<string, string>;\r\n /** Timestamp header if present */\r\n timestamp?: string;\r\n}\r\n\r\n/**\r\n * Inbound webhook configuration\r\n */\r\nexport interface InboundWebhookConfig {\r\n /** Webhook name/identifier */\r\n name: string;\r\n /** Secret for verification */\r\n secret: string;\r\n /** Signature algorithm */\r\n signatureAlgorithm?: SignatureAlgorithm;\r\n /** Signature header name */\r\n signatureHeader?: string;\r\n /** Timestamp header name (for replay prevention) */\r\n timestampHeader?: string;\r\n /** Max age for timestamp validation (seconds) */\r\n timestampTolerance?: number;\r\n}\r\n\r\n/**\r\n * Webhook configuration\r\n */\r\nexport interface WebhookConfig {\r\n /** Max retry attempts */\r\n maxRetries?: number;\r\n /** Initial retry delay in ms */\r\n retryDelayMs?: number;\r\n /** Max retry delay in ms */\r\n maxRetryDelayMs?: number;\r\n /** Backoff multiplier */\r\n backoffMultiplier?: number;\r\n /** Request timeout in ms */\r\n timeoutMs?: number;\r\n /** Max concurrent deliveries */\r\n maxConcurrent?: number;\r\n /** Failure threshold before disabling webhook */\r\n failureThreshold?: number;\r\n /** Delivery history retention in days */\r\n historyRetentionDays?: number;\r\n /** User agent header */\r\n userAgent?: string;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Webhook manager interface\r\n */\r\nexport interface IWebhook {\r\n // ─────────────────────────────────────────────────────────────\r\n // Endpoint Management\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Create a new webhook endpoint\r\n */\r\n create(options: CreateWebhookOptions): Promise<WebhookEndpoint>;\r\n\r\n /**\r\n * Get a webhook endpoint by ID\r\n */\r\n get(id: string): Promise<WebhookEndpoint | null>;\r\n\r\n /**\r\n * Update a webhook endpoint\r\n */\r\n update(id: string, options: UpdateWebhookOptions): Promise<WebhookEndpoint>;\r\n\r\n /**\r\n * Delete a webhook endpoint\r\n */\r\n delete(id: string): Promise<void>;\r\n\r\n /**\r\n * List webhook endpoints\r\n */\r\n list(query?: WebhookQuery): Promise<WebhookEndpoint[]>;\r\n\r\n /**\r\n * Pause a webhook endpoint\r\n */\r\n pause(id: string): Promise<void>;\r\n\r\n /**\r\n * Resume a paused webhook endpoint\r\n */\r\n resume(id: string): Promise<void>;\r\n\r\n /**\r\n * Test a webhook endpoint with a test payload\r\n */\r\n test(id: string): Promise<DeliveryAttempt>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Event Delivery (Outbound)\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Dispatch an event to all matching webhooks\r\n * Returns number of deliveries queued\r\n */\r\n dispatch<T>(event: WebhookEvent<T>): Promise<string[]>;\r\n\r\n /**\r\n * Dispatch to a specific endpoint\r\n */\r\n dispatchTo<T>(endpointId: string, event: WebhookEvent<T>): Promise<string>;\r\n\r\n /**\r\n * Retry a failed delivery\r\n */\r\n retry(deliveryId: string): Promise<DeliveryAttempt>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Delivery History\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get a delivery by ID\r\n */\r\n getDelivery(id: string): Promise<WebhookDelivery | null>;\r\n\r\n /**\r\n * List deliveries\r\n */\r\n listDeliveries(query?: DeliveryQuery): Promise<WebhookDelivery[]>;\r\n\r\n /**\r\n * Get delivery attempts for a delivery\r\n */\r\n getAttempts(deliveryId: string): Promise<DeliveryAttempt[]>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Inbound Webhooks\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Register an inbound webhook configuration\r\n */\r\n registerInbound(config: InboundWebhookConfig): void;\r\n\r\n /**\r\n * Verify an incoming webhook request\r\n */\r\n verify(name: string, context: InboundWebhookContext): VerificationResult;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Statistics\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get webhook statistics\r\n */\r\n getStats(): Promise<WebhookStats>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Lifecycle\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Health check\r\n */\r\n healthCheck(): Promise<boolean>;\r\n\r\n /**\r\n * Close and cleanup resources\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Generate a webhook ID\r\n */\r\nexport function generateWebhookId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `wh_${timestamp}${random}`;\r\n}\r\n\r\n/**\r\n * Generate a delivery ID\r\n */\r\nexport function generateDeliveryId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `del_${timestamp}${random}`;\r\n}\r\n\r\n/**\r\n * Generate an event ID\r\n */\r\nexport function generateEventId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `evt_${timestamp}${random}`;\r\n}\r\n\r\n/**\r\n * Generate a webhook secret\r\n */\r\nexport function generateWebhookSecret(length = 32): string {\r\n const chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';\r\n let secret = 'whsec_';\r\n for (let i = 0; i < length; i++) {\r\n secret += chars.charAt(Math.floor(Math.random() * chars.length));\r\n }\r\n return secret;\r\n}\r\n\r\n/**\r\n * Check if event type matches a pattern\r\n * Supports wildcards: *, **\r\n * - * matches single segment: 'user.*' matches 'user.created' but not 'user.profile.updated'\r\n * - ** matches all segments: 'user.**' matches 'user.created' and 'user.profile.updated'\r\n */\r\nexport function matchEventType(eventType: string, pattern: string): boolean {\r\n // Exact match\r\n if (eventType === pattern || pattern === '*' || pattern === '**') {\r\n return true;\r\n }\r\n\r\n const eventParts = eventType.split('.');\r\n const patternParts = pattern.split('.');\r\n\r\n let ei = 0;\r\n let pi = 0;\r\n\r\n while (ei < eventParts.length && pi < patternParts.length) {\r\n const part = patternParts[pi];\r\n\r\n if (part === '**') {\r\n // ** matches zero or more segments\r\n if (pi === patternParts.length - 1) {\r\n // ** at end matches everything\r\n return true;\r\n }\r\n // Try to match the rest\r\n const nextPattern = patternParts.slice(pi + 1).join('.');\r\n for (let i = ei; i <= eventParts.length; i++) {\r\n const remaining = eventParts.slice(i).join('.');\r\n if (matchEventType(remaining, nextPattern)) {\r\n return true;\r\n }\r\n }\r\n return false;\r\n }\r\n\r\n if (part === '*') {\r\n // * matches exactly one segment\r\n ei++;\r\n pi++;\r\n continue;\r\n }\r\n\r\n if (part !== eventParts[ei]) {\r\n return false;\r\n }\r\n\r\n ei++;\r\n pi++;\r\n }\r\n\r\n return ei === eventParts.length && pi === patternParts.length;\r\n}\r\n\r\n/**\r\n * Calculate next retry delay with exponential backoff\r\n */\r\nexport function calculateRetryDelay(\r\n attempt: number,\r\n initialDelay = 1000,\r\n maxDelay = 3600000, // 1 hour\r\n multiplier = 2\r\n): number {\r\n const delay = initialDelay * Math.pow(multiplier, attempt - 1);\r\n // Add jitter (±25%)\r\n const jitter = delay * 0.25 * (Math.random() * 2 - 1);\r\n return Math.min(delay + jitter, maxDelay);\r\n}\r\n\r\n/**\r\n * Common event type patterns\r\n */\r\nexport const WebhookEventTypes = {\r\n // User events\r\n USER_CREATED: 'user.created',\r\n USER_UPDATED: 'user.updated',\r\n USER_DELETED: 'user.deleted',\r\n USER_LOGIN: 'user.login',\r\n USER_LOGOUT: 'user.logout',\r\n\r\n // Subscription events\r\n SUBSCRIPTION_CREATED: 'subscription.created',\r\n SUBSCRIPTION_UPDATED: 'subscription.updated',\r\n SUBSCRIPTION_CANCELLED: 'subscription.cancelled',\r\n SUBSCRIPTION_RENEWED: 'subscription.renewed',\r\n\r\n // Payment events\r\n PAYMENT_SUCCEEDED: 'payment.succeeded',\r\n PAYMENT_FAILED: 'payment.failed',\r\n PAYMENT_REFUNDED: 'payment.refunded',\r\n\r\n // Invoice events\r\n INVOICE_CREATED: 'invoice.created',\r\n INVOICE_PAID: 'invoice.paid',\r\n INVOICE_FAILED: 'invoice.failed',\r\n\r\n // Order events\r\n ORDER_CREATED: 'order.created',\r\n ORDER_UPDATED: 'order.updated',\r\n ORDER_COMPLETED: 'order.completed',\r\n ORDER_CANCELLED: 'order.cancelled',\r\n\r\n // Patterns for subscriptions\r\n ALL: '**',\r\n ALL_USER: 'user.**',\r\n ALL_PAYMENT: 'payment.**',\r\n ALL_SUBSCRIPTION: 'subscription.**',\r\n ALL_ORDER: 'order.**',\r\n} as const;\r\n","/**\r\n * Notification Interface\r\n *\r\n * Multi-channel notification system with self-hosted options.\r\n * Supports in-app, email, push, and SMS notifications.\r\n *\r\n * Channels:\r\n * - in_app: Stored in database, fetched by clients\r\n * - email: Uses IEmail adapter\r\n * - push: Web Push Protocol (no external service)\r\n * - sms: Via SMTP gateway or direct carrier API\r\n *\r\n * Design Principles:\r\n * - Self-hosted by default\r\n * - No vendor lock-in\r\n * - Multi-channel delivery\r\n * - User preferences respected\r\n */\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Notification channels\r\n */\r\nexport type NotificationChannel = 'in_app' | 'email' | 'push' | 'sms';\r\n\r\n/**\r\n * Notification priority\r\n */\r\nexport type NotificationPriority = 'low' | 'normal' | 'high' | 'urgent';\r\n\r\n/**\r\n * Notification status\r\n */\r\nexport type NotificationStatus = 'pending' | 'sent' | 'delivered' | 'read' | 'failed';\r\n\r\n/**\r\n * Notification category for filtering and preferences\r\n */\r\nexport type NotificationCategory =\r\n | 'system'\r\n | 'security'\r\n | 'account'\r\n | 'billing'\r\n | 'marketing'\r\n | 'social'\r\n | 'updates'\r\n | 'alerts'\r\n | string;\r\n\r\n/**\r\n * Notification template data\r\n */\r\nexport interface NotificationData {\r\n /** Notification title */\r\n title: string;\r\n /** Notification body/message */\r\n body: string;\r\n /** Category for filtering */\r\n category?: NotificationCategory;\r\n /** Priority level */\r\n priority?: NotificationPriority;\r\n /** URL to link to */\r\n url?: string;\r\n /** Icon URL */\r\n icon?: string;\r\n /** Image URL for rich notifications */\r\n image?: string;\r\n /** Action buttons */\r\n actions?: NotificationAction[];\r\n /** Custom data payload */\r\n data?: Record<string, unknown>;\r\n /** Time to live in seconds (default: 86400 = 24 hours) */\r\n ttl?: number;\r\n /** Collapse key for grouping */\r\n collapseKey?: string;\r\n /** Sound to play */\r\n sound?: string;\r\n /** Badge count */\r\n badge?: number;\r\n /** Tags for filtering */\r\n tags?: string[];\r\n}\r\n\r\n/**\r\n * Action button for notifications\r\n */\r\nexport interface NotificationAction {\r\n /** Action identifier */\r\n action: string;\r\n /** Display title */\r\n title: string;\r\n /** Icon URL */\r\n icon?: string;\r\n /** URL to open */\r\n url?: string;\r\n}\r\n\r\n/**\r\n * Target for notification delivery\r\n */\r\nexport interface NotificationTarget {\r\n /** User ID */\r\n userId?: string;\r\n /** User email */\r\n email?: string;\r\n /** Phone number for SMS */\r\n phone?: string;\r\n /** Push subscription for web push */\r\n pushSubscription?: PushSubscription;\r\n /** Device token for mobile push */\r\n deviceToken?: string;\r\n /** Custom data */\r\n data?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Web Push subscription (standard format)\r\n */\r\nexport interface PushSubscription {\r\n /** Push endpoint URL */\r\n endpoint: string;\r\n /** Expiration time */\r\n expirationTime?: number | null;\r\n /** Keys for encryption */\r\n keys: {\r\n /** P-256 key */\r\n p256dh: string;\r\n /** Auth secret */\r\n auth: string;\r\n };\r\n}\r\n\r\n/**\r\n * Stored notification record\r\n */\r\nexport interface StoredNotification {\r\n /** Unique notification ID */\r\n id: string;\r\n /** User ID */\r\n userId: string;\r\n /** Notification data */\r\n data: NotificationData;\r\n /** Channels sent to */\r\n channels: NotificationChannel[];\r\n /** Status per channel */\r\n status: Partial<Record<NotificationChannel, NotificationStatus>>;\r\n /** Created timestamp */\r\n createdAt: string;\r\n /** Read timestamp */\r\n readAt?: string;\r\n /** Metadata */\r\n metadata?: Record<string, unknown>;\r\n}\r\n\r\n/**\r\n * Options for sending notifications\r\n */\r\nexport interface SendNotificationOptions {\r\n /** Target user/device */\r\n target: NotificationTarget;\r\n /** Notification data */\r\n notification: NotificationData;\r\n /** Channels to send to (default: based on user preferences) */\r\n channels?: NotificationChannel[];\r\n /** Override user preferences */\r\n force?: boolean;\r\n /** Schedule for later delivery */\r\n scheduledFor?: Date | string;\r\n /** Idempotency key */\r\n idempotencyKey?: string;\r\n}\r\n\r\n/**\r\n * Options for batch notifications\r\n */\r\nexport interface BatchNotificationOptions {\r\n /** Target users */\r\n targets: NotificationTarget[];\r\n /** Notification data */\r\n notification: NotificationData;\r\n /** Channels to send to */\r\n channels?: NotificationChannel[];\r\n /** Max concurrent sends */\r\n concurrency?: number;\r\n}\r\n\r\n/**\r\n * User notification preferences\r\n */\r\nexport interface NotificationPreferences {\r\n /** User ID */\r\n userId: string;\r\n /** Enabled channels */\r\n enabledChannels: NotificationChannel[];\r\n /** Per-category preferences */\r\n categories: Partial<Record<NotificationCategory, {\r\n enabled: boolean;\r\n channels: NotificationChannel[];\r\n }>>;\r\n /** Quiet hours (no notifications) */\r\n quietHours?: {\r\n enabled: boolean;\r\n start: string; // HH:MM format\r\n end: string; // HH:MM format\r\n timezone: string;\r\n };\r\n /** Email preferences */\r\n email?: {\r\n digest: boolean;\r\n digestFrequency: 'daily' | 'weekly' | 'never';\r\n };\r\n}\r\n\r\n/**\r\n * Query options for notifications\r\n */\r\nexport interface NotificationQuery {\r\n /** Filter by user ID */\r\n userId?: string;\r\n /** Filter by category */\r\n category?: NotificationCategory | NotificationCategory[];\r\n /** Filter by status */\r\n status?: NotificationStatus | NotificationStatus[];\r\n /** Filter by read status */\r\n unreadOnly?: boolean;\r\n /** Filter by date range */\r\n from?: Date | string;\r\n to?: Date | string;\r\n /** Pagination */\r\n offset?: number;\r\n limit?: number;\r\n}\r\n\r\n/**\r\n * Notification result\r\n */\r\nexport interface NotificationResult {\r\n /** Notification ID */\r\n id: string;\r\n /** Success per channel */\r\n results: Partial<Record<NotificationChannel, {\r\n success: boolean;\r\n messageId?: string;\r\n error?: string;\r\n }>>;\r\n}\r\n\r\n/**\r\n * Notification statistics\r\n */\r\nexport interface NotificationStats {\r\n /** Total notifications sent */\r\n totalSent: number;\r\n /** Per channel stats */\r\n byChannel: Partial<Record<NotificationChannel, {\r\n sent: number;\r\n delivered: number;\r\n read: number;\r\n failed: number;\r\n }>>;\r\n /** Per category stats */\r\n byCategory: Partial<Record<NotificationCategory, number>>;\r\n /** Unread count */\r\n unreadCount: number;\r\n}\r\n\r\n/**\r\n * Notification configuration\r\n */\r\nexport interface NotificationConfig {\r\n /** Default channels */\r\n defaultChannels?: NotificationChannel[];\r\n /** Default TTL in seconds */\r\n defaultTtl?: number;\r\n /** Web Push VAPID keys */\r\n vapidKeys?: {\r\n publicKey: string;\r\n privateKey: string;\r\n subject: string;\r\n };\r\n /** SMS gateway configuration */\r\n smsGateway?: {\r\n type: 'smtp' | 'twilio' | 'custom';\r\n config: Record<string, unknown>;\r\n };\r\n /** Batch size for bulk sends */\r\n batchSize?: number;\r\n /** Rate limits per channel */\r\n rateLimits?: Partial<Record<NotificationChannel, {\r\n perSecond?: number;\r\n perMinute?: number;\r\n perHour?: number;\r\n }>>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// INTERFACE\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Notification service interface\r\n */\r\nexport interface INotification {\r\n // ─────────────────────────────────────────────────────────────\r\n // Sending\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Send a notification to a user\r\n */\r\n send(options: SendNotificationOptions): Promise<NotificationResult>;\r\n\r\n /**\r\n * Send notifications to multiple users\r\n */\r\n sendBatch(options: BatchNotificationOptions): Promise<NotificationResult[]>;\r\n\r\n /**\r\n * Send to a topic/segment (all subscribed users)\r\n */\r\n sendToTopic(topic: string, notification: NotificationData): Promise<number>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // In-App Notifications\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get notifications for a user\r\n */\r\n getForUser(userId: string, query?: NotificationQuery): Promise<StoredNotification[]>;\r\n\r\n /**\r\n * Get unread count for a user\r\n */\r\n getUnreadCount(userId: string, category?: NotificationCategory): Promise<number>;\r\n\r\n /**\r\n * Mark notification as read\r\n */\r\n markAsRead(notificationId: string): Promise<void>;\r\n\r\n /**\r\n * Mark all notifications as read for a user\r\n */\r\n markAllAsRead(userId: string, category?: NotificationCategory): Promise<number>;\r\n\r\n /**\r\n * Delete a notification\r\n */\r\n delete(notificationId: string): Promise<void>;\r\n\r\n /**\r\n * Delete all notifications for a user\r\n */\r\n deleteAllForUser(userId: string): Promise<number>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Push Subscriptions\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Register a push subscription\r\n */\r\n registerPushSubscription(userId: string, subscription: PushSubscription): Promise<void>;\r\n\r\n /**\r\n * Remove a push subscription\r\n */\r\n removePushSubscription(userId: string, endpoint: string): Promise<void>;\r\n\r\n /**\r\n * Get push subscriptions for a user\r\n */\r\n getPushSubscriptions(userId: string): Promise<PushSubscription[]>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // User Preferences\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get user notification preferences\r\n */\r\n getPreferences(userId: string): Promise<NotificationPreferences>;\r\n\r\n /**\r\n * Update user notification preferences\r\n */\r\n updatePreferences(userId: string, preferences: Partial<NotificationPreferences>): Promise<void>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Topics/Segments\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Subscribe user to a topic\r\n */\r\n subscribeToTopic(userId: string, topic: string): Promise<void>;\r\n\r\n /**\r\n * Unsubscribe user from a topic\r\n */\r\n unsubscribeFromTopic(userId: string, topic: string): Promise<void>;\r\n\r\n /**\r\n * Get user's subscribed topics\r\n */\r\n getUserTopics(userId: string): Promise<string[]>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Statistics\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Get notification statistics\r\n */\r\n getStats(options?: { userId?: string; period?: 'day' | 'week' | 'month' }): Promise<NotificationStats>;\r\n\r\n // ─────────────────────────────────────────────────────────────\r\n // Lifecycle\r\n // ─────────────────────────────────────────────────────────────\r\n\r\n /**\r\n * Health check\r\n */\r\n healthCheck(): Promise<boolean>;\r\n\r\n /**\r\n * Close and cleanup\r\n */\r\n close(): Promise<void>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Generate notification ID\r\n */\r\nexport function generateNotificationId(): string {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `notif_${timestamp}${random}`;\r\n}\r\n\r\n/**\r\n * Check if notification is within quiet hours\r\n */\r\nexport function isInQuietHours(preferences: NotificationPreferences): boolean {\r\n if (!preferences.quietHours?.enabled) return false;\r\n\r\n const { start, end, timezone } = preferences.quietHours;\r\n const now = new Date();\r\n\r\n // Parse HH:MM format\r\n const [startH, startM] = start.split(':').map(Number);\r\n const [endH, endM] = end.split(':').map(Number);\r\n\r\n // Get current hour/minute in user's timezone\r\n const formatter = new Intl.DateTimeFormat('en-US', {\r\n timeZone: timezone,\r\n hour: 'numeric',\r\n minute: 'numeric',\r\n hour12: false,\r\n });\r\n const parts = formatter.formatToParts(now);\r\n const currentH = parseInt(parts.find(p => p.type === 'hour')?.value ?? '0', 10);\r\n const currentM = parseInt(parts.find(p => p.type === 'minute')?.value ?? '0', 10);\r\n\r\n const currentMinutes = currentH * 60 + currentM;\r\n const startMinutes = (startH ?? 0) * 60 + (startM ?? 0);\r\n const endMinutes = (endH ?? 0) * 60 + (endM ?? 0);\r\n\r\n // Handle overnight quiet hours (e.g., 22:00 - 07:00)\r\n if (startMinutes > endMinutes) {\r\n return currentMinutes >= startMinutes || currentMinutes < endMinutes;\r\n }\r\n\r\n return currentMinutes >= startMinutes && currentMinutes < endMinutes;\r\n}\r\n\r\n/**\r\n * Default preferences factory\r\n */\r\nexport function createDefaultPreferences(userId: string): NotificationPreferences {\r\n return {\r\n userId,\r\n enabledChannels: ['in_app', 'email'],\r\n categories: {\r\n system: { enabled: true, channels: ['in_app', 'email'] },\r\n security: { enabled: true, channels: ['in_app', 'email', 'push'] },\r\n account: { enabled: true, channels: ['in_app', 'email'] },\r\n billing: { enabled: true, channels: ['in_app', 'email'] },\r\n marketing: { enabled: false, channels: ['email'] },\r\n social: { enabled: true, channels: ['in_app', 'push'] },\r\n updates: { enabled: true, channels: ['in_app'] },\r\n alerts: { enabled: true, channels: ['in_app', 'email', 'push'] },\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Filter channels based on user preferences\r\n */\r\nexport function filterChannelsByPreferences(\r\n requestedChannels: NotificationChannel[],\r\n preferences: NotificationPreferences,\r\n category?: NotificationCategory,\r\n force?: boolean\r\n): NotificationChannel[] {\r\n if (force) return requestedChannels;\r\n\r\n // Check quiet hours\r\n if (isInQuietHours(preferences)) {\r\n // Only allow in_app during quiet hours\r\n return requestedChannels.filter(c => c === 'in_app');\r\n }\r\n\r\n // Filter by enabled channels\r\n let channels = requestedChannels.filter(c => preferences.enabledChannels.includes(c));\r\n\r\n // Further filter by category preferences\r\n if (category && preferences.categories[category]) {\r\n const catPref = preferences.categories[category];\r\n if (!catPref?.enabled) {\r\n return [];\r\n }\r\n channels = channels.filter(c => catPref.channels.includes(c));\r\n }\r\n\r\n return channels;\r\n}\r\n\r\n/**\r\n * Common notification templates\r\n */\r\nexport const NotificationTemplates = {\r\n welcome: (name: string): NotificationData => ({\r\n title: 'Welcome!',\r\n body: `Hi ${name}, welcome to our platform! We're excited to have you.`,\r\n category: 'account',\r\n priority: 'normal',\r\n }),\r\n\r\n passwordChanged: (): NotificationData => ({\r\n title: 'Password Changed',\r\n body: 'Your password has been successfully changed. If you did not make this change, please contact support immediately.',\r\n category: 'security',\r\n priority: 'high',\r\n }),\r\n\r\n newLogin: (location?: string): NotificationData => ({\r\n title: 'New Login Detected',\r\n body: location\r\n ? `A new login was detected from ${location}. If this wasn't you, please secure your account.`\r\n : 'A new login was detected on your account. If this wasn\\'t you, please secure your account.',\r\n category: 'security',\r\n priority: 'high',\r\n }),\r\n\r\n paymentSucceeded: (amount: string): NotificationData => ({\r\n title: 'Payment Successful',\r\n body: `Your payment of ${amount} has been processed successfully.`,\r\n category: 'billing',\r\n priority: 'normal',\r\n }),\r\n\r\n paymentFailed: (reason?: string): NotificationData => ({\r\n title: 'Payment Failed',\r\n body: reason\r\n ? `Your payment could not be processed: ${reason}`\r\n : 'Your payment could not be processed. Please update your payment method.',\r\n category: 'billing',\r\n priority: 'high',\r\n }),\r\n\r\n subscriptionExpiring: (daysLeft: number): NotificationData => ({\r\n title: 'Subscription Expiring Soon',\r\n body: `Your subscription will expire in ${daysLeft} day${daysLeft > 1 ? 's' : ''}. Renew now to avoid interruption.`,\r\n category: 'billing',\r\n priority: 'normal',\r\n }),\r\n} as const;\r\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(['memory', 'postgres', 'supabase']);\nexport const CacheProviderSchema = z.enum(['memory', 'redis', 'upstash']);\nexport const StorageProviderSchema = z.enum(['memory', 's3', 'minio', 'r2', 'supabase']);\nexport const EmailProviderSchema = z.enum(['memory', 'console', 'smtp', 'resend']);\nexport const QueueProviderSchema = z.enum(['memory', 'bullmq']);\nexport const TracingProviderSchema = z.enum(['noop', 'memory', 'otlp']);\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error']);\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.string().optional().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.string().optional().describe('Supabase service role key'),\n poolSize: z.number().int().min(1).max(100).default(10).describe('Connection pool size'),\n connectionTimeout: z.number().int().min(1000).max(60000).default(5000).describe('Connection timeout in ms'),\n ssl: z.union([z.boolean(), z.object({ rejectUnauthorized: z.boolean().optional() })]).optional().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: '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.number().int().min(0).default(3600).describe('Default TTL in seconds'),\n keyPrefix: z.string().default('').describe('Prefix for all cache keys'),\n maxRetries: z.number().int().min(0).max(10).default(3).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: '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.string().url().optional().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.string().url().optional().describe('Public URL for accessing files'),\n forcePathStyle: z.boolean().default(false).describe('Use path-style URLs (required for MinIO)'),\n signedUrlExpiry: z.number().int().min(60).max(604800).default(3600).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.number().int().min(1).max(100).default(10).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.string().url().optional().describe('Redis connection URL for BullMQ'),\n queueName: z.string().default('platform-jobs').describe('Default queue name'),\n concurrency: z.number().int().min(1).max(100).default(5).describe('Worker concurrency'),\n maxRetries: z.number().int().min(0).max(10).default(3).describe('Max job retries'),\n retryDelay: z.number().int().min(0).default(1000).describe('Retry delay in ms'),\n removeOnComplete: z.boolean().default(true).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\n// ═══════════════════════════════════════════════════════════════\n// RESILIENCE CONFIGURATION SCHEMAS\n// ═══════════════════════════════════════════════════════════════\n\nexport const RetryConfigSchema = z.object({\n enabled: z.boolean().default(true).describe('Enable retry for failed operations'),\n maxAttempts: z.number().int().min(1).max(10).default(3).describe('Maximum retry attempts'),\n baseDelay: z.number().int().min(0).max(10000).default(100).describe('Base delay in ms'),\n maxDelay: z.number().int().min(0).max(60000).default(5000).describe('Maximum delay in ms'),\n backoffMultiplier: z.number().min(1).max(5).default(2).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.number().int().min(1).max(100).default(5).describe('Failures before opening circuit'),\n resetTimeout: z.number().int().min(1000).max(300000).default(30000).describe('Reset timeout in ms'),\n halfOpenRequests: z.number().int().min(1).max(10).default(3).describe('Requests allowed in half-open state'),\n monitorInterval: z.number().int().min(1000).max(60000).default(10000).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.number().int().min(100).max(300000).default(30000).describe('Default timeout in ms'),\n database: z.number().int().min(100).max(300000).default(10000).describe('Database operation timeout'),\n cache: z.number().int().min(100).max(60000).default(5000).describe('Cache operation timeout'),\n storage: z.number().int().min(100).max(600000).default(60000).describe('Storage operation timeout'),\n email: z.number().int().min(100).max(120000).default(30000).describe('Email operation timeout'),\n queue: z.number().int().min(100).max(60000).default(10000).describe('Queue operation timeout'),\n});\n\nexport const BulkheadConfigSchema = z.object({\n enabled: z.boolean().default(false).describe('Enable bulkhead isolation'),\n maxConcurrent: z.number().int().min(1).max(1000).default(10).describe('Maximum concurrent operations'),\n maxQueued: z.number().int().min(0).max(10000).default(100).describe('Maximum queued operations'),\n timeout: z.number().int().min(0).max(300000).default(30000).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.enum(['json', 'pretty']).default('json').describe('Log output format'),\n includeTimestamp: z.boolean().default(true).describe('Include timestamp in logs'),\n includeCorrelationId: z.boolean().default(true).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.record(z.string()).default({}).describe('Default tags for all metrics'),\n flushInterval: z.number().int().min(1000).max(60000).default(10000).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.string().optional().describe('Environment (dev, staging, production)'),\n sampleRate: z.number().min(0).max(1).default(1).describe('Trace sampling rate'),\n propagateContext: z.boolean().default(true).describe('Propagate trace context to downstream services'),\n endpoint: z.string().url().optional().describe('OTLP exporter endpoint'),\n exporterType: z.enum(['otlp-http', 'otlp-grpc', 'console']).default('otlp-http').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 // 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 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>;\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: process.env.PLATFORM_DB_PROVIDER || process.env.DATABASE_PROVIDER || '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 ? parseInt(process.env.DATABASE_POOL_SIZE) : undefined,\n connectionTimeout: process.env.DATABASE_TIMEOUT ? parseInt(process.env.DATABASE_TIMEOUT) : undefined,\n },\n cache: {\n provider: process.env.PLATFORM_CACHE_PROVIDER || process.env.CACHE_PROVIDER || '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 ? parseInt(process.env.CACHE_DEFAULT_TTL) : undefined,\n keyPrefix: process.env.CACHE_KEY_PREFIX,\n },\n storage: {\n provider: process.env.PLATFORM_STORAGE_PROVIDER || process.env.STORAGE_PROVIDER || '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: 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 ? parseInt(process.env.S3_SIGNED_URL_EXPIRY) : undefined,\n },\n email: {\n provider: process.env.PLATFORM_EMAIL_PROVIDER || process.env.EMAIL_PROVIDER || '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: process.env.PLATFORM_QUEUE_PROVIDER || process.env.QUEUE_PROVIDER || 'memory',\n redisUrl: process.env.REDIS_URL,\n queueName: process.env.QUEUE_NAME,\n concurrency: process.env.QUEUE_CONCURRENCY ? parseInt(process.env.QUEUE_CONCURRENCY) : undefined,\n maxRetries: process.env.QUEUE_MAX_RETRIES ? parseInt(process.env.QUEUE_MAX_RETRIES) : undefined,\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: (process.env.LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error') || '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: (process.env.TRACING_PROVIDER as 'noop' | 'memory' | 'otlp') || '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 ? parseFloat(process.env.TRACING_SAMPLE_RATE) : undefined,\n endpoint: process.env.OTEL_EXPORTER_OTLP_ENDPOINT || process.env.TRACING_ENDPOINT,\n exporterType: (process.env.OTEL_EXPORTER_TYPE as 'otlp-http' | 'otlp-grpc' | '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 * Memory Database Adapter\n * In-memory implementation for testing\n */\n\nimport { IDatabase, IQueryBuilder, QueryResult } 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>(sql: string, params?: unknown[]): 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 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 = { ...item, ...this._updateData, updated_at: new Date().toISOString() };\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 string | number | null;\n const bVal = (b as Record<string, unknown>)[column] as string | number | null;\n if (aVal === null || aVal === undefined) return direction === 'asc' ? 1 : -1;\n if (bVal === null || bVal === undefined) 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>> = 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>(entries: Array<{ key: string; value: T; ttl?: number }>): Promise<void> {\n await Promise.all(entries.map(({ key, value, ttl }) => this.set(key, value, ttl)));\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(channel: string, callback: (message: string) => void): 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 { IStorage, StorageFile, UploadOptions } from \"../../interfaces/IStorage\";\n\nexport class MemoryStorage implements IStorage {\n private files = new Map<string, { data: Buffer; contentType?: string }>();\n \n async upload(key: string, data: Buffer | Blob | ReadableStream, options?: UploadOptions) { \n this.files.set(key, { data: Buffer.from(\"mock\"), contentType: options?.contentType }); \n return { url: \"memory://\" + key }; \n }\n async download(key: string) { return this.files.get(key)?.data || Buffer.from(\"\"); }\n async getSignedUrl(key: string) { return \"memory://\" + key; }\n async delete(key: string) { this.files.delete(key); }\n async deleteMany(keys: string[]) { keys.forEach(k => this.files.delete(k)); }\n async list(prefix?: string): Promise<StorageFile[]> { return []; }\n async exists(key: string) { return this.files.has(key); }\n async getMetadata(key: string) { return null; }\n async healthCheck() { return true; }\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() { return true; }\n \n // Test helpers\n getSentEmails(): EmailMessage[] { return this.sentEmails; }\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","/**\r\n * Correlation Context using AsyncLocalStorage\r\n *\r\n * Provides automatic propagation of trace/correlation IDs and request context\r\n * across async operations without explicit passing.\r\n *\r\n * Design Principles:\r\n * - Zero external dependencies (uses Node.js built-in AsyncLocalStorage)\r\n * - Self-hosted compatible\r\n * - Integrates with logging, metrics, and tracing\r\n */\r\n\r\nimport { AsyncLocalStorage } from 'async_hooks';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CONTEXT TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface CorrelationData {\r\n /** Unique trace ID for distributed tracing */\r\n traceId?: string;\r\n /** Span ID for current operation */\r\n spanId?: string;\r\n /** Request ID for HTTP requests */\r\n requestId?: string;\r\n /** Correlation ID for job/event processing */\r\n correlationId?: string;\r\n /** User ID if authenticated */\r\n userId?: string;\r\n /** Tenant ID for multi-tenant applications */\r\n tenantId?: string;\r\n /** Session ID */\r\n sessionId?: string;\r\n /** Custom metadata */\r\n metadata?: Record<string, unknown>;\r\n /** Operation name (for logging) */\r\n operation?: string;\r\n /** Start time of the context */\r\n startTime?: number;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// CORRELATION CONTEXT CLASS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Singleton correlation context using AsyncLocalStorage\r\n */\r\nclass CorrelationContextManager {\r\n private storage = new AsyncLocalStorage<CorrelationData>();\r\n private idGenerator: () => string;\r\n\r\n constructor() {\r\n // Default ID generator (can be overridden)\r\n this.idGenerator = () => {\r\n const timestamp = Date.now().toString(36);\r\n const random = Math.random().toString(36).substring(2, 10);\r\n return `${timestamp}-${random}`;\r\n };\r\n }\r\n\r\n /**\r\n * Set custom ID generator\r\n */\r\n setIdGenerator(generator: () => string): void {\r\n this.idGenerator = generator;\r\n }\r\n\r\n /**\r\n * Generate a new ID\r\n */\r\n generateId(): string {\r\n return this.idGenerator();\r\n }\r\n\r\n /**\r\n * Run a function with correlation context\r\n */\r\n run<T>(data: CorrelationData, fn: () => T): T {\r\n return this.storage.run(\r\n {\r\n ...data,\r\n startTime: data.startTime ?? Date.now(),\r\n },\r\n fn\r\n );\r\n }\r\n\r\n /**\r\n * Run an async function with correlation context\r\n */\r\n async runAsync<T>(data: CorrelationData, fn: () => Promise<T>): Promise<T> {\r\n return this.storage.run(\r\n {\r\n ...data,\r\n startTime: data.startTime ?? Date.now(),\r\n },\r\n fn\r\n );\r\n }\r\n\r\n /**\r\n * Get current correlation data\r\n */\r\n get(): CorrelationData | undefined {\r\n return this.storage.getStore();\r\n }\r\n\r\n /**\r\n * Get current correlation data or empty object\r\n */\r\n getOrEmpty(): CorrelationData {\r\n return this.storage.getStore() ?? {};\r\n }\r\n\r\n /**\r\n * Get trace ID from current context\r\n */\r\n getTraceId(): string | undefined {\r\n return this.get()?.traceId;\r\n }\r\n\r\n /**\r\n * Get correlation ID from current context\r\n */\r\n getCorrelationId(): string | undefined {\r\n return this.get()?.correlationId ?? this.get()?.traceId;\r\n }\r\n\r\n /**\r\n * Get request ID from current context\r\n */\r\n getRequestId(): string | undefined {\r\n return this.get()?.requestId;\r\n }\r\n\r\n /**\r\n * Get user ID from current context\r\n */\r\n getUserId(): string | undefined {\r\n return this.get()?.userId;\r\n }\r\n\r\n /**\r\n * Get tenant ID from current context\r\n */\r\n getTenantId(): string | undefined {\r\n return this.get()?.tenantId;\r\n }\r\n\r\n /**\r\n * Check if we're in a correlation context\r\n */\r\n isInContext(): boolean {\r\n return this.storage.getStore() !== undefined;\r\n }\r\n\r\n /**\r\n * Update current context (merge data)\r\n * Note: This doesn't actually update the store, but returns merged data\r\n * for use in nested contexts\r\n */\r\n extend(data: Partial<CorrelationData>): CorrelationData {\r\n const current = this.get() ?? {};\r\n return {\r\n ...current,\r\n ...data,\r\n metadata: {\r\n ...current.metadata,\r\n ...data.metadata,\r\n },\r\n };\r\n }\r\n\r\n /**\r\n * Run a nested context with extended data\r\n */\r\n runNested<T>(data: Partial<CorrelationData>, fn: () => T): T {\r\n return this.run(this.extend(data), fn);\r\n }\r\n\r\n /**\r\n * Run a nested async context with extended data\r\n */\r\n async runNestedAsync<T>(data: Partial<CorrelationData>, fn: () => Promise<T>): Promise<T> {\r\n return this.runAsync(this.extend(data), fn);\r\n }\r\n\r\n /**\r\n * Get context as log metadata (for structured logging)\r\n */\r\n getLogMeta(): Record<string, unknown> {\r\n const ctx = this.get();\r\n if (!ctx) return {};\r\n\r\n const meta: Record<string, unknown> = {};\r\n\r\n if (ctx.traceId) meta.traceId = ctx.traceId;\r\n if (ctx.spanId) meta.spanId = ctx.spanId;\r\n if (ctx.requestId) meta.requestId = ctx.requestId;\r\n if (ctx.correlationId) meta.correlationId = ctx.correlationId;\r\n if (ctx.userId) meta.userId = ctx.userId;\r\n if (ctx.tenantId) meta.tenantId = ctx.tenantId;\r\n if (ctx.sessionId) meta.sessionId = ctx.sessionId;\r\n if (ctx.operation) meta.operation = ctx.operation;\r\n\r\n return meta;\r\n }\r\n\r\n /**\r\n * Get context as HTTP headers (for propagation)\r\n */\r\n getHeaders(): Record<string, string> {\r\n const ctx = this.get();\r\n if (!ctx) return {};\r\n\r\n const headers: Record<string, string> = {};\r\n\r\n if (ctx.traceId) {\r\n // W3C Trace Context format\r\n const spanId = ctx.spanId ?? this.generateId().substring(0, 16);\r\n headers['traceparent'] = `00-${ctx.traceId}-${spanId}-01`;\r\n }\r\n\r\n if (ctx.requestId) {\r\n headers['x-request-id'] = ctx.requestId;\r\n }\r\n\r\n if (ctx.correlationId) {\r\n headers['x-correlation-id'] = ctx.correlationId;\r\n }\r\n\r\n return headers;\r\n }\r\n\r\n /**\r\n * Parse context from HTTP headers\r\n */\r\n parseHeaders(headers: Record<string, string | string[] | undefined>): CorrelationData {\r\n const data: CorrelationData = {};\r\n\r\n // Parse W3C Trace Context\r\n const traceparent = headers['traceparent'];\r\n if (traceparent && typeof traceparent === 'string') {\r\n const parts = traceparent.split('-');\r\n if (parts.length >= 3 && parts[0] === '00') {\r\n data.traceId = parts[1];\r\n data.spanId = parts[2];\r\n }\r\n }\r\n\r\n // Parse request ID\r\n const requestId = headers['x-request-id'];\r\n if (requestId) {\r\n data.requestId = Array.isArray(requestId) ? requestId[0] : requestId;\r\n }\r\n\r\n // Parse correlation ID\r\n const correlationId = headers['x-correlation-id'];\r\n if (correlationId) {\r\n data.correlationId = Array.isArray(correlationId) ? correlationId[0] : correlationId;\r\n }\r\n\r\n return data;\r\n }\r\n\r\n /**\r\n * Get elapsed time since context start (ms)\r\n */\r\n getElapsed(): number {\r\n const ctx = this.get();\r\n if (!ctx?.startTime) return 0;\r\n return Date.now() - ctx.startTime;\r\n }\r\n\r\n /**\r\n * Create a child span context\r\n */\r\n createChildSpan(operation: string): CorrelationData {\r\n const current = this.get() ?? {};\r\n return {\r\n ...current,\r\n spanId: this.generateId().substring(0, 16),\r\n operation,\r\n startTime: Date.now(),\r\n };\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// SINGLETON INSTANCE & EXPORTS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Global correlation context instance\r\n */\r\nexport const correlationContext = new CorrelationContextManager();\r\n\r\n// Convenience exports\r\nexport const runWithContext = correlationContext.run.bind(correlationContext);\r\nexport const runWithContextAsync = correlationContext.runAsync.bind(correlationContext);\r\nexport const getContext = correlationContext.get.bind(correlationContext);\r\nexport const getTraceId = correlationContext.getTraceId.bind(correlationContext);\r\nexport const getCorrelationId = correlationContext.getCorrelationId.bind(correlationContext);\r\nexport const getRequestId = correlationContext.getRequestId.bind(correlationContext);\r\nexport const getUserId = correlationContext.getUserId.bind(correlationContext);\r\nexport const getTenantId = correlationContext.getTenantId.bind(correlationContext);\r\nexport const getLogMeta = correlationContext.getLogMeta.bind(correlationContext);\r\nexport const isInContext = correlationContext.isInContext.bind(correlationContext);\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// MIDDLEWARE HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Create correlation context from incoming HTTP request\r\n */\r\nexport function createRequestContext(\r\n headers: Record<string, string | string[] | undefined>,\r\n options?: {\r\n generateTraceId?: boolean;\r\n generateRequestId?: boolean;\r\n operation?: string;\r\n userId?: string;\r\n tenantId?: string;\r\n }\r\n): CorrelationData {\r\n const parsed = correlationContext.parseHeaders(headers);\r\n\r\n return {\r\n ...parsed,\r\n traceId: parsed.traceId ?? (options?.generateTraceId ? correlationContext.generateId() : undefined),\r\n requestId: parsed.requestId ?? (options?.generateRequestId ? correlationContext.generateId() : undefined),\r\n operation: options?.operation,\r\n userId: options?.userId,\r\n tenantId: options?.tenantId,\r\n startTime: Date.now(),\r\n };\r\n}\r\n\r\n/**\r\n * Create correlation context for queue job processing\r\n */\r\nexport function createJobContext(job: {\r\n id: string;\r\n name: string;\r\n correlationId?: string;\r\n metadata?: Record<string, unknown>;\r\n}): CorrelationData {\r\n return {\r\n correlationId: job.correlationId ?? job.id,\r\n traceId: correlationContext.generateId(),\r\n operation: `job:${job.name}`,\r\n metadata: job.metadata,\r\n startTime: Date.now(),\r\n };\r\n}\r\n\r\n/**\r\n * Decorator to wrap a function with correlation context\r\n */\r\nexport function withCorrelation<TArgs extends unknown[], TReturn>(\r\n fn: (...args: TArgs) => TReturn,\r\n getContext: (...args: TArgs) => CorrelationData\r\n): (...args: TArgs) => TReturn {\r\n return (...args: TArgs) => {\r\n const ctx = getContext(...args);\r\n return correlationContext.run(ctx, () => fn(...args));\r\n };\r\n}\r\n\r\n/**\r\n * Decorator to wrap an async function with correlation context\r\n */\r\nexport function withCorrelationAsync<TArgs extends unknown[], TReturn>(\r\n fn: (...args: TArgs) => Promise<TReturn>,\r\n getContext: (...args: TArgs) => CorrelationData\r\n): (...args: TArgs) => Promise<TReturn> {\r\n return async (...args: TArgs) => {\r\n const ctx = getContext(...args);\r\n return correlationContext.runAsync(ctx, () => fn(...args));\r\n };\r\n}\r\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 = () => 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","/**\r\n * Console Email Adapter\r\n * Development implementation that logs emails to console instead of sending\r\n */\r\n\r\nimport { IEmail, EmailMessage, EmailResult, EmailAddress } from '../../interfaces/IEmail';\r\n\r\nexport class ConsoleEmail implements IEmail {\r\n private sentEmails: EmailMessage[] = [];\r\n\r\n async send(message: EmailMessage): Promise<EmailResult> {\r\n const id = `console_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;\r\n\r\n console.log('\\n' + '='.repeat(60));\r\n console.log('📧 EMAIL SENT (Console Adapter)');\r\n console.log('='.repeat(60));\r\n console.log(`ID: ${id}`);\r\n console.log(`To: ${this.formatAddresses(message.to)}`);\r\n console.log(`From: ${message.from ? this.formatAddress(message.from) : '(default)'}`);\r\n console.log(`Subject: ${message.subject}`);\r\n\r\n if (message.replyTo) {\r\n console.log(`Reply-To: ${this.formatAddress(message.replyTo)}`);\r\n }\r\n\r\n if (message.tags && message.tags.length > 0) {\r\n console.log(`Tags: ${message.tags.join(', ')}`);\r\n }\r\n\r\n if (message.attachments && message.attachments.length > 0) {\r\n console.log(`Attachments: ${message.attachments.map((a) => a.filename).join(', ')}`);\r\n }\r\n\r\n console.log('-'.repeat(60));\r\n\r\n if (message.text) {\r\n console.log('TEXT BODY:');\r\n console.log(message.text.slice(0, 500) + (message.text.length > 500 ? '\\n...(truncated)' : ''));\r\n }\r\n\r\n if (message.html) {\r\n console.log('HTML BODY: [HTML content - ' + message.html.length + ' chars]');\r\n }\r\n\r\n console.log('='.repeat(60) + '\\n');\r\n\r\n this.sentEmails.push(message);\r\n\r\n return {\r\n id,\r\n success: true,\r\n };\r\n }\r\n\r\n async sendBatch(messages: EmailMessage[]): Promise<EmailResult[]> {\r\n const results: EmailResult[] = [];\r\n\r\n for (const message of messages) {\r\n results.push(await this.send(message));\r\n }\r\n\r\n return results;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n /**\r\n * Get all sent emails (for testing)\r\n */\r\n getSentEmails(): EmailMessage[] {\r\n return [...this.sentEmails];\r\n }\r\n\r\n /**\r\n * Clear sent emails (for testing)\r\n */\r\n clearSentEmails(): void {\r\n this.sentEmails = [];\r\n }\r\n\r\n private formatAddress(address: EmailAddress): string {\r\n if (address.name) {\r\n return `${address.name} <${address.email}>`;\r\n }\r\n return address.email;\r\n }\r\n\r\n private formatAddresses(addresses: EmailAddress | EmailAddress[]): string {\r\n const list = Array.isArray(addresses) ? addresses : [addresses];\r\n return list.map((addr) => this.formatAddress(addr)).join(', ');\r\n }\r\n}\r\n","/**\n * Platform Factory\n * Create a platform instance with configured adapters\n */\n\nimport { IPlatform, PlatformHealthStatus, IDatabase, ICache, IStorage, IEmail, IQueue, ILogger, IMetrics, ITracing } 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/**\n * Create a database adapter based on configuration\n */\nasync function createDatabaseAdapter(config: PlatformConfig): Promise<IDatabase> {\n switch (config.database.provider) {\n case 'postgres': {\n const connectionString = config.database.connectionString || config.database.url || process.env.DATABASE_URL;\n if (!connectionString) {\n throw new Error('PostgreSQL requires DATABASE_URL, url, or connectionString configuration');\n }\n const { PostgresDatabase } = 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('Supabase requires SUPABASE_URL and SUPABASE_ANON_KEY environment variables');\n }\n const { createClient } = await import('@supabase/supabase-js');\n const { SupabaseDatabase } = await import('./adapters/supabase/SupabaseDatabase');\n const client = createClient(\n config.database.supabaseUrl,\n config.database.supabaseServiceRoleKey || 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('Upstash requires UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN environment variables');\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 = config.database.supabaseServiceRoleKey || config.database.supabaseAnonKey || process.env.SUPABASE_ANON_KEY;\n const bucket = config.storage.bucket || process.env.SUPABASE_STORAGE_BUCKET || 'uploads';\n\n if (!url || !apiKey) {\n throw new Error('Supabase storage requires SUPABASE_URL and SUPABASE_ANON_KEY');\n }\n\n const { SupabaseStorage } = 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 (!config.storage.accessKey || !config.storage.secretKey || !config.storage.bucket) {\n throw new Error('S3 requires S3_ACCESS_KEY, S3_SECRET_KEY, and S3_BUCKET environment variables');\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: config.storage.forcePathStyle || config.storage.provider === 'minio',\n });\n\n return new S3Storage(client, config.storage.bucket, getSignedUrl, config.storage.publicUrl);\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('SMTP requires host and port configuration (SMTP_HOST, SMTP_PORT)');\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 } = 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 a platform instance (async version)\n */\nexport async function createPlatformAsync(config?: Partial<PlatformConfig>): Promise<IPlatform> {\n const finalConfig = config ? deepMerge(loadConfig(), config) : loadConfig();\n\n const [db, cache, storage, email, queue, tracing] = await Promise.all([\n createDatabaseAdapter(finalConfig),\n createCacheAdapter(finalConfig),\n createStorageAdapter(finalConfig),\n createEmailAdapter(finalConfig),\n createQueueAdapter(finalConfig),\n createTracingAdapter(finalConfig),\n ]);\n\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n\n return createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing);\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' && finalConfig.email.provider !== 'console') ||\n finalConfig.observability.tracing.provider === 'otlp';\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 = finalConfig.email.provider === 'console' ? new ConsoleEmail() : new MemoryEmail();\n const queue = new MemoryQueue();\n const logger = createLogger(finalConfig);\n const metrics = createMetrics(finalConfig);\n const tracing = finalConfig.observability.tracing.provider === 'memory'\n ? new MemoryTracing()\n : new NoopTracing();\n\n return createPlatformFromAdapters(db, cache, storage, email, queue, logger, metrics, tracing);\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): IPlatform {\n return {\n db,\n cache,\n storage,\n email,\n queue,\n logger,\n metrics,\n tracing,\n\n async healthCheck(): Promise<PlatformHealthStatus> {\n const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth, tracingHealth] = 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: dbHealth && cacheHealth && storageHealth && emailHealth && queueHealth && 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([db.close(), cache.close(), queue.close(), tracing.close()]);\n },\n };\n}\n\n/**\n * Deep merge two objects\n */\nfunction deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): 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 * Middleware Chain Implementation\r\n */\r\n\r\nimport { randomUUID } from 'crypto';\r\nimport type { Middleware, MiddlewareChain, MiddlewareChainOptions, MiddlewareContext } from './types';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\nimport type { ILogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Create a new middleware chain\r\n */\r\nexport function createMiddlewareChain(options: MiddlewareChainOptions = {}): MiddlewareChain {\r\n const middlewares: Middleware[] = [];\r\n const logger = options.logger ?? new NoopLogger();\r\n const generateCorrelationId = options.generateCorrelationId ?? (() => randomUUID());\r\n\r\n function sortMiddleware(): void {\r\n middlewares.sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100));\r\n }\r\n\r\n const chain: MiddlewareChain = {\r\n use<TArgs = unknown, TResult = unknown>(middleware: Middleware<TArgs, TResult>): MiddlewareChain {\r\n // Remove existing middleware with same name\r\n const existingIndex = middlewares.findIndex((m) => m.name === middleware.name);\r\n if (existingIndex !== -1) {\r\n middlewares.splice(existingIndex, 1);\r\n }\r\n\r\n middlewares.push(middleware as Middleware);\r\n sortMiddleware();\r\n return chain;\r\n },\r\n\r\n remove(name: string): MiddlewareChain {\r\n const index = middlewares.findIndex((m) => m.name === name);\r\n if (index !== -1) {\r\n middlewares.splice(index, 1);\r\n }\r\n return chain;\r\n },\r\n\r\n async execute<TArgs, TResult>(\r\n partialCtx: Omit<MiddlewareContext<TArgs, TResult>, 'metadata' | 'skip' | 'cachedResult'>,\r\n operation: () => Promise<TResult>\r\n ): Promise<TResult> {\r\n const ctx: MiddlewareContext<TArgs, TResult> = {\r\n ...partialCtx,\r\n metadata: new Map(),\r\n skip: false,\r\n cachedResult: undefined,\r\n };\r\n\r\n // Execute before hooks\r\n for (const middleware of middlewares) {\r\n if (middleware.before) {\r\n try {\r\n await middleware.before(ctx);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Middleware ${middleware.name} before hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n\r\n if (ctx.skip) {\r\n break;\r\n }\r\n }\r\n\r\n // Return cached result if set\r\n if (ctx.cachedResult !== undefined) {\r\n ctx.result = ctx.cachedResult;\r\n ctx.duration = Date.now() - ctx.startTime;\r\n\r\n // Still run after hooks for cached results\r\n for (const middleware of middlewares) {\r\n if (middleware.after) {\r\n try {\r\n await middleware.after(ctx);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Middleware ${middleware.name} after hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return ctx.cachedResult;\r\n }\r\n\r\n // Execute the actual operation\r\n try {\r\n const result = await operation();\r\n ctx.result = result;\r\n ctx.duration = Date.now() - ctx.startTime;\r\n\r\n // Execute after hooks\r\n for (const middleware of middlewares) {\r\n if (middleware.after) {\r\n try {\r\n await middleware.after(ctx);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Middleware ${middleware.name} after hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n }\r\n\r\n return result;\r\n } catch (err) {\r\n ctx.error = err instanceof Error ? err : new Error(String(err));\r\n ctx.duration = Date.now() - ctx.startTime;\r\n\r\n // Execute error hooks\r\n for (const middleware of middlewares) {\r\n if (middleware.onError) {\r\n try {\r\n await middleware.onError(ctx, ctx.error);\r\n } catch (hookErr) {\r\n const error = hookErr instanceof Error ? hookErr : new Error(String(hookErr));\r\n logger.error(`Middleware ${middleware.name} onError hook failed`, {\r\n error,\r\n operation: ctx.operation,\r\n });\r\n }\r\n }\r\n }\r\n\r\n throw ctx.error;\r\n }\r\n },\r\n\r\n getMiddleware(): Middleware[] {\r\n return [...middlewares];\r\n },\r\n };\r\n\r\n return chain;\r\n}\r\n\r\n/**\r\n * Create a context for middleware execution\r\n */\r\nexport function createMiddlewareContext<TArgs = unknown, TResult = unknown>(\r\n service: MiddlewareContext['service'],\r\n operation: string,\r\n args: TArgs,\r\n logger: ILogger,\r\n options: {\r\n correlationId?: string;\r\n tenantId?: string;\r\n } = {}\r\n): Omit<MiddlewareContext<TArgs, TResult>, 'metadata' | 'skip' | 'cachedResult'> {\r\n return {\r\n service,\r\n operation,\r\n args,\r\n logger,\r\n startTime: Date.now(),\r\n correlationId: options.correlationId ?? randomUUID(),\r\n tenantId: options.tenantId,\r\n };\r\n}\r\n","/**\r\n * Built-in Middleware Implementations\r\n */\r\n\r\nimport type { Middleware, MiddlewareContext } from './types';\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport type { IMetrics } from '../interfaces/IMetrics';\r\n\r\n/**\r\n * Logging middleware - logs all operations with timing\r\n */\r\nexport function createLoggingMiddleware(logger: ILogger): Middleware {\r\n return {\r\n name: 'logging',\r\n priority: 10,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n logger.debug(`Starting ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n tenantId: ctx.tenantId,\r\n args: sanitizeArgs(ctx.args),\r\n });\r\n },\r\n\r\n after(ctx: MiddlewareContext): void {\r\n logger.info(`Completed ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n duration: ctx.duration,\r\n success: true,\r\n });\r\n },\r\n\r\n onError(ctx: MiddlewareContext, error: Error): void {\r\n logger.error(`Failed ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n duration: ctx.duration,\r\n error,\r\n });\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Metrics middleware - records timing and counters\r\n */\r\nexport function createMetricsMiddleware(metrics: IMetrics): Middleware {\r\n return {\r\n name: 'metrics',\r\n priority: 20,\r\n\r\n after(ctx: MiddlewareContext): void {\r\n metrics.timing(`platform.${ctx.service}.duration`, ctx.duration ?? 0, {\r\n operation: ctx.operation,\r\n success: 'true',\r\n });\r\n\r\n metrics.increment(`platform.${ctx.service}.requests`, 1, {\r\n operation: ctx.operation,\r\n status: 'success',\r\n });\r\n },\r\n\r\n onError(ctx: MiddlewareContext): void {\r\n metrics.timing(`platform.${ctx.service}.duration`, ctx.duration ?? 0, {\r\n operation: ctx.operation,\r\n success: 'false',\r\n });\r\n\r\n metrics.increment(`platform.${ctx.service}.requests`, 1, {\r\n operation: ctx.operation,\r\n status: 'error',\r\n });\r\n\r\n metrics.increment(`platform.${ctx.service}.errors`, 1, {\r\n operation: ctx.operation,\r\n });\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Slow query logging middleware\r\n */\r\nexport function createSlowQueryMiddleware(\r\n logger: ILogger,\r\n thresholdMs: number = 1000\r\n): Middleware {\r\n return {\r\n name: 'slow-query',\r\n priority: 15,\r\n\r\n after(ctx: MiddlewareContext): void {\r\n if (ctx.duration && ctx.duration > thresholdMs) {\r\n logger.warn(`Slow operation detected: ${ctx.service}.${ctx.operation}`, {\r\n correlationId: ctx.correlationId,\r\n duration: ctx.duration,\r\n threshold: thresholdMs,\r\n args: sanitizeArgs(ctx.args),\r\n });\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Tenant isolation middleware - ensures tenant context is set\r\n */\r\nexport function createTenantMiddleware(\r\n options: {\r\n required?: boolean;\r\n headerName?: string;\r\n } = {}\r\n): Middleware {\r\n const { required = false } = options;\r\n\r\n return {\r\n name: 'tenant',\r\n priority: 5,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n if (required && !ctx.tenantId) {\r\n throw new Error('Tenant context required but not provided');\r\n }\r\n\r\n if (ctx.tenantId) {\r\n ctx.metadata.set('tenantId', ctx.tenantId);\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Request ID middleware - ensures correlation ID exists\r\n */\r\nexport function createRequestIdMiddleware(): Middleware {\r\n return {\r\n name: 'request-id',\r\n priority: 1,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n ctx.metadata.set('correlationId', ctx.correlationId);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Timeout middleware - enforces operation timeout\r\n */\r\nexport function createTimeoutMiddleware(timeoutMs: number): Middleware {\r\n return {\r\n name: 'timeout',\r\n priority: 2,\r\n\r\n before(ctx: MiddlewareContext): void {\r\n ctx.metadata.set('timeout', timeoutMs);\r\n ctx.metadata.set('timeoutStart', Date.now());\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Cache middleware - caches results of read operations\r\n */\r\nexport function createCacheMiddleware(\r\n cache: { get: (key: string) => Promise<unknown>; set: (key: string, value: unknown, ttl?: number) => Promise<void> },\r\n options: {\r\n ttl?: number;\r\n keyPrefix?: string;\r\n cacheableOperations?: string[];\r\n } = {}\r\n): Middleware {\r\n const {\r\n ttl = 300,\r\n keyPrefix = 'middleware:cache:',\r\n cacheableOperations = ['get', 'query', 'find', 'list'],\r\n } = options;\r\n\r\n function isCacheable(operation: string): boolean {\r\n return cacheableOperations.some((op) => operation.toLowerCase().includes(op));\r\n }\r\n\r\n function getCacheKey(ctx: MiddlewareContext): string {\r\n const argsHash = JSON.stringify(ctx.args);\r\n return `${keyPrefix}${ctx.service}:${ctx.operation}:${argsHash}`;\r\n }\r\n\r\n return {\r\n name: 'cache',\r\n priority: 50,\r\n\r\n async before(ctx: MiddlewareContext): Promise<void> {\r\n if (!isCacheable(ctx.operation)) return;\r\n\r\n const key = getCacheKey(ctx);\r\n const cached = await cache.get(key);\r\n\r\n if (cached !== null) {\r\n ctx.cachedResult = cached;\r\n ctx.metadata.set('cacheHit', true);\r\n ctx.logger.debug('Cache hit', { key, operation: ctx.operation });\r\n } else {\r\n ctx.metadata.set('cacheHit', false);\r\n }\r\n },\r\n\r\n async after(ctx: MiddlewareContext): Promise<void> {\r\n if (!isCacheable(ctx.operation)) return;\r\n if (ctx.metadata.get('cacheHit')) return;\r\n\r\n const key = getCacheKey(ctx);\r\n await cache.set(key, ctx.result, ttl);\r\n ctx.logger.debug('Cache set', { key, operation: ctx.operation, ttl });\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Rate Limiting Error\r\n */\r\nexport class RateLimitError extends Error {\r\n override readonly name = 'RateLimitError';\r\n readonly retryAfter: number;\r\n readonly limit: number;\r\n readonly remaining: number;\r\n readonly resetAt: Date;\r\n\r\n constructor(\r\n message: string,\r\n options: { retryAfter: number; limit: number; remaining: number; resetAt: Date }\r\n ) {\r\n super(message);\r\n this.retryAfter = options.retryAfter;\r\n this.limit = options.limit;\r\n this.remaining = options.remaining;\r\n this.resetAt = options.resetAt;\r\n }\r\n}\r\n\r\n/**\r\n * Rate limit info for responses\r\n */\r\nexport interface RateLimitInfo {\r\n limit: number;\r\n remaining: number;\r\n resetAt: Date;\r\n}\r\n\r\n/**\r\n * Rate limiter storage interface\r\n */\r\nexport interface RateLimiterStorage {\r\n /**\r\n * Get current count and increment\r\n * Returns: [currentCount, resetAt timestamp]\r\n */\r\n increment(key: string, windowMs: number): Promise<[number, number]>;\r\n\r\n /**\r\n * Get current state without incrementing\r\n */\r\n get(key: string): Promise<{ count: number; resetAt: number } | null>;\r\n}\r\n\r\n/**\r\n * In-memory rate limiter storage\r\n */\r\nexport class MemoryRateLimiterStorage implements RateLimiterStorage {\r\n private windows: Map<string, { count: number; resetAt: number }> = new Map();\r\n private cleanupInterval: NodeJS.Timeout | null = null;\r\n\r\n constructor(options: { cleanupIntervalMs?: number } = {}) {\r\n const cleanupIntervalMs = options.cleanupIntervalMs ?? 60000;\r\n\r\n // Periodic cleanup of expired windows\r\n this.cleanupInterval = setInterval(() => {\r\n const now = Date.now();\r\n for (const [key, window] of this.windows) {\r\n if (window.resetAt < now) {\r\n this.windows.delete(key);\r\n }\r\n }\r\n }, cleanupIntervalMs);\r\n\r\n // Prevent interval from keeping process alive\r\n if (this.cleanupInterval.unref) {\r\n this.cleanupInterval.unref();\r\n }\r\n }\r\n\r\n async increment(key: string, windowMs: number): Promise<[number, number]> {\r\n const now = Date.now();\r\n let window = this.windows.get(key);\r\n\r\n // Check if window expired\r\n if (!window || window.resetAt < now) {\r\n window = { count: 0, resetAt: now + windowMs };\r\n this.windows.set(key, window);\r\n }\r\n\r\n window.count++;\r\n return [window.count, window.resetAt];\r\n }\r\n\r\n async get(key: string): Promise<{ count: number; resetAt: number } | null> {\r\n const window = this.windows.get(key);\r\n if (!window || window.resetAt < Date.now()) {\r\n return null;\r\n }\r\n return window;\r\n }\r\n\r\n /**\r\n * Clear all windows (for testing)\r\n */\r\n clear(): void {\r\n this.windows.clear();\r\n }\r\n\r\n /**\r\n * Stop cleanup interval\r\n */\r\n stop(): void {\r\n if (this.cleanupInterval) {\r\n clearInterval(this.cleanupInterval);\r\n this.cleanupInterval = null;\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Rate limiting algorithm types\r\n */\r\nexport type RateLimitAlgorithm = 'fixed-window' | 'sliding-window' | 'token-bucket';\r\n\r\n/**\r\n * Rate limiting options\r\n */\r\nexport interface RateLimitOptions {\r\n /** Maximum requests per window */\r\n limit: number;\r\n\r\n /** Time window in milliseconds */\r\n windowMs: number;\r\n\r\n /** Storage backend (defaults to memory) */\r\n storage?: RateLimiterStorage;\r\n\r\n /** Key generator function */\r\n keyGenerator?: (ctx: MiddlewareContext) => string;\r\n\r\n /** Skip rate limiting for certain requests */\r\n skip?: (ctx: MiddlewareContext) => boolean;\r\n\r\n /** Handler for rate limit exceeded */\r\n onRateLimited?: (ctx: MiddlewareContext, info: RateLimitInfo) => void;\r\n\r\n /** Whether to throw error or just log (defaults to throw) */\r\n throwOnLimit?: boolean;\r\n\r\n /** Custom message for rate limit error */\r\n message?: string;\r\n\r\n /** Headers to set with rate limit info */\r\n setHeaders?: boolean;\r\n}\r\n\r\n/**\r\n * Rate limiting middleware\r\n * Prevents abuse by limiting request frequency\r\n */\r\nexport function createRateLimitMiddleware(options: RateLimitOptions): Middleware {\r\n const {\r\n limit,\r\n windowMs,\r\n storage = new MemoryRateLimiterStorage(),\r\n keyGenerator = defaultKeyGenerator,\r\n skip,\r\n onRateLimited,\r\n throwOnLimit = true,\r\n message = 'Too many requests, please try again later',\r\n } = options;\r\n\r\n return {\r\n name: 'rate-limit',\r\n priority: 3, // Run early, after request-id and timeout\r\n\r\n async before(ctx: MiddlewareContext): Promise<void> {\r\n // Check if we should skip\r\n if (skip?.(ctx)) {\r\n ctx.metadata.set('rateLimitSkipped', true);\r\n return;\r\n }\r\n\r\n const key = `ratelimit:${keyGenerator(ctx)}`;\r\n const [count, resetAtMs] = await storage.increment(key, windowMs);\r\n const resetAt = new Date(resetAtMs);\r\n const remaining = Math.max(0, limit - count);\r\n const retryAfter = Math.ceil((resetAtMs - Date.now()) / 1000);\r\n\r\n // Store rate limit info in metadata for headers\r\n const info: RateLimitInfo = { limit, remaining, resetAt };\r\n ctx.metadata.set('rateLimit', info);\r\n\r\n if (count > limit) {\r\n onRateLimited?.(ctx, info);\r\n\r\n ctx.logger.warn('Rate limit exceeded', {\r\n correlationId: ctx.correlationId,\r\n tenantId: ctx.tenantId,\r\n key,\r\n count,\r\n limit,\r\n resetAt,\r\n });\r\n\r\n if (throwOnLimit) {\r\n throw new RateLimitError(message, { retryAfter, limit, remaining, resetAt });\r\n }\r\n }\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Default key generator - uses tenant, service, and operation\r\n */\r\nfunction defaultKeyGenerator(ctx: MiddlewareContext): string {\r\n const parts = [ctx.service, ctx.operation];\r\n\r\n if (ctx.tenantId) {\r\n parts.unshift(ctx.tenantId);\r\n }\r\n\r\n return parts.join(':');\r\n}\r\n\r\n/**\r\n * Create an IP-based rate limiter key generator\r\n */\r\nexport function createIpKeyGenerator(\r\n getIp: (ctx: MiddlewareContext) => string | undefined\r\n): (ctx: MiddlewareContext) => string {\r\n return (ctx: MiddlewareContext) => {\r\n const ip = getIp(ctx) ?? 'unknown';\r\n return `ip:${ip}:${ctx.service}:${ctx.operation}`;\r\n };\r\n}\r\n\r\n/**\r\n * Create a user-based rate limiter key generator\r\n */\r\nexport function createUserKeyGenerator(\r\n getUserId: (ctx: MiddlewareContext) => string | undefined\r\n): (ctx: MiddlewareContext) => string {\r\n return (ctx: MiddlewareContext) => {\r\n const userId = getUserId(ctx) ?? 'anonymous';\r\n return `user:${userId}:${ctx.service}:${ctx.operation}`;\r\n };\r\n}\r\n\r\n/**\r\n * Sliding window rate limiter options\r\n */\r\nexport interface SlidingWindowRateLimitOptions extends Omit<RateLimitOptions, 'algorithm'> {\r\n /** Number of sub-windows (more = more accurate, more memory) */\r\n precision?: number;\r\n}\r\n\r\n/**\r\n * Token bucket rate limiter options\r\n */\r\nexport interface TokenBucketOptions {\r\n /** Bucket capacity (max tokens) */\r\n capacity: number;\r\n\r\n /** Token refill rate per second */\r\n refillRate: number;\r\n\r\n /** Storage backend */\r\n storage?: RateLimiterStorage;\r\n\r\n /** Key generator function */\r\n keyGenerator?: (ctx: MiddlewareContext) => string;\r\n\r\n /** Skip rate limiting for certain requests */\r\n skip?: (ctx: MiddlewareContext) => boolean;\r\n\r\n /** Whether to throw error or just log */\r\n throwOnLimit?: boolean;\r\n\r\n /** Custom message for rate limit error */\r\n message?: string;\r\n}\r\n\r\n/**\r\n * Pre-configured rate limit presets\r\n */\r\nexport const RateLimitPresets = {\r\n /** Standard API rate limit: 100 req/min */\r\n standard: { limit: 100, windowMs: 60 * 1000 },\r\n\r\n /** Strict rate limit: 10 req/min */\r\n strict: { limit: 10, windowMs: 60 * 1000 },\r\n\r\n /** Relaxed rate limit: 1000 req/min */\r\n relaxed: { limit: 1000, windowMs: 60 * 1000 },\r\n\r\n /** Burst protection: 50 req/sec */\r\n burst: { limit: 50, windowMs: 1000 },\r\n\r\n /** Auth rate limit: 5 attempts/15 min */\r\n auth: { limit: 5, windowMs: 15 * 60 * 1000 },\r\n\r\n /** Expensive operations: 10 req/hour */\r\n expensive: { limit: 10, windowMs: 60 * 60 * 1000 },\r\n} as const;\r\n\r\n/**\r\n * Sanitize args for logging (remove sensitive data)\r\n */\r\nfunction sanitizeArgs(args: unknown): unknown {\r\n if (args === null || args === undefined) return args;\r\n\r\n if (typeof args !== 'object') return args;\r\n\r\n if (Array.isArray(args)) {\r\n return args.map(sanitizeArgs);\r\n }\r\n\r\n const sanitized: Record<string, unknown> = {};\r\n const sensitiveKeys = ['password', 'token', 'secret', 'key', 'authorization', 'credential'];\r\n\r\n for (const [key, value] of Object.entries(args as Record<string, unknown>)) {\r\n if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk))) {\r\n sanitized[key] = '[REDACTED]';\r\n } else if (typeof value === 'object' && value !== null) {\r\n sanitized[key] = sanitizeArgs(value);\r\n } else {\r\n sanitized[key] = value;\r\n }\r\n }\r\n\r\n return sanitized;\r\n}\r\n","/**\r\n * Hook Registry Implementation\r\n */\r\n\r\nimport type { PlatformHooks, HookRegistry } from './types';\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Create a hook registry\r\n */\r\nexport function createHookRegistry(logger: ILogger = new NoopLogger()): HookRegistry {\r\n let hooks: PlatformHooks = {};\r\n\r\n const registry: HookRegistry = {\r\n register(newHooks: Partial<PlatformHooks>): void {\r\n hooks = { ...hooks, ...newHooks };\r\n logger.debug('Hooks registered', {\r\n hookNames: Object.keys(newHooks),\r\n });\r\n },\r\n\r\n clear(): void {\r\n hooks = {};\r\n logger.debug('Hooks cleared');\r\n },\r\n\r\n async execute<K extends keyof PlatformHooks>(\r\n hookName: K,\r\n ...args: Parameters<NonNullable<PlatformHooks[K]>>\r\n ): Promise<void> {\r\n const hook = hooks[hookName];\r\n\r\n if (!hook) {\r\n return;\r\n }\r\n\r\n try {\r\n // @ts-expect-error - TypeScript can't infer the correct function signature\r\n await hook(...args);\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.error(`Hook ${String(hookName)} failed`, {\r\n error,\r\n hookName: String(hookName),\r\n });\r\n // Don't throw - hooks should not break the main flow\r\n }\r\n },\r\n\r\n getHooks(): PlatformHooks {\r\n return { ...hooks };\r\n },\r\n };\r\n\r\n return registry;\r\n}\r\n\r\n/**\r\n * Compose multiple hook registries\r\n */\r\nexport function composeHookRegistries(...registries: HookRegistry[]): HookRegistry {\r\n const logger = new NoopLogger();\r\n\r\n return {\r\n register(hooks: Partial<PlatformHooks>): void {\r\n registries.forEach((r) => r.register(hooks));\r\n },\r\n\r\n clear(): void {\r\n registries.forEach((r) => r.clear());\r\n },\r\n\r\n async execute<K extends keyof PlatformHooks>(\r\n hookName: K,\r\n ...args: Parameters<NonNullable<PlatformHooks[K]>>\r\n ): Promise<void> {\r\n for (const registry of registries) {\r\n await registry.execute(hookName, ...args);\r\n }\r\n },\r\n\r\n getHooks(): PlatformHooks {\r\n return registries.reduce((acc, r) => ({ ...acc, ...r.getHooks() }), {} as PlatformHooks);\r\n },\r\n };\r\n}\r\n","/**\r\n * Retry Pattern Implementation\r\n *\r\n * Provides configurable retry logic with exponential backoff and jitter.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Options for retry behavior\r\n */\r\nexport interface RetryOptions {\r\n /**\r\n * Maximum number of retry attempts\r\n * @default 3\r\n */\r\n maxAttempts: number;\r\n\r\n /**\r\n * Initial delay between retries in milliseconds\r\n * @default 100\r\n */\r\n baseDelay: number;\r\n\r\n /**\r\n * Maximum delay between retries in milliseconds\r\n * @default 10000\r\n */\r\n maxDelay: number;\r\n\r\n /**\r\n * Multiplier for exponential backoff\r\n * @default 2\r\n */\r\n backoffMultiplier: number;\r\n\r\n /**\r\n * Whether to add random jitter to delays\r\n * @default true\r\n */\r\n jitter: boolean;\r\n\r\n /**\r\n * Maximum jitter in milliseconds\r\n * @default 100\r\n */\r\n maxJitter: number;\r\n\r\n /**\r\n * Function to determine if error is retryable\r\n * @default All errors are retryable\r\n */\r\n retryIf?: (error: Error) => boolean;\r\n\r\n /**\r\n * Function to determine if error is non-retryable\r\n * Takes precedence over retryIf\r\n */\r\n abortIf?: (error: Error) => boolean;\r\n\r\n /**\r\n * Callback on each retry attempt\r\n */\r\n onRetry?: (error: Error, attempt: number, delay: number) => void;\r\n\r\n /**\r\n * Logger for retry operations\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Default retry options\r\n */\r\nexport const DEFAULT_RETRY_OPTIONS: RetryOptions = {\r\n maxAttempts: 3,\r\n baseDelay: 100,\r\n maxDelay: 10000,\r\n backoffMultiplier: 2,\r\n jitter: true,\r\n maxJitter: 100,\r\n};\r\n\r\n/**\r\n * Result of a retry operation\r\n */\r\nexport interface RetryResult<T> {\r\n /** Whether the operation succeeded */\r\n success: boolean;\r\n\r\n /** The result if successful */\r\n result?: T;\r\n\r\n /** The final error if all attempts failed */\r\n error?: Error;\r\n\r\n /** Number of attempts made */\r\n attempts: number;\r\n\r\n /** Total time spent in milliseconds */\r\n totalTime: number;\r\n}\r\n\r\n/**\r\n * Sleep for specified milliseconds\r\n */\r\nfunction sleep(ms: number): Promise<void> {\r\n return new Promise((resolve) => setTimeout(resolve, ms));\r\n}\r\n\r\n/**\r\n * Calculate delay for a given attempt\r\n */\r\nfunction calculateDelay(attempt: number, options: RetryOptions): number {\r\n // Exponential backoff\r\n let delay = options.baseDelay * Math.pow(options.backoffMultiplier, attempt - 1);\r\n\r\n // Cap at max delay\r\n delay = Math.min(delay, options.maxDelay);\r\n\r\n // Add jitter\r\n if (options.jitter) {\r\n const jitter = Math.random() * options.maxJitter;\r\n delay += jitter;\r\n }\r\n\r\n return Math.floor(delay);\r\n}\r\n\r\n/**\r\n * Execute a function with retry logic\r\n */\r\nexport async function withRetry<T>(\r\n fn: () => Promise<T>,\r\n options: Partial<RetryOptions> = {}\r\n): Promise<T> {\r\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\r\n const logger = opts.logger ?? new NoopLogger();\r\n\r\n let lastError: Error | undefined;\r\n let delay = opts.baseDelay;\r\n\r\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\r\n try {\r\n return await fn();\r\n } catch (error) {\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Check if error is non-retryable\r\n if (opts.abortIf?.(lastError)) {\r\n logger.debug('Retry aborted - non-retryable error', {\r\n attempt,\r\n error: lastError,\r\n });\r\n throw lastError;\r\n }\r\n\r\n // Check if error is retryable\r\n if (opts.retryIf && !opts.retryIf(lastError)) {\r\n logger.debug('Retry aborted - error not retryable', {\r\n attempt,\r\n error: lastError,\r\n });\r\n throw lastError;\r\n }\r\n\r\n // If this was the last attempt, throw\r\n if (attempt >= opts.maxAttempts) {\r\n logger.warn('All retry attempts exhausted', {\r\n attempts: attempt,\r\n error: lastError,\r\n });\r\n throw lastError;\r\n }\r\n\r\n // Calculate delay for next attempt\r\n delay = calculateDelay(attempt, opts);\r\n\r\n logger.debug('Retrying operation', {\r\n attempt,\r\n maxAttempts: opts.maxAttempts,\r\n delay,\r\n error: lastError,\r\n });\r\n\r\n // Call retry callback\r\n opts.onRetry?.(lastError, attempt, delay);\r\n\r\n // Wait before next attempt\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n // This should never happen, but TypeScript needs it\r\n throw lastError ?? new Error('Retry failed with no error');\r\n}\r\n\r\n/**\r\n * Execute with retry and return detailed result\r\n */\r\nexport async function withRetryResult<T>(\r\n fn: () => Promise<T>,\r\n options: Partial<RetryOptions> = {}\r\n): Promise<RetryResult<T>> {\r\n const opts: RetryOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };\r\n const startTime = Date.now();\r\n\r\n let attempts = 0;\r\n let lastError: Error | undefined;\r\n let delay = opts.baseDelay;\r\n\r\n for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {\r\n attempts = attempt;\r\n\r\n try {\r\n const result = await fn();\r\n return {\r\n success: true,\r\n result,\r\n attempts,\r\n totalTime: Date.now() - startTime,\r\n };\r\n } catch (error) {\r\n lastError = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (opts.abortIf?.(lastError)) {\r\n break;\r\n }\r\n\r\n if (opts.retryIf && !opts.retryIf(lastError)) {\r\n break;\r\n }\r\n\r\n if (attempt >= opts.maxAttempts) {\r\n break;\r\n }\r\n\r\n delay = calculateDelay(attempt, opts);\r\n opts.onRetry?.(lastError, attempt, delay);\r\n await sleep(delay);\r\n }\r\n }\r\n\r\n return {\r\n success: false,\r\n error: lastError,\r\n attempts,\r\n totalTime: Date.now() - startTime,\r\n };\r\n}\r\n\r\n/**\r\n * Create a retryable version of a function\r\n */\r\nexport function retryable<TArgs extends unknown[], TResult>(\r\n fn: (...args: TArgs) => Promise<TResult>,\r\n options: Partial<RetryOptions> = {}\r\n): (...args: TArgs) => Promise<TResult> {\r\n return (...args: TArgs) => withRetry(() => fn(...args), options);\r\n}\r\n\r\n/**\r\n * Common retry predicates\r\n */\r\nexport const RetryPredicates = {\r\n /**\r\n * Retry on network errors\r\n */\r\n networkErrors: (error: Error): boolean => {\r\n const networkErrorCodes = [\r\n 'ECONNRESET',\r\n 'ECONNREFUSED',\r\n 'ETIMEDOUT',\r\n 'ENOTFOUND',\r\n 'EAI_AGAIN',\r\n 'EHOSTUNREACH',\r\n 'ENETUNREACH',\r\n ];\r\n\r\n const errorCode = (error as NodeJS.ErrnoException).code;\r\n if (errorCode && networkErrorCodes.includes(errorCode)) {\r\n return true;\r\n }\r\n\r\n // Check for common network error messages\r\n const message = error.message.toLowerCase();\r\n return (\r\n message.includes('network') ||\r\n message.includes('timeout') ||\r\n message.includes('connection') ||\r\n message.includes('socket')\r\n );\r\n },\r\n\r\n /**\r\n * Retry on HTTP 5xx errors\r\n */\r\n serverErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode !== undefined && statusCode >= 500 && statusCode < 600;\r\n },\r\n\r\n /**\r\n * Retry on HTTP 429 (rate limit) errors\r\n */\r\n rateLimitErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode === 429;\r\n },\r\n\r\n /**\r\n * Retry on database deadlock errors\r\n */\r\n deadlockErrors: (error: Error): boolean => {\r\n const message = error.message.toLowerCase();\r\n return message.includes('deadlock') || message.includes('lock wait timeout');\r\n },\r\n\r\n /**\r\n * Never retry on authentication errors\r\n */\r\n authenticationErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode === 401 || statusCode === 403;\r\n },\r\n\r\n /**\r\n * Never retry on validation errors\r\n */\r\n validationErrors: (error: Error): boolean => {\r\n const statusCode = (error as Error & { statusCode?: number }).statusCode;\r\n return statusCode === 400 || statusCode === 422;\r\n },\r\n};\r\n\r\n/**\r\n * Common retry configurations\r\n */\r\nexport const RetryConfigs = {\r\n /**\r\n * Fast retry for quick failures\r\n */\r\n fast: {\r\n maxAttempts: 3,\r\n baseDelay: 50,\r\n maxDelay: 500,\r\n backoffMultiplier: 2,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Standard retry configuration\r\n */\r\n standard: {\r\n maxAttempts: 3,\r\n baseDelay: 100,\r\n maxDelay: 5000,\r\n backoffMultiplier: 2,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Aggressive retry for critical operations\r\n */\r\n aggressive: {\r\n maxAttempts: 5,\r\n baseDelay: 200,\r\n maxDelay: 30000,\r\n backoffMultiplier: 2,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Conservative retry for rate-limited APIs\r\n */\r\n rateLimited: {\r\n maxAttempts: 3,\r\n baseDelay: 1000,\r\n maxDelay: 60000,\r\n backoffMultiplier: 3,\r\n jitter: true,\r\n maxJitter: 500,\r\n } as Partial<RetryOptions>,\r\n\r\n /**\r\n * Database retry configuration\r\n */\r\n database: {\r\n maxAttempts: 3,\r\n baseDelay: 100,\r\n maxDelay: 5000,\r\n backoffMultiplier: 2,\r\n retryIf: (error: Error) =>\r\n RetryPredicates.networkErrors(error) || RetryPredicates.deadlockErrors(error),\r\n abortIf: RetryPredicates.validationErrors,\r\n } as Partial<RetryOptions>,\r\n};\r\n","/**\r\n * Circuit Breaker Pattern Implementation\r\n *\r\n * Prevents cascading failures by temporarily blocking calls to a failing service.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Circuit breaker states\r\n */\r\nexport type CircuitState = 'closed' | 'open' | 'half-open';\r\n\r\n/**\r\n * Options for circuit breaker behavior\r\n */\r\nexport interface CircuitBreakerOptions {\r\n /**\r\n * Name of the circuit (for logging)\r\n */\r\n name: string;\r\n\r\n /**\r\n * Number of failures before opening the circuit\r\n * @default 5\r\n */\r\n failureThreshold: number;\r\n\r\n /**\r\n * Time in milliseconds before attempting to close the circuit\r\n * @default 30000\r\n */\r\n resetTimeout: number;\r\n\r\n /**\r\n * Number of successful requests needed in half-open state to close the circuit\r\n * @default 3\r\n */\r\n successThreshold: number;\r\n\r\n /**\r\n * Time window in milliseconds for counting failures\r\n * @default 60000\r\n */\r\n failureWindow: number;\r\n\r\n /**\r\n * Function to determine if error should trip the circuit\r\n * @default All errors trip the circuit\r\n */\r\n shouldTrip?: (error: Error) => boolean;\r\n\r\n /**\r\n * Callback when circuit state changes\r\n */\r\n onStateChange?: (from: CircuitState, to: CircuitState) => void;\r\n\r\n /**\r\n * Callback when circuit opens\r\n */\r\n onOpen?: (failures: number, lastError: Error) => void;\r\n\r\n /**\r\n * Callback when circuit closes\r\n */\r\n onClose?: () => void;\r\n\r\n /**\r\n * Callback when request is rejected due to open circuit\r\n */\r\n onReject?: (state: CircuitState) => void;\r\n\r\n /**\r\n * Logger for circuit breaker events\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Default circuit breaker options\r\n */\r\nexport const DEFAULT_CIRCUIT_BREAKER_OPTIONS: Omit<CircuitBreakerOptions, 'name'> = {\r\n failureThreshold: 5,\r\n resetTimeout: 30000,\r\n successThreshold: 3,\r\n failureWindow: 60000,\r\n};\r\n\r\n/**\r\n * Error thrown when circuit is open\r\n */\r\nexport class CircuitOpenError extends Error {\r\n override readonly name = 'CircuitOpenError';\r\n readonly circuitName: string;\r\n readonly state: CircuitState;\r\n readonly nextAttemptAt: Date;\r\n\r\n constructor(circuitName: string, state: CircuitState, resetTimeout: number) {\r\n super(`Circuit \"${circuitName}\" is ${state}. Retry after ${resetTimeout}ms.`);\r\n this.circuitName = circuitName;\r\n this.state = state;\r\n this.nextAttemptAt = new Date(Date.now() + resetTimeout);\r\n }\r\n}\r\n\r\n/**\r\n * Circuit breaker statistics\r\n */\r\nexport interface CircuitBreakerStats {\r\n state: CircuitState;\r\n failures: number;\r\n successes: number;\r\n lastFailure?: Date;\r\n lastSuccess?: Date;\r\n lastStateChange?: Date;\r\n totalRequests: number;\r\n rejectedRequests: number;\r\n}\r\n\r\n/**\r\n * Circuit breaker implementation\r\n */\r\nexport class CircuitBreaker {\r\n private state: CircuitState = 'closed';\r\n private failures: number = 0;\r\n private successes: number = 0;\r\n private failureTimestamps: number[] = [];\r\n private lastFailure?: Date;\r\n private lastSuccess?: Date;\r\n private lastStateChange?: Date;\r\n private lastOpenedAt?: Date;\r\n private totalRequests: number = 0;\r\n private rejectedRequests: number = 0;\r\n private lastError?: Error;\r\n private readonly options: CircuitBreakerOptions;\r\n private readonly logger: ILogger;\r\n\r\n constructor(options: CircuitBreakerOptions) {\r\n this.options = {\r\n ...DEFAULT_CIRCUIT_BREAKER_OPTIONS,\r\n ...options,\r\n };\r\n this.logger = options.logger ?? new NoopLogger();\r\n }\r\n\r\n /**\r\n * Execute a function with circuit breaker protection\r\n */\r\n async execute<T>(fn: () => Promise<T>): Promise<T> {\r\n this.totalRequests++;\r\n\r\n // Check if circuit allows the request\r\n if (!this.canExecute()) {\r\n this.rejectedRequests++;\r\n this.options.onReject?.(this.state);\r\n\r\n throw new CircuitOpenError(\r\n this.options.name,\r\n this.state,\r\n this.getRemainingTimeout()\r\n );\r\n }\r\n\r\n try {\r\n const result = await fn();\r\n this.onSuccess();\r\n return result;\r\n } catch (error) {\r\n this.onFailure(error instanceof Error ? error : new Error(String(error)));\r\n throw error;\r\n }\r\n }\r\n\r\n /**\r\n * Check if circuit allows execution\r\n */\r\n canExecute(): boolean {\r\n switch (this.state) {\r\n case 'closed':\r\n return true;\r\n\r\n case 'open':\r\n // Check if reset timeout has passed\r\n if (this.shouldAttemptReset()) {\r\n this.transitionTo('half-open');\r\n return true;\r\n }\r\n return false;\r\n\r\n case 'half-open':\r\n // Allow limited requests in half-open state\r\n return true;\r\n\r\n default:\r\n return false;\r\n }\r\n }\r\n\r\n /**\r\n * Record a successful execution\r\n */\r\n private onSuccess(): void {\r\n this.lastSuccess = new Date();\r\n this.successes++;\r\n\r\n switch (this.state) {\r\n case 'half-open':\r\n // Check if we've had enough successes to close\r\n if (this.successes >= this.options.successThreshold) {\r\n this.transitionTo('closed');\r\n }\r\n break;\r\n\r\n case 'closed':\r\n // Reset failure count on success\r\n this.failures = 0;\r\n this.failureTimestamps = [];\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Record a failed execution\r\n */\r\n private onFailure(error: Error): void {\r\n // Check if this error should trip the circuit\r\n if (this.options.shouldTrip && !this.options.shouldTrip(error)) {\r\n return;\r\n }\r\n\r\n this.lastError = error;\r\n this.lastFailure = new Date();\r\n this.failures++;\r\n\r\n const now = Date.now();\r\n this.failureTimestamps.push(now);\r\n\r\n // Remove old failures outside the window\r\n const windowStart = now - this.options.failureWindow;\r\n this.failureTimestamps = this.failureTimestamps.filter((ts) => ts > windowStart);\r\n\r\n switch (this.state) {\r\n case 'closed':\r\n // Check if we've hit the failure threshold\r\n if (this.failureTimestamps.length >= this.options.failureThreshold) {\r\n this.transitionTo('open');\r\n this.options.onOpen?.(this.failures, error);\r\n }\r\n break;\r\n\r\n case 'half-open':\r\n // Any failure in half-open state reopens the circuit\r\n this.transitionTo('open');\r\n this.options.onOpen?.(this.failures, error);\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Transition to a new state\r\n */\r\n private transitionTo(newState: CircuitState): void {\r\n const oldState = this.state;\r\n\r\n if (oldState === newState) return;\r\n\r\n this.state = newState;\r\n this.lastStateChange = new Date();\r\n\r\n this.logger.info(`Circuit \"${this.options.name}\" state change`, {\r\n from: oldState,\r\n to: newState,\r\n failures: this.failures,\r\n successes: this.successes,\r\n });\r\n\r\n this.options.onStateChange?.(oldState, newState);\r\n\r\n switch (newState) {\r\n case 'open':\r\n this.lastOpenedAt = new Date();\r\n this.successes = 0;\r\n break;\r\n\r\n case 'half-open':\r\n this.successes = 0;\r\n break;\r\n\r\n case 'closed':\r\n this.failures = 0;\r\n this.failureTimestamps = [];\r\n this.successes = 0;\r\n this.options.onClose?.();\r\n break;\r\n }\r\n }\r\n\r\n /**\r\n * Check if reset timeout has passed\r\n */\r\n private shouldAttemptReset(): boolean {\r\n if (!this.lastOpenedAt) return true;\r\n\r\n const elapsed = Date.now() - this.lastOpenedAt.getTime();\r\n return elapsed >= this.options.resetTimeout;\r\n }\r\n\r\n /**\r\n * Get remaining time until reset attempt\r\n */\r\n private getRemainingTimeout(): number {\r\n if (!this.lastOpenedAt) return 0;\r\n\r\n const elapsed = Date.now() - this.lastOpenedAt.getTime();\r\n return Math.max(0, this.options.resetTimeout - elapsed);\r\n }\r\n\r\n /**\r\n * Get current circuit state\r\n */\r\n getState(): CircuitState {\r\n return this.state;\r\n }\r\n\r\n /**\r\n * Get circuit breaker statistics\r\n */\r\n getStats(): CircuitBreakerStats {\r\n return {\r\n state: this.state,\r\n failures: this.failures,\r\n successes: this.successes,\r\n lastFailure: this.lastFailure,\r\n lastSuccess: this.lastSuccess,\r\n lastStateChange: this.lastStateChange,\r\n totalRequests: this.totalRequests,\r\n rejectedRequests: this.rejectedRequests,\r\n };\r\n }\r\n\r\n /**\r\n * Manually reset the circuit to closed state\r\n */\r\n reset(): void {\r\n this.transitionTo('closed');\r\n }\r\n\r\n /**\r\n * Manually trip the circuit to open state\r\n */\r\n trip(): void {\r\n this.transitionTo('open');\r\n }\r\n\r\n /**\r\n * Check if circuit is open\r\n */\r\n isOpen(): boolean {\r\n return this.state === 'open';\r\n }\r\n\r\n /**\r\n * Check if circuit is closed\r\n */\r\n isClosed(): boolean {\r\n return this.state === 'closed';\r\n }\r\n\r\n /**\r\n * Check if circuit is half-open\r\n */\r\n isHalfOpen(): boolean {\r\n return this.state === 'half-open';\r\n }\r\n}\r\n\r\n/**\r\n * Create a circuit breaker\r\n */\r\nexport function createCircuitBreaker(options: CircuitBreakerOptions): CircuitBreaker {\r\n return new CircuitBreaker(options);\r\n}\r\n\r\n/**\r\n * Circuit breaker registry for managing multiple circuits\r\n */\r\nexport class CircuitBreakerRegistry {\r\n private circuits: Map<string, CircuitBreaker> = new Map();\r\n private readonly logger: ILogger;\r\n private readonly defaultOptions: Partial<CircuitBreakerOptions>;\r\n\r\n constructor(\r\n options: {\r\n logger?: ILogger;\r\n defaults?: Partial<CircuitBreakerOptions>;\r\n } = {}\r\n ) {\r\n this.logger = options.logger ?? new NoopLogger();\r\n this.defaultOptions = options.defaults ?? {};\r\n }\r\n\r\n /**\r\n * Get or create a circuit breaker\r\n */\r\n get(name: string, options?: Partial<CircuitBreakerOptions>): CircuitBreaker {\r\n let circuit = this.circuits.get(name);\r\n\r\n if (!circuit) {\r\n circuit = new CircuitBreaker({\r\n ...DEFAULT_CIRCUIT_BREAKER_OPTIONS,\r\n ...this.defaultOptions,\r\n ...options,\r\n name,\r\n logger: options?.logger ?? this.logger,\r\n });\r\n this.circuits.set(name, circuit);\r\n }\r\n\r\n return circuit;\r\n }\r\n\r\n /**\r\n * Execute with a named circuit breaker\r\n */\r\n async execute<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n options?: Partial<CircuitBreakerOptions>\r\n ): Promise<T> {\r\n const circuit = this.get(name, options);\r\n return circuit.execute(fn);\r\n }\r\n\r\n /**\r\n * Get all circuit statistics\r\n */\r\n getAllStats(): Record<string, CircuitBreakerStats> {\r\n const stats: Record<string, CircuitBreakerStats> = {};\r\n\r\n for (const [name, circuit] of this.circuits) {\r\n stats[name] = circuit.getStats();\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n /**\r\n * Reset all circuits\r\n */\r\n resetAll(): void {\r\n for (const circuit of this.circuits.values()) {\r\n circuit.reset();\r\n }\r\n }\r\n\r\n /**\r\n * Clear all circuits\r\n */\r\n clear(): void {\r\n this.circuits.clear();\r\n }\r\n}\r\n","/**\r\n * Timeout Pattern Implementation\r\n *\r\n * Enforces time limits on operations to prevent hanging.\r\n */\r\n\r\n/**\r\n * Error thrown when operation times out\r\n */\r\nexport class TimeoutError extends Error {\r\n override readonly name = 'TimeoutError';\r\n readonly operation: string;\r\n readonly timeout: number;\r\n\r\n constructor(operation: string, timeout: number) {\r\n super(`Operation \"${operation}\" timed out after ${timeout}ms`);\r\n this.operation = operation;\r\n this.timeout = timeout;\r\n }\r\n}\r\n\r\n/**\r\n * Options for timeout behavior\r\n */\r\nexport interface TimeoutOptions {\r\n /**\r\n * Timeout in milliseconds\r\n */\r\n timeout: number;\r\n\r\n /**\r\n * Operation name (for error messages)\r\n */\r\n operation?: string;\r\n\r\n /**\r\n * Whether to abort the operation on timeout (if supported)\r\n */\r\n abortOnTimeout?: boolean;\r\n}\r\n\r\n/**\r\n * Execute a function with a timeout\r\n */\r\nexport async function withTimeout<T>(\r\n fn: () => Promise<T>,\r\n options: TimeoutOptions | number\r\n): Promise<T> {\r\n const opts: TimeoutOptions =\r\n typeof options === 'number' ? { timeout: options } : options;\r\n\r\n const { timeout, operation = 'unknown', abortOnTimeout = false } = opts;\r\n\r\n return new Promise<T>((resolve, reject) => {\r\n let timeoutId: NodeJS.Timeout | undefined;\r\n let settled = false;\r\n\r\n // Create abort controller if needed\r\n const abortController = abortOnTimeout ? new AbortController() : undefined;\r\n\r\n // Set up timeout\r\n timeoutId = setTimeout(() => {\r\n if (!settled) {\r\n settled = true;\r\n abortController?.abort();\r\n reject(new TimeoutError(operation, timeout));\r\n }\r\n }, timeout);\r\n\r\n // Execute the function\r\n fn()\r\n .then((result) => {\r\n if (!settled) {\r\n settled = true;\r\n clearTimeout(timeoutId);\r\n resolve(result);\r\n }\r\n })\r\n .catch((error) => {\r\n if (!settled) {\r\n settled = true;\r\n clearTimeout(timeoutId);\r\n reject(error);\r\n }\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Create a timeout-wrapped version of a function\r\n */\r\nexport function withTimeoutWrapper<TArgs extends unknown[], TResult>(\r\n fn: (...args: TArgs) => Promise<TResult>,\r\n options: TimeoutOptions | number\r\n): (...args: TArgs) => Promise<TResult> {\r\n return (...args: TArgs) =>\r\n withTimeout(() => fn(...args), options);\r\n}\r\n\r\n/**\r\n * Race a promise against a timeout\r\n */\r\nexport async function raceTimeout<T>(\r\n promise: Promise<T>,\r\n timeout: number,\r\n operation?: string\r\n): Promise<T> {\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n setTimeout(() => {\r\n reject(new TimeoutError(operation ?? 'promise', timeout));\r\n }, timeout);\r\n });\r\n\r\n return Promise.race([promise, timeoutPromise]);\r\n}\r\n\r\n/**\r\n * Default timeouts for different operations\r\n */\r\nexport const DefaultTimeouts = {\r\n /** Quick operations like cache lookups */\r\n fast: 1000,\r\n\r\n /** Standard database queries */\r\n database: 5000,\r\n\r\n /** API calls to external services */\r\n api: 10000,\r\n\r\n /** File uploads/downloads */\r\n storage: 30000,\r\n\r\n /** Email sending */\r\n email: 15000,\r\n\r\n /** Long-running background jobs */\r\n job: 300000,\r\n};\r\n","/**\r\n * Bulkhead Pattern Implementation\r\n *\r\n * Isolates failures by limiting concurrent operations.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Options for bulkhead behavior\r\n */\r\nexport interface BulkheadOptions {\r\n /**\r\n * Name of the bulkhead (for logging)\r\n */\r\n name: string;\r\n\r\n /**\r\n * Maximum concurrent executions allowed\r\n * @default 10\r\n */\r\n maxConcurrent: number;\r\n\r\n /**\r\n * Maximum queue size for waiting requests\r\n * @default 100\r\n */\r\n maxQueue: number;\r\n\r\n /**\r\n * Timeout for queued requests in milliseconds\r\n * @default 30000\r\n */\r\n queueTimeout: number;\r\n\r\n /**\r\n * Callback when execution is rejected\r\n */\r\n onReject?: (reason: 'concurrent' | 'queue' | 'timeout') => void;\r\n\r\n /**\r\n * Logger for bulkhead events\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Default bulkhead options\r\n */\r\nexport const DEFAULT_BULKHEAD_OPTIONS: Omit<BulkheadOptions, 'name'> = {\r\n maxConcurrent: 10,\r\n maxQueue: 100,\r\n queueTimeout: 30000,\r\n};\r\n\r\n/**\r\n * Error thrown when bulkhead rejects a request\r\n */\r\nexport class BulkheadRejectedError extends Error {\r\n override readonly name = 'BulkheadRejectedError';\r\n readonly bulkheadName: string;\r\n readonly reason: 'concurrent' | 'queue' | 'timeout';\r\n\r\n constructor(bulkheadName: string, reason: 'concurrent' | 'queue' | 'timeout') {\r\n const messages = {\r\n concurrent: `Bulkhead \"${bulkheadName}\" rejected: max concurrent limit reached`,\r\n queue: `Bulkhead \"${bulkheadName}\" rejected: queue is full`,\r\n timeout: `Bulkhead \"${bulkheadName}\" rejected: queue timeout exceeded`,\r\n };\r\n super(messages[reason]);\r\n this.bulkheadName = bulkheadName;\r\n this.reason = reason;\r\n }\r\n}\r\n\r\n/**\r\n * Bulkhead statistics\r\n */\r\nexport interface BulkheadStats {\r\n activeCalls: number;\r\n queuedCalls: number;\r\n maxConcurrent: number;\r\n maxQueue: number;\r\n totalExecutions: number;\r\n rejectedCalls: number;\r\n availableSlots: number;\r\n availableQueueSlots: number;\r\n}\r\n\r\n/**\r\n * Queued request\r\n */\r\ninterface QueuedRequest<T> {\r\n fn: () => Promise<T>;\r\n resolve: (value: T) => void;\r\n reject: (error: Error) => void;\r\n enqueuedAt: number;\r\n timeoutId?: NodeJS.Timeout;\r\n}\r\n\r\n/**\r\n * Bulkhead implementation\r\n */\r\nexport class Bulkhead {\r\n private activeCalls = 0;\r\n private queue: QueuedRequest<unknown>[] = [];\r\n private totalExecutions = 0;\r\n private rejectedCalls = 0;\r\n private readonly options: Required<Omit<BulkheadOptions, 'onReject' | 'logger'>> &\r\n Pick<BulkheadOptions, 'onReject'>;\r\n private readonly logger: ILogger;\r\n\r\n constructor(options: BulkheadOptions) {\r\n this.options = {\r\n ...DEFAULT_BULKHEAD_OPTIONS,\r\n ...options,\r\n };\r\n this.logger = options.logger ?? new NoopLogger();\r\n }\r\n\r\n /**\r\n * Execute a function with bulkhead protection\r\n */\r\n async execute<T>(fn: () => Promise<T>): Promise<T> {\r\n this.totalExecutions++;\r\n\r\n // Check if we can execute immediately\r\n if (this.activeCalls < this.options.maxConcurrent) {\r\n return this.runExecution(fn);\r\n }\r\n\r\n // Check if queue is full\r\n if (this.queue.length >= this.options.maxQueue) {\r\n this.rejectedCalls++;\r\n this.options.onReject?.('queue');\r\n throw new BulkheadRejectedError(this.options.name, 'queue');\r\n }\r\n\r\n // Queue the request\r\n return this.queueExecution(fn);\r\n }\r\n\r\n /**\r\n * Run an execution immediately\r\n */\r\n private async runExecution<T>(fn: () => Promise<T>): Promise<T> {\r\n this.activeCalls++;\r\n\r\n try {\r\n const result = await fn();\r\n return result;\r\n } finally {\r\n this.activeCalls--;\r\n this.processQueue();\r\n }\r\n }\r\n\r\n /**\r\n * Queue a request for later execution\r\n */\r\n private queueExecution<T>(fn: () => Promise<T>): Promise<T> {\r\n return new Promise<T>((resolve, reject) => {\r\n const request: QueuedRequest<T> = {\r\n fn,\r\n resolve,\r\n reject,\r\n enqueuedAt: Date.now(),\r\n };\r\n\r\n // Set up timeout\r\n request.timeoutId = setTimeout(() => {\r\n const index = this.queue.indexOf(request as QueuedRequest<unknown>);\r\n if (index !== -1) {\r\n this.queue.splice(index, 1);\r\n this.rejectedCalls++;\r\n this.options.onReject?.('timeout');\r\n reject(new BulkheadRejectedError(this.options.name, 'timeout'));\r\n }\r\n }, this.options.queueTimeout);\r\n\r\n this.queue.push(request as QueuedRequest<unknown>);\r\n\r\n this.logger.debug(`Request queued in bulkhead \"${this.options.name}\"`, {\r\n queueSize: this.queue.length,\r\n activeCalls: this.activeCalls,\r\n });\r\n });\r\n }\r\n\r\n /**\r\n * Process queued requests\r\n */\r\n private processQueue(): void {\r\n while (this.activeCalls < this.options.maxConcurrent && this.queue.length > 0) {\r\n const request = this.queue.shift();\r\n if (!request) break;\r\n\r\n // Clear timeout\r\n if (request.timeoutId) {\r\n clearTimeout(request.timeoutId);\r\n }\r\n\r\n // Run the execution\r\n this.activeCalls++;\r\n\r\n request\r\n .fn()\r\n .then((result) => {\r\n request.resolve(result);\r\n })\r\n .catch((error) => {\r\n request.reject(error);\r\n })\r\n .finally(() => {\r\n this.activeCalls--;\r\n this.processQueue();\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Get bulkhead statistics\r\n */\r\n getStats(): BulkheadStats {\r\n return {\r\n activeCalls: this.activeCalls,\r\n queuedCalls: this.queue.length,\r\n maxConcurrent: this.options.maxConcurrent,\r\n maxQueue: this.options.maxQueue,\r\n totalExecutions: this.totalExecutions,\r\n rejectedCalls: this.rejectedCalls,\r\n availableSlots: Math.max(0, this.options.maxConcurrent - this.activeCalls),\r\n availableQueueSlots: Math.max(0, this.options.maxQueue - this.queue.length),\r\n };\r\n }\r\n\r\n /**\r\n * Check if bulkhead is at capacity\r\n */\r\n isAtCapacity(): boolean {\r\n return this.activeCalls >= this.options.maxConcurrent;\r\n }\r\n\r\n /**\r\n * Check if queue is full\r\n */\r\n isQueueFull(): boolean {\r\n return this.queue.length >= this.options.maxQueue;\r\n }\r\n\r\n /**\r\n * Drain the queue (reject all pending)\r\n */\r\n drain(): void {\r\n for (const request of this.queue) {\r\n if (request.timeoutId) {\r\n clearTimeout(request.timeoutId);\r\n }\r\n request.reject(new BulkheadRejectedError(this.options.name, 'queue'));\r\n }\r\n this.queue = [];\r\n }\r\n}\r\n\r\n/**\r\n * Create a bulkhead\r\n */\r\nexport function createBulkhead(options: BulkheadOptions): Bulkhead {\r\n return new Bulkhead(options);\r\n}\r\n\r\n/**\r\n * Bulkhead registry for managing multiple bulkheads\r\n */\r\nexport class BulkheadRegistry {\r\n private bulkheads: Map<string, Bulkhead> = new Map();\r\n private readonly logger: ILogger;\r\n private readonly defaultOptions: Partial<BulkheadOptions>;\r\n\r\n constructor(\r\n options: {\r\n logger?: ILogger;\r\n defaults?: Partial<BulkheadOptions>;\r\n } = {}\r\n ) {\r\n this.logger = options.logger ?? new NoopLogger();\r\n this.defaultOptions = options.defaults ?? {};\r\n }\r\n\r\n /**\r\n * Get or create a bulkhead\r\n */\r\n get(name: string, options?: Partial<BulkheadOptions>): Bulkhead {\r\n let bulkhead = this.bulkheads.get(name);\r\n\r\n if (!bulkhead) {\r\n bulkhead = new Bulkhead({\r\n ...DEFAULT_BULKHEAD_OPTIONS,\r\n ...this.defaultOptions,\r\n ...options,\r\n name,\r\n logger: options?.logger ?? this.logger,\r\n });\r\n this.bulkheads.set(name, bulkhead);\r\n }\r\n\r\n return bulkhead;\r\n }\r\n\r\n /**\r\n * Execute with a named bulkhead\r\n */\r\n async execute<T>(\r\n name: string,\r\n fn: () => Promise<T>,\r\n options?: Partial<BulkheadOptions>\r\n ): Promise<T> {\r\n const bulkhead = this.get(name, options);\r\n return bulkhead.execute(fn);\r\n }\r\n\r\n /**\r\n * Get all bulkhead statistics\r\n */\r\n getAllStats(): Record<string, BulkheadStats> {\r\n const stats: Record<string, BulkheadStats> = {};\r\n\r\n for (const [name, bulkhead] of this.bulkheads) {\r\n stats[name] = bulkhead.getStats();\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n /**\r\n * Drain all bulkheads\r\n */\r\n drainAll(): void {\r\n for (const bulkhead of this.bulkheads.values()) {\r\n bulkhead.drain();\r\n }\r\n }\r\n\r\n /**\r\n * Clear all bulkheads\r\n */\r\n clear(): void {\r\n this.drainAll();\r\n this.bulkheads.clear();\r\n }\r\n}\r\n","/**\r\n * Fallback Pattern Implementation\r\n *\r\n * Provides fallback strategies when primary operations fail.\r\n */\r\n\r\nimport type { ILogger } from '../interfaces/ILogger';\r\nimport { NoopLogger } from '../interfaces/ILogger';\r\n\r\n/**\r\n * Fallback options\r\n */\r\nexport interface FallbackOptions<T> {\r\n /**\r\n * Static fallback value\r\n */\r\n value?: T;\r\n\r\n /**\r\n * Fallback function (called with the error)\r\n */\r\n fallbackFn?: (error: Error) => T | Promise<T>;\r\n\r\n /**\r\n * Cache the fallback result\r\n */\r\n cache?: boolean;\r\n\r\n /**\r\n * Cache TTL in milliseconds\r\n */\r\n cacheTTL?: number;\r\n\r\n /**\r\n * Callback when fallback is used\r\n */\r\n onFallback?: (error: Error, fallbackValue: T) => void;\r\n\r\n /**\r\n * Errors to ignore (not trigger fallback)\r\n */\r\n ignoreErrors?: (error: Error) => boolean;\r\n\r\n /**\r\n * Logger for fallback events\r\n */\r\n logger?: ILogger;\r\n}\r\n\r\n/**\r\n * Result of a fallback operation\r\n */\r\nexport interface FallbackResult<T> {\r\n /** The result value */\r\n value: T;\r\n\r\n /** Whether fallback was used */\r\n usedFallback: boolean;\r\n\r\n /** The original error (if fallback was used) */\r\n error?: Error;\r\n\r\n /** Whether the value came from cache */\r\n cached?: boolean;\r\n}\r\n\r\n/**\r\n * Execute with fallback\r\n */\r\nexport async function withFallback<T>(\r\n fn: () => Promise<T>,\r\n options: FallbackOptions<T>\r\n): Promise<T> {\r\n const logger = options.logger ?? new NoopLogger();\r\n\r\n try {\r\n return await fn();\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n // Check if we should ignore this error\r\n if (options.ignoreErrors?.(err)) {\r\n throw err;\r\n }\r\n\r\n logger.warn('Operation failed, using fallback', {\r\n error: err,\r\n });\r\n\r\n // Get fallback value\r\n let fallbackValue: T;\r\n\r\n if (options.fallbackFn) {\r\n fallbackValue = await options.fallbackFn(err);\r\n } else if (options.value !== undefined) {\r\n fallbackValue = options.value;\r\n } else {\r\n // No fallback defined, rethrow\r\n throw err;\r\n }\r\n\r\n options.onFallback?.(err, fallbackValue);\r\n\r\n return fallbackValue;\r\n }\r\n}\r\n\r\n/**\r\n * Execute with fallback and return detailed result\r\n */\r\nexport async function withFallbackResult<T>(\r\n fn: () => Promise<T>,\r\n options: FallbackOptions<T>\r\n): Promise<FallbackResult<T>> {\r\n const logger = options.logger ?? new NoopLogger();\r\n\r\n try {\r\n const value = await fn();\r\n return {\r\n value,\r\n usedFallback: false,\r\n };\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (options.ignoreErrors?.(err)) {\r\n throw err;\r\n }\r\n\r\n logger.warn('Operation failed, using fallback', {\r\n error: err,\r\n });\r\n\r\n let fallbackValue: T;\r\n\r\n if (options.fallbackFn) {\r\n fallbackValue = await options.fallbackFn(err);\r\n } else if (options.value !== undefined) {\r\n fallbackValue = options.value;\r\n } else {\r\n throw err;\r\n }\r\n\r\n options.onFallback?.(err, fallbackValue);\r\n\r\n return {\r\n value: fallbackValue,\r\n usedFallback: true,\r\n error: err,\r\n };\r\n }\r\n}\r\n\r\n/**\r\n * Create a cached fallback\r\n */\r\nexport function createCachedFallback<T>(\r\n options: {\r\n getValue: () => Promise<T>;\r\n cacheTTL?: number;\r\n logger?: ILogger;\r\n }\r\n): () => Promise<T> {\r\n const { getValue, cacheTTL = 60000 } = options;\r\n const logger = options.logger ?? new NoopLogger();\r\n\r\n let cachedValue: T | undefined;\r\n let cachedAt: number | undefined;\r\n let refreshing = false;\r\n\r\n return async (): Promise<T> => {\r\n // Return cached value if valid\r\n if (cachedValue !== undefined && cachedAt !== undefined) {\r\n const age = Date.now() - cachedAt;\r\n if (age < cacheTTL) {\r\n return cachedValue;\r\n }\r\n\r\n // Cache expired, try to refresh in background\r\n if (!refreshing) {\r\n refreshing = true;\r\n getValue()\r\n .then((value) => {\r\n cachedValue = value;\r\n cachedAt = Date.now();\r\n })\r\n .catch((err) => {\r\n const error = err instanceof Error ? err : new Error(String(err));\r\n logger.warn('Failed to refresh cached fallback', {\r\n error,\r\n });\r\n })\r\n .finally(() => {\r\n refreshing = false;\r\n });\r\n }\r\n\r\n // Return stale cache while refreshing\r\n return cachedValue;\r\n }\r\n\r\n // No cache, get fresh value\r\n const value = await getValue();\r\n cachedValue = value;\r\n cachedAt = Date.now();\r\n return value;\r\n };\r\n}\r\n\r\n/**\r\n * Fallback chain - try multiple fallbacks in order\r\n */\r\nexport async function withFallbackChain<T>(\r\n primary: () => Promise<T>,\r\n fallbacks: Array<() => Promise<T>>,\r\n options: {\r\n logger?: ILogger;\r\n onFallback?: (index: number, error: Error) => void;\r\n } = {}\r\n): Promise<T> {\r\n const logger = options.logger ?? new NoopLogger();\r\n const allFns = [primary, ...fallbacks];\r\n\r\n for (let i = 0; i < allFns.length; i++) {\r\n try {\r\n const fn = allFns[i];\r\n if (!fn) continue;\r\n return await fn();\r\n } catch (error) {\r\n const err = error instanceof Error ? error : new Error(String(error));\r\n\r\n if (i < allFns.length - 1) {\r\n logger.warn(`Fallback ${i} failed, trying next`, {\r\n index: i,\r\n error: err,\r\n });\r\n options.onFallback?.(i, err);\r\n } else {\r\n // Last fallback failed\r\n throw err;\r\n }\r\n }\r\n }\r\n\r\n // This should never happen\r\n throw new Error('All fallbacks exhausted');\r\n}\r\n\r\n/**\r\n * Common fallback strategies\r\n */\r\nexport const FallbackStrategies = {\r\n /**\r\n * Return empty array\r\n */\r\n emptyArray: <T>(): FallbackOptions<T[]> => ({\r\n value: [],\r\n }),\r\n\r\n /**\r\n * Return null\r\n */\r\n nullable: <T>(): FallbackOptions<T | null> => ({\r\n value: null,\r\n }),\r\n\r\n /**\r\n * Return default value\r\n */\r\n defaultValue: <T>(value: T): FallbackOptions<T> => ({\r\n value,\r\n }),\r\n\r\n /**\r\n * Return cached value from a cache function\r\n */\r\n fromCache: <T>(\r\n getCached: () => Promise<T | null>,\r\n defaultValue: T\r\n ): FallbackOptions<T> => ({\r\n fallbackFn: async () => {\r\n const cached = await getCached();\r\n return cached ?? defaultValue;\r\n },\r\n }),\r\n\r\n /**\r\n * Degrade gracefully with partial data\r\n */\r\n degrade: <T>(\r\n getDegraded: (error: Error) => T\r\n ): FallbackOptions<T> => ({\r\n fallbackFn: getDegraded,\r\n }),\r\n};\r\n","/**\r\n * Health Check HTTP Endpoints\r\n *\r\n * Provides standardized health check endpoints for Kubernetes probes\r\n * and monitoring systems.\r\n *\r\n * Endpoints:\r\n * - /health/live - Liveness probe (is the process alive?)\r\n * - /health/ready - Readiness probe (can it serve traffic?)\r\n * - /health/startup - Startup probe (has it finished initializing?)\r\n * - /health - Detailed health status for dashboards\r\n */\r\n\r\nimport { IPlatform, PlatformHealthStatus } from '../interfaces';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport type HealthStatus = 'healthy' | 'degraded' | 'unhealthy';\r\n\r\nexport interface LivenessResponse {\r\n status: 'ok' | 'error';\r\n}\r\n\r\nexport interface ReadinessResponse {\r\n status: 'ok' | 'error';\r\n checks: {\r\n database: boolean;\r\n cache: boolean;\r\n storage: boolean;\r\n email: boolean;\r\n queue: boolean;\r\n };\r\n}\r\n\r\nexport interface StartupResponse {\r\n status: 'ok' | 'error';\r\n ready: boolean;\r\n}\r\n\r\nexport interface ServiceHealth {\r\n status: HealthStatus;\r\n latencyMs?: number;\r\n message?: string;\r\n lastChecked?: string;\r\n}\r\n\r\nexport interface DetailedHealthResponse {\r\n status: HealthStatus;\r\n version: string;\r\n environment: string;\r\n uptime: number;\r\n uptimeFormatted: string;\r\n timestamp: string;\r\n services: {\r\n database: ServiceHealth;\r\n cache: ServiceHealth;\r\n storage: ServiceHealth;\r\n email: ServiceHealth;\r\n queue: ServiceHealth;\r\n };\r\n system?: {\r\n memoryUsage: {\r\n heapUsed: number;\r\n heapTotal: number;\r\n external: number;\r\n rss: number;\r\n };\r\n cpuUsage?: {\r\n user: number;\r\n system: number;\r\n };\r\n };\r\n}\r\n\r\nexport interface HealthEndpoints {\r\n /**\r\n * Liveness probe - is the process alive?\r\n * Returns 200 if alive, 503 if dead.\r\n * K8s will restart the pod if this fails.\r\n */\r\n live(): Promise<LivenessResponse>;\r\n\r\n /**\r\n * Readiness probe - can it serve traffic?\r\n * Returns 200 if ready, 503 if not ready.\r\n * K8s will remove from load balancer if this fails.\r\n */\r\n ready(): Promise<ReadinessResponse>;\r\n\r\n /**\r\n * Startup probe - has it finished initializing?\r\n * Returns 200 when startup is complete.\r\n * K8s waits for this before starting liveness/readiness probes.\r\n */\r\n startup(): Promise<StartupResponse>;\r\n\r\n /**\r\n * Detailed health status for monitoring dashboards.\r\n * Includes service-level health, latencies, and system metrics.\r\n */\r\n detailed(): Promise<DetailedHealthResponse>;\r\n\r\n /**\r\n * Mark startup as complete (call after initialization)\r\n */\r\n markStartupComplete(): void;\r\n\r\n /**\r\n * Get raw health status for custom integrations\r\n */\r\n getRawStatus(): Promise<PlatformHealthStatus>;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// IMPLEMENTATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface HealthEndpointsOptions {\r\n /** Application version */\r\n version?: string;\r\n\r\n /** Environment name */\r\n environment?: string;\r\n\r\n /** Include system metrics in detailed response */\r\n includeSystemMetrics?: boolean;\r\n\r\n /** Custom health checks to include */\r\n customChecks?: Record<string, () => Promise<boolean>>;\r\n\r\n /** Timeout for individual health checks (ms) */\r\n checkTimeout?: number;\r\n}\r\n\r\nexport function createHealthEndpoints(\r\n platform: IPlatform,\r\n options: HealthEndpointsOptions = {}\r\n): HealthEndpoints {\r\n const {\r\n version = process.env.npm_package_version || process.env.APP_VERSION || 'unknown',\r\n environment = process.env.NODE_ENV || 'development',\r\n includeSystemMetrics = true,\r\n customChecks = {},\r\n checkTimeout = 5000,\r\n } = options;\r\n\r\n const startTime = Date.now();\r\n let startupComplete = false;\r\n let lastHealthCheck: PlatformHealthStatus | null = null;\r\n let lastCheckTime = 0;\r\n\r\n // Cache health check results for 1 second to avoid hammering services\r\n const CACHE_TTL = 1000;\r\n\r\n async function getCachedHealth(): Promise<PlatformHealthStatus> {\r\n const now = Date.now();\r\n if (lastHealthCheck && now - lastCheckTime < CACHE_TTL) {\r\n return lastHealthCheck;\r\n }\r\n\r\n lastHealthCheck = await withTimeout(platform.healthCheck(), checkTimeout);\r\n lastCheckTime = now;\r\n return lastHealthCheck;\r\n }\r\n\r\n async function checkServiceWithLatency(\r\n checkFn: () => Promise<boolean>\r\n ): Promise<ServiceHealth> {\r\n const start = Date.now();\r\n try {\r\n const healthy = await withTimeout(checkFn(), checkTimeout);\r\n return {\r\n status: healthy ? 'healthy' : 'unhealthy',\r\n latencyMs: Date.now() - start,\r\n lastChecked: new Date().toISOString(),\r\n };\r\n } catch (error) {\r\n return {\r\n status: 'unhealthy',\r\n latencyMs: Date.now() - start,\r\n message: error instanceof Error ? error.message : 'Unknown error',\r\n lastChecked: new Date().toISOString(),\r\n };\r\n }\r\n }\r\n\r\n function formatUptime(ms: number): string {\r\n const seconds = Math.floor(ms / 1000);\r\n const minutes = Math.floor(seconds / 60);\r\n const hours = Math.floor(minutes / 60);\r\n const days = Math.floor(hours / 24);\r\n\r\n if (days > 0) return `${days}d ${hours % 24}h ${minutes % 60}m`;\r\n if (hours > 0) return `${hours}h ${minutes % 60}m ${seconds % 60}s`;\r\n if (minutes > 0) return `${minutes}m ${seconds % 60}s`;\r\n return `${seconds}s`;\r\n }\r\n\r\n function getSystemMetrics() {\r\n if (!includeSystemMetrics) return undefined;\r\n\r\n const memoryUsage = process.memoryUsage();\r\n\r\n return {\r\n memoryUsage: {\r\n heapUsed: memoryUsage.heapUsed,\r\n heapTotal: memoryUsage.heapTotal,\r\n external: memoryUsage.external,\r\n rss: memoryUsage.rss,\r\n },\r\n };\r\n }\r\n\r\n return {\r\n async live(): Promise<LivenessResponse> {\r\n // Liveness is simple - if we can respond, we're alive\r\n return { status: 'ok' };\r\n },\r\n\r\n async ready(): Promise<ReadinessResponse> {\r\n try {\r\n const health = await getCachedHealth();\r\n\r\n // Run custom checks\r\n const customResults: Record<string, boolean> = {};\r\n for (const [name, check] of Object.entries(customChecks)) {\r\n try {\r\n customResults[name] = await withTimeout(check(), checkTimeout);\r\n } catch {\r\n customResults[name] = false;\r\n }\r\n }\r\n\r\n const allCustomHealthy = Object.values(customResults).every(Boolean);\r\n\r\n return {\r\n status: health.healthy && allCustomHealthy ? 'ok' : 'error',\r\n checks: {\r\n database: health.services.database,\r\n cache: health.services.cache,\r\n storage: health.services.storage,\r\n email: health.services.email,\r\n queue: health.services.queue,\r\n ...customResults,\r\n },\r\n };\r\n } catch {\r\n return {\r\n status: 'error',\r\n checks: {\r\n database: false,\r\n cache: false,\r\n storage: false,\r\n email: false,\r\n queue: false,\r\n },\r\n };\r\n }\r\n },\r\n\r\n async startup(): Promise<StartupResponse> {\r\n if (startupComplete) {\r\n return { status: 'ok', ready: true };\r\n }\r\n\r\n // Check if all services are ready\r\n try {\r\n const health = await getCachedHealth();\r\n if (health.healthy) {\r\n startupComplete = true;\r\n return { status: 'ok', ready: true };\r\n }\r\n } catch {\r\n // Not ready yet\r\n }\r\n\r\n return { status: 'error', ready: false };\r\n },\r\n\r\n async detailed(): Promise<DetailedHealthResponse> {\r\n const uptime = Date.now() - startTime;\r\n\r\n // Get individual service health with latencies\r\n const [dbHealth, cacheHealth, storageHealth, emailHealth, queueHealth] = await Promise.all([\r\n checkServiceWithLatency(() => platform.db.healthCheck()),\r\n checkServiceWithLatency(() => platform.cache.healthCheck()),\r\n checkServiceWithLatency(() => platform.storage.healthCheck()),\r\n checkServiceWithLatency(() => platform.email.healthCheck()),\r\n checkServiceWithLatency(() => platform.queue.healthCheck()),\r\n ]);\r\n\r\n const services = {\r\n database: dbHealth,\r\n cache: cacheHealth,\r\n storage: storageHealth,\r\n email: emailHealth,\r\n queue: queueHealth,\r\n };\r\n\r\n // Determine overall status\r\n const statuses = Object.values(services).map((s) => s.status);\r\n let overallStatus: HealthStatus = 'healthy';\r\n\r\n if (statuses.some((s) => s === 'unhealthy')) {\r\n overallStatus = 'unhealthy';\r\n } else if (statuses.some((s) => s === 'degraded')) {\r\n overallStatus = 'degraded';\r\n }\r\n\r\n return {\r\n status: overallStatus,\r\n version,\r\n environment,\r\n uptime,\r\n uptimeFormatted: formatUptime(uptime),\r\n timestamp: new Date().toISOString(),\r\n services,\r\n system: getSystemMetrics(),\r\n };\r\n },\r\n\r\n markStartupComplete(): void {\r\n startupComplete = true;\r\n },\r\n\r\n async getRawStatus(): Promise<PlatformHealthStatus> {\r\n return getCachedHealth();\r\n },\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nasync function withTimeout<T>(promise: Promise<T>, timeoutMs: number): Promise<T> {\r\n let timeoutHandle: ReturnType<typeof setTimeout>;\r\n\r\n const timeoutPromise = new Promise<never>((_, reject) => {\r\n timeoutHandle = setTimeout(() => {\r\n reject(new Error(`Health check timed out after ${timeoutMs}ms`));\r\n }, timeoutMs);\r\n });\r\n\r\n try {\r\n return await Promise.race([promise, timeoutPromise]);\r\n } finally {\r\n clearTimeout(timeoutHandle!);\r\n }\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HTTP HANDLER FACTORIES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Create Express-compatible health route handlers\r\n */\r\nexport function createExpressHealthHandlers(endpoints: HealthEndpoints) {\r\n return {\r\n live: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.live();\r\n res.status(result.status === 'ok' ? 200 : 503).json(result);\r\n },\r\n\r\n ready: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.ready();\r\n res.status(result.status === 'ok' ? 200 : 503).json(result);\r\n },\r\n\r\n startup: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.startup();\r\n res.status(result.status === 'ok' ? 200 : 503).json(result);\r\n },\r\n\r\n detailed: async (_req: unknown, res: { status: (code: number) => { json: (data: unknown) => void } }) => {\r\n const result = await endpoints.detailed();\r\n const statusCode = result.status === 'healthy' ? 200 : result.status === 'degraded' ? 200 : 503;\r\n res.status(statusCode).json(result);\r\n },\r\n };\r\n}\r\n\r\n/**\r\n * Create a simple HTTP server for health checks (standalone, no framework)\r\n */\r\nexport async function createHealthServer(\r\n endpoints: HealthEndpoints,\r\n port: number = 8080\r\n): Promise<{ close: () => Promise<void> }> {\r\n const http = await import('http');\r\n\r\n const server = http.createServer(async (req, res) => {\r\n const url = req.url || '/';\r\n\r\n res.setHeader('Content-Type', 'application/json');\r\n\r\n try {\r\n let result: unknown;\r\n let statusCode = 200;\r\n\r\n switch (url) {\r\n case '/health/live':\r\n case '/healthz':\r\n result = await endpoints.live();\r\n statusCode = (result as LivenessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/ready':\r\n case '/readyz':\r\n result = await endpoints.ready();\r\n statusCode = (result as ReadinessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/startup':\r\n case '/startupz':\r\n result = await endpoints.startup();\r\n statusCode = (result as StartupResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health':\r\n case '/':\r\n result = await endpoints.detailed();\r\n const detailed = result as DetailedHealthResponse;\r\n statusCode = detailed.status === 'healthy' ? 200 : detailed.status === 'degraded' ? 200 : 503;\r\n break;\r\n\r\n default:\r\n res.writeHead(404);\r\n res.end(JSON.stringify({ error: 'Not found' }));\r\n return;\r\n }\r\n\r\n res.writeHead(statusCode);\r\n res.end(JSON.stringify(result));\r\n } catch (error) {\r\n res.writeHead(500);\r\n res.end(JSON.stringify({ error: 'Internal server error' }));\r\n }\r\n });\r\n\r\n return new Promise((resolve) => {\r\n server.listen(port, () => {\r\n resolve({\r\n close: () =>\r\n new Promise<void>((res) => {\r\n server.close(() => res());\r\n }),\r\n });\r\n });\r\n });\r\n}\r\n","/**\r\n * Prometheus Metrics HTTP Endpoint\r\n *\r\n * Provides a /metrics endpoint that exports metrics in Prometheus text format.\r\n * This enables scraping by Prometheus, Grafana Agent, or other compatible systems.\r\n *\r\n * @example\r\n * ```typescript\r\n * import { createMetricsEndpoint } from '@digilogiclabs/platform-core';\r\n *\r\n * const metricsEndpoint = createMetricsEndpoint(platform.metrics, {\r\n * prefix: 'myapp',\r\n * defaultLabels: { service: 'api', environment: 'production' },\r\n * });\r\n *\r\n * // Get Prometheus format output\r\n * const prometheusText = metricsEndpoint.getPrometheusMetrics();\r\n *\r\n * // Or use the built-in server\r\n * const server = await createMetricsServer(metricsEndpoint, 9090);\r\n * ```\r\n */\r\n\r\nimport { IMetrics, MemoryMetrics, MetricsSummary } from '../interfaces/IMetrics';\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// TYPES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport interface MetricsEndpointOptions {\r\n /** Prefix for all metric names */\r\n prefix?: string;\r\n\r\n /** Default labels to add to all metrics */\r\n defaultLabels?: Record<string, string>;\r\n\r\n /** Include process metrics (memory, cpu, etc.) */\r\n includeProcessMetrics?: boolean;\r\n\r\n /** Include Node.js event loop metrics */\r\n includeEventLoopMetrics?: boolean;\r\n\r\n /** Histogram buckets for timing metrics */\r\n histogramBuckets?: number[];\r\n}\r\n\r\nexport interface MetricsEndpoint {\r\n /**\r\n * Get metrics in Prometheus text exposition format\r\n */\r\n getPrometheusMetrics(): string;\r\n\r\n /**\r\n * Get metrics as JSON (for debugging)\r\n */\r\n getJsonMetrics(): MetricsSummary;\r\n\r\n /**\r\n * Record a custom metric\r\n */\r\n recordMetric(type: 'counter' | 'gauge' | 'histogram', name: string, value: number, labels?: Record<string, string>): void;\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PROMETHEUS FORMAT HELPERS\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nfunction sanitizeMetricName(name: string): string {\r\n // Prometheus metric names must match [a-zA-Z_:][a-zA-Z0-9_:]*\r\n return name\r\n .replace(/[.-]/g, '_')\r\n .replace(/[^a-zA-Z0-9_:]/g, '')\r\n .replace(/^([0-9])/, '_$1');\r\n}\r\n\r\nfunction formatLabels(labels: Record<string, string>): string {\r\n const entries = Object.entries(labels);\r\n if (entries.length === 0) return '';\r\n\r\n const formatted = entries\r\n .map(([key, value]) => `${sanitizeMetricName(key)}=\"${escapeLabel(value)}\"`)\r\n .join(',');\r\n\r\n return `{${formatted}}`;\r\n}\r\n\r\nfunction escapeLabel(value: string): string {\r\n return value\r\n .replace(/\\\\/g, '\\\\\\\\')\r\n .replace(/\"/g, '\\\\\"')\r\n .replace(/\\n/g, '\\\\n');\r\n}\r\n\r\nfunction parseMetricKey(key: string): { name: string; labels: Record<string, string> } {\r\n const pipeIndex = key.indexOf('|');\r\n if (pipeIndex === -1) {\r\n return { name: key, labels: {} };\r\n }\r\n\r\n const name = key.substring(0, pipeIndex);\r\n const labelString = key.substring(pipeIndex + 1);\r\n\r\n const labels: Record<string, string> = {};\r\n for (const pair of labelString.split(',')) {\r\n const colonIndex = pair.indexOf(':');\r\n if (colonIndex !== -1) {\r\n const labelKey = pair.substring(0, colonIndex);\r\n const labelValue = pair.substring(colonIndex + 1);\r\n labels[labelKey] = labelValue;\r\n }\r\n }\r\n\r\n return { name, labels };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// PROCESS METRICS COLLECTOR\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\ninterface ProcessMetrics {\r\n memoryHeapUsed: number;\r\n memoryHeapTotal: number;\r\n memoryExternal: number;\r\n memoryRss: number;\r\n uptimeSeconds: number;\r\n cpuUserSeconds?: number;\r\n cpuSystemSeconds?: number;\r\n}\r\n\r\nfunction collectProcessMetrics(): ProcessMetrics {\r\n const memoryUsage = process.memoryUsage();\r\n\r\n return {\r\n memoryHeapUsed: memoryUsage.heapUsed,\r\n memoryHeapTotal: memoryUsage.heapTotal,\r\n memoryExternal: memoryUsage.external,\r\n memoryRss: memoryUsage.rss,\r\n uptimeSeconds: process.uptime(),\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// IMPLEMENTATION\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nexport function createMetricsEndpoint(\r\n metrics: IMetrics,\r\n options: MetricsEndpointOptions = {}\r\n): MetricsEndpoint {\r\n const {\r\n prefix = '',\r\n defaultLabels = {},\r\n includeProcessMetrics = true,\r\n histogramBuckets = [0.005, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 1, 2.5, 5, 10],\r\n } = options;\r\n\r\n const prefixName = (name: string) => (prefix ? `${prefix}_${name}` : name);\r\n\r\n function buildPrometheusOutput(summary: MetricsSummary): string {\r\n const lines: string[] = [];\r\n\r\n // Process metrics\r\n if (includeProcessMetrics) {\r\n const processMetrics = collectProcessMetrics();\r\n const processLabels = formatLabels(defaultLabels);\r\n\r\n lines.push('# HELP process_heap_bytes Node.js heap memory usage in bytes');\r\n lines.push('# TYPE process_heap_bytes gauge');\r\n lines.push(`process_heap_bytes${processLabels} ${processMetrics.memoryHeapUsed}`);\r\n\r\n lines.push('# HELP process_heap_total_bytes Node.js total heap size in bytes');\r\n lines.push('# TYPE process_heap_total_bytes gauge');\r\n lines.push(`process_heap_total_bytes${processLabels} ${processMetrics.memoryHeapTotal}`);\r\n\r\n lines.push('# HELP process_memory_rss_bytes Process resident set size in bytes');\r\n lines.push('# TYPE process_memory_rss_bytes gauge');\r\n lines.push(`process_memory_rss_bytes${processLabels} ${processMetrics.memoryRss}`);\r\n\r\n lines.push('# HELP process_uptime_seconds Process uptime in seconds');\r\n lines.push('# TYPE process_uptime_seconds counter');\r\n lines.push(`process_uptime_seconds${processLabels} ${processMetrics.uptimeSeconds}`);\r\n\r\n lines.push('');\r\n }\r\n\r\n // Counters\r\n for (const [key, value] of Object.entries(summary.counters)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name));\r\n const allLabels = { ...defaultLabels, ...labels };\r\n const labelStr = formatLabels(allLabels);\r\n\r\n lines.push(`# HELP ${metricName} Counter metric`);\r\n lines.push(`# TYPE ${metricName} counter`);\r\n lines.push(`${metricName}${labelStr} ${value}`);\r\n lines.push('');\r\n }\r\n\r\n // Gauges\r\n for (const [key, value] of Object.entries(summary.gauges)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name));\r\n const allLabels = { ...defaultLabels, ...labels };\r\n const labelStr = formatLabels(allLabels);\r\n\r\n lines.push(`# HELP ${metricName} Gauge metric`);\r\n lines.push(`# TYPE ${metricName} gauge`);\r\n lines.push(`${metricName}${labelStr} ${value}`);\r\n lines.push('');\r\n }\r\n\r\n // Histograms (with buckets)\r\n for (const [key, stats] of Object.entries(summary.histograms)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name));\r\n const allLabels = { ...defaultLabels, ...labels };\r\n\r\n lines.push(`# HELP ${metricName} Histogram metric`);\r\n lines.push(`# TYPE ${metricName} histogram`);\r\n\r\n // Note: MemoryMetrics doesn't track individual values for histogram buckets,\r\n // so we output summary statistics instead\r\n const labelStr = formatLabels(allLabels);\r\n lines.push(`${metricName}_count${labelStr} ${stats.count}`);\r\n lines.push(`${metricName}_sum${labelStr} ${stats.sum}`);\r\n lines.push('');\r\n }\r\n\r\n // Timings (as histograms with percentiles as summary)\r\n for (const [key, stats] of Object.entries(summary.timings)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name) + '_seconds');\r\n const allLabels = { ...defaultLabels, ...labels };\r\n\r\n lines.push(`# HELP ${metricName} Timing histogram (converted to seconds)`);\r\n lines.push(`# TYPE ${metricName} summary`);\r\n\r\n // Convert milliseconds to seconds for Prometheus convention\r\n const sumSeconds = stats.sum / 1000;\r\n const p50Seconds = stats.p50 / 1000;\r\n const p95Seconds = stats.p95 / 1000;\r\n const p99Seconds = stats.p99 / 1000;\r\n\r\n const p50Labels = { ...allLabels, quantile: '0.5' };\r\n const p95Labels = { ...allLabels, quantile: '0.95' };\r\n const p99Labels = { ...allLabels, quantile: '0.99' };\r\n\r\n lines.push(`${metricName}${formatLabels(p50Labels)} ${p50Seconds}`);\r\n lines.push(`${metricName}${formatLabels(p95Labels)} ${p95Seconds}`);\r\n lines.push(`${metricName}${formatLabels(p99Labels)} ${p99Seconds}`);\r\n lines.push(`${metricName}_count${formatLabels(allLabels)} ${stats.count}`);\r\n lines.push(`${metricName}_sum${formatLabels(allLabels)} ${sumSeconds}`);\r\n lines.push('');\r\n }\r\n\r\n // Sets (as gauge with cardinality)\r\n for (const [key, value] of Object.entries(summary.sets)) {\r\n const { name, labels } = parseMetricKey(key);\r\n const metricName = sanitizeMetricName(prefixName(name) + '_cardinality');\r\n const allLabels = { ...defaultLabels, ...labels };\r\n const labelStr = formatLabels(allLabels);\r\n\r\n lines.push(`# HELP ${metricName} Set cardinality (unique values)`);\r\n lines.push(`# TYPE ${metricName} gauge`);\r\n lines.push(`${metricName}${labelStr} ${value}`);\r\n lines.push('');\r\n }\r\n\r\n return lines.join('\\n');\r\n }\r\n\r\n return {\r\n getPrometheusMetrics(): string {\r\n // Get summary from MemoryMetrics if available\r\n if (metrics instanceof MemoryMetrics) {\r\n const summary = metrics.getSummary();\r\n return buildPrometheusOutput(summary);\r\n }\r\n\r\n // For other implementations, return just process metrics\r\n if (includeProcessMetrics) {\r\n const processMetrics = collectProcessMetrics();\r\n const processLabels = formatLabels(defaultLabels);\r\n\r\n return [\r\n '# HELP process_heap_bytes Node.js heap memory usage in bytes',\r\n '# TYPE process_heap_bytes gauge',\r\n `process_heap_bytes${processLabels} ${processMetrics.memoryHeapUsed}`,\r\n '',\r\n '# HELP process_heap_total_bytes Node.js total heap size in bytes',\r\n '# TYPE process_heap_total_bytes gauge',\r\n `process_heap_total_bytes${processLabels} ${processMetrics.memoryHeapTotal}`,\r\n '',\r\n '# HELP process_memory_rss_bytes Process resident set size in bytes',\r\n '# TYPE process_memory_rss_bytes gauge',\r\n `process_memory_rss_bytes${processLabels} ${processMetrics.memoryRss}`,\r\n '',\r\n '# HELP process_uptime_seconds Process uptime in seconds',\r\n '# TYPE process_uptime_seconds counter',\r\n `process_uptime_seconds${processLabels} ${processMetrics.uptimeSeconds}`,\r\n '',\r\n ].join('\\n');\r\n }\r\n\r\n return '';\r\n },\r\n\r\n getJsonMetrics(): MetricsSummary {\r\n if (metrics instanceof MemoryMetrics) {\r\n return metrics.getSummary();\r\n }\r\n\r\n return {\r\n counters: {},\r\n gauges: {},\r\n histograms: {},\r\n timings: {},\r\n sets: {},\r\n };\r\n },\r\n\r\n recordMetric(\r\n type: 'counter' | 'gauge' | 'histogram',\r\n name: string,\r\n value: number,\r\n labels: Record<string, string> = {}\r\n ): void {\r\n switch (type) {\r\n case 'counter':\r\n metrics.increment(name, value, labels);\r\n break;\r\n case 'gauge':\r\n metrics.gauge(name, value, labels);\r\n break;\r\n case 'histogram':\r\n metrics.histogram(name, value, labels);\r\n break;\r\n }\r\n },\r\n };\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// HTTP HANDLER FACTORIES\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\n/**\r\n * Create Express-compatible metrics handler\r\n */\r\nexport function createExpressMetricsHandler(endpoint: MetricsEndpoint) {\r\n return (_req: unknown, res: {\r\n setHeader: (name: string, value: string) => void;\r\n status: (code: number) => { send: (data: string) => void }\r\n }) => {\r\n res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\r\n res.status(200).send(endpoint.getPrometheusMetrics());\r\n };\r\n}\r\n\r\n/**\r\n * Create a standalone HTTP server for metrics (no framework required)\r\n */\r\nexport async function createMetricsServer(\r\n endpoint: MetricsEndpoint,\r\n port: number = 9090\r\n): Promise<{ close: () => Promise<void>; port: number }> {\r\n const http = await import('http');\r\n\r\n const server = http.createServer((req, res) => {\r\n const url = req.url || '/';\r\n\r\n if (url === '/metrics' || url === '/') {\r\n res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\r\n res.writeHead(200);\r\n res.end(endpoint.getPrometheusMetrics());\r\n } else if (url === '/metrics.json') {\r\n res.setHeader('Content-Type', 'application/json');\r\n res.writeHead(200);\r\n res.end(JSON.stringify(endpoint.getJsonMetrics(), null, 2));\r\n } else {\r\n res.writeHead(404);\r\n res.end('Not found');\r\n }\r\n });\r\n\r\n return new Promise((resolve) => {\r\n server.listen(port, () => {\r\n resolve({\r\n port,\r\n close: () =>\r\n new Promise<void>((res) => {\r\n server.close(() => res());\r\n }),\r\n });\r\n });\r\n });\r\n}\r\n\r\n// ═══════════════════════════════════════════════════════════════\r\n// COMBINED HEALTH + METRICS SERVER\r\n// ═══════════════════════════════════════════════════════════════\r\n\r\nimport type { HealthEndpoints, DetailedHealthResponse, LivenessResponse, ReadinessResponse, StartupResponse } from './health';\r\n\r\n/**\r\n * Create a combined server that serves both health and metrics endpoints\r\n *\r\n * Endpoints:\r\n * - /health/live, /healthz - Liveness probe\r\n * - /health/ready, /readyz - Readiness probe\r\n * - /health/startup, /startupz - Startup probe\r\n * - /health - Detailed health\r\n * - /metrics - Prometheus metrics\r\n * - /metrics.json - JSON metrics (debugging)\r\n */\r\nexport async function createObservabilityServer(\r\n healthEndpoints: HealthEndpoints,\r\n metricsEndpoint: MetricsEndpoint,\r\n port: number = 8080\r\n): Promise<{ close: () => Promise<void>; port: number }> {\r\n const http = await import('http');\r\n\r\n const server = http.createServer(async (req, res) => {\r\n const url = req.url || '/';\r\n\r\n try {\r\n // Metrics endpoints\r\n if (url === '/metrics') {\r\n res.setHeader('Content-Type', 'text/plain; version=0.0.4; charset=utf-8');\r\n res.writeHead(200);\r\n res.end(metricsEndpoint.getPrometheusMetrics());\r\n return;\r\n }\r\n\r\n if (url === '/metrics.json') {\r\n res.setHeader('Content-Type', 'application/json');\r\n res.writeHead(200);\r\n res.end(JSON.stringify(metricsEndpoint.getJsonMetrics(), null, 2));\r\n return;\r\n }\r\n\r\n // Health endpoints\r\n res.setHeader('Content-Type', 'application/json');\r\n\r\n let result: unknown;\r\n let statusCode = 200;\r\n\r\n switch (url) {\r\n case '/health/live':\r\n case '/healthz':\r\n result = await healthEndpoints.live();\r\n statusCode = (result as LivenessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/ready':\r\n case '/readyz':\r\n result = await healthEndpoints.ready();\r\n statusCode = (result as ReadinessResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health/startup':\r\n case '/startupz':\r\n result = await healthEndpoints.startup();\r\n statusCode = (result as StartupResponse).status === 'ok' ? 200 : 503;\r\n break;\r\n\r\n case '/health':\r\n case '/':\r\n result = await healthEndpoints.detailed();\r\n const detailed = result as DetailedHealthResponse;\r\n statusCode = detailed.status === 'healthy' ? 200 : detailed.status === 'degraded' ? 200 : 503;\r\n break;\r\n\r\n default:\r\n res.writeHead(404);\r\n res.end(JSON.stringify({ error: 'Not found' }));\r\n return;\r\n }\r\n\r\n res.writeHead(statusCode);\r\n res.end(JSON.stringify(result));\r\n } catch (error) {\r\n res.setHeader('Content-Type', 'application/json');\r\n res.writeHead(500);\r\n res.end(JSON.stringify({ error: 'Internal server error' }));\r\n }\r\n });\r\n\r\n return new Promise((resolve) => {\r\n server.listen(port, () => {\r\n resolve({\r\n port,\r\n close: () =>\r\n new Promise<void>((res) => {\r\n server.close(() => res());\r\n }),\r\n });\r\n });\r\n });\r\n}\r\n","/**\r\n * Memory Error Reporter\r\n *\r\n * Self-hosted error reporting with in-memory storage.\r\n * Perfect for development, testing, and self-hosted production.\r\n *\r\n * Features:\r\n * - No external dependencies\r\n * - Automatic correlation context integration\r\n * - Configurable retention and sampling\r\n * - Query/filter error reports\r\n */\r\n\r\nimport type {\r\n IErrorReporter,\r\n ErrorReport,\r\n ErrorLevel,\r\n Breadcrumb,\r\n CaptureOptions,\r\n ErrorReporterConfig,\r\n ErrorContext,\r\n} from '../../interfaces/IErrorReporter';\r\nimport { generateErrorId, generateFingerprint } from '../../interfaces/IErrorReporter';\r\nimport { correlationContext } from '../../context';\r\n\r\nexport interface MemoryErrorReporterConfig extends ErrorReporterConfig {\r\n /** Maximum reports to keep in memory */\r\n maxReports?: number;\r\n /** Log errors to console */\r\n logToConsole?: boolean;\r\n /** Console log level threshold */\r\n consoleLogLevel?: ErrorLevel;\r\n}\r\n\r\nconst LEVEL_PRIORITY: Record<ErrorLevel, number> = {\r\n debug: 0,\r\n info: 1,\r\n warning: 2,\r\n error: 3,\r\n fatal: 4,\r\n};\r\n\r\nexport class MemoryErrorReporter implements IErrorReporter {\r\n private reports: ErrorReport[] = [];\r\n private breadcrumbs: Breadcrumb[] = [];\r\n private userContext: { id?: string; email?: string; username?: string } | null = null;\r\n private contexts: Map<string, Record<string, unknown>> = new Map();\r\n private tags: Map<string, string> = new Map();\r\n private config: Required<MemoryErrorReporterConfig>;\r\n\r\n constructor(config: MemoryErrorReporterConfig) {\r\n this.config = {\r\n serviceName: config.serviceName,\r\n environment: config.environment ?? 'development',\r\n release: config.release ?? 'unknown',\r\n defaultTags: config.defaultTags ?? {},\r\n maxBreadcrumbs: config.maxBreadcrumbs ?? 100,\r\n captureUnhandled: config.captureUnhandled ?? false,\r\n sampleRate: config.sampleRate ?? 1.0,\r\n beforeSend: config.beforeSend ?? ((report) => report),\r\n maxReports: config.maxReports ?? 1000,\r\n logToConsole: config.logToConsole ?? true,\r\n consoleLogLevel: config.consoleLogLevel ?? 'error',\r\n };\r\n\r\n // Set up unhandled error capture if enabled\r\n if (this.config.captureUnhandled && typeof process !== 'undefined') {\r\n process.on('uncaughtException', (error) => {\r\n this.captureError(error, { handled: false, level: 'fatal' });\r\n });\r\n\r\n process.on('unhandledRejection', (reason) => {\r\n const error = reason instanceof Error ? reason : new Error(String(reason));\r\n this.captureError(error, { handled: false, level: 'error' });\r\n });\r\n }\r\n }\r\n\r\n captureError(error: Error, options?: CaptureOptions): string {\r\n // Apply sampling\r\n if (Math.random() > this.config.sampleRate) {\r\n return '';\r\n }\r\n\r\n const context = this.buildContext(options);\r\n const report = this.createReport(error, context, options);\r\n\r\n // Apply beforeSend filter\r\n const filteredReport = this.config.beforeSend(report);\r\n if (!filteredReport) {\r\n return '';\r\n }\r\n\r\n // Add breadcrumbs\r\n filteredReport.breadcrumbs = [...this.breadcrumbs];\r\n\r\n // Store report\r\n this.storeReport(filteredReport);\r\n\r\n // Log to console if enabled\r\n this.logToConsole(filteredReport);\r\n\r\n return filteredReport.id;\r\n }\r\n\r\n captureMessage(message: string, options?: CaptureOptions): string {\r\n // Apply sampling\r\n if (Math.random() > this.config.sampleRate) {\r\n return '';\r\n }\r\n\r\n const context = this.buildContext(options);\r\n const report: ErrorReport = {\r\n id: generateErrorId(),\r\n message,\r\n name: 'Message',\r\n context,\r\n level: options?.level ?? 'info',\r\n timestamp: Date.now(),\r\n handled: true,\r\n fingerprint: options?.fingerprint ?? [message],\r\n breadcrumbs: [...this.breadcrumbs],\r\n };\r\n\r\n // Apply beforeSend filter\r\n const filteredReport = this.config.beforeSend(report);\r\n if (!filteredReport) {\r\n return '';\r\n }\r\n\r\n // Store report\r\n this.storeReport(filteredReport);\r\n\r\n // Log to console if enabled\r\n this.logToConsole(filteredReport);\r\n\r\n return filteredReport.id;\r\n }\r\n\r\n addBreadcrumb(breadcrumb: Omit<Breadcrumb, 'timestamp'>): void {\r\n const crumb: Breadcrumb = {\r\n ...breadcrumb,\r\n timestamp: Date.now(),\r\n };\r\n\r\n this.breadcrumbs.push(crumb);\r\n\r\n // Trim to max breadcrumbs\r\n if (this.breadcrumbs.length > this.config.maxBreadcrumbs) {\r\n this.breadcrumbs = this.breadcrumbs.slice(-this.config.maxBreadcrumbs);\r\n }\r\n }\r\n\r\n setUser(user: { id?: string; email?: string; username?: string } | null): void {\r\n this.userContext = user;\r\n }\r\n\r\n setContext(name: string, context: Record<string, unknown> | null): void {\r\n if (context === null) {\r\n this.contexts.delete(name);\r\n } else {\r\n this.contexts.set(name, context);\r\n }\r\n }\r\n\r\n setTag(key: string, value: string): void {\r\n this.tags.set(key, value);\r\n }\r\n\r\n getReports(options?: { limit?: number; level?: ErrorLevel }): ErrorReport[] {\r\n let reports = [...this.reports];\r\n\r\n // Filter by level\r\n if (options?.level) {\r\n const minPriority = LEVEL_PRIORITY[options.level];\r\n reports = reports.filter((r) => LEVEL_PRIORITY[r.level] >= minPriority);\r\n }\r\n\r\n // Apply limit\r\n if (options?.limit) {\r\n reports = reports.slice(-options.limit);\r\n }\r\n\r\n return reports;\r\n }\r\n\r\n clearReports(): void {\r\n this.reports = [];\r\n }\r\n\r\n async flush(_timeout?: number): Promise<boolean> {\r\n // Memory reporter has no pending async operations\r\n return true;\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Clean up\r\n this.reports = [];\r\n this.breadcrumbs = [];\r\n this.contexts.clear();\r\n this.tags.clear();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // TESTING UTILITIES\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Get reports by fingerprint (for grouping analysis)\r\n */\r\n getReportsByFingerprint(): Map<string, ErrorReport[]> {\r\n const grouped = new Map<string, ErrorReport[]>();\r\n\r\n for (const report of this.reports) {\r\n const key = report.fingerprint?.join('|') ?? report.message;\r\n const existing = grouped.get(key) ?? [];\r\n existing.push(report);\r\n grouped.set(key, existing);\r\n }\r\n\r\n return grouped;\r\n }\r\n\r\n /**\r\n * Get error statistics\r\n */\r\n getStats(): {\r\n total: number;\r\n byLevel: Record<ErrorLevel, number>;\r\n uniqueErrors: number;\r\n } {\r\n const byLevel: Record<ErrorLevel, number> = {\r\n debug: 0,\r\n info: 0,\r\n warning: 0,\r\n error: 0,\r\n fatal: 0,\r\n };\r\n\r\n for (const report of this.reports) {\r\n byLevel[report.level]++;\r\n }\r\n\r\n const uniqueErrors = this.getReportsByFingerprint().size;\r\n\r\n return {\r\n total: this.reports.length,\r\n byLevel,\r\n uniqueErrors,\r\n };\r\n }\r\n\r\n /**\r\n * Find reports matching criteria\r\n */\r\n findReports(predicate: (report: ErrorReport) => boolean): ErrorReport[] {\r\n return this.reports.filter(predicate);\r\n }\r\n\r\n /**\r\n * Get the most recent report\r\n */\r\n getLastReport(): ErrorReport | undefined {\r\n return this.reports[this.reports.length - 1];\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private buildContext(options?: CaptureOptions): ErrorContext {\r\n // Get correlation context if available\r\n let correlationData: Record<string, unknown> = {};\r\n const ctx = correlationContext.get();\r\n if (ctx) {\r\n correlationData = {\r\n traceId: ctx.traceId,\r\n correlationId: ctx.correlationId,\r\n requestId: ctx.requestId,\r\n userId: ctx.userId,\r\n tenantId: ctx.tenantId,\r\n operation: ctx.operation,\r\n };\r\n }\r\n\r\n // Build extra context from stored contexts\r\n const extra: Record<string, unknown> = {};\r\n for (const [name, ctx] of this.contexts) {\r\n extra[name] = ctx;\r\n }\r\n\r\n // Build tags\r\n const tags: Record<string, string> = {\r\n ...this.config.defaultTags,\r\n };\r\n for (const [key, value] of this.tags) {\r\n tags[key] = value;\r\n }\r\n\r\n return {\r\n errorId: generateErrorId(),\r\n traceId: correlationData.traceId as string | undefined,\r\n correlationId: correlationData.correlationId as string | undefined,\r\n requestId: correlationData.requestId as string | undefined,\r\n userId: this.userContext?.id ?? (correlationData.userId as string | undefined),\r\n tenantId: correlationData.tenantId as string | undefined,\r\n operation: correlationData.operation as string | undefined,\r\n environment: this.config.environment,\r\n service: this.config.serviceName,\r\n release: this.config.release,\r\n tags: { ...tags, ...options?.tags },\r\n extra: { ...extra, ...options?.extra },\r\n };\r\n }\r\n\r\n private createReport(\r\n error: Error,\r\n context: ErrorContext,\r\n options?: CaptureOptions\r\n ): ErrorReport {\r\n return {\r\n id: generateErrorId(),\r\n message: error.message,\r\n name: error.name || 'Error',\r\n stack: error.stack,\r\n context,\r\n level: options?.level ?? 'error',\r\n timestamp: Date.now(),\r\n handled: options?.handled ?? true,\r\n fingerprint: options?.fingerprint ?? generateFingerprint(error),\r\n breadcrumbs: [],\r\n };\r\n }\r\n\r\n private storeReport(report: ErrorReport): void {\r\n this.reports.push(report);\r\n\r\n // Trim to max reports\r\n if (this.reports.length > this.config.maxReports) {\r\n this.reports = this.reports.slice(-this.config.maxReports);\r\n }\r\n }\r\n\r\n private logToConsole(report: ErrorReport): void {\r\n if (!this.config.logToConsole) return;\r\n\r\n const reportPriority = LEVEL_PRIORITY[report.level];\r\n const thresholdPriority = LEVEL_PRIORITY[this.config.consoleLogLevel];\r\n\r\n if (reportPriority < thresholdPriority) return;\r\n\r\n const prefix = `[${report.level.toUpperCase()}] [${report.id}]`;\r\n const contextStr = report.context.operation ? ` (${report.context.operation})` : '';\r\n\r\n switch (report.level) {\r\n case 'fatal':\r\n case 'error':\r\n console.error(`${prefix}${contextStr} ${report.message}`);\r\n if (report.stack) console.error(report.stack);\r\n break;\r\n case 'warning':\r\n console.warn(`${prefix}${contextStr} ${report.message}`);\r\n break;\r\n case 'info':\r\n console.info(`${prefix}${contextStr} ${report.message}`);\r\n break;\r\n case 'debug':\r\n console.debug(`${prefix}${contextStr} ${report.message}`);\r\n break;\r\n }\r\n }\r\n}\r\n","/**\r\n * Memory Audit Log Implementation\r\n *\r\n * In-memory audit log for testing and development.\r\n * Full IAuditLog compliance with query support.\r\n */\r\n\r\nimport type {\r\n IAuditLog,\r\n AuditEvent,\r\n StoredAuditEvent,\r\n AuditQuery,\r\n AuditQueryResult,\r\n AuditStats,\r\n AuditRetentionPolicy,\r\n AuditLogConfig,\r\n AuditCategory,\r\n AuditOutcome,\r\n} from '../../interfaces/IAuditLog';\r\nimport {\r\n generateAuditId,\r\n generateChecksum,\r\n matchAction,\r\n} from '../../interfaces/IAuditLog';\r\nimport { correlationContext } from '../../context';\r\n\r\nexport interface MemoryAuditLogConfig extends AuditLogConfig {\r\n /** Maximum events to store (default 10000) */\r\n maxEvents?: number;\r\n}\r\n\r\nexport class MemoryAuditLog implements IAuditLog {\r\n private events: StoredAuditEvent[] = [];\r\n private sequence = 0;\r\n private config: Required<MemoryAuditLogConfig>;\r\n\r\n constructor(config: MemoryAuditLogConfig) {\r\n this.config = {\r\n serviceName: config.serviceName,\r\n environment: config.environment ?? 'development',\r\n retention: config.retention ?? { retentionDays: 90 },\r\n enableChecksums: config.enableChecksums ?? true,\r\n idGenerator: config.idGenerator ?? generateAuditId,\r\n autoCorrelation: config.autoCorrelation ?? true,\r\n maxEvents: config.maxEvents ?? 10000,\r\n };\r\n }\r\n\r\n async log(event: AuditEvent): Promise<StoredAuditEvent> {\r\n const storedEvent = this.createStoredEvent(event);\r\n this.events.push(storedEvent);\r\n this.enforceMaxEvents();\r\n return storedEvent;\r\n }\r\n\r\n async logBatch(events: AuditEvent[]): Promise<StoredAuditEvent[]> {\r\n const storedEvents = events.map((e) => this.createStoredEvent(e));\r\n this.events.push(...storedEvents);\r\n this.enforceMaxEvents();\r\n return storedEvents;\r\n }\r\n\r\n async query(query: AuditQuery): Promise<AuditQueryResult> {\r\n const startTime = Date.now();\r\n let filtered = [...this.events];\r\n\r\n // Apply filters\r\n filtered = this.applyFilters(filtered, query);\r\n\r\n // Get total before pagination\r\n const total = filtered.length;\r\n\r\n // Apply sorting\r\n const orderBy = query.orderBy ?? 'timestamp';\r\n const order = query.order ?? 'desc';\r\n filtered.sort((a, b) => {\r\n const aVal = orderBy === 'timestamp' ? new Date(a.timestamp).getTime() : a.sequence;\r\n const bVal = orderBy === 'timestamp' ? new Date(b.timestamp).getTime() : b.sequence;\r\n return order === 'asc' ? aVal - bVal : bVal - aVal;\r\n });\r\n\r\n // Apply pagination\r\n const offset = query.offset ?? 0;\r\n const limit = Math.min(query.limit ?? 100, 1000);\r\n const paginated = filtered.slice(offset, offset + limit);\r\n\r\n return {\r\n events: paginated,\r\n total,\r\n hasMore: offset + paginated.length < total,\r\n executionTime: Date.now() - startTime,\r\n };\r\n }\r\n\r\n async getEvent(id: string): Promise<StoredAuditEvent | null> {\r\n return this.events.find((e) => e.id === id) ?? null;\r\n }\r\n\r\n async verifyIntegrity(id: string): Promise<boolean> {\r\n const event = await this.getEvent(id);\r\n if (!event) return false;\r\n\r\n if (!this.config.enableChecksums) return true;\r\n\r\n // Recreate checksum from event data\r\n const { checksum: _stored, sequence: _seq, ...eventData } = event;\r\n const computed = generateChecksum(eventData as AuditEvent);\r\n\r\n // Compare the hash portion (after 'sha256:')\r\n return event.checksum.substring(0, 16) === computed.substring(0, 16);\r\n }\r\n\r\n async getStats(): Promise<AuditStats> {\r\n const byCategory: Record<AuditCategory, number> = {\r\n authentication: 0,\r\n authorization: 0,\r\n data_access: 0,\r\n data_mutation: 0,\r\n admin_action: 0,\r\n security: 0,\r\n system: 0,\r\n billing: 0,\r\n integration: 0,\r\n custom: 0,\r\n };\r\n\r\n const byOutcome: Record<AuditOutcome, number> = {\r\n success: 0,\r\n failure: 0,\r\n denied: 0,\r\n error: 0,\r\n };\r\n\r\n for (const event of this.events) {\r\n byCategory[event.category]++;\r\n byOutcome[event.outcome]++;\r\n }\r\n\r\n const sorted = [...this.events].sort(\r\n (a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime()\r\n );\r\n\r\n return {\r\n total: this.events.length,\r\n byCategory,\r\n byOutcome,\r\n oldestEvent: sorted[0]?.timestamp,\r\n newestEvent: sorted[sorted.length - 1]?.timestamp,\r\n storageBytes: JSON.stringify(this.events).length,\r\n };\r\n }\r\n\r\n async applyRetention(policy?: AuditRetentionPolicy): Promise<number> {\r\n const retentionPolicy = policy ?? this.config.retention;\r\n if (retentionPolicy.retentionDays === 0) return 0;\r\n\r\n const cutoffDate = new Date();\r\n cutoffDate.setDate(cutoffDate.getDate() - retentionPolicy.retentionDays);\r\n const cutoffTime = cutoffDate.getTime();\r\n\r\n const exemptCategories = new Set(retentionPolicy.exemptCategories ?? []);\r\n const originalLength = this.events.length;\r\n\r\n this.events = this.events.filter((event) => {\r\n // Keep if exempt\r\n if (exemptCategories.has(event.category)) return true;\r\n // Keep if within retention period\r\n return new Date(event.timestamp).getTime() >= cutoffTime;\r\n });\r\n\r\n return originalLength - this.events.length;\r\n }\r\n\r\n async export(query: AuditQuery): Promise<StoredAuditEvent[]> {\r\n // Export without pagination limits\r\n const result = await this.query({ ...query, limit: 1000000, offset: 0 });\r\n return result.events;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async close(): Promise<void> {\r\n this.events = [];\r\n this.sequence = 0;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // TESTING UTILITIES\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Get all events (for testing)\r\n */\r\n getAll(): StoredAuditEvent[] {\r\n return [...this.events];\r\n }\r\n\r\n /**\r\n * Clear all events (for testing)\r\n */\r\n clear(): void {\r\n this.events = [];\r\n this.sequence = 0;\r\n }\r\n\r\n /**\r\n * Get event count (for testing)\r\n */\r\n get count(): number {\r\n return this.events.length;\r\n }\r\n\r\n /**\r\n * Find events by action (for testing)\r\n */\r\n findByAction(action: string): StoredAuditEvent[] {\r\n return this.events.filter((e) => e.action === action);\r\n }\r\n\r\n /**\r\n * Find events by actor ID (for testing)\r\n */\r\n findByActor(actorId: string): StoredAuditEvent[] {\r\n return this.events.filter((e) => e.actor.id === actorId);\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private createStoredEvent(event: AuditEvent): StoredAuditEvent {\r\n const id = event.id ?? this.config.idGenerator();\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n const seq = ++this.sequence;\r\n\r\n // Auto-add correlation context if enabled\r\n let context = event.context;\r\n if (this.config.autoCorrelation) {\r\n const correlationData = correlationContext.get();\r\n if (correlationData) {\r\n context = {\r\n ...context,\r\n traceId: context?.traceId ?? correlationData.traceId,\r\n correlationId: context?.correlationId ?? correlationData.correlationId,\r\n requestId: context?.requestId ?? correlationData.requestId,\r\n tenantId: context?.tenantId ?? correlationData.tenantId,\r\n };\r\n }\r\n // Add service context\r\n context = {\r\n ...context,\r\n environment: this.config.environment,\r\n service: this.config.serviceName,\r\n };\r\n }\r\n\r\n const eventWithoutChecksum: Omit<StoredAuditEvent, 'checksum' | 'sequence'> = {\r\n id,\r\n timestamp,\r\n category: event.category,\r\n action: event.action,\r\n outcome: event.outcome,\r\n actor: event.actor,\r\n target: event.target,\r\n data: event.data,\r\n changes: event.changes,\r\n error: event.error,\r\n context,\r\n };\r\n\r\n const checksum = this.config.enableChecksums\r\n ? generateChecksum(eventWithoutChecksum)\r\n : '';\r\n\r\n return {\r\n ...eventWithoutChecksum,\r\n checksum,\r\n sequence: seq,\r\n };\r\n }\r\n\r\n private applyFilters(events: StoredAuditEvent[], query: AuditQuery): StoredAuditEvent[] {\r\n return events.filter((event) => {\r\n // Category filter\r\n if (query.category) {\r\n const categories = Array.isArray(query.category) ? query.category : [query.category];\r\n if (!categories.includes(event.category)) return false;\r\n }\r\n\r\n // Action filter (supports wildcards)\r\n if (query.action) {\r\n const actions = Array.isArray(query.action) ? query.action : [query.action];\r\n if (!actions.some((pattern) => matchAction(event.action, pattern))) return false;\r\n }\r\n\r\n // Outcome filter\r\n if (query.outcome) {\r\n const outcomes = Array.isArray(query.outcome) ? query.outcome : [query.outcome];\r\n if (!outcomes.includes(event.outcome)) return false;\r\n }\r\n\r\n // Actor filters\r\n if (query.actorId && event.actor.id !== query.actorId) return false;\r\n if (query.actorType && event.actor.type !== query.actorType) return false;\r\n\r\n // Target filters\r\n if (query.targetType && event.target?.type !== query.targetType) return false;\r\n if (query.targetId && event.target?.id !== query.targetId) return false;\r\n\r\n // Context filters\r\n if (query.tenantId && event.context?.tenantId !== query.tenantId) return false;\r\n if (query.traceId && event.context?.traceId !== query.traceId) return false;\r\n if (query.correlationId && event.context?.correlationId !== query.correlationId) return false;\r\n\r\n // Time range filters\r\n if (query.from) {\r\n const fromTime = new Date(query.from).getTime();\r\n if (new Date(event.timestamp).getTime() < fromTime) return false;\r\n }\r\n if (query.to) {\r\n const toTime = new Date(query.to).getTime();\r\n if (new Date(event.timestamp).getTime() > toTime) return false;\r\n }\r\n\r\n // Data query (simple key-value matching)\r\n if (query.dataQuery && event.data) {\r\n for (const [key, value] of Object.entries(query.dataQuery)) {\r\n if (event.data[key] !== value) return false;\r\n }\r\n }\r\n\r\n return true;\r\n });\r\n }\r\n\r\n private enforceMaxEvents(): void {\r\n if (this.events.length > this.config.maxEvents) {\r\n // Remove oldest events\r\n this.events = this.events.slice(-this.config.maxEvents);\r\n }\r\n }\r\n}\r\n","/**\r\n * Memory Webhook Implementation\r\n *\r\n * In-memory webhook manager for testing.\r\n * Simulates HTTP delivery without actual network calls.\r\n */\r\n\r\nimport type {\r\n IWebhook,\r\n WebhookEndpoint,\r\n WebhookEvent,\r\n WebhookDelivery,\r\n DeliveryAttempt,\r\n CreateWebhookOptions,\r\n UpdateWebhookOptions,\r\n WebhookQuery,\r\n DeliveryQuery,\r\n WebhookStats,\r\n InboundWebhookConfig,\r\n InboundWebhookContext,\r\n VerificationResult,\r\n WebhookConfig,\r\n WebhookState,\r\n DeliveryStatus,\r\n} from '../../interfaces/IWebhook';\r\nimport {\r\n generateWebhookId,\r\n generateDeliveryId,\r\n generateEventId,\r\n generateWebhookSecret,\r\n matchEventType,\r\n} from '../../interfaces/IWebhook';\r\nimport { createHmac } from 'crypto';\r\n\r\nexport interface MemoryWebhookConfig extends WebhookConfig {\r\n /** Simulate failures for testing */\r\n failureRate?: number;\r\n /** Simulated response delay in ms */\r\n simulatedDelay?: number;\r\n}\r\n\r\nexport class MemoryWebhook implements IWebhook {\r\n private endpoints: Map<string, WebhookEndpoint> = new Map();\r\n private deliveries: Map<string, WebhookDelivery> = new Map();\r\n private inboundConfigs: Map<string, InboundWebhookConfig> = new Map();\r\n private config: Required<MemoryWebhookConfig>;\r\n\r\n // For testing - track dispatched events\r\n private dispatchedEvents: Array<{ endpoint: WebhookEndpoint; event: WebhookEvent }> = [];\r\n\r\n constructor(config: MemoryWebhookConfig = {}) {\r\n this.config = {\r\n maxRetries: config.maxRetries ?? 3,\r\n retryDelayMs: config.retryDelayMs ?? 1000,\r\n maxRetryDelayMs: config.maxRetryDelayMs ?? 3600000,\r\n backoffMultiplier: config.backoffMultiplier ?? 2,\r\n timeoutMs: config.timeoutMs ?? 30000,\r\n maxConcurrent: config.maxConcurrent ?? 10,\r\n failureThreshold: config.failureThreshold ?? 10,\r\n historyRetentionDays: config.historyRetentionDays ?? 30,\r\n userAgent: config.userAgent ?? 'DLL-Platform-Webhook/1.0',\r\n failureRate: config.failureRate ?? 0,\r\n simulatedDelay: config.simulatedDelay ?? 0,\r\n };\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // ENDPOINT MANAGEMENT\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async create(options: CreateWebhookOptions): Promise<WebhookEndpoint> {\r\n const now = new Date().toISOString();\r\n const id = options.id ?? generateWebhookId();\r\n\r\n if (this.endpoints.has(id)) {\r\n throw new Error(`Webhook endpoint already exists: ${id}`);\r\n }\r\n\r\n const endpoint: WebhookEndpoint = {\r\n id,\r\n name: options.name,\r\n description: options.description,\r\n url: options.url,\r\n secret: options.secret ?? generateWebhookSecret(),\r\n signatureAlgorithm: options.signatureAlgorithm ?? 'sha256',\r\n signatureHeader: options.signatureHeader ?? 'X-Webhook-Signature',\r\n events: options.events,\r\n state: options.paused ? 'paused' : 'active',\r\n headers: options.headers,\r\n metadata: options.metadata,\r\n tags: options.tags,\r\n createdAt: now,\r\n updatedAt: now,\r\n failureCount: 0,\r\n totalDeliveries: 0,\r\n successfulDeliveries: 0,\r\n };\r\n\r\n this.endpoints.set(id, endpoint);\r\n return endpoint;\r\n }\r\n\r\n async get(id: string): Promise<WebhookEndpoint | null> {\r\n return this.endpoints.get(id) ?? null;\r\n }\r\n\r\n async update(id: string, options: UpdateWebhookOptions): Promise<WebhookEndpoint> {\r\n const endpoint = this.endpoints.get(id);\r\n if (!endpoint) {\r\n throw new Error(`Webhook endpoint not found: ${id}`);\r\n }\r\n\r\n const updated: WebhookEndpoint = {\r\n ...endpoint,\r\n name: options.name ?? endpoint.name,\r\n description: options.description ?? endpoint.description,\r\n url: options.url ?? endpoint.url,\r\n secret: options.rotateSecret ? generateWebhookSecret() : endpoint.secret,\r\n events: options.events ?? endpoint.events,\r\n headers: options.headers ?? endpoint.headers,\r\n metadata: options.metadata ?? endpoint.metadata,\r\n tags: options.tags ?? endpoint.tags,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n\r\n this.endpoints.set(id, updated);\r\n return updated;\r\n }\r\n\r\n async delete(id: string): Promise<void> {\r\n this.endpoints.delete(id);\r\n // Also delete associated deliveries\r\n for (const [deliveryId, delivery] of this.deliveries) {\r\n if (delivery.endpointId === id) {\r\n this.deliveries.delete(deliveryId);\r\n }\r\n }\r\n }\r\n\r\n async list(query?: WebhookQuery): Promise<WebhookEndpoint[]> {\r\n let endpoints = Array.from(this.endpoints.values());\r\n\r\n // Apply filters\r\n if (query?.state) {\r\n const states = Array.isArray(query.state) ? query.state : [query.state];\r\n endpoints = endpoints.filter((e) => states.includes(e.state));\r\n }\r\n\r\n if (query?.events && query.events.length > 0) {\r\n endpoints = endpoints.filter((e) =>\r\n query.events!.some((eventType) =>\r\n e.events.some((pattern) => matchEventType(eventType, pattern))\r\n )\r\n );\r\n }\r\n\r\n if (query?.tags && query.tags.length > 0) {\r\n endpoints = endpoints.filter((e) =>\r\n query.tags!.some((tag) => e.tags?.includes(tag))\r\n );\r\n }\r\n\r\n if (query?.name) {\r\n const pattern = query.name.replace(/\\*/g, '.*');\r\n const regex = new RegExp(`^${pattern}$`, 'i');\r\n endpoints = endpoints.filter((e) => regex.test(e.name));\r\n }\r\n\r\n // Apply pagination\r\n const offset = query?.offset ?? 0;\r\n const limit = query?.limit ?? 100;\r\n return endpoints.slice(offset, offset + limit);\r\n }\r\n\r\n async pause(id: string): Promise<void> {\r\n const endpoint = this.endpoints.get(id);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${id}`);\r\n\r\n endpoint.state = 'paused';\r\n endpoint.updatedAt = new Date().toISOString();\r\n this.endpoints.set(id, endpoint);\r\n }\r\n\r\n async resume(id: string): Promise<void> {\r\n const endpoint = this.endpoints.get(id);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${id}`);\r\n\r\n endpoint.state = 'active';\r\n endpoint.failureCount = 0; // Reset failure count\r\n endpoint.updatedAt = new Date().toISOString();\r\n this.endpoints.set(id, endpoint);\r\n }\r\n\r\n async test(id: string): Promise<DeliveryAttempt> {\r\n const endpoint = this.endpoints.get(id);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${id}`);\r\n\r\n const event: WebhookEvent = {\r\n type: 'webhook.test',\r\n payload: { test: true, timestamp: new Date().toISOString() },\r\n };\r\n\r\n const attempt = await this.executeDelivery(endpoint, event, 1);\r\n return attempt;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // EVENT DELIVERY\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async dispatch<T>(event: WebhookEvent<T>): Promise<string[]> {\r\n const deliveryIds: string[] = [];\r\n const eventId = event.id ?? generateEventId();\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n\r\n const fullEvent: WebhookEvent<T> = {\r\n ...event,\r\n id: eventId,\r\n timestamp,\r\n };\r\n\r\n // Find matching endpoints\r\n const activeEndpoints = Array.from(this.endpoints.values()).filter(\r\n (e) =>\r\n e.state === 'active' &&\r\n e.events.some((pattern) => matchEventType(event.type, pattern))\r\n );\r\n\r\n for (const endpoint of activeEndpoints) {\r\n const deliveryId = await this.dispatchTo(endpoint.id, fullEvent);\r\n deliveryIds.push(deliveryId);\r\n }\r\n\r\n return deliveryIds;\r\n }\r\n\r\n async dispatchTo<T>(endpointId: string, event: WebhookEvent<T>): Promise<string> {\r\n const endpoint = this.endpoints.get(endpointId);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${endpointId}`);\r\n\r\n const eventId = event.id ?? generateEventId();\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n const deliveryId = generateDeliveryId();\r\n\r\n const fullEvent: WebhookEvent<T> = {\r\n ...event,\r\n id: eventId,\r\n timestamp,\r\n };\r\n\r\n // Track for testing\r\n this.dispatchedEvents.push({ endpoint, event: fullEvent });\r\n\r\n // Create delivery record\r\n const delivery: WebhookDelivery = {\r\n id: deliveryId,\r\n endpointId,\r\n eventId,\r\n eventType: event.type,\r\n payload: JSON.stringify(fullEvent),\r\n status: 'pending',\r\n attempts: 0,\r\n attemptHistory: [],\r\n createdAt: new Date().toISOString(),\r\n };\r\n\r\n this.deliveries.set(deliveryId, delivery);\r\n\r\n // Execute delivery with retries\r\n await this.executeWithRetries(endpoint, fullEvent, delivery);\r\n\r\n return deliveryId;\r\n }\r\n\r\n async retry(deliveryId: string): Promise<DeliveryAttempt> {\r\n const delivery = this.deliveries.get(deliveryId);\r\n if (!delivery) throw new Error(`Delivery not found: ${deliveryId}`);\r\n\r\n const endpoint = this.endpoints.get(delivery.endpointId);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${delivery.endpointId}`);\r\n\r\n const event = JSON.parse(delivery.payload) as WebhookEvent;\r\n const attempt = await this.executeDelivery(endpoint, event, delivery.attempts + 1);\r\n\r\n delivery.attempts++;\r\n delivery.attemptHistory.push(attempt);\r\n\r\n if (attempt.status === 'success') {\r\n delivery.status = 'success';\r\n delivery.completedAt = new Date().toISOString();\r\n }\r\n\r\n this.deliveries.set(deliveryId, delivery);\r\n return attempt;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // DELIVERY HISTORY\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async getDelivery(id: string): Promise<WebhookDelivery | null> {\r\n return this.deliveries.get(id) ?? null;\r\n }\r\n\r\n async listDeliveries(query?: DeliveryQuery): Promise<WebhookDelivery[]> {\r\n let deliveries = Array.from(this.deliveries.values());\r\n\r\n // Apply filters\r\n if (query?.endpointId) {\r\n deliveries = deliveries.filter((d) => d.endpointId === query.endpointId);\r\n }\r\n\r\n if (query?.eventType) {\r\n deliveries = deliveries.filter((d) => d.eventType === query.eventType);\r\n }\r\n\r\n if (query?.status) {\r\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\r\n deliveries = deliveries.filter((d) => statuses.includes(d.status));\r\n }\r\n\r\n if (query?.from) {\r\n const from = new Date(query.from).getTime();\r\n deliveries = deliveries.filter((d) => new Date(d.createdAt).getTime() >= from);\r\n }\r\n\r\n if (query?.to) {\r\n const to = new Date(query.to).getTime();\r\n deliveries = deliveries.filter((d) => new Date(d.createdAt).getTime() <= to);\r\n }\r\n\r\n // Sort by creation time (newest first)\r\n deliveries.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\r\n\r\n // Apply pagination\r\n const offset = query?.offset ?? 0;\r\n const limit = query?.limit ?? 100;\r\n return deliveries.slice(offset, offset + limit);\r\n }\r\n\r\n async getAttempts(deliveryId: string): Promise<DeliveryAttempt[]> {\r\n const delivery = this.deliveries.get(deliveryId);\r\n if (!delivery) return [];\r\n return delivery.attemptHistory;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // INBOUND WEBHOOKS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n registerInbound(config: InboundWebhookConfig): void {\r\n this.inboundConfigs.set(config.name, config);\r\n }\r\n\r\n verify(name: string, context: InboundWebhookContext): VerificationResult {\r\n const config = this.inboundConfigs.get(name);\r\n if (!config) {\r\n return { valid: false, error: `Unknown webhook: ${name}` };\r\n }\r\n\r\n // Get signature from headers\r\n const signatureHeader = config.signatureHeader ?? 'X-Webhook-Signature';\r\n const signature = context.headers[signatureHeader.toLowerCase()] ?? context.signature;\r\n\r\n if (!signature) {\r\n return { valid: false, error: 'Missing signature header' };\r\n }\r\n\r\n // Verify timestamp if configured\r\n if (config.timestampHeader) {\r\n const timestamp = context.headers[config.timestampHeader.toLowerCase()];\r\n if (timestamp) {\r\n const timestampMs = parseInt(timestamp, 10) * 1000;\r\n const now = Date.now();\r\n const tolerance = (config.timestampTolerance ?? 300) * 1000; // Default 5 minutes\r\n\r\n if (Math.abs(now - timestampMs) > tolerance) {\r\n return { valid: false, error: 'Timestamp outside tolerance window' };\r\n }\r\n }\r\n }\r\n\r\n // Compute expected signature\r\n const algorithm = config.signatureAlgorithm ?? 'sha256';\r\n const body = typeof context.rawBody === 'string'\r\n ? context.rawBody\r\n : context.rawBody.toString('utf-8');\r\n\r\n const expectedSignature = this.computeSignature(body, config.secret, algorithm);\r\n\r\n // Compare signatures\r\n const providedSig = signature.replace(/^(sha256=|sha512=|sha1=)/, '');\r\n if (providedSig !== expectedSignature) {\r\n return { valid: false, error: 'Invalid signature' };\r\n }\r\n\r\n // Parse payload\r\n try {\r\n const payload = JSON.parse(body);\r\n return { valid: true, payload };\r\n } catch {\r\n return { valid: false, error: 'Invalid JSON payload' };\r\n }\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATISTICS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async getStats(): Promise<WebhookStats> {\r\n const endpoints = Array.from(this.endpoints.values());\r\n const deliveries = Array.from(this.deliveries.values());\r\n const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);\r\n\r\n const recentDeliveries = deliveries.filter(\r\n (d) => new Date(d.createdAt) > yesterday\r\n );\r\n\r\n const successfulRecent = recentDeliveries.filter((d) => d.status === 'success');\r\n const failedRecent = recentDeliveries.filter((d) => d.status === 'failed');\r\n\r\n // Calculate average delivery time\r\n let totalDuration = 0;\r\n let durationCount = 0;\r\n for (const delivery of recentDeliveries) {\r\n for (const attempt of delivery.attemptHistory) {\r\n if (attempt.duration) {\r\n totalDuration += attempt.duration;\r\n durationCount++;\r\n }\r\n }\r\n }\r\n\r\n return {\r\n totalEndpoints: endpoints.length,\r\n activeEndpoints: endpoints.filter((e) => e.state === 'active').length,\r\n pausedEndpoints: endpoints.filter((e) => e.state === 'paused').length,\r\n failedEndpoints: endpoints.filter((e) => e.state === 'failed').length,\r\n deliveriesLast24h: recentDeliveries.length,\r\n successLast24h: successfulRecent.length,\r\n failuresLast24h: failedRecent.length,\r\n avgDeliveryTime: durationCount > 0 ? totalDuration / durationCount : 0,\r\n };\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // LIFECYCLE\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async close(): Promise<void> {\r\n this.endpoints.clear();\r\n this.deliveries.clear();\r\n this.inboundConfigs.clear();\r\n this.dispatchedEvents.length = 0;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // TESTING HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Get all dispatched events (for testing)\r\n */\r\n getDispatchedEvents(): Array<{ endpoint: WebhookEndpoint; event: WebhookEvent }> {\r\n return [...this.dispatchedEvents];\r\n }\r\n\r\n /**\r\n * Clear dispatched events (for testing)\r\n */\r\n clearDispatchedEvents(): void {\r\n this.dispatchedEvents.length = 0;\r\n }\r\n\r\n /**\r\n * Get all deliveries (for testing)\r\n */\r\n getAllDeliveries(): WebhookDelivery[] {\r\n return Array.from(this.deliveries.values());\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private async executeWithRetries(\r\n endpoint: WebhookEndpoint,\r\n event: WebhookEvent,\r\n delivery: WebhookDelivery\r\n ): Promise<void> {\r\n let attempt = 0;\r\n let lastError: string | undefined;\r\n\r\n while (attempt < this.config.maxRetries) {\r\n attempt++;\r\n const result = await this.executeDelivery(endpoint, event, attempt);\r\n\r\n delivery.attempts = attempt;\r\n delivery.attemptHistory.push(result);\r\n\r\n if (result.status === 'success') {\r\n delivery.status = 'success';\r\n delivery.completedAt = new Date().toISOString();\r\n this.updateEndpointStats(endpoint, true);\r\n this.deliveries.set(delivery.id, delivery);\r\n return;\r\n }\r\n\r\n lastError = result.error;\r\n }\r\n\r\n // All retries exhausted\r\n delivery.status = 'failed';\r\n delivery.completedAt = new Date().toISOString();\r\n this.updateEndpointStats(endpoint, false);\r\n this.deliveries.set(delivery.id, delivery);\r\n }\r\n\r\n private async executeDelivery(\r\n endpoint: WebhookEndpoint,\r\n event: WebhookEvent,\r\n attemptNumber: number\r\n ): Promise<DeliveryAttempt> {\r\n const attemptId = `att_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 8)}`;\r\n const startTime = Date.now();\r\n\r\n // Simulate network delay\r\n if (this.config.simulatedDelay > 0) {\r\n await new Promise((resolve) => setTimeout(resolve, this.config.simulatedDelay));\r\n }\r\n\r\n // Simulate failures for testing\r\n const shouldFail = Math.random() < this.config.failureRate;\r\n\r\n const duration = Date.now() - startTime;\r\n\r\n if (shouldFail) {\r\n return {\r\n id: attemptId,\r\n endpointId: endpoint.id,\r\n eventId: event.id!,\r\n eventType: event.type,\r\n attemptNumber,\r\n status: 'failed',\r\n statusCode: 500,\r\n responseBody: 'Simulated failure',\r\n duration,\r\n error: 'Simulated delivery failure',\r\n timestamp: new Date().toISOString(),\r\n };\r\n }\r\n\r\n return {\r\n id: attemptId,\r\n endpointId: endpoint.id,\r\n eventId: event.id!,\r\n eventType: event.type,\r\n attemptNumber,\r\n status: 'success',\r\n statusCode: 200,\r\n responseBody: '{\"received\": true}',\r\n duration,\r\n timestamp: new Date().toISOString(),\r\n };\r\n }\r\n\r\n private updateEndpointStats(endpoint: WebhookEndpoint, success: boolean): void {\r\n endpoint.totalDeliveries++;\r\n endpoint.lastDeliveryAt = new Date().toISOString();\r\n\r\n if (success) {\r\n endpoint.successfulDeliveries++;\r\n endpoint.lastSuccessAt = new Date().toISOString();\r\n endpoint.failureCount = 0;\r\n } else {\r\n endpoint.failureCount++;\r\n\r\n // Check if we should disable the webhook\r\n if (endpoint.failureCount >= this.config.failureThreshold) {\r\n endpoint.state = 'failed';\r\n }\r\n }\r\n\r\n endpoint.updatedAt = new Date().toISOString();\r\n this.endpoints.set(endpoint.id, endpoint);\r\n }\r\n\r\n private computeSignature(payload: string, secret: string, algorithm: string): string {\r\n return createHmac(algorithm, secret).update(payload).digest('hex');\r\n }\r\n}\r\n","/**\r\n * Memory Notification Implementation\r\n *\r\n * In-memory notification service for testing.\r\n * Stores notifications, subscriptions, and preferences in memory.\r\n */\r\n\r\nimport type {\r\n INotification,\r\n NotificationData,\r\n NotificationTarget,\r\n StoredNotification,\r\n NotificationResult,\r\n NotificationStats,\r\n NotificationQuery,\r\n NotificationPreferences,\r\n NotificationChannel,\r\n NotificationCategory,\r\n PushSubscription,\r\n SendNotificationOptions,\r\n BatchNotificationOptions,\r\n NotificationConfig,\r\n} from '../../interfaces/INotification';\r\nimport {\r\n generateNotificationId,\r\n createDefaultPreferences,\r\n filterChannelsByPreferences,\r\n} from '../../interfaces/INotification';\r\n\r\nexport interface MemoryNotificationConfig extends NotificationConfig {\r\n /** Service name */\r\n serviceName?: string;\r\n}\r\n\r\ninterface InternalConfig {\r\n defaultChannels: NotificationChannel[];\r\n defaultTtl: number;\r\n vapidKeys?: NotificationConfig['vapidKeys'];\r\n smsGateway?: NotificationConfig['smsGateway'];\r\n batchSize: number;\r\n rateLimits: Partial<Record<NotificationChannel, {\r\n perSecond?: number;\r\n perMinute?: number;\r\n perHour?: number;\r\n }>>;\r\n serviceName: string;\r\n}\r\n\r\nexport class MemoryNotification implements INotification {\r\n private notifications: Map<string, StoredNotification> = new Map();\r\n private pushSubscriptions: Map<string, PushSubscription[]> = new Map();\r\n private preferences: Map<string, NotificationPreferences> = new Map();\r\n private topics: Map<string, Set<string>> = new Map(); // topic -> userIds\r\n private userTopics: Map<string, Set<string>> = new Map(); // userId -> topics\r\n private config: InternalConfig;\r\n\r\n // For testing - track what was sent\r\n private sentNotifications: Array<{\r\n target: NotificationTarget;\r\n notification: NotificationData;\r\n channels: NotificationChannel[];\r\n result: NotificationResult;\r\n }> = [];\r\n\r\n constructor(config: MemoryNotificationConfig = {}) {\r\n this.config = {\r\n defaultChannels: config.defaultChannels ?? ['in_app'],\r\n defaultTtl: config.defaultTtl ?? 86400,\r\n vapidKeys: config.vapidKeys,\r\n smsGateway: config.smsGateway,\r\n batchSize: config.batchSize ?? 100,\r\n rateLimits: config.rateLimits ?? {},\r\n serviceName: config.serviceName ?? 'notifications',\r\n };\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // SENDING\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async send(options: SendNotificationOptions): Promise<NotificationResult> {\r\n const { target, notification, channels, force } = options;\r\n const userId = target.userId ?? 'anonymous';\r\n const id = generateNotificationId();\r\n\r\n // Get user preferences\r\n const prefs = await this.getPreferences(userId);\r\n\r\n // Determine channels to use\r\n let effectiveChannels = channels ?? this.config.defaultChannels;\r\n effectiveChannels = filterChannelsByPreferences(\r\n effectiveChannels,\r\n prefs,\r\n notification.category,\r\n force\r\n );\r\n\r\n // Create result structure\r\n const results: NotificationResult['results'] = {};\r\n\r\n // Process each channel\r\n for (const channel of effectiveChannels) {\r\n try {\r\n switch (channel) {\r\n case 'in_app':\r\n await this.storeInAppNotification(userId, id, notification, effectiveChannels);\r\n results.in_app = { success: true, messageId: id };\r\n break;\r\n\r\n case 'email':\r\n // In memory, just simulate email send\r\n if (target.email) {\r\n results.email = { success: true, messageId: `email_${id}` };\r\n } else {\r\n results.email = { success: false, error: 'No email address' };\r\n }\r\n break;\r\n\r\n case 'push':\r\n // Simulate push notification\r\n const subs = await this.getPushSubscriptions(userId);\r\n if (subs.length > 0) {\r\n results.push = { success: true, messageId: `push_${id}` };\r\n } else {\r\n results.push = { success: false, error: 'No push subscriptions' };\r\n }\r\n break;\r\n\r\n case 'sms':\r\n // Simulate SMS\r\n if (target.phone) {\r\n results.sms = { success: true, messageId: `sms_${id}` };\r\n } else {\r\n results.sms = { success: false, error: 'No phone number' };\r\n }\r\n break;\r\n }\r\n } catch (error) {\r\n results[channel] = {\r\n success: false,\r\n error: error instanceof Error ? error.message : String(error),\r\n };\r\n }\r\n }\r\n\r\n const result: NotificationResult = { id, results };\r\n\r\n // Track for testing\r\n this.sentNotifications.push({\r\n target,\r\n notification,\r\n channels: effectiveChannels,\r\n result,\r\n });\r\n\r\n return result;\r\n }\r\n\r\n async sendBatch(options: BatchNotificationOptions): Promise<NotificationResult[]> {\r\n const results: NotificationResult[] = [];\r\n\r\n for (const target of options.targets) {\r\n const result = await this.send({\r\n target,\r\n notification: options.notification,\r\n channels: options.channels,\r\n });\r\n results.push(result);\r\n }\r\n\r\n return results;\r\n }\r\n\r\n async sendToTopic(topic: string, notification: NotificationData): Promise<number> {\r\n const userIds = this.topics.get(topic);\r\n if (!userIds || userIds.size === 0) return 0;\r\n\r\n let count = 0;\r\n for (const userId of userIds) {\r\n await this.send({\r\n target: { userId },\r\n notification,\r\n });\r\n count++;\r\n }\r\n\r\n return count;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // IN-APP NOTIFICATIONS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private async storeInAppNotification(\r\n userId: string,\r\n id: string,\r\n notification: NotificationData,\r\n channels: NotificationChannel[]\r\n ): Promise<void> {\r\n const stored: StoredNotification = {\r\n id,\r\n userId,\r\n data: notification,\r\n channels,\r\n status: { in_app: 'delivered' },\r\n createdAt: new Date().toISOString(),\r\n };\r\n this.notifications.set(id, stored);\r\n }\r\n\r\n async getForUser(userId: string, query?: NotificationQuery): Promise<StoredNotification[]> {\r\n let notifications = Array.from(this.notifications.values())\r\n .filter(n => n.userId === userId);\r\n\r\n // Apply filters\r\n if (query?.category) {\r\n const categories = Array.isArray(query.category) ? query.category : [query.category];\r\n notifications = notifications.filter(n =>\r\n n.data.category && categories.includes(n.data.category)\r\n );\r\n }\r\n\r\n if (query?.unreadOnly) {\r\n notifications = notifications.filter(n => !n.readAt);\r\n }\r\n\r\n if (query?.from) {\r\n const from = new Date(query.from).getTime();\r\n notifications = notifications.filter(n =>\r\n new Date(n.createdAt).getTime() >= from\r\n );\r\n }\r\n\r\n if (query?.to) {\r\n const to = new Date(query.to).getTime();\r\n notifications = notifications.filter(n =>\r\n new Date(n.createdAt).getTime() <= to\r\n );\r\n }\r\n\r\n // Sort by creation time (newest first)\r\n notifications.sort((a, b) =>\r\n new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime()\r\n );\r\n\r\n // Apply pagination\r\n const offset = query?.offset ?? 0;\r\n const limit = query?.limit ?? 50;\r\n return notifications.slice(offset, offset + limit);\r\n }\r\n\r\n async getUnreadCount(userId: string, category?: NotificationCategory): Promise<number> {\r\n let notifications = Array.from(this.notifications.values())\r\n .filter(n => n.userId === userId && !n.readAt);\r\n\r\n if (category) {\r\n notifications = notifications.filter(n => n.data.category === category);\r\n }\r\n\r\n return notifications.length;\r\n }\r\n\r\n async markAsRead(notificationId: string): Promise<void> {\r\n const notification = this.notifications.get(notificationId);\r\n if (notification) {\r\n notification.readAt = new Date().toISOString();\r\n notification.status.in_app = 'read';\r\n this.notifications.set(notificationId, notification);\r\n }\r\n }\r\n\r\n async markAllAsRead(userId: string, category?: NotificationCategory): Promise<number> {\r\n let count = 0;\r\n const now = new Date().toISOString();\r\n\r\n for (const [id, notification] of this.notifications) {\r\n if (notification.userId === userId && !notification.readAt) {\r\n if (!category || notification.data.category === category) {\r\n notification.readAt = now;\r\n notification.status.in_app = 'read';\r\n this.notifications.set(id, notification);\r\n count++;\r\n }\r\n }\r\n }\r\n\r\n return count;\r\n }\r\n\r\n async delete(notificationId: string): Promise<void> {\r\n this.notifications.delete(notificationId);\r\n }\r\n\r\n async deleteAllForUser(userId: string): Promise<number> {\r\n let count = 0;\r\n for (const [id, notification] of this.notifications) {\r\n if (notification.userId === userId) {\r\n this.notifications.delete(id);\r\n count++;\r\n }\r\n }\r\n return count;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PUSH SUBSCRIPTIONS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async registerPushSubscription(userId: string, subscription: PushSubscription): Promise<void> {\r\n const subs = this.pushSubscriptions.get(userId) ?? [];\r\n\r\n // Check if already registered\r\n if (!subs.some(s => s.endpoint === subscription.endpoint)) {\r\n subs.push(subscription);\r\n this.pushSubscriptions.set(userId, subs);\r\n }\r\n }\r\n\r\n async removePushSubscription(userId: string, endpoint: string): Promise<void> {\r\n const subs = this.pushSubscriptions.get(userId) ?? [];\r\n const filtered = subs.filter(s => s.endpoint !== endpoint);\r\n this.pushSubscriptions.set(userId, filtered);\r\n }\r\n\r\n async getPushSubscriptions(userId: string): Promise<PushSubscription[]> {\r\n return this.pushSubscriptions.get(userId) ?? [];\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // USER PREFERENCES\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async getPreferences(userId: string): Promise<NotificationPreferences> {\r\n return this.preferences.get(userId) ?? createDefaultPreferences(userId);\r\n }\r\n\r\n async updatePreferences(userId: string, preferences: Partial<NotificationPreferences>): Promise<void> {\r\n const current = await this.getPreferences(userId);\r\n const updated: NotificationPreferences = {\r\n ...current,\r\n ...preferences,\r\n userId, // Ensure userId is correct\r\n };\r\n this.preferences.set(userId, updated);\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // TOPICS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async subscribeToTopic(userId: string, topic: string): Promise<void> {\r\n // Add to topic -> users map\r\n const topicUsers = this.topics.get(topic) ?? new Set();\r\n topicUsers.add(userId);\r\n this.topics.set(topic, topicUsers);\r\n\r\n // Add to user -> topics map\r\n const userTopics = this.userTopics.get(userId) ?? new Set();\r\n userTopics.add(topic);\r\n this.userTopics.set(userId, userTopics);\r\n }\r\n\r\n async unsubscribeFromTopic(userId: string, topic: string): Promise<void> {\r\n // Remove from topic -> users map\r\n const topicUsers = this.topics.get(topic);\r\n if (topicUsers) {\r\n topicUsers.delete(userId);\r\n }\r\n\r\n // Remove from user -> topics map\r\n const userTopics = this.userTopics.get(userId);\r\n if (userTopics) {\r\n userTopics.delete(topic);\r\n }\r\n }\r\n\r\n async getUserTopics(userId: string): Promise<string[]> {\r\n return Array.from(this.userTopics.get(userId) ?? []);\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATISTICS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async getStats(options?: { userId?: string; period?: 'day' | 'week' | 'month' }): Promise<NotificationStats> {\r\n const periodMs = {\r\n day: 24 * 60 * 60 * 1000,\r\n week: 7 * 24 * 60 * 60 * 1000,\r\n month: 30 * 24 * 60 * 60 * 1000,\r\n }[options?.period ?? 'day'];\r\n\r\n const cutoff = Date.now() - periodMs;\r\n\r\n let notifications = Array.from(this.notifications.values());\r\n\r\n if (options?.userId) {\r\n notifications = notifications.filter(n => n.userId === options.userId);\r\n }\r\n\r\n notifications = notifications.filter(n =>\r\n new Date(n.createdAt).getTime() >= cutoff\r\n );\r\n\r\n const stats: NotificationStats = {\r\n totalSent: notifications.length,\r\n byChannel: {\r\n in_app: { sent: 0, delivered: 0, read: 0, failed: 0 },\r\n email: { sent: 0, delivered: 0, read: 0, failed: 0 },\r\n push: { sent: 0, delivered: 0, read: 0, failed: 0 },\r\n sms: { sent: 0, delivered: 0, read: 0, failed: 0 },\r\n },\r\n byCategory: {},\r\n unreadCount: 0,\r\n };\r\n\r\n for (const n of notifications) {\r\n // Count by channel\r\n for (const channel of n.channels) {\r\n const channelStats = stats.byChannel[channel]!;\r\n channelStats.sent++;\r\n const status = n.status[channel];\r\n if (status === 'delivered') channelStats.delivered++;\r\n if (status === 'read') channelStats.read++;\r\n if (status === 'failed') channelStats.failed++;\r\n }\r\n\r\n // Count by category\r\n const cat = n.data.category ?? 'other';\r\n stats.byCategory[cat] = (stats.byCategory[cat] ?? 0) + 1;\r\n\r\n // Count unread\r\n if (!n.readAt) {\r\n stats.unreadCount++;\r\n }\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // LIFECYCLE\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return true;\r\n }\r\n\r\n async close(): Promise<void> {\r\n this.notifications.clear();\r\n this.pushSubscriptions.clear();\r\n this.preferences.clear();\r\n this.topics.clear();\r\n this.userTopics.clear();\r\n this.sentNotifications.length = 0;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // TESTING HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Get all sent notifications (for testing)\r\n */\r\n getSentNotifications(): Array<{\r\n target: NotificationTarget;\r\n notification: NotificationData;\r\n channels: NotificationChannel[];\r\n result: NotificationResult;\r\n }> {\r\n return [...this.sentNotifications];\r\n }\r\n\r\n /**\r\n * Clear sent notifications (for testing)\r\n */\r\n clearSentNotifications(): void {\r\n this.sentNotifications.length = 0;\r\n }\r\n\r\n /**\r\n * Get all stored notifications (for testing)\r\n */\r\n getAllNotifications(): StoredNotification[] {\r\n return Array.from(this.notifications.values());\r\n }\r\n}\r\n","export { SupabaseDatabase, type SupabaseDatabaseConfig } from './SupabaseDatabase';\r\n","/**\r\n * PostgreSQL Database Adapter\r\n *\r\n * Direct PostgreSQL connection with true transaction support.\r\n */\r\n\r\nexport { PostgresDatabase, type PostgresConfig } from './PostgresDatabase';\r\n","export { UpstashCache, type UpstashCacheConfig } from './UpstashCache';\r\n","/**\r\n * Redis Direct Cache Adapter\r\n *\r\n * Direct Redis connection with full feature support including pub/sub.\r\n */\r\n\r\nexport { RedisCache, type RedisConfig } from './RedisCache';\r\n","export { S3Storage, type S3StorageConfig } from './S3Storage';\r\n","/**\r\n * Supabase Storage Adapter\r\n *\r\n * File storage via Supabase Storage buckets.\r\n */\r\n\r\nexport { SupabaseStorage, type SupabaseStorageConfig } from './SupabaseStorage';\r\n","export { ResendEmail, type ResendEmailConfig } from './ResendEmail';\r\n","/**\r\n * SMTP Email Adapter\r\n *\r\n * Standard SMTP email sending via nodemailer.\r\n */\r\n\r\nexport { SmtpEmail, type SmtpConfig } from './SmtpEmail';\r\n","export { BullMQQueue, type BullMQConfig } from './BullMQQueue';\r\n","/**\r\n * Database Audit Log Implementation\r\n *\r\n * Production-ready audit log using IDatabase abstraction.\r\n * Self-hosted, no vendor lock-in.\r\n *\r\n * Requires a table with this schema:\r\n *\r\n * CREATE TABLE audit_logs (\r\n * id VARCHAR(255) PRIMARY KEY,\r\n * sequence BIGSERIAL,\r\n * timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n * category VARCHAR(50) NOT NULL,\r\n * action VARCHAR(255) NOT NULL,\r\n * outcome VARCHAR(20) NOT NULL,\r\n * actor JSONB NOT NULL,\r\n * target JSONB,\r\n * data JSONB,\r\n * changes JSONB,\r\n * error JSONB,\r\n * context JSONB,\r\n * checksum VARCHAR(255),\r\n * created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\r\n * );\r\n *\r\n * CREATE INDEX idx_audit_logs_timestamp ON audit_logs(timestamp DESC);\r\n * CREATE INDEX idx_audit_logs_category ON audit_logs(category);\r\n * CREATE INDEX idx_audit_logs_action ON audit_logs(action);\r\n * CREATE INDEX idx_audit_logs_actor_id ON audit_logs((actor->>'id'));\r\n * CREATE INDEX idx_audit_logs_tenant_id ON audit_logs((context->>'tenantId'));\r\n */\r\n\r\nimport type { IDatabase } from '../../interfaces/IDatabase';\r\nimport type {\r\n IAuditLog,\r\n AuditEvent,\r\n StoredAuditEvent,\r\n AuditQuery,\r\n AuditQueryResult,\r\n AuditStats,\r\n AuditRetentionPolicy,\r\n AuditLogConfig,\r\n AuditCategory,\r\n AuditOutcome,\r\n} from '../../interfaces/IAuditLog';\r\nimport {\r\n generateAuditId,\r\n generateChecksum,\r\n matchAction,\r\n} from '../../interfaces/IAuditLog';\r\nimport { correlationContext } from '../../context';\r\n\r\nexport interface DatabaseAuditLogConfig extends AuditLogConfig {\r\n /** Database instance */\r\n database: IDatabase;\r\n /** Table name (default: 'audit_logs') */\r\n tableName?: string;\r\n /** Batch size for bulk operations */\r\n batchSize?: number;\r\n}\r\n\r\ninterface AuditLogRow {\r\n id: string;\r\n sequence: number;\r\n timestamp: string;\r\n category: string;\r\n action: string;\r\n outcome: string;\r\n actor: string | Record<string, unknown>; // JSON\r\n target?: string | Record<string, unknown>; // JSON\r\n data?: string | Record<string, unknown>; // JSON\r\n changes?: string | Record<string, unknown>; // JSON\r\n error?: string | Record<string, unknown>; // JSON\r\n context?: string | Record<string, unknown>; // JSON\r\n checksum?: string;\r\n}\r\n\r\nexport class DatabaseAuditLog implements IAuditLog {\r\n private db: IDatabase;\r\n private tableName: string;\r\n private config: Required<Omit<DatabaseAuditLogConfig, 'database' | 'tableName'>>;\r\n private sequence = 0;\r\n\r\n constructor(config: DatabaseAuditLogConfig) {\r\n this.db = config.database;\r\n this.tableName = config.tableName ?? 'audit_logs';\r\n this.config = {\r\n serviceName: config.serviceName,\r\n environment: config.environment ?? 'production',\r\n retention: config.retention ?? { retentionDays: 365 },\r\n enableChecksums: config.enableChecksums ?? true,\r\n idGenerator: config.idGenerator ?? generateAuditId,\r\n autoCorrelation: config.autoCorrelation ?? true,\r\n batchSize: config.batchSize ?? 100,\r\n };\r\n }\r\n\r\n async log(event: AuditEvent): Promise<StoredAuditEvent> {\r\n const prepared = this.prepareEvent(event);\r\n const seq = ++this.sequence;\r\n\r\n await this.db\r\n .from(this.tableName)\r\n .insert({\r\n id: prepared.id,\r\n timestamp: prepared.timestamp,\r\n category: prepared.category,\r\n action: prepared.action,\r\n outcome: prepared.outcome,\r\n actor: JSON.stringify(prepared.actor),\r\n target: prepared.target ? JSON.stringify(prepared.target) : null,\r\n data: prepared.data ? JSON.stringify(prepared.data) : null,\r\n changes: prepared.changes ? JSON.stringify(prepared.changes) : null,\r\n error: prepared.error ? JSON.stringify(prepared.error) : null,\r\n context: prepared.context ? JSON.stringify(prepared.context) : null,\r\n checksum: prepared.checksum,\r\n })\r\n .execute();\r\n\r\n return { ...prepared, sequence: seq };\r\n }\r\n\r\n async logBatch(events: AuditEvent[]): Promise<StoredAuditEvent[]> {\r\n const results: StoredAuditEvent[] = [];\r\n\r\n // Process in batches\r\n for (let i = 0; i < events.length; i += this.config.batchSize) {\r\n const batch = events.slice(i, i + this.config.batchSize);\r\n\r\n for (const event of batch) {\r\n const stored = await this.log(event);\r\n results.push(stored);\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n async query(query: AuditQuery): Promise<AuditQueryResult> {\r\n const startTime = Date.now();\r\n\r\n // Build query\r\n let queryBuilder = this.db.from<AuditLogRow>(this.tableName);\r\n\r\n // Apply filters\r\n if (query.category) {\r\n const categories = Array.isArray(query.category) ? query.category : [query.category];\r\n queryBuilder = queryBuilder.whereIn('category', categories);\r\n }\r\n\r\n if (query.action) {\r\n const actions = Array.isArray(query.action) ? query.action : [query.action];\r\n // For now, exact match only (wildcards handled in post-processing for complex patterns)\r\n const exactActions = actions.filter((a) => !a.includes('*'));\r\n if (exactActions.length > 0) {\r\n queryBuilder = queryBuilder.whereIn('action', exactActions);\r\n }\r\n }\r\n\r\n if (query.outcome) {\r\n const outcomes = Array.isArray(query.outcome) ? query.outcome : [query.outcome];\r\n queryBuilder = queryBuilder.whereIn('outcome', outcomes);\r\n }\r\n\r\n if (query.from) {\r\n queryBuilder = queryBuilder.where('timestamp', '>=', new Date(query.from).toISOString());\r\n }\r\n\r\n if (query.to) {\r\n queryBuilder = queryBuilder.where('timestamp', '<=', new Date(query.to).toISOString());\r\n }\r\n\r\n // Get total count first\r\n const countResult = await this.db.raw<{ count: string }>(\r\n `SELECT COUNT(*) as count FROM ${this.tableName}`\r\n );\r\n const total = parseInt(String(countResult.data[0]?.count ?? 0), 10);\r\n\r\n // Apply sorting\r\n const orderBy = query.orderBy ?? 'timestamp';\r\n const order = query.order ?? 'desc';\r\n queryBuilder = queryBuilder.orderBy(orderBy, order);\r\n\r\n // Apply pagination\r\n const offset = query.offset ?? 0;\r\n const limit = Math.min(query.limit ?? 100, 1000);\r\n queryBuilder = queryBuilder.limit(limit).offset(offset);\r\n\r\n // Execute query\r\n const result = await queryBuilder.execute();\r\n let events = result.data.map((row: AuditLogRow) => this.rowToEvent(row));\r\n\r\n // Post-process for wildcard action patterns\r\n if (query.action) {\r\n const actions = Array.isArray(query.action) ? query.action : [query.action];\r\n const wildcardActions = actions.filter((a) => a.includes('*'));\r\n if (wildcardActions.length > 0) {\r\n events = events.filter((e) =>\r\n wildcardActions.some((pattern) => matchAction(e.action, pattern))\r\n );\r\n }\r\n }\r\n\r\n // Post-process for JSON field filters (actor, target, context)\r\n if (query.actorId) {\r\n events = events.filter((e) => e.actor.id === query.actorId);\r\n }\r\n if (query.actorType) {\r\n events = events.filter((e) => e.actor.type === query.actorType);\r\n }\r\n if (query.targetType) {\r\n events = events.filter((e) => e.target?.type === query.targetType);\r\n }\r\n if (query.targetId) {\r\n events = events.filter((e) => e.target?.id === query.targetId);\r\n }\r\n if (query.tenantId) {\r\n events = events.filter((e) => e.context?.tenantId === query.tenantId);\r\n }\r\n if (query.traceId) {\r\n events = events.filter((e) => e.context?.traceId === query.traceId);\r\n }\r\n if (query.correlationId) {\r\n events = events.filter((e) => e.context?.correlationId === query.correlationId);\r\n }\r\n\r\n return {\r\n events,\r\n total,\r\n hasMore: offset + events.length < total,\r\n executionTime: Date.now() - startTime,\r\n };\r\n }\r\n\r\n async getEvent(id: string): Promise<StoredAuditEvent | null> {\r\n const result = await this.db\r\n .from<AuditLogRow>(this.tableName)\r\n .where('id', '=', id)\r\n .execute();\r\n\r\n const row = result.data[0];\r\n if (!row) return null;\r\n return this.rowToEvent(row);\r\n }\r\n\r\n async verifyIntegrity(id: string): Promise<boolean> {\r\n const event = await this.getEvent(id);\r\n if (!event) return false;\r\n if (!this.config.enableChecksums || !event.checksum) return true;\r\n\r\n const { checksum: _stored, sequence: _seq, ...eventData } = event;\r\n const computed = generateChecksum(eventData as AuditEvent);\r\n\r\n // Compare hash prefix\r\n return event.checksum.substring(0, 16) === computed.substring(0, 16);\r\n }\r\n\r\n async getStats(): Promise<AuditStats> {\r\n // Get counts by category\r\n const categoryResult = await this.db.raw<{ category: string; count: string }>(\r\n `SELECT category, COUNT(*) as count FROM ${this.tableName} GROUP BY category`\r\n );\r\n\r\n const byCategory: Record<AuditCategory, number> = {\r\n authentication: 0,\r\n authorization: 0,\r\n data_access: 0,\r\n data_mutation: 0,\r\n admin_action: 0,\r\n security: 0,\r\n system: 0,\r\n billing: 0,\r\n integration: 0,\r\n custom: 0,\r\n };\r\n\r\n for (const row of categoryResult.data) {\r\n byCategory[row.category as AuditCategory] = parseInt(row.count, 10);\r\n }\r\n\r\n // Get counts by outcome\r\n const outcomeResult = await this.db.raw<{ outcome: string; count: string }>(\r\n `SELECT outcome, COUNT(*) as count FROM ${this.tableName} GROUP BY outcome`\r\n );\r\n\r\n const byOutcome: Record<AuditOutcome, number> = {\r\n success: 0,\r\n failure: 0,\r\n denied: 0,\r\n error: 0,\r\n };\r\n\r\n for (const row of outcomeResult.data) {\r\n byOutcome[row.outcome as AuditOutcome] = parseInt(row.count, 10);\r\n }\r\n\r\n // Get total and time range\r\n const statsResult = await this.db.raw<{ total: string; oldest: string; newest: string }>(\r\n `SELECT COUNT(*) as total, MIN(timestamp) as oldest, MAX(timestamp) as newest FROM ${this.tableName}`\r\n );\r\n\r\n const stats = statsResult.data[0];\r\n\r\n return {\r\n total: parseInt(stats?.total ?? '0', 10),\r\n byCategory,\r\n byOutcome,\r\n oldestEvent: stats?.oldest,\r\n newestEvent: stats?.newest,\r\n };\r\n }\r\n\r\n async applyRetention(policy?: AuditRetentionPolicy): Promise<number> {\r\n const retentionPolicy = policy ?? this.config.retention;\r\n if (retentionPolicy.retentionDays === 0) return 0;\r\n\r\n const cutoffDate = new Date();\r\n cutoffDate.setDate(cutoffDate.getDate() - retentionPolicy.retentionDays);\r\n\r\n let sql = `DELETE FROM ${this.tableName} WHERE timestamp < $1`;\r\n const params: unknown[] = [cutoffDate.toISOString()];\r\n\r\n // Exempt categories\r\n if (retentionPolicy.exemptCategories && retentionPolicy.exemptCategories.length > 0) {\r\n const placeholders = retentionPolicy.exemptCategories.map((_, i) => `$${i + 2}`).join(', ');\r\n sql += ` AND category NOT IN (${placeholders})`;\r\n params.push(...retentionPolicy.exemptCategories);\r\n }\r\n\r\n const result = await this.db.raw(sql, params);\r\n return result.count ?? 0;\r\n }\r\n\r\n async export(query: AuditQuery): Promise<StoredAuditEvent[]> {\r\n // Export all matching events\r\n const allEvents: StoredAuditEvent[] = [];\r\n let offset = 0;\r\n const batchSize = 1000;\r\n\r\n while (true) {\r\n const result = await this.query({ ...query, limit: batchSize, offset });\r\n allEvents.push(...result.events);\r\n\r\n if (!result.hasMore) break;\r\n offset += batchSize;\r\n }\r\n\r\n return allEvents;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n try {\r\n await this.db.raw(`SELECT 1 FROM ${this.tableName} LIMIT 1`);\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n\r\n async close(): Promise<void> {\r\n // Database connection is managed externally\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATIC HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * SQL to create the audit_logs table (PostgreSQL)\r\n */\r\n static getCreateTableSQL(tableName: string = 'audit_logs'): string {\r\n return `\r\nCREATE TABLE IF NOT EXISTS ${tableName} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n sequence BIGSERIAL,\r\n timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n category VARCHAR(50) NOT NULL,\r\n action VARCHAR(255) NOT NULL,\r\n outcome VARCHAR(20) NOT NULL,\r\n actor JSONB NOT NULL,\r\n target JSONB,\r\n data JSONB,\r\n changes JSONB,\r\n error JSONB,\r\n context JSONB,\r\n checksum VARCHAR(255),\r\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_timestamp ON ${tableName}(timestamp DESC);\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_category ON ${tableName}(category);\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_action ON ${tableName}(action);\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_outcome ON ${tableName}(outcome);\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_actor_id ON ${tableName}((actor->>'id'));\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_tenant_id ON ${tableName}((context->>'tenantId'));\r\nCREATE INDEX IF NOT EXISTS idx_${tableName}_trace_id ON ${tableName}((context->>'traceId'));\r\n `.trim();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private prepareEvent(event: AuditEvent): Omit<StoredAuditEvent, 'sequence'> {\r\n const id = event.id ?? this.config.idGenerator();\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n\r\n // Auto-add correlation context\r\n let context = event.context;\r\n if (this.config.autoCorrelation) {\r\n const correlationData = correlationContext.get();\r\n if (correlationData) {\r\n context = {\r\n ...context,\r\n traceId: context?.traceId ?? correlationData.traceId,\r\n correlationId: context?.correlationId ?? correlationData.correlationId,\r\n requestId: context?.requestId ?? correlationData.requestId,\r\n tenantId: context?.tenantId ?? correlationData.tenantId,\r\n };\r\n }\r\n context = {\r\n ...context,\r\n environment: this.config.environment,\r\n service: this.config.serviceName,\r\n };\r\n }\r\n\r\n const eventWithoutChecksum = {\r\n id,\r\n timestamp,\r\n category: event.category,\r\n action: event.action,\r\n outcome: event.outcome,\r\n actor: event.actor,\r\n target: event.target,\r\n data: event.data,\r\n changes: event.changes,\r\n error: event.error,\r\n context,\r\n };\r\n\r\n const checksum = this.config.enableChecksums\r\n ? generateChecksum(eventWithoutChecksum)\r\n : '';\r\n\r\n return {\r\n ...eventWithoutChecksum,\r\n checksum,\r\n };\r\n }\r\n\r\n private rowToEvent(row: AuditLogRow): StoredAuditEvent {\r\n const parseJson = (value: string | Record<string, unknown> | undefined | null): Record<string, unknown> | undefined => {\r\n if (value === undefined || value === null) return undefined;\r\n if (typeof value === 'string') {\r\n try {\r\n return JSON.parse(value) as Record<string, unknown>;\r\n } catch {\r\n return undefined;\r\n }\r\n }\r\n return value;\r\n };\r\n\r\n const actorData = parseJson(row.actor);\r\n const targetData = parseJson(row.target);\r\n const changesData = parseJson(row.changes);\r\n const errorData = parseJson(row.error);\r\n const contextData = parseJson(row.context);\r\n\r\n return {\r\n id: row.id,\r\n sequence: row.sequence ?? 0,\r\n timestamp: row.timestamp,\r\n category: row.category as AuditCategory,\r\n action: row.action,\r\n outcome: row.outcome as AuditOutcome,\r\n actor: {\r\n type: (actorData?.type as 'user' | 'service' | 'system' | 'anonymous') ?? 'unknown' as const,\r\n id: actorData?.id as string | undefined,\r\n name: actorData?.name as string | undefined,\r\n email: actorData?.email as string | undefined,\r\n ip: actorData?.ip as string | undefined,\r\n userAgent: actorData?.userAgent as string | undefined,\r\n sessionId: actorData?.sessionId as string | undefined,\r\n },\r\n target: targetData ? {\r\n type: targetData.type as string,\r\n id: targetData.id as string | undefined,\r\n name: targetData.name as string | undefined,\r\n attributes: targetData.attributes as Record<string, unknown> | undefined,\r\n } : undefined,\r\n data: parseJson(row.data),\r\n changes: changesData ? {\r\n before: changesData.before as Record<string, unknown> | undefined,\r\n after: changesData.after as Record<string, unknown> | undefined,\r\n } : undefined,\r\n error: errorData ? {\r\n code: errorData.code as string | undefined,\r\n message: errorData.message as string | undefined,\r\n stack: errorData.stack as string | undefined,\r\n } : undefined,\r\n context: contextData ? {\r\n traceId: contextData.traceId as string | undefined,\r\n correlationId: contextData.correlationId as string | undefined,\r\n requestId: contextData.requestId as string | undefined,\r\n tenantId: contextData.tenantId as string | undefined,\r\n environment: contextData.environment as string | undefined,\r\n service: contextData.service as string | undefined,\r\n } : undefined,\r\n checksum: row.checksum ?? '',\r\n };\r\n }\r\n}\r\n","/**\r\n * Database Error Reporter Implementation\r\n *\r\n * Self-hosted error reporting using database storage.\r\n * No external service dependencies, full data ownership.\r\n *\r\n * Features:\r\n * - Error capture and storage\r\n * - Stack trace parsing\r\n * - Breadcrumb trail\r\n * - User context\r\n * - Error grouping by fingerprint\r\n * - Retention policy\r\n */\r\n\r\nimport type { IDatabase } from '../../interfaces/IDatabase';\r\nimport type {\r\n IErrorReporter,\r\n ErrorReport,\r\n ErrorContext,\r\n ErrorLevel,\r\n Breadcrumb,\r\n CaptureOptions,\r\n ErrorReporterConfig,\r\n} from '../../interfaces/IErrorReporter';\r\nimport {\r\n generateErrorId,\r\n generateFingerprint,\r\n createErrorReport,\r\n} from '../../interfaces/IErrorReporter';\r\nimport { correlationContext } from '../../context';\r\nimport { createHash } from 'crypto';\r\n\r\nexport interface DatabaseErrorReporterConfig extends ErrorReporterConfig {\r\n /** Database instance */\r\n database: IDatabase;\r\n /** Table name for errors (default: 'error_reports') */\r\n errorsTable?: string;\r\n /** Table name for breadcrumbs (default: 'error_breadcrumbs') */\r\n breadcrumbsTable?: string;\r\n /** Max stack trace length to store */\r\n maxStackTraceLength?: number;\r\n /** Retention period in days */\r\n retentionDays?: number;\r\n}\r\n\r\ninterface ErrorRow {\r\n id: string;\r\n level: string;\r\n message: string;\r\n name: string;\r\n stack?: string;\r\n fingerprint: string;\r\n context: string;\r\n handled: boolean;\r\n created_at: number;\r\n}\r\n\r\ninterface BreadcrumbRow {\r\n id: string;\r\n error_id: string;\r\n category: string;\r\n message: string;\r\n level?: string;\r\n data?: string;\r\n timestamp: number;\r\n}\r\n\r\nexport class DatabaseErrorReporter implements IErrorReporter {\r\n private db: IDatabase;\r\n private errorsTable: string;\r\n private breadcrumbsTable: string;\r\n private maxStackTraceLength: number;\r\n private retentionDays: number;\r\n\r\n private breadcrumbs: Breadcrumb[] = [];\r\n private reports: ErrorReport[] = [];\r\n private context: ErrorContext = {};\r\n private tags: Record<string, string> = {};\r\n private userContext: { id?: string; email?: string; username?: string } | null = null;\r\n private maxBreadcrumbs: number;\r\n private sampleRate: number;\r\n private beforeSend?: (report: ErrorReport) => ErrorReport | null;\r\n\r\n // Queue for async database writes\r\n private writeQueue: Promise<void> = Promise.resolve();\r\n\r\n constructor(config: DatabaseErrorReporterConfig) {\r\n this.db = config.database;\r\n this.errorsTable = config.errorsTable ?? 'error_reports';\r\n this.breadcrumbsTable = config.breadcrumbsTable ?? 'error_breadcrumbs';\r\n this.maxStackTraceLength = config.maxStackTraceLength ?? 10000;\r\n this.retentionDays = config.retentionDays ?? 90;\r\n this.maxBreadcrumbs = config.maxBreadcrumbs ?? 100;\r\n this.sampleRate = config.sampleRate ?? 1.0;\r\n this.beforeSend = config.beforeSend;\r\n\r\n // Initialize context from config\r\n this.context = {\r\n service: config.serviceName,\r\n environment: config.environment ?? 'development',\r\n release: config.release,\r\n };\r\n\r\n if (config.defaultTags) {\r\n this.tags = { ...config.defaultTags };\r\n }\r\n }\r\n\r\n captureError(error: Error, options?: CaptureOptions): string {\r\n // Check sample rate\r\n if (Math.random() > this.sampleRate) {\r\n return '';\r\n }\r\n\r\n const ctx = correlationContext.get();\r\n\r\n // Build context\r\n const fullContext: ErrorContext = {\r\n ...this.context,\r\n ...options?.context,\r\n correlationId: ctx?.correlationId ?? this.context.correlationId,\r\n traceId: ctx?.traceId ?? this.context.traceId,\r\n userId: this.userContext?.id ?? this.context.userId,\r\n tags: { ...this.tags, ...options?.tags },\r\n extra: options?.extra,\r\n };\r\n\r\n // Create report\r\n let report = createErrorReport(error, fullContext, {\r\n ...options,\r\n fingerprint: options?.fingerprint ?? generateFingerprint(error),\r\n });\r\n\r\n // Add current breadcrumbs\r\n report.breadcrumbs = [...this.breadcrumbs];\r\n\r\n // Apply beforeSend filter\r\n if (this.beforeSend) {\r\n const filtered = this.beforeSend(report);\r\n if (!filtered) return '';\r\n report = filtered;\r\n }\r\n\r\n // Store in memory\r\n this.reports.push(report);\r\n\r\n // Truncate stack if needed\r\n if (report.stack && report.stack.length > this.maxStackTraceLength) {\r\n report.stack = report.stack.substring(0, this.maxStackTraceLength);\r\n }\r\n\r\n // Queue async database write\r\n this.queueWrite(report);\r\n\r\n return report.id;\r\n }\r\n\r\n captureMessage(message: string, options?: CaptureOptions): string {\r\n // Check sample rate\r\n if (Math.random() > this.sampleRate) {\r\n return '';\r\n }\r\n\r\n const ctx = correlationContext.get();\r\n const id = generateErrorId();\r\n\r\n // Build context\r\n const fullContext: ErrorContext = {\r\n ...this.context,\r\n ...options?.context,\r\n correlationId: ctx?.correlationId ?? this.context.correlationId,\r\n traceId: ctx?.traceId ?? this.context.traceId,\r\n userId: this.userContext?.id ?? this.context.userId,\r\n tags: { ...this.tags, ...options?.tags },\r\n extra: options?.extra,\r\n };\r\n\r\n let report: ErrorReport = {\r\n id,\r\n message,\r\n name: 'Message',\r\n context: fullContext,\r\n level: options?.level ?? 'info',\r\n timestamp: Date.now(),\r\n handled: options?.handled ?? true,\r\n fingerprint: options?.fingerprint ?? [message],\r\n breadcrumbs: [...this.breadcrumbs],\r\n };\r\n\r\n // Apply beforeSend filter\r\n if (this.beforeSend) {\r\n const filtered = this.beforeSend(report);\r\n if (!filtered) return '';\r\n report = filtered;\r\n }\r\n\r\n // Store in memory\r\n this.reports.push(report);\r\n\r\n // Queue async database write\r\n this.queueWrite(report);\r\n\r\n return id;\r\n }\r\n\r\n addBreadcrumb(breadcrumb: Omit<Breadcrumb, 'timestamp'>): void {\r\n const crumb: Breadcrumb = {\r\n ...breadcrumb,\r\n timestamp: Date.now(),\r\n };\r\n\r\n this.breadcrumbs.push(crumb);\r\n\r\n // Trim to max breadcrumbs\r\n if (this.breadcrumbs.length > this.maxBreadcrumbs) {\r\n this.breadcrumbs = this.breadcrumbs.slice(-this.maxBreadcrumbs);\r\n }\r\n }\r\n\r\n setUser(user: { id?: string; email?: string; username?: string } | null): void {\r\n this.userContext = user;\r\n }\r\n\r\n setContext(name: string, context: Record<string, unknown> | null): void {\r\n if (context === null) {\r\n // Remove context\r\n const { [name]: _, ...rest } = this.context.extra ?? {};\r\n this.context.extra = Object.keys(rest).length > 0 ? rest as Record<string, unknown> : undefined;\r\n } else {\r\n // Add/update context\r\n this.context.extra = {\r\n ...this.context.extra,\r\n [name]: context,\r\n };\r\n }\r\n }\r\n\r\n setTag(key: string, value: string): void {\r\n this.tags[key] = value;\r\n }\r\n\r\n getReports(options?: { limit?: number; level?: ErrorLevel }): ErrorReport[] {\r\n let reports = [...this.reports];\r\n\r\n if (options?.level) {\r\n reports = reports.filter((r) => r.level === options.level);\r\n }\r\n\r\n // Sort by timestamp descending\r\n reports.sort((a, b) => b.timestamp - a.timestamp);\r\n\r\n if (options?.limit) {\r\n reports = reports.slice(0, options.limit);\r\n }\r\n\r\n return reports;\r\n }\r\n\r\n clearReports(): void {\r\n this.reports = [];\r\n }\r\n\r\n async flush(timeout?: number): Promise<boolean> {\r\n // Wait for all queued writes with optional timeout\r\n if (timeout) {\r\n return Promise.race([\r\n this.writeQueue.then(() => true),\r\n new Promise<boolean>((resolve) => setTimeout(() => resolve(false), timeout)),\r\n ]);\r\n }\r\n\r\n await this.writeQueue;\r\n return true;\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.flush();\r\n this.reports = [];\r\n this.breadcrumbs = [];\r\n this.context = {};\r\n this.tags = {};\r\n this.userContext = null;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // DATABASE QUERY METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * Load reports from database\r\n */\r\n async loadReports(options?: {\r\n level?: ErrorLevel;\r\n from?: Date | number;\r\n to?: Date | number;\r\n limit?: number;\r\n offset?: number;\r\n }): Promise<ErrorReport[]> {\r\n let builder = this.db.from(this.errorsTable);\r\n\r\n if (options?.level) {\r\n builder = builder.where('level', '=', options.level);\r\n }\r\n if (options?.from) {\r\n const fromTs = typeof options.from === 'number' ? options.from : options.from.getTime();\r\n builder = builder.where('created_at', '>=', fromTs);\r\n }\r\n if (options?.to) {\r\n const toTs = typeof options.to === 'number' ? options.to : options.to.getTime();\r\n builder = builder.where('created_at', '<=', toTs);\r\n }\r\n\r\n builder = builder.orderBy('created_at', 'desc');\r\n\r\n if (options?.limit) {\r\n builder = builder.limit(options.limit);\r\n }\r\n\r\n const result = await builder.execute();\r\n const reports: ErrorReport[] = [];\r\n\r\n for (const row of result.data as ErrorRow[]) {\r\n const breadcrumbs = await this.loadBreadcrumbs(row.id);\r\n reports.push(this.rowToReport(row, breadcrumbs));\r\n }\r\n\r\n return reports;\r\n }\r\n\r\n /**\r\n * Clean up old errors based on retention policy\r\n */\r\n async cleanup(): Promise<number> {\r\n const cutoff = Date.now() - this.retentionDays * 24 * 60 * 60 * 1000;\r\n\r\n // Get IDs of old errors\r\n const oldErrors = await this.db\r\n .from(this.errorsTable)\r\n .where('created_at', '<', cutoff)\r\n .execute();\r\n\r\n const ids = (oldErrors.data as ErrorRow[]).map((r) => r.id);\r\n\r\n if (ids.length === 0) return 0;\r\n\r\n // Delete breadcrumbs for old errors\r\n for (const id of ids) {\r\n await this.db\r\n .from(this.breadcrumbsTable)\r\n .where('error_id', '=', id)\r\n .delete()\r\n .execute();\r\n }\r\n\r\n // Delete old errors\r\n await this.db\r\n .from(this.errorsTable)\r\n .where('created_at', '<', cutoff)\r\n .delete()\r\n .execute();\r\n\r\n return ids.length;\r\n }\r\n\r\n /**\r\n * Get error statistics\r\n */\r\n async getStats(periodMs: number = 24 * 60 * 60 * 1000): Promise<{\r\n total: number;\r\n byLevel: Record<ErrorLevel, number>;\r\n recentErrors: number;\r\n }> {\r\n const cutoff = Date.now() - periodMs;\r\n\r\n const allErrors = await this.db.from(this.errorsTable).execute();\r\n const recentErrors = await this.db\r\n .from(this.errorsTable)\r\n .where('created_at', '>', cutoff)\r\n .execute();\r\n\r\n const errors = allErrors.data as ErrorRow[];\r\n const byLevel: Record<ErrorLevel, number> = {\r\n fatal: 0,\r\n error: 0,\r\n warning: 0,\r\n info: 0,\r\n debug: 0,\r\n };\r\n\r\n for (const error of errors) {\r\n const level = error.level as ErrorLevel;\r\n byLevel[level] = (byLevel[level] ?? 0) + 1;\r\n }\r\n\r\n return {\r\n total: errors.length,\r\n byLevel,\r\n recentErrors: recentErrors.data.length,\r\n };\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATIC HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * SQL to create error reporter tables (PostgreSQL)\r\n */\r\n static getCreateTableSQL(\r\n errorsTable = 'error_reports',\r\n breadcrumbsTable = 'error_breadcrumbs'\r\n ): string {\r\n return `\r\nCREATE TABLE IF NOT EXISTS ${errorsTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n level VARCHAR(20) NOT NULL,\r\n message TEXT NOT NULL,\r\n name VARCHAR(255) NOT NULL,\r\n stack TEXT,\r\n fingerprint TEXT NOT NULL,\r\n context JSONB,\r\n handled BOOLEAN NOT NULL DEFAULT true,\r\n created_at BIGINT NOT NULL\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${errorsTable}_level ON ${errorsTable}(level);\r\nCREATE INDEX IF NOT EXISTS idx_${errorsTable}_created ON ${errorsTable}(created_at DESC);\r\n\r\nCREATE TABLE IF NOT EXISTS ${breadcrumbsTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n error_id VARCHAR(255) NOT NULL REFERENCES ${errorsTable}(id) ON DELETE CASCADE,\r\n category VARCHAR(100) NOT NULL,\r\n message TEXT NOT NULL,\r\n level VARCHAR(20),\r\n data JSONB,\r\n timestamp BIGINT NOT NULL\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${breadcrumbsTable}_error ON ${breadcrumbsTable}(error_id);\r\n `.trim();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private queueWrite(report: ErrorReport): void {\r\n this.writeQueue = this.writeQueue.then(async () => {\r\n try {\r\n await this.writeReportToDb(report);\r\n } catch (error) {\r\n // Log but don't throw - errors in error reporting shouldn't crash the app\r\n console.error('Failed to write error report to database:', error);\r\n }\r\n });\r\n }\r\n\r\n private async writeReportToDb(report: ErrorReport): Promise<void> {\r\n // Insert error\r\n await this.db.from(this.errorsTable).insert({\r\n id: report.id,\r\n level: report.level,\r\n message: report.message,\r\n name: report.name,\r\n stack: report.stack,\r\n fingerprint: JSON.stringify(report.fingerprint ?? []),\r\n context: JSON.stringify(report.context),\r\n handled: report.handled,\r\n created_at: report.timestamp,\r\n }).execute();\r\n\r\n // Insert breadcrumbs\r\n if (report.breadcrumbs && report.breadcrumbs.length > 0) {\r\n for (const crumb of report.breadcrumbs) {\r\n await this.db.from(this.breadcrumbsTable).insert({\r\n id: `bc_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 8)}`,\r\n error_id: report.id,\r\n category: crumb.category,\r\n message: crumb.message,\r\n level: crumb.level,\r\n data: crumb.data ? JSON.stringify(crumb.data) : undefined,\r\n timestamp: crumb.timestamp,\r\n }).execute();\r\n }\r\n }\r\n }\r\n\r\n private async loadBreadcrumbs(errorId: string): Promise<Breadcrumb[]> {\r\n const result = await this.db\r\n .from(this.breadcrumbsTable)\r\n .where('error_id', '=', errorId)\r\n .orderBy('timestamp', 'asc')\r\n .execute();\r\n\r\n return (result.data as BreadcrumbRow[]).map((row) => ({\r\n category: row.category,\r\n message: row.message,\r\n level: row.level as ErrorLevel | undefined,\r\n data: row.data ? (typeof row.data === 'string' ? JSON.parse(row.data) : row.data) : undefined,\r\n timestamp: row.timestamp,\r\n }));\r\n }\r\n\r\n private rowToReport(row: ErrorRow, breadcrumbs: Breadcrumb[]): ErrorReport {\r\n const context = row.context\r\n ? (typeof row.context === 'string' ? JSON.parse(row.context) : row.context)\r\n : {};\r\n\r\n const fingerprint = row.fingerprint\r\n ? (typeof row.fingerprint === 'string' ? JSON.parse(row.fingerprint) : row.fingerprint)\r\n : [];\r\n\r\n return {\r\n id: row.id,\r\n message: row.message,\r\n name: row.name,\r\n stack: row.stack,\r\n context,\r\n level: row.level as ErrorLevel,\r\n timestamp: row.created_at,\r\n handled: row.handled,\r\n fingerprint: Array.isArray(fingerprint) ? fingerprint : [fingerprint],\r\n breadcrumbs,\r\n };\r\n }\r\n}\r\n","/**\r\n * Queue-based Scheduler Implementation\r\n *\r\n * Scheduler built on top of IQueue for job execution.\r\n * Self-hosted, uses database for persistence.\r\n *\r\n * Features:\r\n * - Cron-based recurring jobs\r\n * - One-time scheduled jobs\r\n * - Automatic next-run calculation\r\n * - Execution history tracking\r\n * - Correlation context integration\r\n */\r\n\r\nimport type { IQueue, Job } from '../../interfaces/IQueue';\r\nimport type { IDatabase } from '../../interfaces/IDatabase';\r\nimport type {\r\n IScheduler,\r\n ScheduledJob,\r\n CreateScheduleOptions,\r\n UpdateScheduleOptions,\r\n ScheduleQuery,\r\n ScheduleExecution,\r\n SchedulerStats,\r\n ScheduleHandler,\r\n ScheduleContext,\r\n SchedulerConfig,\r\n ScheduleState,\r\n} from '../../interfaces/IScheduler';\r\nimport {\r\n generateScheduleId,\r\n getNextCronRun,\r\n isValidCron,\r\n} from '../../interfaces/IScheduler';\r\nimport { runWithContext, correlationContext } from '../../context';\r\n\r\nexport interface QueueSchedulerConfig extends SchedulerConfig {\r\n /** Queue instance for job execution */\r\n queue: IQueue;\r\n /** Database for persistence (optional, uses memory if not provided) */\r\n database?: IDatabase;\r\n /** Table name for schedules (default: 'scheduled_jobs') */\r\n schedulesTable?: string;\r\n /** Table name for execution history (default: 'schedule_executions') */\r\n executionsTable?: string;\r\n /** Service name for correlation */\r\n serviceName?: string;\r\n}\r\n\r\ninterface ScheduleRow {\r\n id: string;\r\n name: string;\r\n description?: string;\r\n cron?: string;\r\n run_at?: string;\r\n timezone?: string;\r\n data: string;\r\n state: string;\r\n created_at: string;\r\n updated_at: string;\r\n next_run?: string;\r\n last_run?: string;\r\n last_result?: string;\r\n last_error?: string;\r\n run_count: number;\r\n failure_count: number;\r\n max_runs?: number;\r\n tags?: string;\r\n metadata?: string;\r\n}\r\n\r\ninterface ExecutionRow {\r\n id: string;\r\n schedule_id: string;\r\n started_at: string;\r\n completed_at?: string;\r\n duration?: number;\r\n result: string;\r\n error?: string;\r\n job_id?: string;\r\n}\r\n\r\nexport class QueueScheduler implements IScheduler {\r\n private queue: IQueue;\r\n private db?: IDatabase;\r\n private schedulesTable: string;\r\n private executionsTable: string;\r\n private config: Required<Omit<QueueSchedulerConfig, 'queue' | 'database' | 'schedulesTable' | 'executionsTable'>>;\r\n private handlers: Map<string, ScheduleHandler<unknown>> = new Map();\r\n private checkTimer?: NodeJS.Timeout;\r\n private running = false;\r\n\r\n // In-memory storage if no database provided\r\n private memorySchedules: Map<string, ScheduledJob<unknown>> = new Map();\r\n private memoryExecutions: Map<string, ScheduleExecution[]> = new Map();\r\n\r\n constructor(config: QueueSchedulerConfig) {\r\n this.queue = config.queue;\r\n this.db = config.database;\r\n this.schedulesTable = config.schedulesTable ?? 'scheduled_jobs';\r\n this.executionsTable = config.executionsTable ?? 'schedule_executions';\r\n this.config = {\r\n defaultTimezone: config.defaultTimezone ?? 'UTC',\r\n defaultRetries: config.defaultRetries ?? 3,\r\n checkInterval: config.checkInterval ?? 60000, // 1 minute\r\n lookAheadWindow: config.lookAheadWindow ?? 300000, // 5 minutes\r\n historyRetentionDays: config.historyRetentionDays ?? 30,\r\n maxConcurrency: config.maxConcurrency ?? 10,\r\n serviceName: config.serviceName ?? 'scheduler',\r\n };\r\n }\r\n\r\n async create<T>(options: CreateScheduleOptions<T>): Promise<ScheduledJob<T>> {\r\n // Validate\r\n if (options.cron && !isValidCron(options.cron)) {\r\n throw new Error(`Invalid cron expression: ${options.cron}`);\r\n }\r\n if (!options.cron && !options.runAt) {\r\n throw new Error('Either cron or runAt must be provided');\r\n }\r\n\r\n const now = new Date().toISOString();\r\n const id = options.id ?? generateScheduleId();\r\n\r\n // Calculate next run\r\n let nextRun: string | undefined;\r\n if (options.cron) {\r\n const next = getNextCronRun(options.cron, new Date(), options.timezone);\r\n nextRun = next?.toISOString();\r\n } else if (options.runAt) {\r\n nextRun = new Date(options.runAt).toISOString();\r\n }\r\n\r\n const schedule: ScheduledJob<T> = {\r\n id,\r\n name: options.name,\r\n description: options.description,\r\n cron: options.cron,\r\n runAt: options.runAt ? new Date(options.runAt).toISOString() : undefined,\r\n timezone: options.timezone ?? this.config.defaultTimezone,\r\n data: options.data,\r\n state: options.paused ? 'paused' : 'active',\r\n createdAt: now,\r\n updatedAt: now,\r\n nextRun,\r\n runCount: 0,\r\n failureCount: 0,\r\n maxRuns: options.maxRuns,\r\n tags: options.tags,\r\n metadata: options.metadata,\r\n };\r\n\r\n await this.saveSchedule(schedule);\r\n return schedule;\r\n }\r\n\r\n async get<T>(id: string): Promise<ScheduledJob<T> | null> {\r\n return this.loadSchedule<T>(id);\r\n }\r\n\r\n async update<T>(id: string, options: UpdateScheduleOptions<T>): Promise<ScheduledJob<T>> {\r\n const schedule = await this.loadSchedule<T>(id);\r\n if (!schedule) {\r\n throw new Error(`Schedule not found: ${id}`);\r\n }\r\n\r\n // Validate new cron if provided\r\n if (options.cron && !isValidCron(options.cron)) {\r\n throw new Error(`Invalid cron expression: ${options.cron}`);\r\n }\r\n\r\n // Update fields\r\n const updated: ScheduledJob<T> = {\r\n ...schedule,\r\n cron: options.cron ?? schedule.cron,\r\n runAt: options.runAt ? new Date(options.runAt).toISOString() : schedule.runAt,\r\n timezone: options.timezone ?? schedule.timezone,\r\n data: options.data !== undefined ? options.data : schedule.data,\r\n maxRuns: options.maxRuns ?? schedule.maxRuns,\r\n tags: options.tags ?? schedule.tags,\r\n metadata: options.metadata ?? schedule.metadata,\r\n description: options.description ?? schedule.description,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n\r\n // Recalculate next run if schedule changed\r\n if (options.cron || options.runAt) {\r\n if (updated.cron) {\r\n const next = getNextCronRun(updated.cron, new Date(), updated.timezone);\r\n updated.nextRun = next?.toISOString();\r\n } else if (updated.runAt) {\r\n updated.nextRun = updated.runAt;\r\n }\r\n }\r\n\r\n await this.saveSchedule(updated);\r\n return updated;\r\n }\r\n\r\n async delete(id: string): Promise<void> {\r\n if (this.db) {\r\n await this.db.from(this.schedulesTable).where('id', '=', id).delete().execute();\r\n await this.db.from(this.executionsTable).where('schedule_id', '=', id).delete().execute();\r\n } else {\r\n this.memorySchedules.delete(id);\r\n this.memoryExecutions.delete(id);\r\n }\r\n }\r\n\r\n async pause(id: string): Promise<void> {\r\n const schedule = await this.loadSchedule(id);\r\n if (!schedule) throw new Error(`Schedule not found: ${id}`);\r\n\r\n schedule.state = 'paused';\r\n schedule.updatedAt = new Date().toISOString();\r\n await this.saveSchedule(schedule);\r\n }\r\n\r\n async resume(id: string): Promise<void> {\r\n const schedule = await this.loadSchedule(id);\r\n if (!schedule) throw new Error(`Schedule not found: ${id}`);\r\n\r\n schedule.state = 'active';\r\n schedule.updatedAt = new Date().toISOString();\r\n\r\n // Recalculate next run\r\n if (schedule.cron) {\r\n const next = getNextCronRun(schedule.cron, new Date(), schedule.timezone);\r\n schedule.nextRun = next?.toISOString();\r\n }\r\n\r\n await this.saveSchedule(schedule);\r\n }\r\n\r\n async trigger(id: string): Promise<string> {\r\n const schedule = await this.loadSchedule(id);\r\n if (!schedule) throw new Error(`Schedule not found: ${id}`);\r\n\r\n return this.executeSchedule(schedule);\r\n }\r\n\r\n async list<T>(query?: ScheduleQuery): Promise<ScheduledJob<T>[]> {\r\n let schedules = await this.loadAllSchedules<T>();\r\n\r\n // Apply filters\r\n if (query?.state) {\r\n const states = Array.isArray(query.state) ? query.state : [query.state];\r\n schedules = schedules.filter((s) => states.includes(s.state));\r\n }\r\n\r\n if (query?.tags && query.tags.length > 0) {\r\n schedules = schedules.filter((s) =>\r\n query.tags!.some((tag) => s.tags?.includes(tag))\r\n );\r\n }\r\n\r\n if (query?.name) {\r\n const pattern = query.name.replace(/\\*/g, '.*');\r\n const regex = new RegExp(`^${pattern}$`, 'i');\r\n schedules = schedules.filter((s) => regex.test(s.name));\r\n }\r\n\r\n if (query?.nextRunBefore) {\r\n const before = new Date(query.nextRunBefore).getTime();\r\n schedules = schedules.filter((s) =>\r\n s.nextRun && new Date(s.nextRun).getTime() < before\r\n );\r\n }\r\n\r\n if (query?.nextRunAfter) {\r\n const after = new Date(query.nextRunAfter).getTime();\r\n schedules = schedules.filter((s) =>\r\n s.nextRun && new Date(s.nextRun).getTime() > after\r\n );\r\n }\r\n\r\n // Apply pagination\r\n const offset = query?.offset ?? 0;\r\n const limit = query?.limit ?? 100;\r\n return schedules.slice(offset, offset + limit);\r\n }\r\n\r\n async getHistory(scheduleId: string, limit = 50): Promise<ScheduleExecution[]> {\r\n if (this.db) {\r\n const result = await this.db\r\n .from(this.executionsTable)\r\n .where('schedule_id', '=', scheduleId)\r\n .orderBy('started_at', 'desc')\r\n .limit(limit)\r\n .execute();\r\n\r\n return (result.data as ExecutionRow[]).map((row) => this.rowToExecution(row));\r\n } else {\r\n const executions = this.memoryExecutions.get(scheduleId) ?? [];\r\n return executions.slice(-limit).reverse();\r\n }\r\n }\r\n\r\n handle<T>(name: string, handler: ScheduleHandler<T>): void {\r\n this.handlers.set(name, handler as ScheduleHandler<unknown>);\r\n }\r\n\r\n async start(): Promise<void> {\r\n if (this.running) return;\r\n this.running = true;\r\n\r\n // Set up queue processor for scheduled jobs\r\n this.queue.process(async (job: Job<unknown>) => {\r\n if (job.name.startsWith('scheduled:')) {\r\n const data = job.data as { scheduleId: string; executionId: string };\r\n const scheduleId = data.scheduleId;\r\n const executionId = data.executionId;\r\n await this.processScheduledJob(scheduleId, executionId);\r\n }\r\n });\r\n\r\n // Start periodic check for upcoming jobs\r\n this.checkTimer = setInterval(\r\n () => this.checkUpcomingJobs(),\r\n this.config.checkInterval\r\n );\r\n\r\n // Initial check\r\n await this.checkUpcomingJobs();\r\n }\r\n\r\n async stop(): Promise<void> {\r\n this.running = false;\r\n if (this.checkTimer) {\r\n clearInterval(this.checkTimer);\r\n this.checkTimer = undefined;\r\n }\r\n }\r\n\r\n async getStats(): Promise<SchedulerStats> {\r\n const schedules = await this.loadAllSchedules();\r\n\r\n const stats: SchedulerStats = {\r\n total: schedules.length,\r\n active: 0,\r\n paused: 0,\r\n completed: 0,\r\n cancelled: 0,\r\n executionsLast24h: 0,\r\n failuresLast24h: 0,\r\n };\r\n\r\n for (const schedule of schedules) {\r\n switch (schedule.state) {\r\n case 'active': stats.active++; break;\r\n case 'paused': stats.paused++; break;\r\n case 'completed': stats.completed++; break;\r\n case 'cancelled': stats.cancelled++; break;\r\n }\r\n }\r\n\r\n // Find next execution\r\n const activeWithNextRun = schedules\r\n .filter((s) => s.state === 'active' && s.nextRun)\r\n .sort((a, b) => new Date(a.nextRun!).getTime() - new Date(b.nextRun!).getTime());\r\n\r\n stats.nextExecution = activeWithNextRun[0]?.nextRun;\r\n\r\n // Count recent executions\r\n const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);\r\n for (const schedule of schedules) {\r\n const history = await this.getHistory(schedule.id, 100);\r\n for (const exec of history) {\r\n if (new Date(exec.startedAt) > yesterday) {\r\n stats.executionsLast24h++;\r\n if (exec.result === 'failure') {\r\n stats.failuresLast24h++;\r\n }\r\n }\r\n }\r\n }\r\n\r\n return stats;\r\n }\r\n\r\n async healthCheck(): Promise<boolean> {\r\n return this.running;\r\n }\r\n\r\n async close(): Promise<void> {\r\n await this.stop();\r\n this.handlers.clear();\r\n this.memorySchedules.clear();\r\n this.memoryExecutions.clear();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATIC HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * SQL to create scheduler tables (PostgreSQL)\r\n */\r\n static getCreateTableSQL(\r\n schedulesTable = 'scheduled_jobs',\r\n executionsTable = 'schedule_executions'\r\n ): string {\r\n return `\r\nCREATE TABLE IF NOT EXISTS ${schedulesTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n name VARCHAR(255) NOT NULL,\r\n description TEXT,\r\n cron VARCHAR(100),\r\n run_at TIMESTAMPTZ,\r\n timezone VARCHAR(50) DEFAULT 'UTC',\r\n data JSONB NOT NULL,\r\n state VARCHAR(20) NOT NULL DEFAULT 'active',\r\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n next_run TIMESTAMPTZ,\r\n last_run TIMESTAMPTZ,\r\n last_result VARCHAR(20),\r\n last_error TEXT,\r\n run_count INTEGER NOT NULL DEFAULT 0,\r\n failure_count INTEGER NOT NULL DEFAULT 0,\r\n max_runs INTEGER,\r\n tags TEXT[],\r\n metadata JSONB\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${schedulesTable}_state ON ${schedulesTable}(state);\r\nCREATE INDEX IF NOT EXISTS idx_${schedulesTable}_next_run ON ${schedulesTable}(next_run);\r\nCREATE INDEX IF NOT EXISTS idx_${schedulesTable}_name ON ${schedulesTable}(name);\r\n\r\nCREATE TABLE IF NOT EXISTS ${executionsTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n schedule_id VARCHAR(255) NOT NULL REFERENCES ${schedulesTable}(id) ON DELETE CASCADE,\r\n started_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n completed_at TIMESTAMPTZ,\r\n duration INTEGER,\r\n result VARCHAR(20) NOT NULL DEFAULT 'running',\r\n error TEXT,\r\n job_id VARCHAR(255)\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${executionsTable}_schedule ON ${executionsTable}(schedule_id);\r\nCREATE INDEX IF NOT EXISTS idx_${executionsTable}_started ON ${executionsTable}(started_at DESC);\r\n `.trim();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private async saveSchedule(schedule: ScheduledJob<unknown>): Promise<void> {\r\n if (this.db) {\r\n const existing = await this.db\r\n .from(this.schedulesTable)\r\n .where('id', '=', schedule.id)\r\n .execute();\r\n\r\n const row = this.scheduleToRow(schedule);\r\n\r\n if (existing.data.length > 0) {\r\n await this.db\r\n .from(this.schedulesTable)\r\n .update(row)\r\n .where('id', '=', schedule.id)\r\n .execute();\r\n } else {\r\n await this.db.from(this.schedulesTable).insert(row).execute();\r\n }\r\n } else {\r\n this.memorySchedules.set(schedule.id, schedule);\r\n }\r\n }\r\n\r\n private async loadSchedule<T>(id: string): Promise<ScheduledJob<T> | null> {\r\n if (this.db) {\r\n const result = await this.db\r\n .from(this.schedulesTable)\r\n .where('id', '=', id)\r\n .execute();\r\n\r\n if (result.data.length === 0) return null;\r\n return this.rowToSchedule<T>(result.data[0] as ScheduleRow);\r\n } else {\r\n return (this.memorySchedules.get(id) as ScheduledJob<T>) ?? null;\r\n }\r\n }\r\n\r\n private async loadAllSchedules<T = unknown>(): Promise<ScheduledJob<T>[]> {\r\n if (this.db) {\r\n const result = await this.db.from(this.schedulesTable).execute();\r\n return (result.data as ScheduleRow[]).map((row) => this.rowToSchedule<T>(row));\r\n } else {\r\n return Array.from(this.memorySchedules.values()) as ScheduledJob<T>[];\r\n }\r\n }\r\n\r\n private scheduleToRow(schedule: ScheduledJob<unknown>): Record<string, unknown> {\r\n return {\r\n id: schedule.id,\r\n name: schedule.name,\r\n description: schedule.description,\r\n cron: schedule.cron,\r\n run_at: schedule.runAt,\r\n timezone: schedule.timezone,\r\n data: JSON.stringify(schedule.data),\r\n state: schedule.state,\r\n created_at: schedule.createdAt,\r\n updated_at: schedule.updatedAt,\r\n next_run: schedule.nextRun,\r\n last_run: schedule.lastRun,\r\n last_result: schedule.lastResult,\r\n last_error: schedule.lastError,\r\n run_count: schedule.runCount,\r\n failure_count: schedule.failureCount,\r\n max_runs: schedule.maxRuns,\r\n tags: schedule.tags ? `{${schedule.tags.join(',')}}` : null,\r\n metadata: schedule.metadata ? JSON.stringify(schedule.metadata) : null,\r\n };\r\n }\r\n\r\n private rowToSchedule<T>(row: ScheduleRow): ScheduledJob<T> {\r\n return {\r\n id: row.id,\r\n name: row.name,\r\n description: row.description,\r\n cron: row.cron,\r\n runAt: row.run_at,\r\n timezone: row.timezone,\r\n data: typeof row.data === 'string' ? JSON.parse(row.data) : row.data,\r\n state: row.state as ScheduleState,\r\n createdAt: row.created_at,\r\n updatedAt: row.updated_at,\r\n nextRun: row.next_run,\r\n lastRun: row.last_run,\r\n lastResult: row.last_result as 'success' | 'failure' | undefined,\r\n lastError: row.last_error,\r\n runCount: row.run_count,\r\n failureCount: row.failure_count,\r\n maxRuns: row.max_runs,\r\n tags: row.tags ? row.tags.replace(/[{}]/g, '').split(',').filter(Boolean) : undefined,\r\n metadata: row.metadata ? (typeof row.metadata === 'string' ? JSON.parse(row.metadata) : row.metadata) : undefined,\r\n };\r\n }\r\n\r\n private rowToExecution(row: ExecutionRow): ScheduleExecution {\r\n return {\r\n id: row.id,\r\n scheduleId: row.schedule_id,\r\n startedAt: row.started_at,\r\n completedAt: row.completed_at,\r\n duration: row.duration,\r\n result: row.result as 'success' | 'failure' | 'running',\r\n error: row.error,\r\n jobId: row.job_id,\r\n };\r\n }\r\n\r\n private async checkUpcomingJobs(): Promise<void> {\r\n if (!this.running) return;\r\n\r\n const now = new Date();\r\n const windowEnd = new Date(now.getTime() + this.config.lookAheadWindow);\r\n\r\n const schedules = await this.list({\r\n state: 'active',\r\n nextRunBefore: windowEnd,\r\n });\r\n\r\n for (const schedule of schedules) {\r\n if (!schedule.nextRun) continue;\r\n\r\n const nextRunTime = new Date(schedule.nextRun);\r\n if (nextRunTime <= now) {\r\n // Time to execute\r\n await this.executeSchedule(schedule);\r\n }\r\n }\r\n }\r\n\r\n private async executeSchedule(schedule: ScheduledJob<unknown>): Promise<string> {\r\n const executionId = `exec_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 8)}`;\r\n const startedAt = new Date().toISOString();\r\n\r\n // Create execution record\r\n const execution: ScheduleExecution = {\r\n id: executionId,\r\n scheduleId: schedule.id,\r\n startedAt,\r\n result: 'running',\r\n };\r\n\r\n await this.saveExecution(execution);\r\n\r\n // Add job to queue\r\n const job = await this.queue.add(\r\n `scheduled:${schedule.name}`,\r\n {\r\n scheduleId: schedule.id,\r\n executionId,\r\n data: schedule.data,\r\n },\r\n {\r\n correlationId: executionId,\r\n metadata: {\r\n scheduleName: schedule.name,\r\n scheduledAt: schedule.nextRun,\r\n },\r\n }\r\n );\r\n\r\n // Update execution with job ID\r\n execution.jobId = job.id;\r\n await this.saveExecution(execution);\r\n\r\n // Update schedule next run\r\n await this.updateScheduleAfterTrigger(schedule);\r\n\r\n return executionId;\r\n }\r\n\r\n private async processScheduledJob(scheduleId: string, executionId: string): Promise<void> {\r\n const schedule = await this.loadSchedule(scheduleId);\r\n if (!schedule) return;\r\n\r\n const handler = this.handlers.get(schedule.name);\r\n if (!handler) {\r\n console.warn(`No handler registered for schedule: ${schedule.name}`);\r\n return;\r\n }\r\n\r\n const startTime = Date.now();\r\n const logs: string[] = [];\r\n\r\n const context: ScheduleContext = {\r\n executionId,\r\n scheduleId,\r\n scheduledAt: schedule.nextRun ?? new Date().toISOString(),\r\n startedAt: new Date().toISOString(),\r\n progress: (percent) => {\r\n // Could update progress in queue if supported\r\n },\r\n log: (message, level = 'info') => {\r\n logs.push(`[${level.toUpperCase()}] ${message}`);\r\n },\r\n };\r\n\r\n try {\r\n // Run with correlation context\r\n await runWithContext(\r\n {\r\n correlationId: executionId,\r\n operation: `schedule:${schedule.name}`,\r\n traceId: correlationContext.generateId(),\r\n },\r\n async () => {\r\n await handler(schedule, context);\r\n }\r\n );\r\n\r\n // Success\r\n await this.completeExecution(executionId, 'success', Date.now() - startTime);\r\n await this.updateScheduleResult(scheduleId, 'success');\r\n } catch (error) {\r\n const errorMessage = error instanceof Error ? error.message : String(error);\r\n\r\n // Failure\r\n await this.completeExecution(executionId, 'failure', Date.now() - startTime, errorMessage);\r\n await this.updateScheduleResult(scheduleId, 'failure', errorMessage);\r\n }\r\n }\r\n\r\n private async updateScheduleAfterTrigger(schedule: ScheduledJob<unknown>): Promise<void> {\r\n schedule.runCount++;\r\n schedule.lastRun = new Date().toISOString();\r\n\r\n // Check if max runs reached\r\n if (schedule.maxRuns && schedule.runCount >= schedule.maxRuns) {\r\n schedule.state = 'completed';\r\n schedule.nextRun = undefined;\r\n } else if (schedule.cron) {\r\n // Calculate next run for recurring jobs\r\n const next = getNextCronRun(schedule.cron, new Date(), schedule.timezone);\r\n schedule.nextRun = next?.toISOString();\r\n } else {\r\n // One-time job completed\r\n schedule.state = 'completed';\r\n schedule.nextRun = undefined;\r\n }\r\n\r\n schedule.updatedAt = new Date().toISOString();\r\n await this.saveSchedule(schedule);\r\n }\r\n\r\n private async updateScheduleResult(\r\n scheduleId: string,\r\n result: 'success' | 'failure',\r\n error?: string\r\n ): Promise<void> {\r\n const schedule = await this.loadSchedule(scheduleId);\r\n if (!schedule) return;\r\n\r\n schedule.lastResult = result;\r\n schedule.lastError = error;\r\n if (result === 'failure') {\r\n schedule.failureCount++;\r\n }\r\n schedule.updatedAt = new Date().toISOString();\r\n\r\n await this.saveSchedule(schedule);\r\n }\r\n\r\n private async saveExecution(execution: ScheduleExecution): Promise<void> {\r\n if (this.db) {\r\n const existing = await this.db\r\n .from(this.executionsTable)\r\n .where('id', '=', execution.id)\r\n .execute();\r\n\r\n if (existing.data.length > 0) {\r\n await this.db\r\n .from(this.executionsTable)\r\n .update({\r\n completed_at: execution.completedAt,\r\n duration: execution.duration,\r\n result: execution.result,\r\n error: execution.error,\r\n job_id: execution.jobId,\r\n })\r\n .where('id', '=', execution.id)\r\n .execute();\r\n } else {\r\n await this.db.from(this.executionsTable).insert({\r\n id: execution.id,\r\n schedule_id: execution.scheduleId,\r\n started_at: execution.startedAt,\r\n completed_at: execution.completedAt,\r\n duration: execution.duration,\r\n result: execution.result,\r\n error: execution.error,\r\n job_id: execution.jobId,\r\n }).execute();\r\n }\r\n } else {\r\n const executions = this.memoryExecutions.get(execution.scheduleId) ?? [];\r\n const idx = executions.findIndex((e) => e.id === execution.id);\r\n if (idx >= 0) {\r\n executions[idx] = execution;\r\n } else {\r\n executions.push(execution);\r\n }\r\n this.memoryExecutions.set(execution.scheduleId, executions);\r\n }\r\n }\r\n\r\n private async completeExecution(\r\n executionId: string,\r\n result: 'success' | 'failure',\r\n duration: number,\r\n error?: string\r\n ): Promise<void> {\r\n if (this.db) {\r\n await this.db\r\n .from(this.executionsTable)\r\n .update({\r\n completed_at: new Date().toISOString(),\r\n duration,\r\n result,\r\n error,\r\n })\r\n .where('id', '=', executionId)\r\n .execute();\r\n } else {\r\n for (const [_scheduleId, executions] of this.memoryExecutions) {\r\n const execution = executions.find((e) => e.id === executionId);\r\n if (execution) {\r\n execution.completedAt = new Date().toISOString();\r\n execution.duration = duration;\r\n execution.result = result;\r\n execution.error = error;\r\n break;\r\n }\r\n }\r\n }\r\n }\r\n}\r\n","/**\r\n * HTTP Webhook Implementation\r\n *\r\n * Production webhook manager using native fetch.\r\n * Self-hosted, uses database for persistence.\r\n *\r\n * Features:\r\n * - HMAC signature verification\r\n * - Automatic retries with exponential backoff\r\n * - Event filtering with glob patterns\r\n * - Delivery tracking and history\r\n * - Queue-based async delivery (optional)\r\n */\r\n\r\nimport type { IDatabase } from '../../interfaces/IDatabase';\r\nimport type { IQueue } from '../../interfaces/IQueue';\r\nimport type {\r\n IWebhook,\r\n WebhookEndpoint,\r\n WebhookEvent,\r\n WebhookDelivery,\r\n DeliveryAttempt,\r\n CreateWebhookOptions,\r\n UpdateWebhookOptions,\r\n WebhookQuery,\r\n DeliveryQuery,\r\n WebhookStats,\r\n InboundWebhookConfig,\r\n InboundWebhookContext,\r\n VerificationResult,\r\n WebhookConfig,\r\n SignatureAlgorithm,\r\n} from '../../interfaces/IWebhook';\r\nimport {\r\n generateWebhookId,\r\n generateDeliveryId,\r\n generateEventId,\r\n generateWebhookSecret,\r\n matchEventType,\r\n calculateRetryDelay,\r\n} from '../../interfaces/IWebhook';\r\nimport { createHmac, timingSafeEqual } from 'crypto';\r\nimport { correlationContext } from '../../context';\r\n\r\nexport interface HttpWebhookConfig extends WebhookConfig {\r\n /** Database for persistence (optional, uses memory if not provided) */\r\n database?: IDatabase;\r\n /** Queue for async delivery (optional, uses sync if not provided) */\r\n queue?: IQueue;\r\n /** Table name for endpoints (default: 'webhook_endpoints') */\r\n endpointsTable?: string;\r\n /** Table name for deliveries (default: 'webhook_deliveries') */\r\n deliveriesTable?: string;\r\n /** Table name for attempts (default: 'webhook_attempts') */\r\n attemptsTable?: string;\r\n /** Service name for correlation */\r\n serviceName?: string;\r\n}\r\n\r\ninterface EndpointRow {\r\n id: string;\r\n name: string;\r\n description?: string;\r\n url: string;\r\n secret: string;\r\n signature_algorithm: string;\r\n signature_header: string;\r\n events: string;\r\n state: string;\r\n headers?: string;\r\n metadata?: string;\r\n tags?: string;\r\n created_at: string;\r\n updated_at: string;\r\n last_delivery_at?: string;\r\n last_success_at?: string;\r\n failure_count: number;\r\n total_deliveries: number;\r\n successful_deliveries: number;\r\n}\r\n\r\ninterface DeliveryRow {\r\n id: string;\r\n endpoint_id: string;\r\n event_id: string;\r\n event_type: string;\r\n payload: string;\r\n status: string;\r\n attempts: number;\r\n created_at: string;\r\n completed_at?: string;\r\n}\r\n\r\ninterface AttemptRow {\r\n id: string;\r\n delivery_id: string;\r\n endpoint_id: string;\r\n event_id: string;\r\n event_type: string;\r\n attempt_number: number;\r\n status: string;\r\n status_code?: number;\r\n response_body?: string;\r\n response_headers?: string;\r\n duration?: number;\r\n error?: string;\r\n timestamp: string;\r\n next_retry_at?: string;\r\n}\r\n\r\nexport class HttpWebhook implements IWebhook {\r\n private db?: IDatabase;\r\n private queue?: IQueue;\r\n private endpointsTable: string;\r\n private deliveriesTable: string;\r\n private attemptsTable: string;\r\n private config: Required<Omit<HttpWebhookConfig, 'database' | 'queue' | 'endpointsTable' | 'deliveriesTable' | 'attemptsTable'>>;\r\n private inboundConfigs: Map<string, InboundWebhookConfig> = new Map();\r\n\r\n // In-memory fallback\r\n private memoryEndpoints: Map<string, WebhookEndpoint> = new Map();\r\n private memoryDeliveries: Map<string, WebhookDelivery> = new Map();\r\n\r\n constructor(config: HttpWebhookConfig = {}) {\r\n this.db = config.database;\r\n this.queue = config.queue;\r\n this.endpointsTable = config.endpointsTable ?? 'webhook_endpoints';\r\n this.deliveriesTable = config.deliveriesTable ?? 'webhook_deliveries';\r\n this.attemptsTable = config.attemptsTable ?? 'webhook_attempts';\r\n this.config = {\r\n maxRetries: config.maxRetries ?? 5,\r\n retryDelayMs: config.retryDelayMs ?? 1000,\r\n maxRetryDelayMs: config.maxRetryDelayMs ?? 3600000,\r\n backoffMultiplier: config.backoffMultiplier ?? 2,\r\n timeoutMs: config.timeoutMs ?? 30000,\r\n maxConcurrent: config.maxConcurrent ?? 10,\r\n failureThreshold: config.failureThreshold ?? 10,\r\n historyRetentionDays: config.historyRetentionDays ?? 30,\r\n userAgent: config.userAgent ?? 'DLL-Platform-Webhook/1.0',\r\n serviceName: config.serviceName ?? 'webhook',\r\n };\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // ENDPOINT MANAGEMENT\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async create(options: CreateWebhookOptions): Promise<WebhookEndpoint> {\r\n const now = new Date().toISOString();\r\n const id = options.id ?? generateWebhookId();\r\n\r\n const endpoint: WebhookEndpoint = {\r\n id,\r\n name: options.name,\r\n description: options.description,\r\n url: options.url,\r\n secret: options.secret ?? generateWebhookSecret(),\r\n signatureAlgorithm: options.signatureAlgorithm ?? 'sha256',\r\n signatureHeader: options.signatureHeader ?? 'X-Webhook-Signature',\r\n events: options.events,\r\n state: options.paused ? 'paused' : 'active',\r\n headers: options.headers,\r\n metadata: options.metadata,\r\n tags: options.tags,\r\n createdAt: now,\r\n updatedAt: now,\r\n failureCount: 0,\r\n totalDeliveries: 0,\r\n successfulDeliveries: 0,\r\n };\r\n\r\n await this.saveEndpoint(endpoint);\r\n return endpoint;\r\n }\r\n\r\n async get(id: string): Promise<WebhookEndpoint | null> {\r\n return this.loadEndpoint(id);\r\n }\r\n\r\n async update(id: string, options: UpdateWebhookOptions): Promise<WebhookEndpoint> {\r\n const endpoint = await this.loadEndpoint(id);\r\n if (!endpoint) {\r\n throw new Error(`Webhook endpoint not found: ${id}`);\r\n }\r\n\r\n const updated: WebhookEndpoint = {\r\n ...endpoint,\r\n name: options.name ?? endpoint.name,\r\n description: options.description ?? endpoint.description,\r\n url: options.url ?? endpoint.url,\r\n secret: options.rotateSecret ? generateWebhookSecret() : endpoint.secret,\r\n events: options.events ?? endpoint.events,\r\n headers: options.headers ?? endpoint.headers,\r\n metadata: options.metadata ?? endpoint.metadata,\r\n tags: options.tags ?? endpoint.tags,\r\n updatedAt: new Date().toISOString(),\r\n };\r\n\r\n await this.saveEndpoint(updated);\r\n return updated;\r\n }\r\n\r\n async delete(id: string): Promise<void> {\r\n if (this.db) {\r\n await this.db.from(this.attemptsTable).where('endpoint_id', '=', id).delete().execute();\r\n await this.db.from(this.deliveriesTable).where('endpoint_id', '=', id).delete().execute();\r\n await this.db.from(this.endpointsTable).where('id', '=', id).delete().execute();\r\n } else {\r\n this.memoryEndpoints.delete(id);\r\n for (const [deliveryId, delivery] of this.memoryDeliveries) {\r\n if (delivery.endpointId === id) {\r\n this.memoryDeliveries.delete(deliveryId);\r\n }\r\n }\r\n }\r\n }\r\n\r\n async list(query?: WebhookQuery): Promise<WebhookEndpoint[]> {\r\n let endpoints = await this.loadAllEndpoints();\r\n\r\n // Apply filters\r\n if (query?.state) {\r\n const states = Array.isArray(query.state) ? query.state : [query.state];\r\n endpoints = endpoints.filter((e) => states.includes(e.state));\r\n }\r\n\r\n if (query?.events && query.events.length > 0) {\r\n endpoints = endpoints.filter((e) =>\r\n query.events!.some((eventType) =>\r\n e.events.some((pattern) => matchEventType(eventType, pattern))\r\n )\r\n );\r\n }\r\n\r\n if (query?.tags && query.tags.length > 0) {\r\n endpoints = endpoints.filter((e) =>\r\n query.tags!.some((tag) => e.tags?.includes(tag))\r\n );\r\n }\r\n\r\n if (query?.name) {\r\n const pattern = query.name.replace(/\\*/g, '.*');\r\n const regex = new RegExp(`^${pattern}$`, 'i');\r\n endpoints = endpoints.filter((e) => regex.test(e.name));\r\n }\r\n\r\n // Apply pagination\r\n const offset = query?.offset ?? 0;\r\n const limit = query?.limit ?? 100;\r\n return endpoints.slice(offset, offset + limit);\r\n }\r\n\r\n async pause(id: string): Promise<void> {\r\n const endpoint = await this.loadEndpoint(id);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${id}`);\r\n\r\n endpoint.state = 'paused';\r\n endpoint.updatedAt = new Date().toISOString();\r\n await this.saveEndpoint(endpoint);\r\n }\r\n\r\n async resume(id: string): Promise<void> {\r\n const endpoint = await this.loadEndpoint(id);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${id}`);\r\n\r\n endpoint.state = 'active';\r\n endpoint.failureCount = 0;\r\n endpoint.updatedAt = new Date().toISOString();\r\n await this.saveEndpoint(endpoint);\r\n }\r\n\r\n async test(id: string): Promise<DeliveryAttempt> {\r\n const endpoint = await this.loadEndpoint(id);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${id}`);\r\n\r\n const event: WebhookEvent = {\r\n id: generateEventId(),\r\n type: 'webhook.test',\r\n payload: { test: true, timestamp: new Date().toISOString() },\r\n timestamp: new Date().toISOString(),\r\n };\r\n\r\n return this.executeDelivery(endpoint, event, 1);\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // EVENT DELIVERY\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async dispatch<T>(event: WebhookEvent<T>): Promise<string[]> {\r\n const deliveryIds: string[] = [];\r\n const eventId = event.id ?? generateEventId();\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n\r\n const fullEvent: WebhookEvent<T> = {\r\n ...event,\r\n id: eventId,\r\n timestamp,\r\n correlationId: event.correlationId ?? correlationContext.get()?.correlationId,\r\n };\r\n\r\n // Find matching endpoints\r\n const endpoints = await this.loadAllEndpoints();\r\n const activeEndpoints = endpoints.filter(\r\n (e) =>\r\n e.state === 'active' &&\r\n e.events.some((pattern) => matchEventType(event.type, pattern))\r\n );\r\n\r\n for (const endpoint of activeEndpoints) {\r\n const deliveryId = await this.dispatchTo(endpoint.id, fullEvent);\r\n deliveryIds.push(deliveryId);\r\n }\r\n\r\n return deliveryIds;\r\n }\r\n\r\n async dispatchTo<T>(endpointId: string, event: WebhookEvent<T>): Promise<string> {\r\n const endpoint = await this.loadEndpoint(endpointId);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${endpointId}`);\r\n\r\n const eventId = event.id ?? generateEventId();\r\n const timestamp = event.timestamp ?? new Date().toISOString();\r\n const deliveryId = generateDeliveryId();\r\n\r\n const fullEvent: WebhookEvent<T> = {\r\n ...event,\r\n id: eventId,\r\n timestamp,\r\n correlationId: event.correlationId ?? correlationContext.get()?.correlationId,\r\n };\r\n\r\n // Create delivery record\r\n const delivery: WebhookDelivery = {\r\n id: deliveryId,\r\n endpointId,\r\n eventId,\r\n eventType: event.type,\r\n payload: JSON.stringify(fullEvent),\r\n status: 'pending',\r\n attempts: 0,\r\n attemptHistory: [],\r\n createdAt: new Date().toISOString(),\r\n };\r\n\r\n await this.saveDelivery(delivery);\r\n\r\n // Dispatch via queue if available, otherwise sync\r\n if (this.queue) {\r\n await this.queue.add('webhook:deliver', {\r\n deliveryId,\r\n endpointId,\r\n event: fullEvent,\r\n }, {\r\n correlationId: fullEvent.correlationId,\r\n metadata: { eventType: event.type },\r\n });\r\n } else {\r\n // Sync delivery\r\n await this.executeWithRetries(endpoint, fullEvent, delivery);\r\n }\r\n\r\n return deliveryId;\r\n }\r\n\r\n async retry(deliveryId: string): Promise<DeliveryAttempt> {\r\n const delivery = await this.getDelivery(deliveryId);\r\n if (!delivery) throw new Error(`Delivery not found: ${deliveryId}`);\r\n\r\n const endpoint = await this.loadEndpoint(delivery.endpointId);\r\n if (!endpoint) throw new Error(`Webhook endpoint not found: ${delivery.endpointId}`);\r\n\r\n const event = JSON.parse(delivery.payload) as WebhookEvent;\r\n const attempt = await this.executeDelivery(endpoint, event, delivery.attempts + 1);\r\n\r\n delivery.attempts++;\r\n delivery.attemptHistory.push(attempt);\r\n\r\n if (attempt.status === 'success') {\r\n delivery.status = 'success';\r\n delivery.completedAt = new Date().toISOString();\r\n this.updateEndpointStats(endpoint, true);\r\n }\r\n\r\n await this.saveDelivery(delivery);\r\n await this.saveAttempt(attempt, deliveryId);\r\n\r\n return attempt;\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // DELIVERY HISTORY\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async getDelivery(id: string): Promise<WebhookDelivery | null> {\r\n if (this.db) {\r\n const result = await this.db\r\n .from(this.deliveriesTable)\r\n .where('id', '=', id)\r\n .execute();\r\n\r\n if (result.data.length === 0) return null;\r\n const delivery = this.rowToDelivery(result.data[0] as DeliveryRow);\r\n\r\n // Load attempt history\r\n const attempts = await this.getAttempts(id);\r\n delivery.attemptHistory = attempts;\r\n\r\n return delivery;\r\n } else {\r\n return this.memoryDeliveries.get(id) ?? null;\r\n }\r\n }\r\n\r\n async listDeliveries(query?: DeliveryQuery): Promise<WebhookDelivery[]> {\r\n if (this.db) {\r\n let builder = this.db.from(this.deliveriesTable);\r\n\r\n if (query?.endpointId) {\r\n builder = builder.where('endpoint_id', '=', query.endpointId);\r\n }\r\n\r\n if (query?.eventType) {\r\n builder = builder.where('event_type', '=', query.eventType);\r\n }\r\n\r\n if (query?.status) {\r\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\r\n if (statuses.length === 1) {\r\n builder = builder.where('status', '=', statuses[0]!);\r\n }\r\n }\r\n\r\n builder = builder.orderBy('created_at', 'desc');\r\n\r\n if (query?.limit) {\r\n builder = builder.limit(query.limit);\r\n }\r\n\r\n const result = await builder.execute();\r\n return (result.data as DeliveryRow[]).map((row) => this.rowToDelivery(row));\r\n } else {\r\n let deliveries = Array.from(this.memoryDeliveries.values());\r\n\r\n if (query?.endpointId) {\r\n deliveries = deliveries.filter((d) => d.endpointId === query.endpointId);\r\n }\r\n\r\n if (query?.eventType) {\r\n deliveries = deliveries.filter((d) => d.eventType === query.eventType);\r\n }\r\n\r\n if (query?.status) {\r\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\r\n deliveries = deliveries.filter((d) => statuses.includes(d.status));\r\n }\r\n\r\n deliveries.sort((a, b) => new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime());\r\n\r\n const offset = query?.offset ?? 0;\r\n const limit = query?.limit ?? 100;\r\n return deliveries.slice(offset, offset + limit);\r\n }\r\n }\r\n\r\n async getAttempts(deliveryId: string): Promise<DeliveryAttempt[]> {\r\n if (this.db) {\r\n const result = await this.db\r\n .from(this.attemptsTable)\r\n .where('delivery_id', '=', deliveryId)\r\n .orderBy('attempt_number', 'asc')\r\n .execute();\r\n\r\n return (result.data as AttemptRow[]).map((row) => this.rowToAttempt(row));\r\n } else {\r\n const delivery = this.memoryDeliveries.get(deliveryId);\r\n return delivery?.attemptHistory ?? [];\r\n }\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // INBOUND WEBHOOKS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n registerInbound(config: InboundWebhookConfig): void {\r\n this.inboundConfigs.set(config.name, config);\r\n }\r\n\r\n verify(name: string, context: InboundWebhookContext): VerificationResult {\r\n const config = this.inboundConfigs.get(name);\r\n if (!config) {\r\n return { valid: false, error: `Unknown webhook: ${name}` };\r\n }\r\n\r\n // Get signature from headers\r\n const signatureHeader = config.signatureHeader ?? 'X-Webhook-Signature';\r\n const headerKey = signatureHeader.toLowerCase();\r\n const signature = context.headers[headerKey] ?? context.signature;\r\n\r\n if (!signature) {\r\n return { valid: false, error: 'Missing signature header' };\r\n }\r\n\r\n // Verify timestamp if configured\r\n if (config.timestampHeader) {\r\n const timestampHeaderKey = config.timestampHeader.toLowerCase();\r\n const timestamp = context.headers[timestampHeaderKey];\r\n if (timestamp) {\r\n const timestampMs = parseInt(timestamp, 10) * 1000;\r\n const now = Date.now();\r\n const tolerance = (config.timestampTolerance ?? 300) * 1000;\r\n\r\n if (Math.abs(now - timestampMs) > tolerance) {\r\n return { valid: false, error: 'Timestamp outside tolerance window' };\r\n }\r\n }\r\n }\r\n\r\n // Compute expected signature\r\n const algorithm = config.signatureAlgorithm ?? 'sha256';\r\n const body = typeof context.rawBody === 'string'\r\n ? context.rawBody\r\n : context.rawBody.toString('utf-8');\r\n\r\n const expectedSignature = this.computeSignature(body, config.secret, algorithm);\r\n\r\n // Use timing-safe comparison\r\n const providedSig = signature.replace(/^(sha256=|sha512=|sha1=)/, '');\r\n\r\n try {\r\n const providedBuffer = Buffer.from(providedSig, 'hex');\r\n const expectedBuffer = Buffer.from(expectedSignature, 'hex');\r\n\r\n if (providedBuffer.length !== expectedBuffer.length) {\r\n return { valid: false, error: 'Invalid signature' };\r\n }\r\n\r\n if (!timingSafeEqual(providedBuffer, expectedBuffer)) {\r\n return { valid: false, error: 'Invalid signature' };\r\n }\r\n } catch {\r\n return { valid: false, error: 'Invalid signature format' };\r\n }\r\n\r\n // Parse payload\r\n try {\r\n const payload = JSON.parse(body);\r\n return { valid: true, payload };\r\n } catch {\r\n return { valid: false, error: 'Invalid JSON payload' };\r\n }\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATISTICS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async getStats(): Promise<WebhookStats> {\r\n const endpoints = await this.loadAllEndpoints();\r\n const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);\r\n\r\n let deliveriesLast24h = 0;\r\n let successLast24h = 0;\r\n let failuresLast24h = 0;\r\n let totalDuration = 0;\r\n let durationCount = 0;\r\n\r\n if (this.db) {\r\n // Query database for recent stats\r\n const recentDeliveries = await this.listDeliveries({\r\n from: yesterday,\r\n limit: 10000,\r\n });\r\n\r\n deliveriesLast24h = recentDeliveries.length;\r\n successLast24h = recentDeliveries.filter((d) => d.status === 'success').length;\r\n failuresLast24h = recentDeliveries.filter((d) => d.status === 'failed').length;\r\n } else {\r\n for (const delivery of this.memoryDeliveries.values()) {\r\n if (new Date(delivery.createdAt) > yesterday) {\r\n deliveriesLast24h++;\r\n if (delivery.status === 'success') successLast24h++;\r\n if (delivery.status === 'failed') failuresLast24h++;\r\n\r\n for (const attempt of delivery.attemptHistory) {\r\n if (attempt.duration) {\r\n totalDuration += attempt.duration;\r\n durationCount++;\r\n }\r\n }\r\n }\r\n }\r\n }\r\n\r\n return {\r\n totalEndpoints: endpoints.length,\r\n activeEndpoints: endpoints.filter((e) => e.state === 'active').length,\r\n pausedEndpoints: endpoints.filter((e) => e.state === 'paused').length,\r\n failedEndpoints: endpoints.filter((e) => e.state === 'failed').length,\r\n deliveriesLast24h,\r\n successLast24h,\r\n failuresLast24h,\r\n avgDeliveryTime: durationCount > 0 ? totalDuration / durationCount : 0,\r\n };\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // LIFECYCLE\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n async healthCheck(): Promise<boolean> {\r\n if (this.db) {\r\n try {\r\n await this.db.from(this.endpointsTable).limit(1).execute();\r\n return true;\r\n } catch {\r\n return false;\r\n }\r\n }\r\n return true;\r\n }\r\n\r\n async close(): Promise<void> {\r\n this.memoryEndpoints.clear();\r\n this.memoryDeliveries.clear();\r\n this.inboundConfigs.clear();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // STATIC HELPERS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n /**\r\n * SQL to create webhook tables (PostgreSQL)\r\n */\r\n static getCreateTableSQL(\r\n endpointsTable = 'webhook_endpoints',\r\n deliveriesTable = 'webhook_deliveries',\r\n attemptsTable = 'webhook_attempts'\r\n ): string {\r\n return `\r\nCREATE TABLE IF NOT EXISTS ${endpointsTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n name VARCHAR(255) NOT NULL,\r\n description TEXT,\r\n url TEXT NOT NULL,\r\n secret VARCHAR(255) NOT NULL,\r\n signature_algorithm VARCHAR(20) DEFAULT 'sha256',\r\n signature_header VARCHAR(100) DEFAULT 'X-Webhook-Signature',\r\n events TEXT NOT NULL,\r\n state VARCHAR(20) NOT NULL DEFAULT 'active',\r\n headers JSONB,\r\n metadata JSONB,\r\n tags TEXT[],\r\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n last_delivery_at TIMESTAMPTZ,\r\n last_success_at TIMESTAMPTZ,\r\n failure_count INTEGER NOT NULL DEFAULT 0,\r\n total_deliveries INTEGER NOT NULL DEFAULT 0,\r\n successful_deliveries INTEGER NOT NULL DEFAULT 0\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${endpointsTable}_state ON ${endpointsTable}(state);\r\nCREATE INDEX IF NOT EXISTS idx_${endpointsTable}_name ON ${endpointsTable}(name);\r\n\r\nCREATE TABLE IF NOT EXISTS ${deliveriesTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n endpoint_id VARCHAR(255) NOT NULL REFERENCES ${endpointsTable}(id) ON DELETE CASCADE,\r\n event_id VARCHAR(255) NOT NULL,\r\n event_type VARCHAR(255) NOT NULL,\r\n payload JSONB NOT NULL,\r\n status VARCHAR(20) NOT NULL DEFAULT 'pending',\r\n attempts INTEGER NOT NULL DEFAULT 0,\r\n created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n completed_at TIMESTAMPTZ\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${deliveriesTable}_endpoint ON ${deliveriesTable}(endpoint_id);\r\nCREATE INDEX IF NOT EXISTS idx_${deliveriesTable}_status ON ${deliveriesTable}(status);\r\nCREATE INDEX IF NOT EXISTS idx_${deliveriesTable}_created ON ${deliveriesTable}(created_at DESC);\r\n\r\nCREATE TABLE IF NOT EXISTS ${attemptsTable} (\r\n id VARCHAR(255) PRIMARY KEY,\r\n delivery_id VARCHAR(255) NOT NULL REFERENCES ${deliveriesTable}(id) ON DELETE CASCADE,\r\n endpoint_id VARCHAR(255) NOT NULL,\r\n event_id VARCHAR(255) NOT NULL,\r\n event_type VARCHAR(255) NOT NULL,\r\n attempt_number INTEGER NOT NULL,\r\n status VARCHAR(20) NOT NULL,\r\n status_code INTEGER,\r\n response_body TEXT,\r\n response_headers JSONB,\r\n duration INTEGER,\r\n error TEXT,\r\n timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),\r\n next_retry_at TIMESTAMPTZ\r\n);\r\n\r\nCREATE INDEX IF NOT EXISTS idx_${attemptsTable}_delivery ON ${attemptsTable}(delivery_id);\r\n `.trim();\r\n }\r\n\r\n // ═══════════════════════════════════════════════════════════════\r\n // PRIVATE METHODS\r\n // ═══════════════════════════════════════════════════════════════\r\n\r\n private async saveEndpoint(endpoint: WebhookEndpoint): Promise<void> {\r\n if (this.db) {\r\n const existing = await this.db\r\n .from(this.endpointsTable)\r\n .where('id', '=', endpoint.id)\r\n .execute();\r\n\r\n const row = this.endpointToRow(endpoint);\r\n\r\n if (existing.data.length > 0) {\r\n await this.db\r\n .from(this.endpointsTable)\r\n .update(row)\r\n .where('id', '=', endpoint.id)\r\n .execute();\r\n } else {\r\n await this.db.from(this.endpointsTable).insert(row).execute();\r\n }\r\n } else {\r\n this.memoryEndpoints.set(endpoint.id, endpoint);\r\n }\r\n }\r\n\r\n private async loadEndpoint(id: string): Promise<WebhookEndpoint | null> {\r\n if (this.db) {\r\n const result = await this.db\r\n .from(this.endpointsTable)\r\n .where('id', '=', id)\r\n .execute();\r\n\r\n if (result.data.length === 0) return null;\r\n return this.rowToEndpoint(result.data[0] as EndpointRow);\r\n } else {\r\n return this.memoryEndpoints.get(id) ?? null;\r\n }\r\n }\r\n\r\n private async loadAllEndpoints(): Promise<WebhookEndpoint[]> {\r\n if (this.db) {\r\n const result = await this.db.from(this.endpointsTable).execute();\r\n return (result.data as EndpointRow[]).map((row) => this.rowToEndpoint(row));\r\n } else {\r\n return Array.from(this.memoryEndpoints.values());\r\n }\r\n }\r\n\r\n private async saveDelivery(delivery: WebhookDelivery): Promise<void> {\r\n if (this.db) {\r\n const existing = await this.db\r\n .from(this.deliveriesTable)\r\n .where('id', '=', delivery.id)\r\n .execute();\r\n\r\n const row = this.deliveryToRow(delivery);\r\n\r\n if (existing.data.length > 0) {\r\n await this.db\r\n .from(this.deliveriesTable)\r\n .update(row)\r\n .where('id', '=', delivery.id)\r\n .execute();\r\n } else {\r\n await this.db.from(this.deliveriesTable).insert(row).execute();\r\n }\r\n } else {\r\n this.memoryDeliveries.set(delivery.id, delivery);\r\n }\r\n }\r\n\r\n private async saveAttempt(attempt: DeliveryAttempt, deliveryId: string): Promise<void> {\r\n if (this.db) {\r\n await this.db.from(this.attemptsTable).insert({\r\n id: attempt.id,\r\n delivery_id: deliveryId,\r\n endpoint_id: attempt.endpointId,\r\n event_id: attempt.eventId,\r\n event_type: attempt.eventType,\r\n attempt_number: attempt.attemptNumber,\r\n status: attempt.status,\r\n status_code: attempt.statusCode,\r\n response_body: attempt.responseBody,\r\n response_headers: attempt.responseHeaders ? JSON.stringify(attempt.responseHeaders) : null,\r\n duration: attempt.duration,\r\n error: attempt.error,\r\n timestamp: attempt.timestamp,\r\n next_retry_at: attempt.nextRetryAt,\r\n }).execute();\r\n }\r\n }\r\n\r\n private async executeWithRetries(\r\n endpoint: WebhookEndpoint,\r\n event: WebhookEvent,\r\n delivery: WebhookDelivery\r\n ): Promise<void> {\r\n let attempt = 0;\r\n\r\n while (attempt < this.config.maxRetries) {\r\n attempt++;\r\n const result = await this.executeDelivery(endpoint, event, attempt);\r\n\r\n delivery.attempts = attempt;\r\n delivery.attemptHistory.push(result);\r\n await this.saveAttempt(result, delivery.id);\r\n\r\n if (result.status === 'success') {\r\n delivery.status = 'success';\r\n delivery.completedAt = new Date().toISOString();\r\n await this.updateEndpointStats(endpoint, true);\r\n await this.saveDelivery(delivery);\r\n return;\r\n }\r\n\r\n // Wait before retry\r\n if (attempt < this.config.maxRetries) {\r\n const delay = calculateRetryDelay(\r\n attempt,\r\n this.config.retryDelayMs,\r\n this.config.maxRetryDelayMs,\r\n this.config.backoffMultiplier\r\n );\r\n await new Promise((resolve) => setTimeout(resolve, delay));\r\n }\r\n }\r\n\r\n // All retries exhausted\r\n delivery.status = 'failed';\r\n delivery.completedAt = new Date().toISOString();\r\n await this.updateEndpointStats(endpoint, false);\r\n await this.saveDelivery(delivery);\r\n }\r\n\r\n private async executeDelivery(\r\n endpoint: WebhookEndpoint,\r\n event: WebhookEvent,\r\n attemptNumber: number\r\n ): Promise<DeliveryAttempt> {\r\n const attemptId = `att_${Date.now().toString(36)}${Math.random().toString(36).substring(2, 8)}`;\r\n const startTime = Date.now();\r\n const payloadStr = JSON.stringify(event);\r\n const signature = this.computeSignature(payloadStr, endpoint.secret, endpoint.signatureAlgorithm);\r\n\r\n const headers: Record<string, string> = {\r\n 'Content-Type': 'application/json',\r\n 'User-Agent': this.config.userAgent,\r\n [endpoint.signatureHeader]: `${endpoint.signatureAlgorithm}=${signature}`,\r\n 'X-Webhook-Id': endpoint.id,\r\n 'X-Webhook-Event': event.type,\r\n 'X-Webhook-Delivery-Id': event.id!,\r\n 'X-Webhook-Timestamp': event.timestamp!,\r\n ...(endpoint.headers ?? {}),\r\n };\r\n\r\n if (event.correlationId) {\r\n headers['X-Correlation-Id'] = event.correlationId;\r\n }\r\n\r\n try {\r\n const controller = new AbortController();\r\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs);\r\n\r\n const response = await fetch(endpoint.url, {\r\n method: 'POST',\r\n headers,\r\n body: payloadStr,\r\n signal: controller.signal,\r\n });\r\n\r\n clearTimeout(timeoutId);\r\n\r\n const duration = Date.now() - startTime;\r\n const responseBody = await response.text().catch(() => '');\r\n const responseHeaders: Record<string, string> = {};\r\n response.headers.forEach((value, key) => {\r\n responseHeaders[key] = value;\r\n });\r\n\r\n if (response.ok) {\r\n return {\r\n id: attemptId,\r\n endpointId: endpoint.id,\r\n eventId: event.id!,\r\n eventType: event.type,\r\n attemptNumber,\r\n status: 'success',\r\n statusCode: response.status,\r\n responseBody: responseBody.substring(0, 10000), // Truncate\r\n responseHeaders,\r\n duration,\r\n timestamp: new Date().toISOString(),\r\n };\r\n } else {\r\n return {\r\n id: attemptId,\r\n endpointId: endpoint.id,\r\n eventId: event.id!,\r\n eventType: event.type,\r\n attemptNumber,\r\n status: 'failed',\r\n statusCode: response.status,\r\n responseBody: responseBody.substring(0, 10000),\r\n responseHeaders,\r\n duration,\r\n error: `HTTP ${response.status}: ${response.statusText}`,\r\n timestamp: new Date().toISOString(),\r\n };\r\n }\r\n } catch (error) {\r\n const duration = Date.now() - startTime;\r\n const errorMessage = error instanceof Error ? error.message : String(error);\r\n\r\n return {\r\n id: attemptId,\r\n endpointId: endpoint.id,\r\n eventId: event.id!,\r\n eventType: event.type,\r\n attemptNumber,\r\n status: 'failed',\r\n duration,\r\n error: errorMessage,\r\n timestamp: new Date().toISOString(),\r\n };\r\n }\r\n }\r\n\r\n private async updateEndpointStats(endpoint: WebhookEndpoint, success: boolean): Promise<void> {\r\n endpoint.totalDeliveries++;\r\n endpoint.lastDeliveryAt = new Date().toISOString();\r\n\r\n if (success) {\r\n endpoint.successfulDeliveries++;\r\n endpoint.lastSuccessAt = new Date().toISOString();\r\n endpoint.failureCount = 0;\r\n } else {\r\n endpoint.failureCount++;\r\n\r\n if (endpoint.failureCount >= this.config.failureThreshold) {\r\n endpoint.state = 'failed';\r\n }\r\n }\r\n\r\n endpoint.updatedAt = new Date().toISOString();\r\n await this.saveEndpoint(endpoint);\r\n }\r\n\r\n private computeSignature(payload: string, secret: string, algorithm: SignatureAlgorithm): string {\r\n return createHmac(algorithm, secret).update(payload).digest('hex');\r\n }\r\n\r\n private endpointToRow(endpoint: WebhookEndpoint): Record<string, unknown> {\r\n return {\r\n id: endpoint.id,\r\n name: endpoint.name,\r\n description: endpoint.description,\r\n url: endpoint.url,\r\n secret: endpoint.secret,\r\n signature_algorithm: endpoint.signatureAlgorithm,\r\n signature_header: endpoint.signatureHeader,\r\n events: JSON.stringify(endpoint.events),\r\n state: endpoint.state,\r\n headers: endpoint.headers ? JSON.stringify(endpoint.headers) : null,\r\n metadata: endpoint.metadata ? JSON.stringify(endpoint.metadata) : null,\r\n tags: endpoint.tags ? `{${endpoint.tags.join(',')}}` : null,\r\n created_at: endpoint.createdAt,\r\n updated_at: endpoint.updatedAt,\r\n last_delivery_at: endpoint.lastDeliveryAt,\r\n last_success_at: endpoint.lastSuccessAt,\r\n failure_count: endpoint.failureCount,\r\n total_deliveries: endpoint.totalDeliveries,\r\n successful_deliveries: endpoint.successfulDeliveries,\r\n };\r\n }\r\n\r\n private rowToEndpoint(row: EndpointRow): WebhookEndpoint {\r\n return {\r\n id: row.id,\r\n name: row.name,\r\n description: row.description,\r\n url: row.url,\r\n secret: row.secret,\r\n signatureAlgorithm: row.signature_algorithm as SignatureAlgorithm,\r\n signatureHeader: row.signature_header,\r\n events: typeof row.events === 'string' ? JSON.parse(row.events) : row.events,\r\n state: row.state as WebhookEndpoint['state'],\r\n headers: row.headers ? (typeof row.headers === 'string' ? JSON.parse(row.headers) : row.headers) : undefined,\r\n metadata: row.metadata ? (typeof row.metadata === 'string' ? JSON.parse(row.metadata) : row.metadata) : undefined,\r\n tags: row.tags ? row.tags.replace(/[{}]/g, '').split(',').filter(Boolean) : undefined,\r\n createdAt: row.created_at,\r\n updatedAt: row.updated_at,\r\n lastDeliveryAt: row.last_delivery_at,\r\n lastSuccessAt: row.last_success_at,\r\n failureCount: row.failure_count,\r\n totalDeliveries: row.total_deliveries,\r\n successfulDeliveries: row.successful_deliveries,\r\n };\r\n }\r\n\r\n private deliveryToRow(delivery: WebhookDelivery): Record<string, unknown> {\r\n return {\r\n id: delivery.id,\r\n endpoint_id: delivery.endpointId,\r\n event_id: delivery.eventId,\r\n event_type: delivery.eventType,\r\n payload: delivery.payload,\r\n status: delivery.status,\r\n attempts: delivery.attempts,\r\n created_at: delivery.createdAt,\r\n completed_at: delivery.completedAt,\r\n };\r\n }\r\n\r\n private rowToDelivery(row: DeliveryRow): WebhookDelivery {\r\n return {\r\n id: row.id,\r\n endpointId: row.endpoint_id,\r\n eventId: row.event_id,\r\n eventType: row.event_type,\r\n payload: typeof row.payload === 'string' ? row.payload : JSON.stringify(row.payload),\r\n status: row.status as WebhookDelivery['status'],\r\n attempts: row.attempts,\r\n attemptHistory: [],\r\n createdAt: row.created_at,\r\n completedAt: row.completed_at,\r\n };\r\n }\r\n\r\n private rowToAttempt(row: AttemptRow): DeliveryAttempt {\r\n return {\r\n id: row.id,\r\n endpointId: row.endpoint_id,\r\n eventId: row.event_id,\r\n eventType: row.event_type,\r\n attemptNumber: row.attempt_number,\r\n status: row.status as DeliveryAttempt['status'],\r\n statusCode: row.status_code,\r\n responseBody: row.response_body,\r\n responseHeaders: row.response_headers ? (typeof row.response_headers === 'string' ? JSON.parse(row.response_headers) : row.response_headers) : undefined,\r\n duration: row.duration,\r\n error: row.error,\r\n timestamp: row.timestamp,\r\n nextRetryAt: row.next_retry_at,\r\n };\r\n }\r\n}\r\n","/**\r\n * Database Migrator\r\n *\r\n * Enterprise-grade database migration system supporting:\r\n * - PostgreSQL (primary)\r\n * - Memory database (for testing)\r\n * - Transaction-safe migrations\r\n * - Concurrent execution locking\r\n * - Checksum validation\r\n * - Dry-run mode\r\n */\r\n\r\nimport type {\r\n IMigrator,\r\n Migration,\r\n MigrationRecord,\r\n MigrationResult,\r\n MigrationStatus,\r\n MigratorConfig,\r\n IMigrationDatabase,\r\n} from '../interfaces/IMigration';\r\n\r\nconst DEFAULT_CONFIG: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string } = {\r\n tableName: '_migrations',\r\n schema: 'public',\r\n lockTimeout: 60,\r\n validateChecksums: true,\r\n migrationsDir: undefined,\r\n};\r\n\r\n/**\r\n * Generate a checksum for migration content\r\n */\r\nfunction generateChecksum(content: string): string {\r\n // Simple hash for checksum - in production you might use crypto\r\n let hash = 0;\r\n for (let i = 0; i < content.length; i++) {\r\n const char = content.charCodeAt(i);\r\n hash = (hash << 5) - hash + char;\r\n hash = hash & hash; // Convert to 32-bit integer\r\n }\r\n return Math.abs(hash).toString(16).padStart(8, '0');\r\n}\r\n\r\n/**\r\n * Sort migrations by version\r\n */\r\nfunction sortMigrations(migrations: Migration[]): Migration[] {\r\n return [...migrations].sort((a, b) => a.version.localeCompare(b.version));\r\n}\r\n\r\nexport class Migrator implements IMigrator {\r\n private db: IMigrationDatabase;\r\n private config: Required<Omit<MigratorConfig, 'migrationsDir'>> & { migrationsDir?: string };\r\n private migrations: Migration[] = [];\r\n private initialized = false;\r\n private locked = false;\r\n\r\n constructor(db: IMigrationDatabase, config: MigratorConfig = {}) {\r\n this.db = db;\r\n this.config = { ...DEFAULT_CONFIG, ...config };\r\n }\r\n\r\n /**\r\n * Get the fully qualified migration table name\r\n */\r\n private get tableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}\"`;\r\n }\r\n\r\n /**\r\n * Get the lock table name\r\n */\r\n private get lockTableName(): string {\r\n return `\"${this.config.schema}\".\"${this.config.tableName}_lock\"`;\r\n }\r\n\r\n /**\r\n * Initialize migration tracking tables\r\n */\r\n private async initialize(): Promise<void> {\r\n if (this.initialized) return;\r\n\r\n // Create schema if not exists\r\n await this.db.raw(`CREATE SCHEMA IF NOT EXISTS \"${this.config.schema}\"`);\r\n\r\n // Create migrations tracking table\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.tableName} (\r\n version VARCHAR(255) PRIMARY KEY,\r\n name VARCHAR(255) NOT NULL,\r\n applied_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\r\n execution_time INTEGER NOT NULL,\r\n checksum VARCHAR(64)\r\n )\r\n `);\r\n\r\n // Create lock table for concurrent safety\r\n await this.db.raw(`\r\n CREATE TABLE IF NOT EXISTS ${this.lockTableName} (\r\n id INTEGER PRIMARY KEY DEFAULT 1,\r\n locked_at TIMESTAMP WITH TIME ZONE,\r\n locked_by VARCHAR(255),\r\n CONSTRAINT single_row CHECK (id = 1)\r\n )\r\n `);\r\n\r\n // Insert initial lock row if not exists\r\n await this.db.raw(`\r\n INSERT INTO ${this.lockTableName} (id, locked_at, locked_by)\r\n VALUES (1, NULL, NULL)\r\n ON CONFLICT (id) DO NOTHING\r\n `);\r\n\r\n this.initialized = true;\r\n }\r\n\r\n /**\r\n * Acquire migration lock\r\n */\r\n async lock(): Promise<boolean> {\r\n await this.initialize();\r\n\r\n const lockId = `${process.pid}-${Date.now()}`;\r\n const lockTimeout = new Date(Date.now() - this.config.lockTimeout * 1000);\r\n\r\n // Try to acquire lock (only if not locked or lock expired)\r\n const result = await this.db.raw<{ locked_at: Date | null }>(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = CURRENT_TIMESTAMP, locked_by = $1\r\n WHERE id = 1 AND (locked_at IS NULL OR locked_at < $2)\r\n RETURNING locked_at\r\n `,\r\n [lockId, lockTimeout]\r\n );\r\n\r\n if (result.data.length > 0) {\r\n this.locked = true;\r\n return true;\r\n }\r\n\r\n return false;\r\n }\r\n\r\n /**\r\n * Release migration lock\r\n */\r\n async unlock(): Promise<void> {\r\n if (!this.locked) return;\r\n\r\n await this.db.raw(\r\n `\r\n UPDATE ${this.lockTableName}\r\n SET locked_at = NULL, locked_by = NULL\r\n WHERE id = 1\r\n `\r\n );\r\n\r\n this.locked = false;\r\n }\r\n\r\n /**\r\n * Add migrations to the migrator\r\n */\r\n addMigrations(migrations: Migration[]): void {\r\n for (const migration of migrations) {\r\n // Generate checksum if not provided\r\n if (!migration.checksum) {\r\n const content =\r\n typeof migration.up === 'string' ? migration.up : migration.up.toString();\r\n migration.checksum = generateChecksum(content);\r\n }\r\n\r\n // Avoid duplicates\r\n if (!this.migrations.find((m) => m.version === migration.version)) {\r\n this.migrations.push(migration);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Load migrations from directory\r\n * Expects files named: {version}_{name}.ts or {version}_{name}.sql\r\n */\r\n async loadMigrations(dir: string): Promise<void> {\r\n // Dynamic import for Node.js file system\r\n const { readdir, readFile } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n const files = await readdir(dir);\r\n const migrationFiles = files.filter(\r\n (f) => f.match(/^\\d+_.*\\.(ts|js|sql)$/)\r\n );\r\n\r\n for (const file of migrationFiles) {\r\n const filePath = join(dir, file);\r\n const [version, ...nameParts] = file.replace(/\\.(ts|js|sql)$/, '').split('_');\r\n const name = nameParts.join('_');\r\n\r\n if (file.endsWith('.sql')) {\r\n // SQL file - parse UP and DOWN sections\r\n const content = await readFile(filePath, 'utf-8');\r\n const [up, down] = this.parseSqlMigration(content);\r\n\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up,\r\n down,\r\n },\r\n ]);\r\n } else {\r\n // TypeScript/JavaScript file - import the module\r\n const module = await import(filePath);\r\n this.addMigrations([\r\n {\r\n version: version!,\r\n name,\r\n up: module.up,\r\n down: module.down,\r\n transactional: module.transactional,\r\n },\r\n ]);\r\n }\r\n }\r\n }\r\n\r\n /**\r\n * Parse SQL migration file with -- UP and -- DOWN sections\r\n */\r\n private parseSqlMigration(content: string): [string, string] {\r\n const upMatch = content.match(/--\\s*UP\\s*\\n([\\s\\S]*?)(?=--\\s*DOWN|$)/i);\r\n const downMatch = content.match(/--\\s*DOWN\\s*\\n([\\s\\S]*?)$/i);\r\n\r\n const up = upMatch?.[1]?.trim() ?? content.trim();\r\n const down = downMatch?.[1]?.trim() ?? '';\r\n\r\n return [up, down];\r\n }\r\n\r\n /**\r\n * Get current migration status\r\n */\r\n async status(): Promise<MigrationStatus> {\r\n await this.initialize();\r\n\r\n // Get applied migrations\r\n const result = await this.db.raw<{\r\n version: string;\r\n name: string;\r\n applied_at: Date;\r\n execution_time: number;\r\n checksum: string | null;\r\n }>(\r\n `SELECT version, name, applied_at, execution_time, checksum\r\n FROM ${this.tableName}\r\n ORDER BY version ASC`\r\n );\r\n\r\n const applied: MigrationRecord[] = result.data.map((row) => ({\r\n version: row.version,\r\n name: row.name,\r\n appliedAt: new Date(row.applied_at),\r\n executionTime: row.execution_time,\r\n checksum: row.checksum ?? undefined,\r\n }));\r\n\r\n const appliedVersions = new Set(applied.map((m) => m.version));\r\n const sortedMigrations = sortMigrations(this.migrations);\r\n\r\n const pending = sortedMigrations.filter(\r\n (m) => !appliedVersions.has(m.version)\r\n );\r\n\r\n return {\r\n applied,\r\n pending,\r\n currentVersion: applied.length > 0 ? applied[applied.length - 1]!.version : null,\r\n latestVersion:\r\n sortedMigrations.length > 0\r\n ? sortedMigrations[sortedMigrations.length - 1]!.version\r\n : null,\r\n };\r\n }\r\n\r\n /**\r\n * Run all pending migrations (or up to a specific version)\r\n */\r\n async up(options: { dryRun?: boolean; to?: string } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, to } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n let pending = status.pending;\r\n\r\n // Filter to specific version if requested\r\n if (to) {\r\n const targetIndex = pending.findIndex((m) => m.version === to);\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${to} not found in pending migrations`);\r\n }\r\n pending = pending.slice(0, targetIndex + 1);\r\n }\r\n\r\n for (const migration of pending) {\r\n const result = await this.runMigration(migration, 'up', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break; // Stop on first failure\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback migrations\r\n */\r\n async down(options: { dryRun?: boolean; steps?: number } = {}): Promise<MigrationResult[]> {\r\n const { dryRun = false, steps = 1 } = options;\r\n const results: MigrationResult[] = [];\r\n\r\n if (!dryRun) {\r\n const acquired = await this.lock();\r\n if (!acquired) {\r\n throw new Error('Could not acquire migration lock. Another migration may be in progress.');\r\n }\r\n }\r\n\r\n try {\r\n const status = await this.status();\r\n\r\n // Get the last N applied migrations (in reverse order)\r\n const toRollback = status.applied.slice(-steps).reverse();\r\n\r\n for (const record of toRollback) {\r\n const migration = this.migrations.find((m) => m.version === record.version);\r\n if (!migration) {\r\n throw new Error(\r\n `Migration ${record.version} was applied but is not registered. Cannot rollback.`\r\n );\r\n }\r\n\r\n const result = await this.runMigration(migration, 'down', dryRun);\r\n results.push(result);\r\n\r\n if (!result.success) {\r\n break;\r\n }\r\n }\r\n } finally {\r\n if (!dryRun) {\r\n await this.unlock();\r\n }\r\n }\r\n\r\n return results;\r\n }\r\n\r\n /**\r\n * Rollback all migrations and re-run them\r\n */\r\n async reset(options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const downResults = await this.down({\r\n dryRun: options.dryRun,\r\n steps: status.applied.length,\r\n });\r\n\r\n // Only proceed with up if all downs succeeded\r\n if (downResults.every((r) => r.success)) {\r\n const upResults = await this.up({ dryRun: options.dryRun });\r\n return [...downResults, ...upResults];\r\n }\r\n\r\n return downResults;\r\n }\r\n\r\n /**\r\n * Migrate to a specific version\r\n */\r\n async goto(version: string, options: { dryRun?: boolean } = {}): Promise<MigrationResult[]> {\r\n const status = await this.status();\r\n const currentVersion = status.currentVersion;\r\n const results: MigrationResult[] = [];\r\n\r\n // If already at target, nothing to do\r\n if (currentVersion === version) {\r\n return results;\r\n }\r\n\r\n // Determine direction\r\n const isUp = !currentVersion || version > currentVersion;\r\n\r\n if (isUp) {\r\n return this.up({ ...options, to: version });\r\n } else {\r\n // Find how many steps down we need to go\r\n const currentIndex = status.applied.findIndex((m) => m.version === currentVersion);\r\n const targetIndex = status.applied.findIndex((m) => m.version === version);\r\n\r\n if (targetIndex === -1) {\r\n throw new Error(`Target version ${version} not found in applied migrations`);\r\n }\r\n\r\n const steps = currentIndex - targetIndex;\r\n return this.down({ ...options, steps });\r\n }\r\n }\r\n\r\n /**\r\n * Run a single migration\r\n */\r\n private async runMigration(\r\n migration: Migration,\r\n direction: 'up' | 'down',\r\n dryRun: boolean\r\n ): Promise<MigrationResult> {\r\n const startTime = Date.now();\r\n const action = direction === 'up' ? migration.up : migration.down;\r\n\r\n try {\r\n if (dryRun) {\r\n // Just simulate - don't actually run\r\n return {\r\n migration,\r\n success: true,\r\n executionTime: 0,\r\n dryRun: true,\r\n };\r\n }\r\n\r\n const transactional = migration.transactional !== false;\r\n const runAction = async (db: IMigrationDatabase) => {\r\n if (typeof action === 'string') {\r\n const result = await db.raw(action);\r\n if (result.error) {\r\n throw result.error;\r\n }\r\n } else {\r\n await action(db);\r\n }\r\n };\r\n\r\n if (transactional) {\r\n await this.db.transaction(async (tx) => {\r\n await runAction(tx);\r\n });\r\n } else {\r\n await runAction(this.db);\r\n }\r\n\r\n const executionTime = Date.now() - startTime;\r\n\r\n // Update tracking table\r\n if (direction === 'up') {\r\n await this.db.raw(\r\n `INSERT INTO ${this.tableName} (version, name, execution_time, checksum)\r\n VALUES ($1, $2, $3, $4)`,\r\n [migration.version, migration.name, executionTime, migration.checksum]\r\n );\r\n } else {\r\n await this.db.raw(\r\n `DELETE FROM ${this.tableName} WHERE version = $1`,\r\n [migration.version]\r\n );\r\n }\r\n\r\n return {\r\n migration,\r\n success: true,\r\n executionTime,\r\n dryRun: false,\r\n };\r\n } catch (error) {\r\n return {\r\n migration,\r\n success: false,\r\n executionTime: Date.now() - startTime,\r\n error: error instanceof Error ? error : new Error(String(error)),\r\n dryRun: false,\r\n };\r\n }\r\n }\r\n\r\n /**\r\n * Create a new migration file\r\n */\r\n async create(name: string): Promise<string> {\r\n const { writeFile, mkdir } = await import('fs/promises');\r\n const { join } = await import('path');\r\n\r\n if (!this.config.migrationsDir) {\r\n throw new Error('migrationsDir must be configured to create migrations');\r\n }\r\n\r\n // Ensure directory exists\r\n await mkdir(this.config.migrationsDir, { recursive: true });\r\n\r\n // Generate version timestamp\r\n const now = new Date();\r\n const version = [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n\r\n const safeName = name.replace(/[^a-zA-Z0-9_]/g, '_').toLowerCase();\r\n const fileName = `${version}_${safeName}.sql`;\r\n const filePath = join(this.config.migrationsDir, fileName);\r\n\r\n const template = `-- Migration: ${name}\r\n-- Version: ${version}\r\n-- Created: ${now.toISOString()}\r\n\r\n-- UP\r\n-- Add your forward migration SQL here\r\n\r\n\r\n-- DOWN\r\n-- Add your rollback migration SQL here\r\n\r\n`;\r\n\r\n await writeFile(filePath, template, 'utf-8');\r\n\r\n return filePath;\r\n }\r\n\r\n /**\r\n * Validate migration integrity\r\n */\r\n async validate(): Promise<{ valid: boolean; errors: string[] }> {\r\n const errors: string[] = [];\r\n const status = await this.status();\r\n\r\n if (!this.config.validateChecksums) {\r\n return { valid: true, errors };\r\n }\r\n\r\n for (const applied of status.applied) {\r\n const migration = this.migrations.find((m) => m.version === applied.version);\r\n\r\n if (!migration) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) was applied but is not registered`\r\n );\r\n continue;\r\n }\r\n\r\n if (applied.checksum && migration.checksum !== applied.checksum) {\r\n errors.push(\r\n `Migration ${applied.version} (${applied.name}) has been modified since it was applied`\r\n );\r\n }\r\n }\r\n\r\n return {\r\n valid: errors.length === 0,\r\n errors,\r\n };\r\n }\r\n}\r\n","/**\r\n * Migration Helper Functions\r\n *\r\n * Utilities for creating migrations in a type-safe and convenient way.\r\n */\r\n\r\nimport type { Migration, IMigrationDatabase } from '../interfaces/IMigration';\r\n\r\n/**\r\n * Create a SQL-based migration\r\n *\r\n * @example\r\n * ```typescript\r\n * export default sqlMigration({\r\n * version: '20240101000000',\r\n * name: 'create_users',\r\n * up: `\r\n * CREATE TABLE users (\r\n * id UUID PRIMARY KEY DEFAULT gen_random_uuid(),\r\n * email VARCHAR(255) UNIQUE NOT NULL,\r\n * created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()\r\n * )\r\n * `,\r\n * down: `DROP TABLE users`\r\n * });\r\n * ```\r\n */\r\nexport function sqlMigration(migration: {\r\n version: string;\r\n name: string;\r\n up: string;\r\n down: string;\r\n transactional?: boolean;\r\n}): Migration {\r\n return {\r\n version: migration.version,\r\n name: migration.name,\r\n up: migration.up,\r\n down: migration.down,\r\n transactional: migration.transactional,\r\n };\r\n}\r\n\r\n/**\r\n * Create a function-based migration for complex logic\r\n *\r\n * @example\r\n * ```typescript\r\n * export default createMigration({\r\n * version: '20240102000000',\r\n * name: 'seed_initial_data',\r\n * up: async (db) => {\r\n * await db.raw(`INSERT INTO users (email) VALUES ('admin@example.com')`);\r\n * await db.raw(`INSERT INTO settings (key, value) VALUES ('version', '1.0.0')`);\r\n * },\r\n * down: async (db) => {\r\n * await db.raw(`DELETE FROM settings WHERE key = 'version'`);\r\n * await db.raw(`DELETE FROM users WHERE email = 'admin@example.com'`);\r\n * }\r\n * });\r\n * ```\r\n */\r\nexport function createMigration(migration: {\r\n version: string;\r\n name: string;\r\n up: (db: IMigrationDatabase) => Promise<void>;\r\n down: (db: IMigrationDatabase) => Promise<void>;\r\n transactional?: boolean;\r\n}): Migration {\r\n return {\r\n version: migration.version,\r\n name: migration.name,\r\n up: migration.up,\r\n down: migration.down,\r\n transactional: migration.transactional,\r\n };\r\n}\r\n\r\n/**\r\n * Type-safe migration definition with inference\r\n * Useful for defining migrations in separate files\r\n *\r\n * @example\r\n * ```typescript\r\n * // migrations/20240101000000_create_users.ts\r\n * export const migration = defineMigration({\r\n * version: '20240101000000',\r\n * name: 'create_users',\r\n * up: 'CREATE TABLE users (...)',\r\n * down: 'DROP TABLE users'\r\n * });\r\n *\r\n * // Or with functions\r\n * export const migration = defineMigration({\r\n * version: '20240102000000',\r\n * name: 'complex_migration',\r\n * up: async (db) => { ... },\r\n * down: async (db) => { ... }\r\n * });\r\n * ```\r\n */\r\nexport function defineMigration<\r\n T extends {\r\n version: string;\r\n name: string;\r\n up: string | ((db: IMigrationDatabase) => Promise<void>);\r\n down: string | ((db: IMigrationDatabase) => Promise<void>);\r\n transactional?: boolean;\r\n }\r\n>(migration: T): Migration {\r\n return migration;\r\n}\r\n\r\n/**\r\n * Generate a version timestamp for new migrations\r\n *\r\n * @example\r\n * ```typescript\r\n * const version = generateVersion(); // '20240315143052'\r\n * ```\r\n */\r\nexport function generateVersion(): string {\r\n const now = new Date();\r\n return [\r\n now.getFullYear(),\r\n String(now.getMonth() + 1).padStart(2, '0'),\r\n String(now.getDate()).padStart(2, '0'),\r\n String(now.getHours()).padStart(2, '0'),\r\n String(now.getMinutes()).padStart(2, '0'),\r\n String(now.getSeconds()).padStart(2, '0'),\r\n ].join('');\r\n}\r\n\r\n/**\r\n * Common SQL snippets for migrations\r\n */\r\nexport const SQL = {\r\n /**\r\n * Create updated_at trigger function (PostgreSQL)\r\n */\r\n createUpdatedAtFunction: `\r\n CREATE OR REPLACE FUNCTION update_updated_at_column()\r\n RETURNS TRIGGER AS $$\r\n BEGIN\r\n NEW.updated_at = CURRENT_TIMESTAMP;\r\n RETURN NEW;\r\n END;\r\n $$ language 'plpgsql';\r\n `,\r\n\r\n /**\r\n * Create an updated_at trigger for a table\r\n */\r\n createUpdatedAtTrigger: (tableName: string) => `\r\n CREATE TRIGGER update_${tableName}_updated_at\r\n BEFORE UPDATE ON \"${tableName}\"\r\n FOR EACH ROW\r\n EXECUTE FUNCTION update_updated_at_column();\r\n `,\r\n\r\n /**\r\n * Drop an updated_at trigger\r\n */\r\n dropUpdatedAtTrigger: (tableName: string) => `\r\n DROP TRIGGER IF EXISTS update_${tableName}_updated_at ON \"${tableName}\";\r\n `,\r\n\r\n /**\r\n * Standard timestamp columns\r\n */\r\n timestampColumns: `\r\n created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL,\r\n updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP NOT NULL\r\n `,\r\n\r\n /**\r\n * UUID primary key with default\r\n */\r\n uuidPrimaryKey: `id UUID PRIMARY KEY DEFAULT gen_random_uuid()`,\r\n\r\n /**\r\n * Enable UUID extension\r\n */\r\n enableUuidExtension: `CREATE EXTENSION IF NOT EXISTS \"uuid-ossp\"`,\r\n\r\n /**\r\n * Enable pgcrypto for gen_random_uuid()\r\n */\r\n enablePgCrypto: `CREATE EXTENSION IF NOT EXISTS \"pgcrypto\"`,\r\n};\r\n"],"mappings":";;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AA+DA,SAAS,aAAa,QAAoC;AACxD,QAAM,aAAyB,CAAC;AAEhC,MAAI,OAAO,kBAAkB;AAC3B,eAAW,mBAAmB,OAAO;AAAA,EACvC,OAAO;AACL,eAAW,OAAO,OAAO;AACzB,eAAW,OAAO,OAAO;AACzB,eAAW,WAAW,OAAO;AAC7B,eAAW,OAAO,OAAO;AACzB,eAAW,WAAW,OAAO;AAAA,EAC/B;AAEA,MAAI,OAAO,QAAQ,QAAW;AAC5B,eAAW,MAAM,OAAO;AAAA,EAC1B;AAEA,aAAW,MAAM,OAAO,OAAO;AAC/B,aAAW,oBAAoB,OAAO,qBAAqB;AAC3D,aAAW,0BAA0B,OAAO,2BAA2B;AACvE,aAAW,mBAAmB,OAAO,mBAAmB;AAGxD,MAAI,OAAO,kBAAkB;AAC3B,eAAW,oBAAoB,OAAO;AAAA,EACxC;AAGA,MAAI,OAAO,cAAc;AACvB,eAAW,gBAAgB,OAAO;AAAA,EACpC;AAEA,SAAO;AACT;AAhGA,IAkGa,kBA2HP,qBAsDA;AAnRN;AAAA;AAAA;AAkGO,IAAM,mBAAN,MAAM,kBAAsC;AAAA,MACzC;AAAA,MACA;AAAA,MAER,YAAY,MAAY,SAAyB,CAAC,GAAG;AACnD,aAAK,OAAO;AACZ,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,OAAO,QAAmD;AAErE,cAAM,EAAE,KAAK,IAAI,MAAM,OAAO,IAAI;AAClC,cAAM,aAAa,aAAa,MAAM;AACtC,cAAM,OAAO,IAAI,KAAK,UAAU;AAGhC,cAAM,SAAS,MAAM,KAAK,QAAQ;AAClC,eAAO,QAAQ;AAEf,eAAO,IAAI,kBAAiB,MAAM,MAAM;AAAA,MAC1C;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,UAAqC;AAChD,cAAM,SAAyB;AAAA,UAC7B,kBAAkB,QAAQ,IAAI;AAAA,UAC9B,MAAM,QAAQ,IAAI,iBAAiB,QAAQ,IAAI;AAAA,UAC/C,MAAM,SAAS,QAAQ,IAAI,iBAAiB,QAAQ,IAAI,UAAU,QAAQ,EAAE;AAAA,UAC5E,UAAU,QAAQ,IAAI,qBAAqB,QAAQ,IAAI;AAAA,UACvD,MAAM,QAAQ,IAAI,iBAAiB,QAAQ,IAAI;AAAA,UAC/C,UAAU,QAAQ,IAAI,qBAAqB,QAAQ,IAAI;AAAA,UACvD,KAAK,SAAS,QAAQ,IAAI,qBAAqB,MAAM,EAAE;AAAA,UACvD,KACE,QAAQ,IAAI,iBAAiB,SACzB,EAAE,oBAAoB,QAAQ,IAAI,qCAAqC,QAAQ,IAC/E;AAAA,UACN,iBAAiB,QAAQ,IAAI,qBAAqB;AAAA,QACpD;AAEA,eAAO,kBAAiB,OAAO,MAAM;AAAA,MACvC;AAAA,MAEA,KAAkB,OAAiC;AACjD,eAAO,IAAI,qBAAwB,KAAK,MAAM,KAAK;AAAA,MACrD;AAAA,MAEA,MAAM,IAAiB,KAAa,QAA6C;AAC/E,YAAI;AACF,gBAAM,SAAwB,MAAM,KAAK,KAAK,MAAM,KAAK,MAAM;AAC/D,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,OAAO,OAAO,YAAY;AAAA,UAC5B;AAAA,QACF,SAAS,OAAO;AACd,iBAAO;AAAA,YACL,MAAM,CAAC;AAAA,YACP,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,YAAe,IAA+C;AAClE,cAAM,SAAS,MAAM,KAAK,KAAK,QAAQ;AAEvC,YAAI;AACF,gBAAM,OAAO,MAAM,OAAO;AAG1B,gBAAM,aAAa,IAAI,oBAAoB,MAAM;AAEjD,gBAAM,SAAS,MAAM,GAAG,UAAU;AAElC,gBAAM,OAAO,MAAM,QAAQ;AAC3B,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,OAAO,MAAM,UAAU;AAC7B,gBAAM;AAAA,QACR,UAAE;AACA,iBAAO,QAAQ;AAAA,QACjB;AAAA,MACF;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,KAAK,MAAM,oBAAoB;AACzD,iBAAO,OAAO,KAAK,SAAS;AAAA,QAC9B,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAC3B,cAAM,KAAK,KAAK,IAAI;AAAA,MACtB;AAAA;AAAA;AAAA;AAAA,MAKA,eAIE;AACA,eAAO;AAAA,UACL,YAAY,KAAK,KAAK;AAAA,UACtB,WAAW,KAAK,KAAK;AAAA,UACrB,cAAc,KAAK,KAAK;AAAA,QAC1B;AAAA,MACF;AAAA,IACF;AAKA,IAAM,sBAAN,MAA+C;AAAA,MAC7C,YAAoB,QAAoB;AAApB;AAAA,MAAqB;AAAA,MAEzC,KAAkB,OAAiC;AACjD,eAAO,IAAI,qBAAwB,KAAK,QAAQ,KAAK;AAAA,MACvD;AAAA,MAEA,MAAM,IAAiB,KAAa,QAA6C;AAC/E,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,MAAM;AAClD,iBAAO;AAAA,YACL,MAAM,OAAO;AAAA,YACb,OAAO,OAAO,YAAY;AAAA,UAC5B;AAAA,QACF,SAAS,OAAO;AACd,iBAAO;AAAA,YACL,MAAM,CAAC;AAAA,YACP,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,YAAe,IAA+C;AAElE,cAAM,gBAAgB,MAAM,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;AAE7E,YAAI;AACF,gBAAM,KAAK,OAAO,MAAM,aAAa,aAAa,EAAE;AACpD,gBAAM,SAAS,MAAM,GAAG,IAAI;AAC5B,gBAAM,KAAK,OAAO,MAAM,qBAAqB,aAAa,EAAE;AAC5D,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,gBAAM,KAAK,OAAO,MAAM,yBAAyB,aAAa,EAAE;AAChE,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AACF,gBAAM,KAAK,OAAO,MAAM,UAAU;AAClC,iBAAO;AAAA,QACT,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAAA,MAE7B;AAAA,IACF;AAKA,IAAM,uBAAN,MAAoE;AAAA,MAC1D;AAAA,MACA;AAAA,MACA,UAAoB,CAAC,GAAG;AAAA,MACxB,SAAsE,CAAC;AAAA,MACvE,WAAyD,CAAC;AAAA,MAC1D,WAAiE;AAAA,MACjE,SAAwB;AAAA,MACxB,UAAkB;AAAA,MAClB,cAAmC;AAAA,MACnC,cAAiC;AAAA,MACjC,cAAuB;AAAA,MACvB,aAAuB,CAAC,GAAG;AAAA,MAEnC,YAAY,QAA2B,WAAmB;AACxD,aAAK,SAAS;AACd,aAAK,YAAY,KAAK,iBAAiB,SAAS;AAAA,MAClD;AAAA,MAEA,OAAO,SAA+C;AACpD,YAAI,SAAS;AACX,eAAK,UAAU,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,OAAO;AAAA,QAC5D;AACA,eAAO;AAAA,MACT;AAAA,MAEA,OAAO,MAAmD;AACxD,aAAK,cAAc,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AACrD,eAAO;AAAA,MACT;AAAA,MAEA,OAAO,MAAoC;AACzC,aAAK,cAAc;AACnB,eAAO;AAAA,MACT;AAAA,MAEA,SAA2B;AACzB,aAAK,cAAc;AACnB,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,QAAgB,UAAkB,OAAkC;AACxE,aAAK,OAAO,KAAK,EAAE,QAAQ,UAAU,MAAM,CAAC;AAC5C,eAAO;AAAA,MACT;AAAA,MAEA,QAAQ,QAAgB,QAAqC;AAC3D,aAAK,SAAS,KAAK,EAAE,QAAQ,OAAO,CAAC;AACrC,eAAO;AAAA,MACT;AAAA,MAEA,QAAQ,QAAgB,YAA4B,OAAyB;AAC3E,aAAK,WAAW,EAAE,QAAQ,UAAU;AACpC,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAiC;AACrC,aAAK,SAAS;AACd,eAAO;AAAA,MACT;AAAA,MAEA,OAAO,OAAiC;AACtC,aAAK,UAAU;AACf,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,SAAqD;AACzD,aAAK,SAAS;AACd,cAAM,SAAS,MAAM,KAAK,QAAQ;AAElC,YAAI,OAAO,OAAO;AAChB,iBAAO,EAAE,MAAM,MAAM,OAAO,OAAO,MAAM;AAAA,QAC3C;AAEA,eAAO,EAAE,MAAM,OAAO,KAAK,CAAC,KAAK,KAAK;AAAA,MACxC;AAAA,MAEA,MAAM,UAAmC;AACvC,YAAI;AACF,cAAI,KAAK,aAAa;AACpB,mBAAO,MAAM,KAAK,cAAc;AAAA,UAClC;AAEA,cAAI,KAAK,aAAa;AACpB,mBAAO,MAAM,KAAK,cAAc;AAAA,UAClC;AAEA,cAAI,KAAK,aAAa;AACpB,mBAAO,MAAM,KAAK,cAAc;AAAA,UAClC;AAEA,iBAAO,MAAM,KAAK,cAAc;AAAA,QAClC,SAAS,OAAO;AACd,iBAAO;AAAA,YACL,MAAM,CAAC;AAAA,YACP,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAc,gBAAyC;AACrD,cAAM,SAAoB,CAAC;AAC3B,YAAI,aAAa;AAGjB,cAAM,eAAe,KAAK,QAAQ,IAAI,CAAC,QAAQ,KAAK,iBAAiB,GAAG,CAAC,EAAE,KAAK,IAAI;AACpF,YAAI,MAAM,UAAU,YAAY,SAAS,KAAK,SAAS;AAGvD,cAAM,eAAyB,CAAC;AAEhC,mBAAW,EAAE,QAAQ,UAAU,MAAM,KAAK,KAAK,QAAQ;AACrD,uBAAa,KAAK,GAAG,KAAK,iBAAiB,MAAM,CAAC,IAAI,KAAK,YAAY,QAAQ,CAAC,KAAK,YAAY,EAAE;AACnG,iBAAO,KAAK,KAAK;AAAA,QACnB;AAEA,mBAAW,EAAE,QAAQ,OAAO,KAAK,KAAK,UAAU;AAC9C,gBAAM,eAAe,OAAO,IAAI,MAAM,IAAI,YAAY,EAAE,EAAE,KAAK,IAAI;AACnE,uBAAa,KAAK,GAAG,KAAK,iBAAiB,MAAM,CAAC,QAAQ,YAAY,GAAG;AACzE,iBAAO,KAAK,GAAG,MAAM;AAAA,QACvB;AAEA,YAAI,aAAa,SAAS,GAAG;AAC3B,iBAAO,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,QAC7C;AAGA,YAAI,KAAK,UAAU;AACjB,iBAAO,aAAa,KAAK,iBAAiB,KAAK,SAAS,MAAM,CAAC,IAAI,KAAK,SAAS,UAAU,YAAY,CAAC;AAAA,QAC1G;AAGA,YAAI,KAAK,WAAW,MAAM;AACxB,iBAAO,WAAW,YAAY;AAC9B,iBAAO,KAAK,KAAK,MAAM;AAAA,QACzB;AAEA,YAAI,KAAK,UAAU,GAAG;AACpB,iBAAO,YAAY,YAAY;AAC/B,iBAAO,KAAK,KAAK,OAAO;AAAA,QAC1B;AAEA,cAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,MAAM;AAClD,eAAO;AAAA,UACL,MAAM,OAAO;AAAA,UACb,OAAO,OAAO,YAAY;AAAA,QAC5B;AAAA,MACF;AAAA,MAEA,MAAc,gBAAyC;AACrD,YAAI,CAAC,KAAK,eAAe,KAAK,YAAY,WAAW,GAAG;AACtD,iBAAO,EAAE,MAAM,CAAC,EAAE;AAAA,QACpB;AAEA,cAAM,SAAoB,CAAC;AAC3B,YAAI,aAAa;AAGjB,cAAM,UAAU,oBAAI,IAAY;AAChC,mBAAW,OAAO,KAAK,aAAa;AAClC,iBAAO,KAAK,GAAa,EAAE,QAAQ,CAAC,QAAQ,QAAQ,IAAI,GAAG,CAAC;AAAA,QAC9D;AACA,cAAM,aAAa,MAAM,KAAK,OAAO;AAGrC,cAAM,eAAe,WAAW,IAAI,CAAC,QAAQ,KAAK,iBAAiB,GAAG,CAAC,EAAE,KAAK,IAAI;AAGlF,cAAM,YAAsB,CAAC;AAC7B,mBAAW,OAAO,KAAK,aAAa;AAClC,gBAAM,YAAsB,CAAC;AAC7B,qBAAW,OAAO,YAAY;AAC5B,sBAAU,KAAK,IAAI,YAAY,EAAE;AACjC,mBAAO,KAAM,IAAgC,GAAG,KAAK,IAAI;AAAA,UAC3D;AACA,oBAAU,KAAK,IAAI,UAAU,KAAK,IAAI,CAAC,GAAG;AAAA,QAC5C;AAEA,cAAM,MAAM,eAAe,KAAK,SAAS,KAAK,YAAY,YAAY,UAAU,KAAK,IAAI,CAAC,cAAc,KAAK,WAAW,KAAK,IAAI,CAAC;AAElI,cAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,MAAM;AAClD,eAAO;AAAA,UACL,MAAM,OAAO;AAAA,UACb,OAAO,OAAO,YAAY;AAAA,QAC5B;AAAA,MACF;AAAA,MAEA,MAAc,gBAAyC;AACrD,YAAI,CAAC,KAAK,aAAa;AACrB,iBAAO,EAAE,MAAM,CAAC,EAAE;AAAA,QACpB;AAEA,cAAM,SAAoB,CAAC;AAC3B,YAAI,aAAa;AAGjB,cAAM,aAAuB,CAAC;AAC9B,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,KAAK,WAAqB,GAAG;AACrE,qBAAW,KAAK,GAAG,KAAK,iBAAiB,GAAG,CAAC,OAAO,YAAY,EAAE;AAClE,iBAAO,KAAK,KAAK;AAAA,QACnB;AAEA,YAAI,MAAM,UAAU,KAAK,SAAS,QAAQ,WAAW,KAAK,IAAI,CAAC;AAG/D,cAAM,eAAyB,CAAC;AAEhC,mBAAW,EAAE,QAAQ,UAAU,MAAM,KAAK,KAAK,QAAQ;AACrD,uBAAa,KAAK,GAAG,KAAK,iBAAiB,MAAM,CAAC,IAAI,KAAK,YAAY,QAAQ,CAAC,KAAK,YAAY,EAAE;AACnG,iBAAO,KAAK,KAAK;AAAA,QACnB;AAEA,mBAAW,EAAE,QAAQ,OAAO,KAAK,KAAK,UAAU;AAC9C,gBAAM,eAAe,OAAO,IAAI,MAAM,IAAI,YAAY,EAAE,EAAE,KAAK,IAAI;AACnE,uBAAa,KAAK,GAAG,KAAK,iBAAiB,MAAM,CAAC,QAAQ,YAAY,GAAG;AACzE,iBAAO,KAAK,GAAG,MAAM;AAAA,QACvB;AAEA,YAAI,aAAa,SAAS,GAAG;AAC3B,iBAAO,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,QAC7C;AAEA,eAAO,cAAc,KAAK,WAAW,KAAK,IAAI,CAAC;AAE/C,cAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,MAAM;AAClD,eAAO;AAAA,UACL,MAAM,OAAO;AAAA,UACb,OAAO,OAAO,YAAY;AAAA,QAC5B;AAAA,MACF;AAAA,MAEA,MAAc,gBAAyC;AACrD,cAAM,SAAoB,CAAC;AAC3B,YAAI,aAAa;AAEjB,YAAI,MAAM,eAAe,KAAK,SAAS;AAGvC,cAAM,eAAyB,CAAC;AAEhC,mBAAW,EAAE,QAAQ,UAAU,MAAM,KAAK,KAAK,QAAQ;AACrD,uBAAa,KAAK,GAAG,KAAK,iBAAiB,MAAM,CAAC,IAAI,KAAK,YAAY,QAAQ,CAAC,KAAK,YAAY,EAAE;AACnG,iBAAO,KAAK,KAAK;AAAA,QACnB;AAEA,mBAAW,EAAE,QAAQ,OAAO,KAAK,KAAK,UAAU;AAC9C,gBAAM,eAAe,OAAO,IAAI,MAAM,IAAI,YAAY,EAAE,EAAE,KAAK,IAAI;AACnE,uBAAa,KAAK,GAAG,KAAK,iBAAiB,MAAM,CAAC,QAAQ,YAAY,GAAG;AACzE,iBAAO,KAAK,GAAG,MAAM;AAAA,QACvB;AAEA,YAAI,aAAa,SAAS,GAAG;AAC3B,iBAAO,UAAU,aAAa,KAAK,OAAO,CAAC;AAAA,QAC7C;AAEA,eAAO,cAAc,KAAK,WAAW,KAAK,IAAI,CAAC;AAE/C,cAAM,SAAS,MAAM,KAAK,OAAO,MAAM,KAAK,MAAM;AAClD,eAAO;AAAA,UACL,MAAM,OAAO;AAAA,UACb,OAAO,OAAO,YAAY;AAAA,QAC5B;AAAA,MACF;AAAA,MAEQ,iBAAiB,YAA4B;AAEnD,YAAI,eAAe,IAAK,QAAO;AAG/B,YAAI,WAAW,SAAS,GAAG,GAAG;AAC5B,iBAAO,WACJ,MAAM,GAAG,EACT,IAAI,CAAC,SAAS,IAAI,KAAK,QAAQ,MAAM,IAAI,CAAC,GAAG,EAC7C,KAAK,GAAG;AAAA,QACb;AAGA,eAAO,IAAI,WAAW,QAAQ,MAAM,IAAI,CAAC;AAAA,MAC3C;AAAA,MAEQ,YAAY,UAA0B;AAC5C,gBAAQ,SAAS,YAAY,GAAG;AAAA,UAC9B,KAAK;AAAA,UACL,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AAAA,UACL,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT,KAAK;AACH,mBAAO;AAAA,UACT;AACE,mBAAO;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;ACvkBA;AAAA;AAAA;AAAA;AAAA,IAca,kBA0CP;AAxDN;AAAA;AAAA;AAcO,IAAM,mBAAN,MAA4C;AAAA,MACzC;AAAA,MAER,YAAY,QAAwB;AAClC,aAAK,SAAS;AAAA,MAChB;AAAA,MAEA,KAAkB,OAAiC;AACjD,eAAO,IAAI,qBAAwB,KAAK,QAAQ,KAAK;AAAA,MACvD;AAAA,MAEA,MAAM,IAAiB,KAAa,QAA6C;AAG/E,gBAAQ,KAAK,iFAAiF;AAC9F,eAAO,EAAE,MAAM,CAAC,EAAE;AAAA,MACpB;AAAA,MAEA,MAAM,YAAe,IAA+C;AAGlE,gBAAQ,KAAK,kFAAkF;AAC/F,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AAEF,gBAAM,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,KAAK,eAAe,EAAE,OAAO,GAAG,EAAE,MAAM,CAAC;AAG7E,iBAAO,CAAC,SAAS,MAAM,SAAS;AAAA,QAClC,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAAA,MAE7B;AAAA,IACF;AAEA,IAAM,uBAAN,MAAoE;AAAA,MAC1D;AAAA,MACA;AAAA,MACA,UAAkB;AAAA,MAClB,SAAsE,CAAC;AAAA,MACvE,WAAyD,CAAC;AAAA,MAC1D,WAAiE;AAAA,MACjE,SAAwB;AAAA,MACxB,UAAkB;AAAA,MAClB,cAAmC;AAAA,MACnC,cAAiC;AAAA,MACjC,cAAuB;AAAA,MAE/B,YAAY,QAAwB,WAAmB;AACrD,aAAK,SAAS;AACd,aAAK,YAAY;AAAA,MACnB;AAAA,MAEA,OAAO,SAA+C;AACpD,YAAI,SAAS;AACX,eAAK,UAAU,MAAM,QAAQ,OAAO,IAAI,QAAQ,KAAK,IAAI,IAAI;AAAA,QAC/D;AACA,eAAO;AAAA,MACT;AAAA,MAEA,OAAO,MAAmD;AACxD,aAAK,cAAc,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AACrD,eAAO;AAAA,MACT;AAAA,MAEA,OAAO,MAAoC;AACzC,aAAK,cAAc;AACnB,eAAO;AAAA,MACT;AAAA,MAEA,SAA2B;AACzB,aAAK,cAAc;AACnB,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,QAAgB,UAAkB,OAAkC;AACxE,aAAK,OAAO,KAAK,EAAE,QAAQ,UAAU,MAAM,CAAC;AAC5C,eAAO;AAAA,MACT;AAAA,MAEA,QAAQ,QAAgB,QAAqC;AAC3D,aAAK,SAAS,KAAK,EAAE,QAAQ,OAAO,CAAC;AACrC,eAAO;AAAA,MACT;AAAA,MAEA,QAAQ,QAAgB,YAA4B,OAAyB;AAC3E,aAAK,WAAW,EAAE,QAAQ,UAAU;AACpC,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAiC;AACrC,aAAK,SAAS;AACd,eAAO;AAAA,MACT;AAAA,MAEA,OAAO,OAAiC;AACtC,aAAK,UAAU;AACf,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,SAAqD;AACzD,cAAM,QAAQ,KAAK,iBAAiB,EAAE,MAAM,CAAC,EAAE,OAAO;AACtD,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM;AAE9B,YAAI,SAAS,MAAM,SAAS,YAAY;AACtC,iBAAO,EAAE,MAAM,MAAM,OAAO,IAAI,MAAM,MAAM,OAAO,EAAE;AAAA,QACvD;AAEA,eAAO,EAAE,KAAuB;AAAA,MAClC;AAAA,MAEA,MAAM,UAAmC;AAEvC,YAAI,KAAK,aAAa;AACpB,gBAAM,EAAE,MAAAA,OAAM,OAAAC,OAAM,IAAI,MAAM,KAAK,OAChC,KAAK,KAAK,SAAS,EACnB,OAAO,KAAK,WAAwC,EACpD,OAAO;AAEV,cAAIA,QAAO;AACT,mBAAO,EAAE,MAAM,CAAC,GAAG,OAAO,IAAI,MAAMA,OAAM,OAAO,EAAE;AAAA,UACrD;AACA,iBAAO,EAAE,MAAOD,SAAQ,CAAC,EAAU;AAAA,QACrC;AAGA,YAAI,KAAK,aAAa;AACpB,cAAIE,SAAQ,KAAK,OACd,KAAK,KAAK,SAAS,EACnB,OAAO,KAAK,WAAsC;AAErD,UAAAA,SAAQ,KAAK,aAAaA,MAAK;AAC/B,gBAAM,EAAE,MAAAF,OAAM,OAAAC,OAAM,IAAI,MAAMC,OAAM,OAAO;AAE3C,cAAID,QAAO;AACT,mBAAO,EAAE,MAAM,CAAC,GAAG,OAAO,IAAI,MAAMA,OAAM,OAAO,EAAE;AAAA,UACrD;AACA,iBAAO,EAAE,MAAOD,SAAQ,CAAC,GAAW,OAAOA,OAAM,OAAO;AAAA,QAC1D;AAGA,YAAI,KAAK,aAAa;AACpB,cAAIE,SAAQ,KAAK,OAAO,KAAK,KAAK,SAAS,EAAE,OAAO;AACpD,UAAAA,SAAQ,KAAK,aAAaA,MAAK;AAC/B,gBAAM,EAAE,MAAAF,OAAM,OAAAC,OAAM,IAAI,MAAMC,OAAM,OAAO;AAE3C,cAAID,QAAO;AACT,mBAAO,EAAE,MAAM,CAAC,GAAG,OAAO,IAAI,MAAMA,OAAM,OAAO,EAAE;AAAA,UACrD;AACA,iBAAO,EAAE,MAAOD,SAAQ,CAAC,GAAW,OAAOA,OAAM,OAAO;AAAA,QAC1D;AAGA,cAAM,QAAQ,KAAK,iBAAiB;AACpC,cAAM,EAAE,MAAM,OAAO,MAAM,IAAI,MAAM;AAErC,YAAI,OAAO;AACT,iBAAO,EAAE,MAAM,CAAC,GAAG,OAAO,IAAI,MAAM,MAAM,OAAO,EAAE;AAAA,QACrD;AAEA,eAAO,EAAE,MAAO,QAAQ,CAAC,GAAW,OAAO,SAAS,OAAU;AAAA,MAChE;AAAA,MAEQ,mBAAmB;AACzB,YAAI,QAAQ,KAAK,OAAO,KAAK,KAAK,SAAS,EAAE,OAAO,KAAK,OAAO;AAGhE,gBAAQ,KAAK,aAAa,KAAK;AAG/B,YAAI,KAAK,UAAU;AACjB,kBAAQ,MAAM,MAAM,KAAK,SAAS,QAAQ,EAAE,WAAW,KAAK,SAAS,cAAc,MAAM,CAAC;AAAA,QAC5F;AAGA,YAAI,KAAK,WAAW,MAAM;AACxB,kBAAQ,MAAM,MAAM,KAAK,MAAM;AAAA,QACjC;AAEA,YAAI,KAAK,UAAU,GAAG;AACpB,kBAAQ,MAAM,MAAM,KAAK,SAAS,KAAK,WAAW,KAAK,UAAU,OAAQ,CAAC;AAAA,QAC5E;AAEA,eAAO;AAAA,MACT;AAAA;AAAA,MAGQ,aAAa,OAAiB;AACpC,YAAI,SAAS;AAGb,mBAAW,EAAE,QAAQ,UAAU,MAAM,KAAK,KAAK,QAAQ;AACrD,mBAAS,KAAK,cAAc,QAAQ,QAAQ,UAAU,KAAK;AAAA,QAC7D;AAGA,mBAAW,EAAE,QAAQ,OAAO,KAAK,KAAK,UAAU;AAC9C,mBAAS,OAAO,GAAG,QAAQ,MAAM;AAAA,QACnC;AAEA,eAAO;AAAA,MACT;AAAA;AAAA,MAGQ,cAAc,OAAY,QAAgB,UAAkB,OAAqB;AACvF,gBAAQ,UAAU;AAAA,UAChB,KAAK;AAAA,UACL,KAAK;AACH,mBAAO,MAAM,GAAG,QAAQ,KAAK;AAAA,UAC/B,KAAK;AAAA,UACL,KAAK;AACH,mBAAO,MAAM,IAAI,QAAQ,KAAK;AAAA,UAChC,KAAK;AACH,mBAAO,MAAM,GAAG,QAAQ,KAAK;AAAA,UAC/B,KAAK;AACH,mBAAO,MAAM,IAAI,QAAQ,KAAK;AAAA,UAChC,KAAK;AACH,mBAAO,MAAM,GAAG,QAAQ,KAAK;AAAA,UAC/B,KAAK;AACH,mBAAO,MAAM,IAAI,QAAQ,KAAK;AAAA,UAChC,KAAK;AACH,mBAAO,MAAM,KAAK,QAAQ,KAAe;AAAA,UAC3C,KAAK;AACH,mBAAO,MAAM,MAAM,QAAQ,KAAe;AAAA,UAC5C,KAAK;AACH,mBAAO,MAAM,GAAG,QAAQ,KAAK;AAAA,UAC/B,KAAK;AACH,mBAAO,MAAM,IAAI,QAAQ,MAAM,KAAK;AAAA,UACtC;AACE,mBAAO,MAAM,GAAG,QAAQ,KAAK;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC7PA;AAAA;AAAA;AAAA;AAyFA,SAAS,iBAAiB,QAA8C;AACtE,MAAI,OAAO,KAAK;AACd,WAAO,OAAO;AAAA,EAChB;AAEA,QAAM,UAA0B,CAAC;AAEjC,MAAI,OAAO,KAAM,SAAQ,OAAO,OAAO;AACvC,MAAI,OAAO,KAAM,SAAQ,OAAO,OAAO;AACvC,MAAI,OAAO,SAAU,SAAQ,WAAW,OAAO;AAC/C,MAAI,OAAO,OAAO,OAAW,SAAQ,KAAK,OAAO;AACjD,MAAI,OAAO,SAAU,SAAQ,WAAW,OAAO;AAC/C,MAAI,OAAO,KAAM,SAAQ,OAAO,OAAO;AACvC,MAAI,OAAO,UAAW,SAAQ,YAAY,OAAO;AACjD,MAAI,OAAO,eAAgB,SAAQ,iBAAiB,OAAO;AAC3D,MAAI,OAAO,eAAgB,SAAQ,iBAAiB,OAAO;AAC3D,MAAI,OAAO,UAAW,SAAQ,YAAY,OAAO;AACjD,MAAI,OAAO,yBAAyB,QAAW;AAC7C,YAAQ,uBAAuB,OAAO;AAAA,EACxC;AACA,MAAI,OAAO,YAAa,SAAQ,cAAc,OAAO;AACrD,MAAI,OAAO,uBAAuB,QAAW;AAC3C,YAAQ,qBAAqB,OAAO;AAAA,EACtC;AAGA,MAAI,OAAO,KAAK;AACd,QAAI,OAAO,OAAO,QAAQ,WAAW;AACnC,cAAQ,MAAM,CAAC;AAAA,IACjB,OAAO;AACL,cAAQ,MAAM;AAAA,QACZ,oBAAoB,OAAO,IAAI;AAAA,QAC/B,IAAI,OAAO,IAAI,KAAK,CAAC,OAAO,IAAI,EAAE,IAAI;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;AA/HA,IAiIa;AAjIb;AAAA;AAAA;AAiIO,IAAM,aAAN,MAAM,YAA6B;AAAA,MAChC;AAAA,MACA,mBAAmC;AAAA,MACnC;AAAA,MACA,gBAA6D,oBAAI,IAAI;AAAA,MAE7E,YAAY,QAAiB,SAAsB,CAAC,GAAG;AACrD,aAAK,SAAS;AACd,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,OAAO,QAA0C;AAE5D,cAAM,EAAE,SAAS,MAAM,IAAI,MAAM,OAAO,SAAS;AAEjD,YAAI;AAEJ,YAAI,OAAO,SAAS;AAElB,gBAAM,EAAE,QAAQ,IAAI,MAAM,OAAO,SAAS;AAC1C,mBAAS,IAAI,QAAQ,OAAO,QAAQ,OAAO;AAAA,YACzC,YAAY,OAAO,QAAQ,SAAS,cAAc;AAAA,YAClD,iBAAiB,OAAO,QAAQ,SAAS,mBAAmB;AAAA,YAC5D,cAAc;AAAA,cACZ,UAAU,OAAO;AAAA,cACjB,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,OAAO,QAAQ,YAAY,CAAC,IAAI,OAAO,IAAI,IAAI,CAAC;AAAA,YACjF;AAAA,UACF,CAAC;AAAA,QACH,WAAW,OAAO,UAAU;AAE1B,mBAAS,IAAI,MAAM;AAAA,YACjB,WAAW,OAAO,SAAS;AAAA,YAC3B,MAAM,OAAO,SAAS;AAAA,YACtB,UAAU,OAAO;AAAA,YACjB,kBAAkB,OAAO,SAAS;AAAA,YAClC,GAAI,OAAO,MAAM,EAAE,KAAK,OAAO,OAAO,QAAQ,YAAY,CAAC,IAAI,OAAO,IAAI,IAAI,CAAC;AAAA,UACjF,CAAC;AAAA,QACH,OAAO;AAEL,gBAAM,UAAU,iBAAiB,MAAM;AACvC,mBAAS,OAAO,YAAY,WAAW,IAAI,MAAM,OAAO,IAAI,IAAI,MAAM,OAAO;AAAA,QAC/E;AAGA,YAAI,CAAC,OAAO,aAAa;AACvB,gBAAM,IAAI,QAAc,CAAC,SAAS,WAAW;AAC3C,gBAAI,OAAO,WAAW,SAAS;AAC7B,sBAAQ;AAAA,YACV,OAAO;AACL,qBAAO,KAAK,SAAS,OAAO;AAC5B,qBAAO,KAAK,SAAS,MAAM;AAAA,YAC7B;AAAA,UACF,CAAC;AAAA,QACH;AAEA,eAAO,IAAI,YAAW,QAAQ,MAAM;AAAA,MACtC;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,UAA+B;AAC1C,cAAM,SAAsB;AAAA,UAC1B,KAAK,QAAQ,IAAI;AAAA,UACjB,MAAM,QAAQ,IAAI;AAAA,UAClB,MAAM,SAAS,QAAQ,IAAI,cAAc,QAAQ,EAAE;AAAA,UACnD,UAAU,QAAQ,IAAI;AAAA,UACtB,IAAI,QAAQ,IAAI,WAAW,SAAS,QAAQ,IAAI,UAAU,EAAE,IAAI;AAAA,UAChE,WAAW,QAAQ,IAAI;AAAA,UACvB,KAAK,QAAQ,IAAI,cAAc;AAAA,QACjC;AAEA,eAAO,YAAW,OAAO,MAAM;AAAA,MACjC;AAAA,MAEA,MAAM,IAAiB,KAAgC;AACrD,cAAM,QAAQ,MAAM,KAAK,OAAO,IAAI,GAAG;AACvC,YAAI,UAAU,MAAM;AAClB,iBAAO;AAAA,QACT;AAEA,YAAI;AACF,iBAAO,KAAK,MAAM,KAAK;AAAA,QACzB,QAAQ;AAEN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,IAAiB,KAAa,OAAU,KAA6B;AACzE,cAAM,aAAa,OAAO,UAAU,WAAW,QAAQ,KAAK,UAAU,KAAK;AAE3E,YAAI,KAAK;AACP,gBAAM,KAAK,OAAO,MAAM,KAAK,KAAK,UAAU;AAAA,QAC9C,OAAO;AACL,gBAAM,KAAK,OAAO,IAAI,KAAK,UAAU;AAAA,QACvC;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,KAA4B;AACvC,cAAM,KAAK,OAAO,IAAI,GAAG;AAAA,MAC3B;AAAA,MAEA,MAAM,OAAO,KAA+B;AAC1C,cAAM,SAAS,MAAM,KAAK,OAAO,OAAO,GAAG;AAC3C,eAAO,SAAS;AAAA,MAClB;AAAA,MAEA,MAAM,cAAc,SAAkC;AACpD,cAAM,OAAiB,CAAC;AACxB,YAAI,SAAS;AAGb,WAAG;AACD,gBAAM,SAAS,MAAM,KAAK,OAAO,KAAK,QAAQ,SAAS,SAAS,SAAS,GAAG;AAC5E,mBAAS,OAAO,CAAC;AACjB,eAAK,KAAK,GAAG,OAAO,CAAC,CAAC;AAAA,QACxB,SAAS,WAAW;AAEpB,YAAI,KAAK,WAAW,GAAG;AACrB,iBAAO;AAAA,QACT;AAGA,cAAM,YAAY;AAClB,YAAI,UAAU;AAEd,iBAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK,WAAW;AAC/C,gBAAM,QAAQ,KAAK,MAAM,GAAG,IAAI,SAAS;AACzC,qBAAW,MAAM,KAAK,OAAO,IAAI,GAAG,KAAK;AAAA,QAC3C;AAEA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,KAAkB,MAAuC;AAC7D,YAAI,KAAK,WAAW,GAAG;AACrB,iBAAO,CAAC;AAAA,QACV;AAEA,cAAM,SAAS,MAAM,KAAK,OAAO,KAAK,GAAG,IAAI;AAE7C,eAAO,OAAO,IAAI,CAAC,UAAU;AAC3B,cAAI,UAAU,MAAM;AAClB,mBAAO;AAAA,UACT;AAEA,cAAI;AACF,mBAAO,KAAK,MAAM,KAAK;AAAA,UACzB,QAAQ;AACN,mBAAO;AAAA,UACT;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,KAAkB,SAAwE;AAC9F,YAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,QACF;AAGA,cAAM,QAA0C,CAAC;AACjD,cAAM,UAAyD,CAAC;AAEhE,mBAAW,SAAS,SAAS;AAC3B,cAAI,MAAM,KAAK;AACb,oBAAQ,KAAK,KAA+C;AAAA,UAC9D,OAAO;AACL,kBAAM,KAAK,KAAK;AAAA,UAClB;AAAA,QACF;AAGA,cAAM,WAAW,KAAK,OAAO,SAAS;AAGtC,YAAI,MAAM,SAAS,GAAG;AACpB,gBAAM,OAAiB,CAAC;AACxB,qBAAW,SAAS,OAAO;AACzB,iBAAK,KAAK,MAAM,GAAG;AACnB,iBAAK,KAAK,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,KAAK,UAAU,MAAM,KAAK,CAAC;AAAA,UACvF;AACA,mBAAS,KAAK,GAAG,IAAI;AAAA,QACvB;AAGA,mBAAW,SAAS,SAAS;AAC3B,gBAAM,QAAQ,OAAO,MAAM,UAAU,WAAW,MAAM,QAAQ,KAAK,UAAU,MAAM,KAAK;AACxF,mBAAS,MAAM,MAAM,KAAK,MAAM,KAAK,KAAK;AAAA,QAC5C;AAEA,cAAM,SAAS,KAAK;AAAA,MACtB;AAAA,MAEA,MAAM,KAAK,KAAa,KAAa,GAAoB;AACvD,eAAO,MAAM,KAAK,OAAO,OAAO,KAAK,EAAE;AAAA,MACzC;AAAA,MAEA,MAAM,QAAQ,SAAiB,SAAgC;AAC7D,cAAM,KAAK,OAAO,QAAQ,SAAS,OAAO;AAAA,MAC5C;AAAA,MAEA,MAAM,UAAU,SAAiB,UAA0D;AAEzF,YAAI,CAAC,KAAK,kBAAkB;AAC1B,gBAAM,EAAE,SAAS,MAAM,IAAI,MAAM,OAAO,SAAS;AACjD,gBAAM,UAAU,iBAAiB,KAAK,MAAM;AAC5C,eAAK,mBACH,OAAO,YAAY,WAAW,IAAI,MAAM,OAAO,IAAI,IAAI,MAAM,OAAO;AAGtE,eAAK,iBAAiB,GAAG,WAAW,CAAC,IAAY,YAAoB;AACnE,kBAAM,YAAY,KAAK,cAAc,IAAI,EAAE;AAC3C,gBAAI,WAAW;AACb,yBAAW,MAAM,WAAW;AAC1B,oBAAI;AACF,qBAAG,OAAO;AAAA,gBACZ,SAAS,OAAO;AACd,0BAAQ,MAAM,8CAA8C,EAAE,KAAK,KAAK;AAAA,gBAC1E;AAAA,cACF;AAAA,YACF;AAAA,UACF,CAAC;AAAA,QACH;AAGA,YAAI,CAAC,KAAK,cAAc,IAAI,OAAO,GAAG;AACpC,eAAK,cAAc,IAAI,SAAS,oBAAI,IAAI,CAAC;AACzC,gBAAM,KAAK,iBAAiB,UAAU,OAAO;AAAA,QAC/C;AACA,aAAK,cAAc,IAAI,OAAO,EAAG,IAAI,QAAQ;AAG7C,eAAO,YAAY;AACjB,gBAAM,YAAY,KAAK,cAAc,IAAI,OAAO;AAChD,cAAI,WAAW;AACb,sBAAU,OAAO,QAAQ;AACzB,gBAAI,UAAU,SAAS,GAAG;AACxB,mBAAK,cAAc,OAAO,OAAO;AACjC,oBAAM,KAAK,kBAAkB,YAAY,OAAO;AAAA,YAClD;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,OAAO,KAAK;AACtC,iBAAO,WAAW;AAAA,QACpB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAC3B,YAAI,KAAK,kBAAkB;AACzB,gBAAM,KAAK,iBAAiB,KAAK;AACjC,eAAK,mBAAmB;AAAA,QAC1B;AACA,cAAM,KAAK,OAAO,KAAK;AACvB,aAAK,cAAc,MAAM;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA,MAKA,oBAIE;AACA,eAAO;AAAA,UACL,QAAQ,KAAK,OAAO;AAAA,UACpB,MAAM,KAAK,OAAO;AAAA,UAClB,MAAM,KAAK,OAAO;AAAA,QACpB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,QAAqB,YAAoB,MAA6B;AAE1E,eAAO,MAAO,KAAK,OAAe,KAAK,SAAS,GAAG,IAAI;AAAA,MACzD;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,IAAI,KAA8B;AACtC,eAAO,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,MAClC;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,OAAO,KAAa,SAAmC;AAC3D,cAAM,SAAS,MAAM,KAAK,OAAO,OAAO,KAAK,OAAO;AACpD,eAAO,WAAW;AAAA,MACpB;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,KAAK,SAAoC;AAC7C,cAAM,OAAiB,CAAC;AACxB,YAAI,SAAS;AAEb,WAAG;AACD,gBAAM,SAAS,MAAM,KAAK,OAAO,KAAK,QAAQ,SAAS,SAAS,SAAS,GAAG;AAC5E,mBAAS,OAAO,CAAC;AACjB,eAAK,KAAK,GAAG,OAAO,CAAC,CAAC;AAAA,QACxB,SAAS,WAAW;AAEpB,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;;;AChcA;AAAA;AAAA;AAAA;AAAA,IAaa;AAbb;AAAA;AAAA;AAaO,IAAM,eAAN,MAAqC;AAAA,MAClC;AAAA,MAER,YAAY,QAAe;AACzB,aAAK,SAAS;AAAA,MAChB;AAAA,MAEA,MAAM,IAAiB,KAAgC;AACrD,cAAM,QAAQ,MAAM,KAAK,OAAO,IAAO,GAAG;AAC1C,eAAO,SAAS;AAAA,MAClB;AAAA,MAEA,MAAM,IAAiB,KAAa,OAAU,KAA6B;AACzE,YAAI,KAAK;AACP,gBAAM,KAAK,OAAO,IAAI,KAAK,OAAO,EAAE,IAAI,IAAI,CAAC;AAAA,QAC/C,OAAO;AACL,gBAAM,KAAK,OAAO,IAAI,KAAK,KAAK;AAAA,QAClC;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,KAA4B;AACvC,cAAM,KAAK,OAAO,IAAI,GAAG;AAAA,MAC3B;AAAA,MAEA,MAAM,OAAO,KAA+B;AAC1C,cAAM,SAAS,MAAM,KAAK,OAAO,OAAO,GAAG;AAC3C,eAAO,SAAS;AAAA,MAClB;AAAA,MAEA,MAAM,cAAc,SAAkC;AAEpD,cAAM,OAAiB,CAAC;AACxB,YAAI,SAA0B;AAE9B,WAAG;AACD,gBAAM,SAAsC,MAAM,KAAK,OAAO,KAAK,QAAQ,EAAE,OAAO,SAAS,OAAO,IAAI,CAAC;AACzG,mBAAS,OAAO,CAAC;AACjB,eAAK,KAAK,GAAG,OAAO,CAAC,CAAC;AAAA,QACxB,SAAS,WAAW,KAAK,WAAW;AAEpC,YAAI,KAAK,WAAW,GAAG;AACrB,iBAAO;AAAA,QACT;AAEA,cAAM,UAAU,MAAM,KAAK,OAAO,IAAI,GAAG,IAAI;AAC7C,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,KAAkB,MAAuC;AAC7D,YAAI,KAAK,WAAW,GAAG;AACrB,iBAAO,CAAC;AAAA,QACV;AACA,cAAM,UAAU,MAAM,KAAK,OAAO,KAAmB,GAAG,IAAI;AAC5D,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,KAAkB,SAAwE;AAC9F,YAAI,QAAQ,WAAW,GAAG;AACxB;AAAA,QACF;AAGA,cAAM,WAAW,KAAK,OAAO,SAAS;AAEtC,mBAAW,SAAS,SAAS;AAC3B,cAAI,MAAM,KAAK;AACb,qBAAS,IAAI,MAAM,KAAK,MAAM,OAAO,EAAE,IAAI,MAAM,IAAI,CAAC;AAAA,UACxD,OAAO;AACL,qBAAS,IAAI,MAAM,KAAK,MAAM,KAAK;AAAA,UACrC;AAAA,QACF;AAEA,cAAM,SAAS,KAAK;AAAA,MACtB;AAAA,MAEA,MAAM,KAAK,KAAa,KAAa,GAAoB;AACvD,eAAO,MAAM,KAAK,OAAO,OAAO,KAAK,EAAE;AAAA,MACzC;AAAA,MAEA,MAAM,QAAQ,SAAiB,SAAgC;AAC7D,cAAM,KAAK,OAAO,QAAQ,SAAS,OAAO;AAAA,MAC5C;AAAA,MAEA,MAAM,UAAU,SAAiB,UAA0D;AAGzF,gBAAQ;AAAA,UACN;AAAA,QAEF;AACA,eAAO,MAAM;AAAA,QAAC;AAAA,MAChB;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,OAAO,KAAK;AACtC,iBAAO,WAAW;AAAA,QACpB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAAA,MAE7B;AAAA,IACF;AAAA;AAAA;;;ACtHA;AAAA;AAAA;AAAA;AAAA,IAiCa;AAjCb;AAAA;AAAA;AAiCO,IAAM,kBAAN,MAAM,iBAAoC;AAAA,MACvC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAER,YAAY,QAAwB,QAA8E;AAChH,aAAK,SAAS;AACd,aAAK,SAAS,OAAO;AACrB,aAAK,eAAe,OAAO,gBAAgB;AAC3C,aAAK,kBAAkB,OAAO,mBAAmB;AAAA,MACnD;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,OAAO,QAAyD;AAC3E,cAAM,EAAE,aAAa,IAAI,MAAM,OAAO,uBAAuB;AAC7D,cAAM,SAAS,aAAa,OAAO,KAAK,OAAO,MAAM;AAErD,eAAO,IAAI,iBAAgB,QAAQ;AAAA,UACjC,QAAQ,OAAO;AAAA,UACf,cAAc,OAAO;AAAA,UACrB,iBAAiB,OAAO;AAAA,QAC1B,CAAC;AAAA,MACH;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,UAAoC;AAC/C,cAAM,MAAM,QAAQ,IAAI;AACxB,cAAM,SAAS,QAAQ,IAAI,6BAA6B,QAAQ,IAAI;AACpE,cAAM,SAAS,QAAQ,IAAI,2BAA2B;AAEtD,YAAI,CAAC,OAAO,CAAC,QAAQ;AACnB,gBAAM,IAAI,MAAM,iDAAiD;AAAA,QACnE;AAEA,eAAO,iBAAgB,OAAO;AAAA,UAC5B;AAAA,UACA;AAAA,UACA;AAAA,UACA,cAAc,QAAQ,IAAI,4BAA4B;AAAA,UACtD,iBAAiB,QAAQ,IAAI,6BACzB,SAAS,QAAQ,IAAI,4BAA4B,EAAE,IACnD;AAAA,QACN,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,OAAO,KAAa,MAAsC,SAAmD;AAEjH,YAAI;AACJ,YAAI,gBAAgB,gBAAgB;AAClC,gBAAM,SAAuB,CAAC;AAC9B,gBAAM,SAAS,KAAK,UAAU;AAC9B,iBAAO,MAAM;AACX,kBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,gBAAI,KAAM;AACV,mBAAO,KAAK,KAAK;AAAA,UACnB;AACA,oBAAU,OAAO,OAAO,MAAM;AAAA,QAChC,OAAO;AACL,oBAAU;AAAA,QACZ;AAEA,cAAM,EAAE,MAAM,YAAY,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,OAAO,KAAK,SAAS;AAAA,UACnG,aAAa,SAAS;AAAA,UACtB,QAAQ;AAAA,QACV,CAAC;AAED,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE;AAAA,QAC3D;AAEA,cAAM,MAAM,MAAM,KAAK,OAAO,GAAG;AACjC,eAAO,EAAE,IAAI;AAAA,MACf;AAAA,MAEA,MAAM,SAAS,MAA+B;AAC5C,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,SAAS,IAAI;AAEjF,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,4BAA4B,MAAM,OAAO,EAAE;AAAA,QAC7D;AAGA,cAAM,cAAc,MAAM,KAAK,YAAY;AAC3C,eAAO,OAAO,KAAK,WAAW;AAAA,MAChC;AAAA,MAEA,MAAM,OAAO,MAA6B;AACxC,cAAM,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC;AAE3E,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,0BAA0B,MAAM,OAAO,EAAE;AAAA,QAC3D;AAAA,MACF;AAAA,MAEA,MAAM,WAAW,OAAgC;AAC/C,cAAM,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,OAAO,KAAK;AAE1E,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,2BAA2B,MAAM,OAAO,EAAE;AAAA,QAC5D;AAAA,MACF;AAAA,MAEA,MAAM,YAAY,MAA2C;AAE3D,cAAM,MAAM,KAAK,aAAa,IAAI;AAClC,cAAM,WAAW,KAAK,YAAY,IAAI;AAEtC,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,KAAK,KAAK;AAAA,UAC5E,OAAO;AAAA,UACP,QAAQ;AAAA,QACV,CAAC;AAED,YAAI,SAAS,CAAC,MAAM;AAClB,iBAAO;AAAA,QACT;AAEA,cAAM,OAAO,KAAK,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ;AACjD,YAAI,CAAC,QAAQ,CAAC,KAAK,IAAI;AACrB,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,UACL,KAAK;AAAA,UACL,MAAO,KAAK,UAAU,QAAmB;AAAA,UACzC,aAAa,KAAK,UAAU;AAAA,UAC5B,cAAc,KAAK,aAAa,IAAI,KAAK,KAAK,UAAU,IAAI;AAAA,QAC9D;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,MAAgC;AAC3C,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,KAAK,KAAK,aAAa,IAAI,GAAG;AAAA,UAChG,OAAO;AAAA,UACP,QAAQ,KAAK,YAAY,IAAI;AAAA,QAC/B,CAAC;AAED,YAAI,OAAO;AACT,iBAAO;AAAA,QACT;AAEA,eAAO,KAAK,KAAK,CAAC,SAAS,KAAK,SAAS,KAAK,YAAY,IAAI,CAAC;AAAA,MACjE;AAAA,MAEA,MAAM,KAAK,QAAyC;AAClD,cAAM,SAAS,UAAU;AACzB,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,KAAK,QAAQ;AAAA,UAC/E,OAAO;AAAA,QACT,CAAC;AAED,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,yBAAyB,MAAM,OAAO,EAAE;AAAA,QAC1D;AAEA,cAAM,QAAuB,CAAC;AAE9B,mBAAW,QAAQ,MAAM;AACvB,cAAI,KAAK,IAAI;AAEX,kBAAM,WAAW,SAAS,GAAG,MAAM,IAAI,KAAK,IAAI,KAAK,KAAK;AAC1D,kBAAM,KAAK;AAAA,cACT,KAAK;AAAA,cACL,MAAO,KAAK,UAAU,QAAmB;AAAA,cACzC,aAAa,KAAK,UAAU;AAAA,cAC5B,cAAc,KAAK,aAAa,IAAI,KAAK,KAAK,UAAU,IAAI;AAAA,YAC9D,CAAC;AAAA,UACH;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,aAAa,MAAc,WAAqC;AACpE,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QACvC,KAAK,KAAK,MAAM,EAChB,gBAAgB,MAAM,aAAa,KAAK,eAAe;AAE1D,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,gCAAgC,MAAM,OAAO,EAAE;AAAA,QACjE;AAEA,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AAEF,gBAAM,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,KAAK,IAAI,EAAE,OAAO,EAAE,CAAC;AACnF,iBAAO,CAAC;AAAA,QACV,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAc,OAAO,MAA+B;AAClD,YAAI,KAAK,cAAc;AACrB,gBAAM,EAAE,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,aAAa,IAAI;AACxE,iBAAO,KAAK;AAAA,QACd;AAEA,eAAO,KAAK,aAAa,IAAI;AAAA,MAC/B;AAAA;AAAA;AAAA;AAAA,MAKQ,aAAa,MAAsB;AACzC,cAAM,YAAY,KAAK,YAAY,GAAG;AACtC,eAAO,YAAY,IAAI,KAAK,UAAU,GAAG,SAAS,IAAI;AAAA,MACxD;AAAA;AAAA;AAAA;AAAA,MAKQ,YAAY,MAAsB;AACxC,cAAM,YAAY,KAAK,YAAY,GAAG;AACtC,eAAO,YAAY,IAAI,KAAK,UAAU,YAAY,CAAC,IAAI;AAAA,MACzD;AAAA;AAAA;AAAA;AAAA,MAKA,gBAA2D;AACzD,eAAO;AAAA,UACL,QAAQ,KAAK;AAAA,UACb,cAAc,KAAK;AAAA,QACrB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,KAAK,YAAoB,UAAyD;AACtF,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,KAAK,YAAY,QAAQ;AAE7F,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,wBAAwB,MAAM,OAAO,EAAE;AAAA,QACzD;AAEA,eAAO;AAAA,UACL,KAAK;AAAA,UACL,KAAK,MAAM,KAAK,OAAO,QAAQ;AAAA,QACjC;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,KAAK,YAAoB,UAAyD;AACtF,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK,KAAK,MAAM,EAAE,KAAK,YAAY,QAAQ;AAE7F,YAAI,OAAO;AACT,gBAAM,IAAI,MAAM,wBAAwB,MAAM,OAAO,EAAE;AAAA,QACzD;AAEA,eAAO;AAAA,UACL,KAAK;AAAA,UACL,KAAK,MAAM,KAAK,OAAO,QAAQ;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC3SA;AAAA;AAAA;AAAA;AAAA,IAmBa;AAnBb;AAAA;AAAA;AAmBO,IAAM,YAAN,MAAoC;AAAA,MACjC;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAER,YACE,QACA,QACA,gBACA,WACA;AACA,aAAK,SAAS;AACd,aAAK,SAAS;AACd,aAAK,cAAc;AACnB,aAAK,YAAY;AAAA,MACnB;AAAA,MAEA,MAAM,OACJ,KACA,MACA,SAC0B;AAE1B,YAAI;AACJ,YAAI,gBAAgB,MAAM;AACxB,iBAAO,OAAO,KAAK,MAAM,KAAK,YAAY,CAAC;AAAA,QAC7C,OAAO;AACL,iBAAO;AAAA,QACT;AAEA,cAAM,EAAE,kBAAkB,OAAO,IAAI,MAAM,OAAO,oBAAoB;AAEtE,cAAM,KAAK,OAAO;AAAA,UAChB,IAAI,OAAO;AAAA,YACT,QAAQ,KAAK;AAAA,YACb,KAAK;AAAA,YACL,MAAM;AAAA,YACN,aAAa,SAAS;AAAA,YACtB,UAAU,SAAS;AAAA,YACnB,KAAK,SAAS,SAAS,gBAAgB;AAAA,UACzC,CAAC;AAAA,QACH;AAGA,cAAM,MAAM,KAAK,YACb,GAAG,KAAK,SAAS,IAAI,GAAG,KACxB,MAAM,KAAK,gBAAgB,GAAG;AAElC,eAAO,EAAE,IAAI;AAAA,MACf;AAAA,MAEA,MAAM,SAAS,KAA8B;AAC3C,cAAM,EAAE,kBAAkB,OAAO,IAAI,MAAM,OAAO,oBAAoB;AAEtE,cAAM,WAAW,MAAM,KAAK,OAAO;AAAA,UACjC,IAAI,OAAO;AAAA,YACT,QAAQ,KAAK;AAAA,YACb,KAAK;AAAA,UACP,CAAC;AAAA,QACH;AAEA,cAAM,SAAS,SAAS;AACxB,YAAI,CAAC,QAAQ;AACX,gBAAM,IAAI,MAAM,qBAAqB;AAAA,QACvC;AAGA,cAAM,SAAuB,CAAC;AAC9B,yBAAiB,SAAS,QAAqC;AAC7D,iBAAO,KAAK,KAAK;AAAA,QACnB;AACA,eAAO,OAAO,OAAO,MAAM;AAAA,MAC7B;AAAA,MAEA,MAAM,aAAa,KAAa,YAAoB,MAAuB;AACzE,eAAO,KAAK,gBAAgB,KAAK,SAAS;AAAA,MAC5C;AAAA,MAEA,MAAc,gBAAgB,KAAa,YAAoB,MAAuB;AACpF,cAAM,EAAE,kBAAkB,OAAO,IAAI,MAAM,OAAO,oBAAoB;AAEtE,cAAM,UAAU,IAAI,OAAO;AAAA,UACzB,QAAQ,KAAK;AAAA,UACb,KAAK;AAAA,QACP,CAAC;AAED,eAAO,KAAK,YAAY,KAAK,QAAQ,SAAS,EAAE,UAAU,CAAC;AAAA,MAC7D;AAAA,MAEA,MAAM,OAAO,KAA4B;AACvC,cAAM,EAAE,qBAAqB,UAAU,IAAI,MAAM,OAAO,oBAAoB;AAE5E,cAAM,KAAK,OAAO;AAAA,UAChB,IAAI,UAAU;AAAA,YACZ,QAAQ,KAAK;AAAA,YACb,KAAK;AAAA,UACP,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MAEA,MAAM,WAAW,MAA+B;AAC9C,YAAI,KAAK,WAAW,GAAG;AACrB;AAAA,QACF;AAEA,cAAM,EAAE,sBAAsB,cAAc,IAAI,MAAM,OAAO,oBAAoB;AAEjF,cAAM,KAAK,OAAO;AAAA,UAChB,IAAI,cAAc;AAAA,YAChB,QAAQ,KAAK;AAAA,YACb,QAAQ;AAAA,cACN,SAAS,KAAK,IAAI,CAAC,SAAS,EAAE,KAAK,IAAI,EAAE;AAAA,YAC3C;AAAA,UACF,CAAC;AAAA,QACH;AAAA,MACF;AAAA,MAEA,MAAM,KAAK,QAAyC;AAClD,cAAM,EAAE,sBAAsB,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AAE3E,cAAM,QAAuB,CAAC;AAC9B,YAAI;AAEJ,WAAG;AACD,gBAAM,WAAW,MAAM,KAAK,OAAO;AAAA,YACjC,IAAI,QAAQ;AAAA,cACV,QAAQ,KAAK;AAAA,cACb,QAAQ;AAAA,cACR,mBAAmB;AAAA,YACrB,CAAC;AAAA,UACH;AAEA,cAAI,SAAS,UAAU;AACrB,uBAAW,QAAQ,SAAS,UAAU;AACpC,oBAAM,KAAK;AAAA,gBACT,KAAK,KAAK;AAAA,gBACV,MAAM,KAAK;AAAA,gBACX,cAAc,KAAK;AAAA,gBACnB,MAAM,KAAK;AAAA,cACb,CAAC;AAAA,YACH;AAAA,UACF;AAEA,8BAAoB,SAAS;AAAA,QAC/B,SAAS;AAET,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,OAAO,KAA+B;AAC1C,YAAI;AACF,gBAAM,EAAE,mBAAmB,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AAExE,gBAAM,KAAK,OAAO;AAAA,YAChB,IAAI,QAAQ;AAAA,cACV,QAAQ,KAAK;AAAA,cACb,KAAK;AAAA,YACP,CAAC;AAAA,UACH;AACA,iBAAO;AAAA,QACT,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,YAAY,KAA0C;AAC1D,YAAI;AACF,gBAAM,EAAE,mBAAmB,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AAExE,gBAAM,WAAW,MAAM,KAAK,OAAO;AAAA,YACjC,IAAI,QAAQ;AAAA,cACV,QAAQ,KAAK;AAAA,cACb,KAAK;AAAA,YACP,CAAC;AAAA,UACH;AAEA,iBAAO;AAAA,YACL;AAAA,YACA,MAAM,SAAS;AAAA,YACf,aAAa,SAAS;AAAA,YACtB,cAAc,SAAS;AAAA,YACvB,MAAM,SAAS;AAAA,UACjB;AAAA,QACF,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AACF,gBAAM,EAAE,sBAAsB,QAAQ,IAAI,MAAM,OAAO,oBAAoB;AAE3E,gBAAM,KAAK,OAAO;AAAA,YAChB,IAAI,QAAQ;AAAA,cACV,QAAQ,KAAK;AAAA,cACb,SAAS;AAAA,YACX,CAAC;AAAA,UACH;AACA,iBAAO;AAAA,QACT,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC/NA;AAAA;AAAA;AAAA;AAuDA,SAAS,cAAc,SAAgE;AACrF,MAAI,CAAC,QAAS,QAAO;AACrB,MAAI,OAAO,YAAY,SAAU,QAAO;AACxC,SAAO,QAAQ,OAAO,GAAG,QAAQ,IAAI,KAAK,QAAQ,KAAK,MAAM,QAAQ;AACvE;AAKA,SAAS,iBAAiB,WAA6D;AACrF,MAAI,MAAM,QAAQ,SAAS,GAAG;AAC5B,WAAO,UAAU,IAAI,CAAC,SAAS,cAAc,IAAI,CAAE;AAAA,EACrD;AACA,SAAO,cAAc,SAAS;AAChC;AArEA,IAuEa;AAvEb;AAAA;AAAA;AAuEO,IAAM,YAAN,MAAM,WAA4B;AAAA,MAC/B,cAAiE;AAAA,MACjE;AAAA,MAER,YAAY,QAAoB;AAC9B,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,OAAO,QAAwC;AAC1D,cAAM,UAAU,IAAI,WAAU,MAAM;AACpC,cAAM,QAAQ,WAAW;AACzB,eAAO;AAAA,MACT;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,UAA8B;AACzC,cAAM,SAAqB;AAAA,UACzB,MAAM,QAAQ,IAAI,aAAa;AAAA,UAC/B,MAAM,SAAS,QAAQ,IAAI,aAAa,OAAO,EAAE;AAAA,UACjD,QAAQ,QAAQ,IAAI,gBAAgB;AAAA,UACpC,UAAU,QAAQ,IAAI,iBAAiB,QAAQ,IAAI;AAAA,UACnD,UAAU,QAAQ,IAAI,iBAAiB,QAAQ,IAAI;AAAA,UACnD,MAAM,QAAQ,IAAI,cAAc,QAAQ,IAAI;AAAA,UAC5C,OAAO,QAAQ,IAAI,eAAe;AAAA,QACpC;AAEA,eAAO,WAAU,OAAO,MAAM;AAAA,MAChC;AAAA;AAAA;AAAA;AAAA,MAKA,MAAc,aAA4B;AACxC,cAAM,aAAa,MAAM,OAAO,YAAY;AAE5C,cAAM,UAAiC;AAAA,UACrC,MAAM,KAAK,OAAO;AAAA,UAClB,MAAM,KAAK,OAAO;AAAA,UAClB,QAAQ,KAAK,OAAO,UAAU,KAAK,OAAO,SAAS;AAAA,UACnD,mBAAmB,KAAK,OAAO,qBAAqB;AAAA,UACpD,eAAe,KAAK,OAAO,iBAAiB;AAAA,UAC5C,OAAO,KAAK,OAAO;AAAA,UACnB,QAAQ,KAAK,OAAO;AAAA,QACtB;AAGA,YAAI,KAAK,OAAO,YAAY,KAAK,OAAO,UAAU;AAChD,kBAAQ,OAAO;AAAA,YACb,MAAM,KAAK,OAAO;AAAA,YAClB,MAAM,KAAK,OAAO;AAAA,UACpB;AAAA,QACF;AAGA,YAAI,KAAK,OAAO,uBAAuB,QAAW;AAChD,kBAAQ,MAAM;AAAA,YACZ,oBAAoB,KAAK,OAAO;AAAA,UAClC;AAAA,QACF;AAEA,aAAK,cAAc,WAAW,gBAAgB,OAAO;AAAA,MACvD;AAAA,MAEA,MAAM,KAAK,SAA6C;AACtD,YAAI,CAAC,KAAK,aAAa;AACrB,gBAAM,KAAK,WAAW;AAAA,QACxB;AAEA,YAAI;AACF,gBAAM,cAAc;AAAA,YAClB,MAAM,cAAc,QAAQ,IAAI,KAAK,KAAK,OAAO;AAAA,YACjD,IAAI,iBAAiB,QAAQ,EAAE;AAAA,YAC/B,SAAS,QAAQ;AAAA,YACjB,MAAM,QAAQ;AAAA,YACd,MAAM,QAAQ;AAAA,YACd,SAAS,cAAc,QAAQ,OAAO;AAAA,YACtC,aAAa,QAAQ,aAAa,IAAI,CAAC,SAAS;AAAA,cAC9C,UAAU,IAAI;AAAA,cACd,SAAS,IAAI;AAAA,cACb,aAAa,IAAI;AAAA,YACnB,EAAE;AAAA,YACF,SAAS,QAAQ;AAAA,UACnB;AAEA,gBAAM,SAAS,MAAM,KAAK,YAAa,SAAS,WAAW;AAE3D,iBAAO;AAAA,YACL,IAAI,OAAO,aAAa,QAAQ,KAAK,IAAI,CAAC;AAAA,YAC1C,SAAS;AAAA,UACX;AAAA,QACF,SAAS,OAAO;AACd,iBAAO;AAAA,YACL,IAAI,cAAc,KAAK,IAAI,CAAC;AAAA,YAC5B,SAAS;AAAA,YACT,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UACjE;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,UAAU,UAAkD;AAEhE,cAAM,UAAyB,CAAC;AAChC,mBAAW,OAAO,UAAU;AAC1B,gBAAM,SAAS,MAAM,KAAK,KAAK,GAAG;AAClC,kBAAQ,KAAK,MAAM;AAAA,QACrB;AACA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI,CAAC,KAAK,aAAa;AACrB,cAAI;AACF,kBAAM,KAAK,WAAW;AAAA,UACxB,QAAQ;AACN,mBAAO;AAAA,UACT;AAAA,QACF;AAEA,YAAI;AACF,gBAAM,KAAK,YAAa,OAAO;AAC/B,iBAAO;AAAA,QACT,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,MAAM,QAAuB;AAC3B,YAAI,KAAK,aAAa;AACpB,eAAK,YAAY,MAAM;AACvB,eAAK,cAAc;AAAA,QACrB;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,qBAAsE;AACpE,eAAO;AAAA,UACL,MAAM,KAAK,OAAO;AAAA,UAClB,MAAM,KAAK,OAAO;AAAA,UAClB,QAAQ,KAAK,OAAO,UAAU;AAAA,QAChC;AAAA,MACF;AAAA,IACF;AAAA;AAAA;;;AC9NA;AAAA;AAAA;AAAA;AAAA,IAaa;AAbb;AAAA;AAAA;AAaO,IAAM,cAAN,MAAoC;AAAA,MACjC;AAAA,MACA;AAAA,MAER,YAAY,QAAgB,aAAsB;AAChD,aAAK,SAAS;AACd,aAAK,cAAc,eAAe;AAAA,MACpC;AAAA,MAEA,MAAM,KAAK,SAA6C;AACtD,YAAI;AACF,gBAAM,KAAK,KAAK,gBAAgB,QAAQ,EAAE;AAC1C,gBAAM,OAAO,QAAQ,OACjB,KAAK,cAAc,QAAQ,IAAI,IAC/B,KAAK;AAIT,gBAAM,eAAoB;AAAA,YACxB;AAAA,YACA;AAAA,YACA,SAAS,QAAQ;AAAA,UACnB;AAEA,cAAI,QAAQ,KAAM,cAAa,OAAO,QAAQ;AAC9C,cAAI,QAAQ,KAAM,cAAa,OAAO,QAAQ;AAC9C,cAAI,QAAQ,QAAS,cAAa,UAAU,KAAK,cAAc,QAAQ,OAAO;AAC9E,cAAI,QAAQ,QAAS,cAAa,UAAU,QAAQ;AACpD,cAAI,QAAQ,KAAM,cAAa,OAAO,QAAQ,KAAK,IAAI,CAAC,SAAS,EAAE,MAAM,KAAK,OAAO,IAAI,EAAE;AAC3F,cAAI,QAAQ,aAAa;AACvB,yBAAa,cAAc,QAAQ,YAAY,IAAI,CAAC,OAAO;AAAA,cACzD,UAAU,EAAE;AAAA,cACZ,SAAS,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU,EAAE,QAAQ,SAAS,QAAQ;AAAA,cAChF,aAAa,EAAE;AAAA,YACjB,EAAE;AAAA,UACJ;AAEA,gBAAM,EAAE,MAAM,MAAM,IAAI,MAAM,KAAK,OAAO,OAAO,KAAK,YAAY;AAElE,cAAI,OAAO;AACT,mBAAO;AAAA,cACL,IAAI;AAAA,cACJ,SAAS;AAAA,cACT,OAAO,IAAI,MAAM,MAAM,OAAO;AAAA,YAChC;AAAA,UACF;AAEA,iBAAO;AAAA,YACL,IAAI,MAAM,MAAM;AAAA,YAChB,SAAS;AAAA,UACX;AAAA,QACF,SAAS,KAAK;AACZ,iBAAO;AAAA,YACL,IAAI;AAAA,YACJ,SAAS;AAAA,YACT,OAAO,eAAe,QAAQ,MAAM,IAAI,MAAM,eAAe;AAAA,UAC/D;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,UAAU,UAAkD;AAEhE,cAAM,UAAyB,CAAC;AAEhC,mBAAW,WAAW,UAAU;AAC9B,gBAAM,SAAS,MAAM,KAAK,KAAK,OAAO;AACtC,kBAAQ,KAAK,MAAM;AAGnB,gBAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,GAAG,CAAC;AAAA,QACzD;AAEA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AAEF,gBAAM,EAAE,MAAM,IAAI,MAAM,KAAK,OAAO,QAAQ,KAAK;AACjD,iBAAO,CAAC;AAAA,QACV,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEQ,cAAc,SAA+B;AACnD,YAAI,QAAQ,MAAM;AAChB,iBAAO,GAAG,QAAQ,IAAI,KAAK,QAAQ,KAAK;AAAA,QAC1C;AACA,eAAO,QAAQ;AAAA,MACjB;AAAA,MAEQ,gBAAgB,WAAoD;AAC1E,cAAM,OAAO,MAAM,QAAQ,SAAS,IAAI,YAAY,CAAC,SAAS;AAC9D,eAAO,KAAK,IAAI,CAAC,SAAS,KAAK,cAAc,IAAI,CAAC;AAAA,MACpD;AAAA,IACF;AAAA;AAAA;;;AC7GA;AAAA;AAAA;AAAA;AAAA,IA2FM,UAQA,iBAaO;AAhHb;AAAA;AAAA;AA2FA,IAAM,WAAqC;AAAA,MACzC,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAEA,IAAM,kBAA4C;AAAA,MAChD,SAAS;AAAA,MACT,MAAM;AAAA,MACN,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAMO,IAAM,cAAN,MAAoD;AAAA,MACjD,QAAoC;AAAA,MACpC,SAAsC;AAAA,MACtC;AAAA,MACA,cAAc;AAAA,MACd,gBAA4D,oBAAI,IAAI;AAAA,MAE5E,YAAY,QAAsB;AAChC,aAAK,SAAS;AAAA,MAChB;AAAA;AAAA;AAAA;AAAA,MAKA,MAAc,oBAAmC;AAC/C,YAAI,KAAK,YAAa;AAEtB,cAAM,EAAE,MAAM,IAAI,MAAM,OAAO,QAAQ;AAEvC,cAAM,aAAa,KAAK,oBAAoB;AAE5C,aAAK,QAAQ,IAAI,MAAM,KAAK,OAAO,WAAW;AAAA,UAC5C;AAAA,UACA,mBAAmB,KAAK,OAAO,oBAAoB;AAAA,YACjD,UAAU,KAAK,OAAO,kBAAkB;AAAA,YACxC,SAAS,KAAK,OAAO,kBAAkB;AAAA,YACvC,OAAO,KAAK,OAAO,kBAAkB;AAAA,YACrC,UAAU,KAAK,OAAO,kBAAkB;AAAA,YACxC,kBAAkB,KAAK,OAAO,kBAAkB;AAAA,YAChD,cAAc,KAAK,OAAO,kBAAkB;AAAA,UAC9C,IAAI;AAAA,QACN,CAAC;AAED,aAAK,cAAc;AAAA,MACrB;AAAA,MAEQ,sBAAsB;AAC5B,YAAI,KAAK,OAAO,UAAU;AACxB,iBAAO,EAAE,KAAK,KAAK,OAAO,SAAS;AAAA,QACrC;AACA,eAAO;AAAA,UACL,MAAM,KAAK,OAAO,QAAQ;AAAA,UAC1B,MAAM,KAAK,OAAO,QAAQ;AAAA,UAC1B,UAAU,KAAK,OAAO;AAAA,UACtB,IAAI,KAAK,OAAO;AAAA,QAClB;AAAA,MACF;AAAA,MAEA,MAAM,IAAI,MAAc,MAAS,SAAuC;AACtE,cAAM,KAAK,kBAAkB;AAG7B,cAAM,UAAU,SAAS,YAAY,SAAS,gBAC1C,EAAE,QAAQ,MAAM,YAAY,QAAQ,UAAU,iBAAiB,QAAQ,cAAc,IACrF;AAEJ,cAAM,YAAY,MAAM,KAAK,MAAO,IAAI,MAAM,SAAS;AAAA,UACrD,OAAO,SAAS;AAAA,UAChB,UAAU,SAAS;AAAA,UACnB,SAAS,SAAS;AAAA,UAClB,OAAO,SAAS;AAAA,UAChB,UAAU,SAAS;AAAA,UACnB,kBAAkB,SAAS;AAAA,UAC3B,cAAc,SAAS;AAAA,UACvB,QAAQ,SAAS,SACb;AAAA,YACE,OAAO,QAAQ,OAAO;AAAA,YACtB,SAAS,QAAQ,OAAO;AAAA,YACxB,IAAI,QAAQ,OAAO;AAAA,YACnB,OAAO,QAAQ,OAAO;AAAA,UACxB,IACA;AAAA,QACN,CAAC;AAED,eAAO,KAAK,OAAO,SAAS;AAAA,MAC9B;AAAA,MAEA,MAAM,QAAQ,MAAiF;AAC7F,cAAM,KAAK,kBAAkB;AAE7B,cAAM,aAAa,MAAM,KAAK,MAAO;AAAA,UACnC,KAAK,IAAI,UAAQ;AAAA,YACf,MAAM,IAAI;AAAA,YACV,MAAM,IAAI;AAAA,YACV,MAAM,IAAI,UAAU;AAAA,cAClB,UAAU,IAAI,QAAQ;AAAA,cACtB,SAAS,IAAI,QAAQ;AAAA,cACrB,OAAO,IAAI,QAAQ;AAAA,cACnB,UAAU,IAAI,QAAQ;AAAA,cACtB,kBAAkB,IAAI,QAAQ;AAAA,cAC9B,cAAc,IAAI,QAAQ;AAAA,YAC5B,IAAI;AAAA,UACN,EAAE;AAAA,QACJ;AAEA,eAAO,WAAW,IAAI,SAAO,KAAK,OAAO,GAAG,CAAC;AAAA,MAC/C;AAAA,MAEA,QACE,SACA,SACM;AAEN,aAAK,YAAY,SAAS,SAAS,WAAW,EAAE,MAAM,CAAC,QAAQ;AAC7D,kBAAQ,MAAM,kCAAkC,GAAG;AAAA,QACrD,CAAC;AAAA,MACH;AAAA,MAEA,MAAc,YACZ,SACA,aACe;AACf,cAAM,EAAE,OAAO,IAAI,MAAM,OAAO,QAAQ;AAExC,cAAM,aAAa,KAAK,oBAAoB;AAE5C,cAAM,SAAS,IAAI;AAAA,UACjB,KAAK,OAAO;AAAA,UACZ,OAAO,cAAc;AACnB,kBAAM,MAAM,KAAK,OAAO,SAAyC;AACjE,mBAAO,QAAQ,GAAG;AAAA,UACpB;AAAA,UACA;AAAA,YACE;AAAA,YACA,aAAa,eAAe,KAAK,OAAO,eAAe;AAAA,UACzD;AAAA,QACF;AAEA,aAAK,SAAS;AAGd,eAAO,GAAG,aAAa,CAAC,cAAc;AACpC,cAAI,WAAW;AACb,iBAAK,UAAU,aAAa,SAAyC;AAAA,UACvE;AAAA,QACF,CAAC;AAED,eAAO,GAAG,UAAU,CAAC,WAAW,QAAQ;AACtC,cAAI,WAAW;AACb,iBAAK,UAAU,UAAU,WAA2C,GAAY;AAAA,UAClF;AAAA,QACF,CAAC;AAED,eAAO,GAAG,YAAY,CAAC,WAAW,aAAa;AAC7C,cAAI,WAAW;AACb,iBAAK,UAAU,YAAY,WAA2C,QAAW,QAAkB;AAAA,UACrG;AAAA,QACF,CAAC;AAED,eAAO,GAAG,UAAU,CAAC,cAAc;AACjC,cAAI,WAAW;AACb,iBAAK,UAAU,UAAU,SAAyC;AAAA,UACpE;AAAA,QACF,CAAC;AAED,eAAO,GAAG,WAAW,CAAC,UAAU;AAE9B,eAAK,cAAc,WAAW,KAAK;AAAA,QACrC,CAAC;AAAA,MACH;AAAA,MAEQ,UACN,MACA,WACA,OACA,UACM;AACN,cAAM,WAAW,KAAK,cAAc,IAAI,IAAI;AAC5C,YAAI,CAAC,YAAY,SAAS,SAAS,EAAG;AAEtC,cAAM,QAAqB;AAAA,UACzB;AAAA,UACA,KAAK,KAAK,OAAO,SAAS;AAAA,UAC1B,WAAW,KAAK,IAAI;AAAA,UACpB;AAAA,UACA;AAAA,QACF;AAEA,mBAAW,WAAW,UAAU;AAC9B,cAAI;AACF,oBAAQ,KAAK;AAAA,UACf,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,MAEQ,cAAc,MAAoB,OAAqB;AAC7D,cAAM,WAAW,KAAK,cAAc,IAAI,IAAI;AAC5C,YAAI,CAAC,YAAY,SAAS,SAAS,EAAG;AAGtC,cAAM,QAAqB;AAAA,UACzB;AAAA,UACA,KAAK;AAAA,YACH,IAAI;AAAA,YACJ,MAAM;AAAA,YACN,MAAM,CAAC;AAAA,YACP,cAAc;AAAA,YACd,UAAU;AAAA,YACV,WAAW,KAAK,IAAI;AAAA,UACtB;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,QACtB;AAEA,mBAAW,WAAW,UAAU;AAC9B,cAAI;AACF,oBAAQ,KAAK;AAAA,UACf,QAAQ;AAAA,UAER;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,OAAO,IAAoC;AAC/C,cAAM,KAAK,kBAAkB;AAE7B,cAAM,YAAY,MAAM,KAAK,MAAO,OAAO,EAAE;AAC7C,YAAI,CAAC,UAAW,QAAO;AAEvB,eAAO,KAAK,OAAO,SAAS;AAAA,MAC9B;AAAA,MAEA,MAAM,UAAU,IAA2B;AACzC,cAAM,KAAK,kBAAkB;AAE7B,cAAM,MAAM,MAAM,KAAK,MAAO,OAAO,EAAE;AACvC,YAAI,KAAK;AACP,gBAAM,IAAI,OAAO;AAAA,QACnB;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAC3B,cAAM,KAAK,kBAAkB;AAC7B,cAAM,KAAK,MAAO,MAAM;AAAA,MAC1B;AAAA,MAEA,MAAM,SAAwB;AAC5B,cAAM,KAAK,kBAAkB;AAC7B,cAAM,KAAK,MAAO,OAAO;AAAA,MAC3B;AAAA,MAEA,MAAM,WAMH;AACD,cAAM,KAAK,kBAAkB;AAE7B,cAAM,CAAC,SAAS,QAAQ,WAAW,QAAQ,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,UACtE,KAAK,MAAO,gBAAgB;AAAA,UAC5B,KAAK,MAAO,eAAe;AAAA,UAC3B,KAAK,MAAO,kBAAkB;AAAA,UAC9B,KAAK,MAAO,eAAe;AAAA,UAC3B,KAAK,MAAO,gBAAgB;AAAA,QAC9B,CAAC;AAED,eAAO,EAAE,SAAS,QAAQ,WAAW,QAAQ,QAAQ;AAAA,MACvD;AAAA,MAEA,MAAM,cAAgC;AACpC,YAAI;AACF,gBAAM,KAAK,kBAAkB;AAE7B,gBAAM,KAAK,MAAO,gBAAgB;AAClC,iBAAO;AAAA,QACT,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAM,QAAuB;AAC3B,YAAI,KAAK,QAAQ;AACf,gBAAM,KAAK,OAAO,MAAM;AACxB,eAAK,SAAS;AAAA,QAChB;AACA,YAAI,KAAK,OAAO;AACd,gBAAM,KAAK,MAAM,MAAM;AACvB,eAAK,QAAQ;AAAA,QACf;AACA,aAAK,cAAc;AACnB,aAAK,cAAc,MAAM;AAAA,MAC3B;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,aACJ,MACA,MACA,QACA,SACiB;AACjB,eAAO,KAAK,IAAI,MAAM,MAAM;AAAA,UAC1B,GAAG;AAAA,UACH;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,QACJ,OACA,QAAgB,GAChB,MAAc,IACK;AACnB,cAAM,KAAK,kBAAkB;AAE7B,cAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,cAAM,eAAe,OAAO,IAAI,CAAC,MAAM,SAAS,CAAC,CAAC;AAElD,cAAM,aAAa,MAAM,KAAK,MAAO,QAAQ,cAAc,OAAO,QAAQ,KAAK,SAAY,GAAG;AAC9F,eAAO,WAAW,IAAI,CAAC,QAAQ,KAAK,OAAO,GAAG,CAAC;AAAA,MACjD;AAAA,MAEA,MAAM,cAAc,QAAgB,GAAG,MAAc,IAAuB;AAC1E,eAAO,KAAK,QAAQ,UAAU,OAAO,GAAG;AAAA,MAC1C;AAAA,MAEA,MAAM,SAAS,IAA2B;AACxC,cAAM,KAAK,kBAAkB;AAE7B,cAAM,MAAM,MAAM,KAAK,MAAO,OAAO,EAAE;AACvC,YAAI,KAAK;AACP,gBAAM,IAAI,MAAM,QAAQ;AAAA,QAC1B;AAAA,MACF;AAAA,MAEA,MAAM,kBAAmC;AACvC,cAAM,KAAK,kBAAkB;AAE7B,cAAM,aAAa,MAAM,KAAK,MAAO,QAAQ,CAAC,QAAQ,CAAC;AACvD,YAAI,QAAQ;AAEZ,mBAAW,OAAO,YAAY;AAC5B,cAAI;AACF,kBAAM,IAAI,MAAM,QAAQ;AACxB;AAAA,UACF,QAAQ;AAAA,UAER;AAAA,QACF;AAEA,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,eAAe,IAAY,UAAiC;AAChE,cAAM,KAAK,kBAAkB;AAE7B,cAAM,MAAM,MAAM,KAAK,MAAO,OAAO,EAAE;AACvC,YAAI,KAAK;AACP,gBAAM,IAAI,eAAe,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,QAAQ,CAAC,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA,MAEA,MAAM,MAAM,OAAe,OAAe,OAAoC;AAC5E,cAAM,KAAK,kBAAkB;AAC7B,eAAO,KAAK,MAAO,MAAM,OAAO,OAAO,SAAS,KAAK,CAAC;AAAA,MACxD;AAAA,MAEA,MAAM,WAAW,SAA8C;AAC7D,cAAM,KAAK,kBAAkB;AAC7B,cAAM,KAAK,MAAO,WAAW,OAAO;AAAA,MACtC;AAAA,MAEA,GAAG,OAAqB,SAAmC;AACzD,YAAI,CAAC,KAAK,cAAc,IAAI,KAAK,GAAG;AAClC,eAAK,cAAc,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,QACzC;AACA,aAAK,cAAc,IAAI,KAAK,EAAG,IAAI,OAAO;AAAA,MAC5C;AAAA,MAEA,IAAI,OAAqB,SAAmC;AAC1D,cAAM,WAAW,KAAK,cAAc,IAAI,KAAK;AAC7C,YAAI,UAAU;AACZ,mBAAS,OAAO,OAAO;AAAA,QACzB;AAAA,MACF;AAAA,MAEA,UAAkB;AAChB,eAAO,KAAK,OAAO;AAAA,MACrB;AAAA;AAAA;AAAA;AAAA,MAMQ,OAAO,WAAsC;AAEnD,cAAM,UAAU,UAAU;AAC1B,YAAI;AACJ,YAAI;AACJ,YAAI;AAEJ,YACE,WACA,OAAO,YAAY,YACnB,YAAa,SACb;AACA,gBAAM,UAAU;AAKhB,iBAAO,QAAQ;AACf,0BAAgB,QAAQ;AACxB,qBAAW,QAAQ;AAAA,QACrB,OAAO;AACL,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,UACL,IAAI,UAAU,MAAM;AAAA,UACpB,MAAM,UAAU;AAAA,UAChB;AAAA,UACA,cAAc,UAAU;AAAA,UACxB,UAAU,OAAO,UAAU,aAAa,WAAW,UAAU,WAAW;AAAA,UACxE,WAAW,UAAU;AAAA,UACrB,aAAa,UAAU;AAAA,UACvB,YAAY,UAAU;AAAA,UACtB,cAAc,UAAU;AAAA,UACxB;AAAA,UACA;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAc,YAAY,WAAiD;AACzE,cAAM,QAAQ,MAAM,UAAU,SAAS;AACvC,eAAO,gBAAgB,KAAK,KAAK;AAAA,MACnC;AAAA,IACF;AAAA;AAAA;;;AC/hBA;AAAA;AAAA;AAAA;AAAA,IAqDM,mBAyFO;AA9Ib;AAAA;AAAA;AAqDA,IAAM,oBAAN,MAAyC;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAER,YAAY,MAAc,UAAoB,KAAc;AAC1D,aAAK,QAAQ;AACb,aAAK,WAAW;AAChB,aAAK,MAAM;AAEX,cAAM,MAAM,SAAS,YAAY;AACjC,aAAK,cAAc;AAAA,UACjB,SAAS,IAAI;AAAA,UACb,QAAQ,IAAI;AAAA,UACZ,YAAY,IAAI;AAAA,UAChB,YAAY,IAAI,YAAY,UAAU;AAAA,QACxC;AAAA,MACF;AAAA,MAEA,IAAI,OAAe;AACjB,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,IAAI,UAAuB;AACzB,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,IAAI,cAAuB;AACzB,eAAO,KAAK,SAAS,YAAY;AAAA,MACnC;AAAA,MAEA,aAAa,KAAa,OAAwC;AAChE,aAAK,SAAS,aAAa,KAAK,KAAK;AACrC,eAAO;AAAA,MACT;AAAA,MAEA,cAAc,YAA6D;AACzE,aAAK,SAAS,cAAc,UAAU;AACtC,eAAO;AAAA,MACT;AAAA,MAEA,SAAS,MAAc,YAA8D;AACnF,aAAK,SAAS,SAAS,MAAM,UAAU;AACvC,eAAO;AAAA,MACT;AAAA,MAEA,UAAU,QAA0B;AAClC,YAAI;AACJ,gBAAQ,OAAO,MAAM;AAAA,UACnB,KAAK;AACH,mBAAO,KAAK,IAAI,eAAe;AAC/B;AAAA,UACF,KAAK;AACH,mBAAO,KAAK,IAAI,eAAe;AAC/B;AAAA,UACF;AACE,mBAAO,KAAK,IAAI,eAAe;AAAA,QACnC;AACA,aAAK,SAAS,UAAU,EAAE,MAAM,SAAS,OAAO,QAAQ,CAAC;AACzD,eAAO;AAAA,MACT;AAAA,MAEA,gBAAgB,WAAkB,YAA8D;AAG9F,aAAK,SAAS,gBAAgB,SAAS;AACvC,YAAI,YAAY;AACd,eAAK,SAAS,SAAS,wBAAwB,UAAU;AAAA,QAC3D;AACA,aAAK,UAAU,EAAE,MAAM,SAAS,SAAS,UAAU,QAAQ,CAAC;AAC5D,eAAO;AAAA,MACT;AAAA,MAEA,WAAW,MAAoB;AAC7B,aAAK,QAAQ;AACb,aAAK,SAAS,WAAW,IAAI;AAC7B,eAAO;AAAA,MACT;AAAA,MAEA,IAAI,SAAwB;AAC1B,aAAK,SAAS,IAAI,OAAO;AAAA,MAC3B;AAAA,IACF;AAMO,IAAM,uBAAN,MAAM,sBAAyC;AAAA,MAC5C;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAEA,YAAY,QAAoB,UAA8B,KAAc;AAClF,aAAK,SAAS;AACd,aAAK,WAAW;AAChB,aAAK,MAAM;AAAA,MACb;AAAA;AAAA;AAAA;AAAA,MAKA,aAAa,OAAO,QAA4D;AAE9E,cAAM,MAAM,MAAM,OAAO,oBAAoB;AAC7C,cAAM,EAAE,mBAAmB,IAAI,MAAM,OAAO,+BAA+B;AAC3E,cAAM,EAAE,SAAS,IAAI,MAAM,OAAO,0BAA0B;AAC5D,cAAM,UAAU,MAAM,OAAO,qCAAqC;AAClE,cAAM,EAAE,oBAAoB,oBAAoB,IAAI,MAAM,OAAO,+BAA+B;AAGhG,cAAM,oBACJ,QAAQ,qBAAqB,QAAQ,4BAA4B;AACnE,cAAM,uBACJ,QAAQ,wBAAwB,QAAQ,+BAA+B;AACzE,cAAM,8BACF,QAAoC,oCACtC,QAAQ,sCACR;AAGF,cAAM,qBAA6C;AAAA,UACjD,CAAC,iBAAiB,GAAG,OAAO;AAAA,UAC5B,GAAG,OAAO;AAAA,QACZ;AAEA,YAAI,OAAO,gBAAgB;AACzB,6BAAmB,oBAAoB,IAAI,OAAO;AAAA,QACpD;AAEA,YAAI,OAAO,aAAa;AACtB,6BAAmB,2BAA2B,IAAI,OAAO;AAAA,QAC3D;AAGA,cAAM,WAAW,IAAI,mBAAmB;AAAA,UACtC,UAAU,IAAI,SAAS,kBAAkB;AAAA,QAC3C,CAAC;AAGD,YAAI;AACJ,gBAAQ,OAAO,cAAc;AAAA,UAC3B,KAAK,aAAa;AAChB,kBAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,yCAAyC;AACpF,uBAAW,IAAI,kBAAkB;AAAA,cAC/B,KAAK,OAAO;AAAA,YACd,CAAC;AACD;AAAA,UACF;AAAA,UACA,KAAK;AACH,uBAAW,IAAI,oBAAoB;AACnC;AAAA,UACF,KAAK;AAAA,UACL,SAAS;AACP,kBAAM,EAAE,kBAAkB,IAAI,MAAM,OAAO,yCAAyC;AACpF,uBAAW,IAAI,kBAAkB;AAAA,cAC/B,KAAK,OAAO,YAAY;AAAA,YAC1B,CAAC;AACD;AAAA,UACF;AAAA,QACF;AAGA,iBAAS,iBAAiB,IAAI,mBAAmB,QAAQ,CAAC;AAG1D,iBAAS,SAAS;AAGlB,cAAM,SAAS,IAAI,MAAM,UAAU,OAAO,aAAa,OAAO,cAAc;AAE5E,eAAO,IAAI,sBAAqB,QAAQ,UAAU,GAAG;AAAA,MACvD;AAAA,MAEQ,YAAY,MAAwD;AAC1E,gBAAQ,MAAM;AAAA,UACZ,KAAK;AACH,mBAAO,KAAK,IAAI,SAAS;AAAA,UAC3B,KAAK;AACH,mBAAO,KAAK,IAAI,SAAS;AAAA,UAC3B,KAAK;AACH,mBAAO,KAAK,IAAI,SAAS;AAAA,UAC3B,KAAK;AACH,mBAAO,KAAK,IAAI,SAAS;AAAA,UAC3B,KAAK;AAAA,UACL;AACE,mBAAO,KAAK,IAAI,SAAS;AAAA,QAC7B;AAAA,MACF;AAAA,MAEA,UAAU,MAAc,SAA8B;AACpD,cAAM,WAAW,KAAK,OAAO,UAAU,MAAM;AAAA,UAC3C,MAAM,KAAK,YAAY,SAAS,IAAI;AAAA,UACpC,YAAY,SAAS;AAAA,UACrB,WAAW,SAAS;AAAA,QACtB,CAAC;AAED,cAAM,OAAO,IAAI,kBAAkB,MAAM,UAAU,KAAK,GAAG;AAC3D,aAAK,cAAc;AAEnB,eAAO;AAAA,MACT;AAAA,MAEA,iBAAoC;AAClC,cAAM,aAAa,KAAK,IAAI,MAAM,cAAc;AAChD,YAAI,YAAY;AACd,iBAAO,IAAI,kBAAkB,IAAI,YAAY,KAAK,GAAG;AAAA,QACvD;AACA,eAAO,KAAK;AAAA,MACd;AAAA,MAEA,SAAY,MAAc,IAAwB,SAA0B;AAC1E,cAAM,OAAO,KAAK,UAAU,MAAM,OAAO;AACzC,cAAM,WAAW,KAAK,OAAO,UAAU,MAAM;AAAA,UAC3C,MAAM,KAAK,YAAY,SAAS,IAAI;AAAA,UACpC,YAAY,SAAS;AAAA,QACvB,CAAC;AAED,eAAO,KAAK,IAAI,QAAQ,KAAK,KAAK,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,GAAG,QAAQ,GAAG,MAAM;AAC9F,cAAI;AACF,kBAAM,SAAS,GAAG,IAAI;AACtB,iBAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAC7B,mBAAO;AAAA,UACT,SAAS,OAAO;AACd,iBAAK,gBAAgB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAC9E,kBAAM;AAAA,UACR,UAAE;AACA,iBAAK,IAAI;AACT,qBAAS,IAAI;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,MAAM,cAAiB,MAAc,IAAiC,SAAmC;AACvG,cAAM,OAAO,KAAK,UAAU,MAAM,OAAO;AACzC,cAAM,WAAW,KAAK,OAAO,UAAU,MAAM;AAAA,UAC3C,MAAM,KAAK,YAAY,SAAS,IAAI;AAAA,UACpC,YAAY,SAAS;AAAA,QACvB,CAAC;AAED,eAAO,KAAK,IAAI,QAAQ,KAAK,KAAK,IAAI,MAAM,QAAQ,KAAK,IAAI,QAAQ,OAAO,GAAG,QAAQ,GAAG,YAAY;AACpG,cAAI;AACF,kBAAM,SAAS,MAAM,GAAG,IAAI;AAC5B,iBAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAC7B,mBAAO;AAAA,UACT,SAAS,OAAO;AACd,iBAAK,gBAAgB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAC9E,kBAAM;AAAA,UACR,UAAE;AACA,iBAAK,IAAI;AACT,qBAAS,IAAI;AAAA,UACf;AAAA,QACF,CAAC;AAAA,MACH;AAAA,MAEA,WACE,MACA,IACA,SAC6B;AAC7B,eAAO,IAAI,SAAgB,KAAK,SAAS,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO;AAAA,MAC3E;AAAA,MAEA,gBACE,MACA,IACA,SACsC;AACtC,eAAO,IAAI,SAAgB,KAAK,cAAc,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO;AAAA,MAChF;AAAA,MAEA,eAAe,SAAiF;AAE9F,cAAM,cAAc,QAAQ,aAAa;AACzC,YAAI,CAAC,eAAe,OAAO,gBAAgB,SAAU,QAAO;AAG5D,cAAM,QAAQ,YAAY,MAAM,GAAG;AACnC,YAAI,MAAM,WAAW,KAAK,MAAM,CAAC,MAAM,KAAM,QAAO;AAEpD,cAAM,UAAU,MAAM,CAAC;AACvB,cAAM,SAAS,MAAM,CAAC;AACtB,cAAM,aAAa,SAAS,MAAM,CAAC,GAAI,EAAE;AAEzC,YAAI,CAAC,WAAW,QAAQ,WAAW,MAAM,CAAC,UAAU,OAAO,WAAW,IAAI;AACxE,iBAAO;AAAA,QACT;AAEA,eAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA,YAAY,QAAQ,YAAY;AAAA,QAClC;AAAA,MACF;AAAA,MAEA,cAAc,SAAuC;AACnD,cAAM,aAAa,KAAK,IAAI,MAAM,cAAc;AAChD,YAAI,YAAY;AACd,gBAAM,MAAM,WAAW,YAAY;AACnC,kBAAQ,aAAa,IAAI,MAAM,IAAI,OAAO,IAAI,IAAI,MAAM,IAAI,IAAI,WAAW,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACxG,cAAI,IAAI,YAAY;AAClB,oBAAQ,YAAY,IAAI,IAAI,WAAW,UAAU;AAAA,UACnD;AAAA,QACF,WAAW,KAAK,aAAa;AAC3B,gBAAM,MAAM,KAAK,YAAY;AAC7B,kBAAQ,aAAa,IAAI,MAAM,IAAI,OAAO,IAAI,IAAI,MAAM,IAAI,IAAI,WAAW,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AACxG,cAAI,IAAI,YAAY;AAClB,oBAAQ,YAAY,IAAI,IAAI;AAAA,UAC9B;AAAA,QACF;AAAA,MACF;AAAA,MAEA,MAAM,cAAgC;AAEpC,eAAO;AAAA,MACT;AAAA,MAEA,MAAM,QAAuB;AAC3B,cAAM,KAAK,SAAS,WAAW;AAAA,MACjC;AAAA,MAEA,MAAM,QAAuB;AAC3B,cAAM,KAAK,SAAS,SAAS;AAAA,MAC/B;AAAA,IACF;AAAA;AAAA;;;ACxGO,SAAS,iBAAiB,SAAiB,SAAiC;AACjF,MAAI,QAAQ,SAAS,SAAS;AAC5B,WAAO,QAAQ;AAAA,EACjB;AACA,QAAM,QAAQ,QAAQ,QAAQ,KAAK,IAAI,GAAG,UAAU,CAAC;AACrD,QAAM,WAAW,QAAQ,YAAY,QAAQ,QAAQ;AACrD,SAAO,KAAK,IAAI,OAAO,QAAQ;AACjC;AAKO,SAAS,gBAAwB;AACtC,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,OAAO,SAAS,IAAI,MAAM;AACnC;;;AC5NO,SAAS,oBACd,SACA,WACA,SACmB;AACnB,SAAO;AAAA,IACL,QAAQ,UAAU,YAAY;AAAA,IAC9B;AAAA,IACA,WAAW,oBAAI,KAAK;AAAA,IACpB;AAAA,EACF;AACF;AAKA,eAAsB,iBACpB,IACA,eAAuC,MAAM,MACjB;AAC5B,QAAM,QAAQ,KAAK,IAAI;AACvB,MAAI;AACF,UAAM,SAAS,MAAM,GAAG;AACxB,UAAM,UAAU,aAAa,MAAM;AACnC,WAAO;AAAA,MACL,QAAQ,UAAU,YAAY;AAAA,MAC9B,WAAW,KAAK,IAAI,IAAI;AAAA,MACxB,WAAW,oBAAI,KAAK;AAAA,IACtB;AAAA,EACF,SAAS,OAAO;AACd,WAAO;AAAA,MACL,QAAQ;AAAA,MACR,WAAW,KAAK,IAAI,IAAI;AAAA,MACxB,WAAW,oBAAI,KAAK;AAAA,MACpB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,IACpD;AAAA,EACF;AACF;;;ACnBO,IAAM,gBAAN,MAAM,eAAiC;AAAA,EACpC;AAAA,EACA;AAAA,EAER,OAAe,gBAA0C;AAAA,IACvD,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,EACT;AAAA,EAEA,YAAY,SAAuB,CAAC,GAAG;AACrC,SAAK,UAAU;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,aAAa,OAAO;AAAA,IACtB;AACA,SAAK,QAAQ,OAAO,SAAS;AAAA,EAC/B;AAAA,EAEQ,UAAU,OAA0B;AAC1C,WAAO,eAAc,cAAc,KAAK,KAAK,eAAc,cAAc,KAAK,KAAK;AAAA,EACrF;AAAA,EAEQ,IAAI,OAAiB,SAAiB,MAAsB;AAClE,QAAI,CAAC,KAAK,UAAU,KAAK,EAAG;AAE5B,UAAM,QAAkB;AAAA,MACtB;AAAA,MACA;AAAA,MACA,WAAW,oBAAI,KAAK;AAAA,MACpB;AAAA,MACA,SAAS,KAAK;AAAA,IAChB;AAEA,UAAM,SAAS,IAAI,MAAM,UAAU,YAAY,CAAC,MAAM,MAAM,YAAY,CAAC;AACzE,UAAM,aAAa,OAAO,KAAK,KAAK,OAAO,EAAE,SAAS,IAClD,KAAK,OAAO,QAAQ,KAAK,OAAO,EAAE,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC,MACxE;AAEJ,YAAQ,OAAO;AAAA,MACb,KAAK;AACH,gBAAQ,MAAM,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,IAAI,QAAQ,EAAE;AAC7D;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,IAAI,QAAQ,EAAE;AAC5D;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,IAAI,QAAQ,EAAE;AAC5D;AAAA,MACF,KAAK;AACH,gBAAQ,MAAM,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,IAAI,QAAQ,EAAE;AAC7D,YAAI,MAAM,OAAO;AACf,kBAAQ,MAAM,KAAK,KAAK;AAAA,QAC1B;AACA;AAAA,IACJ;AAAA,EACF;AAAA,EAEA,MAAM,SAAiB,MAAsB;AAC3C,SAAK,IAAI,SAAS,SAAS,IAAI;AAAA,EACjC;AAAA,EAEA,KAAK,SAAiB,MAAsB;AAC1C,SAAK,IAAI,QAAQ,SAAS,IAAI;AAAA,EAChC;AAAA,EAEA,KAAK,SAAiB,MAAsB;AAC1C,SAAK,IAAI,QAAQ,SAAS,IAAI;AAAA,EAChC;AAAA,EAEA,MAAM,SAAiB,MAAsB;AAC3C,SAAK,IAAI,SAAS,SAAS,IAAI;AAAA,EACjC;AAAA,EAEA,MAAM,SAA2C;AAC/C,UAAM,cAAc,IAAI,eAAc,EAAE,OAAO,KAAK,MAAM,CAAC;AAC3D,gBAAY,UAAU,EAAE,GAAG,KAAK,SAAS,GAAG,QAAQ;AACpD,WAAO;AAAA,EACT;AACF;AAKO,IAAM,aAAN,MAAoC;AAAA,EACzC,QAAc;AAAA,EAAC;AAAA,EACf,OAAa;AAAA,EAAC;AAAA,EACd,OAAa;AAAA,EAAC;AAAA,EACd,QAAc;AAAA,EAAC;AAAA,EACf,QAAiB;AACf,WAAO;AAAA,EACT;AACF;;;ACvFO,IAAM,gBAAN,MAAwC;AAAA,EACrC,WAA+D,oBAAI,IAAI;AAAA,EACvE,SAA8E,oBAAI,IAAI;AAAA,EACtF,aAAoE,oBAAI,IAAI;AAAA,EAC5E,UAAiE,oBAAI,IAAI;AAAA,EACzE,OAA0C,oBAAI,IAAI;AAAA,EAE1D,UAAU,MAAc,QAAQ,GAAG,OAAmB,CAAC,GAAS;AAC9D,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,UAAM,WAAW,KAAK,SAAS,IAAI,GAAG;AAEtC,QAAI,YAAY,SAAS,CAAC,GAAG;AAC3B,eAAS,CAAC,EAAE,SAAS;AAAA,IACvB,OAAO;AACL,WAAK,SAAS,IAAI,KAAK,CAAC,EAAE,OAAO,KAAK,CAAC,CAAC;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,UAAU,MAAc,QAAQ,GAAG,OAAmB,CAAC,GAAS;AAC9D,SAAK,UAAU,MAAM,CAAC,OAAO,IAAI;AAAA,EACnC;AAAA,EAEA,MAAM,MAAc,OAAe,OAAmB,CAAC,GAAS;AAC9D,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,SAAK,OAAO,IAAI,KAAK,EAAE,OAAO,MAAM,WAAW,KAAK,IAAI,EAAE,CAAC;AAAA,EAC7D;AAAA,EAEA,UAAU,MAAc,OAAe,OAAmB,CAAC,GAAS;AAClE,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,UAAM,WAAW,KAAK,WAAW,IAAI,GAAG;AAExC,QAAI,YAAY,SAAS,CAAC,GAAG;AAC3B,eAAS,CAAC,EAAE,OAAO,KAAK,KAAK;AAAA,IAC/B,OAAO;AACL,WAAK,WAAW,IAAI,KAAK,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,IACtD;AAAA,EACF;AAAA,EAEA,OAAO,MAAc,OAAe,OAAmB,CAAC,GAAS;AAC/D,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,UAAM,WAAW,KAAK,QAAQ,IAAI,GAAG;AAErC,QAAI,YAAY,SAAS,CAAC,GAAG;AAC3B,eAAS,CAAC,EAAE,OAAO,KAAK,KAAK;AAAA,IAC/B,OAAO;AACL,WAAK,QAAQ,IAAI,KAAK,CAAC,EAAE,QAAQ,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,WAAW,MAAc,OAAmB,CAAC,GAAe;AAC1D,UAAM,QAAQ,KAAK,IAAI;AACvB,WAAO,MAAM;AACX,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,WAAK,OAAO,MAAM,UAAU,IAAI;AAAA,IAClC;AAAA,EACF;AAAA,EAEA,aAAa,MAAc,OAAe,OAAmB,CAAC,GAAS;AACrE,SAAK,UAAU,MAAM,OAAO,IAAI;AAAA,EAClC;AAAA,EAEA,IAAI,MAAc,OAAwB,OAAmB,CAAC,GAAS;AACrE,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,QAAI,WAAW,KAAK,KAAK,IAAI,GAAG;AAEhC,QAAI,CAAC,UAAU;AACb,iBAAW,oBAAI,IAAI;AACnB,WAAK,KAAK,IAAI,KAAK,QAAQ;AAAA,IAC7B;AAEA,aAAS,IAAI,KAAK;AAAA,EACpB;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,WAAW,MAAc,OAAmB,CAAC,GAAW;AACtD,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,UAAM,OAAO,KAAK,SAAS,IAAI,GAAG;AAClC,WAAO,OAAO,CAAC,GAAG,SAAS;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,MAAc,OAAmB,CAAC,GAAuB;AAChE,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,WAAO,KAAK,OAAO,IAAI,GAAG,GAAG;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,MAAc,OAAmB,CAAC,GAAa;AAC1D,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,WAAO,KAAK,WAAW,IAAI,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC;AAAA,EACnD;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,MAAc,OAAmB,CAAC,GAAa;AACvD,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,WAAO,KAAK,QAAQ,IAAI,GAAG,IAAI,CAAC,GAAG,UAAU,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,MAAc,OAAmB,CAAC,GAAW;AACtD,UAAM,MAAM,KAAK,UAAU,MAAM,IAAI;AACrC,WAAO,KAAK,KAAK,IAAI,GAAG,GAAG,QAAQ;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,aAA6B;AAC3B,UAAM,UAA0B;AAAA,MAC9B,UAAU,CAAC;AAAA,MACX,QAAQ,CAAC;AAAA,MACT,YAAY,CAAC;AAAA,MACb,SAAS,CAAC;AAAA,MACV,MAAM,CAAC;AAAA,IACT;AAEA,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,UAAU;AACvC,YAAM,QAAQ,KAAK,CAAC;AACpB,UAAI,OAAO;AACT,gBAAQ,SAAS,GAAG,IAAI,MAAM;AAAA,MAChC;AAAA,IACF;AAEA,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,QAAQ;AACrC,cAAQ,OAAO,GAAG,IAAI,KAAK;AAAA,IAC7B;AAEA,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,YAAY;AACzC,YAAM,QAAQ,KAAK,CAAC;AACpB,UAAI,OAAO;AACT,cAAM,SAAS,MAAM;AACrB,gBAAQ,WAAW,GAAG,IAAI;AAAA,UACxB,OAAO,OAAO;AAAA,UACd,KAAK,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,UACrC,KAAK,KAAK,IAAI,GAAG,MAAM;AAAA,UACvB,KAAK,KAAK,IAAI,GAAG,MAAM;AAAA,UACvB,KAAK,OAAO,SAAS,IAAI,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,OAAO,SAAS;AAAA,QAC/E;AAAA,MACF;AAAA,IACF;AAEA,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,SAAS;AACtC,YAAM,QAAQ,KAAK,CAAC;AACpB,UAAI,OAAO;AACT,cAAM,SAAS,MAAM;AACrB,gBAAQ,QAAQ,GAAG,IAAI;AAAA,UACrB,OAAO,OAAO;AAAA,UACd,KAAK,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC;AAAA,UACrC,KAAK,KAAK,IAAI,GAAG,MAAM;AAAA,UACvB,KAAK,KAAK,IAAI,GAAG,MAAM;AAAA,UACvB,KAAK,OAAO,SAAS,IAAI,OAAO,OAAO,CAAC,GAAG,MAAM,IAAI,GAAG,CAAC,IAAI,OAAO,SAAS;AAAA,UAC7E,KAAK,KAAK,WAAW,QAAQ,EAAE;AAAA,UAC/B,KAAK,KAAK,WAAW,QAAQ,EAAE;AAAA,UAC/B,KAAK,KAAK,WAAW,QAAQ,EAAE;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAEA,eAAW,CAAC,KAAK,IAAI,KAAK,KAAK,MAAM;AACnC,cAAQ,KAAK,GAAG,IAAI,KAAK;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,MAAM;AACpB,SAAK,OAAO,MAAM;AAClB,SAAK,WAAW,MAAM;AACtB,SAAK,QAAQ,MAAM;AACnB,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA,EAEQ,UAAU,MAAc,MAA0B;AACxD,UAAM,SAAS,OAAO,QAAQ,IAAI,EAC/B,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,EACrC,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,EAC3B,KAAK,GAAG;AACX,WAAO,SAAS,GAAG,IAAI,IAAI,MAAM,KAAK;AAAA,EACxC;AAAA,EAEQ,WAAW,QAAkB,GAAmB;AACtD,QAAI,OAAO,WAAW,EAAG,QAAO;AAEhC,UAAM,SAAS,CAAC,GAAG,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,IAAI,CAAC;AAC/C,UAAM,QAAQ,KAAK,KAAM,IAAI,MAAO,OAAO,MAAM,IAAI;AACrD,UAAM,YAAY,KAAK,IAAI,GAAG,KAAK;AACnC,WAAO,OAAO,SAAS,KAAK;AAAA,EAC9B;AACF;AAKO,IAAM,cAAN,MAAsC;AAAA,EAC3C,YAAkB;AAAA,EAAC;AAAA,EACnB,YAAkB;AAAA,EAAC;AAAA,EACnB,QAAc;AAAA,EAAC;AAAA,EACf,YAAkB;AAAA,EAAC;AAAA,EACnB,SAAe;AAAA,EAAC;AAAA,EAChB,aAAyB;AACvB,WAAO,MAAM;AAAA,IAAC;AAAA,EAChB;AAAA,EACA,eAAqB;AAAA,EAAC;AAAA,EACtB,MAAY;AAAA,EAAC;AAAA,EACb,MAAM,QAAuB;AAAA,EAAC;AAAA,EAC9B,MAAM,QAAuB;AAAA,EAAC;AAChC;AAoCO,SAAS,oBACd,SACA,QACA,cAA0B,CAAC,GACjB;AACV,QAAM,eAAe,CAAC,SAAiB,GAAG,MAAM,IAAI,IAAI;AACxD,QAAM,aAAa,CAAC,UAAuB,EAAE,GAAG,aAAa,GAAG,KAAK;AAErE,SAAO;AAAA,IACL,UAAU,MAAM,OAAO,MAAM;AAC3B,cAAQ,UAAU,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IAC/D;AAAA,IACA,UAAU,MAAM,OAAO,MAAM;AAC3B,cAAQ,UAAU,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IAC/D;AAAA,IACA,MAAM,MAAM,OAAO,MAAM;AACvB,cAAQ,MAAM,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IAC3D;AAAA,IACA,UAAU,MAAM,OAAO,MAAM;AAC3B,cAAQ,UAAU,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IAC/D;AAAA,IACA,OAAO,MAAM,OAAO,MAAM;AACxB,cAAQ,OAAO,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IAC5D;AAAA,IACA,WAAW,MAAM,MAAM;AACrB,aAAO,QAAQ,WAAW,aAAa,IAAI,GAAG,WAAW,IAAI,CAAC;AAAA,IAChE;AAAA,IACA,aAAa,MAAM,OAAO,MAAM;AAC9B,cAAQ,eAAe,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IACpE;AAAA,IACA,IAAI,MAAM,OAAO,MAAM;AACrB,cAAQ,MAAM,aAAa,IAAI,GAAG,OAAO,WAAW,IAAI,CAAC;AAAA,IAC3D;AAAA,IACA,OAAO,MAAM,QAAQ,MAAM;AAAA,IAC3B,OAAO,MAAM,QAAQ,MAAM;AAAA,EAC7B;AACF;;;AC9OO,IAAM,aAAN,MAAqC;AAAA,EAClC;AAAA,EACA,QAA2D,oBAAI,IAAI;AAAA,EAE3E,YAAY,UAA+B,CAAC,GAAG;AAC7C,SAAK,SAAS,QAAQ,UAAU;AAAA,EAClC;AAAA,EAEQ,UAAU,KAAqB;AACrC,UAAM,gBAAgB,IAAI,YAAY,EAAE,QAAQ,SAAS,GAAG;AAC5D,WAAO,KAAK,SAAS,GAAG,KAAK,MAAM,IAAI,aAAa,KAAK;AAAA,EAC3D;AAAA,EAEA,MAAM,IAAI,KAAa,SAAoD;AAEzE,QAAI,SAAS,UAAU;AACrB,YAAM,SAAS,KAAK,MAAM,IAAI,GAAG;AACjC,UAAI,UAAU,OAAO,YAAY,KAAK,IAAI,GAAG;AAC3C,eAAO,OAAO;AAAA,MAChB;AAAA,IACF;AAEA,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,UAAM,QAAQ,QAAQ,IAAI,MAAM,KAAK;AAGrC,QAAI,SAAS,SAAS,UAAU;AAC9B,WAAK,MAAM,IAAI,KAAK;AAAA,QAClB;AAAA,QACA,WAAW,KAAK,IAAI,IAAI,QAAQ,WAAW;AAAA,MAC7C,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,gBAAgB,KAAa,SAAoD;AACrF,UAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,OAAO;AACzC,QAAI,UAAU,MAAM;AAClB,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,UAAU;AAAA;AAAA,QAER,WAAW;AAAA,QACX,WAAW;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,MAAqD;AAC9D,UAAM,SAAS,oBAAI,IAA2B;AAC9C,eAAW,OAAO,MAAM;AACtB,aAAO,IAAI,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC;AAAA,IACrC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,KAAa,OAAe,UAA4C;AAChF,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,YAAQ,IAAI,MAAM,IAAI;AAGtB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,WAAO,QAAQ,IAAI,MAAM;AACzB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,OAAO,KAA+B;AAC1C,UAAM,SAAS,KAAK,UAAU,GAAG;AACjC,WAAO,QAAQ,IAAI,MAAM,MAAM;AAAA,EACjC;AAAA,EAEA,MAAM,KAAK,QAAoC;AAC7C,UAAM,OAAiB,CAAC;AACxB,UAAM,YAAY,KAAK,SAAS,GAAG,KAAK,MAAM,MAAM;AACpD,UAAM,eAAe,SACjB,GAAG,SAAS,GAAG,OAAO,YAAY,EAAE,QAAQ,SAAS,GAAG,CAAC,KACzD;AAEJ,eAAW,OAAO,OAAO,KAAK,QAAQ,GAAG,GAAG;AAC1C,UAAI,IAAI,WAAW,gBAAgB,EAAE,GAAG;AAEtC,cAAM,gBAAgB,IACnB,MAAM,UAAU,MAAM,EACtB,YAAY,EACZ,QAAQ,MAAM,GAAG;AACpB,aAAK,KAAK,aAAa;AAAA,MACzB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,KAAa,SAAwD;AAChF,UAAM,gBAAgB,MAAM,KAAK,IAAI,GAAG;AAGxC,UAAM,WAAW,SAAS,aACtB,MAAM,QAAQ,WAAW,IACzB,KAAK,oBAAoB;AAE7B,UAAM,KAAK,IAAI,KAAK,QAAQ;AAE5B,WAAO;AAAA,MACL;AAAA,MACA,eAAe,iBAAiB;AAAA,MAChC,YAAY;AAAA,MACZ,iBAAiB,gBAAgB,aAAa;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,MAAyC;AAEzD,WAAO,CAAC;AAAA,EACV;AAAA,EAEA,MAAM,cAAgC;AAEpC,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,SAAiB,IAAY;AACvD,UAAM,QAAQ;AACd,QAAI,SAAS;AACb,UAAM,eAAe,IAAI,YAAY,MAAM;AAC3C,WAAO,gBAAgB,YAAY;AACnC,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,gBAAU,MAAM,aAAa,CAAC,IAAK,MAAM,MAAM;AAAA,IACjD;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;AAMO,IAAM,gBAAN,MAAwC;AAAA,EACrC,UAA+B,oBAAI,IAAI;AAAA,EACvC,WAA0C,oBAAI,IAAI;AAAA,EAE1D,MAAM,IAAI,KAAa,UAAqD;AAC1E,UAAM,SAAS,KAAK,QAAQ,IAAI,GAAG;AACnC,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,UAAU,aAAa,OAAO,SAAS,YAAY,oBAAI,KAAK,GAAG;AACxE,YAAM,KAAK,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,gBAAgB,KAAa,SAAoD;AACrF,UAAM,QAAQ,MAAM,KAAK,IAAI,KAAK,OAAO;AACzC,QAAI,UAAU,MAAM;AAClB,aAAO;AAAA,IACT;AAEA,WAAO,KAAK,QAAQ,IAAI,GAAG,KAAK;AAAA,EAClC;AAAA,EAEA,MAAM,KAAK,MAAqD;AAC9D,UAAM,SAAS,oBAAI,IAA2B;AAC9C,eAAW,OAAO,MAAM;AACtB,aAAO,IAAI,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC;AAAA,IACrC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,KAAa,OAAe,SAA2C;AAC/E,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,UAAU,IAAI,KAAK,IAAI,CAAC;AAG9B,UAAM,gBAAgB,KAAK,QAAQ,IAAI,GAAG;AAC1C,QAAI,eAAe,UAAU;AAC3B,YAAM,UAAU,KAAK,SAAS,IAAI,GAAG,KAAK,CAAC;AAC3C,cAAQ,KAAK,cAAc,QAAQ;AACnC,WAAK,SAAS,IAAI,KAAK,OAAO;AAAA,IAChC;AAEA,SAAK,QAAQ,IAAI,KAAK;AAAA,MACpB;AAAA,MACA;AAAA,MACA,UAAU;AAAA,QACR;AAAA,QACA,WAAW,eAAe,UAAU,aAAa;AAAA,QACjD,WAAW;AAAA,QACX,WAAW,SAAS;AAAA,QACpB,MAAM,SAAS;AAAA,MACjB;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,SAAK,QAAQ,OAAO,GAAG;AACvB,SAAK,SAAS,OAAO,GAAG;AAAA,EAC1B;AAAA,EAEA,MAAM,OAAO,KAA+B;AAC1C,WAAO,KAAK,QAAQ,IAAI,GAAG;AAAA,EAC7B;AAAA,EAEA,MAAM,KAAK,QAAoC;AAC7C,UAAM,OAAiB,CAAC;AACxB,eAAW,OAAO,KAAK,QAAQ,KAAK,GAAG;AACrC,UAAI,CAAC,UAAU,IAAI,WAAW,MAAM,GAAG;AACrC,aAAK,KAAK,GAAG;AAAA,MACf;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,KAAa,SAAwD;AAChF,UAAM,gBAAgB,KAAK,QAAQ,IAAI,GAAG;AAC1C,UAAM,gBAAgB,eAAe;AACrC,UAAM,kBAAkB,eAAe,UAAU;AAGjD,UAAM,WAAW,SAAS,aACtB,MAAM,QAAQ,WAAW,IACzB,KAAK,oBAAoB;AAE7B,UAAM,KAAK,IAAI,KAAK,QAAQ;AAC5B,UAAM,aAAa,KAAK,QAAQ,IAAI,GAAG,GAAG,UAAU,WAAW;AAE/D,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,KAAwC;AACxD,UAAM,UAAU,KAAK,QAAQ,IAAI,GAAG,GAAG;AACvC,UAAM,UAAU,KAAK,SAAS,IAAI,GAAG,KAAK,CAAC;AAE3C,QAAI,SAAS;AACX,aAAO,CAAC,GAAG,SAAS,OAAO;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEQ,oBAAoB,SAAiB,IAAY;AACvD,UAAM,QAAQ;AACd,QAAI,SAAS;AACb,aAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,gBAAU,MAAM,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AAAA,IAC1D;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,QAAQ,MAAM;AACnB,SAAK,SAAS,MAAM;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,QAAQ;AAAA,EACtB;AACF;;;ACtPA,IAAM,aAAN,MAAkC;AAAA,EACvB;AAAA,EACA;AAAA,EACA,cAAuB;AAAA,EAExB,cAAyD,CAAC;AAAA,EAC1D,UAAuB,CAAC;AAAA,EACxB,UAAsB,EAAE,MAAM,QAAQ;AAAA,EACtC;AAAA,EACA;AAAA,EAER,YAAY,MAAc,SAAiB,cAAuB;AAChE,SAAK,OAAO;AACZ,SAAK,aAAa,KAAK,IAAI;AAC3B,SAAK,UAAU;AAAA,MACb;AAAA,MACA,QAAQ,KAAK,eAAe;AAAA,MAC5B,YAAY;AAAA,IACd;AAAA,EACF;AAAA,EAEQ,iBAAyB;AAC/B,WAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,EAAE,SAAS,IAAI,GAAG;AAAA,EACrE;AAAA,EAEA,aAAa,KAAa,OAAwC;AAChE,SAAK,YAAY,GAAG,IAAI;AACxB,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,YAA6D;AACzE,WAAO,OAAO,KAAK,aAAa,UAAU;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,SAAS,MAAc,YAA8D;AACnF,SAAK,QAAQ,KAAK,EAAE,MAAM,WAAW,KAAK,IAAI,GAAG,WAAW,CAAC;AAC7D,WAAO;AAAA,EACT;AAAA,EAEA,UAAU,QAA0B;AAClC,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA,EAEA,gBAAgB,WAAkB,YAA8D;AAC9F,SAAK,SAAS,aAAa;AAAA,MACzB,kBAAkB,UAAU;AAAA,MAC5B,qBAAqB,UAAU;AAAA,MAC/B,wBAAwB,UAAU,SAAS;AAAA,MAC3C,GAAG;AAAA,IACL,CAAC;AACD,SAAK,UAAU,EAAE,MAAM,SAAS,SAAS,UAAU,QAAQ,CAAC;AAC5D,WAAO;AAAA,EACT;AAAA,EAEA,WAAW,MAAoB;AAC7B,IAAC,KAA0B,OAAO;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,SAAwB;AAC1B,SAAK,WAAW,WAAW,KAAK,IAAI;AAAA,EACtC;AAAA;AAAA,EAGA,gBAA2D;AACzD,WAAO,EAAE,GAAG,KAAK,YAAY;AAAA,EAC/B;AAAA,EAEA,YAAyB;AACvB,WAAO,CAAC,GAAG,KAAK,OAAO;AAAA,EACzB;AAAA,EAEA,YAAwB;AACtB,WAAO,EAAE,GAAG,KAAK,QAAQ;AAAA,EAC3B;AAAA,EAEA,cAAkC;AAChC,WAAO,KAAK,WAAW,KAAK,WAAW,KAAK,aAAa;AAAA,EAC3D;AAAA,EAEA,UAAmB;AACjB,WAAO,KAAK,aAAa;AAAA,EAC3B;AACF;AAEO,IAAM,gBAAN,MAAwC;AAAA,EACrC,QAAsB,CAAC;AAAA,EACvB;AAAA,EACA;AAAA,EAER,cAAc;AACZ,SAAK,UAAU,KAAK,gBAAgB;AAAA,EACtC;AAAA,EAEQ,kBAA0B;AAChC,WAAO,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE,EAAE,SAAS,IAAI,GAAG;AAAA,EACrE;AAAA,EAEA,UAAU,MAAc,SAA8B;AACpD,UAAM,OAAO,IAAI,WAAW,MAAM,KAAK,SAAS,KAAK,aAAa,QAAQ,MAAM;AAEhF,QAAI,SAAS,YAAY;AACvB,WAAK,cAAc,QAAQ,UAAU;AAAA,IACvC;AAEA,SAAK,MAAM,KAAK,IAAI;AACpB,SAAK,cAAc;AAEnB,WAAO;AAAA,EACT;AAAA,EAEA,iBAAoC;AAClC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,SAAY,MAAc,IAAwB,SAA0B;AAC1E,UAAM,OAAO,KAAK,UAAU,MAAM,OAAO;AACzC,QAAI;AACF,YAAM,SAAS,GAAG,IAAI;AACtB,WAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAC7B,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,gBAAgB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAC9E,YAAM;AAAA,IACR,UAAE;AACA,WAAK,IAAI;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,cAAiB,MAAc,IAAiC,SAAmC;AACvG,UAAM,OAAO,KAAK,UAAU,MAAM,OAAO;AACzC,QAAI;AACF,YAAM,SAAS,MAAM,GAAG,IAAI;AAC5B,WAAK,UAAU,EAAE,MAAM,KAAK,CAAC;AAC7B,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,gBAAgB,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AAC9E,YAAM;AAAA,IACR,UAAE;AACA,WAAK,IAAI;AAAA,IACX;AAAA,EACF;AAAA,EAEA,WACE,MACA,IACA,SAC6B;AAC7B,WAAO,IAAI,SAAgB,KAAK,SAAS,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO;AAAA,EAC3E;AAAA,EAEA,gBACE,MACA,IACA,SACsC;AACtC,WAAO,IAAI,SAAgB,KAAK,cAAc,MAAM,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO;AAAA,EAChF;AAAA,EAEA,eAAe,SAAiF;AAC9F,UAAM,cAAc,QAAQ,aAAa;AACzC,QAAI,CAAC,eAAe,OAAO,gBAAgB,SAAU,QAAO;AAG5D,UAAM,QAAQ,YAAY,MAAM,GAAG;AACnC,QAAI,MAAM,WAAW,EAAG,QAAO;AAE/B,WAAO;AAAA,MACL,SAAS,MAAM,CAAC;AAAA,MAChB,QAAQ,MAAM,CAAC;AAAA,MACf,YAAY,SAAS,MAAM,CAAC,GAAI,EAAE;AAAA,IACpC;AAAA,EACF;AAAA,EAEA,cAAc,SAAuC;AACnD,QAAI,KAAK,aAAa;AACpB,YAAM,MAAM,KAAK,YAAY;AAC7B,cAAQ,aAAa,IAAI,MAAM,IAAI,OAAO,IAAI,IAAI,MAAM,IAAI,IAAI,WAAW,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC;AAAA,IAC1G;AAAA,EACF;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,QAAQ,CAAC;AACd,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA,EAGA,WAAyB;AACvB,WAAO,CAAC,GAAG,KAAK,KAAK;AAAA,EACvB;AAAA,EAEA,oBAAkC;AAChC,WAAO,KAAK,MAAM,OAAO,CAAC,MAAM,EAAE,QAAQ,CAAC;AAAA,EAC7C;AAAA,EAEA,QAAc;AACZ,SAAK,QAAQ,CAAC;AACd,SAAK,cAAc;AACnB,SAAK,UAAU,KAAK,gBAAgB;AAAA,EACtC;AACF;AAMA,IAAM,WAAN,MAAgC;AAAA,EACrB,OAAe;AAAA,EACf,UAAuB,EAAE,SAAS,IAAI,QAAQ,IAAI,YAAY,EAAE;AAAA,EAChE,cAAuB;AAAA,EAEhC,eAAqB;AACnB,WAAO;AAAA,EACT;AAAA,EACA,gBAAsB;AACpB,WAAO;AAAA,EACT;AAAA,EACA,WAAiB;AACf,WAAO;AAAA,EACT;AAAA,EACA,YAAkB;AAChB,WAAO;AAAA,EACT;AAAA,EACA,kBAAwB;AACtB,WAAO;AAAA,EACT;AAAA,EACA,aAAmB;AACjB,WAAO;AAAA,EACT;AAAA,EACA,MAAY;AAAA,EAAC;AACf;AAEO,IAAM,cAAN,MAAsC;AAAA,EACnC,WAAW,IAAI,SAAS;AAAA,EAEhC,YAAmB;AACjB,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,iBAAoC;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,SAAY,OAAe,IAA2B;AACpD,WAAO,GAAG,KAAK,QAAQ;AAAA,EACzB;AAAA,EAEA,MAAM,cAAiB,OAAe,IAA6C;AACjF,WAAO,GAAG,KAAK,QAAQ;AAAA,EACzB;AAAA,EAEA,WACE,OACA,IAC6B;AAC7B,WAAO;AAAA,EACT;AAAA,EAEA,gBACE,OACA,IACsC;AACtC,WAAO;AAAA,EACT;AAAA,EAEA,iBAA0C;AACxC,WAAO;AAAA,EACT;AAAA,EAEA,gBAAsB;AAAA,EAAC;AAAA,EAEvB,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAAA,EAAC;AAAA,EAE9B,MAAM,QAAuB;AAAA,EAAC;AAChC;;;ACvTO,SAAS,kBAA0B;AACxC,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,OAAO,SAAS,IAAI,MAAM;AACnC;AAKO,SAAS,oBAAoB,OAAwB;AAC1D,QAAM,cAAwB,CAAC;AAG/B,cAAY,KAAK,MAAM,QAAQ,OAAO;AAGtC,MAAI,MAAM,OAAO;AACf,UAAM,aAAa,MAAM,MAAM,MAAM,IAAI;AACzC,UAAM,aAAa,WAAW,CAAC,GAAG,KAAK;AACvC,QAAI,YAAY;AAEd,YAAM,QAAQ,WAAW,MAAM,yCAAyC;AACxE,UAAI,OAAO;AACT,oBAAY,KAAK,GAAG,MAAM,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,EAAE;AAAA,MAC5C;AAAA,IACF;AAAA,EACF;AAGA,QAAM,oBAAoB,MAAM,QAC7B,QAAQ,sEAAsE,QAAQ,EACtF,QAAQ,YAAY,UAAU;AACjC,cAAY,KAAK,iBAAiB;AAElC,SAAO;AACT;AAKO,SAAS,kBACd,OACA,SACA,SACa;AACb,SAAO;AAAA,IACL,IAAI,gBAAgB;AAAA,IACpB,SAAS,MAAM;AAAA,IACf,MAAM,MAAM,QAAQ;AAAA,IACpB,OAAO,MAAM;AAAA,IACb,SAAS;AAAA,MACP,GAAG;AAAA,MACH,GAAG,SAAS;AAAA,MACZ,MAAM,EAAE,GAAG,QAAQ,MAAM,GAAG,SAAS,KAAK;AAAA,MAC1C,OAAO,EAAE,GAAG,QAAQ,OAAO,GAAG,SAAS,MAAM;AAAA,IAC/C;AAAA,IACA,OAAO,SAAS,SAAS;AAAA,IACzB,WAAW,KAAK,IAAI;AAAA,IACpB,SAAS,SAAS,WAAW;AAAA,IAC7B,aAAa,SAAS,eAAe,oBAAoB,KAAK;AAAA,IAC9D,aAAa,CAAC;AAAA,EAChB;AACF;;;AC2FO,SAAS,kBAA0B;AACxC,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,OAAO,SAAS,GAAG,MAAM;AAClC;AAKO,SAAS,iBAAiB,OAA6C;AAE5E,QAAM,YAAY,KAAK,UAAU,OAAO,OAAO,KAAK,KAAK,EAAE,KAAK,CAAC;AAIjE,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,UAAU,QAAQ,KAAK;AACzC,UAAM,OAAO,UAAU,WAAW,CAAC;AACnC,YAAS,QAAQ,KAAK,OAAQ;AAC9B,WAAO,OAAO;AAAA,EAChB;AAGA,QAAM,MAAM,KAAK,IAAI,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACvD,SAAO,UAAU,GAAG,GAAG,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC;AAChD;AAQO,SAAS,YAAY,QAAgB,SAA0B;AACpE,MAAI,YAAY,IAAK,QAAO;AAC5B,MAAI,YAAY,OAAQ,QAAO;AAE/B,MAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,UAAM,SAAS,QAAQ,MAAM,GAAG,EAAE;AAClC,WAAO,OAAO,WAAW,SAAS,GAAG;AAAA,EACvC;AAEA,SAAO;AACT;AAKO,IAAM,cAAc;AAAA;AAAA,EAEzB,MAAM;AAAA,IACJ,OAAO,CAAC,OAAmB,SAAuB,UAAgD;AAAA,MAChG,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,WAAmC;AAAA,MAC1C,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,IACF;AAAA,IACA,cAAc,CAAC,OAAmB,aAAuC;AAAA,MACvE,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,IACA,gBAAgB,CAAC,OAAmB,aAAuC;AAAA,MACzE,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,IACF;AAAA,IACA,YAAY,CAAC,WAAmC;AAAA,MAC9C,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,MAAM;AAAA,IACJ,MAAM,CAAC,OAAmB,QAAqB,UAAwB,eAA2B;AAAA,MAChG,UAAU;AAAA,MACV,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA,QAAQ,CAAC,OAAmB,QAAqB,UAAgD;AAAA,MAC/F,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,SAAS,EAAE,OAAO,KAAK;AAAA,IACzB;AAAA,IACA,QAAQ,CAAC,OAAmB,QAAqB,QAAkC,WAAiD;AAAA,MAClI,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,SAAS,EAAE,QAAQ,MAAM;AAAA,IAC3B;AAAA,IACA,QAAQ,CAAC,OAAmB,QAAqB,UAAgD;AAAA,MAC/F,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA;AAAA,MACA,SAAS,EAAE,QAAQ,KAAK;AAAA,IAC1B;AAAA,EACF;AAAA;AAAA,EAGA,OAAO;AAAA,IACL,eAAe,CAAC,OAAmB,SAAiB,QAAiB,WAAgC;AAAA,MACnG,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,WAAW,IAAI,QAAQ;AAAA,MACvC,SAAS,EAAE,QAAQ,EAAE,OAAO,OAAO,GAAG,OAAO,EAAE,OAAO,MAAM,EAAE;AAAA,IAChE;AAAA,IACA,aAAa,CAAC,OAAmB,cAAsB,YAAiC;AAAA,MACtF,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,QAAQ,IAAI,aAAa;AAAA,MACzC,MAAM,EAAE,OAAO;AAAA,IACjB;AAAA,EACF;AAAA;AAAA,EAGA,UAAU;AAAA,IACR,cAAc,CAAC,OAAmB,UAAkB,YAAiC;AAAA,MACnF,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,YAAY,IAAI,SAAS;AAAA,MACzC,MAAM,EAAE,OAAO;AAAA,IACjB;AAAA,IACA,aAAa,CAAC,OAAmB,cAAkC;AAAA,MACjE,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,YAAY,IAAI,SAAS;AAAA,IAC3C;AAAA,IACA,oBAAoB,CAAC,OAAmB,aAAqB,UAAgD;AAAA,MAC3G,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,MAAM,EAAE,aAAa,GAAG,KAAK;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA,EAGA,SAAS;AAAA,IACP,qBAAqB,CAAC,OAAmB,gBAAwB,UAA8B;AAAA,MAC7F,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,gBAAgB,IAAI,eAAe;AAAA,MACnD,MAAM,EAAE,KAAK;AAAA,IACf;AAAA,IACA,kBAAkB,CAAC,OAAmB,WAAmB,QAAgB,cAAkC;AAAA,MACzG,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,WAAW,IAAI,UAAU;AAAA,MACzC,MAAM,EAAE,QAAQ,SAAS;AAAA,IAC3B;AAAA,IACA,eAAe,CAAC,OAAmB,WAAmB,YAAgC;AAAA,MACpF,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT;AAAA,MACA,QAAQ,EAAE,MAAM,WAAW,IAAI,UAAU;AAAA,MACzC,OAAO,EAAE,SAAS,OAAO;AAAA,IAC3B;AAAA,EACF;AACF;;;AC3MO,SAAS,qBAA6B;AAC3C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC;AACxD,SAAO,OAAO,SAAS,GAAG,MAAM;AAClC;AAMO,SAAS,eAAe,MAAsB,QAAc,oBAAI,KAAK,GAAG,UAAgC;AAG7G,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,MAAI,MAAM,SAAS,KAAK,MAAM,SAAS,GAAG;AACxC,WAAO;AAAA,EACT;AAIA,QAAM,OAAO,IAAI,KAAK,KAAK;AAC3B,OAAK,WAAW,GAAG,CAAC;AACpB,OAAK,WAAW,KAAK,WAAW,IAAI,CAAC;AACrC,SAAO;AACT;AAKO,SAAS,YAAY,MAA+B;AACzD,QAAM,QAAQ,KAAK,KAAK,EAAE,MAAM,KAAK;AACrC,SAAO,MAAM,UAAU,KAAK,MAAM,UAAU;AAC9C;AAKO,IAAM,cAAc;AAAA;AAAA,EAEzB,aAAa;AAAA;AAAA,EAEb,eAAe;AAAA;AAAA,EAEf,gBAAgB;AAAA;AAAA,EAEhB,gBAAgB;AAAA;AAAA,EAEhB,QAAQ;AAAA;AAAA,EAER,OAAO;AAAA;AAAA,EAEP,YAAY;AAAA;AAAA,EAEZ,cAAc;AAAA;AAAA,EAEd,SAAS;AAAA;AAAA,EAET,UAAU;AAAA;AAAA,EAEV,UAAU;AACZ;AAKO,SAAS,aAAa,MAA8B;AAEzD,QAAM,qBAA6C;AAAA,IACjD,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,IAChB,gBAAgB;AAAA,IAChB,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,aAAa;AAAA,IACb,eAAe;AAAA,IACf,gBAAgB;AAAA,EAClB;AAEA,SAAO,mBAAmB,IAAI,KAAK,SAAS,IAAI;AAClD;;;ACyEO,SAAS,oBAA4B;AAC1C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,MAAM,SAAS,GAAG,MAAM;AACjC;AAKO,SAAS,qBAA6B;AAC3C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,OAAO,SAAS,GAAG,MAAM;AAClC;AAKO,SAAS,kBAA0B;AACxC,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,OAAO,SAAS,GAAG,MAAM;AAClC;AAKO,SAAS,sBAAsB,SAAS,IAAY;AACzD,QAAM,QAAQ;AACd,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,QAAQ,KAAK;AAC/B,cAAU,MAAM,OAAO,KAAK,MAAM,KAAK,OAAO,IAAI,MAAM,MAAM,CAAC;AAAA,EACjE;AACA,SAAO;AACT;AAQO,SAAS,eAAe,WAAmB,SAA0B;AAE1E,MAAI,cAAc,WAAW,YAAY,OAAO,YAAY,MAAM;AAChE,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,UAAU,MAAM,GAAG;AACtC,QAAM,eAAe,QAAQ,MAAM,GAAG;AAEtC,MAAI,KAAK;AACT,MAAI,KAAK;AAET,SAAO,KAAK,WAAW,UAAU,KAAK,aAAa,QAAQ;AACzD,UAAM,OAAO,aAAa,EAAE;AAE5B,QAAI,SAAS,MAAM;AAEjB,UAAI,OAAO,aAAa,SAAS,GAAG;AAElC,eAAO;AAAA,MACT;AAEA,YAAM,cAAc,aAAa,MAAM,KAAK,CAAC,EAAE,KAAK,GAAG;AACvD,eAAS,IAAI,IAAI,KAAK,WAAW,QAAQ,KAAK;AAC5C,cAAM,YAAY,WAAW,MAAM,CAAC,EAAE,KAAK,GAAG;AAC9C,YAAI,eAAe,WAAW,WAAW,GAAG;AAC1C,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,QAAI,SAAS,KAAK;AAEhB;AACA;AACA;AAAA,IACF;AAEA,QAAI,SAAS,WAAW,EAAE,GAAG;AAC3B,aAAO;AAAA,IACT;AAEA;AACA;AAAA,EACF;AAEA,SAAO,OAAO,WAAW,UAAU,OAAO,aAAa;AACzD;AAKO,SAAS,oBACd,SACA,eAAe,KACf,WAAW,MACX,aAAa,GACL;AACR,QAAM,QAAQ,eAAe,KAAK,IAAI,YAAY,UAAU,CAAC;AAE7D,QAAM,SAAS,QAAQ,QAAQ,KAAK,OAAO,IAAI,IAAI;AACnD,SAAO,KAAK,IAAI,QAAQ,QAAQ,QAAQ;AAC1C;AAKO,IAAM,oBAAoB;AAAA;AAAA,EAE/B,cAAc;AAAA,EACd,cAAc;AAAA,EACd,cAAc;AAAA,EACd,YAAY;AAAA,EACZ,aAAa;AAAA;AAAA,EAGb,sBAAsB;AAAA,EACtB,sBAAsB;AAAA,EACtB,wBAAwB;AAAA,EACxB,sBAAsB;AAAA;AAAA,EAGtB,mBAAmB;AAAA,EACnB,gBAAgB;AAAA,EAChB,kBAAkB;AAAA;AAAA,EAGlB,iBAAiB;AAAA,EACjB,cAAc;AAAA,EACd,gBAAgB;AAAA;AAAA,EAGhB,eAAe;AAAA,EACf,eAAe;AAAA,EACf,iBAAiB;AAAA,EACjB,iBAAiB;AAAA;AAAA,EAGjB,KAAK;AAAA,EACL,UAAU;AAAA,EACV,aAAa;AAAA,EACb,kBAAkB;AAAA,EAClB,WAAW;AACb;;;ACxLO,SAAS,yBAAiC;AAC/C,QAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,QAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,SAAO,SAAS,SAAS,GAAG,MAAM;AACpC;AAKO,SAAS,eAAe,aAA+C;AAC5E,MAAI,CAAC,YAAY,YAAY,QAAS,QAAO;AAE7C,QAAM,EAAE,OAAO,KAAK,SAAS,IAAI,YAAY;AAC7C,QAAM,MAAM,oBAAI,KAAK;AAGrB,QAAM,CAAC,QAAQ,MAAM,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,MAAM;AACpD,QAAM,CAAC,MAAM,IAAI,IAAI,IAAI,MAAM,GAAG,EAAE,IAAI,MAAM;AAG9C,QAAM,YAAY,IAAI,KAAK,eAAe,SAAS;AAAA,IACjD,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ;AAAA,IACR,QAAQ;AAAA,EACV,CAAC;AACD,QAAM,QAAQ,UAAU,cAAc,GAAG;AACzC,QAAM,WAAW,SAAS,MAAM,KAAK,OAAK,EAAE,SAAS,MAAM,GAAG,SAAS,KAAK,EAAE;AAC9E,QAAM,WAAW,SAAS,MAAM,KAAK,OAAK,EAAE,SAAS,QAAQ,GAAG,SAAS,KAAK,EAAE;AAEhF,QAAM,iBAAiB,WAAW,KAAK;AACvC,QAAM,gBAAgB,UAAU,KAAK,MAAM,UAAU;AACrD,QAAM,cAAc,QAAQ,KAAK,MAAM,QAAQ;AAG/C,MAAI,eAAe,YAAY;AAC7B,WAAO,kBAAkB,gBAAgB,iBAAiB;AAAA,EAC5D;AAEA,SAAO,kBAAkB,gBAAgB,iBAAiB;AAC5D;AAKO,SAAS,yBAAyB,QAAyC;AAChF,SAAO;AAAA,IACL;AAAA,IACA,iBAAiB,CAAC,UAAU,OAAO;AAAA,IACnC,YAAY;AAAA,MACV,QAAQ,EAAE,SAAS,MAAM,UAAU,CAAC,UAAU,OAAO,EAAE;AAAA,MACvD,UAAU,EAAE,SAAS,MAAM,UAAU,CAAC,UAAU,SAAS,MAAM,EAAE;AAAA,MACjE,SAAS,EAAE,SAAS,MAAM,UAAU,CAAC,UAAU,OAAO,EAAE;AAAA,MACxD,SAAS,EAAE,SAAS,MAAM,UAAU,CAAC,UAAU,OAAO,EAAE;AAAA,MACxD,WAAW,EAAE,SAAS,OAAO,UAAU,CAAC,OAAO,EAAE;AAAA,MACjD,QAAQ,EAAE,SAAS,MAAM,UAAU,CAAC,UAAU,MAAM,EAAE;AAAA,MACtD,SAAS,EAAE,SAAS,MAAM,UAAU,CAAC,QAAQ,EAAE;AAAA,MAC/C,QAAQ,EAAE,SAAS,MAAM,UAAU,CAAC,UAAU,SAAS,MAAM,EAAE;AAAA,IACjE;AAAA,EACF;AACF;AAKO,SAAS,4BACd,mBACA,aACA,UACA,OACuB;AACvB,MAAI,MAAO,QAAO;AAGlB,MAAI,eAAe,WAAW,GAAG;AAE/B,WAAO,kBAAkB,OAAO,OAAK,MAAM,QAAQ;AAAA,EACrD;AAGA,MAAI,WAAW,kBAAkB,OAAO,OAAK,YAAY,gBAAgB,SAAS,CAAC,CAAC;AAGpF,MAAI,YAAY,YAAY,WAAW,QAAQ,GAAG;AAChD,UAAM,UAAU,YAAY,WAAW,QAAQ;AAC/C,QAAI,CAAC,SAAS,SAAS;AACrB,aAAO,CAAC;AAAA,IACV;AACA,eAAW,SAAS,OAAO,OAAK,QAAQ,SAAS,SAAS,CAAC,CAAC;AAAA,EAC9D;AAEA,SAAO;AACT;AAKO,IAAM,wBAAwB;AAAA,EACnC,SAAS,CAAC,UAAoC;AAAA,IAC5C,OAAO;AAAA,IACP,MAAM,MAAM,IAAI;AAAA,IAChB,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EAEA,iBAAiB,OAAyB;AAAA,IACxC,OAAO;AAAA,IACP,MAAM;AAAA,IACN,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EAEA,UAAU,CAAC,cAAyC;AAAA,IAClD,OAAO;AAAA,IACP,MAAM,WACF,iCAAiC,QAAQ,sDACzC;AAAA,IACJ,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EAEA,kBAAkB,CAAC,YAAsC;AAAA,IACvD,OAAO;AAAA,IACP,MAAM,mBAAmB,MAAM;AAAA,IAC/B,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EAEA,eAAe,CAAC,YAAuC;AAAA,IACrD,OAAO;AAAA,IACP,MAAM,SACF,wCAAwC,MAAM,KAC9C;AAAA,IACJ,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AAAA,EAEA,sBAAsB,CAAC,cAAwC;AAAA,IAC7D,OAAO;AAAA,IACP,MAAM,oCAAoC,QAAQ,OAAO,WAAW,IAAI,MAAM,EAAE;AAAA,IAChF,UAAU;AAAA,IACV,UAAU;AAAA,EACZ;AACF;;;ACpkBA,SAAS,SAAS;AAMX,IAAM,yBAAyB,EAAE,KAAK,CAAC,UAAU,YAAY,UAAU,CAAC;AACxE,IAAM,sBAAsB,EAAE,KAAK,CAAC,UAAU,SAAS,SAAS,CAAC;AACjE,IAAM,wBAAwB,EAAE,KAAK,CAAC,UAAU,MAAM,SAAS,MAAM,UAAU,CAAC;AAChF,IAAM,sBAAsB,EAAE,KAAK,CAAC,UAAU,WAAW,QAAQ,QAAQ,CAAC;AAC1E,IAAM,sBAAsB,EAAE,KAAK,CAAC,UAAU,QAAQ,CAAC;AACvD,IAAM,wBAAwB,EAAE,KAAK,CAAC,QAAQ,UAAU,MAAM,CAAC;AAC/D,IAAM,iBAAiB,EAAE,KAAK,CAAC,SAAS,QAAQ,QAAQ,OAAO,CAAC;AAMhE,IAAM,uBAAuB,EACjC,OAAO;AAAA,EACN,UAAU,uBAAuB,QAAQ,QAAQ;AAAA,EACjD,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,2BAA2B;AAAA,EAC/D,kBAAkB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,8CAA8C;AAAA,EAC/F,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,sBAAsB;AAAA,EACxE,iBAAiB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,wBAAwB;AAAA,EACxE,wBAAwB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,2BAA2B;AAAA,EAClF,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS,sBAAsB;AAAA,EACtF,mBAAmB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAI,EAAE,SAAS,0BAA0B;AAAA,EAC1G,KAAK,EAAE,MAAM,CAAC,EAAE,QAAQ,GAAG,EAAE,OAAO,EAAE,oBAAoB,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,SAAS,mBAAmB;AAC/H,CAAC,EACA;AAAA,EACC,CAAC,SAAS;AACR,QAAI,KAAK,aAAa,YAAY;AAChC,aAAO,KAAK,eAAe,KAAK;AAAA,IAClC;AACA,QAAI,KAAK,aAAa,YAAY;AAChC,aAAO,KAAK,OAAO,KAAK;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,SAAS;AAAA,EACX;AACF;AAEK,IAAM,oBAAoB,EAC9B,OAAO;AAAA,EACN,UAAU,oBAAoB,QAAQ,QAAQ;AAAA,EAC9C,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,sBAAsB;AAAA,EAChE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,kBAAkB;AAAA,EACnE,cAAc,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,oBAAoB;AAAA,EACjE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,IAAI,EAAE,SAAS,wBAAwB;AAAA,EACnF,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,SAAS,2BAA2B;AAAA,EACtE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,EAAE,SAAS,kCAAkC;AACpG,CAAC,EACA;AAAA,EACC,CAAC,SAAS;AACR,QAAI,KAAK,aAAa,WAAW;AAC/B,aAAO,KAAK,cAAc,KAAK;AAAA,IACjC;AACA,QAAI,KAAK,aAAa,SAAS;AAC7B,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,SAAS;AAAA,EACX;AACF;AAEK,IAAM,sBAAsB,EAChC,OAAO;AAAA,EACN,UAAU,sBAAsB,QAAQ,QAAQ;AAAA,EAChD,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,4BAA4B;AAAA,EAC3E,QAAQ,EAAE,OAAO,EAAE,QAAQ,WAAW,EAAE,SAAS,YAAY;AAAA,EAC7D,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,mBAAmB;AAAA,EAC7D,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,uBAAuB;AAAA,EACjE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,gBAAgB;AAAA,EACvD,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,gCAAgC;AAAA,EAChF,gBAAgB,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,0CAA0C;AAAA,EAC9F,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,IAAI,MAAM,EAAE,QAAQ,IAAI,EAAE,SAAS,8BAA8B;AAC7G,CAAC,EACA;AAAA,EACC,CAAC,SAAS;AACR,QAAI,CAAC,MAAM,SAAS,IAAI,EAAE,SAAS,KAAK,QAAQ,GAAG;AACjD,aAAO,KAAK,aAAa,KAAK,aAAa,KAAK;AAAA,IAClD;AACA,WAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,SAAS;AAAA,EACX;AACF;AAEK,IAAM,oBAAoB,EAC9B,OAAO;AAAA,EACN,UAAU,oBAAoB,QAAQ,QAAQ;AAAA,EAC9C,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,WAAW;AAAA,EAChD,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,KAAK,EAAE,SAAS,EAAE,SAAS,WAAW;AAAA,EACxE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,kBAAkB;AAAA,EAC9D,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,eAAe;AAAA,EACxD,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,eAAe;AAAA,EACxD,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,gBAAgB;AAAA,EACvD,MAAM,EACH,OAAO,EACP,MAAM,EACN,GAAG,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC,EACpC,SAAS,EACT,SAAS,sBAAsB;AAAA,EAClC,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,0BAA0B;AAAA,EAC1E,oBAAoB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,EAAE,EAAE,SAAS,uBAAuB;AACnG,CAAC,EACA;AAAA,EACC,CAAC,SAAS;AACR,QAAI,KAAK,aAAa,QAAQ;AAC5B,aAAO,KAAK,QAAQ,KAAK;AAAA,IAC3B;AACA,QAAI,KAAK,aAAa,UAAU;AAC9B,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,SAAS;AAAA,EACX;AACF;AAEK,IAAM,oBAAoB,EAC9B,OAAO;AAAA,EACN,UAAU,oBAAoB,QAAQ,QAAQ;AAAA,EAC9C,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,iCAAiC;AAAA,EAChF,WAAW,EAAE,OAAO,EAAE,QAAQ,eAAe,EAAE,SAAS,oBAAoB;AAAA,EAC5E,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS,oBAAoB;AAAA,EACtF,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,EAAE,SAAS,iBAAiB;AAAA,EACjF,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAI,EAAE,SAAS,mBAAmB;AAAA,EAC9E,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,uBAAuB;AAAA,EAC5E,cAAc,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,oBAAoB;AACxE,CAAC,EACA;AAAA,EACC,CAAC,SAAS;AACR,QAAI,KAAK,aAAa,UAAU;AAC9B,aAAO,KAAK;AAAA,IACd;AACA,WAAO;AAAA,EACT;AAAA,EACA;AAAA,IACE,SAAS;AAAA,EACX;AACF;AAMK,IAAM,oBAAoB,EAAE,OAAO;AAAA,EACxC,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,oCAAoC;AAAA,EAChF,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,EAAE,SAAS,wBAAwB;AAAA,EACzF,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAG,EAAE,SAAS,kBAAkB;AAAA,EACtF,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAI,EAAE,SAAS,qBAAqB;AAAA,EACzF,mBAAmB,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,gCAAgC;AAAA,EAChG,QAAQ,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,4BAA4B;AACzE,CAAC;AAEM,IAAM,6BAA6B,EAAE,OAAO;AAAA,EACjD,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,wBAAwB;AAAA,EACpE,kBAAkB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,QAAQ,CAAC,EAAE,SAAS,iCAAiC;AAAA,EACxG,cAAc,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,IAAI,GAAM,EAAE,QAAQ,GAAK,EAAE,SAAS,qBAAqB;AAAA,EAClG,kBAAkB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE,EAAE,QAAQ,CAAC,EAAE,SAAS,qCAAqC;AAAA,EAC3G,iBAAiB,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAK,EAAE,SAAS,+BAA+B;AAChH,CAAC;AAEM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,2BAA2B;AAAA,EACvE,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,GAAM,EAAE,QAAQ,GAAK,EAAE,SAAS,uBAAuB;AAAA,EAC9F,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,GAAM,EAAE,QAAQ,GAAK,EAAE,SAAS,4BAA4B;AAAA,EACpG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAI,EAAE,SAAS,yBAAyB;AAAA,EAC5F,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,GAAM,EAAE,QAAQ,GAAK,EAAE,SAAS,2BAA2B;AAAA,EAClG,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,IAAM,EAAE,QAAQ,GAAK,EAAE,SAAS,yBAAyB;AAAA,EAC9F,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAG,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAK,EAAE,SAAS,yBAAyB;AAC/F,CAAC;AAEM,IAAM,uBAAuB,EAAE,OAAO;AAAA,EAC3C,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,2BAA2B;AAAA,EACxE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAI,EAAE,QAAQ,EAAE,EAAE,SAAS,+BAA+B;AAAA,EACrG,WAAW,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAG,EAAE,SAAS,2BAA2B;AAAA,EAC/F,SAAS,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,GAAM,EAAE,QAAQ,GAAK,EAAE,SAAS,qBAAqB;AAC5F,CAAC;AAEM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,OAAO,kBAAkB,QAAQ,CAAC,CAAC;AAAA,EACnC,gBAAgB,2BAA2B,QAAQ,CAAC,CAAC;AAAA,EACrD,SAAS,oBAAoB,QAAQ,CAAC,CAAC;AAAA,EACvC,UAAU,qBAAqB,QAAQ,CAAC,CAAC;AAC3C,CAAC;AAMM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,OAAO,eAAe,QAAQ,MAAM,EAAE,SAAS,mBAAmB;AAAA,EAClE,QAAQ,EAAE,KAAK,CAAC,QAAQ,QAAQ,CAAC,EAAE,QAAQ,MAAM,EAAE,SAAS,mBAAmB;AAAA,EAC/E,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,2BAA2B;AAAA,EAChF,sBAAsB,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,gCAAgC;AAAA,EACzF,YAAY,EACT,MAAM,EAAE,OAAO,CAAC,EAChB,QAAQ,CAAC,YAAY,SAAS,UAAU,UAAU,eAAe,CAAC,EAClE,SAAS,0BAA0B;AACxC,CAAC;AAEM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,2BAA2B;AAAA,EACxE,QAAQ,EAAE,OAAO,EAAE,QAAQ,UAAU,EAAE,SAAS,oBAAoB;AAAA,EACpE,aAAa,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAC,EAAE,SAAS,8BAA8B;AAAA,EACrF,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,GAAI,EAAE,IAAI,GAAK,EAAE,QAAQ,GAAK,EAAE,SAAS,sBAAsB;AAAA,EACnG,kBAAkB,EACf,MAAM,EAAE,OAAO,CAAC,EAChB,QAAQ,CAAC,GAAG,IAAI,IAAI,IAAI,KAAK,KAAK,KAAK,KAAM,MAAM,KAAM,GAAK,CAAC,EAC/D,SAAS,mCAAmC;AACjD,CAAC;AAEM,IAAM,sBAAsB,EAAE,OAAO;AAAA,EAC1C,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,4BAA4B;AAAA,EACzE,UAAU,sBAAsB,QAAQ,MAAM,EAAE,SAAS,kBAAkB;AAAA,EAC3E,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yBAAyB;AAAA,EACrE,gBAAgB,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,iBAAiB;AAAA,EAChE,aAAa,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,wCAAwC;AAAA,EACpF,YAAY,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,qBAAqB;AAAA,EAC9E,kBAAkB,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,gDAAgD;AAAA,EACrG,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,wBAAwB;AAAA,EACvE,cAAc,EAAE,KAAK,CAAC,aAAa,aAAa,SAAS,CAAC,EAAE,QAAQ,WAAW,EAAE,SAAS,eAAe;AAC3G,CAAC;AAEM,IAAM,4BAA4B,EAAE,OAAO;AAAA,EAChD,SAAS,oBAAoB,QAAQ,CAAC,CAAC;AAAA,EACvC,SAAS,oBAAoB,QAAQ,CAAC,CAAC;AAAA,EACvC,SAAS,oBAAoB,QAAQ,CAAC,CAAC;AACzC,CAAC;AAMM,IAAM,yBAAyB,EAAE,OAAO;AAAA,EAC7C,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,yBAAyB;AAAA,EACrE,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI,EAAE,SAAS,2BAA2B;AAAA,EACvE,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK,EAAE,SAAS,2BAA2B;AAAA,EACxE,WAAW,EACR,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,IAAI;AAAA,IACjC,aAAa,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAI;AAAA,EACnD,CAAC,EACA,QAAQ,CAAC,CAAC;AAAA,EACb,OAAO,EACJ,OAAO;AAAA,IACN,SAAS,EAAE,QAAQ,EAAE,QAAQ,KAAK;AAAA,IAClC,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,QAAQ,GAAG;AAAA,EACjD,CAAC,EACA,QAAQ,CAAC,CAAC;AACf,CAAC;AAMM,IAAM,uBAAuB,EAAE,OAAO;AAAA;AAAA,EAE3C,UAAU,qBAAqB,QAAQ,EAAE,UAAU,SAAS,CAAC;AAAA,EAC7D,OAAO,kBAAkB,QAAQ,EAAE,UAAU,SAAS,CAAC;AAAA,EACvD,SAAS,oBAAoB,QAAQ,EAAE,UAAU,SAAS,CAAC;AAAA,EAC3D,OAAO,kBAAkB,QAAQ,EAAE,UAAU,SAAS,CAAC;AAAA,EACvD,OAAO,kBAAkB,QAAQ,EAAE,UAAU,SAAS,CAAC;AAAA;AAAA,EAGvD,YAAY,uBAAuB,QAAQ,CAAC,CAAC;AAAA;AAAA,EAG7C,eAAe,0BAA0B,QAAQ,CAAC,CAAC;AAAA;AAAA,EAGnD,YAAY,uBAAuB,QAAQ,CAAC,CAAC;AAC/C,CAAC;AAoBM,SAAS,aAA6B;AAC3C,SAAO,qBAAqB,MAAM;AAAA,IAChC,UAAU;AAAA,MACR,UAAU,QAAQ,IAAI,wBAAwB,QAAQ,IAAI,qBAAqB;AAAA,MAC/E,KAAK,QAAQ,IAAI;AAAA,MACjB,aAAa,QAAQ,IAAI;AAAA,MACzB,iBAAiB,QAAQ,IAAI;AAAA,MAC7B,wBAAwB,QAAQ,IAAI;AAAA,MACpC,UAAU,QAAQ,IAAI,qBAAqB,SAAS,QAAQ,IAAI,kBAAkB,IAAI;AAAA,MACtF,mBAAmB,QAAQ,IAAI,mBAAmB,SAAS,QAAQ,IAAI,gBAAgB,IAAI;AAAA,IAC7F;AAAA,IACA,OAAO;AAAA,MACL,UAAU,QAAQ,IAAI,2BAA2B,QAAQ,IAAI,kBAAkB;AAAA,MAC/E,KAAK,QAAQ,IAAI;AAAA,MACjB,YAAY,QAAQ,IAAI;AAAA,MACxB,cAAc,QAAQ,IAAI;AAAA,MAC1B,YAAY,QAAQ,IAAI,oBAAoB,SAAS,QAAQ,IAAI,iBAAiB,IAAI;AAAA,MACtF,WAAW,QAAQ,IAAI;AAAA,IACzB;AAAA,IACA,SAAS;AAAA,MACP,UAAU,QAAQ,IAAI,6BAA6B,QAAQ,IAAI,oBAAoB;AAAA,MACnF,UAAU,QAAQ,IAAI;AAAA,MACtB,QAAQ,QAAQ,IAAI,aAAa,QAAQ,IAAI,cAAc;AAAA,MAC3D,WAAW,QAAQ,IAAI,oBAAoB,QAAQ,IAAI;AAAA,MACvD,WAAW,QAAQ,IAAI,wBAAwB,QAAQ,IAAI;AAAA,MAC3D,QAAQ,QAAQ,IAAI;AAAA,MACpB,WAAW,QAAQ,IAAI;AAAA,MACvB,gBAAgB,QAAQ,IAAI,wBAAwB;AAAA,MACpD,iBAAiB,QAAQ,IAAI,uBAAuB,SAAS,QAAQ,IAAI,oBAAoB,IAAI;AAAA,IACnG;AAAA,IACA,OAAO;AAAA,MACL,UAAU,QAAQ,IAAI,2BAA2B,QAAQ,IAAI,kBAAkB;AAAA,MAC/E,MAAM,QAAQ,IAAI;AAAA,MAClB,MAAM,QAAQ,IAAI,YAAY,SAAS,QAAQ,IAAI,SAAS,IAAI;AAAA,MAChE,QAAQ,QAAQ,IAAI,gBAAgB;AAAA,MACpC,UAAU,QAAQ,IAAI;AAAA,MACtB,UAAU,QAAQ,IAAI;AAAA,MACtB,QAAQ,QAAQ,IAAI;AAAA,MACpB,MAAM,QAAQ,IAAI;AAAA,MAClB,SAAS,QAAQ,IAAI;AAAA,IACvB;AAAA,IACA,OAAO;AAAA,MACL,UAAU,QAAQ,IAAI,2BAA2B,QAAQ,IAAI,kBAAkB;AAAA,MAC/E,UAAU,QAAQ,IAAI;AAAA,MACtB,WAAW,QAAQ,IAAI;AAAA,MACvB,aAAa,QAAQ,IAAI,oBAAoB,SAAS,QAAQ,IAAI,iBAAiB,IAAI;AAAA,MACvF,YAAY,QAAQ,IAAI,oBAAoB,SAAS,QAAQ,IAAI,iBAAiB,IAAI;AAAA,IACxF;AAAA,IACA,YAAY;AAAA,MACV,OAAO;AAAA,QACL,SAAS,QAAQ,IAAI,6BAA6B;AAAA,QAClD,aAAa,QAAQ,IAAI,gCACrB,SAAS,QAAQ,IAAI,6BAA6B,IAClD;AAAA,QACJ,WAAW,QAAQ,IAAI,8BACnB,SAAS,QAAQ,IAAI,2BAA2B,IAChD;AAAA,QACJ,UAAU,QAAQ,IAAI,6BAClB,SAAS,QAAQ,IAAI,0BAA0B,IAC/C;AAAA,MACN;AAAA,MACA,gBAAgB;AAAA,QACd,SAAS,QAAQ,IAAI,uCAAuC;AAAA,QAC5D,kBAAkB,QAAQ,IAAI,uCAC1B,SAAS,QAAQ,IAAI,oCAAoC,IACzD;AAAA,QACJ,cAAc,QAAQ,IAAI,2CACtB,SAAS,QAAQ,IAAI,wCAAwC,IAC7D;AAAA,MACN;AAAA,MACA,SAAS;AAAA,QACP,SAAS,QAAQ,IAAI,+BAA+B;AAAA,QACpD,SAAS,QAAQ,IAAI,6BACjB,SAAS,QAAQ,IAAI,0BAA0B,IAC/C;AAAA,MACN;AAAA,IACF;AAAA,IACA,eAAe;AAAA,MACb,SAAS;AAAA,QACP,OAAQ,QAAQ,IAAI,aAAqD;AAAA,QACzE,QAAS,QAAQ,IAAI,cAAoC;AAAA,MAC3D;AAAA,MACA,SAAS;AAAA,QACP,SAAS,QAAQ,IAAI,oBAAoB;AAAA,QACzC,QAAQ,QAAQ,IAAI;AAAA,MACtB;AAAA,MACA,SAAS;AAAA,QACP,SAAS,QAAQ,IAAI,oBAAoB;AAAA,QACzC,UAAW,QAAQ,IAAI,oBAAmD;AAAA,QAC1E,aAAa,QAAQ,IAAI,gBAAgB,QAAQ,IAAI;AAAA,QACrD,gBAAgB,QAAQ,IAAI;AAAA,QAC5B,aAAa,QAAQ,IAAI;AAAA,QACzB,YAAY,QAAQ,IAAI,sBAAsB,WAAW,QAAQ,IAAI,mBAAmB,IAAI;AAAA,QAC5F,UAAU,QAAQ,IAAI,+BAA+B,QAAQ,IAAI;AAAA,QACjE,cAAe,QAAQ,IAAI,sBAAgE;AAAA,MAC7F;AAAA,IACF;AAAA,IACA,YAAY;AAAA,MACV,SAAS,QAAQ,IAAI,uBAAuB;AAAA,MAC5C,SAAS,QAAQ,IAAI,uBAAuB;AAAA,MAC5C,SAAS,QAAQ,IAAI,uBAAuB;AAAA,MAC5C,WAAW;AAAA,QACT,SAAS,QAAQ,IAAI,0BAA0B;AAAA,QAC/C,aAAa,QAAQ,IAAI,kCACrB,SAAS,QAAQ,IAAI,+BAA+B,IACpD;AAAA,MACN;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAMO,SAAS,eAAe,QAAiC;AAC9D,SAAO,qBAAqB,MAAM,MAAM;AAC1C;AAKO,SAAS,mBAAmB,QAIjC;AACA,QAAM,SAAS,qBAAqB,UAAU,MAAM;AACpD,MAAI,OAAO,SAAS;AAClB,WAAO,EAAE,SAAS,MAAM,MAAM,OAAO,KAAK;AAAA,EAC5C;AACA,SAAO,EAAE,SAAS,OAAO,QAAQ,OAAO,MAAM;AAChD;AAKO,SAAS,mBAAmC;AACjD,SAAO,qBAAqB,MAAM,CAAC,CAAC;AACtC;;;ACtbO,IAAM,iBAAN,MAA0C;AAAA,EACvC,SAAiC,oBAAI,IAAI;AAAA,EAEjD,KAAkB,OAAiC;AACjD,QAAI,CAAC,KAAK,OAAO,IAAI,KAAK,GAAG;AAC3B,WAAK,OAAO,IAAI,OAAO,CAAC,CAAC;AAAA,IAC3B;AACA,WAAO,IAAI,mBAAsB,KAAK,QAAQ,KAAK;AAAA,EACrD;AAAA,EAEA,MAAM,IAAiB,KAAa,QAA6C;AAE/E,YAAQ,KAAK,+CAA+C;AAC5D,WAAO,EAAE,MAAM,CAAC,EAAE;AAAA,EACpB;AAAA,EAEA,MAAM,YAAe,IAA+C;AAElE,WAAO,GAAG,IAAI;AAAA,EAChB;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,OAAO,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,SAAsB,WAAwB;AAC5C,WAAQ,KAAK,OAAO,IAAI,SAAS,KAAa,CAAC;AAAA,EACjD;AACF;AAEA,IAAM,qBAAN,MAAkE;AAAA,EACxD;AAAA,EACA;AAAA,EACA,UAAoB,CAAC,GAAG;AAAA,EACxB,SAAsE,CAAC;AAAA,EACvE,WAAiE;AAAA,EACjE,SAAwB;AAAA,EACxB,UAAkB;AAAA,EAClB,cAAmC;AAAA,EACnC,cAAiC;AAAA,EACjC,cAAuB;AAAA,EAE/B,YAAY,QAAgC,WAAmB;AAC7D,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,OAAO,SAA+C;AACpD,QAAI,SAAS;AACX,WAAK,UAAU,MAAM,QAAQ,OAAO,IAAI,UAAU,CAAC,OAAO;AAAA,IAC5D;AACA,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,MAAmD;AACxD,SAAK,cAAc,MAAM,QAAQ,IAAI,IAAI,OAAO,CAAC,IAAI;AACrD,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,MAAoC;AACzC,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,SAA2B;AACzB,SAAK,cAAc;AACnB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAgB,UAAkB,OAAkC;AACxE,SAAK,OAAO,KAAK,EAAE,QAAQ,UAAU,MAAM,CAAC;AAC5C,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,QAAgB,QAAqC;AAC3D,SAAK,OAAO,KAAK,EAAE,QAAQ,UAAU,MAAM,OAAO,OAAO,CAAC;AAC1D,WAAO;AAAA,EACT;AAAA,EAEA,QAAQ,QAAgB,YAA4B,OAAyB;AAC3E,SAAK,WAAW,EAAE,QAAQ,UAAU;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAiC;AACrC,SAAK,SAAS;AACd,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,OAAiC;AACtC,SAAK,UAAU;AACf,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAqD;AACzD,UAAM,SAAS,MAAM,KAAK,QAAQ;AAClC,WAAO,EAAE,MAAM,OAAO,KAAK,CAAC,KAAK,KAAK;AAAA,EACxC;AAAA,EAEA,MAAM,UAAmC;AACvC,UAAM,QAAQ,KAAK,OAAO,IAAI,KAAK,SAAS,KAAY,CAAC;AAGzD,QAAI,KAAK,aAAa;AACpB,YAAM,WAAW,KAAK,YAAY,IAAI,CAAC,MAAM,OAAO;AAAA,QAClD,IAAI,OAAO,KAAK,IAAI,CAAC,IAAI,CAAC;AAAA,QAC1B,GAAG;AAAA,QACH,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,MACrC,EAAE;AACF,WAAK,OAAO,IAAI,KAAK,WAAW,CAAC,GAAG,OAAO,GAAG,QAAQ,CAAC;AACvD,aAAO,EAAE,MAAM,SAAgB;AAAA,IACjC;AAGA,QAAI,KAAK,aAAa;AACpB,YAAM,WAAW,MAAM,OAAO,UAAQ,CAAC,KAAK,aAAa,IAAI,CAAC;AAC9D,YAAM,UAAU,MAAM,OAAO,UAAQ,KAAK,aAAa,IAAI,CAAC;AAC5D,WAAK,OAAO,IAAI,KAAK,WAAW,QAAQ;AACxC,aAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,OAAO;AAAA,IAChD;AAGA,QAAI,KAAK,aAAa;AACpB,YAAM,UAAe,CAAC;AACtB,YAAM,WAAW,MAAM,IAAI,UAAQ;AACjC,YAAI,KAAK,aAAa,IAAI,GAAG;AAC3B,gBAAM,cAAc,EAAE,GAAG,MAAM,GAAG,KAAK,aAAa,aAAY,oBAAI,KAAK,GAAE,YAAY,EAAE;AACzF,kBAAQ,KAAK,WAAgB;AAC7B,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MACT,CAAC;AACD,WAAK,OAAO,IAAI,KAAK,WAAW,QAAQ;AACxC,aAAO,EAAE,MAAM,SAAS,OAAO,QAAQ,OAAO;AAAA,IAChD;AAGA,QAAI,SAAS,MAAM,OAAO,UAAQ,KAAK,aAAa,IAAI,CAAC;AAGzD,QAAI,KAAK,UAAU;AACjB,YAAM,EAAE,QAAQ,UAAU,IAAI,KAAK;AACnC,aAAO,KAAK,CAAC,GAAG,MAAM;AACpB,cAAM,OAAQ,EAA8B,MAAM;AAClD,cAAM,OAAQ,EAA8B,MAAM;AAClD,YAAI,SAAS,QAAQ,SAAS,OAAW,QAAO,cAAc,QAAQ,IAAI;AAC1E,YAAI,SAAS,QAAQ,SAAS,OAAW,QAAO,cAAc,QAAQ,KAAK;AAC3E,cAAM,MAAM,OAAO,OAAO,KAAK,OAAO,OAAO,IAAI;AACjD,eAAO,cAAc,QAAQ,MAAM,CAAC;AAAA,MACtC,CAAC;AAAA,IACH;AAGA,QAAI,KAAK,UAAU,KAAK,KAAK,WAAW,MAAM;AAC5C,YAAM,QAAQ,KAAK;AACnB,YAAM,MAAM,KAAK,WAAW,OAAO,QAAQ,KAAK,SAAS;AACzD,eAAS,OAAO,MAAM,OAAO,GAAG;AAAA,IAClC;AAEA,WAAO,EAAE,MAAM,QAAQ,OAAO,OAAO,OAAO;AAAA,EAC9C;AAAA,EAEQ,aAAa,MAAkB;AACrC,QAAI,KAAK,OAAO,WAAW,EAAG,QAAO;AAErC,WAAO,KAAK,OAAO,MAAM,CAAC,EAAE,QAAQ,UAAU,MAAM,MAAM;AACxD,YAAM,YAAa,KAAiC,MAAM;AAE1D,cAAQ,UAAU;AAAA,QAChB,KAAK;AAAA,QACL,KAAK;AACH,iBAAO,cAAc;AAAA,QACvB,KAAK;AAAA,QACL,KAAK;AACH,iBAAO,cAAc;AAAA,QACvB,KAAK;AACH,iBAAQ,YAAwB;AAAA,QAClC,KAAK;AACH,iBAAQ,aAAyB;AAAA,QACnC,KAAK;AACH,iBAAQ,YAAwB;AAAA,QAClC,KAAK;AACH,iBAAQ,aAAyB;AAAA,QACnC,KAAK;AACH,iBAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,SAAS,SAAS;AAAA,QACzD,KAAK;AACH,iBAAO,OAAO,SAAS,EAAE,SAAS,OAAO,KAAK,EAAE,QAAQ,MAAM,EAAE,CAAC;AAAA,QACnE;AACE,iBAAO,cAAc;AAAA,MACzB;AAAA,IACF,CAAC;AAAA,EACH;AACF;;;ACzMO,IAAM,cAAN,MAAoC;AAAA,EACjC,QAA0C,oBAAI,IAAI;AAAA,EAClD,gBAA6D,oBAAI,IAAI;AAAA,EAE7E,MAAM,IAAiB,KAAgC;AACrD,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,MAAM,aAAa,KAAK,IAAI,IAAI,MAAM,WAAW;AACnD,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AAAA,EACf;AAAA,EAEA,MAAM,IAAiB,KAAa,OAAU,KAA6B;AACzE,UAAM,YAAY,MAAM,KAAK,IAAI,IAAI,MAAM,MAAO;AAClD,SAAK,MAAM,IAAI,KAAK,EAAE,OAAO,UAAU,CAAC;AAAA,EAC1C;AAAA,EAEA,MAAM,OAAO,KAA4B;AACvC,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA,EAEA,MAAM,OAAO,KAA+B;AAC1C,UAAM,QAAQ,MAAM,KAAK,IAAI,GAAG;AAChC,WAAO,UAAU;AAAA,EACnB;AAAA,EAEA,MAAM,cAAc,SAAkC;AACpD,UAAM,QAAQ,IAAI,OAAO,MAAM,QAAQ,QAAQ,OAAO,IAAI,IAAI,GAAG;AACjE,QAAI,QAAQ;AAEZ,eAAW,OAAO,KAAK,MAAM,KAAK,GAAG;AACnC,UAAI,MAAM,KAAK,GAAG,GAAG;AACnB,aAAK,MAAM,OAAO,GAAG;AACrB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,KAAkB,MAAuC;AAC7D,WAAO,QAAQ,IAAI,KAAK,IAAI,SAAO,KAAK,IAAO,GAAG,CAAC,CAAC;AAAA,EACtD;AAAA,EAEA,MAAM,KAAkB,SAAwE;AAC9F,UAAM,QAAQ,IAAI,QAAQ,IAAI,CAAC,EAAE,KAAK,OAAO,IAAI,MAAM,KAAK,IAAI,KAAK,OAAO,GAAG,CAAC,CAAC;AAAA,EACnF;AAAA,EAEA,MAAM,KAAK,KAAa,KAAa,GAAoB;AACvD,UAAM,UAAU,MAAM,KAAK,IAAY,GAAG,KAAK;AAC/C,UAAM,WAAW,UAAU;AAC3B,UAAM,KAAK,IAAI,KAAK,QAAQ;AAC5B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAQ,SAAiB,SAAgC;AAC7D,UAAM,cAAc,KAAK,cAAc,IAAI,OAAO;AAClD,QAAI,aAAa;AACf,kBAAY,QAAQ,cAAY,SAAS,OAAO,CAAC;AAAA,IACnD;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,SAAiB,UAA0D;AACzF,QAAI,CAAC,KAAK,cAAc,IAAI,OAAO,GAAG;AACpC,WAAK,cAAc,IAAI,SAAS,oBAAI,IAAI,CAAC;AAAA,IAC3C;AAEA,SAAK,cAAc,IAAI,OAAO,EAAG,IAAI,QAAQ;AAE7C,WAAO,MAAM;AACX,WAAK,cAAc,IAAI,OAAO,GAAG,OAAO,QAAQ;AAAA,IAClD;AAAA,EACF;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,MAAM,MAAM;AACjB,SAAK,cAAc,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,MAAM,MAAM;AACjB,SAAK,cAAc,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;;;AC9GO,IAAM,gBAAN,MAAwC;AAAA,EACrC,QAAQ,oBAAI,IAAoD;AAAA,EAExE,MAAM,OAAO,KAAa,MAAsC,SAAyB;AACvF,SAAK,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,KAAK,MAAM,GAAG,aAAa,SAAS,YAAY,CAAC;AACpF,WAAO,EAAE,KAAK,cAAc,IAAI;AAAA,EAClC;AAAA,EACA,MAAM,SAAS,KAAa;AAAE,WAAO,KAAK,MAAM,IAAI,GAAG,GAAG,QAAQ,OAAO,KAAK,EAAE;AAAA,EAAG;AAAA,EACnF,MAAM,aAAa,KAAa;AAAE,WAAO,cAAc;AAAA,EAAK;AAAA,EAC5D,MAAM,OAAO,KAAa;AAAE,SAAK,MAAM,OAAO,GAAG;AAAA,EAAG;AAAA,EACpD,MAAM,WAAW,MAAgB;AAAE,SAAK,QAAQ,OAAK,KAAK,MAAM,OAAO,CAAC,CAAC;AAAA,EAAG;AAAA,EAC5E,MAAM,KAAK,QAAyC;AAAE,WAAO,CAAC;AAAA,EAAG;AAAA,EACjE,MAAM,OAAO,KAAa;AAAE,WAAO,KAAK,MAAM,IAAI,GAAG;AAAA,EAAG;AAAA,EACxD,MAAM,YAAY,KAAa;AAAE,WAAO;AAAA,EAAM;AAAA,EAC9C,MAAM,cAAc;AAAE,WAAO;AAAA,EAAM;AAAA;AAAA;AAAA;AAAA,EAKnC,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;;;AC7BO,IAAM,cAAN,MAAoC;AAAA,EACjC,aAA6B,CAAC;AAAA,EAEtC,MAAM,KAAK,SAA6C;AACtD,SAAK,WAAW,KAAK,OAAO;AAC5B,WAAO,EAAE,IAAI,SAAS,KAAK,WAAW,QAAQ,SAAS,KAAK;AAAA,EAC9D;AAAA,EAEA,MAAM,UAAU,UAAkD;AAChE,WAAO,QAAQ,IAAI,SAAS,IAAI,OAAK,KAAK,KAAK,CAAC,CAAC,CAAC;AAAA,EACpD;AAAA,EAEA,MAAM,cAAc;AAAE,WAAO;AAAA,EAAM;AAAA;AAAA,EAGnC,gBAAgC;AAAE,WAAO,KAAK;AAAA,EAAY;AAAA;AAAA;AAAA;AAAA,EAK1D,QAAc;AACZ,SAAK,aAAa,CAAC;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,WAAW;AAAA,EACzB;AACF;;;ACrBA,SAAS,yBAAyB;AAoClC,IAAM,4BAAN,MAAgC;AAAA,EACtB,UAAU,IAAI,kBAAmC;AAAA,EACjD;AAAA,EAER,cAAc;AAEZ,SAAK,cAAc,MAAM;AACvB,YAAM,YAAY,KAAK,IAAI,EAAE,SAAS,EAAE;AACxC,YAAM,SAAS,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,EAAE;AACzD,aAAO,GAAG,SAAS,IAAI,MAAM;AAAA,IAC/B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,WAA+B;AAC5C,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqB;AACnB,WAAO,KAAK,YAAY;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,IAAO,MAAuB,IAAgB;AAC5C,WAAO,KAAK,QAAQ;AAAA,MAClB;AAAA,QACE,GAAG;AAAA,QACH,WAAW,KAAK,aAAa,KAAK,IAAI;AAAA,MACxC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAY,MAAuB,IAAkC;AACzE,WAAO,KAAK,QAAQ;AAAA,MAClB;AAAA,QACE,GAAG;AAAA,QACH,WAAW,KAAK,aAAa,KAAK,IAAI;AAAA,MACxC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAmC;AACjC,WAAO,KAAK,QAAQ,SAAS;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,aAA8B;AAC5B,WAAO,KAAK,QAAQ,SAAS,KAAK,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,aAAiC;AAC/B,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAuC;AACrC,WAAO,KAAK,IAAI,GAAG,iBAAiB,KAAK,IAAI,GAAG;AAAA,EAClD;AAAA;AAAA;AAAA;AAAA,EAKA,eAAmC;AACjC,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAgC;AAC9B,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAkC;AAChC,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,QAAQ,SAAS,MAAM;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAO,MAAiD;AACtD,UAAM,UAAU,KAAK,IAAI,KAAK,CAAC;AAC/B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,GAAG;AAAA,MACH,UAAU;AAAA,QACR,GAAG,QAAQ;AAAA,QACX,GAAG,KAAK;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,UAAa,MAAgC,IAAgB;AAC3D,WAAO,KAAK,IAAI,KAAK,OAAO,IAAI,GAAG,EAAE;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAkB,MAAgC,IAAkC;AACxF,WAAO,KAAK,SAAS,KAAK,OAAO,IAAI,GAAG,EAAE;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAKA,aAAsC;AACpC,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,IAAK,QAAO,CAAC;AAElB,UAAM,OAAgC,CAAC;AAEvC,QAAI,IAAI,QAAS,MAAK,UAAU,IAAI;AACpC,QAAI,IAAI,OAAQ,MAAK,SAAS,IAAI;AAClC,QAAI,IAAI,UAAW,MAAK,YAAY,IAAI;AACxC,QAAI,IAAI,cAAe,MAAK,gBAAgB,IAAI;AAChD,QAAI,IAAI,OAAQ,MAAK,SAAS,IAAI;AAClC,QAAI,IAAI,SAAU,MAAK,WAAW,IAAI;AACtC,QAAI,IAAI,UAAW,MAAK,YAAY,IAAI;AACxC,QAAI,IAAI,UAAW,MAAK,YAAY,IAAI;AAExC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqC;AACnC,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,IAAK,QAAO,CAAC;AAElB,UAAM,UAAkC,CAAC;AAEzC,QAAI,IAAI,SAAS;AAEf,YAAM,SAAS,IAAI,UAAU,KAAK,WAAW,EAAE,UAAU,GAAG,EAAE;AAC9D,cAAQ,aAAa,IAAI,MAAM,IAAI,OAAO,IAAI,MAAM;AAAA,IACtD;AAEA,QAAI,IAAI,WAAW;AACjB,cAAQ,cAAc,IAAI,IAAI;AAAA,IAChC;AAEA,QAAI,IAAI,eAAe;AACrB,cAAQ,kBAAkB,IAAI,IAAI;AAAA,IACpC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAyE;AACpF,UAAM,OAAwB,CAAC;AAG/B,UAAM,cAAc,QAAQ,aAAa;AACzC,QAAI,eAAe,OAAO,gBAAgB,UAAU;AAClD,YAAM,QAAQ,YAAY,MAAM,GAAG;AACnC,UAAI,MAAM,UAAU,KAAK,MAAM,CAAC,MAAM,MAAM;AAC1C,aAAK,UAAU,MAAM,CAAC;AACtB,aAAK,SAAS,MAAM,CAAC;AAAA,MACvB;AAAA,IACF;AAGA,UAAM,YAAY,QAAQ,cAAc;AACxC,QAAI,WAAW;AACb,WAAK,YAAY,MAAM,QAAQ,SAAS,IAAI,UAAU,CAAC,IAAI;AAAA,IAC7D;AAGA,UAAM,gBAAgB,QAAQ,kBAAkB;AAChD,QAAI,eAAe;AACjB,WAAK,gBAAgB,MAAM,QAAQ,aAAa,IAAI,cAAc,CAAC,IAAI;AAAA,IACzE;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,aAAqB;AACnB,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,KAAK,UAAW,QAAO;AAC5B,WAAO,KAAK,IAAI,IAAI,IAAI;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,WAAoC;AAClD,UAAM,UAAU,KAAK,IAAI,KAAK,CAAC;AAC/B,WAAO;AAAA,MACL,GAAG;AAAA,MACH,QAAQ,KAAK,WAAW,EAAE,UAAU,GAAG,EAAE;AAAA,MACzC;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AAAA,EACF;AACF;AASO,IAAM,qBAAqB,IAAI,0BAA0B;AAGzD,IAAM,iBAAiB,mBAAmB,IAAI,KAAK,kBAAkB;AACrE,IAAM,sBAAsB,mBAAmB,SAAS,KAAK,kBAAkB;AAC/E,IAAM,aAAa,mBAAmB,IAAI,KAAK,kBAAkB;AACjE,IAAM,aAAa,mBAAmB,WAAW,KAAK,kBAAkB;AACxE,IAAM,mBAAmB,mBAAmB,iBAAiB,KAAK,kBAAkB;AACpF,IAAM,eAAe,mBAAmB,aAAa,KAAK,kBAAkB;AAC5E,IAAM,YAAY,mBAAmB,UAAU,KAAK,kBAAkB;AACtE,IAAM,cAAc,mBAAmB,YAAY,KAAK,kBAAkB;AAC1E,IAAM,aAAa,mBAAmB,WAAW,KAAK,kBAAkB;AACxE,IAAM,cAAc,mBAAmB,YAAY,KAAK,kBAAkB;AAS1E,SAAS,qBACd,SACA,SAOiB;AACjB,QAAM,SAAS,mBAAmB,aAAa,OAAO;AAEtD,SAAO;AAAA,IACL,GAAG;AAAA,IACH,SAAS,OAAO,YAAY,SAAS,kBAAkB,mBAAmB,WAAW,IAAI;AAAA,IACzF,WAAW,OAAO,cAAc,SAAS,oBAAoB,mBAAmB,WAAW,IAAI;AAAA,IAC/F,WAAW,SAAS;AAAA,IACpB,QAAQ,SAAS;AAAA,IACjB,UAAU,SAAS;AAAA,IACnB,WAAW,KAAK,IAAI;AAAA,EACtB;AACF;AAKO,SAAS,iBAAiB,KAKb;AAClB,SAAO;AAAA,IACL,eAAe,IAAI,iBAAiB,IAAI;AAAA,IACxC,SAAS,mBAAmB,WAAW;AAAA,IACvC,WAAW,OAAO,IAAI,IAAI;AAAA,IAC1B,UAAU,IAAI;AAAA,IACd,WAAW,KAAK,IAAI;AAAA,EACtB;AACF;AAKO,SAAS,gBACd,IACAG,aAC6B;AAC7B,SAAO,IAAI,SAAgB;AACzB,UAAM,MAAMA,YAAW,GAAG,IAAI;AAC9B,WAAO,mBAAmB,IAAI,KAAK,MAAM,GAAG,GAAG,IAAI,CAAC;AAAA,EACtD;AACF;AAKO,SAAS,qBACd,IACAA,aACsC;AACtC,SAAO,UAAU,SAAgB;AAC/B,UAAM,MAAMA,YAAW,GAAG,IAAI;AAC9B,WAAO,mBAAmB,SAAS,KAAK,MAAM,GAAG,GAAG,IAAI,CAAC;AAAA,EAC3D;AACF;;;AC9VO,IAAM,cAAN,MAAoD;AAAA,EACjD,OAAoC,oBAAI,IAAI;AAAA,EAC5C,WAAqD,CAAC;AAAA,EACtD,gBAA4D,oBAAI,IAAI;AAAA,EACpE,SAAS;AAAA,EACT,wBAAwB;AAAA,EACxB,cAAc;AAAA,EACd,kBAA+C,oBAAI,IAAI;AAAA,EACvD;AAAA,EACA,kBAA4B,CAAC;AAAA,EAC7B,eAAe;AAAA,EAEvB,YAAY,OAAe,WAAW;AACpC,SAAK,YAAY;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,MAAc,MAAS,SAAuC;AACtE,UAAM,QAAQ,SAAS,SAAS,cAAc;AAC9C,UAAM,MAAM,KAAK,IAAI;AAErB,UAAM,MAAsB;AAAA,MAC1B,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,cAAc;AAAA,MACd,UAAU;AAAA,MACV,WAAW;AAAA,MACX,OAAO,SAAS,QAAQ,YAAY;AAAA,MACpC,eAAe,SAAS;AAAA,MACxB,UAAU,SAAS;AAAA,MACnB;AAAA,IACF;AAEA,SAAK,KAAK,IAAI,OAAO,GAAG;AAGxB,QAAI,SAAS,SAAS,QAAQ,QAAQ,GAAG;AACvC,iBAAW,MAAM;AACf,cAAM,IAAI,KAAK,KAAK,IAAI,KAAK;AAC7B,YAAI,KAAK,EAAE,UAAU,WAAW;AAC9B,YAAE,QAAQ;AACV,eAAK,YAAY;AAAA,QACnB;AAAA,MACF,GAAG,QAAQ,KAAK;AAAA,IAClB,OAAO;AACL,WAAK,YAAY;AAAA,IACnB;AAEA,WAAO,KAAK,YAAY,GAAG;AAAA,EAC7B;AAAA,EAEA,MAAM,QACJ,MACmB;AACnB,WAAO,QAAQ,IAAI,KAAK,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;AAAA,EACzE;AAAA,EAEA,QACE,SACA,SACM;AACN,SAAK,SAAS,KAAK,OAAO;AAC1B,QAAI,SAAS,aAAa;AACxB,WAAK,wBAAwB,QAAQ;AAAA,IACvC;AACA,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,OAAO,IAAoC;AAC/C,UAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAC5B,WAAO,MAAM,KAAK,YAAY,GAAG,IAAI;AAAA,EACvC;AAAA,EAEA,MAAM,UAAU,IAA2B;AACzC,SAAK,KAAK,OAAO,EAAE;AAAA,EACrB;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,SAAS;AAAA,EAChB;AAAA,EAEA,MAAM,SAAwB;AAC5B,SAAK,SAAS;AACd,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,WAAgC;AACpC,UAAM,QAAoB;AAAA,MACxB,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAEA,eAAW,OAAO,KAAK,KAAK,OAAO,GAAG;AACpC,cAAQ,IAAI,OAAO;AAAA,QACjB,KAAK;AACH,gBAAM;AACN;AAAA,QACF,KAAK;AACH,gBAAM;AACN;AAAA,QACF,KAAK;AACH,gBAAM;AACN;AAAA,QACF,KAAK;AACH,gBAAM;AACN;AAAA,QACF,KAAK;AACH,gBAAM;AACN;AAAA,MACJ;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAE3B,eAAW,YAAY,KAAK,gBAAgB,OAAO,GAAG;AACpD,oBAAc,QAAQ;AAAA,IACxB;AACA,SAAK,gBAAgB,MAAM;AAC3B,SAAK,KAAK,MAAM;AAChB,SAAK,WAAW,CAAC;AACjB,SAAK,cAAc,MAAM;AACzB,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,aACJ,MACA,MACA,QACA,SACiB;AACjB,UAAM,YAAY,UAAU,IAAI,IAAI,KAAK,IAAI,CAAC;AAG9C,UAAM,MAAM,MAAM,KAAK,IAAI,MAAM,MAAM,EAAE,GAAG,SAAS,OAAO,UAAU,CAAC;AACvE,UAAM,cAAc,KAAK,KAAK,IAAI,SAAS;AAC3C,QAAI,aAAa;AACf,kBAAY,YAAY;AAAA,IAC1B;AAGA,QAAI,OAAO,OAAO;AAChB,UAAI,YAAY;AAChB,YAAM,WAAW,YAAY,YAAY;AACvC,YAAI,OAAO,SAAS,aAAa,OAAO,OAAO;AAC7C,wBAAc,QAAQ;AACtB,eAAK,gBAAgB,OAAO,SAAS;AACrC;AAAA,QACF;AACA;AACA,cAAM,KAAK,IAAI,MAAM,MAAM,OAAO;AAAA,MACpC,GAAG,OAAO,KAAK;AAEf,WAAK,gBAAgB,IAAI,WAAW,QAAQ;AAAA,IAC9C;AAIA,QAAI,OAAO,MAAM;AACf,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QACJ,OACA,QAAgB,GAChB,MAAc,IACK;AACnB,UAAM,SAAS,MAAM,QAAQ,KAAK,IAAI,QAAQ,CAAC,KAAK;AACpD,UAAM,WAAW,MAAM,KAAK,KAAK,KAAK,OAAO,CAAC,EAC3C,OAAO,CAAC,MAAM,OAAO,SAAS,EAAE,SAAS,SAAS,CAAC,EACnD,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAE3C,UAAM,WAAW,QAAQ,KAAK,SAAS,SAAS,MAAM;AACtD,WAAO,SAAS,MAAM,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAAA,EACvE;AAAA,EAEA,MAAM,cAAc,QAAgB,GAAG,MAAc,IAAuB;AAC1E,WAAO,KAAK,QAAQ,UAAU,OAAO,GAAG;AAAA,EAC1C;AAAA,EAEA,MAAM,SAAS,IAA2B;AACxC,UAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAC5B,QAAI,CAAC,OAAO,IAAI,UAAU,UAAU;AAClC;AAAA,IACF;AAEA,QAAI,QAAQ;AACZ,QAAI,eAAe;AACnB,QAAI,eAAe;AACnB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,MAAM,kBAAmC;AACvC,UAAM,aAAa,MAAM,KAAK,KAAK,KAAK,OAAO,CAAC,EAAE;AAAA,MAChD,CAAC,MAAM,EAAE,UAAU;AAAA,IACrB;AAEA,eAAW,OAAO,YAAY;AAC5B,UAAI,QAAQ;AACZ,UAAI,eAAe;AACnB,UAAI,eAAe;AAAA,IACrB;AAEA,SAAK,YAAY;AACjB,WAAO,WAAW;AAAA,EACpB;AAAA,EAEA,MAAM,eAAe,IAAY,UAAiC;AAChE,UAAM,MAAM,KAAK,KAAK,IAAI,EAAE;AAC5B,QAAI,KAAK;AACP,UAAI,WAAW,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,QAAQ,CAAC;AAClD,WAAK,UAAU,YAAY,KAAK,EAAE,SAAS,CAAC;AAAA,IAC9C;AAAA,EACF;AAAA,EAEA,MAAM,MACJ,OACA,OACA,OACmB;AACnB,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,UAAoB,CAAC;AAE3B,eAAW,CAAC,IAAI,GAAG,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC3C,UAAI,QAAQ,UAAU,MAAO;AAE7B,UAAI,IAAI,UAAU,OAAO;AACvB,cAAM,eAAe,IAAI,cAAc,IAAI;AAC3C,YAAI,MAAM,eAAe,OAAO;AAC9B,eAAK,KAAK,OAAO,EAAE;AACnB,kBAAQ,KAAK,EAAE;AAAA,QACjB;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAW,SAA8C;AAE7D,eAAW,YAAY,KAAK,gBAAgB,OAAO,GAAG;AACpD,oBAAc,QAAQ;AAAA,IACxB;AACA,SAAK,gBAAgB,MAAM;AAC3B,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA,EAEA,GAAG,OAAqB,SAAmC;AACzD,QAAI,CAAC,KAAK,cAAc,IAAI,KAAK,GAAG;AAClC,WAAK,cAAc,IAAI,OAAO,oBAAI,IAAI,CAAC;AAAA,IACzC;AACA,SAAK,cAAc,IAAI,KAAK,EAAG,IAAI,OAAO;AAAA,EAC5C;AAAA,EAEA,IAAI,OAAqB,SAAmC;AAC1D,UAAM,WAAW,KAAK,cAAc,IAAI,KAAK;AAC7C,QAAI,UAAU;AACZ,eAAS,OAAO,OAAO;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,UAAkB;AAChB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,QAAc;AACZ,eAAW,YAAY,KAAK,gBAAgB,OAAO,GAAG;AACpD,oBAAc,QAAQ;AAAA,IACxB;AACA,SAAK,gBAAgB,MAAM;AAC3B,SAAK,KAAK,MAAM;AAChB,SAAK,WAAW,CAAC;AACjB,SAAK,SAAS;AACd,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAuB;AACrB,WAAO,MAAM,KAAK,KAAK,KAAK,OAAO,CAAC,EAAE,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAAA,EACtE;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA2B;AACzB,WAAO,MAAM,KAAK,KAAK,KAAK,OAAO,CAAC,EACjC,OAAO,CAAC,MAAM,EAAE,UAAU,SAAS,EACnC,IAAI,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,KAAK;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,UAAkB,KAAqB;AACjD,UAAM,QAAQ,KAAK,IAAI;AACvB,WAAO,KAAK,cAAc,KAAK,KAAK,eAAe,GAAG;AACpD,UAAI,KAAK,IAAI,IAAI,QAAQ,SAAS;AAChC,cAAM,IAAI,MAAM,qBAAqB;AAAA,MACvC;AACA,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AAAA,IACxD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAA0B;AAChC,eAAW,OAAO,KAAK,KAAK,OAAO,GAAG;AACpC,UAAI,IAAI,UAAU,UAAW,QAAO;AAAA,IACtC;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,cAA6B;AACzC,QAAI,KAAK,UAAU,KAAK,SAAS,WAAW,KAAK,KAAK,cAAc;AAClE;AAAA,IACF;AAEA,QAAI,KAAK,eAAe,KAAK,uBAAuB;AAClD;AAAA,IACF;AAGA,QAAI;AACJ,eAAW,OAAO,KAAK,KAAK,OAAO,GAAG;AACpC,UAAI,IAAI,UAAU,WAAW;AAC3B,kBAAU;AACV;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,SAAS;AACZ;AAAA,IACF;AAEA,SAAK;AACL,YAAQ,QAAQ;AAChB,YAAQ,cAAc,KAAK,IAAI;AAE/B,SAAK,UAAU,UAAU,OAAO;AAEhC,QAAI;AAEF,iBAAW,WAAW,KAAK,UAAU;AACnC,cAAM,KAAK,mBAAmB,SAAS,OAAO;AAAA,MAChD;AAGA,cAAQ,QAAQ;AAChB,cAAQ,aAAa,KAAK,IAAI;AAC9B,cAAQ,WAAW;AAEnB,WAAK,UAAU,aAAa,OAAO;AAGnC,UAAI,QAAQ,SAAS,qBAAqB,MAAM;AAC9C,aAAK,KAAK,OAAO,QAAQ,EAAE;AAAA,MAC7B;AAAA,IACF,SAAS,OAAO;AACd,YAAM,KAAK,iBAAiB,SAAS,KAAc;AAAA,IACrD,UAAE;AACA,WAAK;AAEL,mBAAa,MAAM,KAAK,YAAY,CAAC;AAAA,IACvC;AAAA,EACF;AAAA,EAEA,MAAc,mBACZ,SACA,KACe;AACf,UAAM,UAAU,IAAI,SAAS;AAC7B,UAAM,YAAY,KAAK,YAAY,GAAG;AAGtC,UAAM,aAAa,iBAAiB;AAAA,MAClC,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,eAAe,IAAI;AAAA,MACnB,UAAU,IAAI;AAAA,IAChB,CAAC;AAGD,UAAM,iBAAiB,MAAM,eAAe,YAAY,MAAM,QAAQ,SAAS,CAAC;AAEhF,QAAI,CAAC,SAAS;AACZ,YAAM,eAAe;AACrB;AAAA,IACF;AAEA,UAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,iBAAW,MAAM,OAAO,IAAI,MAAM,aAAa,CAAC,GAAG,OAAO;AAAA,IAC5D,CAAC;AAED,UAAM,QAAQ,KAAK,CAAC,eAAe,GAAG,cAAc,CAAC;AAAA,EACvD;AAAA,EAEA,MAAc,iBACZ,KACA,OACe;AACf,QAAI;AACJ,UAAM,cAAc,IAAI,SAAS,YAAY;AAE7C,QAAI,IAAI,eAAe,aAAa;AAElC,UAAI,QAAQ;AACZ,YAAM,eAAe,IAAI,SAAS,UAC9B,iBAAiB,IAAI,cAAc,IAAI,QAAQ,OAAO,IACtD;AAEJ,iBAAW,MAAM;AACf,cAAM,IAAI,KAAK,KAAK,IAAI,IAAI,EAAE;AAC9B,YAAI,KAAK,EAAE,UAAU,WAAW;AAC9B,YAAE,QAAQ;AACV,eAAK,YAAY;AAAA,QACnB;AAAA,MACF,GAAG,YAAY;AAAA,IACjB,OAAO;AAEL,UAAI,QAAQ;AACZ,UAAI,aAAa,KAAK,IAAI;AAC1B,UAAI,eAAe,MAAM;AAEzB,WAAK,UAAU,UAAU,KAAK,EAAE,MAAM,CAAC;AAGvC,UAAI,IAAI,SAAS,iBAAiB,MAAM;AACtC,aAAK,KAAK,OAAO,IAAI,EAAE;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,UACN,MACA,KACA,OACM;AACN,UAAM,WAAW,KAAK,cAAc,IAAI,IAAI;AAC5C,QAAI,CAAC,SAAU;AAEf,UAAM,QAAqB;AAAA,MACzB;AAAA,MACA,KAAK,KAAK,YAAY,GAAG;AAAA,MACzB,WAAW,KAAK,IAAI;AAAA,MACpB,GAAG;AAAA,IACL;AAEA,eAAW,WAAW,UAAU;AAC9B,UAAI;AACF,gBAAQ,KAAK;AAAA,MACf,QAAQ;AAAA,MAER;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,YAAY,KAA6B;AAC/C,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,MAAM,IAAI;AAAA,MACV,cAAc,IAAI;AAAA,MAClB,UAAU,IAAI;AAAA,MACd,WAAW,IAAI;AAAA,MACf,OAAO,IAAI;AAAA,MACX,aAAa,IAAI;AAAA,MACjB,YAAY,IAAI;AAAA,MAChB,cAAc,IAAI;AAAA,MAClB,eAAe,IAAI;AAAA,MACnB,UAAU,IAAI;AAAA,IAChB;AAAA,EACF;AACF;;;ACzhBO,IAAM,eAAN,MAAqC;AAAA,EAClC,aAA6B,CAAC;AAAA,EAEtC,MAAM,KAAK,SAA6C;AACtD,UAAM,KAAK,WAAW,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,MAAM,GAAG,CAAC,CAAC;AAE1E,YAAQ,IAAI,OAAO,IAAI,OAAO,EAAE,CAAC;AACjC,YAAQ,IAAI,wCAAiC;AAC7C,YAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAC1B,YAAQ,IAAI,YAAY,EAAE,EAAE;AAC5B,YAAQ,IAAI,YAAY,KAAK,gBAAgB,QAAQ,EAAE,CAAC,EAAE;AAC1D,YAAQ,IAAI,YAAY,QAAQ,OAAO,KAAK,cAAc,QAAQ,IAAI,IAAI,WAAW,EAAE;AACvF,YAAQ,IAAI,YAAY,QAAQ,OAAO,EAAE;AAEzC,QAAI,QAAQ,SAAS;AACnB,cAAQ,IAAI,aAAa,KAAK,cAAc,QAAQ,OAAO,CAAC,EAAE;AAAA,IAChE;AAEA,QAAI,QAAQ,QAAQ,QAAQ,KAAK,SAAS,GAAG;AAC3C,cAAQ,IAAI,YAAY,QAAQ,KAAK,KAAK,IAAI,CAAC,EAAE;AAAA,IACnD;AAEA,QAAI,QAAQ,eAAe,QAAQ,YAAY,SAAS,GAAG;AACzD,cAAQ,IAAI,gBAAgB,QAAQ,YAAY,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC,EAAE;AAAA,IACrF;AAEA,YAAQ,IAAI,IAAI,OAAO,EAAE,CAAC;AAE1B,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,YAAY;AACxB,cAAQ,IAAI,QAAQ,KAAK,MAAM,GAAG,GAAG,KAAK,QAAQ,KAAK,SAAS,MAAM,qBAAqB,GAAG;AAAA,IAChG;AAEA,QAAI,QAAQ,MAAM;AAChB,cAAQ,IAAI,gCAAgC,QAAQ,KAAK,SAAS,SAAS;AAAA,IAC7E;AAEA,YAAQ,IAAI,IAAI,OAAO,EAAE,IAAI,IAAI;AAEjC,SAAK,WAAW,KAAK,OAAO;AAE5B,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,UAAkD;AAChE,UAAM,UAAyB,CAAC;AAEhC,eAAW,WAAW,UAAU;AAC9B,cAAQ,KAAK,MAAM,KAAK,KAAK,OAAO,CAAC;AAAA,IACvC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgC;AAC9B,WAAO,CAAC,GAAG,KAAK,UAAU;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAwB;AACtB,SAAK,aAAa,CAAC;AAAA,EACrB;AAAA,EAEQ,cAAc,SAA+B;AACnD,QAAI,QAAQ,MAAM;AAChB,aAAO,GAAG,QAAQ,IAAI,KAAK,QAAQ,KAAK;AAAA,IAC1C;AACA,WAAO,QAAQ;AAAA,EACjB;AAAA,EAEQ,gBAAgB,WAAkD;AACxE,UAAM,OAAO,MAAM,QAAQ,SAAS,IAAI,YAAY,CAAC,SAAS;AAC9D,WAAO,KAAK,IAAI,CAAC,SAAS,KAAK,cAAc,IAAI,CAAC,EAAE,KAAK,IAAI;AAAA,EAC/D;AACF;;;ACjEA,eAAe,sBAAsB,QAA4C;AAC/E,UAAQ,OAAO,SAAS,UAAU;AAAA,IAChC,KAAK,YAAY;AACf,YAAM,mBAAmB,OAAO,SAAS,oBAAoB,OAAO,SAAS,OAAO,QAAQ,IAAI;AAChG,UAAI,CAAC,kBAAkB;AACrB,cAAM,IAAI,MAAM,0EAA0E;AAAA,MAC5F;AACA,YAAM,EAAE,kBAAAC,kBAAiB,IAAI,MAAM;AACnC,aAAOA,kBAAiB,OAAO;AAAA,QAC7B;AAAA,QACA,KAAK,OAAO,SAAS;AAAA,QACrB,KAAK,OAAO,SAAS;AAAA,QACrB,yBAAyB,OAAO,SAAS;AAAA,MAC3C,CAAC;AAAA,IACH;AAAA,IACA,KAAK,YAAY;AACf,UAAI,CAAC,OAAO,SAAS,eAAe,CAAC,OAAO,SAAS,iBAAiB;AACpE,cAAM,IAAI,MAAM,4EAA4E;AAAA,MAC9F;AACA,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,uBAAuB;AAC7D,YAAM,EAAE,kBAAAC,kBAAiB,IAAI,MAAM;AACnC,YAAM,SAAS;AAAA,QACb,OAAO,SAAS;AAAA,QAChB,OAAO,SAAS,0BAA0B,OAAO,SAAS;AAAA,MAC5D;AACA,aAAO,IAAIA,kBAAiB,MAAM;AAAA,IACpC;AAAA,IACA,KAAK;AAAA,IACL;AACE,aAAO,IAAI,eAAe;AAAA,EAC9B;AACF;AAKA,eAAe,mBAAmB,QAAyC;AACzE,UAAQ,OAAO,MAAM,UAAU;AAAA,IAC7B,KAAK,SAAS;AACZ,YAAM,MAAM,OAAO,MAAM,OAAO,QAAQ,IAAI;AAC5C,UAAI,CAAC,KAAK;AACR,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACvE;AACA,YAAM,EAAE,YAAAC,YAAW,IAAI,MAAM;AAC7B,aAAOA,YAAW,OAAO;AAAA,QACvB;AAAA,QACA,WAAW,OAAO,MAAM;AAAA,MAC1B,CAAC;AAAA,IACH;AAAA,IACA,KAAK,WAAW;AACd,UAAI,CAAC,OAAO,MAAM,cAAc,CAAC,OAAO,MAAM,cAAc;AAC1D,cAAM,IAAI,MAAM,4FAA4F;AAAA,MAC9G;AACA,YAAM,EAAE,MAAM,IAAI,MAAM,OAAO,gBAAgB;AAC/C,YAAM,EAAE,cAAAC,cAAa,IAAI,MAAM;AAC/B,YAAM,SAAS,IAAI,MAAM;AAAA,QACvB,KAAK,OAAO,MAAM;AAAA,QAClB,OAAO,OAAO,MAAM;AAAA,MACtB,CAAC;AACD,aAAO,IAAIA,cAAa,MAAM;AAAA,IAChC;AAAA,IACA,KAAK;AAAA,IACL;AACE,aAAO,IAAI,YAAY;AAAA,EAC3B;AACF;AAKA,eAAe,qBAAqB,QAA2C;AAC7E,UAAQ,OAAO,QAAQ,UAAU;AAAA,IAC/B,KAAK,YAAY;AACf,YAAM,MAAM,OAAO,SAAS,eAAe,QAAQ,IAAI;AACvD,YAAM,SAAS,OAAO,SAAS,0BAA0B,OAAO,SAAS,mBAAmB,QAAQ,IAAI;AACxG,YAAM,SAAS,OAAO,QAAQ,UAAU,QAAQ,IAAI,2BAA2B;AAE/E,UAAI,CAAC,OAAO,CAAC,QAAQ;AACnB,cAAM,IAAI,MAAM,8DAA8D;AAAA,MAChF;AAEA,YAAM,EAAE,iBAAAC,iBAAgB,IAAI,MAAM;AAClC,aAAOA,iBAAgB,OAAO;AAAA,QAC5B;AAAA,QACA;AAAA,QACA;AAAA,QACA,cAAc,OAAO,QAAQ,cAAc;AAAA,QAC3C,iBAAiB,OAAO,QAAQ;AAAA,MAClC,CAAC;AAAA,IACH;AAAA,IACA,KAAK;AAAA,IACL,KAAK;AAAA,IACL,KAAK,MAAM;AACT,UAAI,CAAC,OAAO,QAAQ,aAAa,CAAC,OAAO,QAAQ,aAAa,CAAC,OAAO,QAAQ,QAAQ;AACpF,cAAM,IAAI,MAAM,+EAA+E;AAAA,MACjG;AACA,YAAM,EAAE,SAAS,IAAI,MAAM,OAAO,oBAAoB;AACtD,YAAM,EAAE,aAAa,IAAI,MAAM,OAAO,+BAA+B;AACrE,YAAM,EAAE,WAAAC,WAAU,IAAI,MAAM;AAE5B,YAAM,SAAS,IAAI,SAAS;AAAA,QAC1B,UAAU,OAAO,QAAQ;AAAA,QACzB,QAAQ,OAAO,QAAQ,UAAU;AAAA,QACjC,aAAa;AAAA,UACX,aAAa,OAAO,QAAQ;AAAA,UAC5B,iBAAiB,OAAO,QAAQ;AAAA,QAClC;AAAA,QACA,gBAAgB,OAAO,QAAQ,kBAAkB,OAAO,QAAQ,aAAa;AAAA,MAC/E,CAAC;AAED,aAAO,IAAIA,WAAU,QAAQ,OAAO,QAAQ,QAAQ,cAAc,OAAO,QAAQ,SAAS;AAAA,IAC5F;AAAA,IACA,KAAK;AAAA,IACL;AACE,aAAO,IAAI,cAAc;AAAA,EAC7B;AACF;AAKA,eAAe,mBAAmB,QAAyC;AACzE,UAAQ,OAAO,MAAM,UAAU;AAAA,IAC7B,KAAK,QAAQ;AACX,UAAI,CAAC,OAAO,MAAM,QAAQ,CAAC,OAAO,MAAM,MAAM;AAC5C,cAAM,IAAI,MAAM,kEAAkE;AAAA,MACpF;AACA,YAAM,EAAE,WAAAC,WAAU,IAAI,MAAM;AAC5B,aAAOA,WAAU,OAAO;AAAA,QACtB,MAAM,OAAO,MAAM;AAAA,QACnB,MAAM,OAAO,MAAM;AAAA,QACnB,QAAQ,OAAO,MAAM;AAAA,QACrB,UAAU,OAAO,MAAM;AAAA,QACvB,UAAU,OAAO,MAAM;AAAA,QACvB,MAAM,OAAO,MAAM;AAAA,MACrB,CAAC;AAAA,IACH;AAAA,IACA,KAAK,UAAU;AACb,UAAI,CAAC,OAAO,MAAM,QAAQ;AACxB,cAAM,IAAI,MAAM,qDAAqD;AAAA,MACvE;AACA,YAAM,EAAE,OAAO,IAAI,MAAM,OAAO,QAAQ;AACxC,YAAM,EAAE,aAAAC,aAAY,IAAI,MAAM;AAC9B,YAAM,SAAS,IAAI,OAAO,OAAO,MAAM,MAAM;AAC7C,aAAO,IAAIA,aAAY,QAAQ,OAAO,MAAM,IAAI;AAAA,IAClD;AAAA,IACA,KAAK;AACH,aAAO,IAAI,aAAa;AAAA,IAC1B,KAAK;AAAA,IACL;AACE,aAAO,IAAI,YAAY;AAAA,EAC3B;AACF;AAKA,eAAe,mBAAmB,QAAyC;AACzE,UAAQ,OAAO,MAAM,UAAU;AAAA,IAC7B,KAAK,UAAU;AACb,UAAI,CAAC,OAAO,MAAM,YAAY,CAAC,OAAO,MAAM,KAAK;AAC/C,cAAM,IAAI,MAAM,gDAAgD;AAAA,MAClE;AACA,YAAM,EAAE,aAAAC,aAAY,IAAI,MAAM;AAC9B,aAAO,IAAIA,aAAY;AAAA,QACrB,UAAU,OAAO,MAAM,YAAY,OAAO,MAAM;AAAA,QAChD,WAAW;AAAA,MACb,CAAC;AAAA,IACH;AAAA,IACA,KAAK;AAAA,IACL;AACE,aAAO,IAAI,YAAY;AAAA,EAC3B;AACF;AAKA,eAAe,qBAAqB,QAA2C;AAC7E,QAAM,gBAAgB,OAAO,cAAc;AAG3C,MAAI,CAAC,cAAc,SAAS;AAC1B,WAAO,IAAI,YAAY;AAAA,EACzB;AAEA,UAAQ,cAAc,UAAU;AAAA,IAC9B,KAAK,QAAQ;AAEX,YAAM,EAAE,sBAAAC,sBAAqB,IAAI,MAAM;AACvC,aAAOA,sBAAqB,OAAO;AAAA,QACjC,aAAa,cAAc,eAAe;AAAA,QAC1C,gBAAgB,cAAc;AAAA,QAC9B,aAAa,cAAc;AAAA,QAC3B,UAAU,cAAc;AAAA,QACxB,cAAc,cAAc;AAAA,QAC5B,YAAY,cAAc;AAAA,MAC5B,CAAC;AAAA,IACH;AAAA,IACA,KAAK;AACH,aAAO,IAAI,cAAc;AAAA,IAC3B,KAAK;AAAA,IACL;AACE,aAAO,IAAI,YAAY;AAAA,EAC3B;AACF;AAKA,SAAS,aAAa,QAAiC;AACrD,MAAI,CAAC,OAAO,cAAc,SAAS;AACjC,WAAO,IAAI,WAAW;AAAA,EACxB;AAEA,SAAO,IAAI,cAAc;AAAA,IACvB,OAAO,OAAO,cAAc,QAAQ;AAAA,IACpC,SAAS,OAAO,cAAc,QAAQ;AAAA,IACtC,aAAa,OAAO,cAAc,QAAQ;AAAA,EAC5C,CAAC;AACH;AAKA,SAAS,cAAc,QAAkC;AACvD,MAAI,CAAC,OAAO,cAAc,QAAQ,SAAS;AACzC,WAAO,IAAI,YAAY;AAAA,EACzB;AAIA,SAAO,IAAI,cAAc;AAC3B;AAKA,eAAsB,oBAAoB,QAAsD;AAC9F,QAAM,cAAc,SAAS,UAAU,WAAW,GAAG,MAAM,IAAI,WAAW;AAE1E,QAAM,CAAC,IAAI,OAAO,SAAS,OAAO,OAAO,OAAO,IAAI,MAAM,QAAQ,IAAI;AAAA,IACpE,sBAAsB,WAAW;AAAA,IACjC,mBAAmB,WAAW;AAAA,IAC9B,qBAAqB,WAAW;AAAA,IAChC,mBAAmB,WAAW;AAAA,IAC9B,mBAAmB,WAAW;AAAA,IAC9B,qBAAqB,WAAW;AAAA,EAClC,CAAC;AAED,QAAM,SAAS,aAAa,WAAW;AACvC,QAAM,UAAU,cAAc,WAAW;AAEzC,SAAO,2BAA2B,IAAI,OAAO,SAAS,OAAO,OAAO,QAAQ,SAAS,OAAO;AAC9F;AAMO,SAAS,eAAe,QAA6C;AAC1E,QAAM,cAAc,SAAS,UAAU,WAAW,GAAG,MAAM,IAAI,WAAW;AAG1E,QAAM,wBACJ,YAAY,SAAS,aAAa,YAClC,YAAY,MAAM,aAAa,YAC/B,YAAY,QAAQ,aAAa,YAChC,YAAY,MAAM,aAAa,YAAY,YAAY,MAAM,aAAa,aAC3E,YAAY,cAAc,QAAQ,aAAa;AAEjD,MAAI,uBAAuB;AACzB,YAAQ;AAAA,MACN;AAAA,IAEF;AAAA,EACF;AAGA,QAAM,KAAK,IAAI,eAAe;AAC9B,QAAM,QAAQ,IAAI,YAAY;AAC9B,QAAM,UAAU,IAAI,cAAc;AAClC,QAAM,QAAQ,YAAY,MAAM,aAAa,YAAY,IAAI,aAAa,IAAI,IAAI,YAAY;AAC9F,QAAM,QAAQ,IAAI,YAAY;AAC9B,QAAM,SAAS,aAAa,WAAW;AACvC,QAAM,UAAU,cAAc,WAAW;AACzC,QAAM,UAAU,YAAY,cAAc,QAAQ,aAAa,WAC3D,IAAI,cAAc,IAClB,IAAI,YAAY;AAEpB,SAAO,2BAA2B,IAAI,OAAO,SAAS,OAAO,OAAO,QAAQ,SAAS,OAAO;AAC9F;AAKA,SAAS,2BACP,IACA,OACA,SACA,OACA,OACA,QACA,SACA,SACW;AACX,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAEA,MAAM,cAA6C;AACjD,YAAM,CAAC,UAAU,aAAa,eAAe,aAAa,aAAa,aAAa,IAAI,MAAM,QAAQ,IAAI;AAAA,QACxG,GAAG,YAAY;AAAA,QACf,MAAM,YAAY;AAAA,QAClB,QAAQ,YAAY;AAAA,QACpB,MAAM,YAAY;AAAA,QAClB,MAAM,YAAY;AAAA,QAClB,QAAQ,YAAY;AAAA,MACtB,CAAC;AAED,aAAO;AAAA,QACL,SAAS,YAAY,eAAe,iBAAiB,eAAe,eAAe;AAAA,QACnF,UAAU;AAAA,UACR,UAAU;AAAA,UACV,OAAO;AAAA,UACP,SAAS;AAAA,UACT,OAAO;AAAA,UACP,OAAO;AAAA,UACP,SAAS;AAAA,QACX;AAAA,QACA,WAAW,KAAK,IAAI;AAAA,MACtB;AAAA,IACF;AAAA,IAEA,MAAM,QAAuB;AAC3B,YAAM,QAAQ,IAAI,CAAC,GAAG,MAAM,GAAG,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,QAAQ,MAAM,CAAC,CAAC;AAAA,IAC/E;AAAA,EACF;AACF;AAKA,SAAS,UAA6C,QAAW,QAAuB;AACtF,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,aAAW,OAAO,QAAQ;AACxB,QAAI,OAAO,UAAU,eAAe,KAAK,QAAQ,GAAG,GAAG;AACrD,YAAM,cAAc,OAAO,GAAG;AAC9B,YAAM,cAAc,OAAO,GAAG;AAE9B,UACE,gBAAgB,UAChB,OAAO,gBAAgB,YACvB,gBAAgB,QAChB,CAAC,MAAM,QAAQ,WAAW,KAC1B,OAAO,gBAAgB,YACvB,gBAAgB,QAChB,CAAC,MAAM,QAAQ,WAAW,GAC1B;AACA,eAAO,GAAG,IAAI;AAAA,UACZ;AAAA,UACA;AAAA,QACF;AAAA,MACF,WAAW,gBAAgB,QAAW;AACpC,eAAO,GAAG,IAAI;AAAA,MAChB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACjZA,SAAS,kBAAkB;AAQpB,SAAS,sBAAsB,UAAkC,CAAC,GAAoB;AAC3F,QAAM,cAA4B,CAAC;AACnC,QAAM,SAAS,QAAQ,UAAU,IAAI,WAAW;AAChD,QAAM,wBAAwB,QAAQ,0BAA0B,MAAM,WAAW;AAEjF,WAAS,iBAAuB;AAC9B,gBAAY,KAAK,CAAC,GAAG,OAAO,EAAE,YAAY,QAAQ,EAAE,YAAY,IAAI;AAAA,EACtE;AAEA,QAAM,QAAyB;AAAA,IAC7B,IAAwC,YAAyD;AAE/F,YAAM,gBAAgB,YAAY,UAAU,CAAC,MAAM,EAAE,SAAS,WAAW,IAAI;AAC7E,UAAI,kBAAkB,IAAI;AACxB,oBAAY,OAAO,eAAe,CAAC;AAAA,MACrC;AAEA,kBAAY,KAAK,UAAwB;AACzC,qBAAe;AACf,aAAO;AAAA,IACT;AAAA,IAEA,OAAO,MAA+B;AACpC,YAAM,QAAQ,YAAY,UAAU,CAAC,MAAM,EAAE,SAAS,IAAI;AAC1D,UAAI,UAAU,IAAI;AAChB,oBAAY,OAAO,OAAO,CAAC;AAAA,MAC7B;AACA,aAAO;AAAA,IACT;AAAA,IAEA,MAAM,QACJ,YACA,WACkB;AAClB,YAAM,MAAyC;AAAA,QAC7C,GAAG;AAAA,QACH,UAAU,oBAAI,IAAI;AAAA,QAClB,MAAM;AAAA,QACN,cAAc;AAAA,MAChB;AAGA,iBAAW,cAAc,aAAa;AACpC,YAAI,WAAW,QAAQ;AACrB,cAAI;AACF,kBAAM,WAAW,OAAO,GAAG;AAAA,UAC7B,SAAS,KAAK;AACZ,kBAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,mBAAO,MAAM,cAAc,WAAW,IAAI,uBAAuB;AAAA,cAC/D;AAAA,cACA,WAAW,IAAI;AAAA,YACjB,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,IAAI,MAAM;AACZ;AAAA,QACF;AAAA,MACF;AAGA,UAAI,IAAI,iBAAiB,QAAW;AAClC,YAAI,SAAS,IAAI;AACjB,YAAI,WAAW,KAAK,IAAI,IAAI,IAAI;AAGhC,mBAAW,cAAc,aAAa;AACpC,cAAI,WAAW,OAAO;AACpB,gBAAI;AACF,oBAAM,WAAW,MAAM,GAAG;AAAA,YAC5B,SAAS,KAAK;AACZ,oBAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,qBAAO,MAAM,cAAc,WAAW,IAAI,sBAAsB;AAAA,gBAC9D;AAAA,gBACA,WAAW,IAAI;AAAA,cACjB,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAEA,eAAO,IAAI;AAAA,MACb;AAGA,UAAI;AACF,cAAM,SAAS,MAAM,UAAU;AAC/B,YAAI,SAAS;AACb,YAAI,WAAW,KAAK,IAAI,IAAI,IAAI;AAGhC,mBAAW,cAAc,aAAa;AACpC,cAAI,WAAW,OAAO;AACpB,gBAAI;AACF,oBAAM,WAAW,MAAM,GAAG;AAAA,YAC5B,SAAS,KAAK;AACZ,oBAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,qBAAO,MAAM,cAAc,WAAW,IAAI,sBAAsB;AAAA,gBAC9D;AAAA,gBACA,WAAW,IAAI;AAAA,cACjB,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAEA,eAAO;AAAA,MACT,SAAS,KAAK;AACZ,YAAI,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAC9D,YAAI,WAAW,KAAK,IAAI,IAAI,IAAI;AAGhC,mBAAW,cAAc,aAAa;AACpC,cAAI,WAAW,SAAS;AACtB,gBAAI;AACF,oBAAM,WAAW,QAAQ,KAAK,IAAI,KAAK;AAAA,YACzC,SAAS,SAAS;AAChB,oBAAM,QAAQ,mBAAmB,QAAQ,UAAU,IAAI,MAAM,OAAO,OAAO,CAAC;AAC5E,qBAAO,MAAM,cAAc,WAAW,IAAI,wBAAwB;AAAA,gBAChE;AAAA,gBACA,WAAW,IAAI;AAAA,cACjB,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAEA,cAAM,IAAI;AAAA,MACZ;AAAA,IACF;AAAA,IAEA,gBAA8B;AAC5B,aAAO,CAAC,GAAG,WAAW;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,wBACd,SACA,WACA,MACA,QACA,UAGI,CAAC,GAC0E;AAC/E,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW,KAAK,IAAI;AAAA,IACpB,eAAe,QAAQ,iBAAiB,WAAW;AAAA,IACnD,UAAU,QAAQ;AAAA,EACpB;AACF;;;AC/JO,SAAS,wBAAwB,QAA6B;AACnE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,OAAO,KAA8B;AACnC,aAAO,MAAM,YAAY,IAAI,OAAO,IAAI,IAAI,SAAS,IAAI;AAAA,QACvD,eAAe,IAAI;AAAA,QACnB,UAAU,IAAI;AAAA,QACd,MAAM,aAAa,IAAI,IAAI;AAAA,MAC7B,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,KAA8B;AAClC,aAAO,KAAK,aAAa,IAAI,OAAO,IAAI,IAAI,SAAS,IAAI;AAAA,QACvD,eAAe,IAAI;AAAA,QACnB,UAAU,IAAI;AAAA,QACd,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,KAAwB,OAAoB;AAClD,aAAO,MAAM,UAAU,IAAI,OAAO,IAAI,IAAI,SAAS,IAAI;AAAA,QACrD,eAAe,IAAI;AAAA,QACnB,UAAU,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAKO,SAAS,wBAAwB,SAA+B;AACrE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,MAAM,KAA8B;AAClC,cAAQ,OAAO,YAAY,IAAI,OAAO,aAAa,IAAI,YAAY,GAAG;AAAA,QACpE,WAAW,IAAI;AAAA,QACf,SAAS;AAAA,MACX,CAAC;AAED,cAAQ,UAAU,YAAY,IAAI,OAAO,aAAa,GAAG;AAAA,QACvD,WAAW,IAAI;AAAA,QACf,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,IAEA,QAAQ,KAA8B;AACpC,cAAQ,OAAO,YAAY,IAAI,OAAO,aAAa,IAAI,YAAY,GAAG;AAAA,QACpE,WAAW,IAAI;AAAA,QACf,SAAS;AAAA,MACX,CAAC;AAED,cAAQ,UAAU,YAAY,IAAI,OAAO,aAAa,GAAG;AAAA,QACvD,WAAW,IAAI;AAAA,QACf,QAAQ;AAAA,MACV,CAAC;AAED,cAAQ,UAAU,YAAY,IAAI,OAAO,WAAW,GAAG;AAAA,QACrD,WAAW,IAAI;AAAA,MACjB,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAKO,SAAS,0BACd,QACA,cAAsB,KACV;AACZ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,MAAM,KAA8B;AAClC,UAAI,IAAI,YAAY,IAAI,WAAW,aAAa;AAC9C,eAAO,KAAK,4BAA4B,IAAI,OAAO,IAAI,IAAI,SAAS,IAAI;AAAA,UACtE,eAAe,IAAI;AAAA,UACnB,UAAU,IAAI;AAAA,UACd,WAAW;AAAA,UACX,MAAM,aAAa,IAAI,IAAI;AAAA,QAC7B,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,uBACd,UAGI,CAAC,GACO;AACZ,QAAM,EAAE,WAAW,MAAM,IAAI;AAE7B,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,OAAO,KAA8B;AACnC,UAAI,YAAY,CAAC,IAAI,UAAU;AAC7B,cAAM,IAAI,MAAM,0CAA0C;AAAA,MAC5D;AAEA,UAAI,IAAI,UAAU;AAChB,YAAI,SAAS,IAAI,YAAY,IAAI,QAAQ;AAAA,MAC3C;AAAA,IACF;AAAA,EACF;AACF;AAKO,SAAS,4BAAwC;AACtD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,OAAO,KAA8B;AACnC,UAAI,SAAS,IAAI,iBAAiB,IAAI,aAAa;AAAA,IACrD;AAAA,EACF;AACF;AAKO,SAAS,wBAAwB,WAA+B;AACrE,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,OAAO,KAA8B;AACnC,UAAI,SAAS,IAAI,WAAW,SAAS;AACrC,UAAI,SAAS,IAAI,gBAAgB,KAAK,IAAI,CAAC;AAAA,IAC7C;AAAA,EACF;AACF;AAKO,SAAS,sBACd,OACA,UAII,CAAC,GACO;AACZ,QAAM;AAAA,IACJ,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,sBAAsB,CAAC,OAAO,SAAS,QAAQ,MAAM;AAAA,EACvD,IAAI;AAEJ,WAAS,YAAY,WAA4B;AAC/C,WAAO,oBAAoB,KAAK,CAAC,OAAO,UAAU,YAAY,EAAE,SAAS,EAAE,CAAC;AAAA,EAC9E;AAEA,WAAS,YAAY,KAAgC;AACnD,UAAM,WAAW,KAAK,UAAU,IAAI,IAAI;AACxC,WAAO,GAAG,SAAS,GAAG,IAAI,OAAO,IAAI,IAAI,SAAS,IAAI,QAAQ;AAAA,EAChE;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA,IAEV,MAAM,OAAO,KAAuC;AAClD,UAAI,CAAC,YAAY,IAAI,SAAS,EAAG;AAEjC,YAAM,MAAM,YAAY,GAAG;AAC3B,YAAM,SAAS,MAAM,MAAM,IAAI,GAAG;AAElC,UAAI,WAAW,MAAM;AACnB,YAAI,eAAe;AACnB,YAAI,SAAS,IAAI,YAAY,IAAI;AACjC,YAAI,OAAO,MAAM,aAAa,EAAE,KAAK,WAAW,IAAI,UAAU,CAAC;AAAA,MACjE,OAAO;AACL,YAAI,SAAS,IAAI,YAAY,KAAK;AAAA,MACpC;AAAA,IACF;AAAA,IAEA,MAAM,MAAM,KAAuC;AACjD,UAAI,CAAC,YAAY,IAAI,SAAS,EAAG;AACjC,UAAI,IAAI,SAAS,IAAI,UAAU,EAAG;AAElC,YAAM,MAAM,YAAY,GAAG;AAC3B,YAAM,MAAM,IAAI,KAAK,IAAI,QAAQ,GAAG;AACpC,UAAI,OAAO,MAAM,aAAa,EAAE,KAAK,WAAW,IAAI,WAAW,IAAI,CAAC;AAAA,IACtE;AAAA,EACF;AACF;AAKO,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACtB,OAAO;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAET,YACE,SACA,SACA;AACA,UAAM,OAAO;AACb,SAAK,aAAa,QAAQ;AAC1B,SAAK,QAAQ,QAAQ;AACrB,SAAK,YAAY,QAAQ;AACzB,SAAK,UAAU,QAAQ;AAAA,EACzB;AACF;AA8BO,IAAM,2BAAN,MAA6D;AAAA,EAC1D,UAA2D,oBAAI,IAAI;AAAA,EACnE,kBAAyC;AAAA,EAEjD,YAAY,UAA0C,CAAC,GAAG;AACxD,UAAM,oBAAoB,QAAQ,qBAAqB;AAGvD,SAAK,kBAAkB,YAAY,MAAM;AACvC,YAAM,MAAM,KAAK,IAAI;AACrB,iBAAW,CAAC,KAAK,MAAM,KAAK,KAAK,SAAS;AACxC,YAAI,OAAO,UAAU,KAAK;AACxB,eAAK,QAAQ,OAAO,GAAG;AAAA,QACzB;AAAA,MACF;AAAA,IACF,GAAG,iBAAiB;AAGpB,QAAI,KAAK,gBAAgB,OAAO;AAC9B,WAAK,gBAAgB,MAAM;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAM,UAAU,KAAa,UAA6C;AACxE,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,SAAS,KAAK,QAAQ,IAAI,GAAG;AAGjC,QAAI,CAAC,UAAU,OAAO,UAAU,KAAK;AACnC,eAAS,EAAE,OAAO,GAAG,SAAS,MAAM,SAAS;AAC7C,WAAK,QAAQ,IAAI,KAAK,MAAM;AAAA,IAC9B;AAEA,WAAO;AACP,WAAO,CAAC,OAAO,OAAO,OAAO,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,IAAI,KAAiE;AACzE,UAAM,SAAS,KAAK,QAAQ,IAAI,GAAG;AACnC,QAAI,CAAC,UAAU,OAAO,UAAU,KAAK,IAAI,GAAG;AAC1C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,QAAQ,MAAM;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,QAAI,KAAK,iBAAiB;AACxB,oBAAc,KAAK,eAAe;AAClC,WAAK,kBAAkB;AAAA,IACzB;AAAA,EACF;AACF;AA2CO,SAAS,0BAA0B,SAAuC;AAC/E,QAAM;AAAA,IACJ;AAAA,IACA;AAAA,IACA,UAAU,IAAI,yBAAyB;AAAA,IACvC,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA,eAAe;AAAA,IACf,UAAU;AAAA,EACZ,IAAI;AAEJ,SAAO;AAAA,IACL,MAAM;AAAA,IACN,UAAU;AAAA;AAAA,IAEV,MAAM,OAAO,KAAuC;AAElD,UAAI,OAAO,GAAG,GAAG;AACf,YAAI,SAAS,IAAI,oBAAoB,IAAI;AACzC;AAAA,MACF;AAEA,YAAM,MAAM,aAAa,aAAa,GAAG,CAAC;AAC1C,YAAM,CAAC,OAAO,SAAS,IAAI,MAAM,QAAQ,UAAU,KAAK,QAAQ;AAChE,YAAM,UAAU,IAAI,KAAK,SAAS;AAClC,YAAM,YAAY,KAAK,IAAI,GAAG,QAAQ,KAAK;AAC3C,YAAM,aAAa,KAAK,MAAM,YAAY,KAAK,IAAI,KAAK,GAAI;AAG5D,YAAM,OAAsB,EAAE,OAAO,WAAW,QAAQ;AACxD,UAAI,SAAS,IAAI,aAAa,IAAI;AAElC,UAAI,QAAQ,OAAO;AACjB,wBAAgB,KAAK,IAAI;AAEzB,YAAI,OAAO,KAAK,uBAAuB;AAAA,UACrC,eAAe,IAAI;AAAA,UACnB,UAAU,IAAI;AAAA,UACd;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAED,YAAI,cAAc;AAChB,gBAAM,IAAI,eAAe,SAAS,EAAE,YAAY,OAAO,WAAW,QAAQ,CAAC;AAAA,QAC7E;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAKA,SAAS,oBAAoB,KAAgC;AAC3D,QAAM,QAAQ,CAAC,IAAI,SAAS,IAAI,SAAS;AAEzC,MAAI,IAAI,UAAU;AAChB,UAAM,QAAQ,IAAI,QAAQ;AAAA,EAC5B;AAEA,SAAO,MAAM,KAAK,GAAG;AACvB;AAKO,SAAS,qBACd,OACoC;AACpC,SAAO,CAAC,QAA2B;AACjC,UAAM,KAAK,MAAM,GAAG,KAAK;AACzB,WAAO,MAAM,EAAE,IAAI,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,EACjD;AACF;AAKO,SAAS,uBACdC,YACoC;AACpC,SAAO,CAAC,QAA2B;AACjC,UAAM,SAASA,WAAU,GAAG,KAAK;AACjC,WAAO,QAAQ,MAAM,IAAI,IAAI,OAAO,IAAI,IAAI,SAAS;AAAA,EACvD;AACF;AAuCO,IAAM,mBAAmB;AAAA;AAAA,EAE9B,UAAU,EAAE,OAAO,KAAK,UAAU,KAAK,IAAK;AAAA;AAAA,EAG5C,QAAQ,EAAE,OAAO,IAAI,UAAU,KAAK,IAAK;AAAA;AAAA,EAGzC,SAAS,EAAE,OAAO,KAAM,UAAU,KAAK,IAAK;AAAA;AAAA,EAG5C,OAAO,EAAE,OAAO,IAAI,UAAU,IAAK;AAAA;AAAA,EAGnC,MAAM,EAAE,OAAO,GAAG,UAAU,KAAK,KAAK,IAAK;AAAA;AAAA,EAG3C,WAAW,EAAE,OAAO,IAAI,UAAU,KAAK,KAAK,IAAK;AACnD;AAKA,SAAS,aAAa,MAAwB;AAC5C,MAAI,SAAS,QAAQ,SAAS,OAAW,QAAO;AAEhD,MAAI,OAAO,SAAS,SAAU,QAAO;AAErC,MAAI,MAAM,QAAQ,IAAI,GAAG;AACvB,WAAO,KAAK,IAAI,YAAY;AAAA,EAC9B;AAEA,QAAM,YAAqC,CAAC;AAC5C,QAAM,gBAAgB,CAAC,YAAY,SAAS,UAAU,OAAO,iBAAiB,YAAY;AAE1F,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAA+B,GAAG;AAC1E,QAAI,cAAc,KAAK,CAAC,OAAO,IAAI,YAAY,EAAE,SAAS,EAAE,CAAC,GAAG;AAC9D,gBAAU,GAAG,IAAI;AAAA,IACnB,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AACtD,gBAAU,GAAG,IAAI,aAAa,KAAK;AAAA,IACrC,OAAO;AACL,gBAAU,GAAG,IAAI;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AACT;;;ACphBO,SAAS,mBAAmB,SAAkB,IAAI,WAAW,GAAiB;AACnF,MAAI,QAAuB,CAAC;AAE5B,QAAM,WAAyB;AAAA,IAC7B,SAAS,UAAwC;AAC/C,cAAQ,EAAE,GAAG,OAAO,GAAG,SAAS;AAChC,aAAO,MAAM,oBAAoB;AAAA,QAC/B,WAAW,OAAO,KAAK,QAAQ;AAAA,MACjC,CAAC;AAAA,IACH;AAAA,IAEA,QAAc;AACZ,cAAQ,CAAC;AACT,aAAO,MAAM,eAAe;AAAA,IAC9B;AAAA,IAEA,MAAM,QACJ,aACG,MACY;AACf,YAAM,OAAO,MAAM,QAAQ;AAE3B,UAAI,CAAC,MAAM;AACT;AAAA,MACF;AAEA,UAAI;AAEF,cAAM,KAAK,GAAG,IAAI;AAAA,MACpB,SAAS,KAAK;AACZ,cAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,eAAO,MAAM,QAAQ,OAAO,QAAQ,CAAC,WAAW;AAAA,UAC9C;AAAA,UACA,UAAU,OAAO,QAAQ;AAAA,QAC3B,CAAC;AAAA,MAEH;AAAA,IACF;AAAA,IAEA,WAA0B;AACxB,aAAO,EAAE,GAAG,MAAM;AAAA,IACpB;AAAA,EACF;AAEA,SAAO;AACT;AAKO,SAAS,yBAAyB,YAA0C;AACjF,QAAM,SAAS,IAAI,WAAW;AAE9B,SAAO;AAAA,IACL,SAAS,OAAqC;AAC5C,iBAAW,QAAQ,CAAC,MAAM,EAAE,SAAS,KAAK,CAAC;AAAA,IAC7C;AAAA,IAEA,QAAc;AACZ,iBAAW,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;AAAA,IACrC;AAAA,IAEA,MAAM,QACJ,aACG,MACY;AACf,iBAAW,YAAY,YAAY;AACjC,cAAM,SAAS,QAAQ,UAAU,GAAG,IAAI;AAAA,MAC1C;AAAA,IACF;AAAA,IAEA,WAA0B;AACxB,aAAO,WAAW,OAAO,CAAC,KAAK,OAAO,EAAE,GAAG,KAAK,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,CAAkB;AAAA,IACzF;AAAA,EACF;AACF;;;ACXO,IAAM,wBAAsC;AAAA,EACjD,aAAa;AAAA,EACb,WAAW;AAAA,EACX,UAAU;AAAA,EACV,mBAAmB;AAAA,EACnB,QAAQ;AAAA,EACR,WAAW;AACb;AAyBA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;AAKA,SAAS,eAAe,SAAiB,SAA+B;AAEtE,MAAI,QAAQ,QAAQ,YAAY,KAAK,IAAI,QAAQ,mBAAmB,UAAU,CAAC;AAG/E,UAAQ,KAAK,IAAI,OAAO,QAAQ,QAAQ;AAGxC,MAAI,QAAQ,QAAQ;AAClB,UAAM,SAAS,KAAK,OAAO,IAAI,QAAQ;AACvC,aAAS;AAAA,EACX;AAEA,SAAO,KAAK,MAAM,KAAK;AACzB;AAKA,eAAsB,UACpB,IACA,UAAiC,CAAC,GACtB;AACZ,QAAM,OAAqB,EAAE,GAAG,uBAAuB,GAAG,QAAQ;AAClE,QAAM,SAAS,KAAK,UAAU,IAAI,WAAW;AAE7C,MAAI;AACJ,MAAI,QAAQ,KAAK;AAEjB,WAAS,UAAU,GAAG,WAAW,KAAK,aAAa,WAAW;AAC5D,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,OAAO;AACd,kBAAY,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAGpE,UAAI,KAAK,UAAU,SAAS,GAAG;AAC7B,eAAO,MAAM,uCAAuC;AAAA,UAClD;AAAA,UACA,OAAO;AAAA,QACT,CAAC;AACD,cAAM;AAAA,MACR;AAGA,UAAI,KAAK,WAAW,CAAC,KAAK,QAAQ,SAAS,GAAG;AAC5C,eAAO,MAAM,uCAAuC;AAAA,UAClD;AAAA,UACA,OAAO;AAAA,QACT,CAAC;AACD,cAAM;AAAA,MACR;AAGA,UAAI,WAAW,KAAK,aAAa;AAC/B,eAAO,KAAK,gCAAgC;AAAA,UAC1C,UAAU;AAAA,UACV,OAAO;AAAA,QACT,CAAC;AACD,cAAM;AAAA,MACR;AAGA,cAAQ,eAAe,SAAS,IAAI;AAEpC,aAAO,MAAM,sBAAsB;AAAA,QACjC;AAAA,QACA,aAAa,KAAK;AAAA,QAClB;AAAA,QACA,OAAO;AAAA,MACT,CAAC;AAGD,WAAK,UAAU,WAAW,SAAS,KAAK;AAGxC,YAAM,MAAM,KAAK;AAAA,IACnB;AAAA,EACF;AAGA,QAAM,aAAa,IAAI,MAAM,4BAA4B;AAC3D;AAKA,eAAsB,gBACpB,IACA,UAAiC,CAAC,GACT;AACzB,QAAM,OAAqB,EAAE,GAAG,uBAAuB,GAAG,QAAQ;AAClE,QAAM,YAAY,KAAK,IAAI;AAE3B,MAAI,WAAW;AACf,MAAI;AACJ,MAAI,QAAQ,KAAK;AAEjB,WAAS,UAAU,GAAG,WAAW,KAAK,aAAa,WAAW;AAC5D,eAAW;AAEX,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,aAAO;AAAA,QACL,SAAS;AAAA,QACT;AAAA,QACA;AAAA,QACA,WAAW,KAAK,IAAI,IAAI;AAAA,MAC1B;AAAA,IACF,SAAS,OAAO;AACd,kBAAY,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAEpE,UAAI,KAAK,UAAU,SAAS,GAAG;AAC7B;AAAA,MACF;AAEA,UAAI,KAAK,WAAW,CAAC,KAAK,QAAQ,SAAS,GAAG;AAC5C;AAAA,MACF;AAEA,UAAI,WAAW,KAAK,aAAa;AAC/B;AAAA,MACF;AAEA,cAAQ,eAAe,SAAS,IAAI;AACpC,WAAK,UAAU,WAAW,SAAS,KAAK;AACxC,YAAM,MAAM,KAAK;AAAA,IACnB;AAAA,EACF;AAEA,SAAO;AAAA,IACL,SAAS;AAAA,IACT,OAAO;AAAA,IACP;AAAA,IACA,WAAW,KAAK,IAAI,IAAI;AAAA,EAC1B;AACF;AAKO,SAAS,UACd,IACA,UAAiC,CAAC,GACI;AACtC,SAAO,IAAI,SAAgB,UAAU,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO;AACjE;AAKO,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA,EAI7B,eAAe,CAAC,UAA0B;AACxC,UAAM,oBAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,UAAM,YAAa,MAAgC;AACnD,QAAI,aAAa,kBAAkB,SAAS,SAAS,GAAG;AACtD,aAAO;AAAA,IACT;AAGA,UAAM,UAAU,MAAM,QAAQ,YAAY;AAC1C,WACE,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,SAAS,KAC1B,QAAQ,SAAS,YAAY,KAC7B,QAAQ,SAAS,QAAQ;AAAA,EAE7B;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,CAAC,UAA0B;AACvC,UAAM,aAAc,MAA0C;AAC9D,WAAO,eAAe,UAAa,cAAc,OAAO,aAAa;AAAA,EACvE;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,CAAC,UAA0B;AAC1C,UAAM,aAAc,MAA0C;AAC9D,WAAO,eAAe;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,CAAC,UAA0B;AACzC,UAAM,UAAU,MAAM,QAAQ,YAAY;AAC1C,WAAO,QAAQ,SAAS,UAAU,KAAK,QAAQ,SAAS,mBAAmB;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAsB,CAAC,UAA0B;AAC/C,UAAM,aAAc,MAA0C;AAC9D,WAAO,eAAe,OAAO,eAAe;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAkB,CAAC,UAA0B;AAC3C,UAAM,aAAc,MAA0C;AAC9D,WAAO,eAAe,OAAO,eAAe;AAAA,EAC9C;AACF;AAKO,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA,EAI1B,MAAM;AAAA,IACJ,aAAa;AAAA,IACb,WAAW;AAAA,IACX,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,WAAW;AAAA,IACX,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY;AAAA,IACV,aAAa;AAAA,IACb,WAAW;AAAA,IACX,UAAU;AAAA,IACV,mBAAmB;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa;AAAA,IACX,aAAa;AAAA,IACb,WAAW;AAAA,IACX,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,QAAQ;AAAA,IACR,WAAW;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU;AAAA,IACR,aAAa;AAAA,IACb,WAAW;AAAA,IACX,UAAU;AAAA,IACV,mBAAmB;AAAA,IACnB,SAAS,CAAC,UACR,gBAAgB,cAAc,KAAK,KAAK,gBAAgB,eAAe,KAAK;AAAA,IAC9E,SAAS,gBAAgB;AAAA,EAC3B;AACF;;;ACxTO,IAAM,kCAAuE;AAAA,EAClF,kBAAkB;AAAA,EAClB,cAAc;AAAA,EACd,kBAAkB;AAAA,EAClB,eAAe;AACjB;AAKO,IAAM,mBAAN,cAA+B,MAAM;AAAA,EACxB,OAAO;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,aAAqB,OAAqB,cAAsB;AAC1E,UAAM,YAAY,WAAW,QAAQ,KAAK,iBAAiB,YAAY,KAAK;AAC5E,SAAK,cAAc;AACnB,SAAK,QAAQ;AACb,SAAK,gBAAgB,IAAI,KAAK,KAAK,IAAI,IAAI,YAAY;AAAA,EACzD;AACF;AAmBO,IAAM,iBAAN,MAAqB;AAAA,EAClB,QAAsB;AAAA,EACtB,WAAmB;AAAA,EACnB,YAAoB;AAAA,EACpB,oBAA8B,CAAC;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,gBAAwB;AAAA,EACxB,mBAA2B;AAAA,EAC3B;AAAA,EACS;AAAA,EACA;AAAA,EAEjB,YAAY,SAAgC;AAC1C,SAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,SAAK,SAAS,QAAQ,UAAU,IAAI,WAAW;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAW,IAAkC;AACjD,SAAK;AAGL,QAAI,CAAC,KAAK,WAAW,GAAG;AACtB,WAAK;AACL,WAAK,QAAQ,WAAW,KAAK,KAAK;AAElC,YAAM,IAAI;AAAA,QACR,KAAK,QAAQ;AAAA,QACb,KAAK;AAAA,QACL,KAAK,oBAAoB;AAAA,MAC3B;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,WAAK,UAAU;AACf,aAAO;AAAA,IACT,SAAS,OAAO;AACd,WAAK,UAAU,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC,CAAC;AACxE,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAsB;AACpB,YAAQ,KAAK,OAAO;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,MAET,KAAK;AAEH,YAAI,KAAK,mBAAmB,GAAG;AAC7B,eAAK,aAAa,WAAW;AAC7B,iBAAO;AAAA,QACT;AACA,eAAO;AAAA,MAET,KAAK;AAEH,eAAO;AAAA,MAET;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,YAAkB;AACxB,SAAK,cAAc,oBAAI,KAAK;AAC5B,SAAK;AAEL,YAAQ,KAAK,OAAO;AAAA,MAClB,KAAK;AAEH,YAAI,KAAK,aAAa,KAAK,QAAQ,kBAAkB;AACnD,eAAK,aAAa,QAAQ;AAAA,QAC5B;AACA;AAAA,MAEF,KAAK;AAEH,aAAK,WAAW;AAChB,aAAK,oBAAoB,CAAC;AAC1B;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,UAAU,OAAoB;AAEpC,QAAI,KAAK,QAAQ,cAAc,CAAC,KAAK,QAAQ,WAAW,KAAK,GAAG;AAC9D;AAAA,IACF;AAEA,SAAK,YAAY;AACjB,SAAK,cAAc,oBAAI,KAAK;AAC5B,SAAK;AAEL,UAAM,MAAM,KAAK,IAAI;AACrB,SAAK,kBAAkB,KAAK,GAAG;AAG/B,UAAM,cAAc,MAAM,KAAK,QAAQ;AACvC,SAAK,oBAAoB,KAAK,kBAAkB,OAAO,CAAC,OAAO,KAAK,WAAW;AAE/E,YAAQ,KAAK,OAAO;AAAA,MAClB,KAAK;AAEH,YAAI,KAAK,kBAAkB,UAAU,KAAK,QAAQ,kBAAkB;AAClE,eAAK,aAAa,MAAM;AACxB,eAAK,QAAQ,SAAS,KAAK,UAAU,KAAK;AAAA,QAC5C;AACA;AAAA,MAEF,KAAK;AAEH,aAAK,aAAa,MAAM;AACxB,aAAK,QAAQ,SAAS,KAAK,UAAU,KAAK;AAC1C;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,UAA8B;AACjD,UAAM,WAAW,KAAK;AAEtB,QAAI,aAAa,SAAU;AAE3B,SAAK,QAAQ;AACb,SAAK,kBAAkB,oBAAI,KAAK;AAEhC,SAAK,OAAO,KAAK,YAAY,KAAK,QAAQ,IAAI,kBAAkB;AAAA,MAC9D,MAAM;AAAA,MACN,IAAI;AAAA,MACJ,UAAU,KAAK;AAAA,MACf,WAAW,KAAK;AAAA,IAClB,CAAC;AAED,SAAK,QAAQ,gBAAgB,UAAU,QAAQ;AAE/C,YAAQ,UAAU;AAAA,MAChB,KAAK;AACH,aAAK,eAAe,oBAAI,KAAK;AAC7B,aAAK,YAAY;AACjB;AAAA,MAEF,KAAK;AACH,aAAK,YAAY;AACjB;AAAA,MAEF,KAAK;AACH,aAAK,WAAW;AAChB,aAAK,oBAAoB,CAAC;AAC1B,aAAK,YAAY;AACjB,aAAK,QAAQ,UAAU;AACvB;AAAA,IACJ;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,qBAA8B;AACpC,QAAI,CAAC,KAAK,aAAc,QAAO;AAE/B,UAAM,UAAU,KAAK,IAAI,IAAI,KAAK,aAAa,QAAQ;AACvD,WAAO,WAAW,KAAK,QAAQ;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKQ,sBAA8B;AACpC,QAAI,CAAC,KAAK,aAAc,QAAO;AAE/B,UAAM,UAAU,KAAK,IAAI,IAAI,KAAK,aAAa,QAAQ;AACvD,WAAO,KAAK,IAAI,GAAG,KAAK,QAAQ,eAAe,OAAO;AAAA,EACxD;AAAA;AAAA;AAAA;AAAA,EAKA,WAAyB;AACvB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,WAAgC;AAC9B,WAAO;AAAA,MACL,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,WAAW,KAAK;AAAA,MAChB,aAAa,KAAK;AAAA,MAClB,aAAa,KAAK;AAAA,MAClB,iBAAiB,KAAK;AAAA,MACtB,eAAe,KAAK;AAAA,MACpB,kBAAkB,KAAK;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,aAAa,QAAQ;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,SAAK,aAAa,MAAM;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAkB;AAChB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,WAAoB;AAClB,WAAO,KAAK,UAAU;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAsB;AACpB,WAAO,KAAK,UAAU;AAAA,EACxB;AACF;AAKO,SAAS,qBAAqB,SAAgD;AACnF,SAAO,IAAI,eAAe,OAAO;AACnC;AAKO,IAAM,yBAAN,MAA6B;AAAA,EAC1B,WAAwC,oBAAI,IAAI;AAAA,EACvC;AAAA,EACA;AAAA,EAEjB,YACE,UAGI,CAAC,GACL;AACA,SAAK,SAAS,QAAQ,UAAU,IAAI,WAAW;AAC/C,SAAK,iBAAiB,QAAQ,YAAY,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAc,SAA0D;AAC1E,QAAI,UAAU,KAAK,SAAS,IAAI,IAAI;AAEpC,QAAI,CAAC,SAAS;AACZ,gBAAU,IAAI,eAAe;AAAA,QAC3B,GAAG;AAAA,QACH,GAAG,KAAK;AAAA,QACR,GAAG;AAAA,QACH;AAAA,QACA,QAAQ,SAAS,UAAU,KAAK;AAAA,MAClC,CAAC;AACD,WAAK,SAAS,IAAI,MAAM,OAAO;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QACJ,MACA,IACA,SACY;AACZ,UAAM,UAAU,KAAK,IAAI,MAAM,OAAO;AACtC,WAAO,QAAQ,QAAQ,EAAE;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA,EAKA,cAAmD;AACjD,UAAM,QAA6C,CAAC;AAEpD,eAAW,CAAC,MAAM,OAAO,KAAK,KAAK,UAAU;AAC3C,YAAM,IAAI,IAAI,QAAQ,SAAS;AAAA,IACjC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAiB;AACf,eAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC5C,cAAQ,MAAM;AAAA,IAChB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,MAAM;AAAA,EACtB;AACF;;;ACrcO,IAAM,eAAN,cAA2B,MAAM;AAAA,EACpB,OAAO;AAAA,EAChB;AAAA,EACA;AAAA,EAET,YAAY,WAAmB,SAAiB;AAC9C,UAAM,cAAc,SAAS,qBAAqB,OAAO,IAAI;AAC7D,SAAK,YAAY;AACjB,SAAK,UAAU;AAAA,EACjB;AACF;AAyBA,eAAsB,YACpB,IACA,SACY;AACZ,QAAM,OACJ,OAAO,YAAY,WAAW,EAAE,SAAS,QAAQ,IAAI;AAEvD,QAAM,EAAE,SAAS,YAAY,WAAW,iBAAiB,MAAM,IAAI;AAEnE,SAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,QAAI;AACJ,QAAI,UAAU;AAGd,UAAM,kBAAkB,iBAAiB,IAAI,gBAAgB,IAAI;AAGjE,gBAAY,WAAW,MAAM;AAC3B,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,yBAAiB,MAAM;AACvB,eAAO,IAAI,aAAa,WAAW,OAAO,CAAC;AAAA,MAC7C;AAAA,IACF,GAAG,OAAO;AAGV,OAAG,EACA,KAAK,CAAC,WAAW;AAChB,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,qBAAa,SAAS;AACtB,gBAAQ,MAAM;AAAA,MAChB;AAAA,IACF,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,UAAI,CAAC,SAAS;AACZ,kBAAU;AACV,qBAAa,SAAS;AACtB,eAAO,KAAK;AAAA,MACd;AAAA,IACF,CAAC;AAAA,EACL,CAAC;AACH;AAKO,SAAS,mBACd,IACA,SACsC;AACtC,SAAO,IAAI,SACT,YAAY,MAAM,GAAG,GAAG,IAAI,GAAG,OAAO;AAC1C;AAKA,eAAsB,YACpB,SACA,SACA,WACY;AACZ,QAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,eAAW,MAAM;AACf,aAAO,IAAI,aAAa,aAAa,WAAW,OAAO,CAAC;AAAA,IAC1D,GAAG,OAAO;AAAA,EACZ,CAAC;AAED,SAAO,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC;AAC/C;AAKO,IAAM,kBAAkB;AAAA;AAAA,EAE7B,MAAM;AAAA;AAAA,EAGN,UAAU;AAAA;AAAA,EAGV,KAAK;AAAA;AAAA,EAGL,SAAS;AAAA;AAAA,EAGT,OAAO;AAAA;AAAA,EAGP,KAAK;AACP;;;ACvFO,IAAM,2BAA0D;AAAA,EACrE,eAAe;AAAA,EACf,UAAU;AAAA,EACV,cAAc;AAChB;AAKO,IAAM,wBAAN,cAAoC,MAAM;AAAA,EAC7B,OAAO;AAAA,EAChB;AAAA,EACA;AAAA,EAET,YAAY,cAAsB,QAA4C;AAC5E,UAAM,WAAW;AAAA,MACf,YAAY,aAAa,YAAY;AAAA,MACrC,OAAO,aAAa,YAAY;AAAA,MAChC,SAAS,aAAa,YAAY;AAAA,IACpC;AACA,UAAM,SAAS,MAAM,CAAC;AACtB,SAAK,eAAe;AACpB,SAAK,SAAS;AAAA,EAChB;AACF;AA8BO,IAAM,WAAN,MAAe;AAAA,EACZ,cAAc;AAAA,EACd,QAAkC,CAAC;AAAA,EACnC,kBAAkB;AAAA,EAClB,gBAAgB;AAAA,EACP;AAAA,EAEA;AAAA,EAEjB,YAAY,SAA0B;AACpC,SAAK,UAAU;AAAA,MACb,GAAG;AAAA,MACH,GAAG;AAAA,IACL;AACA,SAAK,SAAS,QAAQ,UAAU,IAAI,WAAW;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QAAW,IAAkC;AACjD,SAAK;AAGL,QAAI,KAAK,cAAc,KAAK,QAAQ,eAAe;AACjD,aAAO,KAAK,aAAa,EAAE;AAAA,IAC7B;AAGA,QAAI,KAAK,MAAM,UAAU,KAAK,QAAQ,UAAU;AAC9C,WAAK;AACL,WAAK,QAAQ,WAAW,OAAO;AAC/B,YAAM,IAAI,sBAAsB,KAAK,QAAQ,MAAM,OAAO;AAAA,IAC5D;AAGA,WAAO,KAAK,eAAe,EAAE;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAAgB,IAAkC;AAC9D,SAAK;AAEL,QAAI;AACF,YAAM,SAAS,MAAM,GAAG;AACxB,aAAO;AAAA,IACT,UAAE;AACA,WAAK;AACL,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAkB,IAAkC;AAC1D,WAAO,IAAI,QAAW,CAAC,SAAS,WAAW;AACzC,YAAM,UAA4B;AAAA,QAChC;AAAA,QACA;AAAA,QACA;AAAA,QACA,YAAY,KAAK,IAAI;AAAA,MACvB;AAGA,cAAQ,YAAY,WAAW,MAAM;AACnC,cAAM,QAAQ,KAAK,MAAM,QAAQ,OAAiC;AAClE,YAAI,UAAU,IAAI;AAChB,eAAK,MAAM,OAAO,OAAO,CAAC;AAC1B,eAAK;AACL,eAAK,QAAQ,WAAW,SAAS;AACjC,iBAAO,IAAI,sBAAsB,KAAK,QAAQ,MAAM,SAAS,CAAC;AAAA,QAChE;AAAA,MACF,GAAG,KAAK,QAAQ,YAAY;AAE5B,WAAK,MAAM,KAAK,OAAiC;AAEjD,WAAK,OAAO,MAAM,+BAA+B,KAAK,QAAQ,IAAI,KAAK;AAAA,QACrE,WAAW,KAAK,MAAM;AAAA,QACtB,aAAa,KAAK;AAAA,MACpB,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKQ,eAAqB;AAC3B,WAAO,KAAK,cAAc,KAAK,QAAQ,iBAAiB,KAAK,MAAM,SAAS,GAAG;AAC7E,YAAM,UAAU,KAAK,MAAM,MAAM;AACjC,UAAI,CAAC,QAAS;AAGd,UAAI,QAAQ,WAAW;AACrB,qBAAa,QAAQ,SAAS;AAAA,MAChC;AAGA,WAAK;AAEL,cACG,GAAG,EACH,KAAK,CAAC,WAAW;AAChB,gBAAQ,QAAQ,MAAM;AAAA,MACxB,CAAC,EACA,MAAM,CAAC,UAAU;AAChB,gBAAQ,OAAO,KAAK;AAAA,MACtB,CAAC,EACA,QAAQ,MAAM;AACb,aAAK;AACL,aAAK,aAAa;AAAA,MACpB,CAAC;AAAA,IACL;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAA0B;AACxB,WAAO;AAAA,MACL,aAAa,KAAK;AAAA,MAClB,aAAa,KAAK,MAAM;AAAA,MACxB,eAAe,KAAK,QAAQ;AAAA,MAC5B,UAAU,KAAK,QAAQ;AAAA,MACvB,iBAAiB,KAAK;AAAA,MACtB,eAAe,KAAK;AAAA,MACpB,gBAAgB,KAAK,IAAI,GAAG,KAAK,QAAQ,gBAAgB,KAAK,WAAW;AAAA,MACzE,qBAAqB,KAAK,IAAI,GAAG,KAAK,QAAQ,WAAW,KAAK,MAAM,MAAM;AAAA,IAC5E;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,eAAwB;AACtB,WAAO,KAAK,eAAe,KAAK,QAAQ;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,cAAuB;AACrB,WAAO,KAAK,MAAM,UAAU,KAAK,QAAQ;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,eAAW,WAAW,KAAK,OAAO;AAChC,UAAI,QAAQ,WAAW;AACrB,qBAAa,QAAQ,SAAS;AAAA,MAChC;AACA,cAAQ,OAAO,IAAI,sBAAsB,KAAK,QAAQ,MAAM,OAAO,CAAC;AAAA,IACtE;AACA,SAAK,QAAQ,CAAC;AAAA,EAChB;AACF;AAKO,SAAS,eAAe,SAAoC;AACjE,SAAO,IAAI,SAAS,OAAO;AAC7B;AAKO,IAAM,mBAAN,MAAuB;AAAA,EACpB,YAAmC,oBAAI,IAAI;AAAA,EAClC;AAAA,EACA;AAAA,EAEjB,YACE,UAGI,CAAC,GACL;AACA,SAAK,SAAS,QAAQ,UAAU,IAAI,WAAW;AAC/C,SAAK,iBAAiB,QAAQ,YAAY,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,MAAc,SAA8C;AAC9D,QAAI,WAAW,KAAK,UAAU,IAAI,IAAI;AAEtC,QAAI,CAAC,UAAU;AACb,iBAAW,IAAI,SAAS;AAAA,QACtB,GAAG;AAAA,QACH,GAAG,KAAK;AAAA,QACR,GAAG;AAAA,QACH;AAAA,QACA,QAAQ,SAAS,UAAU,KAAK;AAAA,MAClC,CAAC;AACD,WAAK,UAAU,IAAI,MAAM,QAAQ;AAAA,IACnC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,QACJ,MACA,IACA,SACY;AACZ,UAAM,WAAW,KAAK,IAAI,MAAM,OAAO;AACvC,WAAO,SAAS,QAAQ,EAAE;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA,EAKA,cAA6C;AAC3C,UAAM,QAAuC,CAAC;AAE9C,eAAW,CAAC,MAAM,QAAQ,KAAK,KAAK,WAAW;AAC7C,YAAM,IAAI,IAAI,SAAS,SAAS;AAAA,IAClC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAAiB;AACf,eAAW,YAAY,KAAK,UAAU,OAAO,GAAG;AAC9C,eAAS,MAAM;AAAA,IACjB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS;AACd,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;;;AC1RA,eAAsB,aACpB,IACA,SACY;AACZ,QAAM,SAAS,QAAQ,UAAU,IAAI,WAAW;AAEhD,MAAI;AACF,WAAO,MAAM,GAAG;AAAA,EAClB,SAAS,OAAO;AACd,UAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAGpE,QAAI,QAAQ,eAAe,GAAG,GAAG;AAC/B,YAAM;AAAA,IACR;AAEA,WAAO,KAAK,oCAAoC;AAAA,MAC9C,OAAO;AAAA,IACT,CAAC;AAGD,QAAI;AAEJ,QAAI,QAAQ,YAAY;AACtB,sBAAgB,MAAM,QAAQ,WAAW,GAAG;AAAA,IAC9C,WAAW,QAAQ,UAAU,QAAW;AACtC,sBAAgB,QAAQ;AAAA,IAC1B,OAAO;AAEL,YAAM;AAAA,IACR;AAEA,YAAQ,aAAa,KAAK,aAAa;AAEvC,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,mBACpB,IACA,SAC4B;AAC5B,QAAM,SAAS,QAAQ,UAAU,IAAI,WAAW;AAEhD,MAAI;AACF,UAAM,QAAQ,MAAM,GAAG;AACvB,WAAO;AAAA,MACL;AAAA,MACA,cAAc;AAAA,IAChB;AAAA,EACF,SAAS,OAAO;AACd,UAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAEpE,QAAI,QAAQ,eAAe,GAAG,GAAG;AAC/B,YAAM;AAAA,IACR;AAEA,WAAO,KAAK,oCAAoC;AAAA,MAC9C,OAAO;AAAA,IACT,CAAC;AAED,QAAI;AAEJ,QAAI,QAAQ,YAAY;AACtB,sBAAgB,MAAM,QAAQ,WAAW,GAAG;AAAA,IAC9C,WAAW,QAAQ,UAAU,QAAW;AACtC,sBAAgB,QAAQ;AAAA,IAC1B,OAAO;AACL,YAAM;AAAA,IACR;AAEA,YAAQ,aAAa,KAAK,aAAa;AAEvC,WAAO;AAAA,MACL,OAAO;AAAA,MACP,cAAc;AAAA,MACd,OAAO;AAAA,IACT;AAAA,EACF;AACF;AAKO,SAAS,qBACd,SAKkB;AAClB,QAAM,EAAE,UAAU,WAAW,IAAM,IAAI;AACvC,QAAM,SAAS,QAAQ,UAAU,IAAI,WAAW;AAEhD,MAAI;AACJ,MAAI;AACJ,MAAI,aAAa;AAEjB,SAAO,YAAwB;AAE7B,QAAI,gBAAgB,UAAa,aAAa,QAAW;AACvD,YAAM,MAAM,KAAK,IAAI,IAAI;AACzB,UAAI,MAAM,UAAU;AAClB,eAAO;AAAA,MACT;AAGA,UAAI,CAAC,YAAY;AACf,qBAAa;AACb,iBAAS,EACN,KAAK,CAACC,WAAU;AACf,wBAAcA;AACd,qBAAW,KAAK,IAAI;AAAA,QACtB,CAAC,EACA,MAAM,CAAC,QAAQ;AACd,gBAAM,QAAQ,eAAe,QAAQ,MAAM,IAAI,MAAM,OAAO,GAAG,CAAC;AAChE,iBAAO,KAAK,qCAAqC;AAAA,YAC/C;AAAA,UACF,CAAC;AAAA,QACH,CAAC,EACA,QAAQ,MAAM;AACb,uBAAa;AAAA,QACf,CAAC;AAAA,MACL;AAGA,aAAO;AAAA,IACT;AAGA,UAAM,QAAQ,MAAM,SAAS;AAC7B,kBAAc;AACd,eAAW,KAAK,IAAI;AACpB,WAAO;AAAA,EACT;AACF;AAKA,eAAsB,kBACpB,SACA,WACA,UAGI,CAAC,GACO;AACZ,QAAM,SAAS,QAAQ,UAAU,IAAI,WAAW;AAChD,QAAM,SAAS,CAAC,SAAS,GAAG,SAAS;AAErC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,QAAI;AACF,YAAM,KAAK,OAAO,CAAC;AACnB,UAAI,CAAC,GAAI;AACT,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,OAAO;AACd,YAAM,MAAM,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAEpE,UAAI,IAAI,OAAO,SAAS,GAAG;AACzB,eAAO,KAAK,YAAY,CAAC,wBAAwB;AAAA,UAC/C,OAAO;AAAA,UACP,OAAO;AAAA,QACT,CAAC;AACD,gBAAQ,aAAa,GAAG,GAAG;AAAA,MAC7B,OAAO;AAEL,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAGA,QAAM,IAAI,MAAM,yBAAyB;AAC3C;AAKO,IAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA,EAIhC,YAAY,OAAgC;AAAA,IAC1C,OAAO,CAAC;AAAA,EACV;AAAA;AAAA;AAAA;AAAA,EAKA,UAAU,OAAqC;AAAA,IAC7C,OAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,CAAI,WAAkC;AAAA,IAClD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,CACT,WACA,kBACwB;AAAA,IACxB,YAAY,YAAY;AACtB,YAAM,SAAS,MAAM,UAAU;AAC/B,aAAO,UAAU;AAAA,IACnB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,CACP,iBACwB;AAAA,IACxB,YAAY;AAAA,EACd;AACF;;;AC9JO,SAAS,sBACd,UACA,UAAkC,CAAC,GAClB;AACjB,QAAM;AAAA,IACJ,UAAU,QAAQ,IAAI,uBAAuB,QAAQ,IAAI,eAAe;AAAA,IACxE,cAAc,QAAQ,IAAI,YAAY;AAAA,IACtC,uBAAuB;AAAA,IACvB,eAAe,CAAC;AAAA,IAChB,eAAe;AAAA,EACjB,IAAI;AAEJ,QAAM,YAAY,KAAK,IAAI;AAC3B,MAAI,kBAAkB;AACtB,MAAI,kBAA+C;AACnD,MAAI,gBAAgB;AAGpB,QAAM,YAAY;AAElB,iBAAe,kBAAiD;AAC9D,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,mBAAmB,MAAM,gBAAgB,WAAW;AACtD,aAAO;AAAA,IACT;AAEA,sBAAkB,MAAMC,aAAY,SAAS,YAAY,GAAG,YAAY;AACxE,oBAAgB;AAChB,WAAO;AAAA,EACT;AAEA,iBAAe,wBACb,SACwB;AACxB,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACF,YAAM,UAAU,MAAMA,aAAY,QAAQ,GAAG,YAAY;AACzD,aAAO;AAAA,QACL,QAAQ,UAAU,YAAY;AAAA,QAC9B,WAAW,KAAK,IAAI,IAAI;AAAA,QACxB,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL,QAAQ;AAAA,QACR,WAAW,KAAK,IAAI,IAAI;AAAA,QACxB,SAAS,iBAAiB,QAAQ,MAAM,UAAU;AAAA,QAClD,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,MACtC;AAAA,IACF;AAAA,EACF;AAEA,WAAS,aAAa,IAAoB;AACxC,UAAM,UAAU,KAAK,MAAM,KAAK,GAAI;AACpC,UAAM,UAAU,KAAK,MAAM,UAAU,EAAE;AACvC,UAAM,QAAQ,KAAK,MAAM,UAAU,EAAE;AACrC,UAAM,OAAO,KAAK,MAAM,QAAQ,EAAE;AAElC,QAAI,OAAO,EAAG,QAAO,GAAG,IAAI,KAAK,QAAQ,EAAE,KAAK,UAAU,EAAE;AAC5D,QAAI,QAAQ,EAAG,QAAO,GAAG,KAAK,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE;AAChE,QAAI,UAAU,EAAG,QAAO,GAAG,OAAO,KAAK,UAAU,EAAE;AACnD,WAAO,GAAG,OAAO;AAAA,EACnB;AAEA,WAAS,mBAAmB;AAC1B,QAAI,CAAC,qBAAsB,QAAO;AAElC,UAAM,cAAc,QAAQ,YAAY;AAExC,WAAO;AAAA,MACL,aAAa;AAAA,QACX,UAAU,YAAY;AAAA,QACtB,WAAW,YAAY;AAAA,QACvB,UAAU,YAAY;AAAA,QACtB,KAAK,YAAY;AAAA,MACnB;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,OAAkC;AAEtC,aAAO,EAAE,QAAQ,KAAK;AAAA,IACxB;AAAA,IAEA,MAAM,QAAoC;AACxC,UAAI;AACF,cAAM,SAAS,MAAM,gBAAgB;AAGrC,cAAM,gBAAyC,CAAC;AAChD,mBAAW,CAAC,MAAM,KAAK,KAAK,OAAO,QAAQ,YAAY,GAAG;AACxD,cAAI;AACF,0BAAc,IAAI,IAAI,MAAMA,aAAY,MAAM,GAAG,YAAY;AAAA,UAC/D,QAAQ;AACN,0BAAc,IAAI,IAAI;AAAA,UACxB;AAAA,QACF;AAEA,cAAM,mBAAmB,OAAO,OAAO,aAAa,EAAE,MAAM,OAAO;AAEnE,eAAO;AAAA,UACL,QAAQ,OAAO,WAAW,mBAAmB,OAAO;AAAA,UACpD,QAAQ;AAAA,YACN,UAAU,OAAO,SAAS;AAAA,YAC1B,OAAO,OAAO,SAAS;AAAA,YACvB,SAAS,OAAO,SAAS;AAAA,YACzB,OAAO,OAAO,SAAS;AAAA,YACvB,OAAO,OAAO,SAAS;AAAA,YACvB,GAAG;AAAA,UACL;AAAA,QACF;AAAA,MACF,QAAQ;AACN,eAAO;AAAA,UACL,QAAQ;AAAA,UACR,QAAQ;AAAA,YACN,UAAU;AAAA,YACV,OAAO;AAAA,YACP,SAAS;AAAA,YACT,OAAO;AAAA,YACP,OAAO;AAAA,UACT;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,IAEA,MAAM,UAAoC;AACxC,UAAI,iBAAiB;AACnB,eAAO,EAAE,QAAQ,MAAM,OAAO,KAAK;AAAA,MACrC;AAGA,UAAI;AACF,cAAM,SAAS,MAAM,gBAAgB;AACrC,YAAI,OAAO,SAAS;AAClB,4BAAkB;AAClB,iBAAO,EAAE,QAAQ,MAAM,OAAO,KAAK;AAAA,QACrC;AAAA,MACF,QAAQ;AAAA,MAER;AAEA,aAAO,EAAE,QAAQ,SAAS,OAAO,MAAM;AAAA,IACzC;AAAA,IAEA,MAAM,WAA4C;AAChD,YAAM,SAAS,KAAK,IAAI,IAAI;AAG5B,YAAM,CAAC,UAAU,aAAa,eAAe,aAAa,WAAW,IAAI,MAAM,QAAQ,IAAI;AAAA,QACzF,wBAAwB,MAAM,SAAS,GAAG,YAAY,CAAC;AAAA,QACvD,wBAAwB,MAAM,SAAS,MAAM,YAAY,CAAC;AAAA,QAC1D,wBAAwB,MAAM,SAAS,QAAQ,YAAY,CAAC;AAAA,QAC5D,wBAAwB,MAAM,SAAS,MAAM,YAAY,CAAC;AAAA,QAC1D,wBAAwB,MAAM,SAAS,MAAM,YAAY,CAAC;AAAA,MAC5D,CAAC;AAED,YAAM,WAAW;AAAA,QACf,UAAU;AAAA,QACV,OAAO;AAAA,QACP,SAAS;AAAA,QACT,OAAO;AAAA,QACP,OAAO;AAAA,MACT;AAGA,YAAM,WAAW,OAAO,OAAO,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,MAAM;AAC5D,UAAI,gBAA8B;AAElC,UAAI,SAAS,KAAK,CAAC,MAAM,MAAM,WAAW,GAAG;AAC3C,wBAAgB;AAAA,MAClB,WAAW,SAAS,KAAK,CAAC,MAAM,MAAM,UAAU,GAAG;AACjD,wBAAgB;AAAA,MAClB;AAEA,aAAO;AAAA,QACL,QAAQ;AAAA,QACR;AAAA,QACA;AAAA,QACA;AAAA,QACA,iBAAiB,aAAa,MAAM;AAAA,QACpC,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QAClC;AAAA,QACA,QAAQ,iBAAiB;AAAA,MAC3B;AAAA,IACF;AAAA,IAEA,sBAA4B;AAC1B,wBAAkB;AAAA,IACpB;AAAA,IAEA,MAAM,eAA8C;AAClD,aAAO,gBAAgB;AAAA,IACzB;AAAA,EACF;AACF;AAMA,eAAeA,aAAe,SAAqB,WAA+B;AAChF,MAAI;AAEJ,QAAM,iBAAiB,IAAI,QAAe,CAAC,GAAG,WAAW;AACvD,oBAAgB,WAAW,MAAM;AAC/B,aAAO,IAAI,MAAM,gCAAgC,SAAS,IAAI,CAAC;AAAA,IACjE,GAAG,SAAS;AAAA,EACd,CAAC;AAED,MAAI;AACF,WAAO,MAAM,QAAQ,KAAK,CAAC,SAAS,cAAc,CAAC;AAAA,EACrD,UAAE;AACA,iBAAa,aAAc;AAAA,EAC7B;AACF;AASO,SAAS,4BAA4B,WAA4B;AACtE,SAAO;AAAA,IACL,MAAM,OAAO,MAAe,QAAyE;AACnG,YAAM,SAAS,MAAM,UAAU,KAAK;AACpC,UAAI,OAAO,OAAO,WAAW,OAAO,MAAM,GAAG,EAAE,KAAK,MAAM;AAAA,IAC5D;AAAA,IAEA,OAAO,OAAO,MAAe,QAAyE;AACpG,YAAM,SAAS,MAAM,UAAU,MAAM;AACrC,UAAI,OAAO,OAAO,WAAW,OAAO,MAAM,GAAG,EAAE,KAAK,MAAM;AAAA,IAC5D;AAAA,IAEA,SAAS,OAAO,MAAe,QAAyE;AACtG,YAAM,SAAS,MAAM,UAAU,QAAQ;AACvC,UAAI,OAAO,OAAO,WAAW,OAAO,MAAM,GAAG,EAAE,KAAK,MAAM;AAAA,IAC5D;AAAA,IAEA,UAAU,OAAO,MAAe,QAAyE;AACvG,YAAM,SAAS,MAAM,UAAU,SAAS;AACxC,YAAM,aAAa,OAAO,WAAW,YAAY,MAAM,OAAO,WAAW,aAAa,MAAM;AAC5F,UAAI,OAAO,UAAU,EAAE,KAAK,MAAM;AAAA,IACpC;AAAA,EACF;AACF;AAKA,eAAsB,mBACpB,WACA,OAAe,MAC0B;AACzC,QAAM,OAAO,MAAM,OAAO,MAAM;AAEhC,QAAM,SAAS,KAAK,aAAa,OAAO,KAAK,QAAQ;AACnD,UAAM,MAAM,IAAI,OAAO;AAEvB,QAAI,UAAU,gBAAgB,kBAAkB;AAEhD,QAAI;AACF,UAAI;AACJ,UAAI,aAAa;AAEjB,cAAQ,KAAK;AAAA,QACX,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,UAAU,KAAK;AAC9B,uBAAc,OAA4B,WAAW,OAAO,MAAM;AAClE;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,UAAU,MAAM;AAC/B,uBAAc,OAA6B,WAAW,OAAO,MAAM;AACnE;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,UAAU,QAAQ;AACjC,uBAAc,OAA2B,WAAW,OAAO,MAAM;AACjE;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,UAAU,SAAS;AAClC,gBAAM,WAAW;AACjB,uBAAa,SAAS,WAAW,YAAY,MAAM,SAAS,WAAW,aAAa,MAAM;AAC1F;AAAA,QAEF;AACE,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,KAAK,UAAU,EAAE,OAAO,YAAY,CAAC,CAAC;AAC9C;AAAA,MACJ;AAEA,UAAI,UAAU,UAAU;AACxB,UAAI,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,IAChC,SAAS,OAAO;AACd,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF,CAAC;AAED,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,WAAO,OAAO,MAAM,MAAM;AACxB,cAAQ;AAAA,QACN,OAAO,MACL,IAAI,QAAc,CAAC,QAAQ;AACzB,iBAAO,MAAM,MAAM,IAAI,CAAC;AAAA,QAC1B,CAAC;AAAA,MACL,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;;;AClYA,SAAS,mBAAmB,MAAsB;AAEhD,SAAO,KACJ,QAAQ,SAAS,GAAG,EACpB,QAAQ,mBAAmB,EAAE,EAC7B,QAAQ,YAAY,KAAK;AAC9B;AAEA,SAAS,aAAa,QAAwC;AAC5D,QAAM,UAAU,OAAO,QAAQ,MAAM;AACrC,MAAI,QAAQ,WAAW,EAAG,QAAO;AAEjC,QAAM,YAAY,QACf,IAAI,CAAC,CAAC,KAAK,KAAK,MAAM,GAAG,mBAAmB,GAAG,CAAC,KAAK,YAAY,KAAK,CAAC,GAAG,EAC1E,KAAK,GAAG;AAEX,SAAO,IAAI,SAAS;AACtB;AAEA,SAAS,YAAY,OAAuB;AAC1C,SAAO,MACJ,QAAQ,OAAO,MAAM,EACrB,QAAQ,MAAM,KAAK,EACnB,QAAQ,OAAO,KAAK;AACzB;AAEA,SAAS,eAAe,KAA+D;AACrF,QAAM,YAAY,IAAI,QAAQ,GAAG;AACjC,MAAI,cAAc,IAAI;AACpB,WAAO,EAAE,MAAM,KAAK,QAAQ,CAAC,EAAE;AAAA,EACjC;AAEA,QAAM,OAAO,IAAI,UAAU,GAAG,SAAS;AACvC,QAAM,cAAc,IAAI,UAAU,YAAY,CAAC;AAE/C,QAAM,SAAiC,CAAC;AACxC,aAAW,QAAQ,YAAY,MAAM,GAAG,GAAG;AACzC,UAAM,aAAa,KAAK,QAAQ,GAAG;AACnC,QAAI,eAAe,IAAI;AACrB,YAAM,WAAW,KAAK,UAAU,GAAG,UAAU;AAC7C,YAAM,aAAa,KAAK,UAAU,aAAa,CAAC;AAChD,aAAO,QAAQ,IAAI;AAAA,IACrB;AAAA,EACF;AAEA,SAAO,EAAE,MAAM,OAAO;AACxB;AAgBA,SAAS,wBAAwC;AAC/C,QAAM,cAAc,QAAQ,YAAY;AAExC,SAAO;AAAA,IACL,gBAAgB,YAAY;AAAA,IAC5B,iBAAiB,YAAY;AAAA,IAC7B,gBAAgB,YAAY;AAAA,IAC5B,WAAW,YAAY;AAAA,IACvB,eAAe,QAAQ,OAAO;AAAA,EAChC;AACF;AAMO,SAAS,sBACd,SACA,UAAkC,CAAC,GAClB;AACjB,QAAM;AAAA,IACJ,SAAS;AAAA,IACT,gBAAgB,CAAC;AAAA,IACjB,wBAAwB;AAAA,IACxB,mBAAmB,CAAC,MAAO,MAAM,OAAO,MAAM,KAAK,MAAM,KAAK,GAAG,KAAK,GAAG,EAAE;AAAA,EAC7E,IAAI;AAEJ,QAAM,aAAa,CAAC,SAAkB,SAAS,GAAG,MAAM,IAAI,IAAI,KAAK;AAErE,WAAS,sBAAsB,SAAiC;AAC9D,UAAM,QAAkB,CAAC;AAGzB,QAAI,uBAAuB;AACzB,YAAM,iBAAiB,sBAAsB;AAC7C,YAAM,gBAAgB,aAAa,aAAa;AAEhD,YAAM,KAAK,8DAA8D;AACzE,YAAM,KAAK,iCAAiC;AAC5C,YAAM,KAAK,qBAAqB,aAAa,IAAI,eAAe,cAAc,EAAE;AAEhF,YAAM,KAAK,kEAAkE;AAC7E,YAAM,KAAK,uCAAuC;AAClD,YAAM,KAAK,2BAA2B,aAAa,IAAI,eAAe,eAAe,EAAE;AAEvF,YAAM,KAAK,oEAAoE;AAC/E,YAAM,KAAK,uCAAuC;AAClD,YAAM,KAAK,2BAA2B,aAAa,IAAI,eAAe,SAAS,EAAE;AAEjF,YAAM,KAAK,yDAAyD;AACpE,YAAM,KAAK,uCAAuC;AAClD,YAAM,KAAK,yBAAyB,aAAa,IAAI,eAAe,aAAa,EAAE;AAEnF,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,QAAQ,GAAG;AAC3D,YAAM,EAAE,MAAM,OAAO,IAAI,eAAe,GAAG;AAC3C,YAAM,aAAa,mBAAmB,WAAW,IAAI,CAAC;AACtD,YAAM,YAAY,EAAE,GAAG,eAAe,GAAG,OAAO;AAChD,YAAM,WAAW,aAAa,SAAS;AAEvC,YAAM,KAAK,UAAU,UAAU,iBAAiB;AAChD,YAAM,KAAK,UAAU,UAAU,UAAU;AACzC,YAAM,KAAK,GAAG,UAAU,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC9C,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,MAAM,GAAG;AACzD,YAAM,EAAE,MAAM,OAAO,IAAI,eAAe,GAAG;AAC3C,YAAM,aAAa,mBAAmB,WAAW,IAAI,CAAC;AACtD,YAAM,YAAY,EAAE,GAAG,eAAe,GAAG,OAAO;AAChD,YAAM,WAAW,aAAa,SAAS;AAEvC,YAAM,KAAK,UAAU,UAAU,eAAe;AAC9C,YAAM,KAAK,UAAU,UAAU,QAAQ;AACvC,YAAM,KAAK,GAAG,UAAU,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC9C,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,UAAU,GAAG;AAC7D,YAAM,EAAE,MAAM,OAAO,IAAI,eAAe,GAAG;AAC3C,YAAM,aAAa,mBAAmB,WAAW,IAAI,CAAC;AACtD,YAAM,YAAY,EAAE,GAAG,eAAe,GAAG,OAAO;AAEhD,YAAM,KAAK,UAAU,UAAU,mBAAmB;AAClD,YAAM,KAAK,UAAU,UAAU,YAAY;AAI3C,YAAM,WAAW,aAAa,SAAS;AACvC,YAAM,KAAK,GAAG,UAAU,SAAS,QAAQ,IAAI,MAAM,KAAK,EAAE;AAC1D,YAAM,KAAK,GAAG,UAAU,OAAO,QAAQ,IAAI,MAAM,GAAG,EAAE;AACtD,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,YAAM,EAAE,MAAM,OAAO,IAAI,eAAe,GAAG;AAC3C,YAAM,aAAa,mBAAmB,WAAW,IAAI,IAAI,UAAU;AACnE,YAAM,YAAY,EAAE,GAAG,eAAe,GAAG,OAAO;AAEhD,YAAM,KAAK,UAAU,UAAU,0CAA0C;AACzE,YAAM,KAAK,UAAU,UAAU,UAAU;AAGzC,YAAM,aAAa,MAAM,MAAM;AAC/B,YAAM,aAAa,MAAM,MAAM;AAC/B,YAAM,aAAa,MAAM,MAAM;AAC/B,YAAM,aAAa,MAAM,MAAM;AAE/B,YAAM,YAAY,EAAE,GAAG,WAAW,UAAU,MAAM;AAClD,YAAM,YAAY,EAAE,GAAG,WAAW,UAAU,OAAO;AACnD,YAAM,YAAY,EAAE,GAAG,WAAW,UAAU,OAAO;AAEnD,YAAM,KAAK,GAAG,UAAU,GAAG,aAAa,SAAS,CAAC,IAAI,UAAU,EAAE;AAClE,YAAM,KAAK,GAAG,UAAU,GAAG,aAAa,SAAS,CAAC,IAAI,UAAU,EAAE;AAClE,YAAM,KAAK,GAAG,UAAU,GAAG,aAAa,SAAS,CAAC,IAAI,UAAU,EAAE;AAClE,YAAM,KAAK,GAAG,UAAU,SAAS,aAAa,SAAS,CAAC,IAAI,MAAM,KAAK,EAAE;AACzE,YAAM,KAAK,GAAG,UAAU,OAAO,aAAa,SAAS,CAAC,IAAI,UAAU,EAAE;AACtE,YAAM,KAAK,EAAE;AAAA,IACf;AAGA,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,IAAI,GAAG;AACvD,YAAM,EAAE,MAAM,OAAO,IAAI,eAAe,GAAG;AAC3C,YAAM,aAAa,mBAAmB,WAAW,IAAI,IAAI,cAAc;AACvE,YAAM,YAAY,EAAE,GAAG,eAAe,GAAG,OAAO;AAChD,YAAM,WAAW,aAAa,SAAS;AAEvC,YAAM,KAAK,UAAU,UAAU,kCAAkC;AACjE,YAAM,KAAK,UAAU,UAAU,QAAQ;AACvC,YAAM,KAAK,GAAG,UAAU,GAAG,QAAQ,IAAI,KAAK,EAAE;AAC9C,YAAM,KAAK,EAAE;AAAA,IACf;AAEA,WAAO,MAAM,KAAK,IAAI;AAAA,EACxB;AAEA,SAAO;AAAA,IACL,uBAA+B;AAE7B,UAAI,mBAAmB,eAAe;AACpC,cAAM,UAAU,QAAQ,WAAW;AACnC,eAAO,sBAAsB,OAAO;AAAA,MACtC;AAGA,UAAI,uBAAuB;AACzB,cAAM,iBAAiB,sBAAsB;AAC7C,cAAM,gBAAgB,aAAa,aAAa;AAEhD,eAAO;AAAA,UACL;AAAA,UACA;AAAA,UACA,qBAAqB,aAAa,IAAI,eAAe,cAAc;AAAA,UACnE;AAAA,UACA;AAAA,UACA;AAAA,UACA,2BAA2B,aAAa,IAAI,eAAe,eAAe;AAAA,UAC1E;AAAA,UACA;AAAA,UACA;AAAA,UACA,2BAA2B,aAAa,IAAI,eAAe,SAAS;AAAA,UACpE;AAAA,UACA;AAAA,UACA;AAAA,UACA,yBAAyB,aAAa,IAAI,eAAe,aAAa;AAAA,UACtE;AAAA,QACF,EAAE,KAAK,IAAI;AAAA,MACb;AAEA,aAAO;AAAA,IACT;AAAA,IAEA,iBAAiC;AAC/B,UAAI,mBAAmB,eAAe;AACpC,eAAO,QAAQ,WAAW;AAAA,MAC5B;AAEA,aAAO;AAAA,QACL,UAAU,CAAC;AAAA,QACX,QAAQ,CAAC;AAAA,QACT,YAAY,CAAC;AAAA,QACb,SAAS,CAAC;AAAA,QACV,MAAM,CAAC;AAAA,MACT;AAAA,IACF;AAAA,IAEA,aACE,MACA,MACA,OACA,SAAiC,CAAC,GAC5B;AACN,cAAQ,MAAM;AAAA,QACZ,KAAK;AACH,kBAAQ,UAAU,MAAM,OAAO,MAAM;AACrC;AAAA,QACF,KAAK;AACH,kBAAQ,MAAM,MAAM,OAAO,MAAM;AACjC;AAAA,QACF,KAAK;AACH,kBAAQ,UAAU,MAAM,OAAO,MAAM;AACrC;AAAA,MACJ;AAAA,IACF;AAAA,EACF;AACF;AASO,SAAS,4BAA4B,UAA2B;AACrE,SAAO,CAAC,MAAe,QAGjB;AACJ,QAAI,UAAU,gBAAgB,0CAA0C;AACxE,QAAI,OAAO,GAAG,EAAE,KAAK,SAAS,qBAAqB,CAAC;AAAA,EACtD;AACF;AAKA,eAAsB,oBACpB,UACA,OAAe,MACwC;AACvD,QAAM,OAAO,MAAM,OAAO,MAAM;AAEhC,QAAM,SAAS,KAAK,aAAa,CAAC,KAAK,QAAQ;AAC7C,UAAM,MAAM,IAAI,OAAO;AAEvB,QAAI,QAAQ,cAAc,QAAQ,KAAK;AACrC,UAAI,UAAU,gBAAgB,0CAA0C;AACxE,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,SAAS,qBAAqB,CAAC;AAAA,IACzC,WAAW,QAAQ,iBAAiB;AAClC,UAAI,UAAU,gBAAgB,kBAAkB;AAChD,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,KAAK,UAAU,SAAS,eAAe,GAAG,MAAM,CAAC,CAAC;AAAA,IAC5D,OAAO;AACL,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,WAAW;AAAA,IACrB;AAAA,EACF,CAAC;AAED,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,WAAO,OAAO,MAAM,MAAM;AACxB,cAAQ;AAAA,QACN;AAAA,QACA,OAAO,MACL,IAAI,QAAc,CAAC,QAAQ;AACzB,iBAAO,MAAM,MAAM,IAAI,CAAC;AAAA,QAC1B,CAAC;AAAA,MACL,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;AAmBA,eAAsB,0BACpB,iBACA,iBACA,OAAe,MACwC;AACvD,QAAM,OAAO,MAAM,OAAO,MAAM;AAEhC,QAAM,SAAS,KAAK,aAAa,OAAO,KAAK,QAAQ;AACnD,UAAM,MAAM,IAAI,OAAO;AAEvB,QAAI;AAEF,UAAI,QAAQ,YAAY;AACtB,YAAI,UAAU,gBAAgB,0CAA0C;AACxE,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,gBAAgB,qBAAqB,CAAC;AAC9C;AAAA,MACF;AAEA,UAAI,QAAQ,iBAAiB;AAC3B,YAAI,UAAU,gBAAgB,kBAAkB;AAChD,YAAI,UAAU,GAAG;AACjB,YAAI,IAAI,KAAK,UAAU,gBAAgB,eAAe,GAAG,MAAM,CAAC,CAAC;AACjE;AAAA,MACF;AAGA,UAAI,UAAU,gBAAgB,kBAAkB;AAEhD,UAAI;AACJ,UAAI,aAAa;AAEjB,cAAQ,KAAK;AAAA,QACX,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,gBAAgB,KAAK;AACpC,uBAAc,OAA4B,WAAW,OAAO,MAAM;AAClE;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,gBAAgB,MAAM;AACrC,uBAAc,OAA6B,WAAW,OAAO,MAAM;AACnE;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,gBAAgB,QAAQ;AACvC,uBAAc,OAA2B,WAAW,OAAO,MAAM;AACjE;AAAA,QAEF,KAAK;AAAA,QACL,KAAK;AACH,mBAAS,MAAM,gBAAgB,SAAS;AACxC,gBAAM,WAAW;AACjB,uBAAa,SAAS,WAAW,YAAY,MAAM,SAAS,WAAW,aAAa,MAAM;AAC1F;AAAA,QAEF;AACE,cAAI,UAAU,GAAG;AACjB,cAAI,IAAI,KAAK,UAAU,EAAE,OAAO,YAAY,CAAC,CAAC;AAC9C;AAAA,MACJ;AAEA,UAAI,UAAU,UAAU;AACxB,UAAI,IAAI,KAAK,UAAU,MAAM,CAAC;AAAA,IAChC,SAAS,OAAO;AACd,UAAI,UAAU,gBAAgB,kBAAkB;AAChD,UAAI,UAAU,GAAG;AACjB,UAAI,IAAI,KAAK,UAAU,EAAE,OAAO,wBAAwB,CAAC,CAAC;AAAA,IAC5D;AAAA,EACF,CAAC;AAED,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,WAAO,OAAO,MAAM,MAAM;AACxB,cAAQ;AAAA,QACN;AAAA,QACA,OAAO,MACL,IAAI,QAAc,CAAC,QAAQ;AACzB,iBAAO,MAAM,MAAM,IAAI,CAAC;AAAA,QAC1B,CAAC;AAAA,MACL,CAAC;AAAA,IACH,CAAC;AAAA,EACH,CAAC;AACH;;;ACjdA,IAAM,iBAA6C;AAAA,EACjD,OAAO;AAAA,EACP,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AACT;AAEO,IAAM,sBAAN,MAAoD;AAAA,EACjD,UAAyB,CAAC;AAAA,EAC1B,cAA4B,CAAC;AAAA,EAC7B,cAAyE;AAAA,EACzE,WAAiD,oBAAI,IAAI;AAAA,EACzD,OAA4B,oBAAI,IAAI;AAAA,EACpC;AAAA,EAER,YAAY,QAAmC;AAC7C,SAAK,SAAS;AAAA,MACZ,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO,eAAe;AAAA,MACnC,SAAS,OAAO,WAAW;AAAA,MAC3B,aAAa,OAAO,eAAe,CAAC;AAAA,MACpC,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,YAAY,OAAO,cAAc;AAAA,MACjC,YAAY,OAAO,eAAe,CAAC,WAAW;AAAA,MAC9C,YAAY,OAAO,cAAc;AAAA,MACjC,cAAc,OAAO,gBAAgB;AAAA,MACrC,iBAAiB,OAAO,mBAAmB;AAAA,IAC7C;AAGA,QAAI,KAAK,OAAO,oBAAoB,OAAO,YAAY,aAAa;AAClE,cAAQ,GAAG,qBAAqB,CAAC,UAAU;AACzC,aAAK,aAAa,OAAO,EAAE,SAAS,OAAO,OAAO,QAAQ,CAAC;AAAA,MAC7D,CAAC;AAED,cAAQ,GAAG,sBAAsB,CAAC,WAAW;AAC3C,cAAM,QAAQ,kBAAkB,QAAQ,SAAS,IAAI,MAAM,OAAO,MAAM,CAAC;AACzE,aAAK,aAAa,OAAO,EAAE,SAAS,OAAO,OAAO,QAAQ,CAAC;AAAA,MAC7D,CAAC;AAAA,IACH;AAAA,EACF;AAAA,EAEA,aAAa,OAAc,SAAkC;AAE3D,QAAI,KAAK,OAAO,IAAI,KAAK,OAAO,YAAY;AAC1C,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,KAAK,aAAa,OAAO;AACzC,UAAM,SAAS,KAAK,aAAa,OAAO,SAAS,OAAO;AAGxD,UAAM,iBAAiB,KAAK,OAAO,WAAW,MAAM;AACpD,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,IACT;AAGA,mBAAe,cAAc,CAAC,GAAG,KAAK,WAAW;AAGjD,SAAK,YAAY,cAAc;AAG/B,SAAK,aAAa,cAAc;AAEhC,WAAO,eAAe;AAAA,EACxB;AAAA,EAEA,eAAe,SAAiB,SAAkC;AAEhE,QAAI,KAAK,OAAO,IAAI,KAAK,OAAO,YAAY;AAC1C,aAAO;AAAA,IACT;AAEA,UAAM,UAAU,KAAK,aAAa,OAAO;AACzC,UAAM,SAAsB;AAAA,MAC1B,IAAI,gBAAgB;AAAA,MACpB;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,OAAO,SAAS,SAAS;AAAA,MACzB,WAAW,KAAK,IAAI;AAAA,MACpB,SAAS;AAAA,MACT,aAAa,SAAS,eAAe,CAAC,OAAO;AAAA,MAC7C,aAAa,CAAC,GAAG,KAAK,WAAW;AAAA,IACnC;AAGA,UAAM,iBAAiB,KAAK,OAAO,WAAW,MAAM;AACpD,QAAI,CAAC,gBAAgB;AACnB,aAAO;AAAA,IACT;AAGA,SAAK,YAAY,cAAc;AAG/B,SAAK,aAAa,cAAc;AAEhC,WAAO,eAAe;AAAA,EACxB;AAAA,EAEA,cAAc,YAAiD;AAC7D,UAAM,QAAoB;AAAA,MACxB,GAAG;AAAA,MACH,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,YAAY,KAAK,KAAK;AAG3B,QAAI,KAAK,YAAY,SAAS,KAAK,OAAO,gBAAgB;AACxD,WAAK,cAAc,KAAK,YAAY,MAAM,CAAC,KAAK,OAAO,cAAc;AAAA,IACvE;AAAA,EACF;AAAA,EAEA,QAAQ,MAAuE;AAC7E,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,WAAW,MAAc,SAA+C;AACtE,QAAI,YAAY,MAAM;AACpB,WAAK,SAAS,OAAO,IAAI;AAAA,IAC3B,OAAO;AACL,WAAK,SAAS,IAAI,MAAM,OAAO;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,OAAO,KAAa,OAAqB;AACvC,SAAK,KAAK,IAAI,KAAK,KAAK;AAAA,EAC1B;AAAA,EAEA,WAAW,SAAiE;AAC1E,QAAI,UAAU,CAAC,GAAG,KAAK,OAAO;AAG9B,QAAI,SAAS,OAAO;AAClB,YAAM,cAAc,eAAe,QAAQ,KAAK;AAChD,gBAAU,QAAQ,OAAO,CAAC,MAAM,eAAe,EAAE,KAAK,KAAK,WAAW;AAAA,IACxE;AAGA,QAAI,SAAS,OAAO;AAClB,gBAAU,QAAQ,MAAM,CAAC,QAAQ,KAAK;AAAA,IACxC;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,eAAqB;AACnB,SAAK,UAAU,CAAC;AAAA,EAClB;AAAA,EAEA,MAAM,MAAM,UAAqC;AAE/C,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAE3B,SAAK,UAAU,CAAC;AAChB,SAAK,cAAc,CAAC;AACpB,SAAK,SAAS,MAAM;AACpB,SAAK,KAAK,MAAM;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,0BAAsD;AACpD,UAAM,UAAU,oBAAI,IAA2B;AAE/C,eAAW,UAAU,KAAK,SAAS;AACjC,YAAM,MAAM,OAAO,aAAa,KAAK,GAAG,KAAK,OAAO;AACpD,YAAM,WAAW,QAAQ,IAAI,GAAG,KAAK,CAAC;AACtC,eAAS,KAAK,MAAM;AACpB,cAAQ,IAAI,KAAK,QAAQ;AAAA,IAC3B;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,WAIE;AACA,UAAM,UAAsC;AAAA,MAC1C,OAAO;AAAA,MACP,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO;AAAA,MACP,OAAO;AAAA,IACT;AAEA,eAAW,UAAU,KAAK,SAAS;AACjC,cAAQ,OAAO,KAAK;AAAA,IACtB;AAEA,UAAM,eAAe,KAAK,wBAAwB,EAAE;AAEpD,WAAO;AAAA,MACL,OAAO,KAAK,QAAQ;AAAA,MACpB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,WAA4D;AACtE,WAAO,KAAK,QAAQ,OAAO,SAAS;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAyC;AACvC,WAAO,KAAK,QAAQ,KAAK,QAAQ,SAAS,CAAC;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,SAAwC;AAE3D,QAAI,kBAA2C,CAAC;AAChD,UAAM,MAAM,mBAAmB,IAAI;AACnC,QAAI,KAAK;AACP,wBAAkB;AAAA,QAChB,SAAS,IAAI;AAAA,QACb,eAAe,IAAI;AAAA,QACnB,WAAW,IAAI;AAAA,QACf,QAAQ,IAAI;AAAA,QACZ,UAAU,IAAI;AAAA,QACd,WAAW,IAAI;AAAA,MACjB;AAAA,IACF;AAGA,UAAM,QAAiC,CAAC;AACxC,eAAW,CAAC,MAAMC,IAAG,KAAK,KAAK,UAAU;AACvC,YAAM,IAAI,IAAIA;AAAA,IAChB;AAGA,UAAM,OAA+B;AAAA,MACnC,GAAG,KAAK,OAAO;AAAA,IACjB;AACA,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM;AACpC,WAAK,GAAG,IAAI;AAAA,IACd;AAEA,WAAO;AAAA,MACL,SAAS,gBAAgB;AAAA,MACzB,SAAS,gBAAgB;AAAA,MACzB,eAAe,gBAAgB;AAAA,MAC/B,WAAW,gBAAgB;AAAA,MAC3B,QAAQ,KAAK,aAAa,MAAO,gBAAgB;AAAA,MACjD,UAAU,gBAAgB;AAAA,MAC1B,WAAW,gBAAgB;AAAA,MAC3B,aAAa,KAAK,OAAO;AAAA,MACzB,SAAS,KAAK,OAAO;AAAA,MACrB,SAAS,KAAK,OAAO;AAAA,MACrB,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,KAAK;AAAA,MAClC,OAAO,EAAE,GAAG,OAAO,GAAG,SAAS,MAAM;AAAA,IACvC;AAAA,EACF;AAAA,EAEQ,aACN,OACA,SACA,SACa;AACb,WAAO;AAAA,MACL,IAAI,gBAAgB;AAAA,MACpB,SAAS,MAAM;AAAA,MACf,MAAM,MAAM,QAAQ;AAAA,MACpB,OAAO,MAAM;AAAA,MACb;AAAA,MACA,OAAO,SAAS,SAAS;AAAA,MACzB,WAAW,KAAK,IAAI;AAAA,MACpB,SAAS,SAAS,WAAW;AAAA,MAC7B,aAAa,SAAS,eAAe,oBAAoB,KAAK;AAAA,MAC9D,aAAa,CAAC;AAAA,IAChB;AAAA,EACF;AAAA,EAEQ,YAAY,QAA2B;AAC7C,SAAK,QAAQ,KAAK,MAAM;AAGxB,QAAI,KAAK,QAAQ,SAAS,KAAK,OAAO,YAAY;AAChD,WAAK,UAAU,KAAK,QAAQ,MAAM,CAAC,KAAK,OAAO,UAAU;AAAA,IAC3D;AAAA,EACF;AAAA,EAEQ,aAAa,QAA2B;AAC9C,QAAI,CAAC,KAAK,OAAO,aAAc;AAE/B,UAAM,iBAAiB,eAAe,OAAO,KAAK;AAClD,UAAM,oBAAoB,eAAe,KAAK,OAAO,eAAe;AAEpE,QAAI,iBAAiB,kBAAmB;AAExC,UAAM,SAAS,IAAI,OAAO,MAAM,YAAY,CAAC,MAAM,OAAO,EAAE;AAC5D,UAAM,aAAa,OAAO,QAAQ,YAAY,KAAK,OAAO,QAAQ,SAAS,MAAM;AAEjF,YAAQ,OAAO,OAAO;AAAA,MACpB,KAAK;AAAA,MACL,KAAK;AACH,gBAAQ,MAAM,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,OAAO,EAAE;AACxD,YAAI,OAAO,MAAO,SAAQ,MAAM,OAAO,KAAK;AAC5C;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,OAAO,EAAE;AACvD;AAAA,MACF,KAAK;AACH,gBAAQ,KAAK,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,OAAO,EAAE;AACvD;AAAA,MACF,KAAK;AACH,gBAAQ,MAAM,GAAG,MAAM,GAAG,UAAU,IAAI,OAAO,OAAO,EAAE;AACxD;AAAA,IACJ;AAAA,EACF;AACF;;;ACpVO,IAAM,iBAAN,MAA0C;AAAA,EACvC,SAA6B,CAAC;AAAA,EAC9B,WAAW;AAAA,EACX;AAAA,EAER,YAAY,QAA8B;AACxC,SAAK,SAAS;AAAA,MACZ,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO,eAAe;AAAA,MACnC,WAAW,OAAO,aAAa,EAAE,eAAe,GAAG;AAAA,MACnD,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,aAAa,OAAO,eAAe;AAAA,MACnC,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,WAAW,OAAO,aAAa;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,OAA8C;AACtD,UAAM,cAAc,KAAK,kBAAkB,KAAK;AAChD,SAAK,OAAO,KAAK,WAAW;AAC5B,SAAK,iBAAiB;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,SAAS,QAAmD;AAChE,UAAM,eAAe,OAAO,IAAI,CAAC,MAAM,KAAK,kBAAkB,CAAC,CAAC;AAChE,SAAK,OAAO,KAAK,GAAG,YAAY;AAChC,SAAK,iBAAiB;AACtB,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,OAA8C;AACxD,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI,WAAW,CAAC,GAAG,KAAK,MAAM;AAG9B,eAAW,KAAK,aAAa,UAAU,KAAK;AAG5C,UAAM,QAAQ,SAAS;AAGvB,UAAM,UAAU,MAAM,WAAW;AACjC,UAAM,QAAQ,MAAM,SAAS;AAC7B,aAAS,KAAK,CAAC,GAAG,MAAM;AACtB,YAAM,OAAO,YAAY,cAAc,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,EAAE;AAC3E,YAAM,OAAO,YAAY,cAAc,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,EAAE;AAC3E,aAAO,UAAU,QAAQ,OAAO,OAAO,OAAO;AAAA,IAChD,CAAC;AAGD,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,KAAK,GAAI;AAC/C,UAAM,YAAY,SAAS,MAAM,QAAQ,SAAS,KAAK;AAEvD,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,MACA,SAAS,SAAS,UAAU,SAAS;AAAA,MACrC,eAAe,KAAK,IAAI,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,IAA8C;AAC3D,WAAO,KAAK,OAAO,KAAK,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK;AAAA,EACjD;AAAA,EAEA,MAAM,gBAAgB,IAA8B;AAClD,UAAM,QAAQ,MAAM,KAAK,SAAS,EAAE;AACpC,QAAI,CAAC,MAAO,QAAO;AAEnB,QAAI,CAAC,KAAK,OAAO,gBAAiB,QAAO;AAGzC,UAAM,EAAE,UAAU,SAAS,UAAU,MAAM,GAAG,UAAU,IAAI;AAC5D,UAAM,WAAW,iBAAiB,SAAuB;AAGzD,WAAO,MAAM,SAAS,UAAU,GAAG,EAAE,MAAM,SAAS,UAAU,GAAG,EAAE;AAAA,EACrE;AAAA,EAEA,MAAM,WAAgC;AACpC,UAAM,aAA4C;AAAA,MAChD,gBAAgB;AAAA,MAChB,eAAe;AAAA,MACf,aAAa;AAAA,MACb,eAAe;AAAA,MACf,cAAc;AAAA,MACd,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAEA,UAAM,YAA0C;AAAA,MAC9C,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAEA,eAAW,SAAS,KAAK,QAAQ;AAC/B,iBAAW,MAAM,QAAQ;AACzB,gBAAU,MAAM,OAAO;AAAA,IACzB;AAEA,UAAM,SAAS,CAAC,GAAG,KAAK,MAAM,EAAE;AAAA,MAC9B,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,IAC5E;AAEA,WAAO;AAAA,MACL,OAAO,KAAK,OAAO;AAAA,MACnB;AAAA,MACA;AAAA,MACA,aAAa,OAAO,CAAC,GAAG;AAAA,MACxB,aAAa,OAAO,OAAO,SAAS,CAAC,GAAG;AAAA,MACxC,cAAc,KAAK,UAAU,KAAK,MAAM,EAAE;AAAA,IAC5C;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,QAAgD;AACnE,UAAM,kBAAkB,UAAU,KAAK,OAAO;AAC9C,QAAI,gBAAgB,kBAAkB,EAAG,QAAO;AAEhD,UAAM,aAAa,oBAAI,KAAK;AAC5B,eAAW,QAAQ,WAAW,QAAQ,IAAI,gBAAgB,aAAa;AACvE,UAAM,aAAa,WAAW,QAAQ;AAEtC,UAAM,mBAAmB,IAAI,IAAI,gBAAgB,oBAAoB,CAAC,CAAC;AACvE,UAAM,iBAAiB,KAAK,OAAO;AAEnC,SAAK,SAAS,KAAK,OAAO,OAAO,CAAC,UAAU;AAE1C,UAAI,iBAAiB,IAAI,MAAM,QAAQ,EAAG,QAAO;AAEjD,aAAO,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ,KAAK;AAAA,IAChD,CAAC;AAED,WAAO,iBAAiB,KAAK,OAAO;AAAA,EACtC;AAAA,EAEA,MAAM,OAAO,OAAgD;AAE3D,UAAM,SAAS,MAAM,KAAK,MAAM,EAAE,GAAG,OAAO,OAAO,KAAS,QAAQ,EAAE,CAAC;AACvE,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,SAAS,CAAC;AACf,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAA6B;AAC3B,WAAO,CAAC,GAAG,KAAK,MAAM;AAAA,EACxB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,SAAS,CAAC;AACf,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,QAAgB;AAClB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,QAAoC;AAC/C,WAAO,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,WAAW,MAAM;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,SAAqC;AAC/C,WAAO,KAAK,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,OAAO,OAAO;AAAA,EACzD;AAAA;AAAA;AAAA;AAAA,EAMQ,kBAAkB,OAAqC;AAC7D,UAAM,KAAK,MAAM,MAAM,KAAK,OAAO,YAAY;AAC/C,UAAM,YAAY,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC5D,UAAM,MAAM,EAAE,KAAK;AAGnB,QAAI,UAAU,MAAM;AACpB,QAAI,KAAK,OAAO,iBAAiB;AAC/B,YAAM,kBAAkB,mBAAmB,IAAI;AAC/C,UAAI,iBAAiB;AACnB,kBAAU;AAAA,UACR,GAAG;AAAA,UACH,SAAS,SAAS,WAAW,gBAAgB;AAAA,UAC7C,eAAe,SAAS,iBAAiB,gBAAgB;AAAA,UACzD,WAAW,SAAS,aAAa,gBAAgB;AAAA,UACjD,UAAU,SAAS,YAAY,gBAAgB;AAAA,QACjD;AAAA,MACF;AAEA,gBAAU;AAAA,QACR,GAAG;AAAA,QACH,aAAa,KAAK,OAAO;AAAA,QACzB,SAAS,KAAK,OAAO;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,uBAAwE;AAAA,MAC5E;AAAA,MACA;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,OAAO,kBACzB,iBAAiB,oBAAoB,IACrC;AAEJ,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,MACA,UAAU;AAAA,IACZ;AAAA,EACF;AAAA,EAEQ,aAAa,QAA4B,OAAuC;AACtF,WAAO,OAAO,OAAO,CAAC,UAAU;AAE9B,UAAI,MAAM,UAAU;AAClB,cAAM,aAAa,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC,MAAM,QAAQ;AACnF,YAAI,CAAC,WAAW,SAAS,MAAM,QAAQ,EAAG,QAAO;AAAA,MACnD;AAGA,UAAI,MAAM,QAAQ;AAChB,cAAM,UAAU,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM;AAC1E,YAAI,CAAC,QAAQ,KAAK,CAAC,YAAY,YAAY,MAAM,QAAQ,OAAO,CAAC,EAAG,QAAO;AAAA,MAC7E;AAGA,UAAI,MAAM,SAAS;AACjB,cAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,IAAI,MAAM,UAAU,CAAC,MAAM,OAAO;AAC9E,YAAI,CAAC,SAAS,SAAS,MAAM,OAAO,EAAG,QAAO;AAAA,MAChD;AAGA,UAAI,MAAM,WAAW,MAAM,MAAM,OAAO,MAAM,QAAS,QAAO;AAC9D,UAAI,MAAM,aAAa,MAAM,MAAM,SAAS,MAAM,UAAW,QAAO;AAGpE,UAAI,MAAM,cAAc,MAAM,QAAQ,SAAS,MAAM,WAAY,QAAO;AACxE,UAAI,MAAM,YAAY,MAAM,QAAQ,OAAO,MAAM,SAAU,QAAO;AAGlE,UAAI,MAAM,YAAY,MAAM,SAAS,aAAa,MAAM,SAAU,QAAO;AACzE,UAAI,MAAM,WAAW,MAAM,SAAS,YAAY,MAAM,QAAS,QAAO;AACtE,UAAI,MAAM,iBAAiB,MAAM,SAAS,kBAAkB,MAAM,cAAe,QAAO;AAGxF,UAAI,MAAM,MAAM;AACd,cAAM,WAAW,IAAI,KAAK,MAAM,IAAI,EAAE,QAAQ;AAC9C,YAAI,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ,IAAI,SAAU,QAAO;AAAA,MAC7D;AACA,UAAI,MAAM,IAAI;AACZ,cAAM,SAAS,IAAI,KAAK,MAAM,EAAE,EAAE,QAAQ;AAC1C,YAAI,IAAI,KAAK,MAAM,SAAS,EAAE,QAAQ,IAAI,OAAQ,QAAO;AAAA,MAC3D;AAGA,UAAI,MAAM,aAAa,MAAM,MAAM;AACjC,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,SAAS,GAAG;AAC1D,cAAI,MAAM,KAAK,GAAG,MAAM,MAAO,QAAO;AAAA,QACxC;AAAA,MACF;AAEA,aAAO;AAAA,IACT,CAAC;AAAA,EACH;AAAA,EAEQ,mBAAyB;AAC/B,QAAI,KAAK,OAAO,SAAS,KAAK,OAAO,WAAW;AAE9C,WAAK,SAAS,KAAK,OAAO,MAAM,CAAC,KAAK,OAAO,SAAS;AAAA,IACxD;AAAA,EACF;AACF;;;ACvTA,SAAS,kBAAkB;AASpB,IAAM,gBAAN,MAAwC;AAAA,EACrC,YAA0C,oBAAI,IAAI;AAAA,EAClD,aAA2C,oBAAI,IAAI;AAAA,EACnD,iBAAoD,oBAAI,IAAI;AAAA,EAC5D;AAAA;AAAA,EAGA,mBAA8E,CAAC;AAAA,EAEvF,YAAY,SAA8B,CAAC,GAAG;AAC5C,SAAK,SAAS;AAAA,MACZ,YAAY,OAAO,cAAc;AAAA,MACjC,cAAc,OAAO,gBAAgB;AAAA,MACrC,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,WAAW,OAAO,aAAa;AAAA,MAC/B,eAAe,OAAO,iBAAiB;AAAA,MACvC,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,sBAAsB,OAAO,wBAAwB;AAAA,MACrD,WAAW,OAAO,aAAa;AAAA,MAC/B,aAAa,OAAO,eAAe;AAAA,MACnC,gBAAgB,OAAO,kBAAkB;AAAA,IAC3C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,SAAyD;AACpE,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,KAAK,QAAQ,MAAM,kBAAkB;AAE3C,QAAI,KAAK,UAAU,IAAI,EAAE,GAAG;AAC1B,YAAM,IAAI,MAAM,oCAAoC,EAAE,EAAE;AAAA,IAC1D;AAEA,UAAM,WAA4B;AAAA,MAChC;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ;AAAA,MACrB,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ,UAAU,sBAAsB;AAAA,MAChD,oBAAoB,QAAQ,sBAAsB;AAAA,MAClD,iBAAiB,QAAQ,mBAAmB;AAAA,MAC5C,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ,SAAS,WAAW;AAAA,MACnC,SAAS,QAAQ;AAAA,MACjB,UAAU,QAAQ;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd,WAAW;AAAA,MACX,WAAW;AAAA,MACX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,sBAAsB;AAAA,IACxB;AAEA,SAAK,UAAU,IAAI,IAAI,QAAQ;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,IAA6C;AACrD,WAAO,KAAK,UAAU,IAAI,EAAE,KAAK;AAAA,EACnC;AAAA,EAEA,MAAM,OAAO,IAAY,SAAyD;AAChF,UAAM,WAAW,KAAK,UAAU,IAAI,EAAE;AACtC,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAAA,IACrD;AAEA,UAAM,UAA2B;AAAA,MAC/B,GAAG;AAAA,MACH,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC/B,aAAa,QAAQ,eAAe,SAAS;AAAA,MAC7C,KAAK,QAAQ,OAAO,SAAS;AAAA,MAC7B,QAAQ,QAAQ,eAAe,sBAAsB,IAAI,SAAS;AAAA,MAClE,QAAQ,QAAQ,UAAU,SAAS;AAAA,MACnC,SAAS,QAAQ,WAAW,SAAS;AAAA,MACrC,UAAU,QAAQ,YAAY,SAAS;AAAA,MACvC,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC/B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAEA,SAAK,UAAU,IAAI,IAAI,OAAO;AAC9B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,SAAK,UAAU,OAAO,EAAE;AAExB,eAAW,CAAC,YAAY,QAAQ,KAAK,KAAK,YAAY;AACpD,UAAI,SAAS,eAAe,IAAI;AAC9B,aAAK,WAAW,OAAO,UAAU;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,OAAkD;AAC3D,QAAI,YAAY,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC;AAGlD,QAAI,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK;AACtE,kBAAY,UAAU,OAAO,CAAC,MAAM,OAAO,SAAS,EAAE,KAAK,CAAC;AAAA,IAC9D;AAEA,QAAI,OAAO,UAAU,MAAM,OAAO,SAAS,GAAG;AAC5C,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,MAAM,OAAQ;AAAA,UAAK,CAAC,cAClB,EAAE,OAAO,KAAK,CAAC,YAAY,eAAe,WAAW,OAAO,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,QAAQ,MAAM,KAAK,SAAS,GAAG;AACxC,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,MAAM,KAAM,KAAK,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC;AAAA,MACjD;AAAA,IACF;AAEA,QAAI,OAAO,MAAM;AACf,YAAM,UAAU,MAAM,KAAK,QAAQ,OAAO,IAAI;AAC9C,YAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,KAAK,GAAG;AAC5C,kBAAY,UAAU,OAAO,CAAC,MAAM,MAAM,KAAK,EAAE,IAAI,CAAC;AAAA,IACxD;AAGA,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,QAAQ,OAAO,SAAS;AAC9B,WAAO,UAAU,MAAM,QAAQ,SAAS,KAAK;AAAA,EAC/C;AAAA,EAEA,MAAM,MAAM,IAA2B;AACrC,UAAM,WAAW,KAAK,UAAU,IAAI,EAAE;AACtC,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAElE,aAAS,QAAQ;AACjB,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,SAAK,UAAU,IAAI,IAAI,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,WAAW,KAAK,UAAU,IAAI,EAAE;AACtC,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAElE,aAAS,QAAQ;AACjB,aAAS,eAAe;AACxB,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,SAAK,UAAU,IAAI,IAAI,QAAQ;AAAA,EACjC;AAAA,EAEA,MAAM,KAAK,IAAsC;AAC/C,UAAM,WAAW,KAAK,UAAU,IAAI,EAAE;AACtC,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAElE,UAAM,QAAsB;AAAA,MAC1B,MAAM;AAAA,MACN,SAAS,EAAE,MAAM,MAAM,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,IAC7D;AAEA,UAAM,UAAU,MAAM,KAAK,gBAAgB,UAAU,OAAO,CAAC;AAC7D,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAY,OAA2C;AAC3D,UAAM,cAAwB,CAAC;AAC/B,UAAM,UAAU,MAAM,MAAM,gBAAgB;AAC5C,UAAM,YAAY,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAE5D,UAAM,YAA6B;AAAA,MACjC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ;AAAA,IACF;AAGA,UAAM,kBAAkB,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,MAC1D,CAAC,MACC,EAAE,UAAU,YACZ,EAAE,OAAO,KAAK,CAAC,YAAY,eAAe,MAAM,MAAM,OAAO,CAAC;AAAA,IAClE;AAEA,eAAW,YAAY,iBAAiB;AACtC,YAAM,aAAa,MAAM,KAAK,WAAW,SAAS,IAAI,SAAS;AAC/D,kBAAY,KAAK,UAAU;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAc,YAAoB,OAAyC;AAC/E,UAAM,WAAW,KAAK,UAAU,IAAI,UAAU;AAC9C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,UAAU,EAAE;AAE1E,UAAM,UAAU,MAAM,MAAM,gBAAgB;AAC5C,UAAM,YAAY,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC5D,UAAM,aAAa,mBAAmB;AAEtC,UAAM,YAA6B;AAAA,MACjC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ;AAAA,IACF;AAGA,SAAK,iBAAiB,KAAK,EAAE,UAAU,OAAO,UAAU,CAAC;AAGzD,UAAM,WAA4B;AAAA,MAChC,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,SAAS,KAAK,UAAU,SAAS;AAAA,MACjC,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,gBAAgB,CAAC;AAAA,MACjB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAEA,SAAK,WAAW,IAAI,YAAY,QAAQ;AAGxC,UAAM,KAAK,mBAAmB,UAAU,WAAW,QAAQ;AAE3D,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,YAA8C;AACxD,UAAM,WAAW,KAAK,WAAW,IAAI,UAAU;AAC/C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB,UAAU,EAAE;AAElE,UAAM,WAAW,KAAK,UAAU,IAAI,SAAS,UAAU;AACvD,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,SAAS,UAAU,EAAE;AAEnF,UAAM,QAAQ,KAAK,MAAM,SAAS,OAAO;AACzC,UAAM,UAAU,MAAM,KAAK,gBAAgB,UAAU,OAAO,SAAS,WAAW,CAAC;AAEjF,aAAS;AACT,aAAS,eAAe,KAAK,OAAO;AAEpC,QAAI,QAAQ,WAAW,WAAW;AAChC,eAAS,SAAS;AAClB,eAAS,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,IAChD;AAEA,SAAK,WAAW,IAAI,YAAY,QAAQ;AACxC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,IAA6C;AAC7D,WAAO,KAAK,WAAW,IAAI,EAAE,KAAK;AAAA,EACpC;AAAA,EAEA,MAAM,eAAe,OAAmD;AACtE,QAAI,aAAa,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC;AAGpD,QAAI,OAAO,YAAY;AACrB,mBAAa,WAAW,OAAO,CAAC,MAAM,EAAE,eAAe,MAAM,UAAU;AAAA,IACzE;AAEA,QAAI,OAAO,WAAW;AACpB,mBAAa,WAAW,OAAO,CAAC,MAAM,EAAE,cAAc,MAAM,SAAS;AAAA,IACvE;AAEA,QAAI,OAAO,QAAQ;AACjB,YAAM,WAAW,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM;AAC3E,mBAAa,WAAW,OAAO,CAAC,MAAM,SAAS,SAAS,EAAE,MAAM,CAAC;AAAA,IACnE;AAEA,QAAI,OAAO,MAAM;AACf,YAAM,OAAO,IAAI,KAAK,MAAM,IAAI,EAAE,QAAQ;AAC1C,mBAAa,WAAW,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,KAAK,IAAI;AAAA,IAC/E;AAEA,QAAI,OAAO,IAAI;AACb,YAAM,KAAK,IAAI,KAAK,MAAM,EAAE,EAAE,QAAQ;AACtC,mBAAa,WAAW,OAAO,CAAC,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,KAAK,EAAE;AAAA,IAC7E;AAGA,eAAW,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;AAG3F,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,QAAQ,OAAO,SAAS;AAC9B,WAAO,WAAW,MAAM,QAAQ,SAAS,KAAK;AAAA,EAChD;AAAA,EAEA,MAAM,YAAY,YAAgD;AAChE,UAAM,WAAW,KAAK,WAAW,IAAI,UAAU;AAC/C,QAAI,CAAC,SAAU,QAAO,CAAC;AACvB,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,QAAoC;AAClD,SAAK,eAAe,IAAI,OAAO,MAAM,MAAM;AAAA,EAC7C;AAAA,EAEA,OAAO,MAAc,SAAoD;AACvE,UAAM,SAAS,KAAK,eAAe,IAAI,IAAI;AAC3C,QAAI,CAAC,QAAQ;AACX,aAAO,EAAE,OAAO,OAAO,OAAO,oBAAoB,IAAI,GAAG;AAAA,IAC3D;AAGA,UAAM,kBAAkB,OAAO,mBAAmB;AAClD,UAAM,YAAY,QAAQ,QAAQ,gBAAgB,YAAY,CAAC,KAAK,QAAQ;AAE5E,QAAI,CAAC,WAAW;AACd,aAAO,EAAE,OAAO,OAAO,OAAO,2BAA2B;AAAA,IAC3D;AAGA,QAAI,OAAO,iBAAiB;AAC1B,YAAM,YAAY,QAAQ,QAAQ,OAAO,gBAAgB,YAAY,CAAC;AACtE,UAAI,WAAW;AACb,cAAM,cAAc,SAAS,WAAW,EAAE,IAAI;AAC9C,cAAM,MAAM,KAAK,IAAI;AACrB,cAAM,aAAa,OAAO,sBAAsB,OAAO;AAEvD,YAAI,KAAK,IAAI,MAAM,WAAW,IAAI,WAAW;AAC3C,iBAAO,EAAE,OAAO,OAAO,OAAO,qCAAqC;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY,OAAO,sBAAsB;AAC/C,UAAM,OAAO,OAAO,QAAQ,YAAY,WACpC,QAAQ,UACR,QAAQ,QAAQ,SAAS,OAAO;AAEpC,UAAM,oBAAoB,KAAK,iBAAiB,MAAM,OAAO,QAAQ,SAAS;AAG9E,UAAM,cAAc,UAAU,QAAQ,4BAA4B,EAAE;AACpE,QAAI,gBAAgB,mBAAmB;AACrC,aAAO,EAAE,OAAO,OAAO,OAAO,oBAAoB;AAAA,IACpD;AAGA,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,aAAO,EAAE,OAAO,MAAM,QAAQ;AAAA,IAChC,QAAQ;AACN,aAAO,EAAE,OAAO,OAAO,OAAO,uBAAuB;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAkC;AACtC,UAAM,YAAY,MAAM,KAAK,KAAK,UAAU,OAAO,CAAC;AACpD,UAAM,aAAa,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC;AACtD,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI;AAE3D,UAAM,mBAAmB,WAAW;AAAA,MAClC,CAAC,MAAM,IAAI,KAAK,EAAE,SAAS,IAAI;AAAA,IACjC;AAEA,UAAM,mBAAmB,iBAAiB,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS;AAC9E,UAAM,eAAe,iBAAiB,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ;AAGzE,QAAI,gBAAgB;AACpB,QAAI,gBAAgB;AACpB,eAAW,YAAY,kBAAkB;AACvC,iBAAW,WAAW,SAAS,gBAAgB;AAC7C,YAAI,QAAQ,UAAU;AACpB,2BAAiB,QAAQ;AACzB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,gBAAgB,UAAU;AAAA,MAC1B,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAE;AAAA,MAC/D,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAE;AAAA,MAC/D,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAE;AAAA,MAC/D,mBAAmB,iBAAiB;AAAA,MACpC,gBAAgB,iBAAiB;AAAA,MACjC,iBAAiB,aAAa;AAAA,MAC9B,iBAAiB,gBAAgB,IAAI,gBAAgB,gBAAgB;AAAA,IACvE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,UAAU,MAAM;AACrB,SAAK,WAAW,MAAM;AACtB,SAAK,eAAe,MAAM;AAC1B,SAAK,iBAAiB,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,sBAAiF;AAC/E,WAAO,CAAC,GAAG,KAAK,gBAAgB;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,wBAA8B;AAC5B,SAAK,iBAAiB,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAsC;AACpC,WAAO,MAAM,KAAK,KAAK,WAAW,OAAO,CAAC;AAAA,EAC5C;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBACZ,UACA,OACA,UACe;AACf,QAAI,UAAU;AACd,QAAI;AAEJ,WAAO,UAAU,KAAK,OAAO,YAAY;AACvC;AACA,YAAM,SAAS,MAAM,KAAK,gBAAgB,UAAU,OAAO,OAAO;AAElE,eAAS,WAAW;AACpB,eAAS,eAAe,KAAK,MAAM;AAEnC,UAAI,OAAO,WAAW,WAAW;AAC/B,iBAAS,SAAS;AAClB,iBAAS,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC9C,aAAK,oBAAoB,UAAU,IAAI;AACvC,aAAK,WAAW,IAAI,SAAS,IAAI,QAAQ;AACzC;AAAA,MACF;AAEA,kBAAY,OAAO;AAAA,IACrB;AAGA,aAAS,SAAS;AAClB,aAAS,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC9C,SAAK,oBAAoB,UAAU,KAAK;AACxC,SAAK,WAAW,IAAI,SAAS,IAAI,QAAQ;AAAA,EAC3C;AAAA,EAEA,MAAc,gBACZ,UACA,OACA,eAC0B;AAC1B,UAAM,YAAY,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC,CAAC;AAC7F,UAAM,YAAY,KAAK,IAAI;AAG3B,QAAI,KAAK,OAAO,iBAAiB,GAAG;AAClC,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,OAAO,cAAc,CAAC;AAAA,IAChF;AAGA,UAAM,aAAa,KAAK,OAAO,IAAI,KAAK,OAAO;AAE/C,UAAM,WAAW,KAAK,IAAI,IAAI;AAE9B,QAAI,YAAY;AACd,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,YAAY,SAAS;AAAA,QACrB,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR,YAAY;AAAA,QACZ,cAAc;AAAA,QACd;AAAA,QACA,OAAO;AAAA,QACP,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,IACF;AAEA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,YAAY,SAAS;AAAA,MACrB,SAAS,MAAM;AAAA,MACf,WAAW,MAAM;AAAA,MACjB;AAAA,MACA,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,cAAc;AAAA,MACd;AAAA,MACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAAA,EACF;AAAA,EAEQ,oBAAoB,UAA2B,SAAwB;AAC7E,aAAS;AACT,aAAS,kBAAiB,oBAAI,KAAK,GAAE,YAAY;AAEjD,QAAI,SAAS;AACX,eAAS;AACT,eAAS,iBAAgB,oBAAI,KAAK,GAAE,YAAY;AAChD,eAAS,eAAe;AAAA,IAC1B,OAAO;AACL,eAAS;AAGT,UAAI,SAAS,gBAAgB,KAAK,OAAO,kBAAkB;AACzD,iBAAS,QAAQ;AAAA,MACnB;AAAA,IACF;AAEA,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,SAAK,UAAU,IAAI,SAAS,IAAI,QAAQ;AAAA,EAC1C;AAAA,EAEQ,iBAAiB,SAAiB,QAAgB,WAA2B;AACnF,WAAO,WAAW,WAAW,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,EACnE;AACF;;;ACliBO,IAAM,qBAAN,MAAkD;AAAA,EAC/C,gBAAiD,oBAAI,IAAI;AAAA,EACzD,oBAAqD,oBAAI,IAAI;AAAA,EAC7D,cAAoD,oBAAI,IAAI;AAAA,EAC5D,SAAmC,oBAAI,IAAI;AAAA;AAAA,EAC3C,aAAuC,oBAAI,IAAI;AAAA;AAAA,EAC/C;AAAA;AAAA,EAGA,oBAKH,CAAC;AAAA,EAEN,YAAY,SAAmC,CAAC,GAAG;AACjD,SAAK,SAAS;AAAA,MACZ,iBAAiB,OAAO,mBAAmB,CAAC,QAAQ;AAAA,MACpD,YAAY,OAAO,cAAc;AAAA,MACjC,WAAW,OAAO;AAAA,MAClB,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO,aAAa;AAAA,MAC/B,YAAY,OAAO,cAAc,CAAC;AAAA,MAClC,aAAa,OAAO,eAAe;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,KAAK,SAA+D;AACxE,UAAM,EAAE,QAAQ,cAAc,UAAU,MAAM,IAAI;AAClD,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,KAAK,uBAAuB;AAGlC,UAAM,QAAQ,MAAM,KAAK,eAAe,MAAM;AAG9C,QAAI,oBAAoB,YAAY,KAAK,OAAO;AAChD,wBAAoB;AAAA,MAClB;AAAA,MACA;AAAA,MACA,aAAa;AAAA,MACb;AAAA,IACF;AAGA,UAAM,UAAyC,CAAC;AAGhD,eAAW,WAAW,mBAAmB;AACvC,UAAI;AACF,gBAAQ,SAAS;AAAA,UACf,KAAK;AACH,kBAAM,KAAK,uBAAuB,QAAQ,IAAI,cAAc,iBAAiB;AAC7E,oBAAQ,SAAS,EAAE,SAAS,MAAM,WAAW,GAAG;AAChD;AAAA,UAEF,KAAK;AAEH,gBAAI,OAAO,OAAO;AAChB,sBAAQ,QAAQ,EAAE,SAAS,MAAM,WAAW,SAAS,EAAE,GAAG;AAAA,YAC5D,OAAO;AACL,sBAAQ,QAAQ,EAAE,SAAS,OAAO,OAAO,mBAAmB;AAAA,YAC9D;AACA;AAAA,UAEF,KAAK;AAEH,kBAAM,OAAO,MAAM,KAAK,qBAAqB,MAAM;AACnD,gBAAI,KAAK,SAAS,GAAG;AACnB,sBAAQ,OAAO,EAAE,SAAS,MAAM,WAAW,QAAQ,EAAE,GAAG;AAAA,YAC1D,OAAO;AACL,sBAAQ,OAAO,EAAE,SAAS,OAAO,OAAO,wBAAwB;AAAA,YAClE;AACA;AAAA,UAEF,KAAK;AAEH,gBAAI,OAAO,OAAO;AAChB,sBAAQ,MAAM,EAAE,SAAS,MAAM,WAAW,OAAO,EAAE,GAAG;AAAA,YACxD,OAAO;AACL,sBAAQ,MAAM,EAAE,SAAS,OAAO,OAAO,kBAAkB;AAAA,YAC3D;AACA;AAAA,QACJ;AAAA,MACF,SAAS,OAAO;AACd,gBAAQ,OAAO,IAAI;AAAA,UACjB,SAAS;AAAA,UACT,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,QAC9D;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAA6B,EAAE,IAAI,QAAQ;AAGjD,SAAK,kBAAkB,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,MACA,UAAU;AAAA,MACV;AAAA,IACF,CAAC;AAED,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,UAAU,SAAkE;AAChF,UAAM,UAAgC,CAAC;AAEvC,eAAW,UAAU,QAAQ,SAAS;AACpC,YAAM,SAAS,MAAM,KAAK,KAAK;AAAA,QAC7B;AAAA,QACA,cAAc,QAAQ;AAAA,QACtB,UAAU,QAAQ;AAAA,MACpB,CAAC;AACD,cAAQ,KAAK,MAAM;AAAA,IACrB;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,YAAY,OAAe,cAAiD;AAChF,UAAM,UAAU,KAAK,OAAO,IAAI,KAAK;AACrC,QAAI,CAAC,WAAW,QAAQ,SAAS,EAAG,QAAO;AAE3C,QAAI,QAAQ;AACZ,eAAW,UAAU,SAAS;AAC5B,YAAM,KAAK,KAAK;AAAA,QACd,QAAQ,EAAE,OAAO;AAAA,QACjB;AAAA,MACF,CAAC;AACD;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,uBACZ,QACA,IACA,cACA,UACe;AACf,UAAM,SAA6B;AAAA,MACjC;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA,QAAQ,EAAE,QAAQ,YAAY;AAAA,MAC9B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AACA,SAAK,cAAc,IAAI,IAAI,MAAM;AAAA,EACnC;AAAA,EAEA,MAAM,WAAW,QAAgB,OAA0D;AACzF,QAAI,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC,EACvD,OAAO,OAAK,EAAE,WAAW,MAAM;AAGlC,QAAI,OAAO,UAAU;AACnB,YAAM,aAAa,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC,MAAM,QAAQ;AACnF,sBAAgB,cAAc;AAAA,QAAO,OACnC,EAAE,KAAK,YAAY,WAAW,SAAS,EAAE,KAAK,QAAQ;AAAA,MACxD;AAAA,IACF;AAEA,QAAI,OAAO,YAAY;AACrB,sBAAgB,cAAc,OAAO,OAAK,CAAC,EAAE,MAAM;AAAA,IACrD;AAEA,QAAI,OAAO,MAAM;AACf,YAAM,OAAO,IAAI,KAAK,MAAM,IAAI,EAAE,QAAQ;AAC1C,sBAAgB,cAAc;AAAA,QAAO,OACnC,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,KAAK;AAAA,MACrC;AAAA,IACF;AAEA,QAAI,OAAO,IAAI;AACb,YAAM,KAAK,IAAI,KAAK,MAAM,EAAE,EAAE,QAAQ;AACtC,sBAAgB,cAAc;AAAA,QAAO,OACnC,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,KAAK;AAAA,MACrC;AAAA,IACF;AAGA,kBAAc;AAAA,MAAK,CAAC,GAAG,MACrB,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ;AAAA,IAClE;AAGA,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,QAAQ,OAAO,SAAS;AAC9B,WAAO,cAAc,MAAM,QAAQ,SAAS,KAAK;AAAA,EACnD;AAAA,EAEA,MAAM,eAAe,QAAgB,UAAkD;AACrF,QAAI,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC,EACvD,OAAO,OAAK,EAAE,WAAW,UAAU,CAAC,EAAE,MAAM;AAE/C,QAAI,UAAU;AACZ,sBAAgB,cAAc,OAAO,OAAK,EAAE,KAAK,aAAa,QAAQ;AAAA,IACxE;AAEA,WAAO,cAAc;AAAA,EACvB;AAAA,EAEA,MAAM,WAAW,gBAAuC;AACtD,UAAM,eAAe,KAAK,cAAc,IAAI,cAAc;AAC1D,QAAI,cAAc;AAChB,mBAAa,UAAS,oBAAI,KAAK,GAAE,YAAY;AAC7C,mBAAa,OAAO,SAAS;AAC7B,WAAK,cAAc,IAAI,gBAAgB,YAAY;AAAA,IACrD;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,QAAgB,UAAkD;AACpF,QAAI,QAAQ;AACZ,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,eAAW,CAAC,IAAI,YAAY,KAAK,KAAK,eAAe;AACnD,UAAI,aAAa,WAAW,UAAU,CAAC,aAAa,QAAQ;AAC1D,YAAI,CAAC,YAAY,aAAa,KAAK,aAAa,UAAU;AACxD,uBAAa,SAAS;AACtB,uBAAa,OAAO,SAAS;AAC7B,eAAK,cAAc,IAAI,IAAI,YAAY;AACvC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,gBAAuC;AAClD,SAAK,cAAc,OAAO,cAAc;AAAA,EAC1C;AAAA,EAEA,MAAM,iBAAiB,QAAiC;AACtD,QAAI,QAAQ;AACZ,eAAW,CAAC,IAAI,YAAY,KAAK,KAAK,eAAe;AACnD,UAAI,aAAa,WAAW,QAAQ;AAClC,aAAK,cAAc,OAAO,EAAE;AAC5B;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,yBAAyB,QAAgB,cAA+C;AAC5F,UAAM,OAAO,KAAK,kBAAkB,IAAI,MAAM,KAAK,CAAC;AAGpD,QAAI,CAAC,KAAK,KAAK,OAAK,EAAE,aAAa,aAAa,QAAQ,GAAG;AACzD,WAAK,KAAK,YAAY;AACtB,WAAK,kBAAkB,IAAI,QAAQ,IAAI;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAM,uBAAuB,QAAgB,UAAiC;AAC5E,UAAM,OAAO,KAAK,kBAAkB,IAAI,MAAM,KAAK,CAAC;AACpD,UAAM,WAAW,KAAK,OAAO,OAAK,EAAE,aAAa,QAAQ;AACzD,SAAK,kBAAkB,IAAI,QAAQ,QAAQ;AAAA,EAC7C;AAAA,EAEA,MAAM,qBAAqB,QAA6C;AACtE,WAAO,KAAK,kBAAkB,IAAI,MAAM,KAAK,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,QAAkD;AACrE,WAAO,KAAK,YAAY,IAAI,MAAM,KAAK,yBAAyB,MAAM;AAAA,EACxE;AAAA,EAEA,MAAM,kBAAkB,QAAgB,aAA8D;AACpG,UAAM,UAAU,MAAM,KAAK,eAAe,MAAM;AAChD,UAAM,UAAmC;AAAA,MACvC,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA;AAAA,IACF;AACA,SAAK,YAAY,IAAI,QAAQ,OAAO;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,iBAAiB,QAAgB,OAA8B;AAEnE,UAAM,aAAa,KAAK,OAAO,IAAI,KAAK,KAAK,oBAAI,IAAI;AACrD,eAAW,IAAI,MAAM;AACrB,SAAK,OAAO,IAAI,OAAO,UAAU;AAGjC,UAAM,aAAa,KAAK,WAAW,IAAI,MAAM,KAAK,oBAAI,IAAI;AAC1D,eAAW,IAAI,KAAK;AACpB,SAAK,WAAW,IAAI,QAAQ,UAAU;AAAA,EACxC;AAAA,EAEA,MAAM,qBAAqB,QAAgB,OAA8B;AAEvE,UAAM,aAAa,KAAK,OAAO,IAAI,KAAK;AACxC,QAAI,YAAY;AACd,iBAAW,OAAO,MAAM;AAAA,IAC1B;AAGA,UAAM,aAAa,KAAK,WAAW,IAAI,MAAM;AAC7C,QAAI,YAAY;AACd,iBAAW,OAAO,KAAK;AAAA,IACzB;AAAA,EACF;AAAA,EAEA,MAAM,cAAc,QAAmC;AACrD,WAAO,MAAM,KAAK,KAAK,WAAW,IAAI,MAAM,KAAK,CAAC,CAAC;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAS,SAA8F;AAC3G,UAAM,WAAW;AAAA,MACf,KAAK,KAAK,KAAK,KAAK;AAAA,MACpB,MAAM,IAAI,KAAK,KAAK,KAAK;AAAA,MACzB,OAAO,KAAK,KAAK,KAAK,KAAK;AAAA,IAC7B,EAAE,SAAS,UAAU,KAAK;AAE1B,UAAM,SAAS,KAAK,IAAI,IAAI;AAE5B,QAAI,gBAAgB,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAE1D,QAAI,SAAS,QAAQ;AACnB,sBAAgB,cAAc,OAAO,OAAK,EAAE,WAAW,QAAQ,MAAM;AAAA,IACvE;AAEA,oBAAgB,cAAc;AAAA,MAAO,OACnC,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,KAAK;AAAA,IACrC;AAEA,UAAM,QAA2B;AAAA,MAC/B,WAAW,cAAc;AAAA,MACzB,WAAW;AAAA,QACT,QAAQ,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,EAAE;AAAA,QACpD,OAAO,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,EAAE;AAAA,QACnD,MAAM,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,EAAE;AAAA,QAClD,KAAK,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,GAAG,QAAQ,EAAE;AAAA,MACnD;AAAA,MACA,YAAY,CAAC;AAAA,MACb,aAAa;AAAA,IACf;AAEA,eAAW,KAAK,eAAe;AAE7B,iBAAW,WAAW,EAAE,UAAU;AAChC,cAAM,eAAe,MAAM,UAAU,OAAO;AAC5C,qBAAa;AACb,cAAM,SAAS,EAAE,OAAO,OAAO;AAC/B,YAAI,WAAW,YAAa,cAAa;AACzC,YAAI,WAAW,OAAQ,cAAa;AACpC,YAAI,WAAW,SAAU,cAAa;AAAA,MACxC;AAGA,YAAM,MAAM,EAAE,KAAK,YAAY;AAC/B,YAAM,WAAW,GAAG,KAAK,MAAM,WAAW,GAAG,KAAK,KAAK;AAGvD,UAAI,CAAC,EAAE,QAAQ;AACb,cAAM;AAAA,MACR;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAgC;AACpC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,cAAc,MAAM;AACzB,SAAK,kBAAkB,MAAM;AAC7B,SAAK,YAAY,MAAM;AACvB,SAAK,OAAO,MAAM;AAClB,SAAK,WAAW,MAAM;AACtB,SAAK,kBAAkB,SAAS;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,uBAKG;AACD,WAAO,CAAC,GAAG,KAAK,iBAAiB;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAKA,yBAA+B;AAC7B,SAAK,kBAAkB,SAAS;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA,EAKA,sBAA4C;AAC1C,WAAO,MAAM,KAAK,KAAK,cAAc,OAAO,CAAC;AAAA,EAC/C;AACF;;;ACreA;;;ACMA;;;ACNA;;;ACMA;;;ACNA;;;ACMA;;;ACNA;;;ACMA;;;ACNA;;;AC6EO,IAAM,mBAAN,MAA4C;AAAA,EACzC;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EAEnB,YAAY,QAAgC;AAC1C,SAAK,KAAK,OAAO;AACjB,SAAK,YAAY,OAAO,aAAa;AACrC,SAAK,SAAS;AAAA,MACZ,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO,eAAe;AAAA,MACnC,WAAW,OAAO,aAAa,EAAE,eAAe,IAAI;AAAA,MACpD,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,aAAa,OAAO,eAAe;AAAA,MACnC,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,WAAW,OAAO,aAAa;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,OAA8C;AACtD,UAAM,WAAW,KAAK,aAAa,KAAK;AACxC,UAAM,MAAM,EAAE,KAAK;AAEnB,UAAM,KAAK,GACR,KAAK,KAAK,SAAS,EACnB,OAAO;AAAA,MACN,IAAI,SAAS;AAAA,MACb,WAAW,SAAS;AAAA,MACpB,UAAU,SAAS;AAAA,MACnB,QAAQ,SAAS;AAAA,MACjB,SAAS,SAAS;AAAA,MAClB,OAAO,KAAK,UAAU,SAAS,KAAK;AAAA,MACpC,QAAQ,SAAS,SAAS,KAAK,UAAU,SAAS,MAAM,IAAI;AAAA,MAC5D,MAAM,SAAS,OAAO,KAAK,UAAU,SAAS,IAAI,IAAI;AAAA,MACtD,SAAS,SAAS,UAAU,KAAK,UAAU,SAAS,OAAO,IAAI;AAAA,MAC/D,OAAO,SAAS,QAAQ,KAAK,UAAU,SAAS,KAAK,IAAI;AAAA,MACzD,SAAS,SAAS,UAAU,KAAK,UAAU,SAAS,OAAO,IAAI;AAAA,MAC/D,UAAU,SAAS;AAAA,IACrB,CAAC,EACA,QAAQ;AAEX,WAAO,EAAE,GAAG,UAAU,UAAU,IAAI;AAAA,EACtC;AAAA,EAEA,MAAM,SAAS,QAAmD;AAChE,UAAM,UAA8B,CAAC;AAGrC,aAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK,KAAK,OAAO,WAAW;AAC7D,YAAM,QAAQ,OAAO,MAAM,GAAG,IAAI,KAAK,OAAO,SAAS;AAEvD,iBAAW,SAAS,OAAO;AACzB,cAAM,SAAS,MAAM,KAAK,IAAI,KAAK;AACnC,gBAAQ,KAAK,MAAM;AAAA,MACrB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,OAA8C;AACxD,UAAM,YAAY,KAAK,IAAI;AAG3B,QAAI,eAAe,KAAK,GAAG,KAAkB,KAAK,SAAS;AAG3D,QAAI,MAAM,UAAU;AAClB,YAAM,aAAa,MAAM,QAAQ,MAAM,QAAQ,IAAI,MAAM,WAAW,CAAC,MAAM,QAAQ;AACnF,qBAAe,aAAa,QAAQ,YAAY,UAAU;AAAA,IAC5D;AAEA,QAAI,MAAM,QAAQ;AAChB,YAAM,UAAU,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM;AAE1E,YAAM,eAAe,QAAQ,OAAO,CAAC,MAAM,CAAC,EAAE,SAAS,GAAG,CAAC;AAC3D,UAAI,aAAa,SAAS,GAAG;AAC3B,uBAAe,aAAa,QAAQ,UAAU,YAAY;AAAA,MAC5D;AAAA,IACF;AAEA,QAAI,MAAM,SAAS;AACjB,YAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,IAAI,MAAM,UAAU,CAAC,MAAM,OAAO;AAC9E,qBAAe,aAAa,QAAQ,WAAW,QAAQ;AAAA,IACzD;AAEA,QAAI,MAAM,MAAM;AACd,qBAAe,aAAa,MAAM,aAAa,MAAM,IAAI,KAAK,MAAM,IAAI,EAAE,YAAY,CAAC;AAAA,IACzF;AAEA,QAAI,MAAM,IAAI;AACZ,qBAAe,aAAa,MAAM,aAAa,MAAM,IAAI,KAAK,MAAM,EAAE,EAAE,YAAY,CAAC;AAAA,IACvF;AAGA,UAAM,cAAc,MAAM,KAAK,GAAG;AAAA,MAChC,iCAAiC,KAAK,SAAS;AAAA,IACjD;AACA,UAAM,QAAQ,SAAS,OAAO,YAAY,KAAK,CAAC,GAAG,SAAS,CAAC,GAAG,EAAE;AAGlE,UAAM,UAAU,MAAM,WAAW;AACjC,UAAM,QAAQ,MAAM,SAAS;AAC7B,mBAAe,aAAa,QAAQ,SAAS,KAAK;AAGlD,UAAM,SAAS,MAAM,UAAU;AAC/B,UAAM,QAAQ,KAAK,IAAI,MAAM,SAAS,KAAK,GAAI;AAC/C,mBAAe,aAAa,MAAM,KAAK,EAAE,OAAO,MAAM;AAGtD,UAAM,SAAS,MAAM,aAAa,QAAQ;AAC1C,QAAI,SAAS,OAAO,KAAK,IAAI,CAAC,QAAqB,KAAK,WAAW,GAAG,CAAC;AAGvE,QAAI,MAAM,QAAQ;AAChB,YAAM,UAAU,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM;AAC1E,YAAM,kBAAkB,QAAQ,OAAO,CAAC,MAAM,EAAE,SAAS,GAAG,CAAC;AAC7D,UAAI,gBAAgB,SAAS,GAAG;AAC9B,iBAAS,OAAO;AAAA,UAAO,CAAC,MACtB,gBAAgB,KAAK,CAAC,YAAY,YAAY,EAAE,QAAQ,OAAO,CAAC;AAAA,QAClE;AAAA,MACF;AAAA,IACF;AAGA,QAAI,MAAM,SAAS;AACjB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,OAAO,MAAM,OAAO;AAAA,IAC5D;AACA,QAAI,MAAM,WAAW;AACnB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,MAAM,SAAS,MAAM,SAAS;AAAA,IAChE;AACA,QAAI,MAAM,YAAY;AACpB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,SAAS,MAAM,UAAU;AAAA,IACnE;AACA,QAAI,MAAM,UAAU;AAClB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,QAAQ,OAAO,MAAM,QAAQ;AAAA,IAC/D;AACA,QAAI,MAAM,UAAU;AAClB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,aAAa,MAAM,QAAQ;AAAA,IACtE;AACA,QAAI,MAAM,SAAS;AACjB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,YAAY,MAAM,OAAO;AAAA,IACpE;AACA,QAAI,MAAM,eAAe;AACvB,eAAS,OAAO,OAAO,CAAC,MAAM,EAAE,SAAS,kBAAkB,MAAM,aAAa;AAAA,IAChF;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,SAAS,SAAS,OAAO,SAAS;AAAA,MAClC,eAAe,KAAK,IAAI,IAAI;AAAA,IAC9B;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,IAA8C;AAC3D,UAAM,SAAS,MAAM,KAAK,GACvB,KAAkB,KAAK,SAAS,EAChC,MAAM,MAAM,KAAK,EAAE,EACnB,QAAQ;AAEX,UAAM,MAAM,OAAO,KAAK,CAAC;AACzB,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,KAAK,WAAW,GAAG;AAAA,EAC5B;AAAA,EAEA,MAAM,gBAAgB,IAA8B;AAClD,UAAM,QAAQ,MAAM,KAAK,SAAS,EAAE;AACpC,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,CAAC,KAAK,OAAO,mBAAmB,CAAC,MAAM,SAAU,QAAO;AAE5D,UAAM,EAAE,UAAU,SAAS,UAAU,MAAM,GAAG,UAAU,IAAI;AAC5D,UAAM,WAAW,iBAAiB,SAAuB;AAGzD,WAAO,MAAM,SAAS,UAAU,GAAG,EAAE,MAAM,SAAS,UAAU,GAAG,EAAE;AAAA,EACrE;AAAA,EAEA,MAAM,WAAgC;AAEpC,UAAM,iBAAiB,MAAM,KAAK,GAAG;AAAA,MACnC,2CAA2C,KAAK,SAAS;AAAA,IAC3D;AAEA,UAAM,aAA4C;AAAA,MAChD,gBAAgB;AAAA,MAChB,eAAe;AAAA,MACf,aAAa;AAAA,MACb,eAAe;AAAA,MACf,cAAc;AAAA,MACd,UAAU;AAAA,MACV,QAAQ;AAAA,MACR,SAAS;AAAA,MACT,aAAa;AAAA,MACb,QAAQ;AAAA,IACV;AAEA,eAAW,OAAO,eAAe,MAAM;AACrC,iBAAW,IAAI,QAAyB,IAAI,SAAS,IAAI,OAAO,EAAE;AAAA,IACpE;AAGA,UAAM,gBAAgB,MAAM,KAAK,GAAG;AAAA,MAClC,0CAA0C,KAAK,SAAS;AAAA,IAC1D;AAEA,UAAM,YAA0C;AAAA,MAC9C,SAAS;AAAA,MACT,SAAS;AAAA,MACT,QAAQ;AAAA,MACR,OAAO;AAAA,IACT;AAEA,eAAW,OAAO,cAAc,MAAM;AACpC,gBAAU,IAAI,OAAuB,IAAI,SAAS,IAAI,OAAO,EAAE;AAAA,IACjE;AAGA,UAAM,cAAc,MAAM,KAAK,GAAG;AAAA,MAChC,qFAAqF,KAAK,SAAS;AAAA,IACrG;AAEA,UAAM,QAAQ,YAAY,KAAK,CAAC;AAEhC,WAAO;AAAA,MACL,OAAO,SAAS,OAAO,SAAS,KAAK,EAAE;AAAA,MACvC;AAAA,MACA;AAAA,MACA,aAAa,OAAO;AAAA,MACpB,aAAa,OAAO;AAAA,IACtB;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,QAAgD;AACnE,UAAM,kBAAkB,UAAU,KAAK,OAAO;AAC9C,QAAI,gBAAgB,kBAAkB,EAAG,QAAO;AAEhD,UAAM,aAAa,oBAAI,KAAK;AAC5B,eAAW,QAAQ,WAAW,QAAQ,IAAI,gBAAgB,aAAa;AAEvE,QAAI,MAAM,eAAe,KAAK,SAAS;AACvC,UAAM,SAAoB,CAAC,WAAW,YAAY,CAAC;AAGnD,QAAI,gBAAgB,oBAAoB,gBAAgB,iBAAiB,SAAS,GAAG;AACnF,YAAM,eAAe,gBAAgB,iBAAiB,IAAI,CAAC,GAAG,MAAM,IAAI,IAAI,CAAC,EAAE,EAAE,KAAK,IAAI;AAC1F,aAAO,yBAAyB,YAAY;AAC5C,aAAO,KAAK,GAAG,gBAAgB,gBAAgB;AAAA,IACjD;AAEA,UAAM,SAAS,MAAM,KAAK,GAAG,IAAI,KAAK,MAAM;AAC5C,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA,EAEA,MAAM,OAAO,OAAgD;AAE3D,UAAM,YAAgC,CAAC;AACvC,QAAI,SAAS;AACb,UAAM,YAAY;AAElB,WAAO,MAAM;AACX,YAAM,SAAS,MAAM,KAAK,MAAM,EAAE,GAAG,OAAO,OAAO,WAAW,OAAO,CAAC;AACtE,gBAAU,KAAK,GAAG,OAAO,MAAM;AAE/B,UAAI,CAAC,OAAO,QAAS;AACrB,gBAAU;AAAA,IACZ;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAgC;AACpC,QAAI;AACF,YAAM,KAAK,GAAG,IAAI,iBAAiB,KAAK,SAAS,UAAU;AAC3D,aAAO;AAAA,IACT,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,MAAM,QAAuB;AAAA,EAE7B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,kBAAkB,YAAoB,cAAsB;AACjE,WAAO;AAAA,6BACkB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAiBL,SAAS,iBAAiB,SAAS;AAAA,iCACnC,SAAS,gBAAgB,SAAS;AAAA,iCAClC,SAAS,cAAc,SAAS;AAAA,iCAChC,SAAS,eAAe,SAAS;AAAA,iCACjC,SAAS,gBAAgB,SAAS;AAAA,iCAClC,SAAS,iBAAiB,SAAS;AAAA,iCACnC,SAAS,gBAAgB,SAAS;AAAA,MAC7D,KAAK;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,aAAa,OAAuD;AAC1E,UAAM,KAAK,MAAM,MAAM,KAAK,OAAO,YAAY;AAC/C,UAAM,YAAY,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAG5D,QAAI,UAAU,MAAM;AACpB,QAAI,KAAK,OAAO,iBAAiB;AAC/B,YAAM,kBAAkB,mBAAmB,IAAI;AAC/C,UAAI,iBAAiB;AACnB,kBAAU;AAAA,UACR,GAAG;AAAA,UACH,SAAS,SAAS,WAAW,gBAAgB;AAAA,UAC7C,eAAe,SAAS,iBAAiB,gBAAgB;AAAA,UACzD,WAAW,SAAS,aAAa,gBAAgB;AAAA,UACjD,UAAU,SAAS,YAAY,gBAAgB;AAAA,QACjD;AAAA,MACF;AACA,gBAAU;AAAA,QACR,GAAG;AAAA,QACH,aAAa,KAAK,OAAO;AAAA,QACzB,SAAS,KAAK,OAAO;AAAA,MACvB;AAAA,IACF;AAEA,UAAM,uBAAuB;AAAA,MAC3B;AAAA,MACA;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb,QAAQ,MAAM;AAAA,MACd,MAAM,MAAM;AAAA,MACZ,SAAS,MAAM;AAAA,MACf,OAAO,MAAM;AAAA,MACb;AAAA,IACF;AAEA,UAAM,WAAW,KAAK,OAAO,kBACzB,iBAAiB,oBAAoB,IACrC;AAEJ,WAAO;AAAA,MACL,GAAG;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,WAAW,KAAoC;AACrD,UAAM,YAAY,CAAC,UAAoG;AACrH,UAAI,UAAU,UAAa,UAAU,KAAM,QAAO;AAClD,UAAI,OAAO,UAAU,UAAU;AAC7B,YAAI;AACF,iBAAO,KAAK,MAAM,KAAK;AAAA,QACzB,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,UAAU,IAAI,KAAK;AACrC,UAAM,aAAa,UAAU,IAAI,MAAM;AACvC,UAAM,cAAc,UAAU,IAAI,OAAO;AACzC,UAAM,YAAY,UAAU,IAAI,KAAK;AACrC,UAAM,cAAc,UAAU,IAAI,OAAO;AAEzC,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,UAAU,IAAI,YAAY;AAAA,MAC1B,WAAW,IAAI;AAAA,MACf,UAAU,IAAI;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,SAAS,IAAI;AAAA,MACb,OAAO;AAAA,QACL,MAAO,WAAW,QAAwD;AAAA,QAC1E,IAAI,WAAW;AAAA,QACf,MAAM,WAAW;AAAA,QACjB,OAAO,WAAW;AAAA,QAClB,IAAI,WAAW;AAAA,QACf,WAAW,WAAW;AAAA,QACtB,WAAW,WAAW;AAAA,MACxB;AAAA,MACA,QAAQ,aAAa;AAAA,QACnB,MAAM,WAAW;AAAA,QACjB,IAAI,WAAW;AAAA,QACf,MAAM,WAAW;AAAA,QACjB,YAAY,WAAW;AAAA,MACzB,IAAI;AAAA,MACJ,MAAM,UAAU,IAAI,IAAI;AAAA,MACxB,SAAS,cAAc;AAAA,QACrB,QAAQ,YAAY;AAAA,QACpB,OAAO,YAAY;AAAA,MACrB,IAAI;AAAA,MACJ,OAAO,YAAY;AAAA,QACjB,MAAM,UAAU;AAAA,QAChB,SAAS,UAAU;AAAA,QACnB,OAAO,UAAU;AAAA,MACnB,IAAI;AAAA,MACJ,SAAS,cAAc;AAAA,QACrB,SAAS,YAAY;AAAA,QACrB,eAAe,YAAY;AAAA,QAC3B,WAAW,YAAY;AAAA,QACvB,UAAU,YAAY;AAAA,QACtB,aAAa,YAAY;AAAA,QACzB,SAAS,YAAY;AAAA,MACvB,IAAI;AAAA,MACJ,UAAU,IAAI,YAAY;AAAA,IAC5B;AAAA,EACF;AACF;;;AC7bO,IAAM,wBAAN,MAAsD;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,cAA4B,CAAC;AAAA,EAC7B,UAAyB,CAAC;AAAA,EAC1B,UAAwB,CAAC;AAAA,EACzB,OAA+B,CAAC;AAAA,EAChC,cAAyE;AAAA,EACzE;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGA,aAA4B,QAAQ,QAAQ;AAAA,EAEpD,YAAY,QAAqC;AAC/C,SAAK,KAAK,OAAO;AACjB,SAAK,cAAc,OAAO,eAAe;AACzC,SAAK,mBAAmB,OAAO,oBAAoB;AACnD,SAAK,sBAAsB,OAAO,uBAAuB;AACzD,SAAK,gBAAgB,OAAO,iBAAiB;AAC7C,SAAK,iBAAiB,OAAO,kBAAkB;AAC/C,SAAK,aAAa,OAAO,cAAc;AACvC,SAAK,aAAa,OAAO;AAGzB,SAAK,UAAU;AAAA,MACb,SAAS,OAAO;AAAA,MAChB,aAAa,OAAO,eAAe;AAAA,MACnC,SAAS,OAAO;AAAA,IAClB;AAEA,QAAI,OAAO,aAAa;AACtB,WAAK,OAAO,EAAE,GAAG,OAAO,YAAY;AAAA,IACtC;AAAA,EACF;AAAA,EAEA,aAAa,OAAc,SAAkC;AAE3D,QAAI,KAAK,OAAO,IAAI,KAAK,YAAY;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,mBAAmB,IAAI;AAGnC,UAAM,cAA4B;AAAA,MAChC,GAAG,KAAK;AAAA,MACR,GAAG,SAAS;AAAA,MACZ,eAAe,KAAK,iBAAiB,KAAK,QAAQ;AAAA,MAClD,SAAS,KAAK,WAAW,KAAK,QAAQ;AAAA,MACtC,QAAQ,KAAK,aAAa,MAAM,KAAK,QAAQ;AAAA,MAC7C,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,SAAS,KAAK;AAAA,MACvC,OAAO,SAAS;AAAA,IAClB;AAGA,QAAI,SAAS,kBAAkB,OAAO,aAAa;AAAA,MACjD,GAAG;AAAA,MACH,aAAa,SAAS,eAAe,oBAAoB,KAAK;AAAA,IAChE,CAAC;AAGD,WAAO,cAAc,CAAC,GAAG,KAAK,WAAW;AAGzC,QAAI,KAAK,YAAY;AACnB,YAAM,WAAW,KAAK,WAAW,MAAM;AACvC,UAAI,CAAC,SAAU,QAAO;AACtB,eAAS;AAAA,IACX;AAGA,SAAK,QAAQ,KAAK,MAAM;AAGxB,QAAI,OAAO,SAAS,OAAO,MAAM,SAAS,KAAK,qBAAqB;AAClE,aAAO,QAAQ,OAAO,MAAM,UAAU,GAAG,KAAK,mBAAmB;AAAA,IACnE;AAGA,SAAK,WAAW,MAAM;AAEtB,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,eAAe,SAAiB,SAAkC;AAEhE,QAAI,KAAK,OAAO,IAAI,KAAK,YAAY;AACnC,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,mBAAmB,IAAI;AACnC,UAAM,KAAK,gBAAgB;AAG3B,UAAM,cAA4B;AAAA,MAChC,GAAG,KAAK;AAAA,MACR,GAAG,SAAS;AAAA,MACZ,eAAe,KAAK,iBAAiB,KAAK,QAAQ;AAAA,MAClD,SAAS,KAAK,WAAW,KAAK,QAAQ;AAAA,MACtC,QAAQ,KAAK,aAAa,MAAM,KAAK,QAAQ;AAAA,MAC7C,MAAM,EAAE,GAAG,KAAK,MAAM,GAAG,SAAS,KAAK;AAAA,MACvC,OAAO,SAAS;AAAA,IAClB;AAEA,QAAI,SAAsB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO,SAAS,SAAS;AAAA,MACzB,WAAW,KAAK,IAAI;AAAA,MACpB,SAAS,SAAS,WAAW;AAAA,MAC7B,aAAa,SAAS,eAAe,CAAC,OAAO;AAAA,MAC7C,aAAa,CAAC,GAAG,KAAK,WAAW;AAAA,IACnC;AAGA,QAAI,KAAK,YAAY;AACnB,YAAM,WAAW,KAAK,WAAW,MAAM;AACvC,UAAI,CAAC,SAAU,QAAO;AACtB,eAAS;AAAA,IACX;AAGA,SAAK,QAAQ,KAAK,MAAM;AAGxB,SAAK,WAAW,MAAM;AAEtB,WAAO;AAAA,EACT;AAAA,EAEA,cAAc,YAAiD;AAC7D,UAAM,QAAoB;AAAA,MACxB,GAAG;AAAA,MACH,WAAW,KAAK,IAAI;AAAA,IACtB;AAEA,SAAK,YAAY,KAAK,KAAK;AAG3B,QAAI,KAAK,YAAY,SAAS,KAAK,gBAAgB;AACjD,WAAK,cAAc,KAAK,YAAY,MAAM,CAAC,KAAK,cAAc;AAAA,IAChE;AAAA,EACF;AAAA,EAEA,QAAQ,MAAuE;AAC7E,SAAK,cAAc;AAAA,EACrB;AAAA,EAEA,WAAW,MAAc,SAA+C;AACtE,QAAI,YAAY,MAAM;AAEpB,YAAM,EAAE,CAAC,IAAI,GAAG,GAAG,GAAG,KAAK,IAAI,KAAK,QAAQ,SAAS,CAAC;AACtD,WAAK,QAAQ,QAAQ,OAAO,KAAK,IAAI,EAAE,SAAS,IAAI,OAAkC;AAAA,IACxF,OAAO;AAEL,WAAK,QAAQ,QAAQ;AAAA,QACnB,GAAG,KAAK,QAAQ;AAAA,QAChB,CAAC,IAAI,GAAG;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA,EAEA,OAAO,KAAa,OAAqB;AACvC,SAAK,KAAK,GAAG,IAAI;AAAA,EACnB;AAAA,EAEA,WAAW,SAAiE;AAC1E,QAAI,UAAU,CAAC,GAAG,KAAK,OAAO;AAE9B,QAAI,SAAS,OAAO;AAClB,gBAAU,QAAQ,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,KAAK;AAAA,IAC3D;AAGA,YAAQ,KAAK,CAAC,GAAG,MAAM,EAAE,YAAY,EAAE,SAAS;AAEhD,QAAI,SAAS,OAAO;AAClB,gBAAU,QAAQ,MAAM,GAAG,QAAQ,KAAK;AAAA,IAC1C;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,eAAqB;AACnB,SAAK,UAAU,CAAC;AAAA,EAClB;AAAA,EAEA,MAAM,MAAM,SAAoC;AAE9C,QAAI,SAAS;AACX,aAAO,QAAQ,KAAK;AAAA,QAClB,KAAK,WAAW,KAAK,MAAM,IAAI;AAAA,QAC/B,IAAI,QAAiB,CAAC,YAAY,WAAW,MAAM,QAAQ,KAAK,GAAG,OAAO,CAAC;AAAA,MAC7E,CAAC;AAAA,IACH;AAEA,UAAM,KAAK;AACX,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,MAAM;AACjB,SAAK,UAAU,CAAC;AAChB,SAAK,cAAc,CAAC;AACpB,SAAK,UAAU,CAAC;AAChB,SAAK,OAAO,CAAC;AACb,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,YAAY,SAMS;AACzB,QAAI,UAAU,KAAK,GAAG,KAAK,KAAK,WAAW;AAE3C,QAAI,SAAS,OAAO;AAClB,gBAAU,QAAQ,MAAM,SAAS,KAAK,QAAQ,KAAK;AAAA,IACrD;AACA,QAAI,SAAS,MAAM;AACjB,YAAM,SAAS,OAAO,QAAQ,SAAS,WAAW,QAAQ,OAAO,QAAQ,KAAK,QAAQ;AACtF,gBAAU,QAAQ,MAAM,cAAc,MAAM,MAAM;AAAA,IACpD;AACA,QAAI,SAAS,IAAI;AACf,YAAM,OAAO,OAAO,QAAQ,OAAO,WAAW,QAAQ,KAAK,QAAQ,GAAG,QAAQ;AAC9E,gBAAU,QAAQ,MAAM,cAAc,MAAM,IAAI;AAAA,IAClD;AAEA,cAAU,QAAQ,QAAQ,cAAc,MAAM;AAE9C,QAAI,SAAS,OAAO;AAClB,gBAAU,QAAQ,MAAM,QAAQ,KAAK;AAAA,IACvC;AAEA,UAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,UAAM,UAAyB,CAAC;AAEhC,eAAW,OAAO,OAAO,MAAoB;AAC3C,YAAM,cAAc,MAAM,KAAK,gBAAgB,IAAI,EAAE;AACrD,cAAQ,KAAK,KAAK,YAAY,KAAK,WAAW,CAAC;AAAA,IACjD;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAA2B;AAC/B,UAAM,SAAS,KAAK,IAAI,IAAI,KAAK,gBAAgB,KAAK,KAAK,KAAK;AAGhE,UAAM,YAAY,MAAM,KAAK,GAC1B,KAAK,KAAK,WAAW,EACrB,MAAM,cAAc,KAAK,MAAM,EAC/B,QAAQ;AAEX,UAAM,MAAO,UAAU,KAAoB,IAAI,CAAC,MAAM,EAAE,EAAE;AAE1D,QAAI,IAAI,WAAW,EAAG,QAAO;AAG7B,eAAW,MAAM,KAAK;AACpB,YAAM,KAAK,GACR,KAAK,KAAK,gBAAgB,EAC1B,MAAM,YAAY,KAAK,EAAE,EACzB,OAAO,EACP,QAAQ;AAAA,IACb;AAGA,UAAM,KAAK,GACR,KAAK,KAAK,WAAW,EACrB,MAAM,cAAc,KAAK,MAAM,EAC/B,OAAO,EACP,QAAQ;AAEX,WAAO,IAAI;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAS,WAAmB,KAAK,KAAK,KAAK,KAI9C;AACD,UAAM,SAAS,KAAK,IAAI,IAAI;AAE5B,UAAM,YAAY,MAAM,KAAK,GAAG,KAAK,KAAK,WAAW,EAAE,QAAQ;AAC/D,UAAM,eAAe,MAAM,KAAK,GAC7B,KAAK,KAAK,WAAW,EACrB,MAAM,cAAc,KAAK,MAAM,EAC/B,QAAQ;AAEX,UAAM,SAAS,UAAU;AACzB,UAAM,UAAsC;AAAA,MAC1C,OAAO;AAAA,MACP,OAAO;AAAA,MACP,SAAS;AAAA,MACT,MAAM;AAAA,MACN,OAAO;AAAA,IACT;AAEA,eAAW,SAAS,QAAQ;AAC1B,YAAM,QAAQ,MAAM;AACpB,cAAQ,KAAK,KAAK,QAAQ,KAAK,KAAK,KAAK;AAAA,IAC3C;AAEA,WAAO;AAAA,MACL,OAAO,OAAO;AAAA,MACd;AAAA,MACA,cAAc,aAAa,KAAK;AAAA,IAClC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,kBACL,cAAc,iBACd,mBAAmB,qBACX;AACR,WAAO;AAAA,6BACkB,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAYP,WAAW,aAAa,WAAW;AAAA,iCACnC,WAAW,eAAe,WAAW;AAAA;AAAA,6BAEzC,gBAAgB;AAAA;AAAA,8CAEC,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAQxB,gBAAgB,aAAa,gBAAgB;AAAA,MACxE,KAAK;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMQ,WAAW,QAA2B;AAC5C,SAAK,aAAa,KAAK,WAAW,KAAK,YAAY;AACjD,UAAI;AACF,cAAM,KAAK,gBAAgB,MAAM;AAAA,MACnC,SAAS,OAAO;AAEd,gBAAQ,MAAM,6CAA6C,KAAK;AAAA,MAClE;AAAA,IACF,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,gBAAgB,QAAoC;AAEhE,UAAM,KAAK,GAAG,KAAK,KAAK,WAAW,EAAE,OAAO;AAAA,MAC1C,IAAI,OAAO;AAAA,MACX,OAAO,OAAO;AAAA,MACd,SAAS,OAAO;AAAA,MAChB,MAAM,OAAO;AAAA,MACb,OAAO,OAAO;AAAA,MACd,aAAa,KAAK,UAAU,OAAO,eAAe,CAAC,CAAC;AAAA,MACpD,SAAS,KAAK,UAAU,OAAO,OAAO;AAAA,MACtC,SAAS,OAAO;AAAA,MAChB,YAAY,OAAO;AAAA,IACrB,CAAC,EAAE,QAAQ;AAGX,QAAI,OAAO,eAAe,OAAO,YAAY,SAAS,GAAG;AACvD,iBAAW,SAAS,OAAO,aAAa;AACtC,cAAM,KAAK,GAAG,KAAK,KAAK,gBAAgB,EAAE,OAAO;AAAA,UAC/C,IAAI,MAAM,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC,CAAC;AAAA,UAC9E,UAAU,OAAO;AAAA,UACjB,UAAU,MAAM;AAAA,UAChB,SAAS,MAAM;AAAA,UACf,OAAO,MAAM;AAAA,UACb,MAAM,MAAM,OAAO,KAAK,UAAU,MAAM,IAAI,IAAI;AAAA,UAChD,WAAW,MAAM;AAAA,QACnB,CAAC,EAAE,QAAQ;AAAA,MACb;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,SAAwC;AACpE,UAAM,SAAS,MAAM,KAAK,GACvB,KAAK,KAAK,gBAAgB,EAC1B,MAAM,YAAY,KAAK,OAAO,EAC9B,QAAQ,aAAa,KAAK,EAC1B,QAAQ;AAEX,WAAQ,OAAO,KAAyB,IAAI,CAAC,SAAS;AAAA,MACpD,UAAU,IAAI;AAAA,MACd,SAAS,IAAI;AAAA,MACb,OAAO,IAAI;AAAA,MACX,MAAM,IAAI,OAAQ,OAAO,IAAI,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI,IAAI,IAAI,OAAQ;AAAA,MACpF,WAAW,IAAI;AAAA,IACjB,EAAE;AAAA,EACJ;AAAA,EAEQ,YAAY,KAAe,aAAwC;AACzE,UAAM,UAAU,IAAI,UACf,OAAO,IAAI,YAAY,WAAW,KAAK,MAAM,IAAI,OAAO,IAAI,IAAI,UACjE,CAAC;AAEL,UAAM,cAAc,IAAI,cACnB,OAAO,IAAI,gBAAgB,WAAW,KAAK,MAAM,IAAI,WAAW,IAAI,IAAI,cACzE,CAAC;AAEL,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,SAAS,IAAI;AAAA,MACb,MAAM,IAAI;AAAA,MACV,OAAO,IAAI;AAAA,MACX;AAAA,MACA,OAAO,IAAI;AAAA,MACX,WAAW,IAAI;AAAA,MACf,SAAS,IAAI;AAAA,MACb,aAAa,MAAM,QAAQ,WAAW,IAAI,cAAc,CAAC,WAAW;AAAA,MACpE;AAAA,IACF;AAAA,EACF;AACF;;;AC5bO,IAAM,iBAAN,MAA2C;AAAA,EACxC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAkD,oBAAI,IAAI;AAAA,EAC1D;AAAA,EACA,UAAU;AAAA;AAAA,EAGV,kBAAsD,oBAAI,IAAI;AAAA,EAC9D,mBAAqD,oBAAI,IAAI;AAAA,EAErE,YAAY,QAA8B;AACxC,SAAK,QAAQ,OAAO;AACpB,SAAK,KAAK,OAAO;AACjB,SAAK,iBAAiB,OAAO,kBAAkB;AAC/C,SAAK,kBAAkB,OAAO,mBAAmB;AACjD,SAAK,SAAS;AAAA,MACZ,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,eAAe,OAAO,iBAAiB;AAAA;AAAA,MACvC,iBAAiB,OAAO,mBAAmB;AAAA;AAAA,MAC3C,sBAAsB,OAAO,wBAAwB;AAAA,MACrD,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,aAAa,OAAO,eAAe;AAAA,IACrC;AAAA,EACF;AAAA,EAEA,MAAM,OAAU,SAA6D;AAE3E,QAAI,QAAQ,QAAQ,CAAC,YAAY,QAAQ,IAAI,GAAG;AAC9C,YAAM,IAAI,MAAM,4BAA4B,QAAQ,IAAI,EAAE;AAAA,IAC5D;AACA,QAAI,CAAC,QAAQ,QAAQ,CAAC,QAAQ,OAAO;AACnC,YAAM,IAAI,MAAM,uCAAuC;AAAA,IACzD;AAEA,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,KAAK,QAAQ,MAAM,mBAAmB;AAG5C,QAAI;AACJ,QAAI,QAAQ,MAAM;AAChB,YAAM,OAAO,eAAe,QAAQ,MAAM,oBAAI,KAAK,GAAG,QAAQ,QAAQ;AACtE,gBAAU,MAAM,YAAY;AAAA,IAC9B,WAAW,QAAQ,OAAO;AACxB,gBAAU,IAAI,KAAK,QAAQ,KAAK,EAAE,YAAY;AAAA,IAChD;AAEA,UAAM,WAA4B;AAAA,MAChC;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ;AAAA,MACrB,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ,QAAQ,IAAI,KAAK,QAAQ,KAAK,EAAE,YAAY,IAAI;AAAA,MAC/D,UAAU,QAAQ,YAAY,KAAK,OAAO;AAAA,MAC1C,MAAM,QAAQ;AAAA,MACd,OAAO,QAAQ,SAAS,WAAW;AAAA,MACnC,WAAW;AAAA,MACX,WAAW;AAAA,MACX;AAAA,MACA,UAAU;AAAA,MACV,cAAc;AAAA,MACd,SAAS,QAAQ;AAAA,MACjB,MAAM,QAAQ;AAAA,MACd,UAAU,QAAQ;AAAA,IACpB;AAEA,UAAM,KAAK,aAAa,QAAQ;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAO,IAA6C;AACxD,WAAO,KAAK,aAAgB,EAAE;AAAA,EAChC;AAAA,EAEA,MAAM,OAAU,IAAY,SAA6D;AACvF,UAAM,WAAW,MAAM,KAAK,aAAgB,EAAE;AAC9C,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AAAA,IAC7C;AAGA,QAAI,QAAQ,QAAQ,CAAC,YAAY,QAAQ,IAAI,GAAG;AAC9C,YAAM,IAAI,MAAM,4BAA4B,QAAQ,IAAI,EAAE;AAAA,IAC5D;AAGA,UAAM,UAA2B;AAAA,MAC/B,GAAG;AAAA,MACH,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC/B,OAAO,QAAQ,QAAQ,IAAI,KAAK,QAAQ,KAAK,EAAE,YAAY,IAAI,SAAS;AAAA,MACxE,UAAU,QAAQ,YAAY,SAAS;AAAA,MACvC,MAAM,QAAQ,SAAS,SAAY,QAAQ,OAAO,SAAS;AAAA,MAC3D,SAAS,QAAQ,WAAW,SAAS;AAAA,MACrC,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC/B,UAAU,QAAQ,YAAY,SAAS;AAAA,MACvC,aAAa,QAAQ,eAAe,SAAS;AAAA,MAC7C,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAGA,QAAI,QAAQ,QAAQ,QAAQ,OAAO;AACjC,UAAI,QAAQ,MAAM;AAChB,cAAM,OAAO,eAAe,QAAQ,MAAM,oBAAI,KAAK,GAAG,QAAQ,QAAQ;AACtE,gBAAQ,UAAU,MAAM,YAAY;AAAA,MACtC,WAAW,QAAQ,OAAO;AACxB,gBAAQ,UAAU,QAAQ;AAAA,MAC5B;AAAA,IACF;AAEA,UAAM,KAAK,aAAa,OAAO;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,QAAI,KAAK,IAAI;AACX,YAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,MAAM,MAAM,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ;AAC9E,YAAM,KAAK,GAAG,KAAK,KAAK,eAAe,EAAE,MAAM,eAAe,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ;AAAA,IAC1F,OAAO;AACL,WAAK,gBAAgB,OAAO,EAAE;AAC9B,WAAK,iBAAiB,OAAO,EAAE;AAAA,IACjC;AAAA,EACF;AAAA,EAEA,MAAM,MAAM,IAA2B;AACrC,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AAE1D,aAAS,QAAQ;AACjB,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AAE1D,aAAS,QAAQ;AACjB,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAG5C,QAAI,SAAS,MAAM;AACjB,YAAM,OAAO,eAAe,SAAS,MAAM,oBAAI,KAAK,GAAG,SAAS,QAAQ;AACxE,eAAS,UAAU,MAAM,YAAY;AAAA,IACvC;AAEA,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,QAAQ,IAA6B;AACzC,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB,EAAE,EAAE;AAE1D,WAAO,KAAK,gBAAgB,QAAQ;AAAA,EACtC;AAAA,EAEA,MAAM,KAAQ,OAAmD;AAC/D,QAAI,YAAY,MAAM,KAAK,iBAAoB;AAG/C,QAAI,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK;AACtE,kBAAY,UAAU,OAAO,CAAC,MAAM,OAAO,SAAS,EAAE,KAAK,CAAC;AAAA,IAC9D;AAEA,QAAI,OAAO,QAAQ,MAAM,KAAK,SAAS,GAAG;AACxC,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,MAAM,KAAM,KAAK,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC;AAAA,MACjD;AAAA,IACF;AAEA,QAAI,OAAO,MAAM;AACf,YAAM,UAAU,MAAM,KAAK,QAAQ,OAAO,IAAI;AAC9C,YAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,KAAK,GAAG;AAC5C,kBAAY,UAAU,OAAO,CAAC,MAAM,MAAM,KAAK,EAAE,IAAI,CAAC;AAAA,IACxD;AAEA,QAAI,OAAO,eAAe;AACxB,YAAM,SAAS,IAAI,KAAK,MAAM,aAAa,EAAE,QAAQ;AACrD,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,EAAE,WAAW,IAAI,KAAK,EAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,MAC/C;AAAA,IACF;AAEA,QAAI,OAAO,cAAc;AACvB,YAAM,QAAQ,IAAI,KAAK,MAAM,YAAY,EAAE,QAAQ;AACnD,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,EAAE,WAAW,IAAI,KAAK,EAAE,OAAO,EAAE,QAAQ,IAAI;AAAA,MAC/C;AAAA,IACF;AAGA,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,QAAQ,OAAO,SAAS;AAC9B,WAAO,UAAU,MAAM,QAAQ,SAAS,KAAK;AAAA,EAC/C;AAAA,EAEA,MAAM,WAAW,YAAoB,QAAQ,IAAkC;AAC7E,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GACvB,KAAK,KAAK,eAAe,EACzB,MAAM,eAAe,KAAK,UAAU,EACpC,QAAQ,cAAc,MAAM,EAC5B,MAAM,KAAK,EACX,QAAQ;AAEX,aAAQ,OAAO,KAAwB,IAAI,CAAC,QAAQ,KAAK,eAAe,GAAG,CAAC;AAAA,IAC9E,OAAO;AACL,YAAM,aAAa,KAAK,iBAAiB,IAAI,UAAU,KAAK,CAAC;AAC7D,aAAO,WAAW,MAAM,CAAC,KAAK,EAAE,QAAQ;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,OAAU,MAAc,SAAmC;AACzD,SAAK,SAAS,IAAI,MAAM,OAAmC;AAAA,EAC7D;AAAA,EAEA,MAAM,QAAuB;AAC3B,QAAI,KAAK,QAAS;AAClB,SAAK,UAAU;AAGf,SAAK,MAAM,QAAQ,OAAO,QAAsB;AAC9C,UAAI,IAAI,KAAK,WAAW,YAAY,GAAG;AACrC,cAAM,OAAO,IAAI;AACjB,cAAM,aAAa,KAAK;AACxB,cAAM,cAAc,KAAK;AACzB,cAAM,KAAK,oBAAoB,YAAY,WAAW;AAAA,MACxD;AAAA,IACF,CAAC;AAGD,SAAK,aAAa;AAAA,MAChB,MAAM,KAAK,kBAAkB;AAAA,MAC7B,KAAK,OAAO;AAAA,IACd;AAGA,UAAM,KAAK,kBAAkB;AAAA,EAC/B;AAAA,EAEA,MAAM,OAAsB;AAC1B,SAAK,UAAU;AACf,QAAI,KAAK,YAAY;AACnB,oBAAc,KAAK,UAAU;AAC7B,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEA,MAAM,WAAoC;AACxC,UAAM,YAAY,MAAM,KAAK,iBAAiB;AAE9C,UAAM,QAAwB;AAAA,MAC5B,OAAO,UAAU;AAAA,MACjB,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,WAAW;AAAA,MACX,WAAW;AAAA,MACX,mBAAmB;AAAA,MACnB,iBAAiB;AAAA,IACnB;AAEA,eAAW,YAAY,WAAW;AAChC,cAAQ,SAAS,OAAO;AAAA,QACtB,KAAK;AAAU,gBAAM;AAAU;AAAA,QAC/B,KAAK;AAAU,gBAAM;AAAU;AAAA,QAC/B,KAAK;AAAa,gBAAM;AAAa;AAAA,QACrC,KAAK;AAAa,gBAAM;AAAa;AAAA,MACvC;AAAA,IACF;AAGA,UAAM,oBAAoB,UACvB,OAAO,CAAC,MAAM,EAAE,UAAU,YAAY,EAAE,OAAO,EAC/C,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,OAAQ,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,OAAQ,EAAE,QAAQ,CAAC;AAEjF,UAAM,gBAAgB,kBAAkB,CAAC,GAAG;AAG5C,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI;AAC3D,eAAW,YAAY,WAAW;AAChC,YAAM,UAAU,MAAM,KAAK,WAAW,SAAS,IAAI,GAAG;AACtD,iBAAW,QAAQ,SAAS;AAC1B,YAAI,IAAI,KAAK,KAAK,SAAS,IAAI,WAAW;AACxC,gBAAM;AACN,cAAI,KAAK,WAAW,WAAW;AAC7B,kBAAM;AAAA,UACR;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,cAAgC;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAM,QAAuB;AAC3B,UAAM,KAAK,KAAK;AAChB,SAAK,SAAS,MAAM;AACpB,SAAK,gBAAgB,MAAM;AAC3B,SAAK,iBAAiB,MAAM;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,kBACL,iBAAiB,kBACjB,kBAAkB,uBACV;AACR,WAAO;AAAA,6BACkB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAsBV,cAAc,aAAa,cAAc;AAAA,iCACzC,cAAc,gBAAgB,cAAc;AAAA,iCAC5C,cAAc,YAAY,cAAc;AAAA;AAAA,6BAE5C,eAAe;AAAA;AAAA,iDAEK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAS9B,eAAe,gBAAgB,eAAe;AAAA,iCAC9C,eAAe,eAAe,eAAe;AAAA,MACxE,KAAK;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,aAAa,UAAgD;AACzE,QAAI,KAAK,IAAI;AACX,YAAM,WAAW,MAAM,KAAK,GACzB,KAAK,KAAK,cAAc,EACxB,MAAM,MAAM,KAAK,SAAS,EAAE,EAC5B,QAAQ;AAEX,YAAM,MAAM,KAAK,cAAc,QAAQ;AAEvC,UAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,cAAM,KAAK,GACR,KAAK,KAAK,cAAc,EACxB,OAAO,GAAG,EACV,MAAM,MAAM,KAAK,SAAS,EAAE,EAC5B,QAAQ;AAAA,MACb,OAAO;AACL,cAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,OAAO,GAAG,EAAE,QAAQ;AAAA,MAC9D;AAAA,IACF,OAAO;AACL,WAAK,gBAAgB,IAAI,SAAS,IAAI,QAAQ;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,MAAc,aAAgB,IAA6C;AACzE,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GACvB,KAAK,KAAK,cAAc,EACxB,MAAM,MAAM,KAAK,EAAE,EACnB,QAAQ;AAEX,UAAI,OAAO,KAAK,WAAW,EAAG,QAAO;AACrC,aAAO,KAAK,cAAiB,OAAO,KAAK,CAAC,CAAgB;AAAA,IAC5D,OAAO;AACL,aAAQ,KAAK,gBAAgB,IAAI,EAAE,KAAyB;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,MAAc,mBAA4D;AACxE,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,QAAQ;AAC/D,aAAQ,OAAO,KAAuB,IAAI,CAAC,QAAQ,KAAK,cAAiB,GAAG,CAAC;AAAA,IAC/E,OAAO;AACL,aAAO,MAAM,KAAK,KAAK,gBAAgB,OAAO,CAAC;AAAA,IACjD;AAAA,EACF;AAAA,EAEQ,cAAc,UAA0D;AAC9E,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,MAAM,SAAS;AAAA,MACf,aAAa,SAAS;AAAA,MACtB,MAAM,SAAS;AAAA,MACf,QAAQ,SAAS;AAAA,MACjB,UAAU,SAAS;AAAA,MACnB,MAAM,KAAK,UAAU,SAAS,IAAI;AAAA,MAClC,OAAO,SAAS;AAAA,MAChB,YAAY,SAAS;AAAA,MACrB,YAAY,SAAS;AAAA,MACrB,UAAU,SAAS;AAAA,MACnB,UAAU,SAAS;AAAA,MACnB,aAAa,SAAS;AAAA,MACtB,YAAY,SAAS;AAAA,MACrB,WAAW,SAAS;AAAA,MACpB,eAAe,SAAS;AAAA,MACxB,UAAU,SAAS;AAAA,MACnB,MAAM,SAAS,OAAO,IAAI,SAAS,KAAK,KAAK,GAAG,CAAC,MAAM;AAAA,MACvD,UAAU,SAAS,WAAW,KAAK,UAAU,SAAS,QAAQ,IAAI;AAAA,IACpE;AAAA,EACF;AAAA,EAEQ,cAAiB,KAAmC;AAC1D,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,aAAa,IAAI;AAAA,MACjB,MAAM,IAAI;AAAA,MACV,OAAO,IAAI;AAAA,MACX,UAAU,IAAI;AAAA,MACd,MAAM,OAAO,IAAI,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI,IAAI,IAAI;AAAA,MAChE,OAAO,IAAI;AAAA,MACX,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,SAAS,IAAI;AAAA,MACb,SAAS,IAAI;AAAA,MACb,YAAY,IAAI;AAAA,MAChB,WAAW,IAAI;AAAA,MACf,UAAU,IAAI;AAAA,MACd,cAAc,IAAI;AAAA,MAClB,SAAS,IAAI;AAAA,MACb,MAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO,IAAI;AAAA,MAC5E,UAAU,IAAI,WAAY,OAAO,IAAI,aAAa,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI,IAAI,WAAY;AAAA,IAC1G;AAAA,EACF;AAAA,EAEQ,eAAe,KAAsC;AAC3D,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,YAAY,IAAI;AAAA,MAChB,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,MACjB,UAAU,IAAI;AAAA,MACd,QAAQ,IAAI;AAAA,MACZ,OAAO,IAAI;AAAA,MACX,OAAO,IAAI;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAc,oBAAmC;AAC/C,QAAI,CAAC,KAAK,QAAS;AAEnB,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,YAAY,IAAI,KAAK,IAAI,QAAQ,IAAI,KAAK,OAAO,eAAe;AAEtE,UAAM,YAAY,MAAM,KAAK,KAAK;AAAA,MAChC,OAAO;AAAA,MACP,eAAe;AAAA,IACjB,CAAC;AAED,eAAW,YAAY,WAAW;AAChC,UAAI,CAAC,SAAS,QAAS;AAEvB,YAAM,cAAc,IAAI,KAAK,SAAS,OAAO;AAC7C,UAAI,eAAe,KAAK;AAEtB,cAAM,KAAK,gBAAgB,QAAQ;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,gBAAgB,UAAkD;AAC9E,UAAM,cAAc,QAAQ,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC,CAAC;AAChG,UAAM,aAAY,oBAAI,KAAK,GAAE,YAAY;AAGzC,UAAM,YAA+B;AAAA,MACnC,IAAI;AAAA,MACJ,YAAY,SAAS;AAAA,MACrB;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,UAAM,KAAK,cAAc,SAAS;AAGlC,UAAM,MAAM,MAAM,KAAK,MAAM;AAAA,MAC3B,aAAa,SAAS,IAAI;AAAA,MAC1B;AAAA,QACE,YAAY,SAAS;AAAA,QACrB;AAAA,QACA,MAAM,SAAS;AAAA,MACjB;AAAA,MACA;AAAA,QACE,eAAe;AAAA,QACf,UAAU;AAAA,UACR,cAAc,SAAS;AAAA,UACvB,aAAa,SAAS;AAAA,QACxB;AAAA,MACF;AAAA,IACF;AAGA,cAAU,QAAQ,IAAI;AACtB,UAAM,KAAK,cAAc,SAAS;AAGlC,UAAM,KAAK,2BAA2B,QAAQ;AAE9C,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,oBAAoB,YAAoB,aAAoC;AACxF,UAAM,WAAW,MAAM,KAAK,aAAa,UAAU;AACnD,QAAI,CAAC,SAAU;AAEf,UAAM,UAAU,KAAK,SAAS,IAAI,SAAS,IAAI;AAC/C,QAAI,CAAC,SAAS;AACZ,cAAQ,KAAK,uCAAuC,SAAS,IAAI,EAAE;AACnE;AAAA,IACF;AAEA,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,OAAiB,CAAC;AAExB,UAAM,UAA2B;AAAA,MAC/B;AAAA,MACA;AAAA,MACA,aAAa,SAAS,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACxD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MAClC,UAAU,CAAC,YAAY;AAAA,MAEvB;AAAA,MACA,KAAK,CAAC,SAAS,QAAQ,WAAW;AAChC,aAAK,KAAK,IAAI,MAAM,YAAY,CAAC,KAAK,OAAO,EAAE;AAAA,MACjD;AAAA,IACF;AAEA,QAAI;AAEF,YAAM;AAAA,QACJ;AAAA,UACE,eAAe;AAAA,UACf,WAAW,YAAY,SAAS,IAAI;AAAA,UACpC,SAAS,mBAAmB,WAAW;AAAA,QACzC;AAAA,QACA,YAAY;AACV,gBAAM,QAAQ,UAAU,OAAO;AAAA,QACjC;AAAA,MACF;AAGA,YAAM,KAAK,kBAAkB,aAAa,WAAW,KAAK,IAAI,IAAI,SAAS;AAC3E,YAAM,KAAK,qBAAqB,YAAY,SAAS;AAAA,IACvD,SAAS,OAAO;AACd,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAG1E,YAAM,KAAK,kBAAkB,aAAa,WAAW,KAAK,IAAI,IAAI,WAAW,YAAY;AACzF,YAAM,KAAK,qBAAqB,YAAY,WAAW,YAAY;AAAA,IACrE;AAAA,EACF;AAAA,EAEA,MAAc,2BAA2B,UAAgD;AACvF,aAAS;AACT,aAAS,WAAU,oBAAI,KAAK,GAAE,YAAY;AAG1C,QAAI,SAAS,WAAW,SAAS,YAAY,SAAS,SAAS;AAC7D,eAAS,QAAQ;AACjB,eAAS,UAAU;AAAA,IACrB,WAAW,SAAS,MAAM;AAExB,YAAM,OAAO,eAAe,SAAS,MAAM,oBAAI,KAAK,GAAG,SAAS,QAAQ;AACxE,eAAS,UAAU,MAAM,YAAY;AAAA,IACvC,OAAO;AAEL,eAAS,QAAQ;AACjB,eAAS,UAAU;AAAA,IACrB;AAEA,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAc,qBACZ,YACA,QACA,OACe;AACf,UAAM,WAAW,MAAM,KAAK,aAAa,UAAU;AACnD,QAAI,CAAC,SAAU;AAEf,aAAS,aAAa;AACtB,aAAS,YAAY;AACrB,QAAI,WAAW,WAAW;AACxB,eAAS;AAAA,IACX;AACA,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAE5C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAc,cAAc,WAA6C;AACvE,QAAI,KAAK,IAAI;AACX,YAAM,WAAW,MAAM,KAAK,GACzB,KAAK,KAAK,eAAe,EACzB,MAAM,MAAM,KAAK,UAAU,EAAE,EAC7B,QAAQ;AAEX,UAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,cAAM,KAAK,GACR,KAAK,KAAK,eAAe,EACzB,OAAO;AAAA,UACN,cAAc,UAAU;AAAA,UACxB,UAAU,UAAU;AAAA,UACpB,QAAQ,UAAU;AAAA,UAClB,OAAO,UAAU;AAAA,UACjB,QAAQ,UAAU;AAAA,QACpB,CAAC,EACA,MAAM,MAAM,KAAK,UAAU,EAAE,EAC7B,QAAQ;AAAA,MACb,OAAO;AACL,cAAM,KAAK,GAAG,KAAK,KAAK,eAAe,EAAE,OAAO;AAAA,UAC9C,IAAI,UAAU;AAAA,UACd,aAAa,UAAU;AAAA,UACvB,YAAY,UAAU;AAAA,UACtB,cAAc,UAAU;AAAA,UACxB,UAAU,UAAU;AAAA,UACpB,QAAQ,UAAU;AAAA,UAClB,OAAO,UAAU;AAAA,UACjB,QAAQ,UAAU;AAAA,QACpB,CAAC,EAAE,QAAQ;AAAA,MACb;AAAA,IACF,OAAO;AACL,YAAM,aAAa,KAAK,iBAAiB,IAAI,UAAU,UAAU,KAAK,CAAC;AACvE,YAAM,MAAM,WAAW,UAAU,CAAC,MAAM,EAAE,OAAO,UAAU,EAAE;AAC7D,UAAI,OAAO,GAAG;AACZ,mBAAW,GAAG,IAAI;AAAA,MACpB,OAAO;AACL,mBAAW,KAAK,SAAS;AAAA,MAC3B;AACA,WAAK,iBAAiB,IAAI,UAAU,YAAY,UAAU;AAAA,IAC5D;AAAA,EACF;AAAA,EAEA,MAAc,kBACZ,aACA,QACA,UACA,OACe;AACf,QAAI,KAAK,IAAI;AACX,YAAM,KAAK,GACR,KAAK,KAAK,eAAe,EACzB,OAAO;AAAA,QACN,eAAc,oBAAI,KAAK,GAAE,YAAY;AAAA,QACrC;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC,EACA,MAAM,MAAM,KAAK,WAAW,EAC5B,QAAQ;AAAA,IACb,OAAO;AACL,iBAAW,CAAC,aAAa,UAAU,KAAK,KAAK,kBAAkB;AAC7D,cAAM,YAAY,WAAW,KAAK,CAAC,MAAM,EAAE,OAAO,WAAW;AAC7D,YAAI,WAAW;AACb,oBAAU,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC/C,oBAAU,WAAW;AACrB,oBAAU,SAAS;AACnB,oBAAU,QAAQ;AAClB;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ACtuBA,SAAS,cAAAC,aAAY,uBAAuB;AAqErC,IAAM,cAAN,MAAsC;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,iBAAoD,oBAAI,IAAI;AAAA;AAAA,EAG5D,kBAAgD,oBAAI,IAAI;AAAA,EACxD,mBAAiD,oBAAI,IAAI;AAAA,EAEjE,YAAY,SAA4B,CAAC,GAAG;AAC1C,SAAK,KAAK,OAAO;AACjB,SAAK,QAAQ,OAAO;AACpB,SAAK,iBAAiB,OAAO,kBAAkB;AAC/C,SAAK,kBAAkB,OAAO,mBAAmB;AACjD,SAAK,gBAAgB,OAAO,iBAAiB;AAC7C,SAAK,SAAS;AAAA,MACZ,YAAY,OAAO,cAAc;AAAA,MACjC,cAAc,OAAO,gBAAgB;AAAA,MACrC,iBAAiB,OAAO,mBAAmB;AAAA,MAC3C,mBAAmB,OAAO,qBAAqB;AAAA,MAC/C,WAAW,OAAO,aAAa;AAAA,MAC/B,eAAe,OAAO,iBAAiB;AAAA,MACvC,kBAAkB,OAAO,oBAAoB;AAAA,MAC7C,sBAAsB,OAAO,wBAAwB;AAAA,MACrD,WAAW,OAAO,aAAa;AAAA,MAC/B,aAAa,OAAO,eAAe;AAAA,IACrC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,OAAO,SAAyD;AACpE,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,UAAM,KAAK,QAAQ,MAAM,kBAAkB;AAE3C,UAAM,WAA4B;AAAA,MAChC;AAAA,MACA,MAAM,QAAQ;AAAA,MACd,aAAa,QAAQ;AAAA,MACrB,KAAK,QAAQ;AAAA,MACb,QAAQ,QAAQ,UAAU,sBAAsB;AAAA,MAChD,oBAAoB,QAAQ,sBAAsB;AAAA,MAClD,iBAAiB,QAAQ,mBAAmB;AAAA,MAC5C,QAAQ,QAAQ;AAAA,MAChB,OAAO,QAAQ,SAAS,WAAW;AAAA,MACnC,SAAS,QAAQ;AAAA,MACjB,UAAU,QAAQ;AAAA,MAClB,MAAM,QAAQ;AAAA,MACd,WAAW;AAAA,MACX,WAAW;AAAA,MACX,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,sBAAsB;AAAA,IACxB;AAEA,UAAM,KAAK,aAAa,QAAQ;AAChC,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,IAAI,IAA6C;AACrD,WAAO,KAAK,aAAa,EAAE;AAAA,EAC7B;AAAA,EAEA,MAAM,OAAO,IAAY,SAAyD;AAChF,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,UAAU;AACb,YAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAAA,IACrD;AAEA,UAAM,UAA2B;AAAA,MAC/B,GAAG;AAAA,MACH,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC/B,aAAa,QAAQ,eAAe,SAAS;AAAA,MAC7C,KAAK,QAAQ,OAAO,SAAS;AAAA,MAC7B,QAAQ,QAAQ,eAAe,sBAAsB,IAAI,SAAS;AAAA,MAClE,QAAQ,QAAQ,UAAU,SAAS;AAAA,MACnC,SAAS,QAAQ,WAAW,SAAS;AAAA,MACrC,UAAU,QAAQ,YAAY,SAAS;AAAA,MACvC,MAAM,QAAQ,QAAQ,SAAS;AAAA,MAC/B,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAEA,UAAM,KAAK,aAAa,OAAO;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,QAAI,KAAK,IAAI;AACX,YAAM,KAAK,GAAG,KAAK,KAAK,aAAa,EAAE,MAAM,eAAe,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ;AACtF,YAAM,KAAK,GAAG,KAAK,KAAK,eAAe,EAAE,MAAM,eAAe,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ;AACxF,YAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,MAAM,MAAM,KAAK,EAAE,EAAE,OAAO,EAAE,QAAQ;AAAA,IAChF,OAAO;AACL,WAAK,gBAAgB,OAAO,EAAE;AAC9B,iBAAW,CAAC,YAAY,QAAQ,KAAK,KAAK,kBAAkB;AAC1D,YAAI,SAAS,eAAe,IAAI;AAC9B,eAAK,iBAAiB,OAAO,UAAU;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,KAAK,OAAkD;AAC3D,QAAI,YAAY,MAAM,KAAK,iBAAiB;AAG5C,QAAI,OAAO,OAAO;AAChB,YAAM,SAAS,MAAM,QAAQ,MAAM,KAAK,IAAI,MAAM,QAAQ,CAAC,MAAM,KAAK;AACtE,kBAAY,UAAU,OAAO,CAAC,MAAM,OAAO,SAAS,EAAE,KAAK,CAAC;AAAA,IAC9D;AAEA,QAAI,OAAO,UAAU,MAAM,OAAO,SAAS,GAAG;AAC5C,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,MAAM,OAAQ;AAAA,UAAK,CAAC,cAClB,EAAE,OAAO,KAAK,CAAC,YAAY,eAAe,WAAW,OAAO,CAAC;AAAA,QAC/D;AAAA,MACF;AAAA,IACF;AAEA,QAAI,OAAO,QAAQ,MAAM,KAAK,SAAS,GAAG;AACxC,kBAAY,UAAU;AAAA,QAAO,CAAC,MAC5B,MAAM,KAAM,KAAK,CAAC,QAAQ,EAAE,MAAM,SAAS,GAAG,CAAC;AAAA,MACjD;AAAA,IACF;AAEA,QAAI,OAAO,MAAM;AACf,YAAM,UAAU,MAAM,KAAK,QAAQ,OAAO,IAAI;AAC9C,YAAM,QAAQ,IAAI,OAAO,IAAI,OAAO,KAAK,GAAG;AAC5C,kBAAY,UAAU,OAAO,CAAC,MAAM,MAAM,KAAK,EAAE,IAAI,CAAC;AAAA,IACxD;AAGA,UAAM,SAAS,OAAO,UAAU;AAChC,UAAM,QAAQ,OAAO,SAAS;AAC9B,WAAO,UAAU,MAAM,QAAQ,SAAS,KAAK;AAAA,EAC/C;AAAA,EAEA,MAAM,MAAM,IAA2B;AACrC,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAElE,aAAS,QAAQ;AACjB,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,OAAO,IAA2B;AACtC,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAElE,aAAS,QAAQ;AACjB,aAAS,eAAe;AACxB,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAM,KAAK,IAAsC;AAC/C,UAAM,WAAW,MAAM,KAAK,aAAa,EAAE;AAC3C,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,EAAE,EAAE;AAElE,UAAM,QAAsB;AAAA,MAC1B,IAAI,gBAAgB;AAAA,MACpB,MAAM;AAAA,MACN,SAAS,EAAE,MAAM,MAAM,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAAA,MAC3D,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAEA,WAAO,KAAK,gBAAgB,UAAU,OAAO,CAAC;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAY,OAA2C;AAC3D,UAAM,cAAwB,CAAC;AAC/B,UAAM,UAAU,MAAM,MAAM,gBAAgB;AAC5C,UAAM,YAAY,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAE5D,UAAM,YAA6B;AAAA,MACjC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ;AAAA,MACA,eAAe,MAAM,iBAAiB,mBAAmB,IAAI,GAAG;AAAA,IAClE;AAGA,UAAM,YAAY,MAAM,KAAK,iBAAiB;AAC9C,UAAM,kBAAkB,UAAU;AAAA,MAChC,CAAC,MACC,EAAE,UAAU,YACZ,EAAE,OAAO,KAAK,CAAC,YAAY,eAAe,MAAM,MAAM,OAAO,CAAC;AAAA,IAClE;AAEA,eAAW,YAAY,iBAAiB;AACtC,YAAM,aAAa,MAAM,KAAK,WAAW,SAAS,IAAI,SAAS;AAC/D,kBAAY,KAAK,UAAU;AAAA,IAC7B;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,WAAc,YAAoB,OAAyC;AAC/E,UAAM,WAAW,MAAM,KAAK,aAAa,UAAU;AACnD,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,UAAU,EAAE;AAE1E,UAAM,UAAU,MAAM,MAAM,gBAAgB;AAC5C,UAAM,YAAY,MAAM,cAAa,oBAAI,KAAK,GAAE,YAAY;AAC5D,UAAM,aAAa,mBAAmB;AAEtC,UAAM,YAA6B;AAAA,MACjC,GAAG;AAAA,MACH,IAAI;AAAA,MACJ;AAAA,MACA,eAAe,MAAM,iBAAiB,mBAAmB,IAAI,GAAG;AAAA,IAClE;AAGA,UAAM,WAA4B;AAAA,MAChC,IAAI;AAAA,MACJ;AAAA,MACA;AAAA,MACA,WAAW,MAAM;AAAA,MACjB,SAAS,KAAK,UAAU,SAAS;AAAA,MACjC,QAAQ;AAAA,MACR,UAAU;AAAA,MACV,gBAAgB,CAAC;AAAA,MACjB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC;AAEA,UAAM,KAAK,aAAa,QAAQ;AAGhC,QAAI,KAAK,OAAO;AACd,YAAM,KAAK,MAAM,IAAI,mBAAmB;AAAA,QACtC;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MACT,GAAG;AAAA,QACD,eAAe,UAAU;AAAA,QACzB,UAAU,EAAE,WAAW,MAAM,KAAK;AAAA,MACpC,CAAC;AAAA,IACH,OAAO;AAEL,YAAM,KAAK,mBAAmB,UAAU,WAAW,QAAQ;AAAA,IAC7D;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,MAAM,YAA8C;AACxD,UAAM,WAAW,MAAM,KAAK,YAAY,UAAU;AAClD,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,uBAAuB,UAAU,EAAE;AAElE,UAAM,WAAW,MAAM,KAAK,aAAa,SAAS,UAAU;AAC5D,QAAI,CAAC,SAAU,OAAM,IAAI,MAAM,+BAA+B,SAAS,UAAU,EAAE;AAEnF,UAAM,QAAQ,KAAK,MAAM,SAAS,OAAO;AACzC,UAAM,UAAU,MAAM,KAAK,gBAAgB,UAAU,OAAO,SAAS,WAAW,CAAC;AAEjF,aAAS;AACT,aAAS,eAAe,KAAK,OAAO;AAEpC,QAAI,QAAQ,WAAW,WAAW;AAChC,eAAS,SAAS;AAClB,eAAS,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC9C,WAAK,oBAAoB,UAAU,IAAI;AAAA,IACzC;AAEA,UAAM,KAAK,aAAa,QAAQ;AAChC,UAAM,KAAK,YAAY,SAAS,UAAU;AAE1C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,IAA6C;AAC7D,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GACvB,KAAK,KAAK,eAAe,EACzB,MAAM,MAAM,KAAK,EAAE,EACnB,QAAQ;AAEX,UAAI,OAAO,KAAK,WAAW,EAAG,QAAO;AACrC,YAAM,WAAW,KAAK,cAAc,OAAO,KAAK,CAAC,CAAgB;AAGjE,YAAM,WAAW,MAAM,KAAK,YAAY,EAAE;AAC1C,eAAS,iBAAiB;AAE1B,aAAO;AAAA,IACT,OAAO;AACL,aAAO,KAAK,iBAAiB,IAAI,EAAE,KAAK;AAAA,IAC1C;AAAA,EACF;AAAA,EAEA,MAAM,eAAe,OAAmD;AACtE,QAAI,KAAK,IAAI;AACX,UAAI,UAAU,KAAK,GAAG,KAAK,KAAK,eAAe;AAE/C,UAAI,OAAO,YAAY;AACrB,kBAAU,QAAQ,MAAM,eAAe,KAAK,MAAM,UAAU;AAAA,MAC9D;AAEA,UAAI,OAAO,WAAW;AACpB,kBAAU,QAAQ,MAAM,cAAc,KAAK,MAAM,SAAS;AAAA,MAC5D;AAEA,UAAI,OAAO,QAAQ;AACjB,cAAM,WAAW,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM;AAC3E,YAAI,SAAS,WAAW,GAAG;AACzB,oBAAU,QAAQ,MAAM,UAAU,KAAK,SAAS,CAAC,CAAE;AAAA,QACrD;AAAA,MACF;AAEA,gBAAU,QAAQ,QAAQ,cAAc,MAAM;AAE9C,UAAI,OAAO,OAAO;AAChB,kBAAU,QAAQ,MAAM,MAAM,KAAK;AAAA,MACrC;AAEA,YAAM,SAAS,MAAM,QAAQ,QAAQ;AACrC,aAAQ,OAAO,KAAuB,IAAI,CAAC,QAAQ,KAAK,cAAc,GAAG,CAAC;AAAA,IAC5E,OAAO;AACL,UAAI,aAAa,MAAM,KAAK,KAAK,iBAAiB,OAAO,CAAC;AAE1D,UAAI,OAAO,YAAY;AACrB,qBAAa,WAAW,OAAO,CAAC,MAAM,EAAE,eAAe,MAAM,UAAU;AAAA,MACzE;AAEA,UAAI,OAAO,WAAW;AACpB,qBAAa,WAAW,OAAO,CAAC,MAAM,EAAE,cAAc,MAAM,SAAS;AAAA,MACvE;AAEA,UAAI,OAAO,QAAQ;AACjB,cAAM,WAAW,MAAM,QAAQ,MAAM,MAAM,IAAI,MAAM,SAAS,CAAC,MAAM,MAAM;AAC3E,qBAAa,WAAW,OAAO,CAAC,MAAM,SAAS,SAAS,EAAE,MAAM,CAAC;AAAA,MACnE;AAEA,iBAAW,KAAK,CAAC,GAAG,MAAM,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,IAAI,IAAI,KAAK,EAAE,SAAS,EAAE,QAAQ,CAAC;AAE3F,YAAM,SAAS,OAAO,UAAU;AAChC,YAAM,QAAQ,OAAO,SAAS;AAC9B,aAAO,WAAW,MAAM,QAAQ,SAAS,KAAK;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,MAAM,YAAY,YAAgD;AAChE,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GACvB,KAAK,KAAK,aAAa,EACvB,MAAM,eAAe,KAAK,UAAU,EACpC,QAAQ,kBAAkB,KAAK,EAC/B,QAAQ;AAEX,aAAQ,OAAO,KAAsB,IAAI,CAAC,QAAQ,KAAK,aAAa,GAAG,CAAC;AAAA,IAC1E,OAAO;AACL,YAAM,WAAW,KAAK,iBAAiB,IAAI,UAAU;AACrD,aAAO,UAAU,kBAAkB,CAAC;AAAA,IACtC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAgB,QAAoC;AAClD,SAAK,eAAe,IAAI,OAAO,MAAM,MAAM;AAAA,EAC7C;AAAA,EAEA,OAAO,MAAc,SAAoD;AACvE,UAAM,SAAS,KAAK,eAAe,IAAI,IAAI;AAC3C,QAAI,CAAC,QAAQ;AACX,aAAO,EAAE,OAAO,OAAO,OAAO,oBAAoB,IAAI,GAAG;AAAA,IAC3D;AAGA,UAAM,kBAAkB,OAAO,mBAAmB;AAClD,UAAM,YAAY,gBAAgB,YAAY;AAC9C,UAAM,YAAY,QAAQ,QAAQ,SAAS,KAAK,QAAQ;AAExD,QAAI,CAAC,WAAW;AACd,aAAO,EAAE,OAAO,OAAO,OAAO,2BAA2B;AAAA,IAC3D;AAGA,QAAI,OAAO,iBAAiB;AAC1B,YAAM,qBAAqB,OAAO,gBAAgB,YAAY;AAC9D,YAAM,YAAY,QAAQ,QAAQ,kBAAkB;AACpD,UAAI,WAAW;AACb,cAAM,cAAc,SAAS,WAAW,EAAE,IAAI;AAC9C,cAAM,MAAM,KAAK,IAAI;AACrB,cAAM,aAAa,OAAO,sBAAsB,OAAO;AAEvD,YAAI,KAAK,IAAI,MAAM,WAAW,IAAI,WAAW;AAC3C,iBAAO,EAAE,OAAO,OAAO,OAAO,qCAAqC;AAAA,QACrE;AAAA,MACF;AAAA,IACF;AAGA,UAAM,YAAY,OAAO,sBAAsB;AAC/C,UAAM,OAAO,OAAO,QAAQ,YAAY,WACpC,QAAQ,UACR,QAAQ,QAAQ,SAAS,OAAO;AAEpC,UAAM,oBAAoB,KAAK,iBAAiB,MAAM,OAAO,QAAQ,SAAS;AAG9E,UAAM,cAAc,UAAU,QAAQ,4BAA4B,EAAE;AAEpE,QAAI;AACF,YAAM,iBAAiB,OAAO,KAAK,aAAa,KAAK;AACrD,YAAM,iBAAiB,OAAO,KAAK,mBAAmB,KAAK;AAE3D,UAAI,eAAe,WAAW,eAAe,QAAQ;AACnD,eAAO,EAAE,OAAO,OAAO,OAAO,oBAAoB;AAAA,MACpD;AAEA,UAAI,CAAC,gBAAgB,gBAAgB,cAAc,GAAG;AACpD,eAAO,EAAE,OAAO,OAAO,OAAO,oBAAoB;AAAA,MACpD;AAAA,IACF,QAAQ;AACN,aAAO,EAAE,OAAO,OAAO,OAAO,2BAA2B;AAAA,IAC3D;AAGA,QAAI;AACF,YAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,aAAO,EAAE,OAAO,MAAM,QAAQ;AAAA,IAChC,QAAQ;AACN,aAAO,EAAE,OAAO,OAAO,OAAO,uBAAuB;AAAA,IACvD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAkC;AACtC,UAAM,YAAY,MAAM,KAAK,iBAAiB;AAC9C,UAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI;AAE3D,QAAI,oBAAoB;AACxB,QAAI,iBAAiB;AACrB,QAAI,kBAAkB;AACtB,QAAI,gBAAgB;AACpB,QAAI,gBAAgB;AAEpB,QAAI,KAAK,IAAI;AAEX,YAAM,mBAAmB,MAAM,KAAK,eAAe;AAAA,QACjD,MAAM;AAAA,QACN,OAAO;AAAA,MACT,CAAC;AAED,0BAAoB,iBAAiB;AACrC,uBAAiB,iBAAiB,OAAO,CAAC,MAAM,EAAE,WAAW,SAAS,EAAE;AACxE,wBAAkB,iBAAiB,OAAO,CAAC,MAAM,EAAE,WAAW,QAAQ,EAAE;AAAA,IAC1E,OAAO;AACL,iBAAW,YAAY,KAAK,iBAAiB,OAAO,GAAG;AACrD,YAAI,IAAI,KAAK,SAAS,SAAS,IAAI,WAAW;AAC5C;AACA,cAAI,SAAS,WAAW,UAAW;AACnC,cAAI,SAAS,WAAW,SAAU;AAElC,qBAAW,WAAW,SAAS,gBAAgB;AAC7C,gBAAI,QAAQ,UAAU;AACpB,+BAAiB,QAAQ;AACzB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,gBAAgB,UAAU;AAAA,MAC1B,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAE;AAAA,MAC/D,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAE;AAAA,MAC/D,iBAAiB,UAAU,OAAO,CAAC,MAAM,EAAE,UAAU,QAAQ,EAAE;AAAA,MAC/D;AAAA,MACA;AAAA,MACA;AAAA,MACA,iBAAiB,gBAAgB,IAAI,gBAAgB,gBAAgB;AAAA,IACvE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,cAAgC;AACpC,QAAI,KAAK,IAAI;AACX,UAAI;AACF,cAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,MAAM,CAAC,EAAE,QAAQ;AACzD,eAAO;AAAA,MACT,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEA,MAAM,QAAuB;AAC3B,SAAK,gBAAgB,MAAM;AAC3B,SAAK,iBAAiB,MAAM;AAC5B,SAAK,eAAe,MAAM;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,kBACL,iBAAiB,qBACjB,kBAAkB,sBAClB,gBAAgB,oBACR;AACR,WAAO;AAAA,6BACkB,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAsBV,cAAc,aAAa,cAAc;AAAA,iCACzC,cAAc,YAAY,cAAc;AAAA;AAAA,6BAE5C,eAAe;AAAA;AAAA,iDAEK,cAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAU9B,eAAe,gBAAgB,eAAe;AAAA,iCAC9C,eAAe,cAAc,eAAe;AAAA,iCAC5C,eAAe,eAAe,eAAe;AAAA;AAAA,6BAEjD,aAAa;AAAA;AAAA,iDAEO,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,iCAe/B,aAAa,gBAAgB,aAAa;AAAA,MACrE,KAAK;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,aAAa,UAA0C;AACnE,QAAI,KAAK,IAAI;AACX,YAAM,WAAW,MAAM,KAAK,GACzB,KAAK,KAAK,cAAc,EACxB,MAAM,MAAM,KAAK,SAAS,EAAE,EAC5B,QAAQ;AAEX,YAAM,MAAM,KAAK,cAAc,QAAQ;AAEvC,UAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,cAAM,KAAK,GACR,KAAK,KAAK,cAAc,EACxB,OAAO,GAAG,EACV,MAAM,MAAM,KAAK,SAAS,EAAE,EAC5B,QAAQ;AAAA,MACb,OAAO;AACL,cAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,OAAO,GAAG,EAAE,QAAQ;AAAA,MAC9D;AAAA,IACF,OAAO;AACL,WAAK,gBAAgB,IAAI,SAAS,IAAI,QAAQ;AAAA,IAChD;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,IAA6C;AACtE,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GACvB,KAAK,KAAK,cAAc,EACxB,MAAM,MAAM,KAAK,EAAE,EACnB,QAAQ;AAEX,UAAI,OAAO,KAAK,WAAW,EAAG,QAAO;AACrC,aAAO,KAAK,cAAc,OAAO,KAAK,CAAC,CAAgB;AAAA,IACzD,OAAO;AACL,aAAO,KAAK,gBAAgB,IAAI,EAAE,KAAK;AAAA,IACzC;AAAA,EACF;AAAA,EAEA,MAAc,mBAA+C;AAC3D,QAAI,KAAK,IAAI;AACX,YAAM,SAAS,MAAM,KAAK,GAAG,KAAK,KAAK,cAAc,EAAE,QAAQ;AAC/D,aAAQ,OAAO,KAAuB,IAAI,CAAC,QAAQ,KAAK,cAAc,GAAG,CAAC;AAAA,IAC5E,OAAO;AACL,aAAO,MAAM,KAAK,KAAK,gBAAgB,OAAO,CAAC;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,MAAc,aAAa,UAA0C;AACnE,QAAI,KAAK,IAAI;AACX,YAAM,WAAW,MAAM,KAAK,GACzB,KAAK,KAAK,eAAe,EACzB,MAAM,MAAM,KAAK,SAAS,EAAE,EAC5B,QAAQ;AAEX,YAAM,MAAM,KAAK,cAAc,QAAQ;AAEvC,UAAI,SAAS,KAAK,SAAS,GAAG;AAC5B,cAAM,KAAK,GACR,KAAK,KAAK,eAAe,EACzB,OAAO,GAAG,EACV,MAAM,MAAM,KAAK,SAAS,EAAE,EAC5B,QAAQ;AAAA,MACb,OAAO;AACL,cAAM,KAAK,GAAG,KAAK,KAAK,eAAe,EAAE,OAAO,GAAG,EAAE,QAAQ;AAAA,MAC/D;AAAA,IACF,OAAO;AACL,WAAK,iBAAiB,IAAI,SAAS,IAAI,QAAQ;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,MAAc,YAAY,SAA0B,YAAmC;AACrF,QAAI,KAAK,IAAI;AACX,YAAM,KAAK,GAAG,KAAK,KAAK,aAAa,EAAE,OAAO;AAAA,QAC5C,IAAI,QAAQ;AAAA,QACZ,aAAa;AAAA,QACb,aAAa,QAAQ;AAAA,QACrB,UAAU,QAAQ;AAAA,QAClB,YAAY,QAAQ;AAAA,QACpB,gBAAgB,QAAQ;AAAA,QACxB,QAAQ,QAAQ;AAAA,QAChB,aAAa,QAAQ;AAAA,QACrB,eAAe,QAAQ;AAAA,QACvB,kBAAkB,QAAQ,kBAAkB,KAAK,UAAU,QAAQ,eAAe,IAAI;AAAA,QACtF,UAAU,QAAQ;AAAA,QAClB,OAAO,QAAQ;AAAA,QACf,WAAW,QAAQ;AAAA,QACnB,eAAe,QAAQ;AAAA,MACzB,CAAC,EAAE,QAAQ;AAAA,IACb;AAAA,EACF;AAAA,EAEA,MAAc,mBACZ,UACA,OACA,UACe;AACf,QAAI,UAAU;AAEd,WAAO,UAAU,KAAK,OAAO,YAAY;AACvC;AACA,YAAM,SAAS,MAAM,KAAK,gBAAgB,UAAU,OAAO,OAAO;AAElE,eAAS,WAAW;AACpB,eAAS,eAAe,KAAK,MAAM;AACnC,YAAM,KAAK,YAAY,QAAQ,SAAS,EAAE;AAE1C,UAAI,OAAO,WAAW,WAAW;AAC/B,iBAAS,SAAS;AAClB,iBAAS,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC9C,cAAM,KAAK,oBAAoB,UAAU,IAAI;AAC7C,cAAM,KAAK,aAAa,QAAQ;AAChC;AAAA,MACF;AAGA,UAAI,UAAU,KAAK,OAAO,YAAY;AACpC,cAAM,QAAQ;AAAA,UACZ;AAAA,UACA,KAAK,OAAO;AAAA,UACZ,KAAK,OAAO;AAAA,UACZ,KAAK,OAAO;AAAA,QACd;AACA,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,MAC3D;AAAA,IACF;AAGA,aAAS,SAAS;AAClB,aAAS,eAAc,oBAAI,KAAK,GAAE,YAAY;AAC9C,UAAM,KAAK,oBAAoB,UAAU,KAAK;AAC9C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEA,MAAc,gBACZ,UACA,OACA,eAC0B;AAC1B,UAAM,YAAY,OAAO,KAAK,IAAI,EAAE,SAAS,EAAE,CAAC,GAAG,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,UAAU,GAAG,CAAC,CAAC;AAC7F,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,aAAa,KAAK,UAAU,KAAK;AACvC,UAAM,YAAY,KAAK,iBAAiB,YAAY,SAAS,QAAQ,SAAS,kBAAkB;AAEhG,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,cAAc,KAAK,OAAO;AAAA,MAC1B,CAAC,SAAS,eAAe,GAAG,GAAG,SAAS,kBAAkB,IAAI,SAAS;AAAA,MACvE,gBAAgB,SAAS;AAAA,MACzB,mBAAmB,MAAM;AAAA,MACzB,yBAAyB,MAAM;AAAA,MAC/B,uBAAuB,MAAM;AAAA,MAC7B,GAAI,SAAS,WAAW,CAAC;AAAA,IAC3B;AAEA,QAAI,MAAM,eAAe;AACvB,cAAQ,kBAAkB,IAAI,MAAM;AAAA,IACtC;AAEA,QAAI;AACF,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO,SAAS;AAE5E,YAAM,WAAW,MAAM,MAAM,SAAS,KAAK;AAAA,QACzC,QAAQ;AAAA,QACR;AAAA,QACA,MAAM;AAAA,QACN,QAAQ,WAAW;AAAA,MACrB,CAAC;AAED,mBAAa,SAAS;AAEtB,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,YAAM,eAAe,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACzD,YAAM,kBAA0C,CAAC;AACjD,eAAS,QAAQ,QAAQ,CAAC,OAAO,QAAQ;AACvC,wBAAgB,GAAG,IAAI;AAAA,MACzB,CAAC;AAED,UAAI,SAAS,IAAI;AACf,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,YAAY,SAAS;AAAA,UACrB,SAAS,MAAM;AAAA,UACf,WAAW,MAAM;AAAA,UACjB;AAAA,UACA,QAAQ;AAAA,UACR,YAAY,SAAS;AAAA,UACrB,cAAc,aAAa,UAAU,GAAG,GAAK;AAAA;AAAA,UAC7C;AAAA,UACA;AAAA,UACA,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF,OAAO;AACL,eAAO;AAAA,UACL,IAAI;AAAA,UACJ,YAAY,SAAS;AAAA,UACrB,SAAS,MAAM;AAAA,UACf,WAAW,MAAM;AAAA,UACjB;AAAA,UACA,QAAQ;AAAA,UACR,YAAY,SAAS;AAAA,UACrB,cAAc,aAAa,UAAU,GAAG,GAAK;AAAA,UAC7C;AAAA,UACA;AAAA,UACA,OAAO,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,UACtD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,QACpC;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,YAAM,WAAW,KAAK,IAAI,IAAI;AAC9B,YAAM,eAAe,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAE1E,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,YAAY,SAAS;AAAA,QACrB,SAAS,MAAM;AAAA,QACf,WAAW,MAAM;AAAA,QACjB;AAAA,QACA,QAAQ;AAAA,QACR;AAAA,QACA,OAAO;AAAA,QACP,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB,UAA2B,SAAiC;AAC5F,aAAS;AACT,aAAS,kBAAiB,oBAAI,KAAK,GAAE,YAAY;AAEjD,QAAI,SAAS;AACX,eAAS;AACT,eAAS,iBAAgB,oBAAI,KAAK,GAAE,YAAY;AAChD,eAAS,eAAe;AAAA,IAC1B,OAAO;AACL,eAAS;AAET,UAAI,SAAS,gBAAgB,KAAK,OAAO,kBAAkB;AACzD,iBAAS,QAAQ;AAAA,MACnB;AAAA,IACF;AAEA,aAAS,aAAY,oBAAI,KAAK,GAAE,YAAY;AAC5C,UAAM,KAAK,aAAa,QAAQ;AAAA,EAClC;AAAA,EAEQ,iBAAiB,SAAiB,QAAgB,WAAuC;AAC/F,WAAOC,YAAW,WAAW,MAAM,EAAE,OAAO,OAAO,EAAE,OAAO,KAAK;AAAA,EACnE;AAAA,EAEQ,cAAc,UAAoD;AACxE,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,MAAM,SAAS;AAAA,MACf,aAAa,SAAS;AAAA,MACtB,KAAK,SAAS;AAAA,MACd,QAAQ,SAAS;AAAA,MACjB,qBAAqB,SAAS;AAAA,MAC9B,kBAAkB,SAAS;AAAA,MAC3B,QAAQ,KAAK,UAAU,SAAS,MAAM;AAAA,MACtC,OAAO,SAAS;AAAA,MAChB,SAAS,SAAS,UAAU,KAAK,UAAU,SAAS,OAAO,IAAI;AAAA,MAC/D,UAAU,SAAS,WAAW,KAAK,UAAU,SAAS,QAAQ,IAAI;AAAA,MAClE,MAAM,SAAS,OAAO,IAAI,SAAS,KAAK,KAAK,GAAG,CAAC,MAAM;AAAA,MACvD,YAAY,SAAS;AAAA,MACrB,YAAY,SAAS;AAAA,MACrB,kBAAkB,SAAS;AAAA,MAC3B,iBAAiB,SAAS;AAAA,MAC1B,eAAe,SAAS;AAAA,MACxB,kBAAkB,SAAS;AAAA,MAC3B,uBAAuB,SAAS;AAAA,IAClC;AAAA,EACF;AAAA,EAEQ,cAAc,KAAmC;AACvD,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,MAAM,IAAI;AAAA,MACV,aAAa,IAAI;AAAA,MACjB,KAAK,IAAI;AAAA,MACT,QAAQ,IAAI;AAAA,MACZ,oBAAoB,IAAI;AAAA,MACxB,iBAAiB,IAAI;AAAA,MACrB,QAAQ,OAAO,IAAI,WAAW,WAAW,KAAK,MAAM,IAAI,MAAM,IAAI,IAAI;AAAA,MACtE,OAAO,IAAI;AAAA,MACX,SAAS,IAAI,UAAW,OAAO,IAAI,YAAY,WAAW,KAAK,MAAM,IAAI,OAAO,IAAI,IAAI,UAAW;AAAA,MACnG,UAAU,IAAI,WAAY,OAAO,IAAI,aAAa,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI,IAAI,WAAY;AAAA,MACxG,MAAM,IAAI,OAAO,IAAI,KAAK,QAAQ,SAAS,EAAE,EAAE,MAAM,GAAG,EAAE,OAAO,OAAO,IAAI;AAAA,MAC5E,WAAW,IAAI;AAAA,MACf,WAAW,IAAI;AAAA,MACf,gBAAgB,IAAI;AAAA,MACpB,eAAe,IAAI;AAAA,MACnB,cAAc,IAAI;AAAA,MAClB,iBAAiB,IAAI;AAAA,MACrB,sBAAsB,IAAI;AAAA,IAC5B;AAAA,EACF;AAAA,EAEQ,cAAc,UAAoD;AACxE,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,aAAa,SAAS;AAAA,MACtB,UAAU,SAAS;AAAA,MACnB,YAAY,SAAS;AAAA,MACrB,SAAS,SAAS;AAAA,MAClB,QAAQ,SAAS;AAAA,MACjB,UAAU,SAAS;AAAA,MACnB,YAAY,SAAS;AAAA,MACrB,cAAc,SAAS;AAAA,IACzB;AAAA,EACF;AAAA,EAEQ,cAAc,KAAmC;AACvD,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,YAAY,IAAI;AAAA,MAChB,SAAS,IAAI;AAAA,MACb,WAAW,IAAI;AAAA,MACf,SAAS,OAAO,IAAI,YAAY,WAAW,IAAI,UAAU,KAAK,UAAU,IAAI,OAAO;AAAA,MACnF,QAAQ,IAAI;AAAA,MACZ,UAAU,IAAI;AAAA,MACd,gBAAgB,CAAC;AAAA,MACjB,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,aAAa,KAAkC;AACrD,WAAO;AAAA,MACL,IAAI,IAAI;AAAA,MACR,YAAY,IAAI;AAAA,MAChB,SAAS,IAAI;AAAA,MACb,WAAW,IAAI;AAAA,MACf,eAAe,IAAI;AAAA,MACnB,QAAQ,IAAI;AAAA,MACZ,YAAY,IAAI;AAAA,MAChB,cAAc,IAAI;AAAA,MAClB,iBAAiB,IAAI,mBAAoB,OAAO,IAAI,qBAAqB,WAAW,KAAK,MAAM,IAAI,gBAAgB,IAAI,IAAI,mBAAoB;AAAA,MAC/I,UAAU,IAAI;AAAA,MACd,OAAO,IAAI;AAAA,MACX,WAAW,IAAI;AAAA,MACf,aAAa,IAAI;AAAA,IACnB;AAAA,EACF;AACF;;;ACpgCA,IAAM,iBAA+F;AAAA,EACnG,WAAW;AAAA,EACX,QAAQ;AAAA,EACR,aAAa;AAAA,EACb,mBAAmB;AAAA,EACnB,eAAe;AACjB;AAKA,SAASC,kBAAiB,SAAyB;AAEjD,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,UAAM,OAAO,QAAQ,WAAW,CAAC;AACjC,YAAQ,QAAQ,KAAK,OAAO;AAC5B,WAAO,OAAO;AAAA,EAChB;AACA,SAAO,KAAK,IAAI,IAAI,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;AACpD;AAKA,SAAS,eAAe,YAAsC;AAC5D,SAAO,CAAC,GAAG,UAAU,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,cAAc,EAAE,OAAO,CAAC;AAC1E;AAEO,IAAM,WAAN,MAAoC;AAAA,EACjC;AAAA,EACA;AAAA,EACA,aAA0B,CAAC;AAAA,EAC3B,cAAc;AAAA,EACd,SAAS;AAAA,EAEjB,YAAY,IAAwB,SAAyB,CAAC,GAAG;AAC/D,SAAK,KAAK;AACV,SAAK,SAAS,EAAE,GAAG,gBAAgB,GAAG,OAAO;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,YAAoB;AAC9B,WAAO,IAAI,KAAK,OAAO,MAAM,MAAM,KAAK,OAAO,SAAS;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,IAAY,gBAAwB;AAClC,WAAO,IAAI,KAAK,OAAO,MAAM,MAAM,KAAK,OAAO,SAAS;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aAA4B;AACxC,QAAI,KAAK,YAAa;AAGtB,UAAM,KAAK,GAAG,IAAI,gCAAgC,KAAK,OAAO,MAAM,GAAG;AAGvE,UAAM,KAAK,GAAG,IAAI;AAAA,mCACa,KAAK,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAO5C;AAGD,UAAM,KAAK,GAAG,IAAI;AAAA,mCACa,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,KAMhD;AAGD,UAAM,KAAK,GAAG,IAAI;AAAA,oBACF,KAAK,aAAa;AAAA;AAAA;AAAA,KAGjC;AAED,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAyB;AAC7B,UAAM,KAAK,WAAW;AAEtB,UAAM,SAAS,GAAG,QAAQ,GAAG,IAAI,KAAK,IAAI,CAAC;AAC3C,UAAM,cAAc,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,OAAO,cAAc,GAAI;AAGxE,UAAM,SAAS,MAAM,KAAK,GAAG;AAAA,MAC3B;AAAA,eACS,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA;AAAA,MAK3B,CAAC,QAAQ,WAAW;AAAA,IACtB;AAEA,QAAI,OAAO,KAAK,SAAS,GAAG;AAC1B,WAAK,SAAS;AACd,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAwB;AAC5B,QAAI,CAAC,KAAK,OAAQ;AAElB,UAAM,KAAK,GAAG;AAAA,MACZ;AAAA,eACS,KAAK,aAAa;AAAA;AAAA;AAAA;AAAA,IAI7B;AAEA,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,YAA+B;AAC3C,eAAW,aAAa,YAAY;AAElC,UAAI,CAAC,UAAU,UAAU;AACvB,cAAM,UACJ,OAAO,UAAU,OAAO,WAAW,UAAU,KAAK,UAAU,GAAG,SAAS;AAC1E,kBAAU,WAAWA,kBAAiB,OAAO;AAAA,MAC/C;AAGA,UAAI,CAAC,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,YAAY,UAAU,OAAO,GAAG;AACjE,aAAK,WAAW,KAAK,SAAS;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,eAAe,KAA4B;AAE/C,UAAM,EAAE,SAAS,SAAS,IAAI,MAAM,OAAO,aAAa;AACxD,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,MAAM;AAEpC,UAAM,QAAQ,MAAM,QAAQ,GAAG;AAC/B,UAAM,iBAAiB,MAAM;AAAA,MAC3B,CAAC,MAAM,EAAE,MAAM,uBAAuB;AAAA,IACxC;AAEA,eAAW,QAAQ,gBAAgB;AACjC,YAAM,WAAW,KAAK,KAAK,IAAI;AAC/B,YAAM,CAAC,SAAS,GAAG,SAAS,IAAI,KAAK,QAAQ,kBAAkB,EAAE,EAAE,MAAM,GAAG;AAC5E,YAAM,OAAO,UAAU,KAAK,GAAG;AAE/B,UAAI,KAAK,SAAS,MAAM,GAAG;AAEzB,cAAM,UAAU,MAAM,SAAS,UAAU,OAAO;AAChD,cAAM,CAAC,IAAI,IAAI,IAAI,KAAK,kBAAkB,OAAO;AAEjD,aAAK,cAAc;AAAA,UACjB;AAAA,YACE;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA,UACF;AAAA,QACF,CAAC;AAAA,MACH,OAAO;AAEL,cAAM,SAAS,MAAM,OAAO;AAC5B,aAAK,cAAc;AAAA,UACjB;AAAA,YACE;AAAA,YACA;AAAA,YACA,IAAI,OAAO;AAAA,YACX,MAAM,OAAO;AAAA,YACb,eAAe,OAAO;AAAA,UACxB;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,kBAAkB,SAAmC;AAC3D,UAAM,UAAU,QAAQ,MAAM,wCAAwC;AACtE,UAAM,YAAY,QAAQ,MAAM,4BAA4B;AAE5D,UAAM,KAAK,UAAU,CAAC,GAAG,KAAK,KAAK,QAAQ,KAAK;AAChD,UAAM,OAAO,YAAY,CAAC,GAAG,KAAK,KAAK;AAEvC,WAAO,CAAC,IAAI,IAAI;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,SAAmC;AACvC,UAAM,KAAK,WAAW;AAGtB,UAAM,SAAS,MAAM,KAAK,GAAG;AAAA,MAO3B;AAAA,cACQ,KAAK,SAAS;AAAA;AAAA,IAExB;AAEA,UAAM,UAA6B,OAAO,KAAK,IAAI,CAAC,SAAS;AAAA,MAC3D,SAAS,IAAI;AAAA,MACb,MAAM,IAAI;AAAA,MACV,WAAW,IAAI,KAAK,IAAI,UAAU;AAAA,MAClC,eAAe,IAAI;AAAA,MACnB,UAAU,IAAI,YAAY;AAAA,IAC5B,EAAE;AAEF,UAAM,kBAAkB,IAAI,IAAI,QAAQ,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC;AAC7D,UAAM,mBAAmB,eAAe,KAAK,UAAU;AAEvD,UAAM,UAAU,iBAAiB;AAAA,MAC/B,CAAC,MAAM,CAAC,gBAAgB,IAAI,EAAE,OAAO;AAAA,IACvC;AAEA,WAAO;AAAA,MACL;AAAA,MACA;AAAA,MACA,gBAAgB,QAAQ,SAAS,IAAI,QAAQ,QAAQ,SAAS,CAAC,EAAG,UAAU;AAAA,MAC5E,eACE,iBAAiB,SAAS,IACtB,iBAAiB,iBAAiB,SAAS,CAAC,EAAG,UAC/C;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,GAAG,UAA6C,CAAC,GAA+B;AACpF,UAAM,EAAE,SAAS,OAAO,GAAG,IAAI;AAC/B,UAAM,UAA6B,CAAC;AAEpC,QAAI,CAAC,QAAQ;AACX,YAAM,WAAW,MAAM,KAAK,KAAK;AACjC,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,yEAAyE;AAAA,MAC3F;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAI,UAAU,OAAO;AAGrB,UAAI,IAAI;AACN,cAAM,cAAc,QAAQ,UAAU,CAAC,MAAM,EAAE,YAAY,EAAE;AAC7D,YAAI,gBAAgB,IAAI;AACtB,gBAAM,IAAI,MAAM,kBAAkB,EAAE,kCAAkC;AAAA,QACxE;AACA,kBAAU,QAAQ,MAAM,GAAG,cAAc,CAAC;AAAA,MAC5C;AAEA,iBAAW,aAAa,SAAS;AAC/B,cAAM,SAAS,MAAM,KAAK,aAAa,WAAW,MAAM,MAAM;AAC9D,gBAAQ,KAAK,MAAM;AAEnB,YAAI,CAAC,OAAO,SAAS;AACnB;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,UAAI,CAAC,QAAQ;AACX,cAAM,KAAK,OAAO;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,UAAgD,CAAC,GAA+B;AACzF,UAAM,EAAE,SAAS,OAAO,QAAQ,EAAE,IAAI;AACtC,UAAM,UAA6B,CAAC;AAEpC,QAAI,CAAC,QAAQ;AACX,YAAM,WAAW,MAAM,KAAK,KAAK;AACjC,UAAI,CAAC,UAAU;AACb,cAAM,IAAI,MAAM,yEAAyE;AAAA,MAC3F;AAAA,IACF;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,OAAO;AAGjC,YAAM,aAAa,OAAO,QAAQ,MAAM,CAAC,KAAK,EAAE,QAAQ;AAExD,iBAAW,UAAU,YAAY;AAC/B,cAAM,YAAY,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,YAAY,OAAO,OAAO;AAC1E,YAAI,CAAC,WAAW;AACd,gBAAM,IAAI;AAAA,YACR,aAAa,OAAO,OAAO;AAAA,UAC7B;AAAA,QACF;AAEA,cAAM,SAAS,MAAM,KAAK,aAAa,WAAW,QAAQ,MAAM;AAChE,gBAAQ,KAAK,MAAM;AAEnB,YAAI,CAAC,OAAO,SAAS;AACnB;AAAA,QACF;AAAA,MACF;AAAA,IACF,UAAE;AACA,UAAI,CAAC,QAAQ;AACX,cAAM,KAAK,OAAO;AAAA,MACpB;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,UAAgC,CAAC,GAA+B;AAC1E,UAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAM,cAAc,MAAM,KAAK,KAAK;AAAA,MAClC,QAAQ,QAAQ;AAAA,MAChB,OAAO,OAAO,QAAQ;AAAA,IACxB,CAAC;AAGD,QAAI,YAAY,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG;AACvC,YAAM,YAAY,MAAM,KAAK,GAAG,EAAE,QAAQ,QAAQ,OAAO,CAAC;AAC1D,aAAO,CAAC,GAAG,aAAa,GAAG,SAAS;AAAA,IACtC;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,KAAK,SAAiB,UAAgC,CAAC,GAA+B;AAC1F,UAAM,SAAS,MAAM,KAAK,OAAO;AACjC,UAAM,iBAAiB,OAAO;AAC9B,UAAM,UAA6B,CAAC;AAGpC,QAAI,mBAAmB,SAAS;AAC9B,aAAO;AAAA,IACT;AAGA,UAAM,OAAO,CAAC,kBAAkB,UAAU;AAE1C,QAAI,MAAM;AACR,aAAO,KAAK,GAAG,EAAE,GAAG,SAAS,IAAI,QAAQ,CAAC;AAAA,IAC5C,OAAO;AAEL,YAAM,eAAe,OAAO,QAAQ,UAAU,CAAC,MAAM,EAAE,YAAY,cAAc;AACjF,YAAM,cAAc,OAAO,QAAQ,UAAU,CAAC,MAAM,EAAE,YAAY,OAAO;AAEzE,UAAI,gBAAgB,IAAI;AACtB,cAAM,IAAI,MAAM,kBAAkB,OAAO,kCAAkC;AAAA,MAC7E;AAEA,YAAM,QAAQ,eAAe;AAC7B,aAAO,KAAK,KAAK,EAAE,GAAG,SAAS,MAAM,CAAC;AAAA,IACxC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,aACZ,WACA,WACA,QAC0B;AAC1B,UAAM,YAAY,KAAK,IAAI;AAC3B,UAAM,SAAS,cAAc,OAAO,UAAU,KAAK,UAAU;AAE7D,QAAI;AACF,UAAI,QAAQ;AAEV,eAAO;AAAA,UACL;AAAA,UACA,SAAS;AAAA,UACT,eAAe;AAAA,UACf,QAAQ;AAAA,QACV;AAAA,MACF;AAEA,YAAM,gBAAgB,UAAU,kBAAkB;AAClD,YAAM,YAAY,OAAO,OAA2B;AAClD,YAAI,OAAO,WAAW,UAAU;AAC9B,gBAAM,SAAS,MAAM,GAAG,IAAI,MAAM;AAClC,cAAI,OAAO,OAAO;AAChB,kBAAM,OAAO;AAAA,UACf;AAAA,QACF,OAAO;AACL,gBAAM,OAAO,EAAE;AAAA,QACjB;AAAA,MACF;AAEA,UAAI,eAAe;AACjB,cAAM,KAAK,GAAG,YAAY,OAAO,OAAO;AACtC,gBAAM,UAAU,EAAE;AAAA,QACpB,CAAC;AAAA,MACH,OAAO;AACL,cAAM,UAAU,KAAK,EAAE;AAAA,MACzB;AAEA,YAAM,gBAAgB,KAAK,IAAI,IAAI;AAGnC,UAAI,cAAc,MAAM;AACtB,cAAM,KAAK,GAAG;AAAA,UACZ,eAAe,KAAK,SAAS;AAAA;AAAA,UAE7B,CAAC,UAAU,SAAS,UAAU,MAAM,eAAe,UAAU,QAAQ;AAAA,QACvE;AAAA,MACF,OAAO;AACL,cAAM,KAAK,GAAG;AAAA,UACZ,eAAe,KAAK,SAAS;AAAA,UAC7B,CAAC,UAAU,OAAO;AAAA,QACpB;AAAA,MACF;AAEA,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT;AAAA,QACA,QAAQ;AAAA,MACV;AAAA,IACF,SAAS,OAAO;AACd,aAAO;AAAA,QACL;AAAA,QACA,SAAS;AAAA,QACT,eAAe,KAAK,IAAI,IAAI;AAAA,QAC5B,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,QAC/D,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,OAAO,MAA+B;AAC1C,UAAM,EAAE,WAAW,MAAM,IAAI,MAAM,OAAO,aAAa;AACvD,UAAM,EAAE,KAAK,IAAI,MAAM,OAAO,MAAM;AAEpC,QAAI,CAAC,KAAK,OAAO,eAAe;AAC9B,YAAM,IAAI,MAAM,uDAAuD;AAAA,IACzE;AAGA,UAAM,MAAM,KAAK,OAAO,eAAe,EAAE,WAAW,KAAK,CAAC;AAG1D,UAAM,MAAM,oBAAI,KAAK;AACrB,UAAM,UAAU;AAAA,MACd,IAAI,YAAY;AAAA,MAChB,OAAO,IAAI,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MAC1C,OAAO,IAAI,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACrC,OAAO,IAAI,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACtC,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,MACxC,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,IAC1C,EAAE,KAAK,EAAE;AAET,UAAM,WAAW,KAAK,QAAQ,kBAAkB,GAAG,EAAE,YAAY;AACjE,UAAM,WAAW,GAAG,OAAO,IAAI,QAAQ;AACvC,UAAM,WAAW,KAAK,KAAK,OAAO,eAAe,QAAQ;AAEzD,UAAM,WAAW,iBAAiB,IAAI;AAAA,cAC5B,OAAO;AAAA,cACP,IAAI,YAAY,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAW3B,UAAM,UAAU,UAAU,UAAU,OAAO;AAE3C,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA0D;AAC9D,UAAM,SAAmB,CAAC;AAC1B,UAAM,SAAS,MAAM,KAAK,OAAO;AAEjC,QAAI,CAAC,KAAK,OAAO,mBAAmB;AAClC,aAAO,EAAE,OAAO,MAAM,OAAO;AAAA,IAC/B;AAEA,eAAW,WAAW,OAAO,SAAS;AACpC,YAAM,YAAY,KAAK,WAAW,KAAK,CAAC,MAAM,EAAE,YAAY,QAAQ,OAAO;AAE3E,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,UACL,aAAa,QAAQ,OAAO,KAAK,QAAQ,IAAI;AAAA,QAC/C;AACA;AAAA,MACF;AAEA,UAAI,QAAQ,YAAY,UAAU,aAAa,QAAQ,UAAU;AAC/D,eAAO;AAAA,UACL,aAAa,QAAQ,OAAO,KAAK,QAAQ,IAAI;AAAA,QAC/C;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,MACL,OAAO,OAAO,WAAW;AAAA,MACzB;AAAA,IACF;AAAA,EACF;AACF;;;AC1iBO,SAAS,aAAa,WAMf;AACZ,SAAO;AAAA,IACL,SAAS,UAAU;AAAA,IACnB,MAAM,UAAU;AAAA,IAChB,IAAI,UAAU;AAAA,IACd,MAAM,UAAU;AAAA,IAChB,eAAe,UAAU;AAAA,EAC3B;AACF;AAqBO,SAAS,gBAAgB,WAMlB;AACZ,SAAO;AAAA,IACL,SAAS,UAAU;AAAA,IACnB,MAAM,UAAU;AAAA,IAChB,IAAI,UAAU;AAAA,IACd,MAAM,UAAU;AAAA,IAChB,eAAe,UAAU;AAAA,EAC3B;AACF;AAyBO,SAAS,gBAQd,WAAyB;AACzB,SAAO;AACT;AAUO,SAAS,kBAA0B;AACxC,QAAM,MAAM,oBAAI,KAAK;AACrB,SAAO;AAAA,IACL,IAAI,YAAY;AAAA,IAChB,OAAO,IAAI,SAAS,IAAI,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,IAC1C,OAAO,IAAI,QAAQ,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,IACrC,OAAO,IAAI,SAAS,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,IACtC,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,IACxC,OAAO,IAAI,WAAW,CAAC,EAAE,SAAS,GAAG,GAAG;AAAA,EAC1C,EAAE,KAAK,EAAE;AACX;AAKO,IAAM,MAAM;AAAA;AAAA;AAAA;AAAA,EAIjB,yBAAyB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAazB,wBAAwB,CAAC,cAAsB;AAAA,4BACrB,SAAS;AAAA,wBACb,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQ/B,sBAAsB,CAAC,cAAsB;AAAA,oCACX,SAAS,mBAAmB,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA,EAMvE,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQlB,gBAAgB;AAAA;AAAA;AAAA;AAAA,EAKhB,qBAAqB;AAAA;AAAA;AAAA;AAAA,EAKrB,gBAAgB;AAClB;","names":["data","error","query","getContext","PostgresDatabase","SupabaseDatabase","RedisCache","UpstashCache","SupabaseStorage","S3Storage","SmtpEmail","ResendEmail","BullMQQueue","OpenTelemetryTracing","getUserId","value","withTimeout","ctx","createHmac","createHmac","generateChecksum"]}