@nmakarov/cli-toolkit 0.3.0 → 0.4.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/db.cjs ADDED
@@ -0,0 +1,351 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/db.ts
31
+ var db_exports = {};
32
+ __export(db_exports, {
33
+ Db: () => Db
34
+ });
35
+ module.exports = __toCommonJS(db_exports);
36
+
37
+ // src/db/index.ts
38
+ var import_knex = __toESM(require("knex"), 1);
39
+
40
+ // src/errors.ts
41
+ var FrameworkError = class extends Error {
42
+ constructor(message) {
43
+ super(message);
44
+ this.name = "FrameworkError";
45
+ }
46
+ };
47
+ var ParamError = class extends FrameworkError {
48
+ constructor(message) {
49
+ super(message);
50
+ this.name = "ParamError";
51
+ }
52
+ };
53
+
54
+ // src/db/index.ts
55
+ var Db = class {
56
+ knexInstance = null;
57
+ config;
58
+ logger;
59
+ queriesLog = [];
60
+ isConnected = false;
61
+ constructor(config) {
62
+ if (!config.connectionString) {
63
+ throw new ParamError("Db: connectionString is required");
64
+ }
65
+ this.config = {
66
+ testConnection: true,
67
+ profile: false,
68
+ pool: { min: 2, max: 10 },
69
+ acquireConnectionTimeout: 1e4,
70
+ ssl: { rejectUnauthorized: false },
71
+ logger: console,
72
+ name: "default",
73
+ ...config
74
+ };
75
+ this.logger = this.config.logger;
76
+ const instance = this;
77
+ const callableWrapper = function(...args) {
78
+ throw new Error("This should never be called directly");
79
+ };
80
+ callableWrapper._instance = instance;
81
+ return new Proxy(callableWrapper, {
82
+ // Intercept function calls: db('table')
83
+ apply: (target, thisArg, argumentsList) => {
84
+ const inst = target._instance;
85
+ if (!inst.knexInstance) {
86
+ throw new Error("Db: Not connected. Call connect() first.");
87
+ }
88
+ return inst.knexInstance(...argumentsList);
89
+ },
90
+ // Intercept property access: db.schema, db.raw, etc.
91
+ get: (target, prop) => {
92
+ if (prop === "_instance") {
93
+ return target._instance;
94
+ }
95
+ const instance2 = target._instance;
96
+ const ownMethods = [
97
+ "connect",
98
+ "disconnect",
99
+ "testConnection",
100
+ "tableExists",
101
+ "getQueryLog",
102
+ "getKnex",
103
+ "isConnectedToDb",
104
+ "getErrorMessage",
105
+ "detectClient",
106
+ "attachProfiler"
107
+ ];
108
+ if (prop in instance2) {
109
+ const value = instance2[prop];
110
+ if (typeof value === "function" && ownMethods.includes(prop)) {
111
+ return value.bind(instance2);
112
+ }
113
+ if (typeof value !== "function") {
114
+ return value;
115
+ }
116
+ }
117
+ if (instance2.knexInstance) {
118
+ const knexProp = instance2.knexInstance[prop];
119
+ if (typeof knexProp === "function") {
120
+ return knexProp.bind(instance2.knexInstance);
121
+ }
122
+ return knexProp;
123
+ }
124
+ if (prop in instance2) {
125
+ const method = instance2[prop];
126
+ if (typeof method === "function") {
127
+ return method.bind(instance2);
128
+ }
129
+ return method;
130
+ }
131
+ return void 0;
132
+ }
133
+ });
134
+ }
135
+ /**
136
+ * Detect database client type from connection string
137
+ */
138
+ detectClient(connectionString) {
139
+ if (connectionString.match(/^postgresql/)) {
140
+ return "pg";
141
+ }
142
+ if (connectionString.match(/^mysql/)) {
143
+ return "mysql2";
144
+ }
145
+ return null;
146
+ }
147
+ /**
148
+ * Connect to the database
149
+ */
150
+ async connect() {
151
+ if (this.isConnected && this.knexInstance) {
152
+ this.logger.warn?.("[Db] Already connected");
153
+ return;
154
+ }
155
+ const client = this.detectClient(this.config.connectionString);
156
+ if (!client) {
157
+ throw new ParamError(
158
+ `Db: Cannot determine client type from connection string. Expected postgresql:// or mysql://`
159
+ );
160
+ }
161
+ try {
162
+ const connectionConfig = {
163
+ connectionString: this.config.connectionString,
164
+ family: 4
165
+ // Force IPv4 only (disable IPv6)
166
+ };
167
+ this.knexInstance = (0, import_knex.default)({
168
+ client,
169
+ connection: connectionConfig,
170
+ pool: this.config.pool,
171
+ acquireConnectionTimeout: this.config.acquireConnectionTimeout,
172
+ ...this.config.ssl && { ssl: this.config.ssl }
173
+ });
174
+ if (this.config.profile) {
175
+ this.attachProfiler();
176
+ }
177
+ if (this.config.testConnection) {
178
+ await this.testConnection();
179
+ }
180
+ this.isConnected = true;
181
+ this.logger.debug?.(`[Db] Connected to database "${this.config.name || this.config.connectionString}"`);
182
+ } catch (error) {
183
+ if (error instanceof ParamError) {
184
+ throw error;
185
+ }
186
+ const errorMsg = this.getErrorMessage(error);
187
+ throw new ParamError(`Db: Connection failed - ${errorMsg}`);
188
+ }
189
+ }
190
+ /**
191
+ * Disconnect from the database
192
+ */
193
+ async disconnect() {
194
+ if (!this.knexInstance) {
195
+ return;
196
+ }
197
+ try {
198
+ await this.knexInstance.destroy();
199
+ this.knexInstance = null;
200
+ this.isConnected = false;
201
+ this.queriesLog = [];
202
+ this.logger.debug?.(`[Db] Disconnected from database "${this.config.name || this.config.connectionString}"`);
203
+ } catch (error) {
204
+ const errorMsg = this.getErrorMessage(error);
205
+ this.logger.error?.(`[Db] Error disconnecting: ${errorMsg}`);
206
+ throw error;
207
+ }
208
+ }
209
+ /**
210
+ * Extract error message from various error types
211
+ */
212
+ getErrorMessage(error) {
213
+ if (error instanceof AggregateError) {
214
+ const errors = error.errors || [];
215
+ if (errors.length > 0) {
216
+ const firstError = errors[0];
217
+ const firstErrorMsg = firstError instanceof Error ? firstError.message : String(firstError);
218
+ const allSimilar = errors.every((e) => {
219
+ const msg = e instanceof Error ? e.message : String(e);
220
+ const codeMatch = msg.match(/^(\w+)\s/);
221
+ const firstCodeMatch = firstErrorMsg.match(/^(\w+)\s/);
222
+ return codeMatch && firstCodeMatch && codeMatch[1] === firstCodeMatch[1];
223
+ });
224
+ if (allSimilar && errors.length > 1) {
225
+ const addresses = errors.map((e) => {
226
+ const msg = e instanceof Error ? e.message : String(e);
227
+ const addrMatch = msg.match(/([:\d.]+:\d+)/);
228
+ return addrMatch ? addrMatch[1] : null;
229
+ }).filter(Boolean);
230
+ if (addresses.length > 0) {
231
+ const codeMatch = firstErrorMsg.match(/^(\w+)\s/);
232
+ const code = codeMatch ? codeMatch[1] : "Connection error";
233
+ return `${code} (tried: ${addresses.join(", ")})`;
234
+ }
235
+ }
236
+ const uniqueMessages = [...new Set(errors.map((e) => {
237
+ return e instanceof Error ? e.message : String(e);
238
+ }))];
239
+ if (uniqueMessages.length === 1) {
240
+ return uniqueMessages[0];
241
+ }
242
+ return uniqueMessages.join("; ");
243
+ }
244
+ return error.message || "Multiple errors occurred";
245
+ }
246
+ if (error instanceof Error) {
247
+ const errorWithCode = error;
248
+ if (errorWithCode.code) {
249
+ return `${errorWithCode.code}: ${error.message || String(error)}`;
250
+ }
251
+ return error.message || String(error);
252
+ }
253
+ if (typeof error === "string") {
254
+ return error;
255
+ }
256
+ if (error?.message) {
257
+ const msg = String(error.message);
258
+ const errorWithCode = error;
259
+ if (errorWithCode.code) {
260
+ return `${errorWithCode.code}: ${msg}`;
261
+ }
262
+ return msg;
263
+ }
264
+ return String(error) || "Unknown error";
265
+ }
266
+ /**
267
+ * Test database connection
268
+ */
269
+ async testConnection() {
270
+ if (!this.knexInstance) {
271
+ throw new Error("Db: Not connected. Call connect() first.");
272
+ }
273
+ try {
274
+ const result = await this.knexInstance.raw("SELECT 2+3 AS result");
275
+ const isOk = result.rows?.[0]?.result === 5 || result[0]?.[0]?.result === 5;
276
+ this.logger.debug?.(`[Db] Connection test: ${isOk ? "OK" : "FAILED"}`);
277
+ return isOk;
278
+ } catch (error) {
279
+ const errorMsg = this.getErrorMessage(error);
280
+ this.logger.error?.(`[Db] Connection test failed: ${errorMsg}`);
281
+ throw new ParamError(`Db: Connection test failed - ${errorMsg}`);
282
+ }
283
+ }
284
+ /**
285
+ * Attach query profiler to log all queries
286
+ */
287
+ attachProfiler() {
288
+ if (!this.knexInstance) {
289
+ return;
290
+ }
291
+ this.queriesLog = [];
292
+ this.knexInstance.queriesLog = this.queriesLog;
293
+ this.knexInstance.on("query", (query) => {
294
+ query.__startTime = process.hrtime();
295
+ });
296
+ this.knexInstance.on("query-response", (response, query) => {
297
+ const [seconds, nanoseconds] = process.hrtime(query.__startTime);
298
+ const executionTimeMs = (seconds * 1e3 + nanoseconds / 1e6).toFixed(2);
299
+ const logEntry = {
300
+ sql: query.sql,
301
+ bindings: query.bindings || [],
302
+ executionTimeMs
303
+ };
304
+ this.queriesLog.push(logEntry);
305
+ this.logger.debug?.(`[Db] Query: ${query.sql} | Duration: ${executionTimeMs}ms`);
306
+ });
307
+ this.knexInstance.on("query-error", (error, query) => {
308
+ this.logger.error?.(`[Db] Query failed: ${query.sql}`, error);
309
+ });
310
+ }
311
+ /**
312
+ * Get query log (only available if profiling is enabled)
313
+ */
314
+ getQueryLog() {
315
+ return [...this.queriesLog];
316
+ }
317
+ /**
318
+ * Check if a table exists
319
+ */
320
+ async tableExists(tableName) {
321
+ if (!this.knexInstance) {
322
+ throw new Error("Db: Not connected. Call connect() first.");
323
+ }
324
+ try {
325
+ return await this.knexInstance.schema.hasTable(tableName);
326
+ } catch (error) {
327
+ this.logger.error?.(`[Db] Error checking table existence: ${error.message}`);
328
+ throw error;
329
+ }
330
+ }
331
+ /**
332
+ * Get the underlying Knex instance (for advanced usage)
333
+ */
334
+ getKnex() {
335
+ if (!this.knexInstance) {
336
+ throw new Error("Db: Not connected. Call connect() first.");
337
+ }
338
+ return this.knexInstance;
339
+ }
340
+ /**
341
+ * Get connection status
342
+ */
343
+ isConnectedToDb() {
344
+ return this.isConnected && this.knexInstance !== null;
345
+ }
346
+ };
347
+ // Annotate the CommonJS export names for ESM import in node:
348
+ 0 && (module.exports = {
349
+ Db
350
+ });
351
+ //# sourceMappingURL=db.cjs.map
@@ -0,0 +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 { DbConfig, 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 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 private 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","/**\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\n"],"mappings":"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","names":["instance","knex"]}