@dbx-app/node-core 0.4.4 → 0.4.5
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/database.js +4 -16
- package/dist/diagnostics.d.ts +2 -0
- package/dist/diagnostics.js +4 -0
- package/dist/entrypoint.d.ts +1 -0
- package/dist/entrypoint.js +20 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/sql-safety.d.ts +2 -0
- package/dist/sql-safety.js +19 -4
- package/package.json +2 -1
package/dist/database.js
CHANGED
|
@@ -4,6 +4,7 @@ import { join } from "node:path";
|
|
|
4
4
|
import { homedir, platform } from "node:os";
|
|
5
5
|
import Database from "better-sqlite3";
|
|
6
6
|
import { sqlSafetyFromEnv } from "./sql-safety.js";
|
|
7
|
+
import { isDirectQueryType } from "./diagnostics.js";
|
|
7
8
|
const MAX_ROWS = 100;
|
|
8
9
|
const IDLE_TIMEOUT_MS = 5 * 60 * 1000;
|
|
9
10
|
const QUERY_TIMEOUT_MS = 30_000;
|
|
@@ -194,19 +195,6 @@ function portBytes(port) {
|
|
|
194
195
|
function isMysqlType(dbType) {
|
|
195
196
|
return dbType === "mysql" || dbType === "doris" || dbType === "starrocks";
|
|
196
197
|
}
|
|
197
|
-
function isDirectType(dbType) {
|
|
198
|
-
switch (dbType) {
|
|
199
|
-
case "postgres":
|
|
200
|
-
case "redshift":
|
|
201
|
-
case "mysql":
|
|
202
|
-
case "doris":
|
|
203
|
-
case "starrocks":
|
|
204
|
-
case "sqlite":
|
|
205
|
-
return true;
|
|
206
|
-
default:
|
|
207
|
-
return false;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
198
|
function bridgeAppDataDir() {
|
|
211
199
|
const home = homedir();
|
|
212
200
|
switch (platform()) {
|
|
@@ -366,7 +354,7 @@ export async function executeQuery(config, sql, options) {
|
|
|
366
354
|
}
|
|
367
355
|
throw new Error("Use MongoDB shell-style commands, for example: db.projects.find({}).limit(100), db.projects.countDocuments({}), db.projects.insertOne({...}), db.projects.updateOne({...}, {$set: {...}}), or db.projects.deleteOne({...})");
|
|
368
356
|
}
|
|
369
|
-
if (
|
|
357
|
+
if (isDirectQueryType(config.db_type)) {
|
|
370
358
|
return query(config, sql, undefined, options);
|
|
371
359
|
}
|
|
372
360
|
const result = await withTimeout(bridgeDataRequest("/data/execute-query", {
|
|
@@ -389,7 +377,7 @@ export async function listTables(config, schema) {
|
|
|
389
377
|
const result = await query(config, `SELECT name, type FROM sqlite_master WHERE type IN ('table', 'view') AND name NOT LIKE 'sqlite_%' ORDER BY name`);
|
|
390
378
|
return result.rows.map((r) => ({ name: String(r.name || ""), type: String(r.type || "table") }));
|
|
391
379
|
}
|
|
392
|
-
if (!
|
|
380
|
+
if (!isDirectQueryType(config.db_type)) {
|
|
393
381
|
const tables = await bridgeDataRequest("/data/list-tables", {
|
|
394
382
|
connection_name: config.name,
|
|
395
383
|
database: config.database || "",
|
|
@@ -422,7 +410,7 @@ export async function describeTable(config, table, schema) {
|
|
|
422
410
|
comment: null,
|
|
423
411
|
}));
|
|
424
412
|
}
|
|
425
|
-
if (!
|
|
413
|
+
if (!isDirectQueryType(config.db_type)) {
|
|
426
414
|
const columns = await bridgeDataRequest("/data/describe-table", {
|
|
427
415
|
connection_name: config.name,
|
|
428
416
|
database: config.database || "",
|
package/dist/diagnostics.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export declare const DIRECT_QUERY_TYPES: readonly ["postgres", "redshift", "mysql", "doris", "starrocks", "sqlite", "gaussdb", "opengauss"];
|
|
2
|
+
export type DirectQueryType = (typeof DIRECT_QUERY_TYPES)[number];
|
|
3
|
+
export declare function isDirectQueryType(dbType: string): dbType is DirectQueryType;
|
|
2
4
|
export declare const BRIDGE_REQUIRED_TYPES: readonly ["redis", "mongodb", "duckdb", "clickhouse", "sqlserver", "oracle", "elasticsearch", "dameng", "kingbase", "highgo", "vastbase", "goldendb", "yashandb", "databricks", "saphana", "teradata", "vertica", "firebird", "exasol", "oceanbase-oracle", "gbase", "tdengine", "h2", "snowflake", "trino", "hive", "db2", "informix", "neo4j", "cassandra", "bigquery", "kylin", "sundb", "xugu", "jdbc", "access"];
|
|
3
5
|
export interface DbxDiagnostics {
|
|
4
6
|
appDataDir: string;
|
package/dist/diagnostics.js
CHANGED
|
@@ -2,6 +2,10 @@ import { access, readFile } from "node:fs/promises";
|
|
|
2
2
|
import { bridgePortFilePath, dbPath, appDataDir } from "./paths.js";
|
|
3
3
|
import { inspectConnectionStore } from "./connections.js";
|
|
4
4
|
export const DIRECT_QUERY_TYPES = ["postgres", "redshift", "mysql", "doris", "starrocks", "sqlite", "gaussdb", "opengauss"];
|
|
5
|
+
const DIRECT_QUERY_TYPE_SET = new Set(DIRECT_QUERY_TYPES);
|
|
6
|
+
export function isDirectQueryType(dbType) {
|
|
7
|
+
return DIRECT_QUERY_TYPE_SET.has(dbType);
|
|
8
|
+
}
|
|
5
9
|
export const BRIDGE_REQUIRED_TYPES = [
|
|
6
10
|
"redis",
|
|
7
11
|
"mongodb",
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isMainModule(moduleUrl: string, argvPath: string | undefined): boolean;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { realpathSync } from "node:fs";
|
|
2
|
+
import { normalize, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath } from "node:url";
|
|
4
|
+
export function isMainModule(moduleUrl, argvPath) {
|
|
5
|
+
if (!argvPath)
|
|
6
|
+
return false;
|
|
7
|
+
return normalizeEntryPath(fileURLToPath(moduleUrl)) === normalizeEntryPath(argvPath);
|
|
8
|
+
}
|
|
9
|
+
function normalizeEntryPath(path) {
|
|
10
|
+
const normalized = normalize(realpathIfPossible(resolve(path)));
|
|
11
|
+
return process.platform === "win32" ? normalized.toLowerCase() : normalized;
|
|
12
|
+
}
|
|
13
|
+
function realpathIfPossible(path) {
|
|
14
|
+
try {
|
|
15
|
+
return realpathSync.native(path);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return path;
|
|
19
|
+
}
|
|
20
|
+
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/sql-safety.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface SqlSafetyOptions {
|
|
2
2
|
allowWrites?: boolean;
|
|
3
3
|
allowDangerous?: boolean;
|
|
4
|
+
allowMultipleStatements?: boolean;
|
|
4
5
|
}
|
|
5
6
|
export interface SqlSafetyDecision {
|
|
6
7
|
allowed: boolean;
|
|
@@ -8,3 +9,4 @@ export interface SqlSafetyDecision {
|
|
|
8
9
|
}
|
|
9
10
|
export declare function evaluateSqlSafety(sql: string, options?: SqlSafetyOptions): SqlSafetyDecision;
|
|
10
11
|
export declare function sqlSafetyFromEnv(env?: NodeJS.ProcessEnv): SqlSafetyOptions;
|
|
12
|
+
export declare function splitSqlStatements(sql: string): string[];
|
package/dist/sql-safety.js
CHANGED
|
@@ -4,9 +4,24 @@ export function evaluateSqlSafety(sql, options = {}) {
|
|
|
4
4
|
const statements = splitSqlStatements(sql);
|
|
5
5
|
if (statements.length === 0)
|
|
6
6
|
return { allowed: false, reason: "SQL is empty." };
|
|
7
|
-
if (statements.length > 1)
|
|
8
|
-
return { allowed: false, reason: "Only one SQL statement is allowed per
|
|
9
|
-
|
|
7
|
+
if (statements.length > 1 && !options.allowMultipleStatements) {
|
|
8
|
+
return { allowed: false, reason: "Only one SQL statement is allowed per query." };
|
|
9
|
+
}
|
|
10
|
+
for (let i = 0; i < statements.length; i++) {
|
|
11
|
+
const decision = evaluateSingleSqlStatementSafety(statements[i], options);
|
|
12
|
+
if (!decision.allowed && statements.length > 1) {
|
|
13
|
+
return {
|
|
14
|
+
allowed: false,
|
|
15
|
+
reason: `Statement ${i + 1}: ${decision.reason ?? "SQL blocked."}`,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
if (!decision.allowed)
|
|
19
|
+
return decision;
|
|
20
|
+
}
|
|
21
|
+
return { allowed: true };
|
|
22
|
+
}
|
|
23
|
+
function evaluateSingleSqlStatementSafety(sql, options = {}) {
|
|
24
|
+
const normalized = stripSqlCommentsAndStrings(sql).trim();
|
|
10
25
|
const firstKeyword = normalized.match(/^[a-zA-Z_]+/)?.[0]?.toLowerCase();
|
|
11
26
|
if (!firstKeyword)
|
|
12
27
|
return { allowed: false, reason: "SQL statement is not recognized." };
|
|
@@ -37,7 +52,7 @@ export function sqlSafetyFromEnv(env = process.env) {
|
|
|
37
52
|
allowDangerous: env.DBX_MCP_ALLOW_DANGEROUS_SQL === "1" || env.DBX_MCP_ALLOW_DANGEROUS_SQL === "true",
|
|
38
53
|
};
|
|
39
54
|
}
|
|
40
|
-
function splitSqlStatements(sql) {
|
|
55
|
+
export function splitSqlStatements(sql) {
|
|
41
56
|
const statements = [];
|
|
42
57
|
let current = "";
|
|
43
58
|
let quote = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dbx-app/node-core",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.5",
|
|
4
4
|
"description": "Shared Node.js database and DBX connection utilities for DBX CLI and MCP server",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"./connections": "./dist/connections.js",
|
|
17
17
|
"./database": "./dist/database.js",
|
|
18
18
|
"./diagnostics": "./dist/diagnostics.js",
|
|
19
|
+
"./entrypoint": "./dist/entrypoint.js",
|
|
19
20
|
"./format": "./dist/format.js",
|
|
20
21
|
"./paths": "./dist/paths.js",
|
|
21
22
|
"./schema-context": "./dist/schema-context.js",
|