@agentforge/tools 0.16.39 → 0.16.41

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/index.js CHANGED
@@ -4199,6 +4199,59 @@ function scheduleReconnection(context, logger23) {
4199
4199
  }, delay2);
4200
4200
  context.setReconnectionTimer(timer);
4201
4201
  }
4202
+
4203
+ // src/data/relational/connection/connection-cleanup.ts
4204
+ async function cleanupConnectionResources(vendor, client, clearConnection, logger23) {
4205
+ if (!client) {
4206
+ return;
4207
+ }
4208
+ logger23.debug("Cleaning up cancelled connection", {
4209
+ vendor
4210
+ });
4211
+ try {
4212
+ await shutdownClient(vendor, client);
4213
+ } catch (error) {
4214
+ logger23.debug("Error during cancelled connection cleanup", {
4215
+ vendor,
4216
+ error: error instanceof Error ? error.message : String(error)
4217
+ });
4218
+ } finally {
4219
+ clearConnection();
4220
+ }
4221
+ }
4222
+ async function closeManagedConnection(runtime, logger23) {
4223
+ const client = runtime.getClient();
4224
+ if (client) {
4225
+ logger23.info("Closing database connection", {
4226
+ vendor: runtime.vendor,
4227
+ state: runtime.getState()
4228
+ });
4229
+ try {
4230
+ await shutdownClient(runtime.vendor, client);
4231
+ runtime.setState("disconnected" /* DISCONNECTED */);
4232
+ runtime.emitDisconnected();
4233
+ logger23.debug("Database connection closed successfully", {
4234
+ vendor: runtime.vendor,
4235
+ state: runtime.getState()
4236
+ });
4237
+ } catch (error) {
4238
+ logger23.error("Error closing database connection", {
4239
+ vendor: runtime.vendor,
4240
+ error: error instanceof Error ? error.message : String(error),
4241
+ state: runtime.getState()
4242
+ });
4243
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
4244
+ runtime.setState("error" /* ERROR */);
4245
+ runtime.emitError(normalizedError);
4246
+ } finally {
4247
+ runtime.setClient(null);
4248
+ runtime.setDb(null);
4249
+ }
4250
+ } else if (runtime.getState() !== "disconnected" /* DISCONNECTED */) {
4251
+ runtime.setState("disconnected" /* DISCONNECTED */);
4252
+ runtime.emitDisconnected();
4253
+ }
4254
+ }
4202
4255
  var logger7 = createLogger("agentforge:tools:data:relational:connection:vendor-init");
