@nmakarov/cli-toolkit 0.21.0 → 0.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/args.cjs +1 -4
- package/dist/args.cjs.map +1 -1
- package/dist/args.js +1 -1
- package/dist/args.js.map +1 -1
- package/dist/cli-runner.cjs +1370 -623
- package/dist/cli-runner.cjs.map +1 -1
- package/dist/cli-runner.js +1415 -667
- package/dist/cli-runner.js.map +1 -1
- package/dist/db.cjs +173 -158
- package/dist/db.cjs.map +1 -1
- package/dist/db.js +172 -151
- package/dist/db.js.map +1 -1
- package/dist/errors.cjs +2 -2
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.js +2 -1
- package/dist/errors.js.map +1 -1
- package/dist/filedatabase.cjs +19 -19
- package/dist/filedatabase.cjs.map +1 -1
- package/dist/filedatabase.js +19 -16
- package/dist/filedatabase.js.map +1 -1
- package/dist/http-client.cjs +9 -11
- package/dist/http-client.cjs.map +1 -1
- package/dist/http-client.js +10 -9
- package/dist/http-client.js.map +1 -1
- package/dist/http-client2.cjs +34 -37
- package/dist/http-client2.cjs.map +1 -1
- package/dist/http-client2.js +34 -34
- package/dist/http-client2.js.map +1 -1
- package/dist/index.cjs +1831 -713
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1837 -713
- package/dist/index.js.map +1 -1
- package/dist/init.cjs +93 -68
- package/dist/init.cjs.map +1 -1
- package/dist/init.js +108 -82
- package/dist/init.js.map +1 -1
- package/dist/logger.cjs +5 -5
- package/dist/logger.cjs.map +1 -1
- package/dist/logger.js +5 -4
- package/dist/logger.js.map +1 -1
- package/dist/mock-server.cjs +21 -33
- package/dist/mock-server.cjs.map +1 -1
- package/dist/mock-server.js +21 -28
- package/dist/mock-server.js.map +1 -1
- package/dist/params.cjs +18 -9
- package/dist/params.cjs.map +1 -1
- package/dist/params.js +18 -6
- package/dist/params.js.map +1 -1
- package/dist/s3.cjs +286 -0
- package/dist/s3.cjs.map +1 -0
- package/dist/s3.js +273 -0
- package/dist/s3.js.map +1 -0
- package/dist/screen.cjs +34 -39
- package/dist/screen.cjs.map +1 -1
- package/dist/screen.js +48 -46
- package/dist/screen.js.map +1 -1
- package/dist/tasks.cjs +1354 -501
- package/dist/tasks.cjs.map +1 -1
- package/dist/tasks.js +1369 -527
- package/dist/tasks.js.map +1 -1
- package/dist/utils.cjs +7 -8
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.js +6 -6
- package/dist/utils.js.map +1 -1
- package/package.json +32 -47
- package/scripts/ssm/{parse-cli.ts → parse-cli.js} +4 -4
- package/scripts/ssm/{ssm-admin.ts → ssm-admin.js} +12 -12
- package/scripts/ssm/{ssm-pull.ts → ssm-pull.js} +10 -13
package/dist/db.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/db.ts","../src/db/index.ts","../src/errors.ts"],"sourcesContent":["// Re-export Db module\nexport * from \"./db/index.js\";\n\n","/**\n * Database Client - Low-level SQL database operations\n *\n * Wraps Knex.js with connection management, profiling, and utility functions.\n * The instance can be used directly like a Knex instance: db('table').select()\n */\n\nimport knex, { Knex } from 'knex';\nimport { ParamError } from '../errors.js';\nimport type { Context } from '../init/types.js';\nimport type { DbConfig, DbOptions, DatabaseClient, QueryLogEntry, DbInstance } from './types.js';\n\n/**\n * Database client wrapper around Knex\n * \n * Usage:\n * ```typescript\n * const db = new Db({\n * connectionString: 'postgresql://user:pass@host:5432/dbname',\n * testConnection: true,\n * profile: false\n * });\n * await db.connect();\n * \n * // Use like Knex:\n * const users = await db('users').select('*');\n * await db('posts').insert({ title: 'Hello' });\n * ```\n */\nexport class Db {\n private knexInstance: Knex | null = null;\n private config: Required<DbConfig>;\n private logger: any;\n private queriesLog: QueryLogEntry[] = [];\n private isConnected: boolean = false;\n\n /**\n * Constructor - accepts config object\n * Use dbInit() function to initialize with Context\n */\n constructor(config: DbConfig) {\n if (!config.connectionString) {\n throw new ParamError('Db: connectionString is required');\n }\n\n this.config = {\n testConnection: true,\n profile: false,\n pool: { min: 2, max: 10 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n logger: console,\n name: 'default',\n ...config,\n };\n\n this.logger = this.config.logger;\n\n // Create a callable function wrapper that forwards to the instance\n // This allows db('table') to work like Knex\n const instance = this;\n const callableWrapper = function(...args: any[]) {\n // This function body is never executed - the Proxy apply trap handles calls\n // But we need a function to make the Proxy apply trap work\n throw new Error('This should never be called directly');\n };\n \n // Store instance reference on the wrapper for Proxy access\n (callableWrapper as any)._instance = instance;\n\n // Create a Proxy that makes the wrapper callable and forwards property access\n return new Proxy(callableWrapper, {\n // Intercept function calls: db('table')\n apply: (target, thisArg, argumentsList) => {\n const inst = (target as any)._instance;\n if (!inst.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n // Forward the call to the Knex instance (Knex instances are callable)\n return (inst.knexInstance as any)(...argumentsList);\n },\n // Intercept property access: db.schema, db.raw, etc.\n get: (target, prop) => {\n // Allow access to _instance for internal use\n if (prop === '_instance') {\n return (target as any)._instance;\n }\n \n const instance = (target as any)._instance;\n \n // List of our own methods that should NOT be forwarded to Knex\n const ownMethods = [\n 'connect',\n 'disconnect',\n 'testConnection',\n 'tableExists',\n 'getQueryLog',\n 'getKnex',\n 'isConnectedToDb',\n 'getErrorMessage',\n 'detectClient',\n 'attachProfiler',\n ];\n \n // Always return our own methods first (before checking Knex)\n if (prop in instance) {\n const value = (instance as any)[prop];\n // If it's one of our own methods, return it bound to instance\n if (typeof value === 'function' && ownMethods.includes(prop as string)) {\n return value.bind(instance);\n }\n // If it's a non-function property, return it\n if (typeof value !== 'function') {\n return value;\n }\n }\n \n // If we have a Knex instance, forward to it for everything else\n if (instance.knexInstance) {\n const knexProp = (instance.knexInstance as any)[prop];\n if (typeof knexProp === 'function') {\n // Bind methods to the Knex instance\n return knexProp.bind(instance.knexInstance);\n }\n return knexProp;\n }\n \n // Return our own methods that aren't in the ownMethods list (shouldn't happen, but fallback)\n if (prop in instance) {\n const method = (instance as any)[prop];\n if (typeof method === 'function') {\n return method.bind(instance);\n }\n return method;\n }\n \n // Property doesn't exist\n return undefined;\n },\n }) as any;\n }\n\n /**\n * Detect database client type from connection string\n */\n private detectClient(connectionString: string): DatabaseClient | null {\n if (connectionString.match(/^postgresql/)) {\n return 'pg';\n }\n if (connectionString.match(/^mysql/)) {\n return 'mysql2';\n }\n return null;\n }\n\n /**\n * Connect to the database\n */\n async connect(): Promise<void> {\n if (this.isConnected && this.knexInstance) {\n this.logger.warn?.('[Db] Already connected');\n return;\n }\n\n const client = this.detectClient(this.config.connectionString);\n if (!client) {\n throw new ParamError(\n `Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://`\n );\n }\n\n try {\n // Force IPv4 only (disable IPv6) by setting family: 4 in connection config\n // Knex accepts connection as string or object; we wrap string to add family option\n const connectionConfig = {\n connectionString: this.config.connectionString,\n family: 4, // Force IPv4 only (disable IPv6)\n };\n\n this.knexInstance = knex({\n client,\n connection: connectionConfig,\n pool: this.config.pool,\n acquireConnectionTimeout: this.config.acquireConnectionTimeout,\n ...(this.config.ssl && { ssl: this.config.ssl }),\n } as any);\n\n // Attach profiler if enabled\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n // Test connection if requested\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n this.isConnected = true;\n this.logger.debug?.(`[Db] Connected to database \"${this.config.name || this.config.connectionString}\"`);\n } catch (error: any) {\n // If testConnection already threw a ParamError, preserve its message\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = this.getErrorMessage(error);\n throw new ParamError(`Db: Connection failed - ${errorMsg}`);\n }\n }\n\n /**\n * Disconnect from the database\n */\n async disconnect(): Promise<void> {\n if (!this.knexInstance) {\n return;\n }\n\n try {\n await this.knexInstance.destroy();\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this.logger.debug?.(`[Db] Disconnected from database \"${this.config.name || this.config.connectionString}\"`);\n } catch (error: any) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);\n throw error;\n }\n }\n\n /**\n * Extract error message from various error types\n */\n private getErrorMessage(error: any): string {\n // Handle AggregateError (can contain multiple errors)\n if (error instanceof AggregateError) {\n const errors = error.errors || [];\n \n // If all errors are the same type (e.g., ECONNREFUSED for different IPs), show a consolidated message\n if (errors.length > 0) {\n const firstError = errors[0];\n const firstErrorMsg = firstError instanceof Error ? firstError.message : String(firstError);\n \n // Check if all errors are similar (same error code/type, different addresses)\n const allSimilar = errors.every((e: any) => {\n const msg = e instanceof Error ? e.message : String(e);\n // Extract error code (e.g., \"ECONNREFUSED\") from message\n const codeMatch = msg.match(/^(\\w+)\\s/);\n const firstCodeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n return codeMatch && firstCodeMatch && codeMatch[1] === firstCodeMatch[1];\n });\n \n if (allSimilar && errors.length > 1) {\n // Extract addresses/IPs from error messages\n const addresses = errors.map((e: any) => {\n const msg = e instanceof Error ? e.message : String(e);\n // Try to extract address (e.g., \"::1:5432\" or \"127.0.0.1:5432\")\n const addrMatch = msg.match(/([:\\d.]+:\\d+)/);\n return addrMatch ? addrMatch[1] : null;\n }).filter(Boolean);\n \n if (addresses.length > 0) {\n // Show consolidated message with all addresses\n const codeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n const code = codeMatch ? codeMatch[1] : 'Connection error';\n return `${code} (tried: ${addresses.join(', ')})`;\n }\n }\n \n // Fallback: show all errors but deduplicate identical messages\n const uniqueMessages = [...new Set(errors.map((e: any) => {\n return e instanceof Error ? e.message : String(e);\n }))];\n \n if (uniqueMessages.length === 1) {\n return uniqueMessages[0];\n }\n \n return uniqueMessages.join('; ');\n }\n \n return error.message || 'Multiple errors occurred';\n }\n \n // Handle standard Error objects\n if (error instanceof Error) {\n // Check for common database error properties (code is often present on Node.js errors)\n const errorWithCode = error as Error & { code?: string };\n if (errorWithCode.code) {\n return `${errorWithCode.code}: ${error.message || String(error)}`;\n }\n return error.message || String(error);\n }\n \n // Handle string errors\n if (typeof error === 'string') {\n return error;\n }\n \n // Handle objects with message property\n if (error?.message) {\n const msg = String(error.message);\n const errorWithCode = error as { code?: string };\n if (errorWithCode.code) {\n return `${errorWithCode.code}: ${msg}`;\n }\n return msg;\n }\n \n // Fallback: try to stringify the error\n return String(error) || 'Unknown error';\n }\n\n /**\n * Test database connection\n */\n async testConnection(): Promise<boolean> {\n if (!this.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n\n try {\n const result = await this.knexInstance.raw('SELECT 2+3 AS result');\n const isOk = result.rows?.[0]?.result === 5 || result[0]?.[0]?.result === 5;\n this.logger.debug?.(`[Db] Connection test: ${isOk ? 'OK' : 'FAILED'}`);\n return isOk;\n } catch (error: any) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Connection test failed: ${errorMsg}`);\n throw new ParamError(`Db: Connection test failed - ${errorMsg}`);\n }\n }\n\n /**\n * Attach query profiler to log all queries\n */\n attachProfiler(): void {\n if (!this.knexInstance) {\n return;\n }\n\n this.queriesLog = [];\n (this.knexInstance as any).queriesLog = this.queriesLog;\n\n this.knexInstance.on('query', (query: any) => {\n query.__startTime = process.hrtime();\n });\n\n this.knexInstance.on('query-response', (response: any, query: any) => {\n const [seconds, nanoseconds] = process.hrtime(query.__startTime);\n const executionTimeMs = ((seconds * 1000) + (nanoseconds / 1e6)).toFixed(2);\n\n const logEntry: QueryLogEntry = {\n sql: query.sql,\n bindings: query.bindings || [],\n executionTimeMs,\n };\n\n this.queriesLog.push(logEntry);\n this.logger.debug?.(`[Db] Query: ${query.sql} | Duration: ${executionTimeMs}ms`);\n });\n\n this.knexInstance.on('query-error', (error: Error, query: any) => {\n this.logger.error?.(`[Db] Query failed: ${query.sql}`, error);\n });\n }\n\n /**\n * Get query log (only available if profiling is enabled)\n */\n getQueryLog(): QueryLogEntry[] {\n return [...this.queriesLog];\n }\n\n /**\n * Check if a table exists\n */\n async tableExists(tableName: string): Promise<boolean> {\n if (!this.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n\n try {\n return await this.knexInstance.schema.hasTable(tableName);\n } catch (error: any) {\n this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);\n throw error;\n }\n }\n\n /**\n * Get the underlying Knex instance (for advanced usage)\n */\n getKnex(): Knex {\n if (!this.knexInstance) {\n throw new Error('Db: Not connected. Call connect() first.');\n }\n return this.knexInstance;\n }\n\n /**\n * Get connection status\n */\n isConnectedToDb(): boolean {\n return this.isConnected && this.knexInstance !== null;\n }\n\n /**\n * Initialize Db with context (connects and registers disconnect cleanup).\n * Params are read via getAllForModule(\"db\", defs). Same as dbInit(context, dbNameOrConnectionString).\n */\n static async init(context: Context, dbNameOrConnectionString?: string): Promise<Db> {\n return dbFindAndConnect(context, dbNameOrConnectionString);\n }\n}\n\n/**\n * Helper function to capitalize first letter of a string\n */\nfunction capitalizeFirstLetter(str: string): string {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\n/**\n * Connect to database - creates Db instance, connects, registers cleanup, attaches profiler\n * \n * This is a dedicated connect function that handles:\n * - Creating Db instance with proper configuration\n * - Connecting to database\n * - Registering cleanup function\n * - Attaching profiler if needed\n * - Better error handling\n */\nexport async function dbConnect(\n context: Context,\n connectionString: string,\n name?: string,\n dbProfile?: boolean\n): Promise<Db> {\n // Get configuration from params\n const defs = {\n testDbConnection: 'boolean default true',\n name: 'string',\n poolMin: 'number default 2',\n poolMax: 'number default 10',\n acquireConnectionTimeout: 'number default 10000',\n sslRejectUnauthorized: 'boolean default false',\n };\n \n const paramsConfig = context.params.getAllForModule(defs);\n\n // Create config\n const config: DbConfig = {\n connectionString,\n name: paramsConfig.name || name || 'default',\n testConnection: paramsConfig.testDbConnection,\n profile: dbProfile ?? false,\n pool: {\n min: paramsConfig.poolMin,\n max: paramsConfig.poolMax,\n },\n acquireConnectionTimeout: paramsConfig.acquireConnectionTimeout,\n ssl: {\n rejectUnauthorized: paramsConfig.sslRejectUnauthorized,\n },\n logger: context.logger,\n };\n \n try {\n // Create Db instance\n const db = new Db(config);\n \n // Register cleanup function\n context.registerCleanup(async () => {\n await db.disconnect();\n context.logger.debug(`[Db] instance \"${name || connectionString}\" destroyed`);\n });\n \n // Connect to database (profiler is attached automatically if config.profile is true)\n await db.connect();\n \n context.logger.debug(`[Db] instance \"${name || connectionString}\" initialized`);\n \n return db;\n } catch (error: any) {\n // Better error handling\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new ParamError(`[Db] connect error: ${errorMsg}`);\n }\n}\n\n/**\n * Find and connect to database - resolves database name or connection string\n * \n * This function handles:\n * - Direct connection string (postgresql://... or mysql://...)\n * - Database name/label that gets resolved to dbConnectionString${CapitalizedName}\n * - Reading from params if no second parameter provided\n */\nexport async function dbFindAndConnect(\n context: Context,\n dbNameOrConnectionString?: string\n): Promise<Db> {\n let dbName: string | undefined;\n let dbConnectionString: string | undefined;\n let dbProfile: boolean | undefined;\n \n // If second parameter is provided\n if (dbNameOrConnectionString) {\n // Check if it looks like a connection string (postgresql:// or mysql://)\n if (dbNameOrConnectionString.match(/^(postgresql|mysql):\\/\\/[^\\s]+:[^\\s]+@[^\\s]+:\\d+\\/[^\\s]+$/)) {\n dbName = undefined;\n dbConnectionString = dbNameOrConnectionString;\n } else {\n // Treat it as a database name/label\n dbName = dbNameOrConnectionString;\n }\n } else {\n // No second parameter - read from params\n const defs = {\n dbName: 'string',\n dbConnectionString: 'string',\n dbProfile: 'boolean default false',\n };\n \n const paramsConfig = context.params.getAll(defs);\n dbName = paramsConfig.dbName;\n dbConnectionString = paramsConfig.dbConnectionString;\n dbProfile = paramsConfig.dbProfile;\n }\n \n // Validate that we have either dbName or dbConnectionString\n if (!dbName && !dbConnectionString) {\n throw new ParamError('Db: either dbName or dbConnectionString must be specified');\n }\n \n // If dbName is provided, resolve it to connection string\n if (dbName) {\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, 'string');\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n \n // Connect using dedicated connect function\n // context.logger.notice(`[Db] connecting to database \"${dbConnectionString}\"`);\n // TODO: figure out the output of \"--showUsedParams\" in the case of the DB - stuff gets to \"script\" section that doesn't belong there.\n const db = await dbConnect(context, dbConnectionString!, dbName, dbProfile);\n \n // Test connection (connect() already tests if testConnection is true, but we can test explicitly here too)\n // The test is already done in db.connect() if config.testConnection is true\n \n return db;\n}\n\n/**\n * Initialize Db instance with context (auto-connects)\n * \n * This is the standard \"init\" function that auto-initializes the DB component.\n * It calls dbFindAndConnect, optionally passing a second parameter.\n * \n * Usage:\n * ```typescript\n * // Auto-initialize from params:\n * const db = await dbInit(context);\n * \n * // Or with database name/label:\n * const db = await dbInit(context, 'local');\n * \n * // Or with direct connection string:\n * const db = await dbInit(context, 'postgresql://user:pass@host:5432/dbname');\n * ```\n */\nexport async function dbInit(\n context: Context,\n dbNameOrConnectionString?: string\n): Promise<Db> {\n return await dbFindAndConnect(context, dbNameOrConnectionString);\n}\n\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message: string) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n"],"mappings":"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","names":["instance","knex"]}
|
|
1
|
+
{"version":3,"sources":["../src/db/index.js","../src/errors.js"],"sourcesContent":["import knex from \"knex\";\nimport { ParamError } from \"../errors.js\";\n\nconst KNEX_DEFAULTS = {\n testConnection: true,\n pool: { min: 2, max: 10 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n};\n\nexport class Db {\n static async init(context, options = {}) {\n const buildConfig = async () => {\n const defs = {\n dbName: \"string\",\n dbProfile: \"boolean default false\",\n };\n const discovered = context?.params?.getAllForModule?.(\"db\", defs) ?? {};\n const merged = { ...discovered, ...options };\n\n let { dbName, dbProfile } = merged;\n let dbConnectionString = options.dbConnectionString ?? options.connectionString;\n let connectionParam = dbConnectionString ? \"options\" : null;\n\n if (!dbConnectionString) {\n const src = context?.args?.getSource?.(\"dbConnectionString\");\n if (src === \"cli\" || src === \"overrides\" || src === \"config\") {\n dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n connectionParam = \"dbConnectionString\";\n }\n }\n\n if (!dbConnectionString && dbName && /^(postgresql|mysql):\\/\\//.test(dbName)) {\n dbConnectionString = dbName;\n dbName = undefined;\n }\n\n if (!dbConnectionString && dbName) {\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, \"string\");\n connectionParam = paramName;\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n\n if (!dbConnectionString) {\n dbConnectionString = await context.params.get(\"dbConnectionString\", \"string\");\n if (dbConnectionString) {\n connectionParam = \"dbConnectionString\";\n }\n }\n\n if (!dbConnectionString) {\n if (!dbName) {\n dbName = \"local\";\n }\n const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;\n dbConnectionString = await context.params.get(paramName, \"string\");\n connectionParam = paramName;\n if (!dbConnectionString) {\n throw new ParamError(\n `Db: cannot find dbConnectionString for dbName=\"${dbName}\" (looked for param \"${paramName}\")`\n );\n }\n }\n\n const displayName = resolveDbDisplayName(\n dbName,\n connectionParam,\n context?.args?.env,\n merged.name\n );\n\n return {\n ...KNEX_DEFAULTS,\n connectionString: dbConnectionString,\n name: displayName,\n profile: !!dbProfile,\n logger: context.logger,\n };\n };\n\n const config = context?.params?.runWithModuleAsync\n ? await context.params.runWithModuleAsync(\"db\", buildConfig)\n : await buildConfig();\n\n return dbConnect(context, config);\n }\n\n constructor(config) {\n if (!config || !config.connectionString) {\n throw new ParamError(\"Db: connectionString is required\");\n }\n\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n\n this.config = {\n testConnection: true,\n profile: false,\n pool: { min: 2, max: 10 },\n acquireConnectionTimeout: 10000,\n ssl: { rejectUnauthorized: false },\n logger: console,\n ...config,\n };\n\n this.logger = this.config.logger;\n\n const instance = this;\n const callableWrapper = function () {\n throw new Error(\"This should never be called directly\");\n };\n callableWrapper._instance = instance;\n\n return new Proxy(callableWrapper, {\n apply: (target, _thisArg, argumentsList) => {\n const inst = target._instance;\n if (!inst.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return inst.knexInstance(...argumentsList);\n },\n get: (target, prop) => {\n if (prop === \"_instance\") {\n return target._instance;\n }\n\n const inst = target._instance;\n\n const ownMethods = [\n \"connect\",\n \"disconnect\",\n \"testConnection\",\n \"tableExists\",\n \"getQueryLog\",\n \"getKnex\",\n \"isConnectedToDb\",\n \"getErrorMessage\",\n \"detectClient\",\n \"attachProfiler\",\n ];\n\n if (prop in inst) {\n const value = inst[prop];\n if (typeof value === \"function\" && ownMethods.includes(prop)) {\n return value.bind(inst);\n }\n if (typeof value !== \"function\") {\n return value;\n }\n }\n\n if (inst.knexInstance) {\n const knexProp = inst.knexInstance[prop];\n if (typeof knexProp === \"function\") {\n return knexProp.bind(inst.knexInstance);\n }\n return knexProp;\n }\n\n if (prop in inst) {\n const method = inst[prop];\n if (typeof method === \"function\") {\n return method.bind(inst);\n }\n return method;\n }\n\n return undefined;\n },\n });\n }\n\n detectClient(connectionString) {\n if (connectionString.match(/^postgresql/)) {\n return \"pg\";\n }\n if (connectionString.match(/^mysql/)) {\n return \"mysql2\";\n }\n return null;\n }\n\n async connect() {\n if (this.isConnected && this.knexInstance) {\n this.logger.warn?.(\"[Db] Already connected\");\n return;\n }\n\n const client = this.detectClient(this.config.connectionString);\n if (!client) {\n throw new ParamError(\n \"Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://\"\n );\n }\n\n try {\n const connectionConfig = {\n connectionString: this.config.connectionString,\n family: 4,\n };\n\n this.knexInstance = knex({\n client,\n connection: connectionConfig,\n pool: this.config.pool,\n acquireConnectionTimeout: this.config.acquireConnectionTimeout,\n ...(this.config.ssl && { ssl: this.config.ssl }),\n });\n\n if (this.config.profile) {\n this.attachProfiler();\n }\n\n if (this.config.testConnection) {\n await this.testConnection();\n }\n\n this.isConnected = true;\n this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = this.getErrorMessage(error);\n throw new ParamError(`Db: Connection failed - ${errorMsg}`);\n }\n }\n\n async disconnect() {\n if (!this.knexInstance) {\n return;\n }\n\n try {\n await this.knexInstance.destroy();\n this.knexInstance = null;\n this.isConnected = false;\n this.queriesLog = [];\n this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);\n throw error;\n }\n }\n\n getErrorMessage(error) {\n if (error instanceof AggregateError) {\n const errors = error.errors || [];\n\n if (errors.length > 0) {\n const firstError = errors[0];\n const firstErrorMsg =\n firstError instanceof Error ? firstError.message : String(firstError);\n\n const allSimilar = errors.every((e) => {\n const msg = e instanceof Error ? e.message : String(e);\n const codeMatch = msg.match(/^(\\w+)\\s/);\n const firstCodeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n return codeMatch && firstCodeMatch && codeMatch[1] === firstCodeMatch[1];\n });\n\n if (allSimilar && errors.length > 1) {\n const addresses = errors\n .map((e) => {\n const msg = e instanceof Error ? e.message : String(e);\n const addrMatch = msg.match(/([:\\d.]+:\\d+)/);\n return addrMatch ? addrMatch[1] : null;\n })\n .filter(Boolean);\n\n if (addresses.length > 0) {\n const codeMatch = firstErrorMsg.match(/^(\\w+)\\s/);\n const code = codeMatch ? codeMatch[1] : \"Connection error\";\n return `${code} (tried: ${addresses.join(\", \")})`;\n }\n }\n\n const uniqueMessages = [\n ...new Set(\n errors.map((e) => (e instanceof Error ? e.message : String(e)))\n ),\n ];\n\n if (uniqueMessages.length === 1) {\n return uniqueMessages[0];\n }\n\n return uniqueMessages.join(\"; \");\n }\n\n return error.message || \"Multiple errors occurred\";\n }\n\n if (error instanceof Error) {\n const code = error.code;\n if (code) {\n return `${code}: ${error.message || String(error)}`;\n }\n return error.message || String(error);\n }\n\n if (typeof error === \"string\") {\n return error;\n }\n\n if (error && typeof error === \"object\" && \"message\" in error) {\n const msg = String(error.message);\n const code = error.code;\n if (code) {\n return `${code}: ${msg}`;\n }\n return msg;\n }\n\n return String(error) || \"Unknown error\";\n }\n\n async testConnection() {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n\n try {\n const result = await this.knexInstance.raw(\"SELECT 2+3 AS result\");\n const isOk = result.rows?.[0]?.result === 5 || result[0]?.[0]?.result === 5;\n this.logger.debug?.(`[Db] Connection test: ${isOk ? \"OK\" : \"FAILED\"}`);\n return isOk;\n } catch (error) {\n const errorMsg = this.getErrorMessage(error);\n this.logger.error?.(`[Db] Connection test failed: ${errorMsg}`);\n throw new ParamError(`Db: Connection test failed - ${errorMsg}`);\n }\n }\n\n attachProfiler() {\n if (!this.knexInstance) {\n return;\n }\n\n this.queriesLog = [];\n this.knexInstance.queriesLog = this.queriesLog;\n\n this.knexInstance.on(\"query\", (query) => {\n query.__startTime = process.hrtime();\n });\n\n this.knexInstance.on(\"query-response\", (_response, query) => {\n const [seconds, nanoseconds] = process.hrtime(query.__startTime);\n const executionTimeMs = (seconds * 1000 + nanoseconds / 1e6).toFixed(2);\n\n const logEntry = {\n sql: query.sql,\n bindings: query.bindings || [],\n executionTimeMs,\n };\n\n this.queriesLog.push(logEntry);\n this.logger.debug?.(`[Db] Query: ${query.sql} | Duration: ${executionTimeMs}ms`);\n });\n\n this.knexInstance.on(\"query-error\", (error, query) => {\n this.logger.error?.(`[Db] Query failed: ${query.sql}`, error);\n });\n }\n\n getQueryLog() {\n return [...this.queriesLog];\n }\n\n async tableExists(tableName) {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n\n try {\n return await this.knexInstance.schema.hasTable(tableName);\n } catch (error) {\n this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);\n throw error;\n }\n }\n\n getKnex() {\n if (!this.knexInstance) {\n throw new Error(\"Db: Not connected. Call connect() first.\");\n }\n return this.knexInstance;\n }\n\n isConnectedToDb() {\n return this.isConnected && this.knexInstance !== null;\n }\n}\n\nfunction capitalizeFirstLetter(str) {\n return str.charAt(0).toUpperCase() + str.slice(1);\n}\n\nfunction resolveDbDisplayName(dbName, connectionParam, argsEnv, mergedName) {\n if (dbName) {\n return dbName;\n }\n if (mergedName) {\n return mergedName;\n }\n if (\n connectionParam?.startsWith(\"dbConnectionString\") &&\n connectionParam.length > \"dbConnectionString\".length\n ) {\n return connectionParam.slice(\"dbConnectionString\".length).toLowerCase();\n }\n if (connectionParam === \"dbConnectionString\" && argsEnv) {\n return argsEnv;\n }\n return undefined;\n}\n\nfunction formatDbConnectMessage(name, connectionString) {\n const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n if (name) {\n return `[Db] Connected to database \"${name}\"${endpointSuffix}`;\n }\n return `[Db] Connected${endpointSuffix}`;\n}\n\nfunction formatDbDisconnectMessage(name, connectionString) {\n const endpointSuffix = formatConnectionEndpointSuffix(connectionString);\n if (name) {\n return `[Db] Disconnected from database \"${name}\"${endpointSuffix}`;\n }\n return `[Db] Disconnected${endpointSuffix}`;\n}\n\nfunction formatDbInstanceMessage(action, name) {\n if (name) {\n return `[Db] instance \"${name}\" ${action}`;\n }\n return `[Db] instance ${action}`;\n}\n\nfunction formatConnectionEndpointSuffix(connectionString) {\n const endpoint = formatConnectionEndpoint(connectionString);\n return endpoint ? ` (${endpoint})` : \"\";\n}\n\nfunction formatConnectionEndpoint(connectionString) {\n try {\n const url = new URL(connectionString);\n const host = url.hostname;\n if (!host) {\n return null;\n }\n\n let port = url.port;\n if (!port) {\n if (url.protocol === \"postgresql:\") {\n port = \"5432\";\n } else if (url.protocol === \"mysql:\") {\n port = \"3306\";\n }\n }\n\n return port ? `${host}:${port}` : host;\n } catch {\n return null;\n }\n}\n\nasync function dbConnect(context, config) {\n try {\n const db = new Db(config);\n\n context.registerCleanup(async () => {\n await db.disconnect();\n context.logger.debug?.(formatDbInstanceMessage(\"disconnected\", config.name));\n });\n\n await db.connect();\n\n context.logger.debug?.(formatDbInstanceMessage(\"initialized\", config.name));\n\n return db;\n } catch (error) {\n if (error instanceof ParamError) {\n throw error;\n }\n const errorMsg = error instanceof Error ? error.message : String(error);\n throw new ParamError(`[Db] connect error: ${errorMsg}`);\n }\n}\n","/**\n * Error classes for the CLI toolkit\n */\n\nexport class FrameworkError extends Error {\n constructor(message) {\n super(message);\n this.name = \"FrameworkError\";\n }\n}\n\nexport class ParamError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"ParamError\";\n }\n}\n\nexport class InitError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"InitError\";\n }\n}\n\nexport class CriticalRequestError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"CriticalRequestError\";\n }\n}\n\nexport class ControlFlowError extends Error {\n constructor(message) {\n super(message);\n this.name = \"ControlFlowError\";\n }\n}\n\nexport class HttpClientError extends FrameworkError {\n constructor(message, cause) {\n super(message);this.cause = cause;;\n this.name = \"HttpClientError\";\n }\n}\n\nexport class FileDatabaseError extends FrameworkError {\n constructor(message) {\n super(message);\n this.name = \"FileDatabaseError\";\n }\n}\n\n"],"mappings":"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","names":["knex"]}
|
package/dist/db.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
// src/db/index.
|
|
1
|
+
// src/db/index.js
|
|
2
2
|
import knex from "knex";
|
|
3
3
|
|
|
4
|
-
// src/errors.
|
|
4
|
+
// src/errors.js
|
|
5
5
|
var FrameworkError = class extends Error {
|
|
6
6
|
constructor(message) {
|
|
7
7
|
super(message);
|
|
@@ -15,21 +15,89 @@ var ParamError = class extends FrameworkError {
|
|
|
15
15
|
}
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
// src/db/index.
|
|
18
|
+
// src/db/index.js
|
|
19
|
+
var KNEX_DEFAULTS = {
|
|
20
|
+
testConnection: true,
|
|
21
|
+
pool: { min: 2, max: 10 },
|
|
22
|
+
acquireConnectionTimeout: 1e4,
|
|
23
|
+
ssl: { rejectUnauthorized: false }
|
|
24
|
+
};
|
|
19
25
|
var Db = class {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
static async init(context, options = {}) {
|
|
27
|
+
const buildConfig = async () => {
|
|
28
|
+
const defs = {
|
|
29
|
+
dbName: "string",
|
|
30
|
+
dbProfile: "boolean default false"
|
|
31
|
+
};
|
|
32
|
+
const discovered = context?.params?.getAllForModule?.("db", defs) ?? {};
|
|
33
|
+
const merged = { ...discovered, ...options };
|
|
34
|
+
let { dbName, dbProfile } = merged;
|
|
35
|
+
let dbConnectionString = options.dbConnectionString ?? options.connectionString;
|
|
36
|
+
let connectionParam = dbConnectionString ? "options" : null;
|
|
37
|
+
if (!dbConnectionString) {
|
|
38
|
+
const src = context?.args?.getSource?.("dbConnectionString");
|
|
39
|
+
if (src === "cli" || src === "overrides" || src === "config") {
|
|
40
|
+
dbConnectionString = await context.params.get("dbConnectionString", "string");
|
|
41
|
+
connectionParam = "dbConnectionString";
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
if (!dbConnectionString && dbName && /^(postgresql|mysql):\/\//.test(dbName)) {
|
|
45
|
+
dbConnectionString = dbName;
|
|
46
|
+
dbName = void 0;
|
|
47
|
+
}
|
|
48
|
+
if (!dbConnectionString && dbName) {
|
|
49
|
+
const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;
|
|
50
|
+
dbConnectionString = await context.params.get(paramName, "string");
|
|
51
|
+
connectionParam = paramName;
|
|
52
|
+
if (!dbConnectionString) {
|
|
53
|
+
throw new ParamError(
|
|
54
|
+
`Db: cannot find dbConnectionString for dbName="${dbName}" (looked for param "${paramName}")`
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
if (!dbConnectionString) {
|
|
59
|
+
dbConnectionString = await context.params.get("dbConnectionString", "string");
|
|
60
|
+
if (dbConnectionString) {
|
|
61
|
+
connectionParam = "dbConnectionString";
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (!dbConnectionString) {
|
|
65
|
+
if (!dbName) {
|
|
66
|
+
dbName = "local";
|
|
67
|
+
}
|
|
68
|
+
const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;
|
|
69
|
+
dbConnectionString = await context.params.get(paramName, "string");
|
|
70
|
+
connectionParam = paramName;
|
|
71
|
+
if (!dbConnectionString) {
|
|
72
|
+
throw new ParamError(
|
|
73
|
+
`Db: cannot find dbConnectionString for dbName="${dbName}" (looked for param "${paramName}")`
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
const displayName = resolveDbDisplayName(
|
|
78
|
+
dbName,
|
|
79
|
+
connectionParam,
|
|
80
|
+
context?.args?.env,
|
|
81
|
+
merged.name
|
|
82
|
+
);
|
|
83
|
+
return {
|
|
84
|
+
...KNEX_DEFAULTS,
|
|
85
|
+
connectionString: dbConnectionString,
|
|
86
|
+
name: displayName,
|
|
87
|
+
profile: !!dbProfile,
|
|
88
|
+
logger: context.logger
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
const config = context?.params?.runWithModuleAsync ? await context.params.runWithModuleAsync("db", buildConfig) : await buildConfig();
|
|
92
|
+
return dbConnect(context, config);
|
|
93
|
+
}
|
|
29
94
|
constructor(config) {
|
|
30
|
-
if (!config.connectionString) {
|
|
95
|
+
if (!config || !config.connectionString) {
|
|
31
96
|
throw new ParamError("Db: connectionString is required");
|
|
32
97
|
}
|
|
98
|
+
this.knexInstance = null;
|
|
99
|
+
this.isConnected = false;
|
|
100
|
+
this.queriesLog = [];
|
|
33
101
|
this.config = {
|
|
34
102
|
testConnection: true,
|
|
35
103
|
profile: false,
|
|
@@ -37,30 +105,27 @@ var Db = class {
|
|
|
37
105
|
acquireConnectionTimeout: 1e4,
|
|
38
106
|
ssl: { rejectUnauthorized: false },
|
|
39
107
|
logger: console,
|
|
40
|
-
name: "default",
|
|
41
108
|
...config
|
|
42
109
|
};
|
|
43
110
|
this.logger = this.config.logger;
|
|
44
111
|
const instance = this;
|
|
45
|
-
const callableWrapper = function(
|
|
112
|
+
const callableWrapper = function() {
|
|
46
113
|
throw new Error("This should never be called directly");
|
|
47
114
|
};
|
|
48
115
|
callableWrapper._instance = instance;
|
|
49
116
|
return new Proxy(callableWrapper, {
|
|
50
|
-
|
|
51
|
-
apply: (target, thisArg, argumentsList) => {
|
|
117
|
+
apply: (target, _thisArg, argumentsList) => {
|
|
52
118
|
const inst = target._instance;
|
|
53
119
|
if (!inst.knexInstance) {
|
|
54
120
|
throw new Error("Db: Not connected. Call connect() first.");
|
|
55
121
|
}
|
|
56
122
|
return inst.knexInstance(...argumentsList);
|
|
57
123
|
},
|
|
58
|
-
// Intercept property access: db.schema, db.raw, etc.
|
|
59
124
|
get: (target, prop) => {
|
|
60
125
|
if (prop === "_instance") {
|
|
61
126
|
return target._instance;
|
|
62
127
|
}
|
|
63
|
-
const
|
|
128
|
+
const inst = target._instance;
|
|
64
129
|
const ownMethods = [
|
|
65
130
|
"connect",
|
|
66
131
|
"disconnect",
|
|
@@ -73,26 +138,26 @@ var Db = class {
|
|
|
73
138
|
"detectClient",
|
|
74
139
|
"attachProfiler"
|
|
75
140
|
];
|
|
76
|
-
if (prop in
|
|
77
|
-
const value =
|
|
141
|
+
if (prop in inst) {
|
|
142
|
+
const value = inst[prop];
|
|
78
143
|
if (typeof value === "function" && ownMethods.includes(prop)) {
|
|
79
|
-
return value.bind(
|
|
144
|
+
return value.bind(inst);
|
|
80
145
|
}
|
|
81
146
|
if (typeof value !== "function") {
|
|
82
147
|
return value;
|
|
83
148
|
}
|
|
84
149
|
}
|
|
85
|
-
if (
|
|
86
|
-
const knexProp =
|
|
150
|
+
if (inst.knexInstance) {
|
|
151
|
+
const knexProp = inst.knexInstance[prop];
|
|
87
152
|
if (typeof knexProp === "function") {
|
|
88
|
-
return knexProp.bind(
|
|
153
|
+
return knexProp.bind(inst.knexInstance);
|
|
89
154
|
}
|
|
90
155
|
return knexProp;
|
|
91
156
|
}
|
|
92
|
-
if (prop in
|
|
93
|
-
const method =
|
|
157
|
+
if (prop in inst) {
|
|
158
|
+
const method = inst[prop];
|
|
94
159
|
if (typeof method === "function") {
|
|
95
|
-
return method.bind(
|
|
160
|
+
return method.bind(inst);
|
|
96
161
|
}
|
|
97
162
|
return method;
|
|
98
163
|
}
|
|
@@ -100,9 +165,6 @@ var Db = class {
|
|
|
100
165
|
}
|
|
101
166
|
});
|
|
102
167
|
}
|
|
103
|
-
/**
|
|
104
|
-
* Detect database client type from connection string
|
|
105
|
-
*/
|
|
106
168
|
detectClient(connectionString) {
|
|
107
169
|
if (connectionString.match(/^postgresql/)) {
|
|
108
170
|
return "pg";
|
|
@@ -112,9 +174,6 @@ var Db = class {
|
|
|
112
174
|
}
|
|
113
175
|
return null;
|
|
114
176
|
}
|
|
115
|
-
/**
|
|
116
|
-
* Connect to the database
|
|
117
|
-
*/
|
|
118
177
|
async connect() {
|
|
119
178
|
if (this.isConnected && this.knexInstance) {
|
|
120
179
|
this.logger.warn?.("[Db] Already connected");
|
|
@@ -123,14 +182,13 @@ var Db = class {
|
|
|
123
182
|
const client = this.detectClient(this.config.connectionString);
|
|
124
183
|
if (!client) {
|
|
125
184
|
throw new ParamError(
|
|
126
|
-
|
|
185
|
+
"Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://"
|
|
127
186
|
);
|
|
128
187
|
}
|
|
129
188
|
try {
|
|
130
189
|
const connectionConfig = {
|
|
131
190
|
connectionString: this.config.connectionString,
|
|
132
191
|
family: 4
|
|
133
|
-
// Force IPv4 only (disable IPv6)
|
|
134
192
|
};
|
|
135
193
|
this.knexInstance = knex({
|
|
136
194
|
client,
|
|
@@ -146,7 +204,7 @@ var Db = class {
|
|
|
146
204
|
await this.testConnection();
|
|
147
205
|
}
|
|
148
206
|
this.isConnected = true;
|
|
149
|
-
this.logger.debug?.(
|
|
207
|
+
this.logger.debug?.(formatDbConnectMessage(this.config.name, this.config.connectionString));
|
|
150
208
|
} catch (error) {
|
|
151
209
|
if (error instanceof ParamError) {
|
|
152
210
|
throw error;
|
|
@@ -155,9 +213,6 @@ var Db = class {
|
|
|
155
213
|
throw new ParamError(`Db: Connection failed - ${errorMsg}`);
|
|
156
214
|
}
|
|
157
215
|
}
|
|
158
|
-
/**
|
|
159
|
-
* Disconnect from the database
|
|
160
|
-
*/
|
|
161
216
|
async disconnect() {
|
|
162
217
|
if (!this.knexInstance) {
|
|
163
218
|
return;
|
|
@@ -167,16 +222,13 @@ var Db = class {
|
|
|
167
222
|
this.knexInstance = null;
|
|
168
223
|
this.isConnected = false;
|
|
169
224
|
this.queriesLog = [];
|
|
170
|
-
this.logger.debug?.(
|
|
225
|
+
this.logger.debug?.(formatDbDisconnectMessage(this.config.name, this.config.connectionString));
|
|
171
226
|
} catch (error) {
|
|
172
227
|
const errorMsg = this.getErrorMessage(error);
|
|
173
228
|
this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);
|
|
174
229
|
throw error;
|
|
175
230
|
}
|
|
176
231
|
}
|
|
177
|
-
/**
|
|
178
|
-
* Extract error message from various error types
|
|
179
|
-
*/
|
|
180
232
|
getErrorMessage(error) {
|
|
181
233
|
if (error instanceof AggregateError) {
|
|
182
234
|
const errors = error.errors || [];
|
|
@@ -201,9 +253,11 @@ var Db = class {
|
|
|
201
253
|
return `${code} (tried: ${addresses.join(", ")})`;
|
|
202
254
|
}
|
|
203
255
|
}
|
|
204
|
-
const uniqueMessages = [
|
|
205
|
-
|
|
206
|
-
|
|
256
|
+
const uniqueMessages = [
|
|
257
|
+
...new Set(
|
|
258
|
+
errors.map((e) => e instanceof Error ? e.message : String(e))
|
|
259
|
+
)
|
|
260
|
+
];
|
|
207
261
|
if (uniqueMessages.length === 1) {
|
|
208
262
|
return uniqueMessages[0];
|
|
209
263
|
}
|
|
@@ -212,28 +266,25 @@ var Db = class {
|
|
|
212
266
|
return error.message || "Multiple errors occurred";
|
|
213
267
|
}
|
|
214
268
|
if (error instanceof Error) {
|
|
215
|
-
const
|
|
216
|
-
if (
|
|
217
|
-
return `${
|
|
269
|
+
const code = error.code;
|
|
270
|
+
if (code) {
|
|
271
|
+
return `${code}: ${error.message || String(error)}`;
|
|
218
272
|
}
|
|
219
273
|
return error.message || String(error);
|
|
220
274
|
}
|
|
221
275
|
if (typeof error === "string") {
|
|
222
276
|
return error;
|
|
223
277
|
}
|
|
224
|
-
if (error
|
|
278
|
+
if (error && typeof error === "object" && "message" in error) {
|
|
225
279
|
const msg = String(error.message);
|
|
226
|
-
const
|
|
227
|
-
if (
|
|
228
|
-
return `${
|
|
280
|
+
const code = error.code;
|
|
281
|
+
if (code) {
|
|
282
|
+
return `${code}: ${msg}`;
|
|
229
283
|
}
|
|
230
284
|
return msg;
|
|
231
285
|
}
|
|
232
286
|
return String(error) || "Unknown error";
|
|
233
287
|
}
|
|
234
|
-
/**
|
|
235
|
-
* Test database connection
|
|
236
|
-
*/
|
|
237
288
|
async testConnection() {
|
|
238
289
|
if (!this.knexInstance) {
|
|
239
290
|
throw new Error("Db: Not connected. Call connect() first.");
|
|
@@ -249,9 +300,6 @@ var Db = class {
|
|
|
249
300
|
throw new ParamError(`Db: Connection test failed - ${errorMsg}`);
|
|
250
301
|
}
|
|
251
302
|
}
|
|
252
|
-
/**
|
|
253
|
-
* Attach query profiler to log all queries
|
|
254
|
-
*/
|
|
255
303
|
attachProfiler() {
|
|
256
304
|
if (!this.knexInstance) {
|
|
257
305
|
return;
|
|
@@ -261,7 +309,7 @@ var Db = class {
|
|
|
261
309
|
this.knexInstance.on("query", (query) => {
|
|
262
310
|
query.__startTime = process.hrtime();
|
|
263
311
|
});
|
|
264
|
-
this.knexInstance.on("query-response", (
|
|
312
|
+
this.knexInstance.on("query-response", (_response, query) => {
|
|
265
313
|
const [seconds, nanoseconds] = process.hrtime(query.__startTime);
|
|
266
314
|
const executionTimeMs = (seconds * 1e3 + nanoseconds / 1e6).toFixed(2);
|
|
267
315
|
const logEntry = {
|
|
@@ -276,15 +324,9 @@ var Db = class {
|
|
|
276
324
|
this.logger.error?.(`[Db] Query failed: ${query.sql}`, error);
|
|
277
325
|
});
|
|
278
326
|
}
|
|
279
|
-
/**
|
|
280
|
-
* Get query log (only available if profiling is enabled)
|
|
281
|
-
*/
|
|
282
327
|
getQueryLog() {
|
|
283
328
|
return [...this.queriesLog];
|
|
284
329
|
}
|
|
285
|
-
/**
|
|
286
|
-
* Check if a table exists
|
|
287
|
-
*/
|
|
288
330
|
async tableExists(tableName) {
|
|
289
331
|
if (!this.knexInstance) {
|
|
290
332
|
throw new Error("Db: Not connected. Call connect() first.");
|
|
@@ -296,65 +338,87 @@ var Db = class {
|
|
|
296
338
|
throw error;
|
|
297
339
|
}
|
|
298
340
|
}
|
|
299
|
-
/**
|
|
300
|
-
* Get the underlying Knex instance (for advanced usage)
|
|
301
|
-
*/
|
|
302
341
|
getKnex() {
|
|
303
342
|
if (!this.knexInstance) {
|
|
304
343
|
throw new Error("Db: Not connected. Call connect() first.");
|
|
305
344
|
}
|
|
306
345
|
return this.knexInstance;
|
|
307
346
|
}
|
|
308
|
-
/**
|
|
309
|
-
* Get connection status
|
|
310
|
-
*/
|
|
311
347
|
isConnectedToDb() {
|
|
312
348
|
return this.isConnected && this.knexInstance !== null;
|
|
313
349
|
}
|
|
314
|
-
/**
|
|
315
|
-
* Initialize Db with context (connects and registers disconnect cleanup).
|
|
316
|
-
* Params are read via getAllForModule("db", defs). Same as dbInit(context, dbNameOrConnectionString).
|
|
317
|
-
*/
|
|
318
|
-
static async init(context, dbNameOrConnectionString) {
|
|
319
|
-
return dbFindAndConnect(context, dbNameOrConnectionString);
|
|
320
|
-
}
|
|
321
350
|
};
|
|
322
351
|
function capitalizeFirstLetter(str) {
|
|
323
352
|
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
324
353
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
354
|
+
function resolveDbDisplayName(dbName, connectionParam, argsEnv, mergedName) {
|
|
355
|
+
if (dbName) {
|
|
356
|
+
return dbName;
|
|
357
|
+
}
|
|
358
|
+
if (mergedName) {
|
|
359
|
+
return mergedName;
|
|
360
|
+
}
|
|
361
|
+
if (connectionParam?.startsWith("dbConnectionString") && connectionParam.length > "dbConnectionString".length) {
|
|
362
|
+
return connectionParam.slice("dbConnectionString".length).toLowerCase();
|
|
363
|
+
}
|
|
364
|
+
if (connectionParam === "dbConnectionString" && argsEnv) {
|
|
365
|
+
return argsEnv;
|
|
366
|
+
}
|
|
367
|
+
return void 0;
|
|
368
|
+
}
|
|
369
|
+
function formatDbConnectMessage(name, connectionString) {
|
|
370
|
+
const endpointSuffix = formatConnectionEndpointSuffix(connectionString);
|
|
371
|
+
if (name) {
|
|
372
|
+
return `[Db] Connected to database "${name}"${endpointSuffix}`;
|
|
373
|
+
}
|
|
374
|
+
return `[Db] Connected${endpointSuffix}`;
|
|
375
|
+
}
|
|
376
|
+
function formatDbDisconnectMessage(name, connectionString) {
|
|
377
|
+
const endpointSuffix = formatConnectionEndpointSuffix(connectionString);
|
|
378
|
+
if (name) {
|
|
379
|
+
return `[Db] Disconnected from database "${name}"${endpointSuffix}`;
|
|
380
|
+
}
|
|
381
|
+
return `[Db] Disconnected${endpointSuffix}`;
|
|
382
|
+
}
|
|
383
|
+
function formatDbInstanceMessage(action, name) {
|
|
384
|
+
if (name) {
|
|
385
|
+
return `[Db] instance "${name}" ${action}`;
|
|
386
|
+
}
|
|
387
|
+
return `[Db] instance ${action}`;
|
|
388
|
+
}
|
|
389
|
+
function formatConnectionEndpointSuffix(connectionString) {
|
|
390
|
+
const endpoint = formatConnectionEndpoint(connectionString);
|
|
391
|
+
return endpoint ? ` (${endpoint})` : "";
|
|
392
|
+
}
|
|
393
|
+
function formatConnectionEndpoint(connectionString) {
|
|
394
|
+
try {
|
|
395
|
+
const url = new URL(connectionString);
|
|
396
|
+
const host = url.hostname;
|
|
397
|
+
if (!host) {
|
|
398
|
+
return null;
|
|
399
|
+
}
|
|
400
|
+
let port = url.port;
|
|
401
|
+
if (!port) {
|
|
402
|
+
if (url.protocol === "postgresql:") {
|
|
403
|
+
port = "5432";
|
|
404
|
+
} else if (url.protocol === "mysql:") {
|
|
405
|
+
port = "3306";
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
return port ? `${host}:${port}` : host;
|
|
409
|
+
} catch {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
async function dbConnect(context, config) {
|
|
350
414
|
try {
|
|
351
415
|
const db = new Db(config);
|
|
352
416
|
context.registerCleanup(async () => {
|
|
353
417
|
await db.disconnect();
|
|
354
|
-
context.logger.debug(
|
|
418
|
+
context.logger.debug?.(formatDbInstanceMessage("disconnected", config.name));
|
|
355
419
|
});
|
|
356
420
|
await db.connect();
|
|
357
|
-
context.logger.debug(
|
|
421
|
+
context.logger.debug?.(formatDbInstanceMessage("initialized", config.name));
|
|
358
422
|
return db;
|
|
359
423
|
} catch (error) {
|
|
360
424
|
if (error instanceof ParamError) {
|
|
@@ -364,50 +428,7 @@ async function dbConnect(context, connectionString, name, dbProfile) {
|
|
|
364
428
|
throw new ParamError(`[Db] connect error: ${errorMsg}`);
|
|
365
429
|
}
|
|
366
430
|
}
|
|
367
|
-
async function dbFindAndConnect(context, dbNameOrConnectionString) {
|
|
368
|
-
let dbName;
|
|
369
|
-
let dbConnectionString;
|
|
370
|
-
let dbProfile;
|
|
371
|
-
if (dbNameOrConnectionString) {
|
|
372
|
-
if (dbNameOrConnectionString.match(/^(postgresql|mysql):\/\/[^\s]+:[^\s]+@[^\s]+:\d+\/[^\s]+$/)) {
|
|
373
|
-
dbName = void 0;
|
|
374
|
-
dbConnectionString = dbNameOrConnectionString;
|
|
375
|
-
} else {
|
|
376
|
-
dbName = dbNameOrConnectionString;
|
|
377
|
-
}
|
|
378
|
-
} else {
|
|
379
|
-
const defs = {
|
|
380
|
-
dbName: "string",
|
|
381
|
-
dbConnectionString: "string",
|
|
382
|
-
dbProfile: "boolean default false"
|
|
383
|
-
};
|
|
384
|
-
const paramsConfig = context.params.getAll(defs);
|
|
385
|
-
dbName = paramsConfig.dbName;
|
|
386
|
-
dbConnectionString = paramsConfig.dbConnectionString;
|
|
387
|
-
dbProfile = paramsConfig.dbProfile;
|
|
388
|
-
}
|
|
389
|
-
if (!dbName && !dbConnectionString) {
|
|
390
|
-
throw new ParamError("Db: either dbName or dbConnectionString must be specified");
|
|
391
|
-
}
|
|
392
|
-
if (dbName) {
|
|
393
|
-
const paramName = `dbConnectionString${capitalizeFirstLetter(dbName)}`;
|
|
394
|
-
dbConnectionString = await context.params.get(paramName, "string");
|
|
395
|
-
if (!dbConnectionString) {
|
|
396
|
-
throw new ParamError(
|
|
397
|
-
`Db: cannot find dbConnectionString for dbName="${dbName}" (looked for param "${paramName}")`
|
|
398
|
-
);
|
|
399
|
-
}
|
|
400
|
-
}
|
|
401
|
-
const db = await dbConnect(context, dbConnectionString, dbName, dbProfile);
|
|
402
|
-
return db;
|
|
403
|
-
}
|
|
404
|
-
async function dbInit(context, dbNameOrConnectionString) {
|
|
405
|
-
return await dbFindAndConnect(context, dbNameOrConnectionString);
|
|
406
|
-
}
|
|
407
431
|
export {
|
|
408
|
-
Db
|
|
409
|
-
dbConnect,
|
|
410
|
-
dbFindAndConnect,
|
|
411
|
-
dbInit
|
|
432
|
+
Db
|
|
412
433
|
};
|
|
413
434
|
//# sourceMappingURL=db.js.map
|