@zz1996/dbhub-dameng 0.1.7 → 1.2.5-dameng.620

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.
Files changed (32) hide show
  1. package/README.md +56 -164
  2. package/dbhub.dameng.toml.example +4 -11
  3. package/dist/{chunk-SQA2ISDE.js → chunk-2JL4KCP5.js} +21 -119
  4. package/dist/chunk-3RJRH3CN.js +121 -0
  5. package/dist/chunk-4276LPPU.js +179 -0
  6. package/dist/chunk-FU2ZJE4E.js +16 -0
  7. package/dist/chunk-HDPZAIDL.js +155 -0
  8. package/dist/{chunk-2A2QF3CS.js → chunk-HGU7ILEZ.js} +215 -68
  9. package/dist/{chunk-IPK7BYBL.js → chunk-JFWX35TB.js} +0 -1
  10. package/dist/chunk-O3PEWKBB.js +302 -0
  11. package/dist/dameng-NKF7NZKE.js +250 -0
  12. package/dist/index.js +461 -251
  13. package/dist/{mariadb-7F72IRB4.js → mariadb-MMC6WMEG.js} +86 -53
  14. package/dist/{mysql-A43SL7UM.js → mysql-TESH7KKV.js} +126 -50
  15. package/dist/{postgres-VFNLBWMF.js → postgres-C24SBQ4I.js} +154 -36
  16. package/dist/public/assets/index-BJ-1UrcV.css +1 -0
  17. package/dist/public/assets/index-BdBaFSHd.js +148 -0
  18. package/dist/public/assets/postgres-BpcazhJg.svg +22 -0
  19. package/dist/public/assets/sqlserver-ByfFYYpV.svg +11 -0
  20. package/dist/public/favicon.svg +57 -0
  21. package/dist/public/index.html +14 -0
  22. package/dist/public/logo-full-light.svg +58 -0
  23. package/dist/{registry-XSX2VZTD.js → registry-WVSFVS35.js} +3 -2
  24. package/dist/{sqlite-IOUAYHGE.js → sqlite-7BNGDMBZ.js} +57 -42
  25. package/dist/sqlserver-KZPPK67Q.js +1042 -0
  26. package/package.json +22 -65
  27. package/dist/chunk-RTB262PR.js +0 -60
  28. package/dist/chunk-ZNQTMARG.js +0 -127
  29. package/dist/dameng-5KYI5JBK.js +0 -898
  30. package/dist/sqlserver-OE4SFH4B.js +0 -587
  31. package/docs/README.md +0 -14
  32. package/docs/dameng-connector-plan.md +0 -143
