mcp-server-db2i 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 +97 -4
- package/dist/config.d.ts +66 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +111 -5
- package/dist/config.js.map +1 -1
- package/dist/server.js +2 -2
- package/dist/server.js.map +1 -1
- package/dist/tools/query.d.ts +1 -0
- package/dist/tools/query.d.ts.map +1 -1
- package/dist/tools/query.js +8 -4
- package/dist/tools/query.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,6 +88,10 @@ LOG_COLORS=true # Override: force colors on/off (auto
|
|
|
88
88
|
RATE_LIMIT_WINDOW_MS=900000 # Time window in ms (default: 900000 = 15 minutes)
|
|
89
89
|
RATE_LIMIT_MAX_REQUESTS=100 # Max requests per window (default: 100)
|
|
90
90
|
RATE_LIMIT_ENABLED=true # Set to 'false' to disable (default: true)
|
|
91
|
+
|
|
92
|
+
# Optional - Query Limits
|
|
93
|
+
QUERY_DEFAULT_LIMIT=1000 # Default rows returned (default: 1000)
|
|
94
|
+
QUERY_MAX_LIMIT=10000 # Maximum rows allowed (default: 10000)
|
|
91
95
|
```
|
|
92
96
|
|
|
93
97
|
### Environment Variables
|
|
@@ -95,8 +99,10 @@ RATE_LIMIT_ENABLED=true # Set to 'false' to disable (default:
|
|
|
95
99
|
| Variable | Required | Default | Description |
|
|
96
100
|
|----------|----------|---------|-------------|
|
|
97
101
|
| `DB2I_HOSTNAME` | Yes | - | IBM i hostname or IP address |
|
|
98
|
-
| `DB2I_USERNAME` | Yes | - | IBM i user profile |
|
|
99
|
-
| `DB2I_PASSWORD` | Yes | - | User password |
|
|
102
|
+
| `DB2I_USERNAME` | Yes* | - | IBM i user profile |
|
|
103
|
+
| `DB2I_PASSWORD` | Yes* | - | User password |
|
|
104
|
+
| `DB2I_USERNAME_FILE` | No | - | Path to file containing username (overrides `DB2I_USERNAME`) |
|
|
105
|
+
| `DB2I_PASSWORD_FILE` | No | - | Path to file containing password (overrides `DB2I_PASSWORD`) |
|
|
100
106
|
| `DB2I_PORT` | No | `446` | JDBC port (446 is standard for IBM i) |
|
|
101
107
|
| `DB2I_DATABASE` | No | `*LOCAL` | Database name |
|
|
102
108
|
| `DB2I_SCHEMA` | No | - | Default schema/library for tools. If set, you don't need to specify schema in each tool call. |
|
|
@@ -108,6 +114,10 @@ RATE_LIMIT_ENABLED=true # Set to 'false' to disable (default:
|
|
|
108
114
|
| `RATE_LIMIT_WINDOW_MS` | No | `900000` | Rate limit time window in milliseconds (15 min) |
|
|
109
115
|
| `RATE_LIMIT_MAX_REQUESTS` | No | `100` | Maximum requests allowed per window |
|
|
110
116
|
| `RATE_LIMIT_ENABLED` | No | `true` | Set to `false` or `0` to disable rate limiting |
|
|
117
|
+
| `QUERY_DEFAULT_LIMIT` | No | `1000` | Default number of rows returned by queries |
|
|
118
|
+
| `QUERY_MAX_LIMIT` | No | `10000` | Maximum rows allowed (caps user-provided limits) |
|
|
119
|
+
|
|
120
|
+
*Either the environment variable or the corresponding `*_FILE` variable must be set. File-based secrets take priority when both are provided.
|
|
111
121
|
|
|
112
122
|
### JDBC Options
|
|
113
123
|
|
|
@@ -263,12 +273,95 @@ npm run typecheck
|
|
|
263
273
|
## Security
|
|
264
274
|
|
|
265
275
|
- **Read-only access**: Only SELECT statements are permitted
|
|
266
|
-
- **No credentials in code**: All sensitive data via environment variables
|
|
276
|
+
- **No credentials in code**: All sensitive data via environment variables or file-based secrets
|
|
267
277
|
- **Query validation**: AST-based SQL parsing plus regex validation blocks dangerous operations
|
|
268
|
-
- **Result limiting**: Default limit of 1000 rows
|
|
278
|
+
- **Result limiting**: Default limit of 1000 rows, configurable max limit (default: 10000)
|
|
269
279
|
- **Rate limiting**: Configurable request throttling to prevent abuse (100 req/15 min default)
|
|
270
280
|
- **Structured logging**: Automatic redaction of sensitive fields like passwords
|
|
271
281
|
|
|
282
|
+
### Rate Limiting
|
|
283
|
+
|
|
284
|
+
The server includes built-in rate limiting to protect the IBM i database from excessive queries:
|
|
285
|
+
|
|
286
|
+
- **Default**: 100 requests per 15-minute window
|
|
287
|
+
- **Scope**: Per server instance (for stdio transport, this effectively means per-client since each MCP client spawns its own server process)
|
|
288
|
+
- **Configurable**: Adjust via `RATE_LIMIT_*` environment variables or disable entirely
|
|
289
|
+
|
|
290
|
+
When the rate limit is exceeded, queries return an error with `waitTimeSeconds` indicating when to retry.
|
|
291
|
+
|
|
292
|
+
### Credential Management
|
|
293
|
+
|
|
294
|
+
The server supports multiple methods for providing credentials, listed from most to least secure:
|
|
295
|
+
|
|
296
|
+
#### Option 1: Docker Secrets (Recommended for Production)
|
|
297
|
+
|
|
298
|
+
Docker secrets provide the most secure credential management. Secrets are mounted as files and never exposed in environment variables or process listings.
|
|
299
|
+
|
|
300
|
+
1. Create secret files:
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
mkdir -p ./secrets
|
|
304
|
+
echo "your-username" > ./secrets/db2i_username.txt
|
|
305
|
+
echo "your-password" > ./secrets/db2i_password.txt
|
|
306
|
+
chmod 600 ./secrets/*.txt
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
2. Configure docker-compose.yml to use secrets:
|
|
310
|
+
|
|
311
|
+
```yaml
|
|
312
|
+
services:
|
|
313
|
+
mcp-server-db2i:
|
|
314
|
+
# ... other config ...
|
|
315
|
+
environment:
|
|
316
|
+
- DB2I_HOSTNAME=${DB2I_HOSTNAME}
|
|
317
|
+
- DB2I_USERNAME_FILE=/run/secrets/db2i_username
|
|
318
|
+
- DB2I_PASSWORD_FILE=/run/secrets/db2i_password
|
|
319
|
+
secrets:
|
|
320
|
+
- db2i_username
|
|
321
|
+
- db2i_password
|
|
322
|
+
|
|
323
|
+
secrets:
|
|
324
|
+
db2i_username:
|
|
325
|
+
file: ./secrets/db2i_username.txt
|
|
326
|
+
db2i_password:
|
|
327
|
+
file: ./secrets/db2i_password.txt
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
For Docker Swarm or Kubernetes, use their native secret management instead of file-based secrets.
|
|
331
|
+
|
|
332
|
+
#### Option 2: External Secret Management
|
|
333
|
+
|
|
334
|
+
For enterprise deployments, integrate with secret management systems:
|
|
335
|
+
|
|
336
|
+
- **HashiCorp Vault**: Inject secrets at runtime
|
|
337
|
+
- **AWS Secrets Manager**: Use IAM roles for access
|
|
338
|
+
- **Azure Key Vault**: Integrate with managed identities
|
|
339
|
+
|
|
340
|
+
These systems can populate the `*_FILE` environment variables or inject secrets directly.
|
|
341
|
+
|
|
342
|
+
#### Option 3: Environment Variables (Development Only)
|
|
343
|
+
|
|
344
|
+
Plain environment variables are convenient for development but expose credentials through:
|
|
345
|
+
- `docker inspect` output
|
|
346
|
+
- Process listings (`ps aux`)
|
|
347
|
+
- Shell history
|
|
348
|
+
- Log files
|
|
349
|
+
|
|
350
|
+
```bash
|
|
351
|
+
# .env file (ensure it's in .gitignore)
|
|
352
|
+
DB2I_USERNAME=your-username
|
|
353
|
+
DB2I_PASSWORD=your-password
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Warning**: Never commit `.env` files or credentials to version control.
|
|
357
|
+
|
|
358
|
+
### File-Based Secret Variables
|
|
359
|
+
|
|
360
|
+
| Variable | Description |
|
|
361
|
+
|----------|-------------|
|
|
362
|
+
| `DB2I_USERNAME_FILE` | Path to file containing username (takes priority over `DB2I_USERNAME`) |
|
|
363
|
+
| `DB2I_PASSWORD_FILE` | Path to file containing password (takes priority over `DB2I_PASSWORD`) |
|
|
364
|
+
|
|
272
365
|
## Compatibility
|
|
273
366
|
|
|
274
367
|
- IBM i V7R3 and later (V7R5 recommended)
|
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration module for IBM DB2i MCP Server
|
|
3
3
|
* Handles environment variables and JDBC connection options
|
|
4
|
+
*
|
|
5
|
+
* Supports file-based secrets (e.g., Docker secrets) via *_FILE environment variables.
|
|
6
|
+
* File-based secrets take priority over plain environment variables.
|
|
4
7
|
*/
|
|
5
8
|
export interface DB2iConfig {
|
|
6
9
|
hostname: string;
|
|
@@ -21,7 +24,39 @@ export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal';
|
|
|
21
24
|
*/
|
|
22
25
|
export declare function getLogLevel(): LogLevel;
|
|
23
26
|
/**
|
|
24
|
-
*
|
|
27
|
+
* Read a secret value from a file.
|
|
28
|
+
* Docker secrets are typically mounted at /run/secrets/<secret_name>
|
|
29
|
+
*
|
|
30
|
+
* @param filePath - Path to the file containing the secret
|
|
31
|
+
* @returns The secret value with leading/trailing whitespace trimmed
|
|
32
|
+
* @throws Error if file cannot be read
|
|
33
|
+
*/
|
|
34
|
+
export declare function readSecretFromFile(filePath: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Get a secret value from either a file or environment variable.
|
|
37
|
+
* File-based secrets take priority (more secure).
|
|
38
|
+
*
|
|
39
|
+
* @param envVar - Name of the environment variable containing the value
|
|
40
|
+
* @param fileEnvVar - Name of the environment variable containing the file path
|
|
41
|
+
* @returns The secret value, or undefined if neither is set
|
|
42
|
+
*/
|
|
43
|
+
export declare function getSecret(envVar: string, fileEnvVar: string): string | undefined;
|
|
44
|
+
/**
|
|
45
|
+
* Validate hostname format.
|
|
46
|
+
* Accepts valid hostnames (RFC 1123) and IPv4 addresses.
|
|
47
|
+
*
|
|
48
|
+
* @param hostname - The hostname or IP address to validate
|
|
49
|
+
* @returns true if the hostname format is valid, false otherwise
|
|
50
|
+
*/
|
|
51
|
+
export declare function validateHostname(hostname: string): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Load configuration from environment variables.
|
|
54
|
+
*
|
|
55
|
+
* Supports file-based secrets for sensitive values (recommended for production):
|
|
56
|
+
* - DB2I_PASSWORD_FILE: Path to file containing password (e.g., Docker secret)
|
|
57
|
+
* - DB2I_USERNAME_FILE: Path to file containing username (optional)
|
|
58
|
+
*
|
|
59
|
+
* File-based secrets take priority over plain environment variables.
|
|
25
60
|
*/
|
|
26
61
|
export declare function loadConfig(): DB2iConfig;
|
|
27
62
|
/**
|
|
@@ -57,4 +92,34 @@ export interface RateLimitConfig {
|
|
|
57
92
|
* - RATE_LIMIT_ENABLED: Set to 'false' or '0' to disable (default: true)
|
|
58
93
|
*/
|
|
59
94
|
export declare const DEFAULT_RATE_LIMIT: RateLimitConfig;
|
|
95
|
+
/**
|
|
96
|
+
* Query limit configuration interface
|
|
97
|
+
*/
|
|
98
|
+
export interface QueryLimitConfig {
|
|
99
|
+
/** Default number of rows to return (default: 1000) */
|
|
100
|
+
defaultLimit: number;
|
|
101
|
+
/** Maximum number of rows allowed (default: 10000) */
|
|
102
|
+
maxLimit: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Default query limit configuration values
|
|
106
|
+
*
|
|
107
|
+
* Environment variables:
|
|
108
|
+
* - QUERY_DEFAULT_LIMIT: Default rows to return (default: 1000)
|
|
109
|
+
* - QUERY_MAX_LIMIT: Maximum rows allowed, caps user-provided limits (default: 10000)
|
|
110
|
+
*/
|
|
111
|
+
export declare const DEFAULT_QUERY_LIMIT: QueryLimitConfig;
|
|
112
|
+
/**
|
|
113
|
+
* Get query limit configuration from environment variables
|
|
114
|
+
*/
|
|
115
|
+
export declare function getQueryLimitConfig(): QueryLimitConfig;
|
|
116
|
+
/**
|
|
117
|
+
* Apply query limit constraints.
|
|
118
|
+
* Returns the effective limit, capped to maxLimit.
|
|
119
|
+
*
|
|
120
|
+
* @param requestedLimit - The limit requested by the user (or undefined for default)
|
|
121
|
+
* @param config - Query limit configuration
|
|
122
|
+
* @returns The effective limit to use
|
|
123
|
+
*/
|
|
124
|
+
export declare function applyQueryLimit(requestedLimit: number | undefined, config?: QueryLimitConfig): number;
|
|
60
125
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACrC;AAED;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAErE;;;GAGG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAStC;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAK3D;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAMhF;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAwB1D;AA6BD;;;;;;;;GAQG;AACH,wBAAgB,UAAU,IAAI,UAAU,CAiCvC;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,GAAG;IACzD,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;CACvB,CA4BA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,GAAG,SAAS,CAEvE;AAED;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,iEAAiE;IACjE,QAAQ,EAAE,MAAM,CAAC;IACjB,yDAAyD;IACzD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,EAAE,eAIhC,CAAC;AAEF;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,uDAAuD;IACvD,YAAY,EAAE,MAAM,CAAC;IACrB,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,gBAGjC,CAAC;AAEF;;GAEG;AACH,wBAAgB,mBAAmB,IAAI,gBAAgB,CAQtD;AAED;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,MAAM,GAAE,gBAAwC,GAC/C,MAAM,CAGR"}
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Configuration module for IBM DB2i MCP Server
|
|
3
3
|
* Handles environment variables and JDBC connection options
|
|
4
|
+
*
|
|
5
|
+
* Supports file-based secrets (e.g., Docker secrets) via *_FILE environment variables.
|
|
6
|
+
* File-based secrets take priority over plain environment variables.
|
|
4
7
|
*/
|
|
8
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
5
9
|
/**
|
|
6
10
|
* Get the configured log level from environment
|
|
7
11
|
* Defaults to 'info' if not set or invalid
|
|
@@ -14,6 +18,65 @@ export function getLogLevel() {
|
|
|
14
18
|
}
|
|
15
19
|
return 'info';
|
|
16
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Read a secret value from a file.
|
|
23
|
+
* Docker secrets are typically mounted at /run/secrets/<secret_name>
|
|
24
|
+
*
|
|
25
|
+
* @param filePath - Path to the file containing the secret
|
|
26
|
+
* @returns The secret value with leading/trailing whitespace trimmed
|
|
27
|
+
* @throws Error if file cannot be read
|
|
28
|
+
*/
|
|
29
|
+
export function readSecretFromFile(filePath) {
|
|
30
|
+
if (!existsSync(filePath)) {
|
|
31
|
+
throw new Error(`Secret file not found: ${filePath}`);
|
|
32
|
+
}
|
|
33
|
+
return readFileSync(filePath, 'utf8').trim();
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Get a secret value from either a file or environment variable.
|
|
37
|
+
* File-based secrets take priority (more secure).
|
|
38
|
+
*
|
|
39
|
+
* @param envVar - Name of the environment variable containing the value
|
|
40
|
+
* @param fileEnvVar - Name of the environment variable containing the file path
|
|
41
|
+
* @returns The secret value, or undefined if neither is set
|
|
42
|
+
*/
|
|
43
|
+
export function getSecret(envVar, fileEnvVar) {
|
|
44
|
+
const filePath = process.env[fileEnvVar];
|
|
45
|
+
if (filePath) {
|
|
46
|
+
return readSecretFromFile(filePath);
|
|
47
|
+
}
|
|
48
|
+
return process.env[envVar];
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Validate hostname format.
|
|
52
|
+
* Accepts valid hostnames (RFC 1123) and IPv4 addresses.
|
|
53
|
+
*
|
|
54
|
+
* @param hostname - The hostname or IP address to validate
|
|
55
|
+
* @returns true if the hostname format is valid, false otherwise
|
|
56
|
+
*/
|
|
57
|
+
export function validateHostname(hostname) {
|
|
58
|
+
const trimmed = hostname.trim();
|
|
59
|
+
if (!trimmed)
|
|
60
|
+
return false;
|
|
61
|
+
// IPv4 pattern: four octets separated by dots
|
|
62
|
+
const ipv4Pattern = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
63
|
+
const ipv4Match = trimmed.match(ipv4Pattern);
|
|
64
|
+
if (ipv4Match) {
|
|
65
|
+
// Validate each octet is 0-255
|
|
66
|
+
return ipv4Match.slice(1).every((octet) => {
|
|
67
|
+
const num = parseInt(octet, 10);
|
|
68
|
+
return num >= 0 && num <= 255;
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
// Hostname pattern (RFC 1123):
|
|
72
|
+
// - Labels separated by dots
|
|
73
|
+
// - Each label: 1-63 chars, alphanumeric or hyphen, cannot start/end with hyphen
|
|
74
|
+
// - Total length up to 253 chars
|
|
75
|
+
if (trimmed.length > 253)
|
|
76
|
+
return false;
|
|
77
|
+
const hostnamePattern = /^[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(\.[a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
78
|
+
return hostnamePattern.test(trimmed);
|
|
79
|
+
}
|
|
17
80
|
/**
|
|
18
81
|
* Parse JDBC options from a semicolon-separated string
|
|
19
82
|
* Format: "key1=value1;key2=value2"
|
|
@@ -38,20 +101,29 @@ function parseJdbcOptions(optionsString) {
|
|
|
38
101
|
return options;
|
|
39
102
|
}
|
|
40
103
|
/**
|
|
41
|
-
* Load configuration from environment variables
|
|
104
|
+
* Load configuration from environment variables.
|
|
105
|
+
*
|
|
106
|
+
* Supports file-based secrets for sensitive values (recommended for production):
|
|
107
|
+
* - DB2I_PASSWORD_FILE: Path to file containing password (e.g., Docker secret)
|
|
108
|
+
* - DB2I_USERNAME_FILE: Path to file containing username (optional)
|
|
109
|
+
*
|
|
110
|
+
* File-based secrets take priority over plain environment variables.
|
|
42
111
|
*/
|
|
43
112
|
export function loadConfig() {
|
|
44
113
|
const hostname = process.env.DB2I_HOSTNAME;
|
|
45
|
-
const username =
|
|
46
|
-
const password =
|
|
114
|
+
const username = getSecret('DB2I_USERNAME', 'DB2I_USERNAME_FILE');
|
|
115
|
+
const password = getSecret('DB2I_PASSWORD', 'DB2I_PASSWORD_FILE');
|
|
47
116
|
if (!hostname) {
|
|
48
117
|
throw new Error('DB2I_HOSTNAME environment variable is required');
|
|
49
118
|
}
|
|
119
|
+
if (!validateHostname(hostname)) {
|
|
120
|
+
throw new Error(`Invalid DB2I_HOSTNAME format: "${hostname}". Must be a valid hostname or IPv4 address.`);
|
|
121
|
+
}
|
|
50
122
|
if (!username) {
|
|
51
|
-
throw new Error('DB2I_USERNAME environment variable is required');
|
|
123
|
+
throw new Error('DB2I_USERNAME environment variable is required (or DB2I_USERNAME_FILE for file-based secret)');
|
|
52
124
|
}
|
|
53
125
|
if (!password) {
|
|
54
|
-
throw new Error('DB2I_PASSWORD environment variable is required');
|
|
126
|
+
throw new Error('DB2I_PASSWORD environment variable is required (or DB2I_PASSWORD_FILE for file-based secret)');
|
|
55
127
|
}
|
|
56
128
|
return {
|
|
57
129
|
hostname,
|
|
@@ -105,4 +177,38 @@ export const DEFAULT_RATE_LIMIT = {
|
|
|
105
177
|
maxRequests: 100,
|
|
106
178
|
enabled: true,
|
|
107
179
|
};
|
|
180
|
+
/**
|
|
181
|
+
* Default query limit configuration values
|
|
182
|
+
*
|
|
183
|
+
* Environment variables:
|
|
184
|
+
* - QUERY_DEFAULT_LIMIT: Default rows to return (default: 1000)
|
|
185
|
+
* - QUERY_MAX_LIMIT: Maximum rows allowed, caps user-provided limits (default: 10000)
|
|
186
|
+
*/
|
|
187
|
+
export const DEFAULT_QUERY_LIMIT = {
|
|
188
|
+
defaultLimit: 1000,
|
|
189
|
+
maxLimit: 10000,
|
|
190
|
+
};
|
|
191
|
+
/**
|
|
192
|
+
* Get query limit configuration from environment variables
|
|
193
|
+
*/
|
|
194
|
+
export function getQueryLimitConfig() {
|
|
195
|
+
const defaultLimit = parseInt(process.env.QUERY_DEFAULT_LIMIT || '1000', 10);
|
|
196
|
+
const maxLimit = parseInt(process.env.QUERY_MAX_LIMIT || '10000', 10);
|
|
197
|
+
return {
|
|
198
|
+
defaultLimit: Math.max(1, defaultLimit),
|
|
199
|
+
maxLimit: Math.max(1, maxLimit),
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Apply query limit constraints.
|
|
204
|
+
* Returns the effective limit, capped to maxLimit.
|
|
205
|
+
*
|
|
206
|
+
* @param requestedLimit - The limit requested by the user (or undefined for default)
|
|
207
|
+
* @param config - Query limit configuration
|
|
208
|
+
* @returns The effective limit to use
|
|
209
|
+
*/
|
|
210
|
+
export function applyQueryLimit(requestedLimit, config = getQueryLimitConfig()) {
|
|
211
|
+
const limit = requestedLimit ?? config.defaultLimit;
|
|
212
|
+
return Math.min(Math.max(1, limit), config.maxLimit);
|
|
213
|
+
}
|
|
108
214
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAiBnD;;;GAGG;AACH,MAAM,UAAU,WAAW;IACzB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,WAAW,EAAE,CAAC;IACnD,MAAM,WAAW,GAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;IAE5E,IAAI,KAAK,IAAI,WAAW,CAAC,QAAQ,CAAC,KAAiB,CAAC,EAAE,CAAC;QACrD,OAAO,KAAiB,CAAC;IAC3B,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,0BAA0B,QAAQ,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,YAAY,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;AAC/C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,SAAS,CAAC,MAAc,EAAE,UAAkB;IAC1D,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IACzC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IACtC,CAAC;IACD,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AAC7B,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAgB;IAC/C,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC;IAChC,IAAI,CAAC,OAAO;QAAE,OAAO,KAAK,CAAC;IAE3B,8CAA8C;IAC9C,MAAM,WAAW,GAAG,8CAA8C,CAAC;IACnE,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IAC7C,IAAI,SAAS,EAAE,CAAC;QACd,+BAA+B;QAC/B,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;YACxC,MAAM,GAAG,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;YAChC,OAAO,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,GAAG,CAAC;QAChC,CAAC,CAAC,CAAC;IACL,CAAC;IAED,+BAA+B;IAC/B,6BAA6B;IAC7B,iFAAiF;IACjF,iCAAiC;IACjC,IAAI,OAAO,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAC;IAEvC,MAAM,eAAe,GACnB,+FAA+F,CAAC;IAClG,OAAO,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CAAC,aAAiC;IACzD,IAAI,CAAC,aAAa,EAAE,CAAC;QACnB,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAA2B,EAAE,CAAC;IAC3C,MAAM,KAAK,GAAG,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,SAAS;QAEvB,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,OAAO,GAAG,CAAC,EAAE,CAAC;YAChB,MAAM,GAAG,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;YACjD,MAAM,KAAK,GAAG,OAAO,CAAC,SAAS,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC3C,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;IAClE,MAAM,QAAQ,GAAG,SAAS,CAAC,eAAe,EAAE,oBAAoB,CAAC,CAAC;IAElE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CACb,kCAAkC,QAAQ,8CAA8C,CACzF,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACb,8FAA8F,CAC/F,CAAC;IACJ,CAAC;IAED,OAAO;QACL,QAAQ;QACR,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,KAAK,EAAE,EAAE,CAAC;QAClD,QAAQ;QACR,QAAQ;QACR,QAAQ,EAAE,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,QAAQ;QAC/C,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE;QACrC,WAAW,EAAE,gBAAgB,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;KAC7D,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAAkB;IAMtD,MAAM,gBAAgB,GAKlB;QACF,IAAI,EAAE,MAAM,CAAC,QAAQ;QACrB,IAAI,EAAE,MAAM,CAAC,QAAQ;QACrB,QAAQ,EAAE,MAAM,CAAC,QAAQ;KAC1B,CAAC;IAEF,6EAA6E;IAC7E,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClC,gBAAgB,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;IACxC,CAAC;IAED,mCAAmC;IACnC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC,aAAa,CAAC,EAAE,CAAC;QACvC,gBAAgB,CAAC,aAAa,CAAC,GAAG,KAAK,CAAC;IAC1C,CAAC;IAED,gCAAgC;IAChC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,WAAW,CAAC,EAAE,CAAC;QAC9D,gBAAgB,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,OAAO,gBAAgB,CAAC;AAC1B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,OAAO,MAAM,CAAC,MAAM,IAAI,SAAS,CAAC;AACpC,CAAC;AAcD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAoB;IACjD,QAAQ,EAAE,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,aAAa;IACvC,WAAW,EAAE,GAAG;IAChB,OAAO,EAAE,IAAI;CACd,CAAC;AAYF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAqB;IACnD,YAAY,EAAE,IAAI;IAClB,QAAQ,EAAE,KAAK;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,mBAAmB;IACjC,MAAM,YAAY,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7E,MAAM,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,OAAO,EAAE,EAAE,CAAC,CAAC;IAEtE,OAAO;QACL,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,YAAY,CAAC;QACvC,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC;KAChC,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,cAAkC,EAClC,SAA2B,mBAAmB,EAAE;IAEhD,MAAM,KAAK,GAAG,cAAc,IAAI,MAAM,CAAC,YAAY,CAAC;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;AACvD,CAAC"}
|
package/dist/server.js
CHANGED
|
@@ -62,12 +62,12 @@ export function createServer() {
|
|
|
62
62
|
inputSchema: {
|
|
63
63
|
sql: z.string().describe('SQL SELECT query to execute'),
|
|
64
64
|
params: z.array(z.unknown()).optional().describe('Query parameters for prepared statement'),
|
|
65
|
-
limit: z.number().optional().default(1000).describe('Maximum number of rows to return (default: 1000)'),
|
|
65
|
+
limit: z.number().optional().default(1000).describe('Maximum number of rows to return (default: 1000, max: configured via QUERY_MAX_LIMIT)'),
|
|
66
66
|
},
|
|
67
67
|
}, withToolHandler((args) => executeQueryTool({
|
|
68
68
|
sql: args.sql,
|
|
69
69
|
params: args.params,
|
|
70
|
-
limit: args.limit
|
|
70
|
+
limit: args.limit,
|
|
71
71
|
}), 'Query failed'));
|
|
72
72
|
// Register list_schemas tool
|
|
73
73
|
server.registerTool('list_schemas', {
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EACL,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,aAAa,EACb,eAAe,EACf,uBAAuB,GACxB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD,sEAAsE;AACtE,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,WAAW,GAAG,OAAO,CAAC,iBAAiB,CAAsC,CAAC;AAEpF,MAAM,CAAC,MAAM,WAAW,GAAG,WAAW,CAAC,IAAI,CAAC;AAC5C,MAAM,CAAC,MAAM,cAAc,GAAG,WAAW,CAAC,OAAO,CAAC;AAmBlD;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA0C,EAC1C,YAAoB;IAEpB,OAAO,KAAK,EAAE,IAAW,EAA4B,EAAE;QACrD,mBAAmB;QACnB,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;QACrC,MAAM,UAAU,GAAG,WAAW,CAAC,UAAU,EAAE,CAAC;QAE5C,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC;YACxB,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YAClD,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBACjE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,mBAAmB;QACnB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAEnC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,KAAK,IAAI,YAAY,EAAE,CAAC;gBAC/D,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;QAED,OAAO;YACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;SACnE,CAAC;IACJ,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,cAAc;KACxB,CAAC,CAAC;IAEH,8BAA8B;IAC9B,MAAM,CAAC,YAAY,CACjB,eAAe,EACf;QACE,KAAK,EAAE,mBAAmB;QAC1B,WAAW,EAAE,mLAAmL;QAChM,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;QACnC,WAAW,EAAE;YACX,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;YACvD,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;YAC3F,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/query.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC;IACxE,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC,CAkDD"}
|
package/dist/tools/query.js
CHANGED
|
@@ -4,13 +4,16 @@
|
|
|
4
4
|
import { executeQuery } from '../db/connection.js';
|
|
5
5
|
import { validateQuery } from '../db/queries.js';
|
|
6
6
|
import { createChildLogger } from '../utils/logger.js';
|
|
7
|
+
import { applyQueryLimit, getQueryLimitConfig } from '../config.js';
|
|
7
8
|
const log = createChildLogger({ component: 'query-tool' });
|
|
8
9
|
/**
|
|
9
10
|
* Execute a read-only SQL query
|
|
10
11
|
*/
|
|
11
12
|
export async function executeQueryTool(input) {
|
|
12
|
-
const { sql, params = []
|
|
13
|
-
|
|
13
|
+
const { sql, params = [] } = input;
|
|
14
|
+
const queryConfig = getQueryLimitConfig();
|
|
15
|
+
const effectiveLimit = applyQueryLimit(input.limit, queryConfig);
|
|
16
|
+
log.debug({ sqlPreview: sql.substring(0, 100), requestedLimit: input.limit, effectiveLimit }, 'Received query request');
|
|
14
17
|
// Validate that query is read-only using enhanced security validator
|
|
15
18
|
const validationResult = validateQuery(sql);
|
|
16
19
|
if (!validationResult.isValid) {
|
|
@@ -30,14 +33,15 @@ export async function executeQueryTool(input) {
|
|
|
30
33
|
if (limitedSql.endsWith(';')) {
|
|
31
34
|
limitedSql = limitedSql.slice(0, -1);
|
|
32
35
|
}
|
|
33
|
-
limitedSql = `${limitedSql} FETCH FIRST ${
|
|
36
|
+
limitedSql = `${limitedSql} FETCH FIRST ${effectiveLimit} ROWS ONLY`;
|
|
34
37
|
}
|
|
35
38
|
const result = await executeQuery(limitedSql, params);
|
|
36
|
-
log.info({ rowCount: result.rows.length }, 'Query executed successfully');
|
|
39
|
+
log.info({ rowCount: result.rows.length, effectiveLimit }, 'Query executed successfully');
|
|
37
40
|
return {
|
|
38
41
|
success: true,
|
|
39
42
|
data: result.rows,
|
|
40
43
|
rowCount: result.rows.length,
|
|
44
|
+
limitApplied: effectiveLimit,
|
|
41
45
|
};
|
|
42
46
|
}
|
|
43
47
|
catch (error) {
|
package/dist/tools/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/tools/query.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAEpE,MAAM,GAAG,GAAG,iBAAiB,CAAC,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC,CAAC;AAW3D;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,KAAwB;IAQ7D,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC;IACnC,MAAM,WAAW,GAAG,mBAAmB,EAAE,CAAC;IAC1C,MAAM,cAAc,GAAG,eAAe,CAAC,KAAK,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAEjE,GAAG,CAAC,KAAK,CACP,EAAE,UAAU,EAAE,GAAG,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,cAAc,EAAE,KAAK,CAAC,KAAK,EAAE,cAAc,EAAE,EAClF,wBAAwB,CACzB,CAAC;IAEF,qEAAqE;IACrE,MAAM,gBAAgB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC,gBAAgB,CAAC,OAAO,EAAE,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,gBAAgB,CAAC,UAAU,EAAE,EAAE,4CAA4C,CAAC,CAAC;QACpG,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,+BAA+B,gBAAgB,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;YAC9E,UAAU,EAAE,gBAAgB,CAAC,UAAU;SACxC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACH,iEAAiE;QACjE,IAAI,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,aAAa,CAAC;YACjD,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAChD,uCAAuC;YACvC,IAAI,UAAU,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;gBAC7B,UAAU,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;YACvC,CAAC;YACD,UAAU,GAAG,GAAG,UAAU,gBAAgB,cAAc,YAAY,CAAC;QACvE,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,MAAmB,CAAC,CAAC;QAEnE,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,cAAc,EAAE,EAAE,6BAA6B,CAAC,CAAC;QAC1F,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,MAAM,CAAC,IAAI;YACjB,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM;YAC5B,YAAY,EAAE,cAAc;SAC7B,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,wBAAwB,CAAC;QAClF,GAAG,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,wBAAwB,CAAC,CAAC;QACpD,OAAO;YACL,OAAO,EAAE,KAAK;YACd,KAAK,EAAE,OAAO;SACf,CAAC;IACJ,CAAC;AACH,CAAC"}
|