@bytebase/dbhub 0.18.0 → 0.19.1

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.
@@ -70,6 +70,9 @@ import { readFileSync, realpathSync, statSync } from "fs";
70
70
  import { homedir } from "os";
71
71
  import { join } from "path";
72
72
  import SSHConfig from "ssh-config";
73
+ function getDefaultSSHConfigPath() {
74
+ return join(homedir(), ".ssh", "config");
75
+ }
73
76
  var DEFAULT_SSH_KEYS = [
74
77
  "~/.ssh/id_rsa",
75
78
  "~/.ssh/id_ed25519",
@@ -503,7 +506,7 @@ var SSHTunnel = class {
503
506
  // src/config/toml-loader.ts
504
507
  import fs2 from "fs";
505
508
  import path2 from "path";
506
- import { homedir as homedir3 } from "os";
509
+ import { homedir as homedir2 } from "os";
507
510
  import toml from "@iarna/toml";
508
511
 
509
512
  // src/config/env.ts
@@ -511,7 +514,6 @@ import dotenv from "dotenv";
511
514
  import path from "path";
512
515
  import fs from "fs";
513
516
  import { fileURLToPath } from "url";
514
- import { homedir as homedir2 } from "os";
515
517
 
516
518
  // src/utils/safe-url.ts
517
519
  var SafeURL = class {
@@ -970,7 +972,7 @@ function resolveSSHConfig() {
970
972
  sources.push("SSH_HOST from environment");
971
973
  }
972
974
  if (sshConfigHost && looksLikeSSHAlias(sshConfigHost)) {
973
- const sshConfigPath = path.join(homedir2(), ".ssh", "config");
975
+ const sshConfigPath = getDefaultSSHConfigPath();
974
976
  console.error(`Attempting to parse SSH config for host '${sshConfigHost}' from: ${sshConfigPath}`);
975
977
  const sshConfigData = parseSSHConfig(sshConfigHost, sshConfigPath);
976
978
  if (sshConfigData) {
@@ -1150,7 +1152,8 @@ function loadTomlConfig() {
1150
1152
  }
1151
1153
  try {
1152
1154
  const fileContent = fs2.readFileSync(configPath, "utf-8");
1153
- const parsedToml = toml.parse(fileContent);
1155
+ const rawToml = toml.parse(fileContent);
1156
+ const parsedToml = interpolateEnvVars(rawToml);
1154
1157
  if (!Array.isArray(parsedToml.sources)) {
1155
1158
  throw new Error(
1156
1159
  `Configuration file ${configPath}: must contain a [[sources]] array. Use [[sources]] syntax for array of tables in TOML.`
@@ -1460,9 +1463,29 @@ function processSourceConfigs(sources, configPath) {
1460
1463
  return processed;
1461
1464
  });
1462
1465
  }
1466
+ var ENV_VAR_PATTERN = /\$\{([^}]+)\}/g;
1467
+ function interpolateEnvVars(value) {
1468
+ if (typeof value === "string") {
1469
+ return value.replace(ENV_VAR_PATTERN, (match, varName) => {
1470
+ const envValue = process.env[varName];
1471
+ return envValue !== void 0 ? envValue : match;
1472
+ });
1473
+ }
1474
+ if (Array.isArray(value)) {
1475
+ return value.map((item) => interpolateEnvVars(item));
1476
+ }
1477
+ if (value !== null && typeof value === "object" && Object.getPrototypeOf(value) === Object.prototype) {
1478
+ const result = {};
1479
+ for (const [key, val] of Object.entries(value)) {
1480
+ result[key] = interpolateEnvVars(val);
1481
+ }
1482
+ return result;
1483
+ }
1484
+ return value;
1485
+ }
1463
1486
  function expandHomeDir(filePath) {
1464
1487
  if (filePath.startsWith("~/")) {
1465
- return path2.join(homedir3(), filePath.substring(2));
1488
+ return path2.join(homedir2(), filePath.substring(2));
1466
1489
  }
1467
1490
  return filePath;
1468
1491
  }
@@ -1644,25 +1667,32 @@ var ConnectorManager = class {
1644
1667
  console.error(` - ${sourceId}: ${redactDSN(dsn)}`);
1645
1668
  let actualDSN = dsn;
1646
1669
  if (source.ssh_host) {
1647
- if (!source.ssh_user) {
1648
- throw new Error(
1649
- `Source '${sourceId}': SSH tunnel requires ssh_user`
1650
- );
1670
+ let resolvedSSHConfig = null;
1671
+ if (looksLikeSSHAlias(source.ssh_host)) {
1672
+ const sshConfigPath = getDefaultSSHConfigPath();
1673
+ console.error(` Resolving SSH config for host '${source.ssh_host}' from: ${sshConfigPath}`);
1674
+ resolvedSSHConfig = parseSSHConfig(source.ssh_host, sshConfigPath);
1651
1675
  }
1676
+ const username = source.ssh_user || resolvedSSHConfig?.username;
1652
1677
  const sshConfig = {
1653
- host: source.ssh_host,
1654
- port: source.ssh_port || 22,
1655
- username: source.ssh_user,
1678
+ host: resolvedSSHConfig?.host || source.ssh_host,
1679
+ port: source.ssh_port || resolvedSSHConfig?.port || 22,
1680
+ username: username || "",
1656
1681
  password: source.ssh_password,
1657
- privateKey: source.ssh_key,
1682
+ privateKey: source.ssh_key || resolvedSSHConfig?.privateKey,
1658
1683
  passphrase: source.ssh_passphrase,
1659
- proxyJump: source.ssh_proxy_jump,
1684
+ proxyJump: source.ssh_proxy_jump || resolvedSSHConfig?.proxyJump,
1660
1685
  keepaliveInterval: source.ssh_keepalive_interval,
1661
1686
  keepaliveCountMax: source.ssh_keepalive_count_max
1662
1687
  };
1688
+ if (!username) {
1689
+ throw new Error(
1690
+ `Source '${sourceId}': SSH tunnel requires ssh_user (or a matching Host entry in ~/.ssh/config with User)`
1691
+ );
1692
+ }
1663
1693
  if (!sshConfig.password && !sshConfig.privateKey) {
1664
1694
  throw new Error(
1665
- `Source '${sourceId}': SSH tunnel requires either ssh_password or ssh_key`
1695
+ `Source '${sourceId}': SSH tunnel requires either ssh_password or ssh_key (or a matching Host entry in ~/.ssh/config with IdentityFile)`
1666
1696
  );
1667
1697
  }
1668
1698
  const url = new URL(dsn);
package/dist/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  resolveTransport,
21
21
  splitSQLStatements,
22
22
  stripCommentsAndStrings
23
- } from "./chunk-WCXOWHL3.js";
23
+ } from "./chunk-LUNM7TUY.js";
24
24
 
25
25
  // src/connectors/postgres/index.ts
26
26
  import pg from "pg";
@@ -1182,6 +1182,7 @@ var SQLiteConnector = class _SQLiteConnector {
1182
1182
  dbOptions.readonly = true;
1183
1183
  }
1184
1184
  this.db = new Database(this.dbPath, dbOptions);
1185
+ this.db.defaultSafeIntegers(true);
1185
1186
  if (initScript) {
1186
1187
  this.db.exec(initScript);
1187
1188
  }
@@ -1491,8 +1492,10 @@ Expected: ${expectedFormat}`
1491
1492
  // Remove leading '/' if exists
1492
1493
  user: url.username,
1493
1494
  password: url.password,
1494
- multipleStatements: true
1495
+ multipleStatements: true,
1495
1496
  // Enable native multi-statement support
1497
+ supportBigNumbers: true
1498
+ // Return BIGINT as string when value exceeds Number.MAX_SAFE_INTEGER
1496
1499
  };
1497
1500
  url.forEachSearchParam((value, key) => {
1498
1501
  if (key === "sslmode") {
@@ -2378,8 +2381,13 @@ import { fileURLToPath } from "url";
2378
2381
  import { z } from "zod";
2379
2382
 
2380
2383
  // src/utils/response-formatter.ts
2384
+ var MIN_SAFE_BIGINT = BigInt(Number.MIN_SAFE_INTEGER);
2385
+ var MAX_SAFE_BIGINT = BigInt(Number.MAX_SAFE_INTEGER);
2381
2386
  function bigIntReplacer(_key, value) {
2382
2387
  if (typeof value === "bigint") {
2388
+ if (value >= MIN_SAFE_BIGINT && value <= MAX_SAFE_BIGINT) {
2389
+ return Number(value);
2390
+ }
2383
2391
  return value.toString();
2384
2392
  }
2385
2393
  return value;
@@ -3697,7 +3705,7 @@ See documentation for more details on configuring database connections.
3697
3705
  const sources = sourceConfigsData.sources;
3698
3706
  console.error(`Configuration source: ${sourceConfigsData.source}`);
3699
3707
  await connectorManager.connectWithSources(sources);
3700
- const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-NTKAVQCA.js");
3708
+ const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-6VNMKD6G.js");
3701
3709
  initializeToolRegistry2({
3702
3710
  sources: sourceConfigsData.sources,
3703
3711
  tools: sourceConfigsData.tools
@@ -2,7 +2,7 @@ import {
2
2
  ToolRegistry,
3
3
  getToolRegistry,
4
4
  initializeToolRegistry
5
- } from "./chunk-WCXOWHL3.js";
5
+ } from "./chunk-LUNM7TUY.js";
6
6
  export {
7
7
  ToolRegistry,
8
8
  getToolRegistry,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bytebase/dbhub",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "mcpName": "io.github.bytebase/dbhub",
5
5
  "description": "Minimal, token-efficient Database MCP Server for PostgreSQL, MySQL, SQL Server, SQLite, MariaDB",
6
6
  "repository": {