@eamonboyle/mssql-mcp 1.1.0 → 1.2.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.
- package/README.md +134 -22
- package/dist/__tests__/ExplainQueryTool.test.d.ts +2 -0
- package/dist/__tests__/ExplainQueryTool.test.d.ts.map +1 -0
- package/dist/__tests__/ExplainQueryTool.test.js +96 -0
- package/dist/__tests__/ExplainQueryTool.test.js.map +1 -0
- package/dist/__tests__/config.test.d.ts +2 -0
- package/dist/__tests__/config.test.d.ts.map +1 -0
- package/dist/__tests__/config.test.js +29 -0
- package/dist/__tests__/config.test.js.map +1 -0
- package/dist/__tests__/db.test.d.ts +1 -1
- package/dist/__tests__/db.test.js +203 -203
- package/dist/__tests__/promptRegistry.test.d.ts +2 -0
- package/dist/__tests__/promptRegistry.test.d.ts.map +1 -0
- package/dist/__tests__/promptRegistry.test.js +40 -0
- package/dist/__tests__/promptRegistry.test.js.map +1 -0
- package/dist/__tests__/resourceRegistry.test.d.ts +2 -0
- package/dist/__tests__/resourceRegistry.test.d.ts.map +1 -0
- package/dist/__tests__/resourceRegistry.test.js +40 -0
- package/dist/__tests__/resourceRegistry.test.js.map +1 -0
- package/dist/__tests__/schema.test.d.ts +2 -0
- package/dist/__tests__/schema.test.d.ts.map +1 -0
- package/dist/__tests__/schema.test.js +130 -0
- package/dist/__tests__/schema.test.js.map +1 -0
- package/dist/__tests__/sql.test.d.ts +2 -0
- package/dist/__tests__/sql.test.d.ts.map +1 -0
- package/dist/__tests__/sql.test.js +35 -0
- package/dist/__tests__/sql.test.js.map +1 -0
- package/dist/__tests__/toolRegistry.test.d.ts +2 -0
- package/dist/__tests__/toolRegistry.test.d.ts.map +1 -0
- package/dist/__tests__/toolRegistry.test.js +47 -0
- package/dist/__tests__/toolRegistry.test.js.map +1 -0
- package/dist/__tests__/validation.test.d.ts +1 -1
- package/dist/__tests__/validation.test.js +110 -110
- package/dist/__tests__/validation.test.js.map +1 -1
- package/dist/__tests__/writeTools.test.d.ts +2 -0
- package/dist/__tests__/writeTools.test.d.ts.map +1 -0
- package/dist/__tests__/writeTools.test.js +115 -0
- package/dist/__tests__/writeTools.test.js.map +1 -0
- package/dist/config.d.ts +5 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +34 -0
- package/dist/config.js.map +1 -0
- package/dist/db.d.ts +28 -24
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +144 -112
- package/dist/db.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +70 -122
- package/dist/index.js.map +1 -1
- package/dist/promptRegistry.d.ts +16 -0
- package/dist/promptRegistry.d.ts.map +1 -0
- package/dist/promptRegistry.js +107 -0
- package/dist/promptRegistry.js.map +1 -0
- package/dist/resourceRegistry.d.ts +12 -0
- package/dist/resourceRegistry.d.ts.map +1 -0
- package/dist/resourceRegistry.js +172 -0
- package/dist/resourceRegistry.js.map +1 -0
- package/dist/schema.d.ts +41 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +211 -0
- package/dist/schema.js.map +1 -0
- package/dist/sql.d.ts +7 -0
- package/dist/sql.d.ts.map +1 -0
- package/dist/sql.js +73 -0
- package/dist/sql.js.map +1 -0
- package/dist/toolRegistry.d.ts +16 -0
- package/dist/toolRegistry.d.ts.map +1 -0
- package/dist/toolRegistry.js +401 -0
- package/dist/toolRegistry.js.map +1 -0
- package/dist/tools/CreateIndexTool.d.ts +30 -23
- package/dist/tools/CreateIndexTool.d.ts.map +1 -1
- package/dist/tools/CreateIndexTool.js +47 -77
- package/dist/tools/CreateIndexTool.js.map +1 -1
- package/dist/tools/CreateTableTool.d.ts +18 -11
- package/dist/tools/CreateTableTool.d.ts.map +1 -1
- package/dist/tools/CreateTableTool.js +37 -61
- package/dist/tools/CreateTableTool.js.map +1 -1
- package/dist/tools/DeleteDataTool.d.ts +22 -0
- package/dist/tools/DeleteDataTool.d.ts.map +1 -0
- package/dist/tools/DeleteDataTool.js +35 -0
- package/dist/tools/DeleteDataTool.js.map +1 -0
- package/dist/tools/DescribeObjectTool.d.ts +21 -0
- package/dist/tools/DescribeObjectTool.d.ts.map +1 -0
- package/dist/tools/DescribeObjectTool.js +31 -0
- package/dist/tools/DescribeObjectTool.js.map +1 -0
- package/dist/tools/DescribeTableTool.d.ts +19 -20
- package/dist/tools/DescribeTableTool.d.ts.map +1 -1
- package/dist/tools/DescribeTableTool.js +23 -44
- package/dist/tools/DescribeTableTool.js.map +1 -1
- package/dist/tools/DropTableTool.d.ts +13 -11
- package/dist/tools/DropTableTool.d.ts.map +1 -1
- package/dist/tools/DropTableTool.js +30 -44
- package/dist/tools/DropTableTool.js.map +1 -1
- package/dist/tools/ExplainQueryTool.d.ts +32 -0
- package/dist/tools/ExplainQueryTool.d.ts.map +1 -0
- package/dist/tools/ExplainQueryTool.js +102 -0
- package/dist/tools/ExplainQueryTool.js.map +1 -0
- package/dist/tools/InsertDataTool.d.ts +20 -16
- package/dist/tools/InsertDataTool.d.ts.map +1 -1
- package/dist/tools/InsertDataTool.js +91 -108
- package/dist/tools/InsertDataTool.js.map +1 -1
- package/dist/tools/ListObjectsTool.d.ts +20 -0
- package/dist/tools/ListObjectsTool.d.ts.map +1 -0
- package/dist/tools/ListObjectsTool.js +26 -0
- package/dist/tools/ListObjectsTool.js.map +1 -0
- package/dist/tools/ListTableTool.d.ts +20 -16
- package/dist/tools/ListTableTool.d.ts.map +1 -1
- package/dist/tools/ListTableTool.js +32 -51
- package/dist/tools/ListTableTool.js.map +1 -1
- package/dist/tools/ReadDataTool.d.ts +35 -33
- package/dist/tools/ReadDataTool.d.ts.map +1 -1
- package/dist/tools/ReadDataTool.js +92 -105
- package/dist/tools/ReadDataTool.js.map +1 -1
- package/dist/tools/SearchDataTool.d.ts +27 -0
- package/dist/tools/SearchDataTool.d.ts.map +1 -0
- package/dist/tools/SearchDataTool.js +61 -0
- package/dist/tools/SearchDataTool.js.map +1 -0
- package/dist/tools/UpdateDataTool.d.ts +21 -16
- package/dist/tools/UpdateDataTool.d.ts.map +1 -1
- package/dist/tools/UpdateDataTool.js +45 -65
- package/dist/tools/UpdateDataTool.js.map +1 -1
- package/dist/validation.d.ts +13 -13
- package/dist/validation.js +133 -133
- package/dist/validation.js.map +1 -1
- package/dist/writeSafety.d.ts +21 -0
- package/dist/writeSafety.d.ts.map +1 -0
- package/dist/writeSafety.js +169 -0
- package/dist/writeSafety.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.test.js","sourceRoot":"","sources":["../../src/__tests__/schema.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/sql.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { buildQualifiedName, getFriendlyObjectType, getObjectTypeCodes, quoteIdentifier, } from "../sql.js";
|
|
3
|
+
describe("sql helpers", () => {
|
|
4
|
+
it("quotes safe identifiers", () => {
|
|
5
|
+
expect(quoteIdentifier("Users")).toBe("[Users]");
|
|
6
|
+
expect(buildQualifiedName("Users", "dbo")).toBe("[dbo].[Users]");
|
|
7
|
+
expect(quoteIdentifier("Order Details")).toBe("[Order Details]");
|
|
8
|
+
expect(quoteIdentifier("Users]Archive")).toBe("[Users]]Archive]");
|
|
9
|
+
});
|
|
10
|
+
it("rejects empty or control-character identifiers", () => {
|
|
11
|
+
expect(() => quoteIdentifier("")).toThrow("Invalid identifier.");
|
|
12
|
+
expect(() => buildQualifiedName("", "dbo")).toThrow("Invalid object name.");
|
|
13
|
+
expect(() => buildQualifiedName("Users", "dbo\u0000")).toThrow("Invalid schema name.");
|
|
14
|
+
expect(() => quoteIdentifier("Users\u0000Archive")).toThrow("Invalid identifier.");
|
|
15
|
+
});
|
|
16
|
+
it("maps friendly object types", () => {
|
|
17
|
+
expect(getFriendlyObjectType("U")).toBe("table");
|
|
18
|
+
expect(getFriendlyObjectType("V")).toBe("view");
|
|
19
|
+
expect(getFriendlyObjectType("P")).toBe("procedure");
|
|
20
|
+
expect(getFriendlyObjectType("FN")).toBe("function");
|
|
21
|
+
expect(getFriendlyObjectType("TR")).toBe("trigger");
|
|
22
|
+
});
|
|
23
|
+
it("resolves object type filters", () => {
|
|
24
|
+
expect(getObjectTypeCodes(["table", "view"])).toEqual(["U", "V"]);
|
|
25
|
+
expect(getObjectTypeCodes(["function"])).toEqual([
|
|
26
|
+
"FN",
|
|
27
|
+
"IF",
|
|
28
|
+
"TF",
|
|
29
|
+
"FS",
|
|
30
|
+
"FT",
|
|
31
|
+
]);
|
|
32
|
+
expect(() => getObjectTypeCodes(["queue"])).toThrow("Unsupported object type 'queue'. Expected one of: table, view, procedure, function, trigger.");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=sql.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sql.test.js","sourceRoot":"","sources":["../../src/__tests__/sql.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,GAChB,MAAM,WAAW,CAAC;AAEnB,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,yBAAyB,EAAE,GAAG,EAAE;QACjC,MAAM,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QACjE,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;QACjE,MAAM,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,kBAAkB,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC,CAAC;QACjE,MAAM,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,sBAAsB,CAAC,CAAC;QAC5E,MAAM,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,OAAO,CAC5D,sBAAsB,CACvB,CAAC;QACF,MAAM,CAAC,GAAG,EAAE,CAAC,eAAe,CAAC,oBAAoB,CAAC,CAAC,CAAC,OAAO,CACzD,qBAAqB,CACtB,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4BAA4B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACjD,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAChD,MAAM,CAAC,qBAAqB,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;QACrD,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACrD,MAAM,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,kBAAkB,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QAClE,MAAM,CAAC,kBAAkB,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC/C,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;YACJ,IAAI;SACL,CAAC,CAAC;QACH,MAAM,CAAC,GAAG,EAAE,CAAC,kBAAkB,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CACjD,8FAA8F,CAC/F,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolRegistry.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/toolRegistry.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import { toolDefinitions } from "../toolRegistry.js";
|
|
3
|
+
function getToolSchema(name) {
|
|
4
|
+
const definition = toolDefinitions.find((tool) => tool.tool.name === name);
|
|
5
|
+
if (!definition) {
|
|
6
|
+
throw new Error(`Missing tool definition for ${name}`);
|
|
7
|
+
}
|
|
8
|
+
return definition.inputSchema;
|
|
9
|
+
}
|
|
10
|
+
describe("toolRegistry write schemas", () => {
|
|
11
|
+
it("requires structured filters for update_data", () => {
|
|
12
|
+
const schema = getToolSchema("update_data");
|
|
13
|
+
expect(schema.safeParse({
|
|
14
|
+
tableName: "Users",
|
|
15
|
+
updates: { status: "active" },
|
|
16
|
+
whereClause: "id = 1",
|
|
17
|
+
}).success).toBe(false);
|
|
18
|
+
expect(schema.safeParse({
|
|
19
|
+
tableName: "Users",
|
|
20
|
+
updates: { status: "active" },
|
|
21
|
+
filters: [{ column: "id", operator: "=", value: 1 }],
|
|
22
|
+
}).success).toBe(true);
|
|
23
|
+
});
|
|
24
|
+
it("rejects unknown keys for delete_data", () => {
|
|
25
|
+
const schema = getToolSchema("delete_data");
|
|
26
|
+
expect(schema.safeParse({
|
|
27
|
+
tableName: "Users",
|
|
28
|
+
filters: [{ column: "id", operator: "=", value: 1 }],
|
|
29
|
+
extra: true,
|
|
30
|
+
}).success).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
it("rejects extra column properties for create_table", () => {
|
|
33
|
+
const schema = getToolSchema("create_table");
|
|
34
|
+
expect(schema.safeParse({
|
|
35
|
+
tableName: "Users",
|
|
36
|
+
columns: [
|
|
37
|
+
{
|
|
38
|
+
name: "id",
|
|
39
|
+
type: "INT",
|
|
40
|
+
nullable: false,
|
|
41
|
+
unexpected: "value",
|
|
42
|
+
},
|
|
43
|
+
],
|
|
44
|
+
}).success).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
//# sourceMappingURL=toolRegistry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"toolRegistry.test.js","sourceRoot":"","sources":["../../src/__tests__/toolRegistry.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAErD,SAAS,aAAa,CAAC,IAAY;IACjC,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC3E,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,EAAE,CAAC,CAAC;IACzD,CAAC;IAED,OAAO,UAAU,CAAC,WAAW,CAAC;AAChC,CAAC;AAED,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;QAE5C,MAAM,CACJ,MAAM,CAAC,SAAS,CAAC;YACf,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;YAC7B,WAAW,EAAE,QAAQ;SACtB,CAAC,CAAC,OAAO,CACX,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAEd,MAAM,CACJ,MAAM,CAAC,SAAS,CAAC;YACf,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE;YAC7B,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;SACrD,CAAC,CAAC,OAAO,CACX,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACf,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC9C,MAAM,MAAM,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;QAE5C,MAAM,CACJ,MAAM,CAAC,SAAS,CAAC;YACf,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YACpD,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC,OAAO,CACX,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC1D,MAAM,MAAM,GAAG,aAAa,CAAC,cAAc,CAAC,CAAC;QAE7C,MAAM,CACJ,MAAM,CAAC,SAAS,CAAC;YACf,SAAS,EAAE,OAAO;YAClB,OAAO,EAAE;gBACP;oBACE,IAAI,EAAE,IAAI;oBACV,IAAI,EAAE,KAAK;oBACX,QAAQ,EAAE,KAAK;oBACf,UAAU,EAAE,OAAO;iBACpB;aACF;SACF,CAAC,CAAC,OAAO,CACX,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAChB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export {};
|
|
1
|
+
export {};
|
|
2
2
|
//# sourceMappingURL=validation.test.d.ts.map
|
|
@@ -1,111 +1,111 @@
|
|
|
1
|
-
import { describe, it, expect } from "vitest";
|
|
2
|
-
import { validateReadQuery } from "../validation.js";
|
|
3
|
-
describe("validateReadQuery", () => {
|
|
4
|
-
it("accepts simple SELECT query", () => {
|
|
5
|
-
expect(validateReadQuery("SELECT * FROM movies")).toEqual({
|
|
6
|
-
isValid: true,
|
|
7
|
-
});
|
|
8
|
-
expect(validateReadQuery("SELECT id, name FROM users WHERE id = 1")).toEqual({
|
|
9
|
-
isValid: true,
|
|
10
|
-
});
|
|
11
|
-
});
|
|
12
|
-
it("rejects empty or non-string input", () => {
|
|
13
|
-
expect(validateReadQuery("")).toEqual({
|
|
14
|
-
isValid: false,
|
|
15
|
-
error: "Query must be a non-empty string",
|
|
16
|
-
});
|
|
17
|
-
expect(validateReadQuery(" ")).toEqual({
|
|
18
|
-
isValid: false,
|
|
19
|
-
error: "Query cannot be empty after removing comments",
|
|
20
|
-
});
|
|
21
|
-
expect(validateReadQuery(null)).toEqual({
|
|
22
|
-
isValid: false,
|
|
23
|
-
error: "Query must be a non-empty string",
|
|
24
|
-
});
|
|
25
|
-
});
|
|
26
|
-
it("rejects query that does not start with SELECT", () => {
|
|
27
|
-
expect(validateReadQuery("DELETE FROM users")).toEqual({
|
|
28
|
-
isValid: false,
|
|
29
|
-
error: "Query must start with SELECT for security reasons",
|
|
30
|
-
});
|
|
31
|
-
expect(validateReadQuery(" UPDATE users SET x = 1")).toEqual({
|
|
32
|
-
isValid: false,
|
|
33
|
-
error: "Query must start with SELECT for security reasons",
|
|
34
|
-
});
|
|
35
|
-
});
|
|
36
|
-
it("rejects dangerous keywords", () => {
|
|
37
|
-
expect(validateReadQuery("SELECT * FROM users; DELETE FROM logs")).toEqual({
|
|
38
|
-
isValid: false,
|
|
39
|
-
error: expect.stringContaining("Dangerous keyword"),
|
|
40
|
-
});
|
|
41
|
-
expect(validateReadQuery("SELECT * INTO backup FROM users")).toEqual({
|
|
42
|
-
isValid: false,
|
|
43
|
-
error: expect.stringContaining("Dangerous keyword"),
|
|
44
|
-
});
|
|
45
|
-
expect(validateReadQuery("SELECT * FROM users; DROP TABLE users")).toEqual({
|
|
46
|
-
isValid: false,
|
|
47
|
-
error: expect.stringContaining("Dangerous keyword"),
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
it("rejects SELECT INTO pattern", () => {
|
|
51
|
-
const result = validateReadQuery("SELECT * INTO newtable FROM users");
|
|
52
|
-
expect(result.isValid).toBe(false);
|
|
53
|
-
expect(result.error).toBeDefined();
|
|
54
|
-
});
|
|
55
|
-
it("rejects multiple statements", () => {
|
|
56
|
-
const result = validateReadQuery("SELECT 1; SELECT 2");
|
|
57
|
-
expect(result.isValid).toBe(false);
|
|
58
|
-
expect(result.error).toBeDefined();
|
|
59
|
-
});
|
|
60
|
-
it("rejects character conversion functions", () => {
|
|
61
|
-
expect(validateReadQuery("SELECT CHAR(65) FROM users")).toEqual({
|
|
62
|
-
isValid: false,
|
|
63
|
-
error: "Character conversion functions are not allowed as they may be used for obfuscation.",
|
|
64
|
-
});
|
|
65
|
-
expect(validateReadQuery("SELECT NCHAR(65) FROM users")).toEqual({
|
|
66
|
-
isValid: false,
|
|
67
|
-
error: "Character conversion functions are not allowed as they may be used for obfuscation.",
|
|
68
|
-
});
|
|
69
|
-
expect(validateReadQuery("SELECT ASCII('A') FROM users")).toEqual({
|
|
70
|
-
isValid: false,
|
|
71
|
-
error: "Character conversion functions are not allowed as they may be used for obfuscation.",
|
|
72
|
-
});
|
|
73
|
-
});
|
|
74
|
-
it("rejects query exceeding length limit", () => {
|
|
75
|
-
const longQuery = "SELECT * FROM users WHERE " + "x = 1 AND ".repeat(2000);
|
|
76
|
-
expect(longQuery.length).toBeGreaterThan(10000);
|
|
77
|
-
expect(validateReadQuery(longQuery)).toEqual({
|
|
78
|
-
isValid: false,
|
|
79
|
-
error: "Query is too long. Maximum allowed length is 10,000 characters.",
|
|
80
|
-
});
|
|
81
|
-
});
|
|
82
|
-
it("rejects stored procedure patterns", () => {
|
|
83
|
-
expect(validateReadQuery("SELECT * FROM sp_help")).toEqual({
|
|
84
|
-
isValid: false,
|
|
85
|
-
error: "Potentially malicious SQL pattern detected. Only simple SELECT queries are allowed.",
|
|
86
|
-
});
|
|
87
|
-
expect(validateReadQuery("SELECT * FROM xp_cmdshell")).toEqual({
|
|
88
|
-
isValid: false,
|
|
89
|
-
error: "Potentially malicious SQL pattern detected. Only simple SELECT queries are allowed.",
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
it("rejects WAITFOR delay/time patterns", () => {
|
|
93
|
-
const result = validateReadQuery("SELECT 1; WAITFOR DELAY '0:0:5'");
|
|
94
|
-
expect(result.isValid).toBe(false);
|
|
95
|
-
expect(result.error).toBeDefined();
|
|
96
|
-
});
|
|
97
|
-
it("rejects query that is only comments", () => {
|
|
98
|
-
expect(validateReadQuery("-- comment only")).toEqual({
|
|
99
|
-
isValid: false,
|
|
100
|
-
error: "Query cannot be empty after removing comments",
|
|
101
|
-
});
|
|
102
|
-
expect(validateReadQuery("/* block comment */")).toEqual({
|
|
103
|
-
isValid: false,
|
|
104
|
-
error: "Query cannot be empty after removing comments",
|
|
105
|
-
});
|
|
106
|
-
});
|
|
107
|
-
it("accepts SELECT with WHERE and JOIN", () => {
|
|
108
|
-
expect(validateReadQuery("SELECT u.id, u.name FROM users u JOIN orders o ON u.id = o.user_id WHERE u.active = 1")).toEqual({ isValid: true });
|
|
109
|
-
});
|
|
110
|
-
});
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { validateReadQuery } from "../validation.js";
|
|
3
|
+
describe("validateReadQuery", () => {
|
|
4
|
+
it("accepts simple SELECT query", () => {
|
|
5
|
+
expect(validateReadQuery("SELECT * FROM movies")).toEqual({
|
|
6
|
+
isValid: true,
|
|
7
|
+
});
|
|
8
|
+
expect(validateReadQuery("SELECT id, name FROM users WHERE id = 1")).toEqual({
|
|
9
|
+
isValid: true,
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
it("rejects empty or non-string input", () => {
|
|
13
|
+
expect(validateReadQuery("")).toEqual({
|
|
14
|
+
isValid: false,
|
|
15
|
+
error: "Query must be a non-empty string",
|
|
16
|
+
});
|
|
17
|
+
expect(validateReadQuery(" ")).toEqual({
|
|
18
|
+
isValid: false,
|
|
19
|
+
error: "Query cannot be empty after removing comments",
|
|
20
|
+
});
|
|
21
|
+
expect(validateReadQuery(null)).toEqual({
|
|
22
|
+
isValid: false,
|
|
23
|
+
error: "Query must be a non-empty string",
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
it("rejects query that does not start with SELECT", () => {
|
|
27
|
+
expect(validateReadQuery("DELETE FROM users")).toEqual({
|
|
28
|
+
isValid: false,
|
|
29
|
+
error: "Query must start with SELECT for security reasons",
|
|
30
|
+
});
|
|
31
|
+
expect(validateReadQuery(" UPDATE users SET x = 1")).toEqual({
|
|
32
|
+
isValid: false,
|
|
33
|
+
error: "Query must start with SELECT for security reasons",
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
it("rejects dangerous keywords", () => {
|
|
37
|
+
expect(validateReadQuery("SELECT * FROM users; DELETE FROM logs")).toEqual({
|
|
38
|
+
isValid: false,
|
|
39
|
+
error: expect.stringContaining("Dangerous keyword"),
|
|
40
|
+
});
|
|
41
|
+
expect(validateReadQuery("SELECT * INTO backup FROM users")).toEqual({
|
|
42
|
+
isValid: false,
|
|
43
|
+
error: expect.stringContaining("Dangerous keyword"),
|
|
44
|
+
});
|
|
45
|
+
expect(validateReadQuery("SELECT * FROM users; DROP TABLE users")).toEqual({
|
|
46
|
+
isValid: false,
|
|
47
|
+
error: expect.stringContaining("Dangerous keyword"),
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it("rejects SELECT INTO pattern", () => {
|
|
51
|
+
const result = validateReadQuery("SELECT * INTO newtable FROM users");
|
|
52
|
+
expect(result.isValid).toBe(false);
|
|
53
|
+
expect(result.error).toBeDefined();
|
|
54
|
+
});
|
|
55
|
+
it("rejects multiple statements", () => {
|
|
56
|
+
const result = validateReadQuery("SELECT 1; SELECT 2");
|
|
57
|
+
expect(result.isValid).toBe(false);
|
|
58
|
+
expect(result.error).toBeDefined();
|
|
59
|
+
});
|
|
60
|
+
it("rejects character conversion functions", () => {
|
|
61
|
+
expect(validateReadQuery("SELECT CHAR(65) FROM users")).toEqual({
|
|
62
|
+
isValid: false,
|
|
63
|
+
error: "Character conversion functions are not allowed as they may be used for obfuscation.",
|
|
64
|
+
});
|
|
65
|
+
expect(validateReadQuery("SELECT NCHAR(65) FROM users")).toEqual({
|
|
66
|
+
isValid: false,
|
|
67
|
+
error: "Character conversion functions are not allowed as they may be used for obfuscation.",
|
|
68
|
+
});
|
|
69
|
+
expect(validateReadQuery("SELECT ASCII('A') FROM users")).toEqual({
|
|
70
|
+
isValid: false,
|
|
71
|
+
error: "Character conversion functions are not allowed as they may be used for obfuscation.",
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
it("rejects query exceeding length limit", () => {
|
|
75
|
+
const longQuery = "SELECT * FROM users WHERE " + "x = 1 AND ".repeat(2000);
|
|
76
|
+
expect(longQuery.length).toBeGreaterThan(10000);
|
|
77
|
+
expect(validateReadQuery(longQuery)).toEqual({
|
|
78
|
+
isValid: false,
|
|
79
|
+
error: "Query is too long. Maximum allowed length is 10,000 characters.",
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
it("rejects stored procedure patterns", () => {
|
|
83
|
+
expect(validateReadQuery("SELECT * FROM sp_help")).toEqual({
|
|
84
|
+
isValid: false,
|
|
85
|
+
error: "Potentially malicious SQL pattern detected. Only simple SELECT queries are allowed.",
|
|
86
|
+
});
|
|
87
|
+
expect(validateReadQuery("SELECT * FROM xp_cmdshell")).toEqual({
|
|
88
|
+
isValid: false,
|
|
89
|
+
error: "Potentially malicious SQL pattern detected. Only simple SELECT queries are allowed.",
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
it("rejects WAITFOR delay/time patterns", () => {
|
|
93
|
+
const result = validateReadQuery("SELECT 1; WAITFOR DELAY '0:0:5'");
|
|
94
|
+
expect(result.isValid).toBe(false);
|
|
95
|
+
expect(result.error).toBeDefined();
|
|
96
|
+
});
|
|
97
|
+
it("rejects query that is only comments", () => {
|
|
98
|
+
expect(validateReadQuery("-- comment only")).toEqual({
|
|
99
|
+
isValid: false,
|
|
100
|
+
error: "Query cannot be empty after removing comments",
|
|
101
|
+
});
|
|
102
|
+
expect(validateReadQuery("/* block comment */")).toEqual({
|
|
103
|
+
isValid: false,
|
|
104
|
+
error: "Query cannot be empty after removing comments",
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
it("accepts SELECT with WHERE and JOIN", () => {
|
|
108
|
+
expect(validateReadQuery("SELECT u.id, u.name FROM users u JOIN orders o ON u.id = o.user_id WHERE u.active = 1")).toEqual({ isValid: true });
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
111
|
//# sourceMappingURL=validation.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../../src/__tests__/validation.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,MAAM,CAAC,iBAAiB,CAAC,sBAAsB,CAAC,CAAC,CAAC,OAAO,CAAC;YACxD,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,MAAM,CACJ,iBAAiB,CAAC,yCAAyC,CAAC,CAC7D,CAAC,OAAO,CAAC;YACR,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;YACpC,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,kCAAkC;SAC1C,CAAC,CAAC;QACH,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC;YACvC,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,+CAA+C;SACvD,CAAC,CAAC;QACH,MAAM,CAAC,iBAAiB,CAAC,
|
|
1
|
+
{"version":3,"file":"validation.test.js","sourceRoot":"","sources":["../../src/__tests__/validation.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeTools.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/writeTools.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
const dbMockState = vi.hoisted(() => ({
|
|
3
|
+
error: undefined,
|
|
4
|
+
inputCalls: [],
|
|
5
|
+
queryCalls: [],
|
|
6
|
+
queryResults: [],
|
|
7
|
+
}));
|
|
8
|
+
vi.mock("../db.js", () => ({
|
|
9
|
+
getSqlRequest: vi.fn(async () => {
|
|
10
|
+
if (dbMockState.error) {
|
|
11
|
+
return {
|
|
12
|
+
request: null,
|
|
13
|
+
error: dbMockState.error,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
request: {
|
|
18
|
+
input(name, value) {
|
|
19
|
+
dbMockState.inputCalls.push({ name, value });
|
|
20
|
+
},
|
|
21
|
+
async query(query) {
|
|
22
|
+
dbMockState.queryCalls.push(query);
|
|
23
|
+
return (dbMockState.queryResults.shift() ?? {
|
|
24
|
+
rowsAffected: [1],
|
|
25
|
+
recordset: [],
|
|
26
|
+
});
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}),
|
|
31
|
+
}));
|
|
32
|
+
import { CreateIndexTool } from "../tools/CreateIndexTool.js";
|
|
33
|
+
import { CreateTableTool } from "../tools/CreateTableTool.js";
|
|
34
|
+
import { DeleteDataTool } from "../tools/DeleteDataTool.js";
|
|
35
|
+
import { InsertDataTool } from "../tools/InsertDataTool.js";
|
|
36
|
+
import { UpdateDataTool } from "../tools/UpdateDataTool.js";
|
|
37
|
+
describe("write tools", () => {
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
vi.spyOn(console, "error").mockImplementation(() => { });
|
|
40
|
+
dbMockState.error = undefined;
|
|
41
|
+
dbMockState.inputCalls.length = 0;
|
|
42
|
+
dbMockState.queryCalls.length = 0;
|
|
43
|
+
dbMockState.queryResults.length = 0;
|
|
44
|
+
});
|
|
45
|
+
afterEach(() => {
|
|
46
|
+
vi.restoreAllMocks();
|
|
47
|
+
});
|
|
48
|
+
it("parameterizes delete filters instead of interpolating raw SQL", async () => {
|
|
49
|
+
const tool = new DeleteDataTool();
|
|
50
|
+
const result = await tool.run({
|
|
51
|
+
tableName: "Order Details",
|
|
52
|
+
schemaName: "sales-data",
|
|
53
|
+
filters: [{ column: "Order ID", operator: "=", value: 42 }],
|
|
54
|
+
});
|
|
55
|
+
expect(result).toMatchObject({ success: true, rowsAffected: 1 });
|
|
56
|
+
expect(dbMockState.queryCalls[0]).toBe("DELETE FROM [sales-data].[Order Details] WHERE [Order ID] = @delete_filter_0");
|
|
57
|
+
expect(dbMockState.inputCalls).toEqual([
|
|
58
|
+
{ name: "delete_filter_0", value: 42 },
|
|
59
|
+
]);
|
|
60
|
+
});
|
|
61
|
+
it("parameterizes update filters and quotes updated columns", async () => {
|
|
62
|
+
const tool = new UpdateDataTool();
|
|
63
|
+
const result = await tool.run({
|
|
64
|
+
tableName: "Users",
|
|
65
|
+
updates: { "display name": "Ada" },
|
|
66
|
+
filters: [{ column: "id", operator: "IN", values: [1, 2] }],
|
|
67
|
+
});
|
|
68
|
+
expect(result).toMatchObject({ success: true, rowsAffected: 1 });
|
|
69
|
+
expect(dbMockState.queryCalls[0]).toBe("UPDATE [Users] SET [display name] = @update_0 WHERE [id] IN (@update_filter_0_0, @update_filter_0_1)");
|
|
70
|
+
expect(dbMockState.inputCalls).toEqual([
|
|
71
|
+
{ name: "update_0", value: "Ada" },
|
|
72
|
+
{ name: "update_filter_0_0", value: 1 },
|
|
73
|
+
{ name: "update_filter_0_1", value: 2 },
|
|
74
|
+
]);
|
|
75
|
+
});
|
|
76
|
+
it("quotes identifiers for inserts", async () => {
|
|
77
|
+
const tool = new InsertDataTool();
|
|
78
|
+
const result = await tool.run({
|
|
79
|
+
tableName: "Order Details",
|
|
80
|
+
data: {
|
|
81
|
+
"Customer Name": "Ada",
|
|
82
|
+
"Order ID": 10,
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
expect(result).toMatchObject({ success: true, recordsInserted: 1 });
|
|
86
|
+
expect(dbMockState.queryCalls[0]).toBe("INSERT INTO [Order Details] ([Customer Name], [Order ID]) VALUES (@value0, @value1)");
|
|
87
|
+
});
|
|
88
|
+
it("quotes identifiers for created indexes", async () => {
|
|
89
|
+
const tool = new CreateIndexTool();
|
|
90
|
+
const result = await tool.run({
|
|
91
|
+
schemaName: "sales-data",
|
|
92
|
+
tableName: "Order Details",
|
|
93
|
+
indexName: "IX Order Lookup",
|
|
94
|
+
columns: ["Order ID", "Line Number"],
|
|
95
|
+
});
|
|
96
|
+
expect(result).toMatchObject({ success: true });
|
|
97
|
+
expect(dbMockState.queryCalls[0]).toBe("CREATE NONCLUSTERED INDEX [IX Order Lookup] ON [sales-data].[Order Details] ([Order ID], [Line Number])");
|
|
98
|
+
});
|
|
99
|
+
it("rejects unsafe free-form column type fragments", async () => {
|
|
100
|
+
const tool = new CreateTableTool();
|
|
101
|
+
const result = await tool.run({
|
|
102
|
+
tableName: "Users",
|
|
103
|
+
columns: [
|
|
104
|
+
{
|
|
105
|
+
name: "id",
|
|
106
|
+
type: "INT); DROP TABLE users; --",
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
});
|
|
110
|
+
expect(result).toMatchObject({ success: false });
|
|
111
|
+
expect(String(result.message)).toContain("Unsupported SQL type declaration");
|
|
112
|
+
expect(dbMockState.queryCalls).toHaveLength(0);
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
//# sourceMappingURL=writeTools.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"writeTools.test.js","sourceRoot":"","sources":["../../src/__tests__/writeTools.test.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function getMaxRows(): number;
|
|
2
|
+
export declare function getQueryTimeoutMs(): number;
|
|
3
|
+
export declare function getDefaultSearchLimit(): number;
|
|
4
|
+
export declare function clampRowLimit(limit: unknown, fallback?: number): number;
|
|
5
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAqBA,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CAK1C;AAED,wBAAgB,qBAAqB,IAAI,MAAM,CAE9C;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,QAAQ,SAAe,GAAG,MAAM,CAa7E"}
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const DEFAULT_MAX_ROWS = 10000;
|
|
2
|
+
const DEFAULT_QUERY_TIMEOUT_MS = 30000;
|
|
3
|
+
const DEFAULT_SEARCH_LIMIT = 100;
|
|
4
|
+
function parsePositiveInt(value, fallback, minimum = 1) {
|
|
5
|
+
if (!value) {
|
|
6
|
+
return fallback;
|
|
7
|
+
}
|
|
8
|
+
const parsed = Number.parseInt(value, 10);
|
|
9
|
+
if (!Number.isFinite(parsed) || parsed < minimum) {
|
|
10
|
+
return fallback;
|
|
11
|
+
}
|
|
12
|
+
return parsed;
|
|
13
|
+
}
|
|
14
|
+
export function getMaxRows() {
|
|
15
|
+
return parsePositiveInt(process.env.MAX_ROWS, DEFAULT_MAX_ROWS);
|
|
16
|
+
}
|
|
17
|
+
export function getQueryTimeoutMs() {
|
|
18
|
+
return parsePositiveInt(process.env.QUERY_TIMEOUT_MS, DEFAULT_QUERY_TIMEOUT_MS);
|
|
19
|
+
}
|
|
20
|
+
export function getDefaultSearchLimit() {
|
|
21
|
+
return Math.min(getMaxRows(), DEFAULT_SEARCH_LIMIT);
|
|
22
|
+
}
|
|
23
|
+
export function clampRowLimit(limit, fallback = getMaxRows()) {
|
|
24
|
+
const parsed = typeof limit === "number"
|
|
25
|
+
? limit
|
|
26
|
+
: typeof limit === "string"
|
|
27
|
+
? Number.parseInt(limit, 10)
|
|
28
|
+
: Number.NaN;
|
|
29
|
+
if (!Number.isFinite(parsed) || parsed < 1) {
|
|
30
|
+
return Math.min(fallback, getMaxRows());
|
|
31
|
+
}
|
|
32
|
+
return Math.min(Math.floor(parsed), getMaxRows());
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,MAAM,gBAAgB,GAAG,KAAK,CAAC;AAC/B,MAAM,wBAAwB,GAAG,KAAK,CAAC;AACvC,MAAM,oBAAoB,GAAG,GAAG,CAAC;AAEjC,SAAS,gBAAgB,CACvB,KAAyB,EACzB,QAAgB,EAChB,OAAO,GAAG,CAAC;IAEX,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAC1C,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,OAAO,EAAE,CAAC;QACjD,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,gBAAgB,CAAC,CAAC;AAClE,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,gBAAgB,CACrB,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAC5B,wBAAwB,CACzB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,EAAE,oBAAoB,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,QAAQ,GAAG,UAAU,EAAE;IACnE,MAAM,MAAM,GACV,OAAO,KAAK,KAAK,QAAQ;QACvB,CAAC,CAAC,KAAK;QACP,CAAC,CAAC,OAAO,KAAK,KAAK,QAAQ;YACzB,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC;YAC5B,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;IAEnB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAC1C,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC;AACpD,CAAC"}
|
package/dist/db.d.ts
CHANGED
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
import sql from "mssql";
|
|
2
|
-
/**
|
|
3
|
-
* Returns the list of allowed database names.
|
|
4
|
-
* If DATABASES is set, returns those; otherwise returns only DATABASE_NAME.
|
|
5
|
-
*/
|
|
6
|
-
export declare function getAllowedDatabases(): string[];
|
|
7
|
-
/**
|
|
8
|
-
* Resolves the database name to use (param or default).
|
|
9
|
-
* Returns null if invalid.
|
|
10
|
-
*/
|
|
11
|
-
export declare function resolveDatabaseName(databaseName?: string): string | null;
|
|
12
|
-
/**
|
|
13
|
-
* Ensures a connection pool exists for the given database.
|
|
14
|
-
*/
|
|
15
|
-
export declare function ensureSqlConnection(databaseName: string): Promise<sql.ConnectionPool>;
|
|
16
|
-
/**
|
|
17
|
-
* Returns a sql.Request for the given database.
|
|
18
|
-
* Resolves database name (param or default), validates against allowed list,
|
|
19
|
-
* ensures connection, and returns pool.request().
|
|
20
|
-
*/
|
|
21
|
-
export declare function getSqlRequest(databaseName?: string): Promise<{
|
|
22
|
-
request: sql.Request;
|
|
23
|
-
error?: string;
|
|
24
|
-
}>;
|
|
1
|
+
import sql from "mssql";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the list of allowed database names.
|
|
4
|
+
* If DATABASES is set, returns those; otherwise returns only DATABASE_NAME.
|
|
5
|
+
*/
|
|
6
|
+
export declare function getAllowedDatabases(): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Resolves the database name to use (param or default).
|
|
9
|
+
* Returns null if invalid.
|
|
10
|
+
*/
|
|
11
|
+
export declare function resolveDatabaseName(databaseName?: string): string | null;
|
|
12
|
+
/**
|
|
13
|
+
* Ensures a connection pool exists for the given database.
|
|
14
|
+
*/
|
|
15
|
+
export declare function ensureSqlConnection(databaseName: string): Promise<sql.ConnectionPool>;
|
|
16
|
+
/**
|
|
17
|
+
* Returns a sql.Request for the given database.
|
|
18
|
+
* Resolves database name (param or default), validates against allowed list,
|
|
19
|
+
* ensures connection, and returns pool.request().
|
|
20
|
+
*/
|
|
21
|
+
export declare function getSqlRequest(databaseName?: string): Promise<{
|
|
22
|
+
request: sql.Request;
|
|
23
|
+
error?: string;
|
|
24
|
+
}>;
|
|
25
|
+
export declare function getDedicatedSqlPool(databaseName?: string): Promise<{
|
|
26
|
+
pool: sql.ConnectionPool;
|
|
27
|
+
error?: string;
|
|
28
|
+
}>;
|
|
25
29
|
//# sourceMappingURL=db.d.ts.map
|
package/dist/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../src/db.ts"],"names":[],"mappings":"AAAA,OAAO,GAAG,MAAM,OAAO,CAAC;AAgCxB;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,EAAE,CAQ9C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQxE;AA6CD;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAoB7B;AAED;;;;GAIG;AACH,wBAAsB,aAAa,CACjC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAWnD;AAED,wBAAsB,mBAAmB,CACvC,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC;IAAE,IAAI,EAAE,GAAG,CAAC,cAAc,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAqBvD"}
|