4203
4256
  var SAFE_INITIALIZATION_PATTERNS = [
4204
4257
  "Pool max connections must be",
@@ -4354,6 +4407,190 @@ async function initializeSQLiteConnection(connection) {
4354
4407
  return { client, db };
4355
4408
  }
4356
4409
 
4410
+ // src/data/relational/connection/connection-initialization.ts
4411
+ async function initializeManagedConnection(runtime, logger23) {
4412
+ const startTime = Date.now();
4413
+ const currentGeneration = runtime.getConnectionGeneration();
4414
+ if (runtime.getState() === "connected" /* CONNECTED */ && runtime.getClient()) {
4415
+ logger23.warn("Re-initializing an already connected manager; emitting disconnected before cleanup", {
4416
+ vendor: runtime.vendor
4417
+ });
4418
+ runtime.setState("disconnected" /* DISCONNECTED */);
4419
+ runtime.emitDisconnected();
4420
+ await cleanupConnectionResources(
4421
+ runtime.vendor,
4422
+ runtime.getClient(),
4423
+ () => {
4424
+ runtime.setClient(null);
4425
+ runtime.setDb(null);
4426
+ },
4427
+ logger23
4428
+ );
4429
+ }
4430
+ runtime.setState("connecting" /* CONNECTING */);
4431
+ logger23.info("Initializing database connection", {
4432
+ vendor: runtime.vendor,
4433
+ connectionType: typeof runtime.config.connection,
4434
+ state: runtime.getState()
4435
+ });
4436
+ try {
4437
+ const initialized = await initializeVendorConnection(runtime.config);
4438
+ runtime.setClient(initialized.client);
4439
+ runtime.setDb(initialized.db);
4440
+ if (currentGeneration !== runtime.getConnectionGeneration()) {
4441
+ logger23.debug("Connection cancelled during initialization", {
4442
+ vendor: runtime.vendor,
4443
+ currentGeneration,
4444
+ newGeneration: runtime.getConnectionGeneration()
4445
+ });
4446
+ await cleanupConnectionResources(
4447
+ runtime.vendor,
4448
+ runtime.getClient(),
4449
+ () => {
4450
+ runtime.setClient(null);
4451
+ runtime.setDb(null);
4452
+ },
4453
+ logger23
4454
+ );
4455
+ runtime.setState("disconnected" /* DISCONNECTED */);
4456
+ throw new Error("Connection cancelled during initialization");
4457
+ }
4458
+ logger23.debug("Validating connection health", { vendor: runtime.vendor });
4459
+ const healthy = await runtime.isHealthy();
4460
+ if (!healthy) {
4461
+ throw new Error(`Failed to establish healthy connection to ${runtime.vendor} database`);
4462
+ }
4463
+ if (currentGeneration !== runtime.getConnectionGeneration()) {
4464
+ logger23.debug("Connection cancelled during health check", {
4465
+ vendor: runtime.vendor,
4466
+ currentGeneration,
4467
+ newGeneration: runtime.getConnectionGeneration()
4468
+ });
4469
+ await cleanupConnectionResources(
4470
+ runtime.vendor,
4471
+ runtime.getClient(),
4472
+ () => {
4473
+ runtime.setClient(null);
4474
+ runtime.setDb(null);
4475
+ },
4476
+ logger23
4477
+ );
4478
+ runtime.setState("disconnected" /* DISCONNECTED */);
4479
+ throw new Error("Connection cancelled during health check");
4480
+ }
4481
+ runtime.setState("connected" /* CONNECTED */);
4482
+ runtime.emitConnected();
4483
+ runtime.resetReconnectionAttempts();
4484
+ logger23.info("Database connection initialized successfully", {
4485
+ vendor: runtime.vendor,
4486
+ duration: Date.now() - startTime,
4487
+ state: runtime.getState()
4488
+ });
4489
+ } catch (error) {
4490
+ const errorMessage = `Failed to initialize ${runtime.vendor} connection`;
4491
+ const normalizedError = error instanceof Error ? error : new Error(String(error));
4492
+ const isValidationError = SAFE_INITIALIZATION_PATTERNS.some(
4493
+ (pattern) => normalizedError.message.includes(pattern)
4494
+ );
4495
+ if (isValidationError) {
4496
+ runtime.setState("error" /* ERROR */);
4497
+ throw normalizedError;
4498
+ }
4499
+ const isCancellation = normalizedError.message.includes("Connection cancelled");
4500
+ if (!isCancellation) {
4501
+ runtime.setState("error" /* ERROR */);
4502
+ if (runtime.errorListenerCount() > 0) {
4503
+ runtime.emitError(normalizedError);
4504
+ }
4505
+ logger23.error(errorMessage, {
4506
+ vendor: runtime.vendor,
4507
+ error: normalizedError.message,
4508
+ duration: Date.now() - startTime,
4509
+ state: runtime.getState()
4510
+ });
4511
+ await cleanupConnectionResources(
4512
+ runtime.vendor,
4513
+ runtime.getClient(),
4514
+ () => {
4515
+ runtime.setClient(null);
4516
+ runtime.setDb(null);
4517
+ },
4518
+ logger23
4519
+ );
4520
+ if (runtime.getReconnectionConfig().enabled && currentGeneration === runtime.getConnectionGeneration()) {
4521
+ runtime.scheduleReconnection();
4522
+ }
4523
+ } else {
4524
+ logger23.debug("Connection initialization cancelled", {
4525
+ vendor: runtime.vendor,
4526
+ duration: Date.now() - startTime,
4527
+ state: runtime.getState()
4528
+ });
4529
+ }
4530
+ if (error instanceof Error) {
4531
+ throw new Error(errorMessage, { cause: error });
4532
+ }
4533
+ throw new Error(`${errorMessage}: ${String(error)}`);
4534
+ }
4535
+ }
4536
+ function isSqliteNonQueryError(error) {
4537
+ if (!(error instanceof Error)) return false;
4538
+ const isSqliteOrTypeError = error.constructor?.name === "SqliteError" || error.name === "SqliteError" || error instanceof TypeError;
4539
+ const hasNonQueryMessage = error.message.includes("does not return data");
4540
+ return isSqliteOrTypeError && hasNonQueryMessage;
4541
+ }
4542
+ async function checkConnectionHealth(args, logger23) {
4543
+ if (!args.db || !args.client) {
4544
+ logger23.debug("Health check failed: connection not initialized", { vendor: args.vendor });
4545
+ return false;
4546
+ }
4547
+ try {
4548
+ await args.execute(sql`SELECT 1`);
4549
+ logger23.debug("Health check passed", { vendor: args.vendor });
4550
+ return true;
4551
+ } catch (error) {
4552
+ logger23.debug("Health check failed", {
4553
+ vendor: args.vendor,
4554
+ error: error instanceof Error ? error.message : String(error)
4555
+ });
4556
+ return false;
4557
+ }
4558
+ }
4559
+ function getConnectionPoolMetrics(vendor, client) {
4560
+ if (!client) {
4561
+ return { totalCount: 0, activeCount: 0, idleCount: 0, waitingCount: 0 };
4562
+ }
4563
+ if (vendor === "postgresql") {
4564
+ const pgClient = client;
4565
+ const totalCount2 = pgClient.totalCount || 0;
4566
+ const idleCount = pgClient.idleCount || 0;
4567
+ const waitingCount = pgClient.waitingCount || 0;
4568
+ const activeCount = Math.max(totalCount2 - idleCount, 0);
4569
+ return {
4570
+ totalCount: totalCount2,
4571
+ activeCount,
4572
+ idleCount,
4573
+ waitingCount
4574
+ };
4575
+ }
4576
+ if (vendor === "mysql") {
4577
+ return {
4578
+ totalCount: 0,
4579
+ activeCount: 0,
4580
+ idleCount: 0,
4581
+ waitingCount: 0
4582
+ };
4583
+ }
4584
+ const sqliteClient = client;
4585
+ const totalCount = sqliteClient.open ? 1 : 0;
4586
+ return {
4587
+ totalCount,
4588
+ activeCount: totalCount,
4589
+ idleCount: 0,
4590
+ waitingCount: 0
4591
+ };
4592
+ }
4593
+
4357
4594
  // src/data/relational/connection/query-execution.ts
4358
4595
  async function executeQuery(context, query, logger23) {
4359
4596
  logger23.debug("Executing SQL query", {
@@ -4373,11 +4610,11 @@ async function executeQuery(context, query, logger23) {
4373
4610
  }
4374
4611
  return context.db.execute(query);
4375
4612
  }
4376
- async function executeSqliteQuery(db, query, isSqliteNonQueryError) {
4613
+ async function executeSqliteQuery(db, query, isSqliteNonQueryError2) {
4377
4614
  try {
4378
4615
  return db.all(query);
4379
4616
  } catch (error) {
4380
- if (isSqliteNonQueryError(error)) {
4617
+ if (isSqliteNonQueryError2(error)) {
4381
4618
  const runResult = db.run(query);
4382
4619
  return { ...runResult, affectedRows: runResult.changes ?? 0 };
4383
4620
  }
@@ -4442,11 +4679,6 @@ var ConnectionManager = class extends EventEmitter {
4442
4679
  // Track in-flight connection attempts
4443
4680
  connectionGeneration = 0;
4444
4681
  // Cancellation token for disconnect
4445
- /**
4446
- * Create a new ConnectionManager instance
4447
- * @param config - Connection configuration
4448
- * @param reconnectionConfig - Optional reconnection configuration
4449
- */
4450
4682
  constructor(config, reconnectionConfig) {
4451
4683
  super();
4452
4684
  this.config = config;
@@ -4459,11 +4691,6 @@ var ConnectionManager = class extends EventEmitter {
4459
4691
  };
4460
4692
  checkPeerDependency(this.vendor);
4461
4693
  }
4462
- /**
4463
- * Connect to the database
4464
- * Initializes the connection and sets up automatic reconnection if configured
4465
- * @throws {Error} If connection fails or configuration is invalid
4466
- */
4467
4694
  async connect() {
4468
4695
  if (this.state === "connected" /* CONNECTED */) {
4469
4696
  logger8.debug("Already connected", { vendor: this.vendor });
@@ -4487,13 +4714,6 @@ var ConnectionManager = class extends EventEmitter {
4487
4714
  });
4488
4715
  return this.connectPromise;
4489
4716
  }
4490
- /**
4491
- * Disconnect from the database
4492
- * Closes the connection and cancels any pending reconnection attempts
4493
- *
4494
- * Note: Event listeners are NOT removed by this method. If you need to dispose
4495
- * of the ConnectionManager instance entirely, call dispose() instead.
4496
- */
4497
4717
  async disconnect() {
4498
4718
  this.connectionGeneration++;
4499
4719
  this.reconnectionTimer = cancelPendingReconnection(
@@ -4511,142 +4731,22 @@ var ConnectionManager = class extends EventEmitter {
4511
4731
  );
4512
4732
  await this.close();
4513
4733
  }
4514
- /**
4515
- * Dispose of the ConnectionManager instance
4516
- * Disconnects and removes all event listeners
4517
- * Call this when you're done with the ConnectionManager and won't reuse it
4518
- */
4519
4734
  async dispose() {
4520
4735
  await this.disconnect();
4521
4736
  this.removeAllListeners();
4522
4737
  }
4523
- /**
4524
- * Check if the connection is currently connected
4525
- * @returns true if connected, false otherwise
4526
- */
4527
4738
  isConnected() {
4528
4739
  return this.state === "connected" /* CONNECTED */;
4529
4740
  }
4530
- /**
4531
- * Get the current connection state
4532
- * @returns Current connection state
4533
- */
4534
4741
  getState() {
4535
4742
  return this.state;
4536
4743
  }
4537
- /**
4538
- * Get the configured database vendor.
4539
- */
4540
4744
  getVendor() {
4541
4745
  return this.vendor;
4542
4746
  }
4543
- /**
4544
- * Initialize the database connection
4545
- *
4546
- * This method is public to maintain compatibility with the DatabaseConnection interface
4547
- * and existing code (e.g., relational-query.ts). For new code, prefer using connect()
4548
- * which provides lifecycle management and automatic reconnection.
4549
- *
4550
- * @throws {Error} If connection fails or configuration is invalid
4551
- */
4552
4747
  async initialize() {
4553
- const startTime = Date.now();
4554
- const currentGeneration = this.connectionGeneration;
4555
- if (this.state === "connected" /* CONNECTED */ && this.client) {
4556
- logger8.warn("Re-initializing an already connected manager; emitting disconnected before cleanup", {
4557
- vendor: this.vendor
4558
- });
4559
- this.setState("disconnected" /* DISCONNECTED */);
4560
- this.emit("disconnected");
4561
- await this.cleanupCancelledConnection();
4562
- }
4563
- this.setState("connecting" /* CONNECTING */);
4564
- logger8.info("Initializing database connection", {
4565
- vendor: this.vendor,
4566
- connectionType: typeof this.config.connection,
4567
- state: this.state
4568
- });
4569
- try {
4570
- const initialized = await initializeVendorConnection(this.config);
4571
- this.client = initialized.client;
4572
- this.db = initialized.db;
4573
- if (currentGeneration !== this.connectionGeneration) {
4574
- logger8.debug("Connection cancelled during initialization", {
4575
- vendor: this.vendor,
4576
- currentGeneration,
4577
- newGeneration: this.connectionGeneration
4578
- });
4579
- await this.cleanupCancelledConnection();
4580
- this.setState("disconnected" /* DISCONNECTED */);
4581
- throw new Error("Connection cancelled during initialization");
4582
- }
4583
- logger8.debug("Validating connection health", { vendor: this.vendor });
4584
- const healthy = await this.isHealthy();
4585
- if (!healthy) {
4586
- throw new Error(`Failed to establish healthy connection to ${this.vendor} database`);
4587
- }
4588
- if (currentGeneration !== this.connectionGeneration) {
4589
- logger8.debug("Connection cancelled during health check", {
4590
- vendor: this.vendor,
4591
- currentGeneration,
4592
- newGeneration: this.connectionGeneration
4593
- });
4594
- await this.cleanupCancelledConnection();
4595
- this.setState("disconnected" /* DISCONNECTED */);
4596
- throw new Error("Connection cancelled during health check");
4597
- }
4598
- this.setState("connected" /* CONNECTED */);
4599
- this.emit("connected");
4600
- this.reconnectionAttempts = 0;
4601
- logger8.info("Database connection initialized successfully", {
4602
- vendor: this.vendor,
4603
- duration: Date.now() - startTime,
4604
- state: this.state
4605
- });
4606
- } catch (error) {
4607
- const errorMessage = `Failed to initialize ${this.vendor} connection`;
4608
- const normalizedError = error instanceof Error ? error : new Error(String(error));
4609
- const isValidationError = SAFE_INITIALIZATION_PATTERNS.some(
4610
- (pattern) => normalizedError.message.includes(pattern)
4611
- );
4612
- if (isValidationError) {
4613
- this.setState("error" /* ERROR */);
4614
- throw normalizedError;
4615
- }
4616
- const isCancellation = normalizedError.message.includes("Connection cancelled");
4617
- if (!isCancellation) {
4618
- this.setState("error" /* ERROR */);
4619
- if (this.listenerCount("error") > 0) {
4620
- this.emit("error", normalizedError);
4621
- }
4622
- logger8.error(errorMessage, {
4623
- vendor: this.vendor,
4624
- error: normalizedError.message,
4625
- duration: Date.now() - startTime,
4626
- state: this.state
4627
- });
4628
- await this.cleanupCancelledConnection();
4629
- if (this.reconnectionConfig.enabled && currentGeneration === this.connectionGeneration) {
4630
- this.scheduleReconnection();
4631
- }
4632
- } else {
4633
- logger8.debug("Connection initialization cancelled", {
4634
- vendor: this.vendor,
4635
- duration: Date.now() - startTime,
4636
- state: this.state
4637
- });
4638
- }
4639
- if (error instanceof Error) {
4640
- throw new Error(errorMessage, { cause: error });
4641
- }
4642
- throw new Error(`${errorMessage}: ${String(error)}`);
4643
- }
4748
+ return initializeManagedConnection(this.createRuntimeAdapter(), logger8);
4644
4749
  }
4645
- /**
4646
- * Set the connection state and log the change
4647
- * @param newState - New connection state
4648
- * @private
4649
- */
4650
4750
  setState(newState) {
4651
4751
  const oldState = this.state;
4652
4752
  this.state = newState;
@@ -4658,10 +4758,6 @@ var ConnectionManager = class extends EventEmitter {
4658
4758
  });
4659
4759
  }
4660
4760
  }
4661
- /**
4662
- * Schedule a reconnection attempt with exponential backoff
4663
- * @private
4664
- */
4665
4761
  scheduleReconnection() {
4666
4762
  scheduleReconnection(
4667
4763
  {
@@ -4688,40 +4784,39 @@ var ConnectionManager = class extends EventEmitter {
4688
4784
  logger8
4689
4785
  );
4690
4786
  }
4691
- /**
4692
- * Determine whether an error thrown by drizzle-orm's better-sqlite3 adapter
4693
- * `.all()` indicates the statement does not return data (i.e. it is DML/DDL,
4694
- * not a SELECT).
4695
- *
4696
- * The adapter may surface this as either a native `SqliteError` or a
4697
- * `TypeError` depending on the drizzle-orm / better-sqlite3 version, so we
4698
- * accept both types while still requiring the distinctive message substring
4699
- * to avoid false positives from unrelated errors.
4700
- */
4701
- isSqliteNonQueryError(error) {
4702
- if (!(error instanceof Error)) return false;
4703
- const isSqliteOrTypeError = error.constructor?.name === "SqliteError" || error.name === "SqliteError" || error instanceof TypeError;
4704
- const hasNonQueryMessage = error.message.includes("does not return data");
4705
- return isSqliteOrTypeError && hasNonQueryMessage;
4787
+ createRuntimeAdapter() {
4788
+ return {
4789
+ vendor: this.vendor,
4790
+ config: this.config,
4791
+ getState: () => this.state,
4792
+ setState: (state) => this.setState(state),
4793
+ getClient: () => this.client,
4794
+ setClient: (client) => {
4795
+ this.client = client;
4796
+ },
4797
+ getDb: () => this.db,
4798
+ setDb: (db) => {
4799
+ this.db = db;
4800
+ },
4801
+ emitConnected: () => {
4802
+ this.emit("connected");
4803
+ },
4804
+ emitDisconnected: () => {
4805
+ this.emit("disconnected");
4806
+ },
4807
+ emitError: (error) => {
4808
+ this.emit("error", error);
4809
+ },
4810
+ errorListenerCount: () => this.listenerCount("error"),
4811
+ getReconnectionConfig: () => this.reconnectionConfig,
4812
+ scheduleReconnection: () => this.scheduleReconnection(),
4813
+ resetReconnectionAttempts: () => {
4814
+ this.reconnectionAttempts = 0;
4815
+ },
4816
+ getConnectionGeneration: () => this.connectionGeneration,
4817
+ isHealthy: () => this.isHealthy()
4818
+ };
4706
4819
  }
4707
- /**
4708
- * Execute a SQL query
4709
- *
4710
- * Executes a parameterized SQL query using Drizzle's SQL template objects.
4711
- * This method provides safe parameter binding to prevent SQL injection.
4712
- *
4713
- * @param query - Drizzle SQL template object with parameter binding
4714
- * @returns Query result
4715
- *
4716
- * @example
4717
- * ```typescript
4718
- * import { sql } from 'drizzle-orm';
4719
- *
4720
- * const result = await manager.execute(
4721
- * sql`SELECT * FROM users WHERE id = ${userId}`
4722
- * );
4723
- * ```
4724
- */
4725
4820
  async execute(query) {
4726
4821
  if (!this.db) {
4727
4822
  throw new Error("Database not initialized. Call initialize() first.");
@@ -4730,18 +4825,12 @@ var ConnectionManager = class extends EventEmitter {
4730
4825
  {
4731
4826
  vendor: this.vendor,
4732
4827
  db: this.db,
4733
- isSqliteNonQueryError: (error) => this.isSqliteNonQueryError(error)
4828
+ isSqliteNonQueryError
4734
4829
  },
4735
4830
  query,
4736
4831
  logger8
4737
4832
  );
4738
4833
  }
4739
- /**
4740
- * Execute a callback with a single dedicated database connection/session.
4741
- *
4742
- * This is required for multi-statement transactions so all statements run on
4743
- * the same underlying connection.
4744
- */
4745
4834
  async executeInConnection(callback) {
4746
4835
  if (!this.client || !this.db) {
4747
4836
  throw new Error("Database not initialized. Call connect() first.");
@@ -4751,65 +4840,14 @@ var ConnectionManager = class extends EventEmitter {
4751
4840
  vendor: this.vendor,
4752
4841
  client: this.client,
4753
4842
  db: this.db,
4754
- isSqliteNonQueryError: (error) => this.isSqliteNonQueryError(error)
4843
+ isSqliteNonQueryError
4755
4844
  },
4756
4845
  callback
4757
4846
  );
4758
4847
  }
4759
- /**
4760
- * Get connection pool metrics
4761
- *
4762
- * Returns information about the current state of the connection pool.
4763
- * For SQLite, returns basic connection status since it uses a single connection.
4764
- *
4765
- * @returns Pool metrics including total, active, idle, and waiting connections
4766
- */
4767
4848
  getPoolMetrics() {
4768
- if (!this.client) {
4769
- return { totalCount: 0, activeCount: 0, idleCount: 0, waitingCount: 0 };
4770
- }
4771
- if (this.vendor === "postgresql") {
4772
- const totalCount = this.client.totalCount || 0;
4773
- const idleCount = this.client.idleCount || 0;
4774
- const waitingCount = this.client.waitingCount || 0;
4775
- const activeCount = Math.max(totalCount - idleCount, 0);
4776
- return {
4777
- totalCount,
4778
- activeCount,
4779
- idleCount,
4780
- waitingCount
4781
- };
4782
- } else if (this.vendor === "mysql") {
4783
- return {
4784
- totalCount: 0,
4785
- activeCount: 0,
4786
- idleCount: 0,
4787
- waitingCount: 0
4788
- };
4789
- } else {
4790
- const totalCount = this.client.open ? 1 : 0;
4791
- const idleCount = 0;
4792
- const waitingCount = 0;
4793
- const activeCount = this.client.open ? 1 : 0;
4794
- return {
4795
- totalCount,
4796
- activeCount,
4797
- idleCount,
4798
- waitingCount
4799
- };
4800
- }
4849
+ return getConnectionPoolMetrics(this.vendor, this.client);
4801
4850
  }
4802
- /**
4803
- * Close the database connection
4804
- *
4805
- * This method is public to maintain compatibility with the DatabaseConnection interface
4806
- * and existing code (e.g., relational-query.ts). For new code, prefer using disconnect()
4807
- * for connection lifecycle management. Note that disconnect() does NOT clean up event
4808
- * listeners; call dispose() if you need full cleanup including listener removal.
4809
- *
4810
- * Note: This method coordinates with in-flight connect()/initialize() operations
4811
- * and cancels pending reconnection timers to prevent unexpected reconnections.
4812
- */
4813
4851
  async close() {
4814
4852
  this.connectionGeneration++;
4815
4853
  this.reconnectionTimer = cancelPendingReconnection(
@@ -4824,80 +4862,38 @@ var ConnectionManager = class extends EventEmitter {
4824
4862
  this.vendor,
4825
4863
  "close"
4826
4864
  );
4827
- if (this.client) {
4828
- logger8.info("Closing database connection", {
4829
- vendor: this.vendor,
4830
- state: this.state
4831
- });
4832
- try {
4833
- await shutdownClient(this.vendor, this.client);
4834
- this.setState("disconnected" /* DISCONNECTED */);
4835
- this.emit("disconnected");
4836
- logger8.debug("Database connection closed successfully", {
4837
- vendor: this.vendor,
4838
- state: this.state
4839
- });
4840
- } catch (error) {
4841
- logger8.error("Error closing database connection", {
4842
- vendor: this.vendor,
4843
- error: error instanceof Error ? error.message : String(error),
4844
- state: this.state
4845
- });
4846
- const normalizedError = error instanceof Error ? error : new Error(String(error));
4847
- this.setState("error" /* ERROR */);
4848
- this.emit("error", normalizedError);
4849
- } finally {
4850
- this.client = null;
4851
- this.db = null;
4852
- }
4853
- } else if (this.state !== "disconnected" /* DISCONNECTED */) {
4854
- this.setState("disconnected" /* DISCONNECTED */);
4855
- this.emit("disconnected");
4856
- }
4857
- }
4858
- /**
4859
- * Clean up resources when a connection is cancelled during initialization
4860
- * This prevents connection leaks when disconnect() is called while initialize() is in-flight
4861
- */
4862
- async cleanupCancelledConnection() {
4863
- if (!this.client) {
4864
- return;
4865
- }
4866
- logger8.debug("Cleaning up cancelled connection", {
4867
- vendor: this.vendor
4868
- });
4869
- try {
4870
- await shutdownClient(this.vendor, this.client);
4871
- } catch (error) {
4872
- logger8.debug("Error during cancelled connection cleanup", {
4865
+ await closeManagedConnection(
4866
+ {
4873
4867
  vendor: this.vendor,
4874
- error: error instanceof Error ? error.message : String(error)
4875
- });
4876
- } finally {
4877
- this.client = null;
4878
- this.db = null;
4879
- }
4868
+ getState: () => this.state,
4869
+ setState: (state) => this.setState(state),
4870
+ getClient: () => this.client,
4871
+ setClient: (client) => {
4872
+ this.client = client;
4873
+ },
4874
+ setDb: (db) => {
4875
+ this.db = db;
4876
+ },
4877
+ emitDisconnected: () => {
4878
+ this.emit("disconnected");
4879
+ },
4880
+ emitError: (error) => {
4881
+ this.emit("error", error);
4882
+ }
4883
+ },
4884
+ logger8
4885
+ );
4880
4886
  }
4881
- /**
4882
- * Check if the connection is healthy
4883
- * @returns true if connection is healthy, false otherwise
4884
- */
4885
4887
  async isHealthy() {
4886
- if (!this.db || !this.client) {
4887
- logger8.debug("Health check failed: connection not initialized", { vendor: this.vendor });
4888
- return false;
4889
- }
4890
- try {
4891
- await this.execute(sql`SELECT 1`);
4892
- logger8.debug("Health check passed", { vendor: this.vendor });
4893
- return true;
4894
- } catch (error) {
4895
- logger8.debug("Health check failed", {
4888
+ return checkConnectionHealth(
4889
+ {
4896
4890
  vendor: this.vendor,
4897
- error: error instanceof Error ? error.message : String(error)
4898
- });
4899
- return false;
4900
- }
4891
+ db: this.db,
4892
+ client: this.client,
4893
+ execute: (query) => this.execute(query)
4894
+ },
4895
+ logger8
4896
+ );
4901
4897
  }
4902
4898
  };
4903
4899
  var logger9 = createLogger("agentforge:tools:data:relational:query");