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.
Files changed (89) hide show
  1. package/README.md +332 -0
  2. package/cordis.patch.yml +7 -0
  3. package/lib/admin-contract.d.ts +274 -0
  4. package/lib/admin-http.d.ts +31 -0
  5. package/lib/admin-validate.d.ts +87 -0
  6. package/lib/admin.d.ts +60 -0
  7. package/lib/client.js +2969 -0
  8. package/lib/client.js.map +1 -0
  9. package/lib/datasource/columns.d.ts +13 -0
  10. package/lib/datasource/connection.d.ts +33 -0
  11. package/lib/datasource/connector/base.d.ts +21 -0
  12. package/lib/datasource/connector/mysql.d.ts +23 -0
  13. package/lib/datasource/connector/postgresql.d.ts +23 -0
  14. package/lib/datasource/crypto.d.ts +13 -0
  15. package/lib/datasource/driver.d.ts +39 -0
  16. package/lib/datasource/errors.d.ts +25 -0
  17. package/lib/datasource/importer.d.ts +38 -0
  18. package/lib/datasource/source-sql.d.ts +11 -0
  19. package/lib/datasource/source-store.d.ts +28 -0
  20. package/lib/datasource/types.d.ts +119 -0
  21. package/lib/db.d.ts +91 -0
  22. package/lib/http-common.d.ts +31 -0
  23. package/lib/http.d.ts +13 -0
  24. package/lib/index.d.ts +50 -0
  25. package/lib/index.js +5735 -0
  26. package/lib/parse.d.ts +41 -0
  27. package/lib/preview.d.ts +75 -0
  28. package/lib/render.d.ts +100 -0
  29. package/lib/scope-registry.d.ts +47 -0
  30. package/lib/scope.d.ts +56 -0
  31. package/lib/sql.d.ts +133 -0
  32. package/lib/store.d.ts +174 -0
  33. package/lib/table.d.ts +38 -0
  34. package/lib/tooling.d.ts +267 -0
  35. package/lib/tools/datasource.d.ts +16 -0
  36. package/lib/tools/import.d.ts +21 -0
  37. package/lib/tools/read.d.ts +77 -0
  38. package/lib/tools/registry.d.ts +12 -0
  39. package/lib/tools/write.d.ts +37 -0
  40. package/lib/view.d.ts +138 -0
  41. package/package.json +61 -0
  42. package/src/admin-contract.ts +351 -0
  43. package/src/admin-http.ts +254 -0
  44. package/src/admin-validate.ts +393 -0
  45. package/src/admin.ts +558 -0
  46. package/src/client/index.ts +403 -0
  47. package/src/client/settings/CreateForm.tsx +186 -0
  48. package/src/client/settings/DataSourceForm.tsx +278 -0
  49. package/src/client/settings/DataSourcesPanel.tsx +301 -0
  50. package/src/client/settings/DatasetEditor.tsx +245 -0
  51. package/src/client/settings/DatasetTable.tsx +110 -0
  52. package/src/client/settings/DatasetsPanel.tsx +207 -0
  53. package/src/client/settings/RowsPanel.tsx +196 -0
  54. package/src/client/settings/Section.tsx +41 -0
  55. package/src/client/settings/SourceTablesPanel.tsx +226 -0
  56. package/src/client/settings/api.ts +154 -0
  57. package/src/client/settings/styles.ts +125 -0
  58. package/src/datasource/columns.ts +56 -0
  59. package/src/datasource/connection.ts +124 -0
  60. package/src/datasource/connector/base.ts +54 -0
  61. package/src/datasource/connector/mysql.ts +187 -0
  62. package/src/datasource/connector/postgresql.ts +212 -0
  63. package/src/datasource/crypto.ts +61 -0
  64. package/src/datasource/driver.ts +108 -0
  65. package/src/datasource/errors.ts +69 -0
  66. package/src/datasource/importer.ts +262 -0
  67. package/src/datasource/index.ts +62 -0
  68. package/src/datasource/source-sql.ts +64 -0
  69. package/src/datasource/source-store.ts +152 -0
  70. package/src/datasource/types.ts +133 -0
  71. package/src/db.ts +277 -0
  72. package/src/http-common.ts +91 -0
  73. package/src/http.ts +130 -0
  74. package/src/index.ts +486 -0
  75. package/src/parse.ts +213 -0
  76. package/src/preview.ts +198 -0
  77. package/src/render.ts +294 -0
  78. package/src/scope-registry.ts +111 -0
  79. package/src/scope.ts +159 -0
  80. package/src/sql.ts +491 -0
  81. package/src/store.ts +412 -0
  82. package/src/table.ts +160 -0
  83. package/src/tooling.ts +551 -0
  84. package/src/tools/datasource.ts +378 -0
  85. package/src/tools/import.ts +282 -0
  86. package/src/tools/read.ts +536 -0
  87. package/src/tools/registry.ts +56 -0
  88. package/src/tools/write.ts +241 -0
  89. package/src/view.ts +371 -0
