@dbx-app/node-core 0.4.7 → 0.4.9

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/README.md CHANGED
@@ -21,13 +21,7 @@ Other DBX connection types can be routed through DBX Desktop bridge integrations
21
21
  ## Public Modules
22
22
 
23
23
  ```ts
24
- import {
25
- createBackend,
26
- loadConnections,
27
- getDbxDiagnostics,
28
- evaluateSqlSafety,
29
- buildSchemaContext,
30
- } from "@dbx-app/node-core";
24
+ import { createBackend, loadConnections, getDbxDiagnostics, evaluateSqlSafety, buildSchemaContext } from "@dbx-app/node-core";
31
25
  ```
32
26
 
33
27
  The package is intended as a shared implementation layer for official DBX Node packages. Applications should prefer `@dbx-app/cli` for terminal workflows and `@dbx-app/mcp-server` for MCP clients.
package/dist/backend.js CHANGED
@@ -1,5 +1,5 @@
1
- import { addConnection as desktopAddConnection, findConnection as desktopFindConnection, loadConnections as desktopLoadConnections, removeConnection as desktopRemoveConnection, } from "./connections.js";
2
- import { closeDatabaseResources as desktopCloseDatabaseResources, describeTable as desktopDescribeTable, executeQuery as desktopExecuteQuery, listTables as desktopListTables, } from "./database.js";
1
+ import { addConnection as desktopAddConnection, findConnection as desktopFindConnection, loadConnections as desktopLoadConnections, removeConnection as desktopRemoveConnection } from "./connections.js";
2
+ import { closeDatabaseResources as desktopCloseDatabaseResources, describeTable as desktopDescribeTable, executeQuery as desktopExecuteQuery, listTables as desktopListTables } from "./database.js";
3
3
  export async function createBackend(env = process.env) {
4
4
  if (env.DBX_WEB_URL) {
5
5
  return await import("./web-backend.js");
@@ -19,6 +19,8 @@ export interface ConnectionConfig {
19
19
  redis_sentinel_username?: string;
20
20
  redis_sentinel_password?: string;
21
21
  redis_sentinel_tls?: boolean;
22
+ redis_key_separator?: string;
23
+ read_only?: boolean;
22
24
  }
23
25
  export type TransportLayerConfig = ({
24
26
  type: "ssh";
@@ -37,6 +39,7 @@ export interface SshTunnelConfig {
37
39
  key_passphrase?: string;
38
40
  connect_timeout_secs?: number;
39
41
  expose_lan?: boolean;
42
+ use_ssh_agent?: boolean;
40
43
  }
41
44
  export interface ProxyTunnelConfig {
42
45
  id: string;
@@ -32,9 +32,7 @@ function openDb(readonly = false, path = defaultDbPath()) {
32
32
  return new Database(path, { readonly });
33
33
  }
34
34
  function getSecret(db, connectionId, key) {
35
- const row = db
36
- .prepare("SELECT secret FROM connection_secrets WHERE connection_id = ? AND key = ?")
37
- .get(connectionId, key);
35
+ const row = db.prepare("SELECT secret FROM connection_secrets WHERE connection_id = ? AND key = ?").get(connectionId, key);
38
36
  return row?.secret ?? "";
39
37
  }
40
38
  function transportLayerSecretSegment(index, layer) {
@@ -69,6 +67,7 @@ function normalizeTransportLayers(config) {
69
67
  key_passphrase: config.ssh_key_passphrase || "",
70
68
  connect_timeout_secs: config.ssh_connect_timeout_secs || 5,
71
69
  expose_lan: !!config.ssh_expose_lan,
70
+ use_ssh_agent: false,
72
71
  });
73
72
  }
74
73
  if (config.proxy_enabled && config.proxy_host) {
@@ -89,19 +88,11 @@ function hydrateTransportLayerSecrets(db, config, connectionId) {
89
88
  config.transport_layers = normalizeTransportLayers(config);
90
89
  config.transport_layers.forEach((layer, index) => {
91
90
  if (layer.type === "ssh") {
92
- layer.password ||=
93
- getSecret(db, connectionId, transportLayerSshPasswordKey(index, layer)) ||
94
- (layer.id === "legacy" ? getSecret(db, connectionId, "ssh_password") : getSecret(db, connectionId, `ssh_tunnels.${layer.id || index}.password`));
95
- layer.key_passphrase ||=
96
- getSecret(db, connectionId, transportLayerSshKeyPassphraseKey(index, layer)) ||
97
- (layer.id === "legacy"
98
- ? getSecret(db, connectionId, "ssh_key_passphrase")
99
- : getSecret(db, connectionId, `ssh_tunnels.${layer.id || index}.key_passphrase`));
91
+ layer.password ||= getSecret(db, connectionId, transportLayerSshPasswordKey(index, layer)) || (layer.id === "legacy" ? getSecret(db, connectionId, "ssh_password") : getSecret(db, connectionId, `ssh_tunnels.${layer.id || index}.password`));
92
+ layer.key_passphrase ||= getSecret(db, connectionId, transportLayerSshKeyPassphraseKey(index, layer)) || (layer.id === "legacy" ? getSecret(db, connectionId, "ssh_key_passphrase") : getSecret(db, connectionId, `ssh_tunnels.${layer.id || index}.key_passphrase`));
100
93
  }
101
94
  else {
102
- layer.password ||=
103
- getSecret(db, connectionId, transportLayerProxyPasswordKey(index, layer)) ||
104
- (layer.id === "legacy-proxy" ? getSecret(db, connectionId, "proxy_password") : "");
95
+ layer.password ||= getSecret(db, connectionId, transportLayerProxyPasswordKey(index, layer)) || (layer.id === "legacy-proxy" ? getSecret(db, connectionId, "proxy_password") : "");
105
96
  }
106
97
  });
107
98
  }
@@ -176,9 +167,7 @@ export async function inspectConnectionStore(options = {}) {
176
167
  return diagnostics;
177
168
  }
178
169
  function tableExists(db, name) {
179
- const row = db
180
- .prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?")
181
- .get(name);
170
+ const row = db.prepare("SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = ?").get(name);
182
171
  return !!row;
183
172
  }
184
173
  export async function findConnection(name) {
package/dist/database.js CHANGED
@@ -274,7 +274,9 @@ function resolveTimeoutMs(options) {
274
274
  function convertBridgeQueryResult(result, options) {
275
275
  const rows = result.rows.slice(0, resolveMaxRows(options)).map((row) => {
276
276
  const obj = {};
277
- result.columns.forEach((col, i) => { obj[col] = row[i]; });
277
+ result.columns.forEach((col, i) => {
278
+ obj[col] = row[i];
279
+ });
278
280
  return obj;
279
281
  });
280
282
  return { columns: result.columns, rows, row_count: rows.length };
@@ -1,7 +1,7 @@
1
1
  export declare const DIRECT_QUERY_TYPES: readonly ["postgres", "redshift", "mysql", "doris", "starrocks", "sqlite", "rqlite", "gaussdb", "kwdb", "opengauss"];
2
2
  export type DirectQueryType = (typeof DIRECT_QUERY_TYPES)[number];
3
3
  export declare function isDirectQueryType(dbType: string): dbType is DirectQueryType;
4
- export declare const BRIDGE_REQUIRED_TYPES: readonly ["redis", "mongodb", "duckdb", "clickhouse", "sqlserver", "oracle", "elasticsearch", "dameng", "kingbase", "highgo", "vastbase", "goldendb", "databend", "yashandb", "databricks", "saphana", "teradata", "vertica", "firebird", "exasol", "oceanbase-oracle", "gbase", "tdengine", "iotdb", "h2", "snowflake", "trino", "hive", "db2", "informix", "iris", "neo4j", "cassandra", "bigquery", "kylin", "sundb", "xugu", "jdbc", "access"];
4
+ export declare const BRIDGE_REQUIRED_TYPES: readonly ["redis", "mongodb", "duckdb", "clickhouse", "sqlserver", "oracle", "elasticsearch", "etcd", "dameng", "kingbase", "highgo", "vastbase", "goldendb", "databend", "yashandb", "databricks", "saphana", "teradata", "vertica", "firebird", "exasol", "oceanbase-oracle", "gbase", "tdengine", "iotdb", "h2", "snowflake", "trino", "hive", "db2", "informix", "iris", "neo4j", "cassandra", "bigquery", "kylin", "sundb", "xugu", "jdbc", "access", "influxdb"];
5
5
  export interface DbxDiagnostics {
6
6
  appDataDir: string;
7
7
  dbPath: string;
@@ -1,18 +1,7 @@
1
1
  import { access, readFile } from "node:fs/promises";
2
2
  import { bridgePortFilePath, dbPath, appDataDir } from "./paths.js";
3
3
  import { inspectConnectionStore } from "./connections.js";
4
- export const DIRECT_QUERY_TYPES = [
5
- "postgres",
6
- "redshift",
7
- "mysql",
8
- "doris",
9
- "starrocks",
10
- "sqlite",
11
- "rqlite",
12
- "gaussdb",
13
- "kwdb",
14
- "opengauss",
15
- ];
4
+ export const DIRECT_QUERY_TYPES = ["postgres", "redshift", "mysql", "doris", "starrocks", "sqlite", "rqlite", "gaussdb", "kwdb", "opengauss"];
16
5
  const DIRECT_QUERY_TYPE_SET = new Set(DIRECT_QUERY_TYPES);
17
6
  export function isDirectQueryType(dbType) {
18
7
  return DIRECT_QUERY_TYPE_SET.has(dbType);
@@ -25,6 +14,7 @@ export const BRIDGE_REQUIRED_TYPES = [
25
14
  "sqlserver",
26
15
  "oracle",
27
16
  "elasticsearch",
17
+ "etcd",
28
18
  "dameng",
29
19
  "kingbase",
30
20
  "highgo",
@@ -57,6 +47,7 @@ export const BRIDGE_REQUIRED_TYPES = [
57
47
  "xugu",
58
48
  "jdbc",
59
49
  "access",
50
+ "influxdb",
60
51
  ];
61
52
  export async function getDbxDiagnostics() {
62
53
  const portFile = bridgePortFilePath();
@@ -79,9 +70,7 @@ export async function getDbxDiagnostics() {
79
70
  loadConnectionsOk: connectionStore.loadConnectionsOk,
80
71
  loadedConnectionCount: connectionStore.loadedConnectionCount,
81
72
  loadConnectionsError: connectionStore.loadConnectionsError,
82
- loadConnectionsHint: connectionStore.loadConnectionsError
83
- ? connectionStoreHint(connectionStore.loadConnectionsError)
84
- : undefined,
73
+ loadConnectionsHint: connectionStore.loadConnectionsError ? connectionStoreHint(connectionStore.loadConnectionsError) : undefined,
85
74
  bridgePortFile: portFile,
86
75
  bridgePortFileExists,
87
76
  bridgeUrl,
@@ -3,9 +3,7 @@ export async function buildSchemaContext(backend, config, options = {}) {
3
3
  const maxTables = Math.max(1, Math.min(options.maxTables ?? DEFAULT_MAX_TABLES, 20));
4
4
  const availableTables = await backend.listTables(config, options.schema);
5
5
  const requested = new Set((options.tables ?? []).map((table) => table.toLowerCase()));
6
- const selected = requested.size
7
- ? availableTables.filter((table) => requested.has(table.name.toLowerCase()))
8
- : availableTables.slice(0, maxTables);
6
+ const selected = requested.size ? availableTables.filter((table) => requested.has(table.name.toLowerCase())) : availableTables.slice(0, maxTables);
9
7
  const limited = selected.slice(0, maxTables);
10
8
  const tables = await Promise.all(limited.map(async (table) => ({
11
9
  name: table.name,
@@ -21,19 +19,10 @@ export async function buildSchemaContext(backend, config, options = {}) {
21
19
  };
22
20
  }
23
21
  export function formatSchemaContext(context) {
24
- const header = [
25
- `Connection: ${context.connection}`,
26
- context.database ? `Database: ${context.database}` : "",
27
- context.schema ? `Schema: ${context.schema}` : "",
28
- ].filter(Boolean);
22
+ const header = [`Connection: ${context.connection}`, context.database ? `Database: ${context.database}` : "", context.schema ? `Schema: ${context.schema}` : ""].filter(Boolean);
29
23
  const sections = context.tables.map((table) => {
30
24
  const lines = table.columns.map((column) => {
31
- const parts = [
32
- column.name,
33
- column.data_type,
34
- column.is_nullable ? "NULL" : "NOT NULL",
35
- column.is_primary_key ? "PK" : "",
36
- ].filter(Boolean);
25
+ const parts = [column.name, column.data_type, column.is_nullable ? "NULL" : "NOT NULL", column.is_primary_key ? "PK" : ""].filter(Boolean);
37
26
  return `- ${parts.join(" ")}${column.comment ? ` -- ${column.comment}` : ""}`;
38
27
  });
39
28
  return [`## ${table.name}`, `Type: ${table.type}`, ...lines].join("\n");
@@ -1,4 +1,4 @@
1
- import { evaluateMongoAggregateSafety, evaluateMongoWriteSafety, inferMongoColumns, mongoDocumentsToQueryResult, parseMongoAggregateCommand, parseMongoCountDocumentsCommand, parseMongoFindCommand, parseMongoGetIndexesCommand, parseMongoWriteCommand, } from "./database.js";
1
+ import { evaluateMongoAggregateSafety, evaluateMongoWriteSafety, inferMongoColumns, mongoDocumentsToQueryResult, parseMongoAggregateCommand, parseMongoCountDocumentsCommand, parseMongoFindCommand, parseMongoGetIndexesCommand, parseMongoWriteCommand } from "./database.js";
2
2
  import { sqlSafetyFromEnv } from "./sql-safety.js";
3
3
  const baseUrl = process.env.DBX_WEB_URL.replace(/\/+$/, "");
4
4
  const password = process.env.DBX_WEB_PASSWORD || "";
package/package.json CHANGED
@@ -1,14 +1,12 @@
1
1
  {
2
2
  "name": "@dbx-app/node-core",
3
- "version": "0.4.7",
3
+ "version": "0.4.9",
4
4
  "description": "Shared Node.js database and DBX connection utilities for DBX CLI and MCP server",
5
- "type": "module",
6
- "engines": {
7
- "node": ">=22.13.0"
8
- },
5
+ "license": "Apache-2.0",
9
6
  "files": [
10
7
  "dist"
11
8
  ],
9
+ "type": "module",
12
10
  "exports": {
13
11
  ".": "./dist/index.js",
14
12
  "./backend": "./dist/backend.js",
@@ -22,7 +20,6 @@
22
20
  "./schema-context": "./dist/schema-context.js",
23
21
  "./sql-safety": "./dist/sql-safety.js"
24
22
  },
25
- "license": "Apache-2.0",
26
23
  "dependencies": {
27
24
  "better-sqlite3": "^12.9.0",
28
25
  "keytar": "^7.9.0",
@@ -36,6 +33,9 @@
36
33
  "tsx": "^4.19.4",
37
34
  "typescript": "^5.8.3"
38
35
  },
36
+ "engines": {
37
+ "node": ">=22.13.0"
38
+ },
39
39
  "scripts": {
40
40
  "test": "vitest run --config vitest.config.ts",
41
41
  "build": "tsc"