package/README.md CHANGED
@@ -1,183 +1,75 @@
1
- > [!NOTE]
2
- > Brought to you by [Bytebase](https://www.bytebase.com/), open-source database DevSecOps platform.
3
-
4
- > [!NOTE]
5
- > This package is a local Dameng/DM8 connector fork of Bytebase DBHub. Use
6
- > `npx -y @zz1996/dbhub-dameng --transport stdio --config ./dbhub.dameng.toml`
7
- > for Dameng MCP usage.
8
- >
9
- > Dameng DSN format: `dameng://user:password@host:5236/schema`. Prefer a
10
- > least-privilege read-only Dameng account for production or shared databases,
11
- > even when the `execute_sql` tool is configured with `readonly = true`.
12
-
13
- <p align="center">
14
- <a href="https://dbhub.ai/" target="_blank">
15
- <picture>
16
- <source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/bytebase/dbhub/main/docs/images/logo/full-dark.svg" width="75%">
17
- <source media="(prefers-color-scheme: light)" srcset="https://raw.githubusercontent.com/bytebase/dbhub/main/docs/images/logo/full-light.svg" width="75%">
18
- <img src="https://raw.githubusercontent.com/bytebase/dbhub/main/docs/images/logo/full-light.svg" width="75%" alt="DBHub Logo">
19
- </picture>
20
- </a>
21
- </p>
22
-
23
- ```bash
24
- +------------------+ +--------------+ +------------------+
25
- | | | | | |
26
- | | | | | |
27
- | Claude Desktop +--->+ +--->+ PostgreSQL |
28
- | | | | | |
29
- | Claude Code +--->+ +--->+ SQL Server |
30
- | | | | | |
31
- | Cursor +--->+ DBHub +--->+ SQLite |
32
- | | | | | |
33
- | VS Code +--->+ +--->+ MySQL |
34
- | | | | | |
35
- | Copilot CLI +--->+ +--->+ MariaDB |
36
- | | | | | |
37
- | +--->+ +--->+ Dameng / DM8 |
38
- | | | | | |
39
- +------------------+ +--------------+ +------------------+
40
- MCP Clients MCP Server Databases
41
- ```
42
-
43
- DBHub is a zero-dependency, token efficient MCP server implementing the Model Context Protocol (MCP) server interface. This lightweight gateway allows MCP-compatible clients to connect to and explore different databases:
44
-
45
- - **Local Development First**: Zero dependency, token efficient with just two MCP tools to maximize context window
46
- - **Multi-Database**: PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, and Dameng/DM8 through a single interface
47
- - **Multi-Connection**: Connect to multiple databases simultaneously with TOML configuration
48
- - **Guardrails**: Read-only mode, row limiting, and query timeout to prevent runaway operations
49
- - **Secure Access**: SSH tunneling and SSL/TLS encryption
50
-
51
- ## Supported Databases
52
-
53
- PostgreSQL, MySQL, SQL Server, MariaDB, SQLite, and Dameng/DM8.
54
-
55
- ## MCP Tools
56
-
57
- DBHub implements MCP tools for database operations:
58
-
59
- - **[execute_sql](https://dbhub.ai/tools/execute-sql)**: Execute SQL queries with transaction support and safety controls
60
- - **[search_objects](https://dbhub.ai/tools/search-objects)**: Search and explore database schemas, tables, columns, indexes, and procedures with progressive disclosure
61
- - **[Custom Tools](https://dbhub.ai/tools/custom-tools)**: Define reusable, parameterized SQL operations in your `dbhub.toml` configuration file
1
+ # DBHub:最小达梦适配
62
2
 
63
- ## Workbench
3
+ 基于 [Bytebase DBHub](https://github.com/bytebase/dbhub) 的薄层 fork。
4
+ 默认仍只有 `search_objects` 和 `execute_sql`,保留上游搜索流程和结果格式。
64
5
 
65
- DBHub includes a [built-in web interface](https://dbhub.ai/workbench/overview) for interacting with your database tools. It provides a visual way to execute queries, run custom tools, and view request traces without requiring an MCP client.
6
+ ## 使用
66
7
 
67
- ![workbench](https://raw.githubusercontent.com/bytebase/dbhub/main/docs/images/workbench/workbench.webp)
8
+ Node.js >= 22.5。将 `dbhub.dameng.toml.example` 复制为本地 `dbhub.toml`,
9
+ 通过环境变量 `DAMENG_DSN` 提供连接串:
68
10
 
69
- ## Installation
70
-
71
- See the full [Installation Guide](https://dbhub.ai/installation) for detailed instructions.
72
-
73
- ### Quick Start
74
-
75
- **Docker:**
76
-
77
- ```bash
78
- docker run --rm --init \
79
- --name dbhub \
80
- --publish 8080:8080 \
81
- bytebase/dbhub \
82
- --transport http \
83
- --port 8080 \
84
- --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
11
+ ```text
12
+ dameng://user:password@host:5236/APP
85
13
  ```
86
14
 
87
- **NPM:** (requires Node.js >= 22.5.0)
15
+ 账号、密码中的特殊字符需要 URL 编码。路径是 schema,名称与数据库保持一致,
16
+ 包括大小写。使用最小权限只读账号连接共享或生产库。
88
17
 
89
- ```bash
90
- npx @bytebase/dbhub@latest --transport http --port 8080 --dsn "postgres://user:password@localhost:5432/dbname?sslmode=disable"
18
+ ```sh
19
+ npx @zz1996/dbhub-dameng@latest --transport stdio --config ./dbhub.toml
91
20
  ```
92
21
 
93
- **Dameng / DM8 fork:**
94
-
95
- ```bash
96
- npx -y @zz1996/dbhub-dameng --transport stdio --config ./dbhub.dameng.toml
97
- ```
98
-
99
- Minimal Dameng TOML configuration:
100
-
101
- ```toml
102
- [[sources]]
103
- id = "dm8_readonly"
104
- description = "Dameng DM8 database for schema discovery and read-only SQL queries"
105
- dsn = "dameng://${DM8_USER}:${DM8_PASSWORD}@${DM8_HOST}:5236/${DM8_SCHEMA}"
106
- query_timeout = 30
107
- lazy = true
108
-
109
- [[tools]]
110
- name = "search_objects"
111
- source = "dm8_readonly"
112
-
113
- [[tools]]
114
- name = "execute_sql"
115
- source = "dm8_readonly"
116
- readonly = true
117
- max_rows = 100
22
+ - 驱动为固定版本 `dmdb`,采用原生连接池、参数绑定和行数限制。
23
+ - 不增加连接重试、超时重建、后台恢复或元数据搜索加速。
24
+ - `connection_timeout`、`query_timeout` 分别传给驱动的 `connectTimeout`、`sessionTimeout`。
25
+ - SQL 结果按语句返回,超过 `max_rows` 时附带 `truncated`。
26
+ - 自定义工具使用 `?` 占位符;参数仅支持单语句。
27
+ - 只读判断复用上游策略,不能代替数据库账号权限;函数副作用不由连接器保证隔离。
28
+ - 本实验覆盖普通 SQL 查询和元数据浏览;不提供达梦 `explain_sql`、`health_check`,
29
+ 不支持包含内部分号的匿名 PL/SQL 块。初始化脚本按上游惯例在启动时执行,
30
+ 不应依赖它设置连接池每条连接的会话状态,schema 应在 DSN 中指定。
31
+
32
+ ## 验证
33
+
34
+ ```sh
35
+ pnpm install --frozen-lockfile
36
+ pnpm test:unit
37
+ pnpm build
38
+ pnpm test:build
39
+ # 可选:明确指定本机配置,只读验证真实 DM8(不会执行 init_script)
40
+ node scripts/verify-dameng.mjs /absolute/path/to/dbhub.toml [source-id]
118
41
  ```
119
42
 
120
- To verify the local Dameng connector against a real DM8 instance without
121
- committing credentials, set `DAMENG_DSN` or point to a local TOML file:
43
+ GitHub 检查无需真实库凭据;真实 DM8 验证在本机显式运行。
122
44
 
123
- ```bash
124
- DAMENG_DSN="dameng://user:password@host:5236/schema" pnpm verify:dameng
125
- pnpm verify:dameng -- --config ./dbhub.dameng.toml --source dm8_readonly
126
- ```
45
+ ## 自动同步和发布
127
46
 
128
- **Demo Mode:**
47
+ `.github/workflows/dameng-sync-publish.yml` 每天北京时间 10:23 执行,
48
+ 也会在 `main` 更新时执行,支持手动运行。
129
49
 
130
- ```bash
131
- npx @bytebase/dbhub@latest --transport http --port 8080 --demo
132
- ```
133
-
134
- **Restrict to loopback (recommended for production):**
135
-
136
- ```bash
137
- npx @bytebase/dbhub@latest --transport http --host 127.0.0.1 --port 8080 --demo
138
- ```
139
-
140
- > The HTTP transport defaults to `--host 0.0.0.0`, exposing DBHub on every network interface. For production, bind to `127.0.0.1` and front DBHub with a reverse proxy (nginx/Caddy) or firewall — DBHub does not authenticate HTTP clients.
141
- >
142
- > The HTTP transport also has built-in DNS-rebinding protection: it only accepts requests whose `Host` is loopback, this machine's own hostname/IPs, or a name you allow via [`--allowed-hosts`](https://dbhub.ai/config/command-line#allowed-hosts). If a client behind a reverse proxy or custom DNS name gets a `403`, add that hostname with `--allowed-hosts`.
143
-
144
- See [Command-Line Options](https://dbhub.ai/config/command-line) for all available parameters.
145
-
146
- ### Multi-Database Setup
147
-
148
- Connect to multiple databases simultaneously using TOML configuration files. Perfect for managing production, staging, and development databases from a single DBHub instance.
149
-
150
- See [Multi-Database Configuration](https://dbhub.ai/config/toml) for complete setup instructions.
151
-
152
- ## Development
153
-
154
- Requires Node.js >= 22.5.0 (DBHub uses the built-in `node:sqlite` module).
155
-
156
- ```bash
157
- # Install dependencies
158
- pnpm install
159
-
160
- # Run in development mode
161
- pnpm dev
162
-
163
- # Build and run for production
164
- pnpm build && pnpm start --transport stdio --dsn "postgres://user:password@localhost:5432/dbname"
165
- ```
50
+ 1. 将最新 `bytebase/dbhub:main` 合并到临时工作区。
51
+ 2. 安装锁定依赖,运行单测、完整构建与打包导入检查。
52
+ 3. 全部通过后才将合并提交推送到本仓库 `main`,不强推。
53
+ 4. 准备发布目录,使用 npm OIDC 发布 `@zz1996/dbhub-dameng`。
166
54
 
167
- See [Testing](.claude/skills/testing/SKILL.md) and [Debug](https://dbhub.ai/config/debug).
55
+ 冲突、测试或构建失败时停止,不更新远端 `main`,通过 GitHub Actions 失败通知处理。
56
+ 发布失败时保留已验证的合并结果,可重新运行;已发布版本会跳过。
57
+ 机器人推送不会触发新的 workflow;产生合并提交后显式再次触发本工作流,
58
+ 由新提交对应的运行发布,确保 npm provenance 指向实际构建的提交。
59
+ 这是检查后直接合并的最小流程,不创建自动审批 PR,也不需要长期 PAT。
168
60
 
169
- ## Contributors
61
+ 源码的 `package.json` 版本号、包名、上游 README 和上游发布工作流保持原样。
62
+ 仅打包时设置 fork 身份,版本为 `<上游版本>-dameng.<提交总数>`,发布到 `latest` 标签。
63
+ 例如 `1.2.5-dameng.620`;它是独立 fork 版本,不是 Bytebase 官方发行版。
64
+ 每次代码合并都会得到新版本,同一提交重跑使用同一个版本号。
170
65
 
171
- <a href="https://github.com/bytebase/dbhub/graphs/contributors">
172
- <img src="https://contrib.rocks/image?repo=bytebase/dbhub" />
173
- </a>
66
+ 首次配置:
174
67
 
175
- ## Star History
68
+ - 在本仓库 Actions 设置中禁用继承的 `npm-publish.yml`、`docker-publish.yml`、
69
+ `mcpb-release.yml`,避免执行 Bytebase 的发布流程;保持文件原样以降低同步冲突。
70
+ - 在 npm 包设置中添加 GitHub Actions Trusted Publisher:用户 `zuozh11`,
71
+ 仓库 `dbhub-dameng`,工作流 `dameng-sync-publish.yml`,环境名留空,允许 `npm publish`。
72
+ - workflow 显式申请 `contents: write`、`actions: write` 和 `id-token: write`;无需 npm token。
73
+ - 手动运行时可取消 `publish`,只验证同步和打包。
176
74
 
177
- <a href="https://www.star-history.com/?repos=bytebase%2Fdbhub&type=date&legend=top-left">
178
- <picture>
179
- <source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/chart?repos=bytebase/dbhub&type=date&theme=dark&legend=top-left" />
180
- <source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/chart?repos=bytebase/dbhub&type=date&legend=top-left" />
181
- <img alt="Star History Chart" src="https://api.star-history.com/chart?repos=bytebase/dbhub&type=date&legend=top-left" />
182
- </picture>
183
- </a>
75
+ 旧实现保留在 `dameng-connector` 分支中;新实现不继承其恢复机制。
@@ -1,20 +1,13 @@
1
- # Example DBHub configuration for the local Dameng/DM8 fork.
2
- # Do not commit real credentials. Prefer environment variables.
3
-
4
1
  [[sources]]
5
- id = "dm8_dev"
6
- description = "Dameng DM8 development database. Read-only access for agent schema discovery and SQL queries."
7
- dsn = "dameng://${DM8_USER}:${DM8_PASSWORD}@${DM8_HOST}:5236/${DM8_SCHEMA}"
8
- connection_timeout = 5
9
- query_timeout = 30
10
- lazy = true
2
+ id = "default"
3
+ dsn = "${DAMENG_DSN}"
11
4
 
12
5
  [[tools]]
13
6
  name = "execute_sql"
14
- source = "dm8_dev"
7
+ source = "default"
15
8
  readonly = true
16
9
  max_rows = 100
17
10
 
18
11
  [[tools]]
19
12
  name = "search_objects"
20
- source = "dm8_dev"
13
+ source = "default"
@@ -91,7 +91,9 @@ var SafeURL = class {
91
91
  }
92
92
  });
93
93
  }
94
- const atIndex = urlString.indexOf("@");
94
+ const pathStart = urlString.indexOf("/");
95
+ const authorityEnd = pathStart === -1 ? urlString.length : pathStart;
96
+ const atIndex = urlString.lastIndexOf("@", authorityEnd - 1);
95
97
  if (atIndex !== -1) {
96
98
  const auth = urlString.substring(0, atIndex);
97
99
  urlString = urlString.substring(atIndex + 1);
@@ -143,118 +145,6 @@ var SafeURL = class {
143
145
  }
144
146
  };
145
147
 
146
- // src/utils/dsn-obfuscate.ts
147
- function parseConnectionInfoFromDSN(dsn) {
148
- if (!dsn) {
149
- return null;
150
- }
151
- try {
152
- const type = getDatabaseTypeFromDSN(dsn);
153
- if (typeof type === "undefined") {
154
- return null;
155
- }
156
- if (type === "sqlite") {
157
- const prefix = "sqlite:///";
158
- if (dsn.length > prefix.length) {
159
- const rawPath = dsn.substring(prefix.length);
160
- const firstChar = rawPath[0];
161
- const isWindowsDrive = rawPath.length > 1 && rawPath[1] === ":";
162
- const isSpecialPath = firstChar === ":" || firstChar === "." || firstChar === "~" || isWindowsDrive;
163
- return {
164
- type,
165
- database: isSpecialPath ? rawPath : "/" + rawPath
166
- };
167
- }
168
- return { type };
169
- }
170
- const url = new SafeURL(dsn);
171
- const info = { type };
172
- if (url.hostname) {
173
- info.host = url.hostname;
174
- }
175
- if (url.port) {
176
- info.port = parseInt(url.port, 10);
177
- }
178
- if (url.pathname && url.pathname.length > 1) {
179
- info.database = url.pathname.substring(1);
180
- }
181
- if (url.username) {
182
- info.user = url.username;
183
- }
184
- return info;
185
- } catch {
186
- return null;
187
- }
188
- }
189
- function obfuscateDSNPassword(dsn) {
190
- if (!dsn) {
191
- return dsn;
192
- }
193
- try {
194
- const type = getDatabaseTypeFromDSN(dsn);
195
- if (type === "sqlite") {
196
- return dsn;
197
- }
198
- const url = new SafeURL(dsn);
199
- if (!url.password) {
200
- return dsn;
201
- }
202
- const obfuscatedPassword = "*".repeat(Math.min(url.password.length, 8));
203
- const protocol = dsn.split(":")[0];
204
- let result;
205
- if (url.username) {
206
- result = `${protocol}://${url.username}:${obfuscatedPassword}@${url.hostname}`;
207
- } else {
208
- result = `${protocol}://${obfuscatedPassword}@${url.hostname}`;
209
- }
210
- if (url.port) {
211
- result += `:${url.port}`;
212
- }
213
- result += url.pathname;
214
- if (url.searchParams.size > 0) {
215
- const params = [];
216
- url.forEachSearchParam((value, key) => {
217
- params.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
218
- });
219
- result += `?${params.join("&")}`;
220
- }
221
- return result;
222
- } catch {
223
- return dsn;
224
- }
225
- }
226
- function getDatabaseTypeFromDSN(dsn) {
227
- if (!dsn) {
228
- return void 0;
229
- }
230
- const protocol = dsn.split(":")[0];
231
- return protocolToConnectorType(protocol);
232
- }
233
- function protocolToConnectorType(protocol) {
234
- const mapping = {
235
- "postgres": "postgres",
236
- "postgresql": "postgres",
237
- "mysql": "mysql",
238
- "mariadb": "mariadb",
239
- "sqlserver": "sqlserver",
240
- "sqlite": "sqlite",
241
- "dameng": "dameng",
242
- "dm": "dameng"
243
- };
244
- return mapping[protocol];
245
- }
246
- function getDefaultPortForType(type) {
247
- const ports = {
248
- "postgres": 5432,
249
- "mysql": 3306,
250
- "mariadb": 3306,
251
- "sqlserver": 1433,
252
- "sqlite": void 0,
253
- "dameng": 5236
254
- };
255
- return ports[type];
256
- }
257
-
258
148
  // src/utils/sql-parser.ts
259
149
  var TokenType = { Plain: 0, Comment: 1, QuotedBlock: 2 };
260
150
  function plainToken(i) {
@@ -431,12 +321,12 @@ function scanTokenSQLServer(sql, i) {
431
321
  return scanSingleLineComment(sql, i) ?? scanMultiLineComment(sql, i) ?? scanSingleQuotedString(sql, i) ?? scanDoubleQuotedString(sql, i) ?? scanBracketQuotedIdentifier(sql, i) ?? plainToken(i);
432
322
  }
433
323
  var dialectScanners = {
324
+ dameng: scanTokenAnsi,
434
325
  postgres: scanTokenPostgres,
435
326
  mysql: scanTokenMySQL,
436
327
  mariadb: scanTokenMySQL,
437
328
  sqlite: scanTokenSQLite,
438
- sqlserver: scanTokenSQLServer,
439
- dameng: scanTokenAnsi
329
+ sqlserver: scanTokenSQLServer
440
330
  };
441
331
  function getScanner(dialect) {
442
332
  return dialect ? dialectScanners[dialect] ?? scanTokenAnsi : scanTokenAnsi;
@@ -466,6 +356,21 @@ function stripCommentsAndStrings(sql, dialect) {
466
356
  }
467
357
  return parts.join("");
468
358
  }
359
+ function blankCommentsAndStrings(sql, dialect) {
360
+ const scanToken = getScanner(dialect);
361
+ let result = "";
362
+ let i = 0;
363
+ while (i < sql.length) {
364
+ const token = scanToken(sql, i);
365
+ if (token.type === TokenType.Plain) {
366
+ result += sql[i];
367
+ } else {
368
+ result += " ".repeat(token.end - i);
369
+ }
370
+ i = token.end;
371
+ }
372
+ return result;
373
+ }
469
374
  function splitSQLStatements(sql, dialect) {
470
375
  const scanToken = getScanner(dialect);
471
376
  const statements = [];
@@ -494,10 +399,7 @@ function splitSQLStatements(sql, dialect) {
494
399
  export {
495
400
  ConnectorRegistry,
496
401
  SafeURL,
497
- parseConnectionInfoFromDSN,
498
- obfuscateDSNPassword,
499
- getDatabaseTypeFromDSN,
500
- getDefaultPortForType,
501
402
  stripCommentsAndStrings,
403
+ blankCommentsAndStrings,
502
404
  splitSQLStatements
503
405
  };
@@ -0,0 +1,121 @@
1
+ import {
2
+ SafeURL
3
+ } from "./chunk-2JL4KCP5.js";
4
+
5
+ // src/utils/dsn-obfuscate.ts
6
+ function parseConnectionInfoFromDSN(dsn) {
7
+ if (!dsn) {
8
+ return null;
9
+ }
10
+ try {
11
+ const type = getDatabaseTypeFromDSN(dsn);
12
+ if (typeof type === "undefined") {
13
+ return null;
14
+ }
15
+ if (type === "sqlite") {
16
+ const prefix = "sqlite:///";
17
+ if (dsn.length > prefix.length) {
18
+ const rawPath = dsn.substring(prefix.length);
19
+ const firstChar = rawPath[0];
20
+ const isWindowsDrive = rawPath.length > 1 && rawPath[1] === ":";
21
+ const isSpecialPath = firstChar === ":" || firstChar === "." || firstChar === "~" || isWindowsDrive;
22
+ return {
23
+ type,
24
+ database: isSpecialPath ? rawPath : "/" + rawPath
25
+ };
26
+ }
27
+ return { type };
28
+ }
29
+ const url = new SafeURL(dsn);
30
+ const info = { type };
31
+ if (url.hostname) {
32
+ info.host = url.hostname;
33
+ }
34
+ if (url.port) {
35
+ info.port = parseInt(url.port, 10);
36
+ }
37
+ if (url.pathname && url.pathname.length > 1) {
38
+ info.database = url.pathname.substring(1);
39
+ }
40
+ if (url.username) {
41
+ info.user = url.username;
42
+ }
43
+ return info;
44
+ } catch {
45
+ return null;
46
+ }
47
+ }
48
+ function obfuscateDSNPassword(dsn) {
49
+ if (!dsn) {
50
+ return dsn;
51
+ }
52
+ try {
53
+ const type = getDatabaseTypeFromDSN(dsn);
54
+ if (type === "sqlite") {
55
+ return dsn;
56
+ }
57
+ const url = new SafeURL(dsn);
58
+ if (!url.password) {
59
+ return dsn;
60
+ }
61
+ const obfuscatedPassword = "*".repeat(Math.min(url.password.length, 8));
62
+ const protocol = dsn.split(":")[0];
63
+ let result;
64
+ if (url.username) {
65
+ result = `${protocol}://${url.username}:${obfuscatedPassword}@${url.hostname}`;
66
+ } else {
67
+ result = `${protocol}://${obfuscatedPassword}@${url.hostname}`;
68
+ }
69
+ if (url.port) {
70
+ result += `:${url.port}`;
71
+ }
72
+ result += url.pathname;
73
+ if (url.searchParams.size > 0) {
74
+ const params = [];
75
+ url.forEachSearchParam((value, key) => {
76
+ params.push(`${encodeURIComponent(key)}=${encodeURIComponent(value)}`);
77
+ });
78
+ result += `?${params.join("&")}`;
79
+ }
80
+ return result;
81
+ } catch {
82
+ return dsn;
83
+ }
84
+ }
85
+ function getDatabaseTypeFromDSN(dsn) {
86
+ if (!dsn) {
87
+ return void 0;
88
+ }
89
+ const protocol = dsn.split(":")[0];
90
+ return protocolToConnectorType(protocol);
91
+ }
92
+ function protocolToConnectorType(protocol) {
93
+ const mapping = {
94
+ "dameng": "dameng",
95
+ "postgres": "postgres",
96
+ "postgresql": "postgres",
97
+ "mysql": "mysql",
98
+ "mariadb": "mariadb",
99
+ "sqlserver": "sqlserver",
100
+ "sqlite": "sqlite"
101
+ };
102
+ return mapping[protocol];
103
+ }
104
+ function getDefaultPortForType(type) {
105
+ const ports = {
106
+ "dameng": 5236,
107
+ "postgres": 5432,
108
+ "mysql": 3306,
109
+ "mariadb": 3306,
110
+ "sqlserver": 1433,
111
+ "sqlite": void 0
112
+ };
113
+ return ports[type];
114
+ }
115
+
116
+ export {
117
+ parseConnectionInfoFromDSN,
118
+ obfuscateDSNPassword,
119
+ getDatabaseTypeFromDSN,
120
+ getDefaultPortForType
121
+ };