@invect/core 0.1.0 → 0.1.1

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,"file":"database.service.js","names":[],"sources":["../../../src/services/database/database.service.ts"],"sourcesContent":["// Framework-agnostic Database Service for Invect core\n\nimport { DatabaseConnectionFactory, type DatabaseConnection } from '../../database/connection';\nimport { verifySchema, type SchemaVerificationOptions } from '../../database/schema-verification';\nimport { CORE_SCHEMA } from '../../database/core-schema';\nimport { DatabaseError } from 'src/types/common/errors.types';\nimport { FlowRunsModel } from '../flow-runs/flow-runs.model';\nimport { FlowsModel } from '../flows/flows.model';\nimport { BatchJobsModel } from '../batch-jobs/batch-jobs.model';\nimport { FlowVersionsModel } from '../flow-versions/flow-versions.model';\nimport { NodeExecutionsModel } from '../node-executions/node-executions.model';\nimport { AgentToolExecutionsModel } from '../agent-tool-executions/agent-tool-executions.model';\nimport { FlowTriggersModel } from '../triggers/flow-triggers.model';\nimport { ChatMessagesModel } from '../chat/chat-messages.model';\nimport { InvectDatabaseConfig, Logger } from 'src/types/schemas';\nimport type { InvectPlugin } from 'src/types/plugin.types';\nimport type { InvectAdapter } from '../../database/adapter';\nimport { createAdapterFromConnection } from '../../database/adapters/connection-bridge';\n\ntype PostgreSqlClientLike = {\n <T = Record<string, unknown>>(query: string): Promise<T[]>;\n (strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;\n};\n\ntype SqliteClientLike = {\n prepare(sql: string): {\n all(...params: unknown[]): Record<string, unknown>[];\n run(...params: unknown[]): { changes: number };\n get(...params: unknown[]): Record<string, unknown> | undefined;\n };\n exec(sql: string): void;\n};\n\ntype MysqlClientLike = {\n execute<T = Record<string, unknown>>(\n query: string,\n params?: unknown[],\n ): Promise<[T[] | unknown, unknown]>;\n};\n\ntype PostgreSqlDbLike = {\n $client: PostgreSqlClientLike;\n};\n\ntype SqliteDbLike = {\n $client: SqliteClientLike;\n};\n\ntype MysqlDbLike = {\n $client: MysqlClientLike;\n};\n\n/**\n * Describes tables that a plugin needs checked at startup.\n */\nexport interface PluginTableRequirement {\n pluginId: string;\n pluginName: string;\n tables: string[];\n setupInstructions?: string;\n}\n\n/**\n * Core database service implementation\n */\nexport class DatabaseService {\n private connection: DatabaseConnection | null = null;\n private _database: Database | null = null;\n private _adapter: InvectAdapter | null = null;\n private schemaVerificationOptions?: SchemaVerificationOptions;\n private pluginTableRequirements: PluginTableRequirement[] = [];\n\n constructor(\n private readonly hostDbConfig: InvectDatabaseConfig,\n private readonly logger: Logger = console,\n schemaVerification?: SchemaVerificationOptions,\n plugins?: InvectPlugin[],\n ) {\n this.schemaVerificationOptions = schemaVerification;\n this.pluginTableRequirements = DatabaseService.extractPluginTableRequirements(plugins ?? []);\n }\n\n /**\n * Get the Database instance with all model classes\n */\n get database(): Database {\n if (!this._database) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n return this._database;\n }\n\n /**\n * Get the InvectAdapter instance for direct adapter access\n */\n get adapter(): InvectAdapter {\n if (!this._adapter) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n return this._adapter;\n }\n\n /**\n * Direct access to flows model\n */\n get flows() {\n return this.database.flows;\n }\n\n /**\n * Direct access to flow versions model\n */\n get flowVersions() {\n return this.database.flowVersions;\n }\n\n /**\n * Direct access to flow executions model\n */\n get flowRuns() {\n return this.database.flowRuns;\n }\n\n /**\n * Direct access to execution traces model\n */\n get nodeExecutions() {\n return this.database.executionTraces;\n }\n\n /**\n * Direct access to batch jobs model\n */\n get batchJobs() {\n return this.database.batchJobs;\n }\n\n /**\n * Direct access to agent tool executions model\n */\n get agentToolExecutions() {\n return this.database.agentToolExecutions;\n }\n\n /**\n * Direct access to flow triggers model\n */\n get flowTriggers() {\n return this.database.flowTriggers;\n }\n\n /**\n * Direct access to chat messages model\n */\n get chatMessages() {\n return this.database.chatMessages;\n }\n\n /**\n * Initialize the database connection and models\n */\n async initialize(): Promise<void> {\n if (this.connection) {\n this.logger.debug('Database connection already initialized');\n return;\n }\n\n // --- Step 1: Establish the database connection ---\n try {\n this.connection = await DatabaseConnectionFactory.createHostDBConnection(\n this.hostDbConfig,\n this.logger,\n );\n } catch (error) {\n this.logConnectionError(error);\n throw new DatabaseError(\n `Failed to connect to the database: ${error instanceof Error ? error.message : error}`,\n { error, originalStack: error instanceof Error ? error.stack : undefined },\n );\n }\n\n // --- Step 2: Verify connectivity with a simple query ---\n try {\n await this.runConnectivityCheck(this.connection);\n } catch (error) {\n this.logConnectivityError(error);\n throw new DatabaseError(\n `Database connectivity check failed: ${error instanceof Error ? error.message : error}`,\n { error },\n );\n }\n\n // --- Step 3: Check that core Invect tables exist ---\n // This always runs (regardless of schemaVerification config) to catch\n // the common case of a fresh database that hasn't had migrations applied.\n await this.runCoreTableCheck(this.connection);\n\n // --- Step 3b: Check that plugin-required tables exist ---\n // Each plugin can declare requiredTables to get a clear error at startup\n // instead of a cryptic runtime crash when a table is missing.\n await this.runPluginTableChecks(this.connection);\n\n // --- Step 4: Initialize the database models ---\n this._adapter = createAdapterFromConnection(this.connection);\n this._database = new Database(this.connection, this.logger, this._adapter);\n\n // --- Step 5: Run detailed schema verification (opt-in) ---\n // This checks columns, not just tables. Controlled by config.schemaVerification.\n if (this.schemaVerificationOptions) {\n await verifySchema(this.connection, this.logger, this.schemaVerificationOptions);\n }\n\n this.logger.info('Database service initialized successfully');\n }\n\n /**\n * Get the database connection for sharing with other services\n */\n getConnection(): DatabaseConnection {\n if (!this.connection) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n return this.connection;\n }\n\n /**\n * Execute a SQL query on a provided queryDatabase\n */\n async executeQuery(\n query: string,\n queryDBConfig: InvectDatabaseConfig,\n ): Promise<Record<string, unknown>[]> {\n try {\n this.logger.debug('Executing query on external database', {\n query,\n dbType: queryDBConfig.type,\n dbId: queryDBConfig.id,\n });\n\n // Create or get existing query database connection\n const queryConnection = await DatabaseConnectionFactory.createQueryDbConnection(\n queryDBConfig,\n this.logger,\n );\n\n // Execute the query based on database type and return results\n let result: Record<string, unknown>[] = [];\n\n switch (queryDBConfig.type) {\n case 'postgresql': {\n // PostgreSQL query execution using postgres.js client directly\n const client = (queryConnection.db as unknown as PostgreSqlDbLike).$client;\n result = await client<Record<string, unknown>>(query);\n break;\n }\n case 'sqlite': {\n // SQLite query execution using better-sqlite3 synchronous API\n const sqliteClient = (queryConnection.db as unknown as SqliteDbLike).$client;\n result = sqliteClient.prepare(query).all() as Record<string, unknown>[];\n break;\n }\n case 'mysql': {\n // MySQL query execution using mysql2 client directly\n const client = (queryConnection.db as unknown as MysqlDbLike).$client;\n const [rows] = await client.execute<Record<string, unknown>>(query);\n result = Array.isArray(rows) ? rows : [];\n break;\n }\n default:\n throw new DatabaseError(`Unsupported database type: ${queryDBConfig.type}`);\n }\n\n this.logger.debug('Query executed successfully', {\n rowCount: Array.isArray(result) ? result.length : 'unknown',\n dbType: queryDBConfig.type,\n dbId: queryDBConfig.id,\n });\n\n return result;\n } catch (error) {\n this.logger.error('Failed to execute query on external database', {\n error: error instanceof Error ? error.message : error,\n query,\n dbType: queryDBConfig.type,\n dbId: queryDBConfig.id,\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n throw new DatabaseError(\n `Query execution failed on ${queryDBConfig.type} database (${queryDBConfig.id}): ${\n error instanceof Error ? error.message : error\n }`,\n {\n error,\n query,\n dbConfig: queryDBConfig,\n originalStack: error instanceof Error ? error.stack : undefined,\n },\n );\n }\n }\n\n /**\n * Health check method\n */\n async healthCheck(): Promise<void> {\n this.logger.debug('Performing database health check');\n\n if (!this.connection) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n\n try {\n // Simple connectivity test using host database connection\n switch (this.connection.type) {\n case 'postgresql': {\n const client = (this.connection.db as unknown as PostgreSqlDbLike).$client;\n await client`SELECT 1 as health`;\n break;\n }\n case 'sqlite': {\n const client = (this.connection.db as unknown as SqliteDbLike).$client;\n client.prepare('SELECT 1 as health').get();\n break;\n }\n case 'mysql': {\n const client = (this.connection.db as unknown as MysqlDbLike).$client;\n await client.execute('SELECT 1 as health');\n break;\n }\n default:\n throw new DatabaseError('Unsupported database type for health check');\n }\n\n this.logger.debug('Database health check passed');\n } catch (error) {\n this.logger.error('Database health check failed', error);\n throw new DatabaseError('Database health check failed', { error });\n }\n }\n\n /**\n * Close the database connection\n */\n async close(): Promise<void> {\n if (this.connection) {\n this.logger.debug('Closing database connection');\n this.connection = null;\n this._database = null;\n this.logger.info('Database connection closed');\n }\n }\n\n // ===========================================================================\n // Plugin table requirement extraction\n // ===========================================================================\n\n /**\n * Extract table requirements from plugin declarations.\n *\n * A plugin can declare required tables via:\n * 1. `requiredTables: string[]` — explicit list (preferred)\n * 2. `schema: { tableName: ... }` — inferred from abstract schema definitions\n *\n * If both are present, `requiredTables` takes precedence.\n */\n static extractPluginTableRequirements(plugins: InvectPlugin[]): PluginTableRequirement[] {\n const requirements: PluginTableRequirement[] = [];\n\n for (const plugin of plugins) {\n let tables: string[] = [];\n\n if (plugin.requiredTables && plugin.requiredTables.length > 0) {\n // Explicit declaration takes priority\n tables = [...plugin.requiredTables];\n } else if (plugin.schema) {\n // Infer from abstract schema — each entry's tableName (or snake_case key)\n for (const [key, def] of Object.entries(plugin.schema)) {\n const tableName = (def as { tableName?: string }).tableName ?? key;\n const disabled = (def as { disableMigration?: boolean }).disableMigration;\n if (!disabled) {\n tables.push(tableName);\n }\n }\n }\n\n if (tables.length > 0) {\n requirements.push({\n pluginId: plugin.id,\n pluginName: plugin.name ?? plugin.id,\n tables,\n setupInstructions: plugin.setupInstructions,\n });\n }\n }\n\n return requirements;\n }\n\n // ===========================================================================\n // Startup check helpers\n // ===========================================================================\n\n /**\n * Run a simple `SELECT 1` query to verify the database is reachable.\n */\n private async runConnectivityCheck(connection: DatabaseConnection): Promise<void> {\n switch (connection.type) {\n case 'postgresql': {\n const client = (connection.db as unknown as PostgreSqlDbLike).$client;\n await client`SELECT 1 as health`;\n break;\n }\n case 'sqlite': {\n const client = (connection.db as unknown as SqliteDbLike).$client;\n client.prepare('SELECT 1 as health').get();\n break;\n }\n case 'mysql': {\n const client = (connection.db as unknown as MysqlDbLike).$client;\n await client.execute('SELECT 1 as health');\n break;\n }\n }\n }\n\n /**\n * Check that the essential Invect tables exist in the database.\n * This catches the most common developer mistake: running the app\n * before applying the database schema.\n *\n * Only checks for table *existence*, not column correctness (that's\n * what the opt-in `schemaVerification` does).\n */\n private async runCoreTableCheck(connection: DatabaseConnection): Promise<void> {\n // Collect the expected core table names from the abstract schema\n const expectedTables: string[] = [];\n for (const def of Object.values(CORE_SCHEMA)) {\n const tableDef = def as { tableName?: string; disableMigration?: boolean };\n if (tableDef.disableMigration) {\n continue;\n }\n if (tableDef.tableName) {\n expectedTables.push(tableDef.tableName);\n }\n }\n\n // Get actual table names from the database\n let actualTableNames: Set<string>;\n try {\n actualTableNames = await this.listTableNames(connection);\n } catch (error) {\n // If we can't even list tables, the database is probably unreachable\n // or misconfigured — the connectivity check should have caught this,\n // but log and proceed gracefully.\n this.logger.warn('Could not introspect database tables. Skipping startup table check.', {\n error: error instanceof Error ? error.message : error,\n });\n return;\n }\n\n const missingTables = expectedTables.filter((t) => !actualTableNames.has(t));\n\n if (missingTables.length === 0) {\n this.logger.debug('Core table check passed', {\n tablesFound: expectedTables.length,\n });\n return;\n }\n\n // --- Build a helpful error message ---\n const allMissing = missingTables.length === expectedTables.length;\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — DATABASE NOT READY ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n ];\n\n if (allMissing) {\n lines.push(\n 'Your database exists but has no Invect tables.',\n \"This usually means you haven't pushed the schema yet.\",\n );\n } else {\n lines.push(\n `Your database is missing ${missingTables.length} of ${expectedTables.length} required Invect tables:`,\n ` Missing: ${missingTables.join(', ')}`,\n '',\n 'This usually means your schema is out of date.',\n );\n }\n\n lines.push('');\n\n // Fix instructions — point users to the Invect CLI\n lines.push(\n 'To fix this, run:',\n '',\n ' npx invect generate # generate schema files (core + plugins)',\n ' npx drizzle-kit push # push schema to the database',\n '',\n 'Or if you use migrations:',\n '',\n ' npx invect generate # generate schema files',\n ' npx drizzle-kit generate',\n ' npx invect migrate # apply migrations',\n '',\n 'The Invect CLI reads your invect.config.ts to discover installed',\n 'plugins and generates the correct schema for all of them.',\n '',\n );\n\n const message = lines.join('\\n');\n this.logger.error(message);\n\n throw new DatabaseError(\n `Database is missing ${allMissing ? 'all' : missingTables.length} required Invect table(s). ` +\n `Run schema migrations before starting the server. See logs above for instructions.`,\n { missingTables },\n );\n }\n\n /**\n * Check that tables required by plugins exist in the database.\n *\n * Each plugin can declare `requiredTables` (explicit list) or have them\n * inferred from its `schema` definition. This method checks all of them\n * in a single pass and produces a clear, attributed error message so the\n * developer knows exactly which plugin needs which tables.\n */\n private async runPluginTableChecks(connection: DatabaseConnection): Promise<void> {\n if (this.pluginTableRequirements.length === 0) {\n return; // No plugins declared required tables\n }\n\n // Get actual table names from the database\n let actualTableNames: Set<string>;\n try {\n actualTableNames = await this.listTableNames(connection);\n } catch {\n // If introspection fails, skip gracefully (core check already warned)\n return;\n }\n\n // Collect all missing tables grouped by plugin\n const pluginsWithMissing: Array<{\n pluginId: string;\n pluginName: string;\n missingTables: string[];\n setupInstructions?: string;\n }> = [];\n\n for (const req of this.pluginTableRequirements) {\n const missing = req.tables.filter((t) => !actualTableNames.has(t));\n if (missing.length > 0) {\n pluginsWithMissing.push({\n pluginId: req.pluginId,\n pluginName: req.pluginName,\n missingTables: missing,\n setupInstructions: req.setupInstructions,\n });\n }\n }\n\n if (pluginsWithMissing.length === 0) {\n const totalTables = this.pluginTableRequirements.reduce((sum, r) => sum + r.tables.length, 0);\n this.logger.debug('Plugin table check passed', {\n plugins: this.pluginTableRequirements.length,\n tablesChecked: totalTables,\n });\n return;\n }\n\n // --- Build a helpful, plugin-attributed error message ---\n const totalMissing = pluginsWithMissing.reduce((sum, p) => sum + p.missingTables.length, 0);\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — PLUGIN TABLES MISSING ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n `${totalMissing} table(s) required by ${pluginsWithMissing.length} plugin(s) are missing from the database:`,\n '',\n ];\n\n for (const plugin of pluginsWithMissing) {\n lines.push(\n ` Plugin: ${plugin.pluginName} (${plugin.pluginId})`,\n ` Missing tables: ${plugin.missingTables.join(', ')}`,\n );\n\n if (plugin.setupInstructions) {\n lines.push(` Fix: ${plugin.setupInstructions}`);\n }\n\n lines.push('');\n }\n\n // Check if any plugin provided custom instructions\n const hasCustomInstructions = pluginsWithMissing.some((p) => p.setupInstructions);\n\n if (!hasCustomInstructions) {\n // Generic fix instructions — point to the CLI\n lines.push(\n 'To fix this, run:',\n '',\n ' npx invect generate # generate schema files (core + plugins)',\n ' npx drizzle-kit push # push schema to the database',\n '',\n 'The Invect CLI reads your invect.config.ts, discovers all plugins',\n 'and their required tables, and generates the complete schema.',\n );\n }\n\n lines.push(\n '',\n 'If a plugin defines a schema, `npx invect generate` will include it',\n 'automatically. For plugins with externally-managed tables, see the',\n \"plugin's README for additional schema setup instructions.\",\n '',\n );\n\n const message = lines.join('\\n');\n this.logger.error(message);\n\n throw new DatabaseError(\n `Database is missing ${totalMissing} table(s) required by plugin(s): ` +\n pluginsWithMissing\n .map((p) => `${p.pluginName} (${p.missingTables.join(', ')})`)\n .join('; ') +\n `. Push the schema before starting the server. See logs above for instructions.`,\n {\n pluginsWithMissing: pluginsWithMissing.map((p) => ({\n pluginId: p.pluginId,\n missingTables: p.missingTables,\n })),\n },\n );\n }\n\n /**\n * Get a set of table names from the database.\n */\n private async listTableNames(connection: DatabaseConnection): Promise<Set<string>> {\n const names = new Set<string>();\n\n switch (connection.type) {\n case 'sqlite': {\n const db = connection.db as unknown as SqliteDbLike;\n // Note: In SQL LIKE, '_' is a single-char wildcard. We must escape it\n // with ESCAPE '\\' so 'sqlite\\_%' matches literal 'sqlite_*' and\n // '\\\\_\\\\_%' matches literal names starting with '__'.\n const query = `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite\\\\_%' ESCAPE '\\\\' AND name NOT LIKE '\\\\_\\\\_%' ESCAPE '\\\\'`;\n const rows = db.$client.prepare(query).all() as Array<{ name: string }>;\n for (const row of rows) {\n names.add(row.name);\n }\n break;\n }\n case 'postgresql': {\n const db = connection.db as unknown as PostgreSqlDbLike;\n const rows = (await db.$client`\n SELECT table_name FROM information_schema.tables\n WHERE table_schema = 'public' AND table_type = 'BASE TABLE'\n `) as Array<{ table_name: string }>;\n for (const row of rows) {\n names.add(row.table_name);\n }\n break;\n }\n case 'mysql': {\n const db = connection.db as unknown as MysqlDbLike;\n const [rows] = await db.$client.execute(\n `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE'`,\n );\n for (const row of rows as Array<Record<string, string>>) {\n names.add(row['TABLE_NAME']);\n }\n break;\n }\n }\n\n return names;\n }\n\n /**\n * Log a helpful error when the database connection itself fails.\n */\n private logConnectionError(error: unknown): void {\n const msg = error instanceof Error ? error.message : String(error);\n const dbType = this.hostDbConfig.type;\n const connStr = this.hostDbConfig.connectionString;\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — DATABASE CONNECTION FAILED ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n `Database type: ${dbType}`,\n `Connection string: ${this.redactConnectionString(connStr)}`,\n `Error: ${msg}`,\n '',\n ];\n\n if (dbType === 'sqlite') {\n if (msg.includes('SQLITE_CANTOPEN') || msg.includes('unable to open')) {\n lines.push(\n 'The SQLite database file could not be opened.',\n 'Check that the path is correct and the directory exists.',\n '',\n ` Configured path: ${connStr}`,\n );\n } else {\n lines.push(\n 'Could not connect to the SQLite database.',\n 'Make sure the connection string in your config is valid.',\n '',\n 'Common formats:',\n ' file:./dev.db (relative path)',\n ' file:/absolute/path.db (absolute path)',\n );\n }\n } else if (dbType === 'postgresql') {\n if (msg.includes('ECONNREFUSED') || msg.includes('connect')) {\n lines.push(\n 'Could not reach the PostgreSQL server.',\n 'Make sure PostgreSQL is running and the connection string is correct.',\n '',\n 'Common causes:',\n ' • PostgreSQL is not running (start with: pg_ctl start)',\n ' • Wrong host/port in connection string',\n ' • Firewall blocking the connection',\n );\n } else if (msg.includes('authentication') || msg.includes('password')) {\n lines.push(\n 'PostgreSQL authentication failed.',\n 'Check that the username and password in your connection string are correct.',\n );\n } else if (msg.includes('does not exist')) {\n lines.push(\n 'The PostgreSQL database does not exist.',\n 'Create it with: createdb <database_name>',\n );\n } else {\n lines.push('Could not connect to PostgreSQL. Verify your DATABASE_URL is correct.');\n }\n } else if (dbType === 'mysql') {\n if (msg.includes('ECONNREFUSED') || msg.includes('connect')) {\n lines.push(\n 'Could not reach the MySQL server.',\n 'Make sure MySQL is running and the connection string is correct.',\n );\n } else {\n lines.push('Could not connect to MySQL. Verify your connection string.');\n }\n }\n\n lines.push('');\n this.logger.error(lines.join('\\n'));\n }\n\n /**\n * Log a helpful error when the connectivity probe (SELECT 1) fails.\n */\n private logConnectivityError(error: unknown): void {\n const msg = error instanceof Error ? error.message : String(error);\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — DATABASE CONNECTIVITY CHECK FAILED ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n 'A connection was established but a simple SELECT query failed.',\n `Error: ${msg}`,\n '',\n 'This may indicate:',\n ' • The database server dropped the connection',\n ' • Insufficient permissions for the database user',\n ' • The database file is corrupted (SQLite)',\n '',\n ];\n\n this.logger.error(lines.join('\\n'));\n }\n\n /**\n * Redact credentials from a connection string for safe logging.\n */\n private redactConnectionString(connStr: string): string {\n // Hide passwords in postgres/mysql URLs: postgres://user:PASS@host → postgres://user:***@host\n return connStr.replace(/:([^/:@]+)@/, ':***@');\n }\n}\n\n/**\n * Database Models Factory - Creates all model instances with shared connection and logger\n */\nclass Database {\n public readonly flows: FlowsModel;\n public readonly flowVersions: FlowVersionsModel;\n public readonly flowRuns: FlowRunsModel;\n public readonly executionTraces: NodeExecutionsModel;\n public readonly batchJobs: BatchJobsModel;\n public readonly agentToolExecutions: AgentToolExecutionsModel;\n public readonly flowTriggers: FlowTriggersModel;\n public readonly chatMessages: ChatMessagesModel;\n\n constructor(_connection: DatabaseConnection, logger: Logger, adapter: InvectAdapter) {\n this.flows = new FlowsModel(adapter, logger);\n this.flowVersions = new FlowVersionsModel(adapter, logger);\n this.flowRuns = new FlowRunsModel(adapter, logger);\n this.executionTraces = new NodeExecutionsModel(adapter, logger);\n this.batchJobs = new BatchJobsModel(adapter, logger);\n this.agentToolExecutions = new AgentToolExecutionsModel(adapter, logger);\n this.flowTriggers = new FlowTriggersModel(adapter, logger);\n this.chatMessages = new ChatMessagesModel(adapter, logger);\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"database.service.js","names":[],"sources":["../../../src/services/database/database.service.ts"],"sourcesContent":["// Framework-agnostic Database Service for Invect core\n\nimport { DatabaseConnectionFactory, type DatabaseConnection } from '../../database/connection';\nimport { verifySchema, type SchemaVerificationOptions } from '../../database/schema-verification';\nimport { CORE_SCHEMA } from '../../database/core-schema';\nimport { DatabaseError } from 'src/types/common/errors.types';\nimport { FlowRunsModel } from '../flow-runs/flow-runs.model';\nimport { FlowsModel } from '../flows/flows.model';\nimport { BatchJobsModel } from '../batch-jobs/batch-jobs.model';\nimport { FlowVersionsModel } from '../flow-versions/flow-versions.model';\nimport { NodeExecutionsModel } from '../node-executions/node-executions.model';\nimport { AgentToolExecutionsModel } from '../agent-tool-executions/agent-tool-executions.model';\nimport { FlowTriggersModel } from '../triggers/flow-triggers.model';\nimport { ChatMessagesModel } from '../chat/chat-messages.model';\nimport { InvectDatabaseConfig, Logger } from 'src/types/schemas';\nimport type { InvectPlugin } from 'src/types/plugin.types';\nimport type { InvectAdapter } from '../../database/adapter';\nimport { createAdapterFromConnection } from '../../database/adapters/connection-bridge';\n\ntype PostgreSqlClientLike = {\n <T = Record<string, unknown>>(query: string): Promise<T[]>;\n (strings: TemplateStringsArray, ...values: unknown[]): Promise<unknown[]>;\n};\n\ntype SqliteClientLike = {\n prepare(sql: string): {\n all(...params: unknown[]): Record<string, unknown>[];\n run(...params: unknown[]): { changes: number };\n get(...params: unknown[]): Record<string, unknown> | undefined;\n };\n exec(sql: string): void;\n};\n\ntype MysqlClientLike = {\n execute<T = Record<string, unknown>>(\n query: string,\n params?: unknown[],\n ): Promise<[T[] | unknown, unknown]>;\n};\n\ntype PostgreSqlDbLike = {\n $client: PostgreSqlClientLike;\n};\n\ntype SqliteDbLike = {\n $client: SqliteClientLike;\n};\n\ntype MysqlDbLike = {\n $client: MysqlClientLike;\n};\n\n/**\n * Describes tables that a plugin needs checked at startup.\n */\nexport interface PluginTableRequirement {\n pluginId: string;\n pluginName: string;\n tables: string[];\n setupInstructions?: string;\n}\n\n/**\n * Core database service implementation\n */\nexport class DatabaseService {\n private connection: DatabaseConnection | null = null;\n private _database: Database | null = null;\n private _adapter: InvectAdapter | null = null;\n private schemaVerificationOptions?: SchemaVerificationOptions;\n private pluginTableRequirements: PluginTableRequirement[] = [];\n\n constructor(\n private readonly hostDbConfig: InvectDatabaseConfig,\n private readonly logger: Logger = console,\n schemaVerification?: SchemaVerificationOptions,\n plugins?: InvectPlugin[],\n ) {\n this.schemaVerificationOptions = schemaVerification;\n this.pluginTableRequirements = DatabaseService.extractPluginTableRequirements(plugins ?? []);\n }\n\n /**\n * Get the Database instance with all model classes\n */\n get database(): Database {\n if (!this._database) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n return this._database;\n }\n\n /**\n * Get the InvectAdapter instance for direct adapter access\n */\n get adapter(): InvectAdapter {\n if (!this._adapter) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n return this._adapter;\n }\n\n /**\n * Direct access to flows model\n */\n get flows() {\n return this.database.flows;\n }\n\n /**\n * Direct access to flow versions model\n */\n get flowVersions() {\n return this.database.flowVersions;\n }\n\n /**\n * Direct access to flow executions model\n */\n get flowRuns() {\n return this.database.flowRuns;\n }\n\n /**\n * Direct access to execution traces model\n */\n get nodeExecutions() {\n return this.database.executionTraces;\n }\n\n /**\n * Direct access to batch jobs model\n */\n get batchJobs() {\n return this.database.batchJobs;\n }\n\n /**\n * Direct access to agent tool executions model\n */\n get agentToolExecutions() {\n return this.database.agentToolExecutions;\n }\n\n /**\n * Direct access to flow triggers model\n */\n get flowTriggers() {\n return this.database.flowTriggers;\n }\n\n /**\n * Direct access to chat messages model\n */\n get chatMessages() {\n return this.database.chatMessages;\n }\n\n /**\n * Initialize the database connection and models\n */\n async initialize(): Promise<void> {\n if (this.connection) {\n this.logger.debug('Database connection already initialized');\n return;\n }\n\n // --- Step 1: Establish the database connection ---\n try {\n this.connection = await DatabaseConnectionFactory.createHostDBConnection(\n this.hostDbConfig,\n this.logger,\n );\n } catch (error) {\n this.logConnectionError(error);\n throw new DatabaseError(\n `Failed to connect to the database: ${error instanceof Error ? error.message : error}`,\n { error, originalStack: error instanceof Error ? error.stack : undefined },\n );\n }\n\n // --- Step 2: Verify connectivity with a simple query ---\n try {\n await this.runConnectivityCheck(this.connection);\n } catch (error) {\n this.logConnectivityError(error);\n throw new DatabaseError(\n `Database connectivity check failed: ${error instanceof Error ? error.message : error}`,\n { error },\n );\n }\n\n // --- Step 3: Check that core Invect tables exist ---\n // This always runs (regardless of schemaVerification config) to catch\n // the common case of a fresh database that hasn't had migrations applied.\n await this.runCoreTableCheck(this.connection);\n\n // --- Step 3b: Check that plugin-required tables exist ---\n // Each plugin can declare requiredTables to get a clear error at startup\n // instead of a cryptic runtime crash when a table is missing.\n await this.runPluginTableChecks(this.connection);\n\n // --- Step 4: Initialize the database models ---\n this._adapter = createAdapterFromConnection(this.connection);\n this._database = new Database(this.connection, this.logger, this._adapter);\n\n // --- Step 5: Run detailed schema verification (opt-in) ---\n // This checks columns, not just tables. Controlled by config.schemaVerification.\n if (this.schemaVerificationOptions) {\n await verifySchema(this.connection, this.logger, this.schemaVerificationOptions);\n }\n\n this.logger.info('Database service initialized successfully');\n }\n\n /**\n * Get the database connection for sharing with other services\n */\n getConnection(): DatabaseConnection {\n if (!this.connection) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n return this.connection;\n }\n\n /**\n * Execute a SQL query on a provided queryDatabase\n */\n async executeQuery(\n query: string,\n queryDBConfig: InvectDatabaseConfig,\n ): Promise<Record<string, unknown>[]> {\n try {\n this.logger.debug('Executing query on external database', {\n query,\n dbType: queryDBConfig.type,\n dbId: queryDBConfig.id,\n });\n\n // Create or get existing query database connection\n const queryConnection = await DatabaseConnectionFactory.createQueryDbConnection(\n queryDBConfig,\n this.logger,\n );\n\n // Execute the query based on database type and return results\n let result: Record<string, unknown>[] = [];\n\n switch (queryDBConfig.type) {\n case 'postgresql': {\n // PostgreSQL query execution using postgres.js client directly\n const client = (queryConnection.db as unknown as PostgreSqlDbLike).$client;\n result = await client<Record<string, unknown>>(query);\n break;\n }\n case 'sqlite': {\n // SQLite query execution using better-sqlite3 synchronous API\n const sqliteClient = (queryConnection.db as unknown as SqliteDbLike).$client;\n result = sqliteClient.prepare(query).all() as Record<string, unknown>[];\n break;\n }\n case 'mysql': {\n // MySQL query execution using mysql2 client directly\n const client = (queryConnection.db as unknown as MysqlDbLike).$client;\n const [rows] = await client.execute<Record<string, unknown>>(query);\n result = Array.isArray(rows) ? rows : [];\n break;\n }\n default:\n throw new DatabaseError(`Unsupported database type: ${queryDBConfig.type}`);\n }\n\n this.logger.debug('Query executed successfully', {\n rowCount: Array.isArray(result) ? result.length : 'unknown',\n dbType: queryDBConfig.type,\n dbId: queryDBConfig.id,\n });\n\n return result;\n } catch (error) {\n this.logger.error('Failed to execute query on external database', {\n error: error instanceof Error ? error.message : error,\n query,\n dbType: queryDBConfig.type,\n dbId: queryDBConfig.id,\n stack: error instanceof Error ? error.stack : undefined,\n });\n\n throw new DatabaseError(\n `Query execution failed on ${queryDBConfig.type} database (${queryDBConfig.id}): ${\n error instanceof Error ? error.message : error\n }`,\n {\n error,\n query,\n dbConfig: queryDBConfig,\n originalStack: error instanceof Error ? error.stack : undefined,\n },\n );\n }\n }\n\n /**\n * Health check method\n */\n async healthCheck(): Promise<void> {\n this.logger.debug('Performing database health check');\n\n if (!this.connection) {\n throw new DatabaseError('Database not initialized - call initialize() first');\n }\n\n try {\n // Simple connectivity test using host database connection\n switch (this.connection.type) {\n case 'postgresql': {\n const client = (this.connection.db as unknown as PostgreSqlDbLike).$client;\n await client`SELECT 1 as health`;\n break;\n }\n case 'sqlite': {\n const client = (this.connection.db as unknown as SqliteDbLike).$client;\n client.prepare('SELECT 1 as health').get();\n break;\n }\n case 'mysql': {\n const client = (this.connection.db as unknown as MysqlDbLike).$client;\n await client.execute('SELECT 1 as health');\n break;\n }\n default:\n throw new DatabaseError('Unsupported database type for health check');\n }\n\n this.logger.debug('Database health check passed');\n } catch (error) {\n this.logger.error('Database health check failed', error);\n throw new DatabaseError('Database health check failed', { error });\n }\n }\n\n /**\n * Close the database connection\n */\n async close(): Promise<void> {\n if (this.connection) {\n this.logger.debug('Closing database connection');\n this.connection = null;\n this._database = null;\n this.logger.info('Database connection closed');\n }\n }\n\n // ===========================================================================\n // Plugin table requirement extraction\n // ===========================================================================\n\n /**\n * Extract table requirements from plugin declarations.\n *\n * A plugin can declare required tables via:\n * 1. `requiredTables: string[]` — explicit list (preferred)\n * 2. `schema: { tableName: ... }` — inferred from abstract schema definitions\n *\n * If both are present, `requiredTables` takes precedence.\n */\n static extractPluginTableRequirements(plugins: InvectPlugin[]): PluginTableRequirement[] {\n const requirements: PluginTableRequirement[] = [];\n\n for (const plugin of plugins) {\n let tables: string[] = [];\n\n if (plugin.requiredTables && plugin.requiredTables.length > 0) {\n // Explicit declaration takes priority\n tables = [...plugin.requiredTables];\n } else if (plugin.schema) {\n // Infer from abstract schema — each entry's tableName (or snake_case key)\n for (const [key, def] of Object.entries(plugin.schema)) {\n const tableName = (def as { tableName?: string }).tableName ?? key;\n const disabled = (def as { disableMigration?: boolean }).disableMigration;\n if (!disabled) {\n tables.push(tableName);\n }\n }\n }\n\n if (tables.length > 0) {\n requirements.push({\n pluginId: plugin.id,\n pluginName: plugin.name ?? plugin.id,\n tables,\n setupInstructions: plugin.setupInstructions,\n });\n }\n }\n\n return requirements;\n }\n\n // ===========================================================================\n // Startup check helpers\n // ===========================================================================\n\n /**\n * Run a simple `SELECT 1` query to verify the database is reachable.\n */\n private async runConnectivityCheck(connection: DatabaseConnection): Promise<void> {\n switch (connection.type) {\n case 'postgresql': {\n const client = (connection.db as unknown as PostgreSqlDbLike).$client;\n await client`SELECT 1 as health`;\n break;\n }\n case 'sqlite': {\n const client = (connection.db as unknown as SqliteDbLike).$client;\n client.prepare('SELECT 1 as health').get();\n break;\n }\n case 'mysql': {\n const client = (connection.db as unknown as MysqlDbLike).$client;\n await client.execute('SELECT 1 as health');\n break;\n }\n }\n }\n\n /**\n * Check that the essential Invect tables exist in the database.\n * This catches the most common developer mistake: running the app\n * before applying the database schema.\n *\n * Only checks for table *existence*, not column correctness (that's\n * what the opt-in `schemaVerification` does).\n */\n private async runCoreTableCheck(connection: DatabaseConnection): Promise<void> {\n // Collect the expected core table names from the abstract schema\n const expectedTables: string[] = [];\n for (const def of Object.values(CORE_SCHEMA)) {\n const tableDef = def as { tableName?: string; disableMigration?: boolean };\n if (tableDef.disableMigration) {\n continue;\n }\n if (tableDef.tableName) {\n expectedTables.push(tableDef.tableName);\n }\n }\n\n // Get actual table names from the database\n let actualTableNames: Set<string>;\n try {\n actualTableNames = await this.listTableNames(connection);\n } catch (error) {\n // If we can't even list tables, the database is probably unreachable\n // or misconfigured — the connectivity check should have caught this,\n // but log and proceed gracefully.\n this.logger.warn('Could not introspect database tables. Skipping startup table check.', {\n error: error instanceof Error ? error.message : error,\n });\n return;\n }\n\n const missingTables = expectedTables.filter((t) => !actualTableNames.has(t));\n\n if (missingTables.length === 0) {\n this.logger.debug('Core table check passed', {\n tablesFound: expectedTables.length,\n });\n return;\n }\n\n // --- Build a helpful error message ---\n const allMissing = missingTables.length === expectedTables.length;\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — DATABASE NOT READY ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n ];\n\n if (allMissing) {\n lines.push(\n 'Your database exists but has no Invect tables.',\n \"This usually means you haven't pushed the schema yet.\",\n );\n } else {\n lines.push(\n `Your database is missing ${missingTables.length} of ${expectedTables.length} required Invect tables:`,\n ` Missing: ${missingTables.join(', ')}`,\n '',\n 'This usually means your schema is out of date.',\n );\n }\n\n lines.push('');\n\n // Fix instructions — point users to the Invect CLI\n lines.push(\n 'To fix this, run:',\n '',\n ' npx invect-cli generate # generate schema files (core + plugins)',\n ' npx drizzle-kit push # push schema to the database',\n '',\n 'Or if you use migrations:',\n '',\n ' npx invect-cli generate # generate schema files',\n ' npx drizzle-kit generate',\n ' npx invect-cli migrate # apply migrations',\n '',\n 'The Invect CLI reads your invect.config.ts to discover installed',\n 'plugins and generates the correct schema for all of them.',\n '',\n );\n\n const message = lines.join('\\n');\n this.logger.error(message);\n\n throw new DatabaseError(\n `Database is missing ${allMissing ? 'all' : missingTables.length} required Invect table(s). ` +\n `Run schema migrations before starting the server. See logs above for instructions.`,\n { missingTables },\n );\n }\n\n /**\n * Check that tables required by plugins exist in the database.\n *\n * Each plugin can declare `requiredTables` (explicit list) or have them\n * inferred from its `schema` definition. This method checks all of them\n * in a single pass and produces a clear, attributed error message so the\n * developer knows exactly which plugin needs which tables.\n */\n private async runPluginTableChecks(connection: DatabaseConnection): Promise<void> {\n if (this.pluginTableRequirements.length === 0) {\n return; // No plugins declared required tables\n }\n\n // Get actual table names from the database\n let actualTableNames: Set<string>;\n try {\n actualTableNames = await this.listTableNames(connection);\n } catch {\n // If introspection fails, skip gracefully (core check already warned)\n return;\n }\n\n // Collect all missing tables grouped by plugin\n const pluginsWithMissing: Array<{\n pluginId: string;\n pluginName: string;\n missingTables: string[];\n setupInstructions?: string;\n }> = [];\n\n for (const req of this.pluginTableRequirements) {\n const missing = req.tables.filter((t) => !actualTableNames.has(t));\n if (missing.length > 0) {\n pluginsWithMissing.push({\n pluginId: req.pluginId,\n pluginName: req.pluginName,\n missingTables: missing,\n setupInstructions: req.setupInstructions,\n });\n }\n }\n\n if (pluginsWithMissing.length === 0) {\n const totalTables = this.pluginTableRequirements.reduce((sum, r) => sum + r.tables.length, 0);\n this.logger.debug('Plugin table check passed', {\n plugins: this.pluginTableRequirements.length,\n tablesChecked: totalTables,\n });\n return;\n }\n\n // --- Build a helpful, plugin-attributed error message ---\n const totalMissing = pluginsWithMissing.reduce((sum, p) => sum + p.missingTables.length, 0);\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — PLUGIN TABLES MISSING ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n `${totalMissing} table(s) required by ${pluginsWithMissing.length} plugin(s) are missing from the database:`,\n '',\n ];\n\n for (const plugin of pluginsWithMissing) {\n lines.push(\n ` Plugin: ${plugin.pluginName} (${plugin.pluginId})`,\n ` Missing tables: ${plugin.missingTables.join(', ')}`,\n );\n\n if (plugin.setupInstructions) {\n lines.push(` Fix: ${plugin.setupInstructions}`);\n }\n\n lines.push('');\n }\n\n // Check if any plugin provided custom instructions\n const hasCustomInstructions = pluginsWithMissing.some((p) => p.setupInstructions);\n\n if (!hasCustomInstructions) {\n // Generic fix instructions — point to the CLI\n lines.push(\n 'To fix this, run:',\n '',\n ' npx invect-cli generate # generate schema files (core + plugins)',\n ' npx drizzle-kit push # push schema to the database',\n '',\n 'The Invect CLI reads your invect.config.ts, discovers all plugins',\n 'and their required tables, and generates the complete schema.',\n );\n }\n\n lines.push(\n '',\n 'If a plugin defines a schema, `npx invect-cli generate` will include it',\n 'automatically. For plugins with externally-managed tables, see the',\n \"plugin's README for additional schema setup instructions.\",\n '',\n );\n\n const message = lines.join('\\n');\n this.logger.error(message);\n\n throw new DatabaseError(\n `Database is missing ${totalMissing} table(s) required by plugin(s): ` +\n pluginsWithMissing\n .map((p) => `${p.pluginName} (${p.missingTables.join(', ')})`)\n .join('; ') +\n `. Push the schema before starting the server. See logs above for instructions.`,\n {\n pluginsWithMissing: pluginsWithMissing.map((p) => ({\n pluginId: p.pluginId,\n missingTables: p.missingTables,\n })),\n },\n );\n }\n\n /**\n * Get a set of table names from the database.\n */\n private async listTableNames(connection: DatabaseConnection): Promise<Set<string>> {\n const names = new Set<string>();\n\n switch (connection.type) {\n case 'sqlite': {\n const db = connection.db as unknown as SqliteDbLike;\n // Note: In SQL LIKE, '_' is a single-char wildcard. We must escape it\n // with ESCAPE '\\' so 'sqlite\\_%' matches literal 'sqlite_*' and\n // '\\\\_\\\\_%' matches literal names starting with '__'.\n const query = `SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite\\\\_%' ESCAPE '\\\\' AND name NOT LIKE '\\\\_\\\\_%' ESCAPE '\\\\'`;\n const rows = db.$client.prepare(query).all() as Array<{ name: string }>;\n for (const row of rows) {\n names.add(row.name);\n }\n break;\n }\n case 'postgresql': {\n const db = connection.db as unknown as PostgreSqlDbLike;\n const rows = (await db.$client`\n SELECT table_name FROM information_schema.tables\n WHERE table_schema = 'public' AND table_type = 'BASE TABLE'\n `) as Array<{ table_name: string }>;\n for (const row of rows) {\n names.add(row.table_name);\n }\n break;\n }\n case 'mysql': {\n const db = connection.db as unknown as MysqlDbLike;\n const [rows] = await db.$client.execute(\n `SELECT TABLE_NAME FROM information_schema.TABLES WHERE TABLE_SCHEMA = DATABASE() AND TABLE_TYPE = 'BASE TABLE'`,\n );\n for (const row of rows as Array<Record<string, string>>) {\n names.add(row['TABLE_NAME']);\n }\n break;\n }\n }\n\n return names;\n }\n\n /**\n * Log a helpful error when the database connection itself fails.\n */\n private logConnectionError(error: unknown): void {\n const msg = error instanceof Error ? error.message : String(error);\n const dbType = this.hostDbConfig.type;\n const connStr = this.hostDbConfig.connectionString;\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — DATABASE CONNECTION FAILED ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n `Database type: ${dbType}`,\n `Connection string: ${this.redactConnectionString(connStr)}`,\n `Error: ${msg}`,\n '',\n ];\n\n if (dbType === 'sqlite') {\n if (msg.includes('SQLITE_CANTOPEN') || msg.includes('unable to open')) {\n lines.push(\n 'The SQLite database file could not be opened.',\n 'Check that the path is correct and the directory exists.',\n '',\n ` Configured path: ${connStr}`,\n );\n } else {\n lines.push(\n 'Could not connect to the SQLite database.',\n 'Make sure the connection string in your config is valid.',\n '',\n 'Common formats:',\n ' file:./dev.db (relative path)',\n ' file:/absolute/path.db (absolute path)',\n );\n }\n } else if (dbType === 'postgresql') {\n if (msg.includes('ECONNREFUSED') || msg.includes('connect')) {\n lines.push(\n 'Could not reach the PostgreSQL server.',\n 'Make sure PostgreSQL is running and the connection string is correct.',\n '',\n 'Common causes:',\n ' • PostgreSQL is not running (start with: pg_ctl start)',\n ' • Wrong host/port in connection string',\n ' • Firewall blocking the connection',\n );\n } else if (msg.includes('authentication') || msg.includes('password')) {\n lines.push(\n 'PostgreSQL authentication failed.',\n 'Check that the username and password in your connection string are correct.',\n );\n } else if (msg.includes('does not exist')) {\n lines.push(\n 'The PostgreSQL database does not exist.',\n 'Create it with: createdb <database_name>',\n );\n } else {\n lines.push('Could not connect to PostgreSQL. Verify your DATABASE_URL is correct.');\n }\n } else if (dbType === 'mysql') {\n if (msg.includes('ECONNREFUSED') || msg.includes('connect')) {\n lines.push(\n 'Could not reach the MySQL server.',\n 'Make sure MySQL is running and the connection string is correct.',\n );\n } else {\n lines.push('Could not connect to MySQL. Verify your connection string.');\n }\n }\n\n lines.push('');\n this.logger.error(lines.join('\\n'));\n }\n\n /**\n * Log a helpful error when the connectivity probe (SELECT 1) fails.\n */\n private logConnectivityError(error: unknown): void {\n const msg = error instanceof Error ? error.message : String(error);\n\n const lines: string[] = [\n '',\n '╔══════════════════════════════════════════════════════════════╗',\n '║ ⚠ INVECT — DATABASE CONNECTIVITY CHECK FAILED ⚠ ║',\n '╚══════════════════════════════════════════════════════════════╝',\n '',\n 'A connection was established but a simple SELECT query failed.',\n `Error: ${msg}`,\n '',\n 'This may indicate:',\n ' • The database server dropped the connection',\n ' • Insufficient permissions for the database user',\n ' • The database file is corrupted (SQLite)',\n '',\n ];\n\n this.logger.error(lines.join('\\n'));\n }\n\n /**\n * Redact credentials from a connection string for safe logging.\n */\n private redactConnectionString(connStr: string): string {\n // Hide passwords in postgres/mysql URLs: postgres://user:PASS@host → postgres://user:***@host\n return connStr.replace(/:([^/:@]+)@/, ':***@');\n }\n}\n\n/**\n * Database Models Factory - Creates all model instances with shared connection and logger\n */\nclass Database {\n public readonly flows: FlowsModel;\n public readonly flowVersions: FlowVersionsModel;\n public readonly flowRuns: FlowRunsModel;\n public readonly executionTraces: NodeExecutionsModel;\n public readonly batchJobs: BatchJobsModel;\n public readonly agentToolExecutions: AgentToolExecutionsModel;\n public readonly flowTriggers: FlowTriggersModel;\n public readonly chatMessages: ChatMessagesModel;\n\n constructor(_connection: DatabaseConnection, logger: Logger, adapter: InvectAdapter) {\n this.flows = new FlowsModel(adapter, logger);\n this.flowVersions = new FlowVersionsModel(adapter, logger);\n this.flowRuns = new FlowRunsModel(adapter, logger);\n this.executionTraces = new NodeExecutionsModel(adapter, logger);\n this.batchJobs = new BatchJobsModel(adapter, logger);\n this.agentToolExecutions = new AgentToolExecutionsModel(adapter, logger);\n this.flowTriggers = new FlowTriggersModel(adapter, logger);\n this.chatMessages = new ChatMessagesModel(adapter, logger);\n }\n}\n"],"mappings":"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"}
@@ -519,7 +519,7 @@ interface InvectPlugin {
519
519
  * The Invect CLI generates the concrete Drizzle schema files
520
520
  * from core + plugin schemas combined.
521
521
  *
522
- * Run `npx invect generate` after adding/changing plugin schemas.
522
+ * Run `npx invect-cli generate` after adding/changing plugin schemas.
523
523
  */
524
524
  schema?: InvectPluginSchema;
525
525
  /**
@@ -519,7 +519,7 @@ interface InvectPlugin {
519
519
  * The Invect CLI generates the concrete Drizzle schema files
520
520
  * from core + plugin schemas combined.
521
521
  *
522
- * Run `npx invect generate` after adding/changing plugin schemas.
522
+ * Run `npx invect-cli generate` after adding/changing plugin schemas.
523
523
  */
524
524
  schema?: InvectPluginSchema;
525
525
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"invect-config.cjs","names":["z","ChatConfigSchema"],"sources":["../../../src/types/schemas-fresh/invect-config.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { ChatConfigSchema } from 'src/services/chat/chat-types';\n\nconst databaseConfigSchema = z.object({\n connectionString: z.string().min(1, 'Database URL is required'),\n type: z.enum(['postgresql', 'sqlite', 'mysql']),\n id: z.string(), // Optional ID for the database, useful for multi-database setups\n name: z.string().optional(), // Human readable name for the database\n});\n\nexport type InvectDatabaseConfig = z.infer<typeof databaseConfigSchema>;\n\n/**\n * Database configuration schema\n */\nexport const queryDatabasesConfigSchema = z\n .array(databaseConfigSchema)\n .optional()\n .default(() => []);\n\n/**\n * Execution configuration schema\n */\nexport const ExecutionConfigSchema = z.object({\n defaultTimeout: z.number().positive().default(60000),\n maxConcurrentExecutions: z.number().positive().default(10),\n enableTracing: z.boolean().default(true),\n /**\n * Maximum time (in ms) a flow run is allowed to stay in RUNNING state\n * before being considered stale and marked as FAILED.\n * @default 600_000 (10 minutes)\n */\n flowTimeoutMs: z.number().positive().default(600_000),\n /**\n * Interval (in ms) at which the heartbeat is updated during flow execution.\n * @default 30_000 (30 seconds)\n */\n heartbeatIntervalMs: z.number().positive().default(30_000),\n /**\n * Interval (in ms) at which the stale run detector polls for stuck runs.\n * @default 60_000 (60 seconds)\n */\n staleRunCheckIntervalMs: z.number().positive().default(60_000),\n});\n\n/**\n * Log level enum values\n */\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'silent']);\n\n/**\n * Logging configuration schema with support for scope-level overrides.\n *\n * Scopes allow independent log level control for different feature areas:\n * - execution: Flow execution orchestration\n * - validation: Flow validation\n * - batch: Batch processing (AI providers)\n * - database: Database operations\n * - node: Node execution\n * - graph: Graph operations (topological sort, etc.)\n * - credentials: Credential management\n * - ai: AI/LLM operations\n * - template: Template rendering\n * - renderer: React Flow rendering\n * - flows: Flow management (CRUD)\n * - versions: Flow version management\n * - http: HTTP/API layer\n *\n * @example\n * ```typescript\n * const config = {\n * logging: {\n * level: 'info', // Default level for all scopes\n * scopes: {\n * execution: 'debug', // Verbose execution logging\n * validation: 'warn', // Only validation warnings\n * batch: 'silent', // Disable batch logging\n * }\n * }\n * };\n * ```\n */\nexport const LoggingConfigSchema = z.object({\n /** Default log level for all scopes */\n level: LogLevelSchema.default('silent'),\n /** Per-scope log level overrides */\n scopes: z.record(z.string(), LogLevelSchema).optional(),\n});\n\n/**\n * Built-in Invect roles\n */\nexport const InvectRoleSchema = z.enum(['admin', 'editor', 'operator', 'viewer']);\n\n/**\n * Invect permissions\n */\nexport const InvectPermissionSchema = z.enum([\n // Flow permissions\n 'flow:create',\n 'flow:read',\n 'flow:update',\n 'flow:delete',\n 'flow:publish',\n // Flow version permissions\n 'flow-version:create',\n 'flow-version:read',\n // Execution permissions\n 'flow-run:create',\n 'flow-run:read',\n 'flow-run:cancel',\n // Credential permissions\n 'credential:create',\n 'credential:read',\n 'credential:update',\n 'credential:delete',\n // Agent/tool permissions\n 'agent-tool:read',\n 'agent-tool:configure',\n // Node testing\n 'node:test',\n // Admin wildcard\n 'admin:*',\n]);\n\n/**\n * Authentication/Authorization configuration schema.\n *\n * Invect uses a \"BYO Auth\" (Bring Your Own Authentication) pattern.\n * The host app handles authentication and provides user identity to Invect.\n * Invect handles authorization based on roles and permissions.\n *\n * @example\n * ```typescript\n * const config = {\n * auth: {\n * enabled: true,\n * resolveUser: async (req) => ({\n * id: req.user.id,\n * role: req.user.invectRole,\n * }),\n * roleMapper: {\n * 'super_admin': 'admin',\n * 'content_manager': 'editor',\n * },\n * }\n * };\n * ```\n */\nexport const InvectAuthConfigSchema = z.object({\n /**\n * Enable RBAC (Role-Based Access Control).\n * When false, all requests are allowed without authentication checks.\n * @default false\n */\n enabled: z.boolean().default(false),\n\n /**\n * Function to resolve user identity from incoming request.\n * This is provided at runtime, not validated by Zod.\n */\n resolveUser: z.any().optional(),\n\n /**\n * Map host app roles to Invect roles.\n */\n roleMapper: z.record(z.string(), z.string()).optional(),\n\n /**\n * Define custom roles with specific permissions.\n */\n customRoles: z.record(z.string(), z.array(InvectPermissionSchema)).optional(),\n\n /**\n * Custom authorization callback (provided at runtime).\n */\n customAuthorize: z.any().optional(),\n\n /**\n * Routes that don't require authentication.\n */\n publicRoutes: z.array(z.string()).optional(),\n\n /**\n * Default role for authenticated users without explicit role.\n */\n defaultRole: z.string().default('viewer'),\n\n /**\n * Behavior when auth fails.\n */\n onAuthFailure: z.enum(['throw', 'log', 'deny']).default('throw'),\n\n /**\n * Use the flow_access database table to manage flow-level permissions.\n * When enabled, Invect stores flow access records in its own database.\n * @default false\n */\n useFlowAccessTable: z.boolean().default(false),\n});\n\n/**\n * Core Invect configuration schema\n */\nexport const InvectConfigSchema = z.object({\n queryDatabases: queryDatabasesConfigSchema.optional(),\n baseDatabaseConfig: databaseConfigSchema,\n logging: LoggingConfigSchema.default(() => ({\n level: 'info' as const,\n })).optional(),\n logger: z.any().optional(),\n basePath: z.string().optional(),\n /**\n * Execution settings: flow timeout, heartbeat interval, stale run detection.\n */\n execution: ExecutionConfigSchema.optional(),\n /**\n * Authentication and authorization configuration.\n * When not provided, auth is disabled (all requests allowed).\n */\n auth: InvectAuthConfigSchema.optional(),\n /**\n * Trigger system configuration.\n * Controls webhook and cron scheduler behavior.\n */\n triggers: z\n .object({\n /**\n * The public-facing base URL where Invect routes are mounted.\n * Used to display the full webhook URL in the flow editor.\n * Example: \"https://api.myapp.com/invect\"\n */\n webhookBaseUrl: z.string().optional(),\n /**\n * Enable/disable the cron scheduler. When disabled, cron trigger nodes\n * can still be placed on flows but won't fire automatically.\n * @default true\n */\n cronEnabled: z.boolean().default(true),\n })\n .optional(),\n /**\n * Chat assistant configuration.\n * Controls the AI chat sidebar for flow building assistance.\n */\n chat: ChatConfigSchema.optional(),\n /**\n * Plugins extend Invect with additional capabilities:\n * actions, hooks, endpoints, database schema, and middleware.\n *\n * Plugins are plain objects satisfying the `InvectPlugin` interface.\n * They are initialized in array order during `Invect.initialize()`.\n *\n * Database schema changes from plugins require running `npx invect generate`\n * to regenerate the Drizzle schema files, then `npx invect migrate` to apply.\n *\n * @example\n * ```typescript\n * import { rbac } from '@invect/plugin-rbac';\n * import { auditLog } from '@invect/plugin-audit-log';\n *\n * const config = {\n * plugins: [\n * rbac({ resolveUser: (req) => req.user }),\n * auditLog({ destination: 'database' }),\n * ],\n * };\n * ```\n */\n plugins: z.array(z.any()).optional(),\n /**\n * Schema verification configuration.\n *\n * When enabled, Invect checks on startup that the database has all\n * required tables and columns. This does NOT run migrations — the\n * developer is responsible for applying schema changes via the CLI:\n *\n * npx invect generate # regenerate schema files\n * npx drizzle-kit push # apply via Drizzle\n * npx prisma db push # apply via Prisma\n *\n * @example\n * ```typescript\n * const config = {\n * schemaVerification: true, // warn on missing tables/columns\n * // or\n * schemaVerification: { strict: true }, // throw on missing tables/columns\n * };\n * ```\n */\n schemaVerification: z\n .union([\n z.boolean(),\n z.object({\n /** If true, throw an error when schema is invalid. If false, only log warnings. */\n strict: z.boolean().default(false),\n }),\n ])\n .optional(),\n /**\n * Default credentials to ensure on startup.\n *\n * Each entry is created if no credential with the same `name` already exists.\n * Useful for development environments where you want API keys and OAuth\n * tokens available immediately without running a separate seed script.\n *\n * @example\n * ```typescript\n * const config = {\n * defaultCredentials: [\n * {\n * name: 'Anthropic API Key',\n * type: 'http-api',\n * authType: 'bearer',\n * config: { token: process.env.SEED_ANTHROPIC_API_KEY! },\n * description: 'Seeded Anthropic credential',\n * },\n * ],\n * };\n * ```\n */\n defaultCredentials: z\n .array(\n z.object({\n name: z.string(),\n type: z.string(),\n authType: z.string(),\n config: z.record(z.string(), z.unknown()),\n description: z.string().optional(),\n isShared: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n }),\n )\n .optional(),\n});\n\n/**\n * Type inference from schemas\n */\nexport type QueryDatabasesConfig = z.infer<typeof queryDatabasesConfigSchema>;\nexport type ExecutionConfig = z.infer<typeof ExecutionConfigSchema>;\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\nexport type InvectAuthConfigZod = z.infer<typeof InvectAuthConfigSchema>;\nexport type InvectConfig = z.infer<typeof InvectConfigSchema>;\n\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"invect-config.cjs","names":["z","ChatConfigSchema"],"sources":["../../../src/types/schemas-fresh/invect-config.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { ChatConfigSchema } from 'src/services/chat/chat-types';\n\nconst databaseConfigSchema = z.object({\n connectionString: z.string().min(1, 'Database URL is required'),\n type: z.enum(['postgresql', 'sqlite', 'mysql']),\n id: z.string(), // Optional ID for the database, useful for multi-database setups\n name: z.string().optional(), // Human readable name for the database\n});\n\nexport type InvectDatabaseConfig = z.infer<typeof databaseConfigSchema>;\n\n/**\n * Database configuration schema\n */\nexport const queryDatabasesConfigSchema = z\n .array(databaseConfigSchema)\n .optional()\n .default(() => []);\n\n/**\n * Execution configuration schema\n */\nexport const ExecutionConfigSchema = z.object({\n defaultTimeout: z.number().positive().default(60000),\n maxConcurrentExecutions: z.number().positive().default(10),\n enableTracing: z.boolean().default(true),\n /**\n * Maximum time (in ms) a flow run is allowed to stay in RUNNING state\n * before being considered stale and marked as FAILED.\n * @default 600_000 (10 minutes)\n */\n flowTimeoutMs: z.number().positive().default(600_000),\n /**\n * Interval (in ms) at which the heartbeat is updated during flow execution.\n * @default 30_000 (30 seconds)\n */\n heartbeatIntervalMs: z.number().positive().default(30_000),\n /**\n * Interval (in ms) at which the stale run detector polls for stuck runs.\n * @default 60_000 (60 seconds)\n */\n staleRunCheckIntervalMs: z.number().positive().default(60_000),\n});\n\n/**\n * Log level enum values\n */\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'silent']);\n\n/**\n * Logging configuration schema with support for scope-level overrides.\n *\n * Scopes allow independent log level control for different feature areas:\n * - execution: Flow execution orchestration\n * - validation: Flow validation\n * - batch: Batch processing (AI providers)\n * - database: Database operations\n * - node: Node execution\n * - graph: Graph operations (topological sort, etc.)\n * - credentials: Credential management\n * - ai: AI/LLM operations\n * - template: Template rendering\n * - renderer: React Flow rendering\n * - flows: Flow management (CRUD)\n * - versions: Flow version management\n * - http: HTTP/API layer\n *\n * @example\n * ```typescript\n * const config = {\n * logging: {\n * level: 'info', // Default level for all scopes\n * scopes: {\n * execution: 'debug', // Verbose execution logging\n * validation: 'warn', // Only validation warnings\n * batch: 'silent', // Disable batch logging\n * }\n * }\n * };\n * ```\n */\nexport const LoggingConfigSchema = z.object({\n /** Default log level for all scopes */\n level: LogLevelSchema.default('silent'),\n /** Per-scope log level overrides */\n scopes: z.record(z.string(), LogLevelSchema).optional(),\n});\n\n/**\n * Built-in Invect roles\n */\nexport const InvectRoleSchema = z.enum(['admin', 'editor', 'operator', 'viewer']);\n\n/**\n * Invect permissions\n */\nexport const InvectPermissionSchema = z.enum([\n // Flow permissions\n 'flow:create',\n 'flow:read',\n 'flow:update',\n 'flow:delete',\n 'flow:publish',\n // Flow version permissions\n 'flow-version:create',\n 'flow-version:read',\n // Execution permissions\n 'flow-run:create',\n 'flow-run:read',\n 'flow-run:cancel',\n // Credential permissions\n 'credential:create',\n 'credential:read',\n 'credential:update',\n 'credential:delete',\n // Agent/tool permissions\n 'agent-tool:read',\n 'agent-tool:configure',\n // Node testing\n 'node:test',\n // Admin wildcard\n 'admin:*',\n]);\n\n/**\n * Authentication/Authorization configuration schema.\n *\n * Invect uses a \"BYO Auth\" (Bring Your Own Authentication) pattern.\n * The host app handles authentication and provides user identity to Invect.\n * Invect handles authorization based on roles and permissions.\n *\n * @example\n * ```typescript\n * const config = {\n * auth: {\n * enabled: true,\n * resolveUser: async (req) => ({\n * id: req.user.id,\n * role: req.user.invectRole,\n * }),\n * roleMapper: {\n * 'super_admin': 'admin',\n * 'content_manager': 'editor',\n * },\n * }\n * };\n * ```\n */\nexport const InvectAuthConfigSchema = z.object({\n /**\n * Enable RBAC (Role-Based Access Control).\n * When false, all requests are allowed without authentication checks.\n * @default false\n */\n enabled: z.boolean().default(false),\n\n /**\n * Function to resolve user identity from incoming request.\n * This is provided at runtime, not validated by Zod.\n */\n resolveUser: z.any().optional(),\n\n /**\n * Map host app roles to Invect roles.\n */\n roleMapper: z.record(z.string(), z.string()).optional(),\n\n /**\n * Define custom roles with specific permissions.\n */\n customRoles: z.record(z.string(), z.array(InvectPermissionSchema)).optional(),\n\n /**\n * Custom authorization callback (provided at runtime).\n */\n customAuthorize: z.any().optional(),\n\n /**\n * Routes that don't require authentication.\n */\n publicRoutes: z.array(z.string()).optional(),\n\n /**\n * Default role for authenticated users without explicit role.\n */\n defaultRole: z.string().default('viewer'),\n\n /**\n * Behavior when auth fails.\n */\n onAuthFailure: z.enum(['throw', 'log', 'deny']).default('throw'),\n\n /**\n * Use the flow_access database table to manage flow-level permissions.\n * When enabled, Invect stores flow access records in its own database.\n * @default false\n */\n useFlowAccessTable: z.boolean().default(false),\n});\n\n/**\n * Core Invect configuration schema\n */\nexport const InvectConfigSchema = z.object({\n queryDatabases: queryDatabasesConfigSchema.optional(),\n baseDatabaseConfig: databaseConfigSchema,\n logging: LoggingConfigSchema.default(() => ({\n level: 'info' as const,\n })).optional(),\n logger: z.any().optional(),\n basePath: z.string().optional(),\n /**\n * Execution settings: flow timeout, heartbeat interval, stale run detection.\n */\n execution: ExecutionConfigSchema.optional(),\n /**\n * Authentication and authorization configuration.\n * When not provided, auth is disabled (all requests allowed).\n */\n auth: InvectAuthConfigSchema.optional(),\n /**\n * Trigger system configuration.\n * Controls webhook and cron scheduler behavior.\n */\n triggers: z\n .object({\n /**\n * The public-facing base URL where Invect routes are mounted.\n * Used to display the full webhook URL in the flow editor.\n * Example: \"https://api.myapp.com/invect\"\n */\n webhookBaseUrl: z.string().optional(),\n /**\n * Enable/disable the cron scheduler. When disabled, cron trigger nodes\n * can still be placed on flows but won't fire automatically.\n * @default true\n */\n cronEnabled: z.boolean().default(true),\n })\n .optional(),\n /**\n * Chat assistant configuration.\n * Controls the AI chat sidebar for flow building assistance.\n */\n chat: ChatConfigSchema.optional(),\n /**\n * Plugins extend Invect with additional capabilities:\n * actions, hooks, endpoints, database schema, and middleware.\n *\n * Plugins are plain objects satisfying the `InvectPlugin` interface.\n * They are initialized in array order during `Invect.initialize()`.\n *\n * Database schema changes from plugins require running `npx invect-cli generate`\n * to regenerate the Drizzle schema files, then `npx invect-cli migrate` to apply.\n *\n * @example\n * ```typescript\n * import { rbac } from '@invect/plugin-rbac';\n * import { auditLog } from '@invect/plugin-audit-log';\n *\n * const config = {\n * plugins: [\n * rbac({ resolveUser: (req) => req.user }),\n * auditLog({ destination: 'database' }),\n * ],\n * };\n * ```\n */\n plugins: z.array(z.any()).optional(),\n /**\n * Schema verification configuration.\n *\n * When enabled, Invect checks on startup that the database has all\n * required tables and columns. This does NOT run migrations — the\n * developer is responsible for applying schema changes via the CLI:\n *\n * npx invect-cli generate # regenerate schema files\n * npx drizzle-kit push # apply via Drizzle\n * npx prisma db push # apply via Prisma\n *\n * @example\n * ```typescript\n * const config = {\n * schemaVerification: true, // warn on missing tables/columns\n * // or\n * schemaVerification: { strict: true }, // throw on missing tables/columns\n * };\n * ```\n */\n schemaVerification: z\n .union([\n z.boolean(),\n z.object({\n /** If true, throw an error when schema is invalid. If false, only log warnings. */\n strict: z.boolean().default(false),\n }),\n ])\n .optional(),\n /**\n * Default credentials to ensure on startup.\n *\n * Each entry is created if no credential with the same `name` already exists.\n * Useful for development environments where you want API keys and OAuth\n * tokens available immediately without running a separate seed script.\n *\n * @example\n * ```typescript\n * const config = {\n * defaultCredentials: [\n * {\n * name: 'Anthropic API Key',\n * type: 'http-api',\n * authType: 'bearer',\n * config: { token: process.env.SEED_ANTHROPIC_API_KEY! },\n * description: 'Seeded Anthropic credential',\n * },\n * ],\n * };\n * ```\n */\n defaultCredentials: z\n .array(\n z.object({\n name: z.string(),\n type: z.string(),\n authType: z.string(),\n config: z.record(z.string(), z.unknown()),\n description: z.string().optional(),\n isShared: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n }),\n )\n .optional(),\n});\n\n/**\n * Type inference from schemas\n */\nexport type QueryDatabasesConfig = z.infer<typeof queryDatabasesConfigSchema>;\nexport type ExecutionConfig = z.infer<typeof ExecutionConfigSchema>;\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\nexport type InvectAuthConfigZod = z.infer<typeof InvectAuthConfigSchema>;\nexport type InvectConfig = z.infer<typeof InvectConfigSchema>;\n\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"invect-config.js","names":[],"sources":["../../../src/types/schemas-fresh/invect-config.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { ChatConfigSchema } from 'src/services/chat/chat-types';\n\nconst databaseConfigSchema = z.object({\n connectionString: z.string().min(1, 'Database URL is required'),\n type: z.enum(['postgresql', 'sqlite', 'mysql']),\n id: z.string(), // Optional ID for the database, useful for multi-database setups\n name: z.string().optional(), // Human readable name for the database\n});\n\nexport type InvectDatabaseConfig = z.infer<typeof databaseConfigSchema>;\n\n/**\n * Database configuration schema\n */\nexport const queryDatabasesConfigSchema = z\n .array(databaseConfigSchema)\n .optional()\n .default(() => []);\n\n/**\n * Execution configuration schema\n */\nexport const ExecutionConfigSchema = z.object({\n defaultTimeout: z.number().positive().default(60000),\n maxConcurrentExecutions: z.number().positive().default(10),\n enableTracing: z.boolean().default(true),\n /**\n * Maximum time (in ms) a flow run is allowed to stay in RUNNING state\n * before being considered stale and marked as FAILED.\n * @default 600_000 (10 minutes)\n */\n flowTimeoutMs: z.number().positive().default(600_000),\n /**\n * Interval (in ms) at which the heartbeat is updated during flow execution.\n * @default 30_000 (30 seconds)\n */\n heartbeatIntervalMs: z.number().positive().default(30_000),\n /**\n * Interval (in ms) at which the stale run detector polls for stuck runs.\n * @default 60_000 (60 seconds)\n */\n staleRunCheckIntervalMs: z.number().positive().default(60_000),\n});\n\n/**\n * Log level enum values\n */\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'silent']);\n\n/**\n * Logging configuration schema with support for scope-level overrides.\n *\n * Scopes allow independent log level control for different feature areas:\n * - execution: Flow execution orchestration\n * - validation: Flow validation\n * - batch: Batch processing (AI providers)\n * - database: Database operations\n * - node: Node execution\n * - graph: Graph operations (topological sort, etc.)\n * - credentials: Credential management\n * - ai: AI/LLM operations\n * - template: Template rendering\n * - renderer: React Flow rendering\n * - flows: Flow management (CRUD)\n * - versions: Flow version management\n * - http: HTTP/API layer\n *\n * @example\n * ```typescript\n * const config = {\n * logging: {\n * level: 'info', // Default level for all scopes\n * scopes: {\n * execution: 'debug', // Verbose execution logging\n * validation: 'warn', // Only validation warnings\n * batch: 'silent', // Disable batch logging\n * }\n * }\n * };\n * ```\n */\nexport const LoggingConfigSchema = z.object({\n /** Default log level for all scopes */\n level: LogLevelSchema.default('silent'),\n /** Per-scope log level overrides */\n scopes: z.record(z.string(), LogLevelSchema).optional(),\n});\n\n/**\n * Built-in Invect roles\n */\nexport const InvectRoleSchema = z.enum(['admin', 'editor', 'operator', 'viewer']);\n\n/**\n * Invect permissions\n */\nexport const InvectPermissionSchema = z.enum([\n // Flow permissions\n 'flow:create',\n 'flow:read',\n 'flow:update',\n 'flow:delete',\n 'flow:publish',\n // Flow version permissions\n 'flow-version:create',\n 'flow-version:read',\n // Execution permissions\n 'flow-run:create',\n 'flow-run:read',\n 'flow-run:cancel',\n // Credential permissions\n 'credential:create',\n 'credential:read',\n 'credential:update',\n 'credential:delete',\n // Agent/tool permissions\n 'agent-tool:read',\n 'agent-tool:configure',\n // Node testing\n 'node:test',\n // Admin wildcard\n 'admin:*',\n]);\n\n/**\n * Authentication/Authorization configuration schema.\n *\n * Invect uses a \"BYO Auth\" (Bring Your Own Authentication) pattern.\n * The host app handles authentication and provides user identity to Invect.\n * Invect handles authorization based on roles and permissions.\n *\n * @example\n * ```typescript\n * const config = {\n * auth: {\n * enabled: true,\n * resolveUser: async (req) => ({\n * id: req.user.id,\n * role: req.user.invectRole,\n * }),\n * roleMapper: {\n * 'super_admin': 'admin',\n * 'content_manager': 'editor',\n * },\n * }\n * };\n * ```\n */\nexport const InvectAuthConfigSchema = z.object({\n /**\n * Enable RBAC (Role-Based Access Control).\n * When false, all requests are allowed without authentication checks.\n * @default false\n */\n enabled: z.boolean().default(false),\n\n /**\n * Function to resolve user identity from incoming request.\n * This is provided at runtime, not validated by Zod.\n */\n resolveUser: z.any().optional(),\n\n /**\n * Map host app roles to Invect roles.\n */\n roleMapper: z.record(z.string(), z.string()).optional(),\n\n /**\n * Define custom roles with specific permissions.\n */\n customRoles: z.record(z.string(), z.array(InvectPermissionSchema)).optional(),\n\n /**\n * Custom authorization callback (provided at runtime).\n */\n customAuthorize: z.any().optional(),\n\n /**\n * Routes that don't require authentication.\n */\n publicRoutes: z.array(z.string()).optional(),\n\n /**\n * Default role for authenticated users without explicit role.\n */\n defaultRole: z.string().default('viewer'),\n\n /**\n * Behavior when auth fails.\n */\n onAuthFailure: z.enum(['throw', 'log', 'deny']).default('throw'),\n\n /**\n * Use the flow_access database table to manage flow-level permissions.\n * When enabled, Invect stores flow access records in its own database.\n * @default false\n */\n useFlowAccessTable: z.boolean().default(false),\n});\n\n/**\n * Core Invect configuration schema\n */\nexport const InvectConfigSchema = z.object({\n queryDatabases: queryDatabasesConfigSchema.optional(),\n baseDatabaseConfig: databaseConfigSchema,\n logging: LoggingConfigSchema.default(() => ({\n level: 'info' as const,\n })).optional(),\n logger: z.any().optional(),\n basePath: z.string().optional(),\n /**\n * Execution settings: flow timeout, heartbeat interval, stale run detection.\n */\n execution: ExecutionConfigSchema.optional(),\n /**\n * Authentication and authorization configuration.\n * When not provided, auth is disabled (all requests allowed).\n */\n auth: InvectAuthConfigSchema.optional(),\n /**\n * Trigger system configuration.\n * Controls webhook and cron scheduler behavior.\n */\n triggers: z\n .object({\n /**\n * The public-facing base URL where Invect routes are mounted.\n * Used to display the full webhook URL in the flow editor.\n * Example: \"https://api.myapp.com/invect\"\n */\n webhookBaseUrl: z.string().optional(),\n /**\n * Enable/disable the cron scheduler. When disabled, cron trigger nodes\n * can still be placed on flows but won't fire automatically.\n * @default true\n */\n cronEnabled: z.boolean().default(true),\n })\n .optional(),\n /**\n * Chat assistant configuration.\n * Controls the AI chat sidebar for flow building assistance.\n */\n chat: ChatConfigSchema.optional(),\n /**\n * Plugins extend Invect with additional capabilities:\n * actions, hooks, endpoints, database schema, and middleware.\n *\n * Plugins are plain objects satisfying the `InvectPlugin` interface.\n * They are initialized in array order during `Invect.initialize()`.\n *\n * Database schema changes from plugins require running `npx invect generate`\n * to regenerate the Drizzle schema files, then `npx invect migrate` to apply.\n *\n * @example\n * ```typescript\n * import { rbac } from '@invect/plugin-rbac';\n * import { auditLog } from '@invect/plugin-audit-log';\n *\n * const config = {\n * plugins: [\n * rbac({ resolveUser: (req) => req.user }),\n * auditLog({ destination: 'database' }),\n * ],\n * };\n * ```\n */\n plugins: z.array(z.any()).optional(),\n /**\n * Schema verification configuration.\n *\n * When enabled, Invect checks on startup that the database has all\n * required tables and columns. This does NOT run migrations — the\n * developer is responsible for applying schema changes via the CLI:\n *\n * npx invect generate # regenerate schema files\n * npx drizzle-kit push # apply via Drizzle\n * npx prisma db push # apply via Prisma\n *\n * @example\n * ```typescript\n * const config = {\n * schemaVerification: true, // warn on missing tables/columns\n * // or\n * schemaVerification: { strict: true }, // throw on missing tables/columns\n * };\n * ```\n */\n schemaVerification: z\n .union([\n z.boolean(),\n z.object({\n /** If true, throw an error when schema is invalid. If false, only log warnings. */\n strict: z.boolean().default(false),\n }),\n ])\n .optional(),\n /**\n * Default credentials to ensure on startup.\n *\n * Each entry is created if no credential with the same `name` already exists.\n * Useful for development environments where you want API keys and OAuth\n * tokens available immediately without running a separate seed script.\n *\n * @example\n * ```typescript\n * const config = {\n * defaultCredentials: [\n * {\n * name: 'Anthropic API Key',\n * type: 'http-api',\n * authType: 'bearer',\n * config: { token: process.env.SEED_ANTHROPIC_API_KEY! },\n * description: 'Seeded Anthropic credential',\n * },\n * ],\n * };\n * ```\n */\n defaultCredentials: z\n .array(\n z.object({\n name: z.string(),\n type: z.string(),\n authType: z.string(),\n config: z.record(z.string(), z.unknown()),\n description: z.string().optional(),\n isShared: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n }),\n )\n .optional(),\n});\n\n/**\n * Type inference from schemas\n */\nexport type QueryDatabasesConfig = z.infer<typeof queryDatabasesConfigSchema>;\nexport type ExecutionConfig = z.infer<typeof ExecutionConfigSchema>;\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\nexport type InvectAuthConfigZod = z.infer<typeof InvectAuthConfigSchema>;\nexport type InvectConfig = z.infer<typeof InvectConfigSchema>;\n\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"invect-config.js","names":[],"sources":["../../../src/types/schemas-fresh/invect-config.ts"],"sourcesContent":["import { z } from 'zod/v4';\nimport { ChatConfigSchema } from 'src/services/chat/chat-types';\n\nconst databaseConfigSchema = z.object({\n connectionString: z.string().min(1, 'Database URL is required'),\n type: z.enum(['postgresql', 'sqlite', 'mysql']),\n id: z.string(), // Optional ID for the database, useful for multi-database setups\n name: z.string().optional(), // Human readable name for the database\n});\n\nexport type InvectDatabaseConfig = z.infer<typeof databaseConfigSchema>;\n\n/**\n * Database configuration schema\n */\nexport const queryDatabasesConfigSchema = z\n .array(databaseConfigSchema)\n .optional()\n .default(() => []);\n\n/**\n * Execution configuration schema\n */\nexport const ExecutionConfigSchema = z.object({\n defaultTimeout: z.number().positive().default(60000),\n maxConcurrentExecutions: z.number().positive().default(10),\n enableTracing: z.boolean().default(true),\n /**\n * Maximum time (in ms) a flow run is allowed to stay in RUNNING state\n * before being considered stale and marked as FAILED.\n * @default 600_000 (10 minutes)\n */\n flowTimeoutMs: z.number().positive().default(600_000),\n /**\n * Interval (in ms) at which the heartbeat is updated during flow execution.\n * @default 30_000 (30 seconds)\n */\n heartbeatIntervalMs: z.number().positive().default(30_000),\n /**\n * Interval (in ms) at which the stale run detector polls for stuck runs.\n * @default 60_000 (60 seconds)\n */\n staleRunCheckIntervalMs: z.number().positive().default(60_000),\n});\n\n/**\n * Log level enum values\n */\nexport const LogLevelSchema = z.enum(['debug', 'info', 'warn', 'error', 'silent']);\n\n/**\n * Logging configuration schema with support for scope-level overrides.\n *\n * Scopes allow independent log level control for different feature areas:\n * - execution: Flow execution orchestration\n * - validation: Flow validation\n * - batch: Batch processing (AI providers)\n * - database: Database operations\n * - node: Node execution\n * - graph: Graph operations (topological sort, etc.)\n * - credentials: Credential management\n * - ai: AI/LLM operations\n * - template: Template rendering\n * - renderer: React Flow rendering\n * - flows: Flow management (CRUD)\n * - versions: Flow version management\n * - http: HTTP/API layer\n *\n * @example\n * ```typescript\n * const config = {\n * logging: {\n * level: 'info', // Default level for all scopes\n * scopes: {\n * execution: 'debug', // Verbose execution logging\n * validation: 'warn', // Only validation warnings\n * batch: 'silent', // Disable batch logging\n * }\n * }\n * };\n * ```\n */\nexport const LoggingConfigSchema = z.object({\n /** Default log level for all scopes */\n level: LogLevelSchema.default('silent'),\n /** Per-scope log level overrides */\n scopes: z.record(z.string(), LogLevelSchema).optional(),\n});\n\n/**\n * Built-in Invect roles\n */\nexport const InvectRoleSchema = z.enum(['admin', 'editor', 'operator', 'viewer']);\n\n/**\n * Invect permissions\n */\nexport const InvectPermissionSchema = z.enum([\n // Flow permissions\n 'flow:create',\n 'flow:read',\n 'flow:update',\n 'flow:delete',\n 'flow:publish',\n // Flow version permissions\n 'flow-version:create',\n 'flow-version:read',\n // Execution permissions\n 'flow-run:create',\n 'flow-run:read',\n 'flow-run:cancel',\n // Credential permissions\n 'credential:create',\n 'credential:read',\n 'credential:update',\n 'credential:delete',\n // Agent/tool permissions\n 'agent-tool:read',\n 'agent-tool:configure',\n // Node testing\n 'node:test',\n // Admin wildcard\n 'admin:*',\n]);\n\n/**\n * Authentication/Authorization configuration schema.\n *\n * Invect uses a \"BYO Auth\" (Bring Your Own Authentication) pattern.\n * The host app handles authentication and provides user identity to Invect.\n * Invect handles authorization based on roles and permissions.\n *\n * @example\n * ```typescript\n * const config = {\n * auth: {\n * enabled: true,\n * resolveUser: async (req) => ({\n * id: req.user.id,\n * role: req.user.invectRole,\n * }),\n * roleMapper: {\n * 'super_admin': 'admin',\n * 'content_manager': 'editor',\n * },\n * }\n * };\n * ```\n */\nexport const InvectAuthConfigSchema = z.object({\n /**\n * Enable RBAC (Role-Based Access Control).\n * When false, all requests are allowed without authentication checks.\n * @default false\n */\n enabled: z.boolean().default(false),\n\n /**\n * Function to resolve user identity from incoming request.\n * This is provided at runtime, not validated by Zod.\n */\n resolveUser: z.any().optional(),\n\n /**\n * Map host app roles to Invect roles.\n */\n roleMapper: z.record(z.string(), z.string()).optional(),\n\n /**\n * Define custom roles with specific permissions.\n */\n customRoles: z.record(z.string(), z.array(InvectPermissionSchema)).optional(),\n\n /**\n * Custom authorization callback (provided at runtime).\n */\n customAuthorize: z.any().optional(),\n\n /**\n * Routes that don't require authentication.\n */\n publicRoutes: z.array(z.string()).optional(),\n\n /**\n * Default role for authenticated users without explicit role.\n */\n defaultRole: z.string().default('viewer'),\n\n /**\n * Behavior when auth fails.\n */\n onAuthFailure: z.enum(['throw', 'log', 'deny']).default('throw'),\n\n /**\n * Use the flow_access database table to manage flow-level permissions.\n * When enabled, Invect stores flow access records in its own database.\n * @default false\n */\n useFlowAccessTable: z.boolean().default(false),\n});\n\n/**\n * Core Invect configuration schema\n */\nexport const InvectConfigSchema = z.object({\n queryDatabases: queryDatabasesConfigSchema.optional(),\n baseDatabaseConfig: databaseConfigSchema,\n logging: LoggingConfigSchema.default(() => ({\n level: 'info' as const,\n })).optional(),\n logger: z.any().optional(),\n basePath: z.string().optional(),\n /**\n * Execution settings: flow timeout, heartbeat interval, stale run detection.\n */\n execution: ExecutionConfigSchema.optional(),\n /**\n * Authentication and authorization configuration.\n * When not provided, auth is disabled (all requests allowed).\n */\n auth: InvectAuthConfigSchema.optional(),\n /**\n * Trigger system configuration.\n * Controls webhook and cron scheduler behavior.\n */\n triggers: z\n .object({\n /**\n * The public-facing base URL where Invect routes are mounted.\n * Used to display the full webhook URL in the flow editor.\n * Example: \"https://api.myapp.com/invect\"\n */\n webhookBaseUrl: z.string().optional(),\n /**\n * Enable/disable the cron scheduler. When disabled, cron trigger nodes\n * can still be placed on flows but won't fire automatically.\n * @default true\n */\n cronEnabled: z.boolean().default(true),\n })\n .optional(),\n /**\n * Chat assistant configuration.\n * Controls the AI chat sidebar for flow building assistance.\n */\n chat: ChatConfigSchema.optional(),\n /**\n * Plugins extend Invect with additional capabilities:\n * actions, hooks, endpoints, database schema, and middleware.\n *\n * Plugins are plain objects satisfying the `InvectPlugin` interface.\n * They are initialized in array order during `Invect.initialize()`.\n *\n * Database schema changes from plugins require running `npx invect-cli generate`\n * to regenerate the Drizzle schema files, then `npx invect-cli migrate` to apply.\n *\n * @example\n * ```typescript\n * import { rbac } from '@invect/plugin-rbac';\n * import { auditLog } from '@invect/plugin-audit-log';\n *\n * const config = {\n * plugins: [\n * rbac({ resolveUser: (req) => req.user }),\n * auditLog({ destination: 'database' }),\n * ],\n * };\n * ```\n */\n plugins: z.array(z.any()).optional(),\n /**\n * Schema verification configuration.\n *\n * When enabled, Invect checks on startup that the database has all\n * required tables and columns. This does NOT run migrations — the\n * developer is responsible for applying schema changes via the CLI:\n *\n * npx invect-cli generate # regenerate schema files\n * npx drizzle-kit push # apply via Drizzle\n * npx prisma db push # apply via Prisma\n *\n * @example\n * ```typescript\n * const config = {\n * schemaVerification: true, // warn on missing tables/columns\n * // or\n * schemaVerification: { strict: true }, // throw on missing tables/columns\n * };\n * ```\n */\n schemaVerification: z\n .union([\n z.boolean(),\n z.object({\n /** If true, throw an error when schema is invalid. If false, only log warnings. */\n strict: z.boolean().default(false),\n }),\n ])\n .optional(),\n /**\n * Default credentials to ensure on startup.\n *\n * Each entry is created if no credential with the same `name` already exists.\n * Useful for development environments where you want API keys and OAuth\n * tokens available immediately without running a separate seed script.\n *\n * @example\n * ```typescript\n * const config = {\n * defaultCredentials: [\n * {\n * name: 'Anthropic API Key',\n * type: 'http-api',\n * authType: 'bearer',\n * config: { token: process.env.SEED_ANTHROPIC_API_KEY! },\n * description: 'Seeded Anthropic credential',\n * },\n * ],\n * };\n * ```\n */\n defaultCredentials: z\n .array(\n z.object({\n name: z.string(),\n type: z.string(),\n authType: z.string(),\n config: z.record(z.string(), z.unknown()),\n description: z.string().optional(),\n isShared: z.boolean().optional(),\n metadata: z.record(z.string(), z.unknown()).optional(),\n }),\n )\n .optional(),\n});\n\n/**\n * Type inference from schemas\n */\nexport type QueryDatabasesConfig = z.infer<typeof queryDatabasesConfigSchema>;\nexport type ExecutionConfig = z.infer<typeof ExecutionConfigSchema>;\nexport type LoggingConfig = z.infer<typeof LoggingConfigSchema>;\nexport type InvectAuthConfigZod = z.infer<typeof InvectAuthConfigSchema>;\nexport type InvectConfig = z.infer<typeof InvectConfigSchema>;\n\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invect/core",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "description": "Framework-agnostic core package for Invect workflow execution engine",
6
6
  "main": "dist/index.cjs",
@@ -33,30 +33,8 @@
33
33
  "require": "./dist/database/schema-mysql.cjs"
34
34
  }
35
35
  },
36
- "scripts": {
37
- "build": "tsdown",
38
- "prepublishOnly": "pnpm run build",
39
- "build:watch": "tsdown --watch",
40
- "dev": "tsdown --watch",
41
- "clean": "rm -rf dist",
42
- "format": "prettier --write \"src/**/*.ts\"",
43
- "typecheck": "tsc --noEmit",
44
- "lint": "eslint src tests e2e",
45
- "lint:fix": "eslint src tests --fix",
46
- "test": "vitest run",
47
- "test:watch": "vitest",
48
- "test:coverage": "vitest run --coverage",
49
- "test:unit": "vitest run tests/unit",
50
- "test:integration": "vitest run tests/integration",
51
- "test:e2e": "tsx e2e/run.ts",
52
- "test:run-all": "tsx tests/run-tests.ts",
53
- "db:generate": "drizzle-kit generate",
54
- "db:migrate": "drizzle-kit migrate",
55
- "db:studio": "drizzle-kit studio"
56
- },
57
36
  "dependencies": {
58
37
  "@anthropic-ai/sdk": "^0.57.0",
59
- "@invect/layouts": "workspace:*",
60
38
  "better-sqlite3": "^12.0.0",
61
39
  "croner": "^10.0.1",
62
40
  "drizzle-orm": "^0.44.7",
@@ -67,7 +45,8 @@
67
45
  "openai": "^5.11.0",
68
46
  "postgres": "^3.4.7",
69
47
  "quickjs-emscripten": "^0.32.0",
70
- "zod": "^3.25.1"
48
+ "zod": "^3.25.1",
49
+ "@invect/layouts": "0.1.0"
71
50
  },
72
51
  "devDependencies": {
73
52
  "@eslint/js": "^9.31.0",
@@ -118,5 +97,25 @@
118
97
  "core",
119
98
  "framework-agnostic"
120
99
  ],
121
- "license": "MIT"
122
- }
100
+ "license": "MIT",
101
+ "scripts": {
102
+ "build": "tsdown",
103
+ "build:watch": "tsdown --watch",
104
+ "dev": "tsdown --watch",
105
+ "clean": "rm -rf dist",
106
+ "format": "prettier --write \"src/**/*.ts\"",
107
+ "typecheck": "tsc --noEmit",
108
+ "lint": "eslint src tests e2e",
109
+ "lint:fix": "eslint src tests --fix",
110
+ "test": "vitest run",
111
+ "test:watch": "vitest",
112
+ "test:coverage": "vitest run --coverage",
113
+ "test:unit": "vitest run tests/unit",
114
+ "test:integration": "vitest run tests/integration",
115
+ "test:e2e": "tsx e2e/run.ts",
116
+ "test:run-all": "tsx tests/run-tests.ts",
117
+ "db:generate": "drizzle-kit generate",
118
+ "db:migrate": "drizzle-kit migrate",
119
+ "db:studio": "drizzle-kit studio"
120
+ }
121
+ }