@@ -0,0 +1,267 @@
1
+ /**
2
+ * 工具定义适配器 —— 设计文档 §2.2 的**方案 B**(零 dsh 运行时依赖)。
3
+ *
4
+ * 与 `dsh-lh-judge` 保持一致:运行时不 import 任何 dsh 框架包,手写
5
+ * `ToolDefinition` 字面量 + 自持参数校验。切换方案 A(`@deepseek-ai/dsh-tools`
6
+ * 的 `defineTool`)时只改本文件:其余模块只依赖这里导出的
7
+ * `ToolSpec` / `ValueSchemaSpec` / `ToolExec` 三个契约。
8
+ *
9
+ * 类型层刻意与 dsh-tools 的 `ParameterSchemaSpec` / `ValueSchemaSpec` 同构:
10
+ * - 参数根对象是隐式开放对象,必填用属性级 `required: true` 标注;
11
+ * - 显式 object 节点必须写 `additionalProperties: true | false`;
12
+ * - 编译产物是 dsh-tools `json-schema.ts` 的受支持子集(否则 `register()` 会抛
13
+ * `UNSUPPORTED_SCHEMA`)。
14
+ */
15
+ /** 插件标识:回注消息与后台任务的 `source.plugin` 字段。 */
16
+ export declare const PLUGIN_NAME = "dsh-lh-data";
17
+ /**
18
+ * 视图分页排查用的临时后台日志(走 stdout),定位完成后删除本函数及其全部调用点。
19
+ */
20
+ export declare function debugLog(scope: string, payload: unknown): void;
21
+ export type JsonScalar = string | number | boolean | null;
22
+ export type JsonValue = JsonScalar | JsonValue[] | {
23
+ [key: string]: JsonValue;
24
+ };
25
+ export type JsonObject = {
26
+ [key: string]: JsonValue;
27
+ };
28
+ /** 模型可见内容块(本插件只产出文本)。 */
29
+ export interface TextContentBlock {
30
+ type: 'text';
31
+ text: string;
32
+ }
33
+ export type ContentBlock = TextContentBlock;
34
+ /** 所有节点共享的注解关键字。 */
35
+ export interface ValueSchemaAnnotations {
36
+ description?: string;
37
+ title?: string;
38
+ }
39
+ export interface StringValueSchemaSpec extends ValueSchemaAnnotations {
40
+ type: 'string';
41
+ enum?: readonly string[];
42
+ }
43
+ export interface NumberValueSchemaSpec extends ValueSchemaAnnotations {
44
+ type: 'number';
45
+ }
46
+ export interface IntegerValueSchemaSpec extends ValueSchemaAnnotations {
47
+ type: 'integer';
48
+ }
49
+ export interface BooleanValueSchemaSpec extends ValueSchemaAnnotations {
50
+ type: 'boolean';
51
+ }
52
+ export interface NullValueSchemaSpec extends ValueSchemaAnnotations {
53
+ type: 'null';
54
+ }
55
+ export interface ArrayValueSchemaSpec extends ValueSchemaAnnotations {
56
+ type: 'array';
57
+ items?: ValueSchemaSpec;
58
+ }
59
+ /** 显式对象节点;开放性是必填字段,避免拿到 JSON Schema 的意外默认值。 */
60
+ export interface ObjectValueSchemaSpec extends ValueSchemaAnnotations {
61
+ type: 'object';
62
+ properties?: {
63
+ [key: string]: ValueSchemaSpec;
64
+ };
65
+ additionalProperties: boolean;
66
+ }
67
+ /** 作者侧「任意无损 JSON」节点;编译后是注解-only schema。 */
68
+ export interface JsonValueSchemaSpec extends ValueSchemaAnnotations {
69
+ type: 'json';
70
+ }
71
+ export interface OneOfValueSchemaSpec extends ValueSchemaAnnotations {
72
+ oneOf: readonly [ValueSchemaSpec, ValueSchemaSpec, ...ValueSchemaSpec[]];
73
+ }
74
+ export type ValueSchemaSpec = StringValueSchemaSpec | NumberValueSchemaSpec | IntegerValueSchemaSpec | BooleanValueSchemaSpec | NullValueSchemaSpec | ArrayValueSchemaSpec | ObjectValueSchemaSpec | JsonValueSchemaSpec | OneOfValueSchemaSpec;
75
+ /** 隐式参数根对象的一个属性;`required: true` 表示必填。 */
76
+ export type ParameterPropertySpec = ValueSchemaSpec & {
77
+ required?: true;
78
+ };
79
+ export type ParameterSchemaSpec = {
80
+ [key: string]: ParameterPropertySpec;
81
+ };
82
+ /** 拍平交叉类型,便于 hover 阅读。 */
83
+ type Simplify<T> = {
84
+ [K in keyof T]: T[K];
85
+ } & {};
86
+ /** 标记为必填的属性名。 */
87
+ type RequiredKeys<S> = {
88
+ [K in keyof S]: S[K] extends {
89
+ required: true;
90
+ } ? K : never;
91
+ }[keyof S];
92
+ /** 显式对象节点的推导(含声明的开放性)。 */
93
+ type InferObject<S extends {
94
+ additionalProperties: boolean;
95
+ }> = S extends {
96
+ properties: infer P;
97
+ } ? S['additionalProperties'] extends true ? {
98
+ [K in keyof P]: InferValue<P[K]>;
99
+ } & JsonObject : {
100
+ [K in keyof P]: InferValue<P[K]>;
101
+ } : S['additionalProperties'] extends true ? JsonObject : Record<string, never>;
102
+ /** 一个节点接受的 TypeScript 值。 */
103
+ export type InferValue<S> = S extends {
104
+ type: 'string';
105
+ } ? S extends {
106
+ enum: readonly (infer E)[];
107
+ } ? E : string : S extends {
108
+ type: 'number' | 'integer';
109
+ } ? S extends {
110
+ enum: readonly (infer E)[];
111
+ } ? E : number : S extends {
112
+ type: 'boolean';
113
+ } ? boolean : S extends {
114
+ type: 'null';
115
+ } ? null : S extends {
116
+ type: 'array';
117
+ } ? S extends {
118
+ items: infer I;
119
+ } ? InferValue<I>[] : JsonValue[] : S extends {
120
+ type: 'object';
121
+ additionalProperties: boolean;
122
+ } ? Simplify<InferObject<S>> : S extends {
123
+ type: 'json';
124
+ } ? JsonValue : S extends {
125
+ oneOf: readonly (infer B)[];
126
+ } ? InferValue<B> : never;
127
+ /** 一个隐式参数 map 推导出的 args 对象类型。 */
128
+ export type InferArgs<S extends ParameterSchemaSpec> = Simplify<{
129
+ [K in RequiredKeys<S>]: InferValue<S[K]>;
130
+ } & {
131
+ [K in Exclude<keyof S, RequiredKeys<S>>]?: InferValue<S[K]>;
132
+ }>;
133
+ export type JsonSchemaScalar = string | number | boolean | null;
134
+ export type JsonSchemaType = 'object' | 'array' | 'string' | 'number' | 'integer' | 'boolean' | 'null';
135
+ export interface JsonSchemaNode {
136
+ type?: JsonSchemaType;
137
+ oneOf?: JsonSchemaNode[];
138
+ properties?: Record<string, JsonSchemaNode>;
139
+ required?: string[];
140
+ additionalProperties?: boolean;
141
+ items?: JsonSchemaNode;
142
+ enum?: JsonSchemaScalar[];
143
+ description?: string;
144
+ title?: string;
145
+ }
146
+ /** 工具定义的作者错误(schema 写错):让插件加载即报错,而不是运行时才发现。 */
147
+ export declare class ToolSchemaError extends Error {
148
+ constructor(message: string);
149
+ }
150
+ /** 工具通用错误;`code` 便于门禁与日志归类。 */
151
+ export declare class ToolError extends Error {
152
+ readonly code: string;
153
+ constructor(message: string, code?: string);
154
+ }
155
+ /** 模型生成的参数不合法(对应 dsh-tools 的 `ToolArgsError` / `INVALID_ARGS`)。 */
156
+ export declare class ToolArgsError extends ToolError {
157
+ readonly violations: string[];
158
+ constructor(violations: string[]);
159
+ }
160
+ /** 判断一个值是否为无损 JSON(用于 `json` 节点)。 */
161
+ export declare function isJsonValue(value: unknown, depth?: number): boolean;
162
+ /** 编译参数 map(隐式开放对象根)。 */
163
+ export declare function compileParameters(spec: ParameterSchemaSpec): JsonSchemaNode;
164
+ /** 编译输出 schema(任意 JSON 根)。 */
165
+ export declare function compileOutputSchema(spec: ValueSchemaSpec): JsonSchemaNode;
166
+ /** 校验一个值是否匹配已编译节点;返回空数组表示通过。 */
167
+ export declare function validateValue(node: JsonSchemaNode, value: unknown, path?: string): string[];
168
+ /** 调用方 agent 的最小视图(duck-typed,不 import dsh 运行时)。 */
169
+ export interface AgentLike {
170
+ /**
171
+ * 真实 dsh:`Agent.session` 是 `Session`,工作目录挂在它的 `header.cwd`
172
+ * (`SessionHeader`);扁平的 `cwd` / `id` 只是 headless 与自测的兼容位。
173
+ */
174
+ session?: {
175
+ header?: {
176
+ cwd?: string;
177
+ id?: string;
178
+ };
179
+ cwd?: string;
180
+ id?: string;
181
+ };
182
+ inject?(message: unknown): void;
183
+ }
184
+ /** `defineTool` 交给 execute 的上下文(`ToolRunContext` 的最小视图)。 */
185
+ export interface ToolExec {
186
+ readonly name: string;
187
+ readonly arguments: unknown;
188
+ readonly agent?: AgentLike;
189
+ readonly signal: AbortSignal;
190
+ deferContext?(message: unknown): void;
191
+ }
192
+ /** UI 渲染意图:本插件只用 generic 卡片。 */
193
+ export interface GenericCallView {
194
+ card: 'generic';
195
+ title: string;
196
+ kind?: 'read' | 'write' | 'search' | 'edit' | 'run';
197
+ content?: string;
198
+ rawInput?: string;
199
+ locations?: {
200
+ path: string;
201
+ line?: number;
202
+ }[];
203
+ }
204
+ export type ToolCallView = GenericCallView;
205
+ /** 注册到 `ctx.tools` 的原始工具定义。 */
206
+ export interface ToolDefinition {
207
+ name: string;
208
+ description: string;
209
+ parameters: Record<string, unknown>;
210
+ output: {
211
+ schema: Record<string, unknown>;
212
+ render(args: unknown, value: unknown): ContentBlock[];
213
+ /** 可选:只给前端的展示元数据(模型不可见)。 */
214
+ presentationMeta?(args: unknown, value: unknown): JsonValue;
215
+ };
216
+ execute(args: unknown, exec: ToolExec): Promise<unknown>;
217
+ presentCall?(args: unknown): ToolCallView | undefined;
218
+ }
219
+ /** `ctx.tools` 服务的最小视图。 */
220
+ export interface ToolRegistry {
221
+ register(definition: ToolDefinition): () => void;
222
+ guard?(guard: (exec: ToolExec) => string | undefined): () => void;
223
+ }
224
+ /** `tools/pre-execute` 的决策(与 dsh-tools 的 `PreToolDecision` 同构)。 */
225
+ export type PreToolDecision = {
226
+ kind: 'allow';
227
+ } | {
228
+ kind: 'deny';
229
+ reason: string;
230
+ } | {
231
+ kind: 'ask';
232
+ reason?: string;
233
+ };
234
+ export declare const ALLOW_DECISION: PreToolDecision;
235
+ export interface ToolOutputSpec<P extends ParameterSchemaSpec, V> {
236
+ /** 规范输出 schema;execute 的返回值会被强制校验。 */
237
+ schema: ValueSchemaSpec;
238
+ /**
239
+ * 把规范值渲染成模型可见内容(纯函数,不做 I/O)。
240
+ * 调用处请显式标注 value 的类型(与 execute 的返回类型一致),
241
+ * 以保证 render 内部拿到精确类型。
242
+ */
243
+ render(args: InferArgs<P>, value: V): ContentBlock[];
244
+ /**
245
+ * 只给 UI 的展示元数据(模型不可见)。平台只对顶层调用计算一次,
246
+ * 因此它必须是 (args, value) 的**纯函数**:任何需要交给前端的东西都要随规范值携带。
247
+ */
248
+ presentationMeta?(args: InferArgs<P>, value: V): JsonValue;
249
+ }
250
+ export interface ToolSpec<P extends ParameterSchemaSpec, V> {
251
+ name: string;
252
+ /** 模型唯一可见的说明。 */
253
+ description: string;
254
+ parameters: P;
255
+ output: ToolOutputSpec<P, V>;
256
+ /** pending 卡片;参数不合法时由适配器返回 undefined(渲染永不抛错)。 */
257
+ presentCall?(args: InferArgs<P>): ToolCallView | undefined;
258
+ execute(args: InferArgs<P>, exec: ToolExec): Promise<V>;
259
+ }
260
+ /**
261
+ * 把作者侧定义编译成注册表可接受的 `ToolDefinition`:
262
+ * - 编译期校验作者 schema(违反受支持子集直接抛错,fail-loud);
263
+ * - `execute` 前校验模型入参,违规抛 `ToolArgsError`(→ `INVALID_ARGS`);
264
+ * - `presentCall` 软校验,任何异常回落到通用卡片。
265
+ */
266
+ export declare function toolDef<const P extends ParameterSchemaSpec, V>(spec: ToolSpec<P, V>): ToolDefinition;
267
+ export {};
@@ -0,0 +1,16 @@
1
+ /**
2
+ * `datasource_*`:数据源的列表 / 连通性测试 / 远端表浏览 / 导入。
3
+ *
4
+ * 与 `dataset_*` 的关系:数据源只是**数据来源**的另一种形态——导入完成后的数据集
5
+ * 与 Excel 导入的完全同权,之后一律用 `dataset_*` 工具操作。
6
+ *
7
+ * 脱敏红线:四个工具的返回值与渲染文本里都不出现密码、连接串与本地物理表名。
8
+ */
9
+ import type { DataServices } from '../store';
10
+ import { type ToolDefinition } from '../tooling';
11
+ export declare function createSourceListTool(services: DataServices): ToolDefinition;
12
+ export declare function createSourceTestTool(services: DataServices): ToolDefinition;
13
+ export declare function createSourceTablesTool(services: DataServices): ToolDefinition;
14
+ export declare function createSourceImportTool(services: DataServices): ToolDefinition;
15
+ /** 供 registry 聚合。 */
16
+ export declare function createDataSourceTools(services: DataServices): ToolDefinition[];
@@ -0,0 +1,21 @@
1
+ /**
2
+ * `dataset_import`:解析工作区 Excel/CSV → 建表 → 批量插入 → 登记元数据。
3
+ *
4
+ * 大文件(≥ `backgroundThresholdRows`,或显式 `background: true`)走后台分支:
5
+ * 立即返回 `{ status: 'running', jobId }`,插入在 `ctx.jobs` 任务里跑完后回注通知
6
+ * (设计文档 §5.2)。任何失败都会删掉半截的物理表并把元数据标记为 `failed`。
7
+ */
8
+ import { type ColumnInfo } from '../parse';
9
+ import { type DataServices } from '../store';
10
+ import { type ToolDefinition } from '../tooling';
11
+ export declare const IMPORT_JOB_KIND = "dataset-import";
12
+ export interface ImportOutput {
13
+ datasetId: string;
14
+ name: string;
15
+ rowCount: number;
16
+ columnCount: number;
17
+ status: string;
18
+ jobId?: string;
19
+ columns: ColumnInfo[];
20
+ }
21
+ export declare function createImportTool(services: DataServices): ToolDefinition;
@@ -0,0 +1,77 @@
1
+ /**
2
+ * 只读工具:`dataset_list` / `dataset_schema` / `dataset_query`。
3
+ *
4
+ * 三个工具都不修改数据,因此走 `allow`(不触发审批);返回值只出现 datasetId 与登记名,
5
+ * 物理表名留在 `store.ts` 内部(设计文档 §7.1)。
6
+ */
7
+ import type { ColumnInfo } from '../parse';
8
+ import type { Row } from '../db';
9
+ import { type DataServices } from '../store';
10
+ import { type ColumnSummary } from '../preview';
11
+ import { type ToolDefinition } from '../tooling';
12
+ export interface DatasetSummary {
13
+ datasetId: string;
14
+ name: string;
15
+ rowCount: number;
16
+ columnCount: number;
17
+ status: string;
18
+ sourcePath: string | null;
19
+ createdAt: number;
20
+ updatedAt: number;
21
+ }
22
+ export interface ListOutput {
23
+ count: number;
24
+ datasets: DatasetSummary[];
25
+ }
26
+ export interface SchemaOutput {
27
+ datasetId: string;
28
+ name: string;
29
+ description: string | null;
30
+ rowCount: number;
31
+ status: string;
32
+ columns: ColumnInfo[];
33
+ }
34
+ /** 结果视图的定位信息(设计文档 §5.1 / §5.4)。 */
35
+ export interface QueryViewInfo {
36
+ viewId: string;
37
+ endpoint: string;
38
+ pageSize: number;
39
+ maxPageSize: number;
40
+ /** 排序是否稳定(false 时前端只展示首页)。 */
41
+ stable: boolean;
42
+ /** 允许前端排序的列名白名单。 */
43
+ sortable: string[];
44
+ }
45
+ export interface QueryOutput {
46
+ datasetId: string;
47
+ name: string;
48
+ columns: {
49
+ name: string;
50
+ type: string;
51
+ }[];
52
+ /** 实际命中的行数(不受上限收敛影响)。 */
53
+ matchedRows: number;
54
+ /** 本次可服务的行数(已按 maxQueryRows / maxViewRows 收敛)。 */
55
+ totalRows: number;
56
+ preview: {
57
+ rows: Row[];
58
+ columns: string[];
59
+ /** 头段行数(`gap` 为真时其后是尾段)。 */
60
+ headCount: number;
61
+ gap: boolean;
62
+ skipped: number;
63
+ cellTruncated: boolean;
64
+ columnTruncated: boolean;
65
+ hiddenColumns: number;
66
+ };
67
+ summary: ColumnSummary[];
68
+ limit: number;
69
+ offset: number;
70
+ /** 预览只是结果的一部分。 */
71
+ truncated: boolean;
72
+ /** 存在前端视图(完整结果由前端分页拉取)。 */
73
+ view?: QueryViewInfo;
74
+ }
75
+ export declare function createListTool(services: DataServices): ToolDefinition;
76
+ export declare function createSchemaTool(services: DataServices): ToolDefinition;
77
+ export declare function createQueryTool(services: DataServices): ToolDefinition;
@@ -0,0 +1,12 @@
1
+ /**
2
+ * 八个工具的聚合导出(设计文档 §5.1)。
3
+ */
4
+ import type { DataServices } from '../store';
5
+ import type { ToolDefinition } from '../tooling';
6
+ /** 数据源工具(`datasourceEnabled=false` 时整体不注册)。 */
7
+ export declare const DATA_SOURCE_TOOLS: ReadonlySet<string>;
8
+ /** 本插件注册的全部工具名。 */
9
+ export declare const DATASET_TOOLS: ReadonlySet<string>;
10
+ /** 破坏性工具:写类,默认走 `ctx.approval` 人工确认(fail-closed)。 */
11
+ export declare const WRITE_TOOLS: ReadonlySet<string>;
12
+ export declare function createToolDefinitions(services: DataServices): ToolDefinition[];
@@ -0,0 +1,37 @@
1
+ /**
2
+ * 写工具:`dataset_insert` / `dataset_update` / `dataset_delete` / `dataset_drop`。
3
+ *
4
+ * 四个工具都是破坏性的,默认由 `src/index.ts` 的 `tools/pre-execute` 监听器返回
5
+ * `{ kind: 'ask' }` 交给 `ctx.approval` 人工确认(无审批通道即拒绝,fail-closed)。
6
+ * 这里再兜一层 `readOnly` 检查,避免门禁被绕过时的静默写入。
7
+ */
8
+ import { type DataServices } from '../store';
9
+ import { type ToolDefinition } from '../tooling';
10
+ export interface InsertOutput {
11
+ datasetId: string;
12
+ name: string;
13
+ inserted: number;
14
+ rowCount: number;
15
+ }
16
+ export interface UpdateOutput {
17
+ datasetId: string;
18
+ rowId: number;
19
+ updated: boolean;
20
+ changedColumns: string[];
21
+ rowCount: number;
22
+ }
23
+ export interface DeleteOutput {
24
+ datasetId: string;
25
+ rowId: number;
26
+ deleted: boolean;
27
+ rowCount: number;
28
+ }
29
+ export interface DropOutput {
30
+ datasetId: string;
31
+ name: string;
32
+ dropped: boolean;
33
+ }
34
+ export declare function createInsertTool(services: DataServices): ToolDefinition;
35
+ export declare function createUpdateTool(services: DataServices): ToolDefinition;
36
+ export declare function createDeleteTool(services: DataServices): ToolDefinition;
37
+ export declare function createDropTool(services: DataServices): ToolDefinition;
package/lib/view.d.ts ADDED
@@ -0,0 +1,138 @@
1
+ /**
2
+ * 查询结果视图注册中心 —— 设计文档 §6。
3
+ *
4
+ * 视图是**主机侧的句柄**:`viewId` 之外的一切(物理表名、count/page 语句)都留在这里,
5
+ * 既不出现在模型上下文里,也不出现在 HTTP 响应里。前端只能拿 `viewId` + 分页参数换页。
6
+ *
7
+ * 生命周期:视图元数据持久化到数据库表(`lh_views`,与 `datasets` 同库同 scope),
8
+ * 进程重启 / 插件重载 / 热更新后仍能继续翻页查看,永不过期、不被容量淘汰。
9
+ * 翻页行数据始终实时查询原始数据表,因此底层数据可能被并发写入改变
10
+ * (前端卡片常驻软警告「数据可能已发生变化」)。
11
+ *
12
+ * 内部仍保留 `Map` 作为热缓存,`get()` / `page()` / `revoke()` 同步操作缓存(翻页 O(1)),
13
+ * 仅 `create` / `revoke` 会写库,启动时 `loadAll()` 从各库预载一次。
14
+ */
15
+ import type { Database } from './db';
16
+ import type { ScopeRegistry } from './scope-registry';
17
+ /** 视图能看到的列(列名保持原始表头,含中文)。 */
18
+ export interface ViewColumn {
19
+ name: string;
20
+ type: string;
21
+ }
22
+ /** 派生分页语句所需的三件套,排序可按前端请求重排。 */
23
+ export interface ViewSqlParts {
24
+ /** 已校验、无 LIMIT/OFFSET 的基础语句。 */
25
+ baseSql: string;
26
+ /** 模型(或结构化参数)给出的排序项,已引号化。 */
27
+ baseOrder?: string;
28
+ /** 兜底排序键(通常 `_row_id`);拿不到时为空,此时不保证翻页稳定。 */
29
+ tie?: string;
30
+ }
31
+ export interface CreateViewInput extends ViewSqlParts {
32
+ scopeKey: string;
33
+ datasetId: string;
34
+ name: string;
35
+ /** 物理表名:只在本模块内部持有,绝不外发。 */
36
+ tableName: string;
37
+ columns: ViewColumn[];
38
+ countSql: string;
39
+ totalRows: number;
40
+ /** 该视图最多可翻到的行数(已与 maxQueryRows 取小)。 */
41
+ rowCap: number;
42
+ /** 允许前端排序的列名(已登记列的白名单)。 */
43
+ sortable: string[];
44
+ stable: boolean;
45
+ }
46
+ /** 注册后的视图(内部形态)。 */
47
+ export interface RegisteredView extends CreateViewInput {
48
+ viewId: string;
49
+ createdAt: number;
50
+ }
51
+ /** 交给前端的描述符(`output.presentationMeta` 的载荷)。 */
52
+ export interface ViewDescriptor {
53
+ kind: 'dataset-view';
54
+ viewId: string;
55
+ endpoint: string;
56
+ datasetId: string;
57
+ name: string;
58
+ columns: ViewColumn[];
59
+ totalRows: number;
60
+ pageSize: number;
61
+ maxPageSize: number;
62
+ stable: boolean;
63
+ sortable: string[];
64
+ }
65
+ export interface ViewOptions {
66
+ /** HTTP 路由前缀,用于拼 `endpoint`。 */
67
+ routePrefix: string;
68
+ defaultPageSize: number;
69
+ maxPageSize: number;
70
+ /** 视图可服务行数的硬上限。 */
71
+ maxViewRows: number;
72
+ }
73
+ /** 持久化所需的外部依赖(以回调注入,避免与 store 形成值循环依赖)。 */
74
+ export interface ViewDeps {
75
+ /** 已登记工作区枚举(`loadAll` 遍历用)。 */
76
+ scopes: ScopeRegistry;
77
+ /** 按 scope 取得对应业务库连接。 */
78
+ database: (scopeKey: string) => Promise<Database>;
79
+ }
80
+ export type SortOrder = 'asc' | 'desc';
81
+ export interface PageRequest {
82
+ page?: number;
83
+ pageSize?: number;
84
+ sort?: string;
85
+ order?: SortOrder;
86
+ }
87
+ /** 一次分页查询的 SQL 与参数(执行仍由调用方持库连接完成)。 */
88
+ export interface PageStatement {
89
+ sql: string;
90
+ params: [number, number];
91
+ page: number;
92
+ pageSize: number;
93
+ totalRows: number;
94
+ totalPages: number;
95
+ stable: boolean;
96
+ }
97
+ export declare class ViewError extends Error {
98
+ readonly code: 'VIEW_NOT_FOUND' | 'BAD_REQUEST';
99
+ readonly status: 400 | 404;
100
+ constructor(code: 'VIEW_NOT_FOUND' | 'BAD_REQUEST', status: 400 | 404, message: string);
101
+ }
102
+ /** 拼排序子句:前端排序 > 模型排序 > 兜底键。 */
103
+ export declare function composeOrderBy(parts: ViewSqlParts, sort?: {
104
+ column: string;
105
+ order: SortOrder;
106
+ }): string;
107
+ export declare class ViewRegistry {
108
+ private readonly views;
109
+ private readonly options;
110
+ private readonly deps;
111
+ constructor(options: ViewOptions, deps: ViewDeps);
112
+ /** 当前存活视图数(测试与日志用)。 */
113
+ get size(): number;
114
+ /** 确保某 scope 的业务库已存在视图表(幂等),返回库连接。 */
115
+ private ensureTable;
116
+ /** 把一行 DB 记录还原成内部视图对象。 */
117
+ private static fromRow;
118
+ /** 注册一个视图:双写内存缓存与数据库表,返回给前端的描述符。 */
119
+ create(input: CreateViewInput): Promise<ViewDescriptor>;
120
+ /** 取一个已注册的视图(同步读内存缓存;启动已 loadAll 预载)。 */
121
+ get(viewId: string): RegisteredView | undefined;
122
+ /** 主动释放(前端卸载卡片 / DELETE)。双删:内存缓存 + 数据库行。 */
123
+ revoke(viewId: string): Promise<boolean>;
124
+ /** 仅清空内存热缓存(不删库表,否则持久化失效)。 */
125
+ clear(): void;
126
+ /**
127
+ * 启动时预载:遍历所有已登记 scope,把各库 `lh_views` 表读进内存。
128
+ * 必须在注册路由前完成,避免早期请求漏命中。
129
+ */
130
+ loadAll(): Promise<void>;
131
+ /**
132
+ * 解析分页参数并产出可直接执行的语句。
133
+ * 排序只接受视图创建时登记的白名单列,越界一律 `BAD_REQUEST`。
134
+ */
135
+ page(viewId: string, request?: PageRequest): PageStatement;
136
+ }
137
+ /** 视图注册中心的构造入口(`DataServices.views`)。 */
138
+ export declare function createViewRegistry(options: ViewOptions, deps: ViewDeps): ViewRegistry;
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "dsh-lh-data",
3
+ "version": "0.1.0",
4
+ "description": "dsh 插件:把工作区 Excel/CSV 导入本地 Turso(libSQL),并以句柄化的 dataset_* 工具做增删改查。",
5
+ "type": "module",
6
+ "main": "lib/index.js",
7
+ "types": "lib/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./lib/index.d.ts",
11
+ "import": "./lib/index.js"
12
+ },
13
+ "./client": {
14
+ "types": "./src/client/index.ts",
15
+ "default": "./lib/client.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "lib/",
20
+ "src/",
21
+ "cordis.patch.yml"
22
+ ],
23
+ "dsh": {
24
+ "bundle": {
25
+ "patch": "./cordis.patch.yml"
26
+ },
27
+ "client": {
28
+ "platform": "web",
29
+ "external": [
30
+ "react"
31
+ ]
32
+ }
33
+ },
34
+ "dependencies": {
35
+ "@deepseek-ai/schemastery": "^3.18.1",
36
+ "@libsql/client": "^0.17.4",
37
+ "mysql2": "^3.24.3",
38
+ "papaparse": "^5.7.0",
39
+ "pg": "^8.23.0",
40
+ "xlsx": "^0.18.5"
41
+ },
42
+ "devDependencies": {
43
+ "@deepseek-ai/cordis": "^4.0.1",
44
+ "@types/node": "^24.0.0",
45
+ "@types/papaparse": "^5.5.2",
46
+ "@types/react": "^18.3.31",
47
+ "tsdown": "^0.4.0",
48
+ "typescript": "^5.5.4"
49
+ },
50
+ "scripts": {
51
+ "prebuild": "node -e \"require('node:fs').rmSync('lib', { recursive: true, force: true })\"",
52
+ "build": "tsdown",
53
+ "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.client.json --noEmit",
54
+ "typecheck:host": "tsc -p tsconfig.json --noEmit",
55
+ "typecheck:client": "tsc -p tsconfig.client.json --noEmit",
56
+ "import": "node examples/run-import.mjs",
57
+ "view": "node examples/run-view.mjs",
58
+ "admin": "node examples/run-admin.mjs",
59
+ "datasource": "node examples/run-datasource.mjs"
60
+ }
61
+ }