@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.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.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,
|
|
4613
|
+
async function executeSqliteQuery(db, query, isSqliteNonQueryError2) {
|
|
4377
4614
|
try {
|
|
4378
4615
|
return db.all(query);
|
|
4379
4616
|
} catch (error) {
|
|
4380
|
-
if (
|
|
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
|
-
|
|
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
|
-
|
|
4693
|
-
|
|
4694
|
-
|
|
4695
|
-
|
|
4696
|
-
|
|
4697
|
-
|
|
4698
|
-
|
|
4699
|
-
|
|
4700
|
-
|
|
4701
|
-
|
|
4702
|
-
|
|
4703
|
-
|
|
4704
|
-
|
|
4705
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
4828
|
-
|
|
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
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
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
|
-
|
|
4887
|
-
|
|
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
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
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");
|