@bytebase/dbhub 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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";
@@ -3697,7 +3697,7 @@ See documentation for more details on configuring database connections.
3697
3697
  const sources = sourceConfigsData.sources;
3698
3698
  console.error(`Configuration source: ${sourceConfigsData.source}`);
3699
3699
  await connectorManager.connectWithSources(sources);
3700
- const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-NTKAVQCA.js");
3700
+ const { initializeToolRegistry: initializeToolRegistry2 } = await import("./registry-6VNMKD6G.js");
3701
3701
  initializeToolRegistry2({
3702
3702
  sources: sourceConfigsData.sources,
3703
3703
  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.0",
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": {