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