dsh-lh-data 0.1.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 +332 -0
- package/cordis.patch.yml +7 -0
- package/lib/admin-contract.d.ts +274 -0
- package/lib/admin-http.d.ts +31 -0
- package/lib/admin-validate.d.ts +87 -0
- package/lib/admin.d.ts +60 -0
- package/lib/client.js +2969 -0
- package/lib/client.js.map +1 -0
- package/lib/datasource/columns.d.ts +13 -0
- package/lib/datasource/connection.d.ts +33 -0
- package/lib/datasource/connector/base.d.ts +21 -0
- package/lib/datasource/connector/mysql.d.ts +23 -0
- package/lib/datasource/connector/postgresql.d.ts +23 -0
- package/lib/datasource/crypto.d.ts +13 -0
- package/lib/datasource/driver.d.ts +39 -0
- package/lib/datasource/errors.d.ts +25 -0
- package/lib/datasource/importer.d.ts +38 -0
- package/lib/datasource/source-sql.d.ts +11 -0
- package/lib/datasource/source-store.d.ts +28 -0
- package/lib/datasource/types.d.ts +119 -0
- package/lib/db.d.ts +91 -0
- package/lib/http-common.d.ts +31 -0
- package/lib/http.d.ts +13 -0
- package/lib/index.d.ts +50 -0
- package/lib/index.js +5735 -0
- package/lib/parse.d.ts +41 -0
- package/lib/preview.d.ts +75 -0
- package/lib/render.d.ts +100 -0
- package/lib/scope-registry.d.ts +47 -0
- package/lib/scope.d.ts +56 -0
- package/lib/sql.d.ts +133 -0
- package/lib/store.d.ts +174 -0
- package/lib/table.d.ts +38 -0
- package/lib/tooling.d.ts +267 -0
- package/lib/tools/datasource.d.ts +16 -0
- package/lib/tools/import.d.ts +21 -0
- package/lib/tools/read.d.ts +77 -0
- package/lib/tools/registry.d.ts +12 -0
- package/lib/tools/write.d.ts +37 -0
- package/lib/view.d.ts +138 -0
- package/package.json +61 -0
- package/src/admin-contract.ts +351 -0
- package/src/admin-http.ts +254 -0
- package/src/admin-validate.ts +393 -0
- package/src/admin.ts +558 -0
- package/src/client/index.ts +403 -0
- package/src/client/settings/CreateForm.tsx +186 -0
- package/src/client/settings/DataSourceForm.tsx +278 -0
- package/src/client/settings/DataSourcesPanel.tsx +301 -0
- package/src/client/settings/DatasetEditor.tsx +245 -0
- package/src/client/settings/DatasetTable.tsx +110 -0
- package/src/client/settings/DatasetsPanel.tsx +207 -0
- package/src/client/settings/RowsPanel.tsx +196 -0
- package/src/client/settings/Section.tsx +41 -0
- package/src/client/settings/SourceTablesPanel.tsx +226 -0
- package/src/client/settings/api.ts +154 -0
- package/src/client/settings/styles.ts +125 -0
- package/src/datasource/columns.ts +56 -0
- package/src/datasource/connection.ts +124 -0
- package/src/datasource/connector/base.ts +54 -0
- package/src/datasource/connector/mysql.ts +187 -0
- package/src/datasource/connector/postgresql.ts +212 -0
- package/src/datasource/crypto.ts +61 -0
- package/src/datasource/driver.ts +108 -0
- package/src/datasource/errors.ts +69 -0
- package/src/datasource/importer.ts +262 -0
- package/src/datasource/index.ts +62 -0
- package/src/datasource/source-sql.ts +64 -0
- package/src/datasource/source-store.ts +152 -0
- package/src/datasource/types.ts +133 -0
- package/src/db.ts +277 -0
- package/src/http-common.ts +91 -0
- package/src/http.ts +130 -0
- package/src/index.ts +486 -0
- package/src/parse.ts +213 -0
- package/src/preview.ts +198 -0
- package/src/render.ts +294 -0
- package/src/scope-registry.ts +111 -0
- package/src/scope.ts +159 -0
- package/src/sql.ts +491 -0
- package/src/store.ts +412 -0
- package/src/table.ts +160 -0
- package/src/tooling.ts +551 -0
- package/src/tools/datasource.ts +378 -0
- package/src/tools/import.ts +282 -0
- package/src/tools/read.ts +536 -0
- package/src/tools/registry.ts +56 -0
- package/src/tools/write.ts +241 -0
- package/src/view.ts +371 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据库驱动的运行时加载。
|
|
3
|
+
*
|
|
4
|
+
* `mysql2` / `pg` 已随插件默认安装(`dependencies`),但仍走**动态 import**:
|
|
5
|
+
* 用到哪个才加载哪个,CLI 剖面与只用文件导入的用户不会被这两个包拖慢启动。
|
|
6
|
+
* 万一运行环境里缺包(裁剪安装、pnpm 过滤等),抛 `DataSourceError('DRIVER_MISSING')`
|
|
7
|
+
* 并在消息里带上安装命令,而不是崩在裸栈上。
|
|
8
|
+
*
|
|
9
|
+
* 导入说明符必须走变量,不能用字面量——字面量会让 TypeScript 与打包器在解析期
|
|
10
|
+
* 就去解析这两个包,缺包时 typecheck / build 直接失败。
|
|
11
|
+
*/
|
|
12
|
+
import type { DataSourceType } from './types';
|
|
13
|
+
export declare const DRIVER_INSTALL_HINTS: Readonly<Record<DataSourceType, string>>;
|
|
14
|
+
interface MysqlLike {
|
|
15
|
+
createPool(options: Record<string, unknown>): MysqlPoolLike;
|
|
16
|
+
createConnection(options: Record<string, unknown>): Promise<MysqlConnLike>;
|
|
17
|
+
}
|
|
18
|
+
export interface MysqlPoolLike {
|
|
19
|
+
execute(sql: string, params?: unknown[]): Promise<[unknown[], unknown]>;
|
|
20
|
+
end(): Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
interface MysqlConnLike {
|
|
23
|
+
execute(sql: string, params?: unknown[]): Promise<[unknown[], unknown]>;
|
|
24
|
+
end(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
interface PgLike {
|
|
27
|
+
Pool: new (options: Record<string, unknown>) => PgPoolLike;
|
|
28
|
+
}
|
|
29
|
+
export interface PgPoolLike {
|
|
30
|
+
query(sql: string, params?: unknown[]): Promise<{
|
|
31
|
+
rows: unknown[];
|
|
32
|
+
}>;
|
|
33
|
+
end(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
/** 仅供测试:清掉模块级缓存。 */
|
|
36
|
+
export declare function resetDriverCache(): void;
|
|
37
|
+
export declare function loadMysqlDriver(): Promise<MysqlLike>;
|
|
38
|
+
export declare function loadPgDriver(): Promise<PgLike>;
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据源模块的统一错误类型。
|
|
3
|
+
*
|
|
4
|
+
* 主机侧的边界(工具 / 管理接口)把它翻译成 `ToolError` / `AdminServiceError`。
|
|
5
|
+
* 错误文本一律脱敏:不含密码、不含本地物理表名。
|
|
6
|
+
*/
|
|
7
|
+
export type DataSourceErrorCode = 'NOT_FOUND' | 'DRIVER_MISSING' | 'UNREACHABLE' | 'BAD_REQUEST' | 'TOO_MANY_ROWS' | 'IMPORT_FAILED';
|
|
8
|
+
export declare class DataSourceError extends Error {
|
|
9
|
+
readonly code: DataSourceErrorCode;
|
|
10
|
+
constructor(code: DataSourceErrorCode, message: string);
|
|
11
|
+
}
|
|
12
|
+
export declare function isDataSourceError(error: unknown): error is DataSourceError;
|
|
13
|
+
/**
|
|
14
|
+
* 原生驱动错误 → 脱敏的中文提示。
|
|
15
|
+
* 只保留可定位的主机与端口,凭据绝不进文本。
|
|
16
|
+
*/
|
|
17
|
+
export declare function describeCause(error: unknown): string;
|
|
18
|
+
/**
|
|
19
|
+
* 连接 / 查询异常归一为 `DataSourceError`。
|
|
20
|
+
* 已经是 `DataSourceError` 的(如 DRIVER_MISSING)保持原语义,其余按「连不上」处理,
|
|
21
|
+
* 这样工具与设置页永远不会把驱动的裸栈抛给模型 / 浏览器。
|
|
22
|
+
*/
|
|
23
|
+
export declare function wrapConnectionError(error: unknown, host: string, port: number): unknown;
|
|
24
|
+
/** 错误码 → HTTP 状态码(管理接口用;工具侧另有一套映射)。 */
|
|
25
|
+
export declare function dataSourceErrorStatus(code: DataSourceErrorCode): number;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 远端表 → 本地数据集的导入。
|
|
3
|
+
*
|
|
4
|
+
* 落库完全复用文件导入的那一套(`createDatasetTable` / `insertRows` / `DatasetStore`),
|
|
5
|
+
* 因此导进来的数据集与 Excel 导入的**结构完全一致**,八个 `dataset_*` 工具零改动可用。
|
|
6
|
+
* 远端表名只出现在发往远端的 SQL 里,本地表名仍走 `generateTableName` 白名单。
|
|
7
|
+
*/
|
|
8
|
+
import type { ColumnInfo } from '../parse';
|
|
9
|
+
import { type DataServices } from '../store';
|
|
10
|
+
import { type ToolExec } from '../tooling';
|
|
11
|
+
import type { DataSourceRecord } from './types';
|
|
12
|
+
export declare const REMOTE_IMPORT_JOB_KIND = "datasource-import";
|
|
13
|
+
export interface RemoteImportParams {
|
|
14
|
+
scopeKey: string;
|
|
15
|
+
source: DataSourceRecord;
|
|
16
|
+
tableName: string;
|
|
17
|
+
schemaName?: string | null;
|
|
18
|
+
/** 数据集登记名;缺省取远端表名。 */
|
|
19
|
+
name?: string | null;
|
|
20
|
+
/** 只导入前 N 行;配合 `datasourceMaxImportRows` 双重夹紧。 */
|
|
21
|
+
limit?: number | null;
|
|
22
|
+
}
|
|
23
|
+
export interface RemoteImportContext {
|
|
24
|
+
signal: AbortSignal;
|
|
25
|
+
/** 有 agent 才能回注后台任务的完成通知;设置页导入时传 undefined。 */
|
|
26
|
+
exec?: ToolExec;
|
|
27
|
+
background?: boolean;
|
|
28
|
+
}
|
|
29
|
+
export interface RemoteImportResult {
|
|
30
|
+
datasetId: string;
|
|
31
|
+
name: string;
|
|
32
|
+
rowCount: number;
|
|
33
|
+
columnCount: number;
|
|
34
|
+
columns: ColumnInfo[];
|
|
35
|
+
status: 'ready' | 'running';
|
|
36
|
+
jobId?: string;
|
|
37
|
+
}
|
|
38
|
+
export declare function importRemoteTable(services: DataServices, params: RemoteImportParams, context: RemoteImportContext): Promise<RemoteImportResult>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `lh_data_sources` 的 DDL 与行映射。
|
|
3
|
+
*
|
|
4
|
+
* 数据源是**全局**的(catalog 库,跨工作区共享),与 `dataset_scopes` 同库。
|
|
5
|
+
* DDL 与行映射单独放这里,`source-store.ts` 只留 CRUD,避免类膨胀。
|
|
6
|
+
*/
|
|
7
|
+
import type { Row } from '../db';
|
|
8
|
+
import type { DataSourceRecord } from './types';
|
|
9
|
+
export declare const SOURCE_SCHEMA_SQL = "\nCREATE TABLE IF NOT EXISTS lh_data_sources (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n type TEXT NOT NULL,\n host TEXT NOT NULL,\n port INTEGER NOT NULL,\n database_name TEXT NOT NULL,\n username TEXT NOT NULL,\n password_enc TEXT NOT NULL,\n ssl_mode TEXT,\n pool_max INTEGER,\n description TEXT,\n status TEXT NOT NULL DEFAULT 'unknown',\n last_error TEXT,\n last_checked_at INTEGER,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n);\nCREATE UNIQUE INDEX IF NOT EXISTS idx_lh_data_sources_name ON lh_data_sources(name);\n";
|
|
10
|
+
export declare function makeSourceId(): string;
|
|
11
|
+
export declare function rowToSource(row: Row): DataSourceRecord;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据源的持久化:catalog 库 `lh_data_sources` 的 CRUD。
|
|
3
|
+
*
|
|
4
|
+
* 密码在这一层加密落库;改 / 删数据源会顺带关掉对应的连接池,避免缓存里残留
|
|
5
|
+
* 旧凭据。`list()` / `find()` 返回的是含密文的完整记录——**绝不能直接序列化
|
|
6
|
+
* 给前端或模型**,边界处必须过 `toView()` / 工具侧的脱敏。
|
|
7
|
+
*/
|
|
8
|
+
import { type DbConfig } from '../db';
|
|
9
|
+
import type { DataSourceConfig, DataSourceInput, DataSourcePatch, DataSourceRecord } from './types';
|
|
10
|
+
export declare class DataSourceStore {
|
|
11
|
+
private readonly cfg;
|
|
12
|
+
private initialized;
|
|
13
|
+
constructor(cfg: DataSourceConfig & DbConfig);
|
|
14
|
+
private db;
|
|
15
|
+
list(): Promise<DataSourceRecord[]>;
|
|
16
|
+
/** 按 id 或登记名查找;找不到返回 undefined(不抛错)。 */
|
|
17
|
+
find(reference: string): Promise<DataSourceRecord | undefined>;
|
|
18
|
+
require(reference: string): Promise<DataSourceRecord>;
|
|
19
|
+
/** 全局唯一的名字:已存在则追加 `_2` / `_3`。 */
|
|
20
|
+
uniqueName(name: string): Promise<string>;
|
|
21
|
+
create(input: DataSourceInput): Promise<DataSourceRecord>;
|
|
22
|
+
update(id: string, patch: DataSourcePatch): Promise<DataSourceRecord>;
|
|
23
|
+
/** 记录一次连通性检测的结果。 */
|
|
24
|
+
recordCheck(id: string, success: boolean, error: string | null): Promise<void>;
|
|
25
|
+
remove(id: string): Promise<void>;
|
|
26
|
+
private insert;
|
|
27
|
+
}
|
|
28
|
+
export declare function createSourceStore(cfg: DataSourceConfig & DbConfig): DataSourceStore;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 数据源(DataSource)的类型定义。
|
|
3
|
+
*
|
|
4
|
+
* 数据源 = 一条远程关系型数据库的连接配置,全局登记在 catalog 库,跨工作区共享;
|
|
5
|
+
* 导入产出的数据集仍落在**当前工作区**的 scope 库里。
|
|
6
|
+
*/
|
|
7
|
+
import type { ColumnType } from '../parse';
|
|
8
|
+
/** 支持的关系型数据库类型。 */
|
|
9
|
+
export type DataSourceType = 'mysql' | 'postgresql';
|
|
10
|
+
/** 连通状态:从未检测 / 最近一次成功 / 最近一次失败。 */
|
|
11
|
+
export type DataSourceStatus = 'unknown' | 'connected' | 'error';
|
|
12
|
+
/**
|
|
13
|
+
* 与 `DataConfig` 结构同源的最小视图。
|
|
14
|
+
* 只声明本模块真正读取的键,避免 `datasource/*` → `store.ts` 的循环依赖。
|
|
15
|
+
*/
|
|
16
|
+
export interface DataSourceConfig {
|
|
17
|
+
datasourceEnabled: boolean;
|
|
18
|
+
datasourceFetchBatchSize: number;
|
|
19
|
+
datasourceConnectTimeoutMs: number;
|
|
20
|
+
datasourceMaxImportRows: number;
|
|
21
|
+
datasourceEncryptKey: string;
|
|
22
|
+
}
|
|
23
|
+
/** catalog 库 `lh_data_sources` 的一行。`passwordEnc` 恒为密文。 */
|
|
24
|
+
export interface DataSourceRecord {
|
|
25
|
+
id: string;
|
|
26
|
+
name: string;
|
|
27
|
+
type: DataSourceType;
|
|
28
|
+
host: string;
|
|
29
|
+
port: number;
|
|
30
|
+
database: string;
|
|
31
|
+
username: string;
|
|
32
|
+
passwordEnc: string;
|
|
33
|
+
sslMode: string | null;
|
|
34
|
+
poolMax: number | null;
|
|
35
|
+
description: string | null;
|
|
36
|
+
status: DataSourceStatus;
|
|
37
|
+
lastError: string | null;
|
|
38
|
+
lastCheckedAt: number | null;
|
|
39
|
+
createdAt: number;
|
|
40
|
+
updatedAt: number;
|
|
41
|
+
}
|
|
42
|
+
/** 新建一条数据源需要的字段(密码为明文,落库前加密)。 */
|
|
43
|
+
export interface DataSourceInput {
|
|
44
|
+
name: string;
|
|
45
|
+
type: DataSourceType;
|
|
46
|
+
host: string;
|
|
47
|
+
port: number;
|
|
48
|
+
database: string;
|
|
49
|
+
username: string;
|
|
50
|
+
password: string;
|
|
51
|
+
sslMode?: string | null;
|
|
52
|
+
poolMax?: number | null;
|
|
53
|
+
description?: string | null;
|
|
54
|
+
}
|
|
55
|
+
/** 改一条数据源:字段缺省表示不改;`password` 给空串表示清空。 */
|
|
56
|
+
export interface DataSourcePatch {
|
|
57
|
+
name?: string;
|
|
58
|
+
type?: DataSourceType;
|
|
59
|
+
host?: string;
|
|
60
|
+
port?: number;
|
|
61
|
+
database?: string;
|
|
62
|
+
username?: string;
|
|
63
|
+
password?: string | null;
|
|
64
|
+
sslMode?: string | null;
|
|
65
|
+
poolMax?: number | null;
|
|
66
|
+
description?: string | null;
|
|
67
|
+
status?: DataSourceStatus;
|
|
68
|
+
lastError?: string | null;
|
|
69
|
+
lastCheckedAt?: number | null;
|
|
70
|
+
}
|
|
71
|
+
/** 明文连接参数:只在内存里流转,绝不落库、绝不回显给前端或模型。 */
|
|
72
|
+
export interface ConnectionConfig {
|
|
73
|
+
host: string;
|
|
74
|
+
port: number;
|
|
75
|
+
database: string;
|
|
76
|
+
username: string;
|
|
77
|
+
password: string;
|
|
78
|
+
sslMode: string | null;
|
|
79
|
+
poolMax: number | null;
|
|
80
|
+
connectTimeoutMs: number;
|
|
81
|
+
}
|
|
82
|
+
/** 连接器返回的列元数据(方言无关,已把远端类型映射成本项目的列类型)。 */
|
|
83
|
+
export interface RemoteColumn {
|
|
84
|
+
name: string;
|
|
85
|
+
nativeType: ColumnType;
|
|
86
|
+
nullable: boolean;
|
|
87
|
+
comment: string | null;
|
|
88
|
+
}
|
|
89
|
+
export interface RemoteTable {
|
|
90
|
+
tableName: string;
|
|
91
|
+
schemaName: string | null;
|
|
92
|
+
/** 远端的估计行数(MySQL `TABLE_ROWS` / PG `reltuples`),可能为 -1(未知)。 */
|
|
93
|
+
rowCount: number;
|
|
94
|
+
primaryKey: string | null;
|
|
95
|
+
columns: RemoteColumn[];
|
|
96
|
+
}
|
|
97
|
+
export interface SchemaSummary {
|
|
98
|
+
schemaName: string;
|
|
99
|
+
tableCount: number;
|
|
100
|
+
}
|
|
101
|
+
export interface ConnectionTestResult {
|
|
102
|
+
success: boolean;
|
|
103
|
+
latency: number;
|
|
104
|
+
version: string | null;
|
|
105
|
+
error: string | null;
|
|
106
|
+
}
|
|
107
|
+
/** 分块拉取的区间。 */
|
|
108
|
+
export interface FetchRange {
|
|
109
|
+
limit?: number;
|
|
110
|
+
offset?: number;
|
|
111
|
+
}
|
|
112
|
+
/** 导入一张远端表的请求(`datasource_import` 与设置页共用)。 */
|
|
113
|
+
export interface ImportRequest {
|
|
114
|
+
scopeKey: string;
|
|
115
|
+
tableName: string;
|
|
116
|
+
schemaName?: string | null;
|
|
117
|
+
name?: string | null;
|
|
118
|
+
limit?: number | null;
|
|
119
|
+
}
|
package/lib/db.d.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* libSQL 客户端与生命周期。
|
|
3
|
+
*
|
|
4
|
+
* 移植自 `agentic-data-mini` 的 `src/lib/primitives/db.ts`,保留其关键行为:
|
|
5
|
+
* URL 优先级、裸路径补 `file:`、启动 PRAGMA(WAL + 外键)、日志不打印 authToken。
|
|
6
|
+
* 插件侧新增:按 scope 解析库文件(`perWorkspace`)+ `closeAllDatabases()` 供
|
|
7
|
+
* `ctx.effect()` 在 HMR / 卸载时确定性释放(设计文档 §8)。
|
|
8
|
+
*/
|
|
9
|
+
import { type Client } from '@libsql/client';
|
|
10
|
+
/** 无损 JSON 值(与 dsh 的 `snapshotJsonValue` 边界一致)。 */
|
|
11
|
+
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
12
|
+
[key: string]: JsonValue;
|
|
13
|
+
};
|
|
14
|
+
/** 一行查询结果:键为列名,值保证是无损 JSON。 */
|
|
15
|
+
export type Row = {
|
|
16
|
+
[key: string]: JsonValue;
|
|
17
|
+
};
|
|
18
|
+
export interface RunResult {
|
|
19
|
+
changes: number;
|
|
20
|
+
lastInsertRowid: number;
|
|
21
|
+
}
|
|
22
|
+
export interface PreparedStatement {
|
|
23
|
+
all(...params: unknown[]): Promise<Row[]>;
|
|
24
|
+
get(...params: unknown[]): Promise<Row | undefined>;
|
|
25
|
+
run(...params: unknown[]): Promise<RunResult>;
|
|
26
|
+
}
|
|
27
|
+
/** 本模块需要的配置子集(由 `store.ts` 的 DataConfig 提供)。 */
|
|
28
|
+
export interface DbConfig {
|
|
29
|
+
dbPath: string;
|
|
30
|
+
dbUrl: string;
|
|
31
|
+
authToken: string;
|
|
32
|
+
perWorkspace: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** 近似 bun:sqlite 的兼容层:封装 @libsql/client。 */
|
|
35
|
+
export declare class Database {
|
|
36
|
+
private readonly client;
|
|
37
|
+
readonly url: string;
|
|
38
|
+
readonly remote: boolean;
|
|
39
|
+
private initPromise;
|
|
40
|
+
constructor(client: Client, url: string, remote: boolean);
|
|
41
|
+
prepare(sql: string): PreparedStatement;
|
|
42
|
+
/** 执行多条语句(建表 / 建索引)。 */
|
|
43
|
+
exec(sql: string): Promise<void>;
|
|
44
|
+
close(): void;
|
|
45
|
+
private run;
|
|
46
|
+
/** PRAGMA 只做一次;远程库不支持时忽略。 */
|
|
47
|
+
private ensureInit;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* 把 libSQL 的返回值规整成无损 JSON。
|
|
51
|
+
*
|
|
52
|
+
* libSQL 的行对象同时挂着具名列与**不可枚举**的数字索引 `0..n` 和 `length`
|
|
53
|
+
* (行既能按名也能按位置访问)。dsh 的 `snapshotJsonValue` 把「存在不可枚举的
|
|
54
|
+
* 自有属性」判为有损 —— 工具返回值会被直接拒为 `INVALID_TOOL_OUTPUT`
|
|
55
|
+
* (`value is not lossless JSON`)。这里统一重建为只含可枚举字符串键的纯对象;
|
|
56
|
+
* 顺带把 JSON 无法无损表达的值转成 JSON 安全形式:
|
|
57
|
+
* BigInt(超安全整数范围转字符串)、BLOB(base64)、NaN / ±Infinity(null)、
|
|
58
|
+
* `-0`(0)、Date(ISO 字符串)、function / symbol(null)。
|
|
59
|
+
*/
|
|
60
|
+
export declare function toJsonValue(value: unknown, depth?: number): JsonValue;
|
|
61
|
+
/** 一行 → 只含可枚举字符串键的纯对象。 */
|
|
62
|
+
export declare function toJsonRow(row: unknown): Row;
|
|
63
|
+
/** 稳定短哈希:物理表名前缀与 perWorkspace 库文件后缀都用它。 */
|
|
64
|
+
export declare function shortHash(input: string, length?: number): string;
|
|
65
|
+
/** 仅用于兜底消毒的标识符(保留中文):移植自参考实现的 `sanitizeId`。 */
|
|
66
|
+
export declare function sanitizeId(name: string): string;
|
|
67
|
+
/** 默认库目录:`$DSH_HOME/lh-data`。 */
|
|
68
|
+
export declare function defaultDbDirectory(): string;
|
|
69
|
+
/**
|
|
70
|
+
* 不含 scope 后缀的库 URL —— 连接优先级链的终点:
|
|
71
|
+
* `dbUrl` > `dbPath` > `SQLITE_PATH` > `TURSO_DATABASE_URL` > 默认本地文件。
|
|
72
|
+
*/
|
|
73
|
+
export declare function baseDbUrl(cfg: DbConfig): string;
|
|
74
|
+
/**
|
|
75
|
+
* 连接优先级:`dbUrl` > `dbPath` > `SQLITE_PATH` > `TURSO_DATABASE_URL` > 默认本地文件。
|
|
76
|
+
* `perWorkspace` 且是本地库时,为每个 scope 派生独立库文件。
|
|
77
|
+
*/
|
|
78
|
+
export declare function resolveDbUrl(cfg: DbConfig, scopeKey: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* 目录库:**不做 scope 分片**的固定库,供工作区注册表使用。
|
|
81
|
+
*
|
|
82
|
+
* `perWorkspace=false` 时它与业务库是同一个 URL(同一个 `Database` 实例,
|
|
83
|
+
* 注册表与 datasets 表共存);`perWorkspace=true` 时它是没有后缀的那份
|
|
84
|
+
* `data.db`,与各工作区的 `data-<hash>.db` 并列。
|
|
85
|
+
* 远程库(`libsql://`)不做分片,两种情况都是同一个库。
|
|
86
|
+
*/
|
|
87
|
+
export declare function resolveCatalogDatabase(cfg: DbConfig): Database;
|
|
88
|
+
/** 惰性建立连接(不在 apply() 里同步建立),按 url 缓存单例。 */
|
|
89
|
+
export declare function resolveDatabase(cfg: DbConfig, scopeKey: string): Database;
|
|
90
|
+
/** 关闭全部连接:`ctx.effect()` 的 disposer 调用它。 */
|
|
91
|
+
export declare function closeAllDatabases(): void;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 自建 HTTP 路由的公共层(视图路由与管理路由共用)。
|
|
3
|
+
*
|
|
4
|
+
* 抽出原因:`http.ts` 的视图路由已有 160 行,再加管理路由会失控;两路由共享
|
|
5
|
+
* 同样的「鉴权 + JSON 收发 + queryInt 解析」原语,单独成模块避免复制。
|
|
6
|
+
*
|
|
7
|
+
* 仅主机侧使用;`node:http` 的类型在这里统一引入,视图/管理路由都从这里取。
|
|
8
|
+
*/
|
|
9
|
+
import type { IncomingMessage } from 'node:http';
|
|
10
|
+
/** 路由需要的请求面(duck-typed:只用这几个字段)。 */
|
|
11
|
+
export interface RouteRequest {
|
|
12
|
+
method?: string;
|
|
13
|
+
url?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface RouteResponse {
|
|
16
|
+
writeHead(status: number, headers?: Record<string, string>): unknown;
|
|
17
|
+
end(body?: string): unknown;
|
|
18
|
+
}
|
|
19
|
+
export declare const JSON_HEADERS: Record<string, string>;
|
|
20
|
+
export declare function sendJson(response: RouteResponse, status: number, payload: unknown): void;
|
|
21
|
+
export declare function sendError(response: RouteResponse, status: number, code: string, message: string): void;
|
|
22
|
+
export declare function queryInt(raw: string | null): number | undefined;
|
|
23
|
+
/**
|
|
24
|
+
* 鉴权:复用平台同样的连接围栏(Host/Origin + 浏览器登录态)。
|
|
25
|
+
* 通过返回 undefined;否则返回应写入的 HTTP 状态码(401 / 403)。
|
|
26
|
+
*/
|
|
27
|
+
export declare function authorize(connection: {
|
|
28
|
+
requestRejection(request: unknown): 401 | 403 | undefined;
|
|
29
|
+
}, request: unknown): 401 | 403 | undefined;
|
|
30
|
+
/** 读取并 JSON 解析请求体,超 `maxBytes` 或非法 JSON 时抛错(由调用方映射成响应)。 */
|
|
31
|
+
export declare function readJsonBody(request: IncomingMessage & RouteRequest, maxBytes: number): Promise<unknown>;
|
package/lib/http.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 前端分页取数的 HTTP 路由 —— 设计文档 §5.5 / §9。
|
|
3
|
+
*
|
|
4
|
+
* 只暴露两个能力:按 `viewId` 取一页、按 `viewId` 释放视图。
|
|
5
|
+
* 接口**不接受任何 SQL**:语句由 `ViewRegistry` 在主机侧持有,因此没有注入面。
|
|
6
|
+
* 每个请求先过 `connection.requestRejection()`(Host/Origin 围栏 + 浏览器鉴权)。
|
|
7
|
+
*/
|
|
8
|
+
import type { DataServices } from './store';
|
|
9
|
+
/**
|
|
10
|
+
* 注册视图路由。返回 disposer;宿主缺失(`webServer` / `connection` 任一不可用)时返回 undefined。
|
|
11
|
+
* 路由路径重复会抛错(webserver 的契约),由调用方决定如何降级。
|
|
12
|
+
*/
|
|
13
|
+
export declare function registerViewRoutes(services: DataServices): (() => void) | undefined;
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 插件入口:`name` / `inject` / `Config` / `apply`。
|
|
3
|
+
*
|
|
4
|
+
* 装载链路与 `dsh-lh-judge` 完全一致:
|
|
5
|
+
* `pnpm run build` → `pnpm dsh plugin --profile web add D:\fastwork\projects\node\dsh-lh-data`
|
|
6
|
+
*
|
|
7
|
+
* 职责(设计文档 §7.2 / §9):
|
|
8
|
+
* - 注册八个 `dataset_*` 工具(句柄化,物理表名不外泄);
|
|
9
|
+
* - `tools/pre-execute` 给写工具加 `ask` 门禁(无审批通道即拒绝,fail-closed);
|
|
10
|
+
* - `ctx.tools.guard()` 单调兜底:写工具缺少归属句柄一律拒绝;
|
|
11
|
+
* - `ctx.systemPrompt.section()` 注入使用引导(可选依赖);
|
|
12
|
+
* - `ctx.effect()` 在 HMR / 卸载时关闭 libSQL 连接。
|
|
13
|
+
*/
|
|
14
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
15
|
+
import Schema from '@deepseek-ai/schemastery';
|
|
16
|
+
import { type DataConfig } from './store';
|
|
17
|
+
import { type ToolRegistry } from './tooling';
|
|
18
|
+
/** cordis 用于加载/去重的唯一标识。 */
|
|
19
|
+
export declare const name: string;
|
|
20
|
+
/** 等 `ctx.tools` 就绪后才 apply。 */
|
|
21
|
+
export declare const inject: string[];
|
|
22
|
+
/** 插件与 dsh 运行时交互的最小上下文(duck-typed:只声明实际用到的成员)。 */
|
|
23
|
+
export interface PluginContext {
|
|
24
|
+
tools: ToolRegistry;
|
|
25
|
+
on(event: string, handler: (...args: any[]) => any): void;
|
|
26
|
+
effect?(setup: () => (() => void) | void): () => void;
|
|
27
|
+
inject?(deps: string[], callback: (injected: unknown) => void): unknown;
|
|
28
|
+
logger?: {
|
|
29
|
+
info?(message: string): void;
|
|
30
|
+
warn?(message: string): void;
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* 插件配置。类型与 `store.ts` 的 DataConfig 同源(在此只做具名导出),
|
|
35
|
+
* 避免 tools → index 的类型循环。
|
|
36
|
+
*/
|
|
37
|
+
export interface Config extends DataConfig {
|
|
38
|
+
}
|
|
39
|
+
export declare const Config: Schema<Config>;
|
|
40
|
+
export declare function validateConfig(cfg?: Partial<DataConfig>): Config;
|
|
41
|
+
export declare function apply(ctx: Context, config: Config): void;
|
|
42
|
+
export { closeAllDatabases } from './db';
|
|
43
|
+
export { buildColumns, fillSamples, mapRowKeys } from './datasource/columns';
|
|
44
|
+
export { decryptPassword, encryptPassword, isValidEncryptedFormat, resolveEncryptKey } from './datasource/crypto';
|
|
45
|
+
export { closeAllConnectors } from './datasource/connection';
|
|
46
|
+
export { inferColumnType, isCodeOrIdField, isLargeNumber, parseCSV, parseXLSX, sanitizeColumnName, } from './parse';
|
|
47
|
+
export { canonicalDirectory, isInside, normalizeDirectory, resolveInputFile } from './scope';
|
|
48
|
+
export { SqlError, buildStructuredQuery, substituteDatasetAlias, validateReadOnlyQuery } from './sql';
|
|
49
|
+
export { PHYSICAL_TABLE_PATTERN, assertPhysicalTableName, generateTableName } from './store';
|
|
50
|
+
export { PLUGIN_NAME } from './tooling';
|