fdb2 1.0.26 → 1.0.31

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 (80) hide show
  1. package/bin/fdb2.js +18 -2
  2. package/dist/public/.vite/manifest.json +4 -4
  3. package/dist/public/bootstrap.js +6 -5
  4. package/dist/public/explorer.css +513 -503
  5. package/dist/public/explorer.js +343 -218
  6. package/dist/public/favicon.ico +0 -0
  7. package/dist/public/index.css +100 -41
  8. package/dist/public/index.js +490 -263
  9. package/dist/public/layout.css +68 -68
  10. package/dist/public/layout.js +10 -10
  11. package/dist/public/rolldown-runtime.js +8 -1
  12. package/dist/public/vconsole.min.js +0 -26
  13. package/dist/public/vue.js +5238 -5192
  14. package/dist/server/cli/format.d.ts +6 -0
  15. package/dist/server/cli/format.d.ts.map +1 -0
  16. package/dist/server/cli/format.js +116 -0
  17. package/dist/server/cli/format.js.map +1 -0
  18. package/dist/server/cli/format.ts +104 -0
  19. package/dist/server/cli/main.d.ts +3 -0
  20. package/dist/server/cli/main.d.ts.map +1 -0
  21. package/dist/server/cli/main.js +710 -0
  22. package/dist/server/cli/main.js.map +1 -0
  23. package/dist/server/cli/main.ts +746 -0
  24. package/dist/server/cli/parse.d.ts +18 -0
  25. package/dist/server/cli/parse.d.ts.map +1 -0
  26. package/dist/server/cli/parse.js +150 -0
  27. package/dist/server/cli/parse.js.map +1 -0
  28. package/dist/server/cli/parse.ts +148 -0
  29. package/dist/server/core/column-spec.d.ts +29 -0
  30. package/dist/server/core/column-spec.d.ts.map +1 -0
  31. package/dist/server/core/column-spec.js +148 -0
  32. package/dist/server/core/column-spec.js.map +1 -0
  33. package/dist/server/core/column-spec.ts +147 -0
  34. package/dist/server/core/config.d.ts +34 -0
  35. package/dist/server/core/config.d.ts.map +1 -0
  36. package/dist/server/core/config.js +187 -0
  37. package/dist/server/core/config.js.map +1 -0
  38. package/dist/server/core/config.ts +165 -0
  39. package/dist/server/core/db-api.d.ts +169 -0
  40. package/dist/server/core/db-api.d.ts.map +1 -0
  41. package/dist/server/core/db-api.js +1078 -0
  42. package/dist/server/core/db-api.js.map +1 -0
  43. package/dist/server/core/db-api.ts +1181 -0
  44. package/dist/server/core/dialect.d.ts +44 -0
  45. package/dist/server/core/dialect.d.ts.map +1 -0
  46. package/dist/server/core/dialect.js +260 -0
  47. package/dist/server/core/dialect.js.map +1 -0
  48. package/dist/server/core/dialect.ts +293 -0
  49. package/dist/server/core/errors.d.ts +22 -0
  50. package/dist/server/core/errors.d.ts.map +1 -0
  51. package/dist/server/core/errors.js +61 -0
  52. package/dist/server/core/errors.js.map +1 -0
  53. package/dist/server/core/errors.ts +58 -0
  54. package/dist/server/core/filter-dsl.d.ts +39 -0
  55. package/dist/server/core/filter-dsl.d.ts.map +1 -0
  56. package/dist/server/core/filter-dsl.js +167 -0
  57. package/dist/server/core/filter-dsl.js.map +1 -0
  58. package/dist/server/core/filter-dsl.ts +180 -0
  59. package/dist/server/core/guard.d.ts +54 -0
  60. package/dist/server/core/guard.d.ts.map +1 -0
  61. package/dist/server/core/guard.js +207 -0
  62. package/dist/server/core/guard.js.map +1 -0
  63. package/dist/server/core/guard.ts +205 -0
  64. package/dist/server/core/query-builder.d.ts +72 -0
  65. package/dist/server/core/query-builder.d.ts.map +1 -0
  66. package/dist/server/core/query-builder.js +478 -0
  67. package/dist/server/core/query-builder.js.map +1 -0
  68. package/dist/server/core/query-builder.ts +502 -0
  69. package/dist/server/service/connection.service.d.ts.map +1 -1
  70. package/dist/server/service/connection.service.js +7 -3
  71. package/dist/server/service/connection.service.js.map +1 -1
  72. package/dist/server/service/connection.service.ts +5 -3
  73. package/dist/server/utils/data-dir.d.ts.map +1 -1
  74. package/dist/server/utils/data-dir.js +2 -0
  75. package/dist/server/utils/data-dir.js.map +1 -1
  76. package/dist/server/utils/data-dir.ts +2 -0
  77. package/electron/updater.js +12 -66
  78. package/package.json +22 -22
  79. package/public/favicon.ico +0 -0
  80. package/public/favicon.png +0 -0
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ /**
3
+ * CLI 统一错误码与错误类型
4
+ * 退出码:
5
+ * 0 成功
6
+ * 1 通用错误(GENERIC)
7
+ * 2 参数/用法错误(PARAM_ERROR、UNKNOWN_COMMAND、INVALID_FILTER)
8
+ * 3 连接不存在(CONN_NOT_FOUND、NO_DEFAULT_CONN)
9
+ * 4 未就绪(NOT_READY)
10
+ * 5 需确认/预演(REQUIRE_DRYRUN、CONFIRM_REQUIRED、CONFIRM_EXPIRED、FORCE_REQUIRED、WRITE_BLOCKED、MULTI_STATEMENT_BLOCKED)
11
+ * 6 SQL/数据库错误(SQL_ERROR、DB_NOT_FOUND、TABLE_NOT_FOUND、COLUMN_NOT_FOUND、UNSUPPORTED、DRIVER_UNAVAILABLE)
12
+ */
13
+ Object.defineProperty(exports, "__esModule", { value: true });
14
+ exports.AppError = void 0;
15
+ exports.exitCodeOf = exitCodeOf;
16
+ class AppError extends Error {
17
+ code;
18
+ hint;
19
+ details;
20
+ constructor(code, message, opts) {
21
+ super(message);
22
+ this.code = code;
23
+ this.hint = opts?.hint;
24
+ this.details = opts?.details;
25
+ }
26
+ }
27
+ exports.AppError = AppError;
28
+ function exitCodeOf(code) {
29
+ switch (code) {
30
+ case 'PARAM_ERROR':
31
+ case 'UNKNOWN_COMMAND':
32
+ case 'INVALID_FILTER':
33
+ case 'INVALID_COLUMN_SPEC':
34
+ case 'INVALID_OPTION':
35
+ return 2;
36
+ case 'CONN_NOT_FOUND':
37
+ case 'NO_DEFAULT_CONN':
38
+ return 3;
39
+ case 'NOT_READY':
40
+ return 4;
41
+ case 'REQUIRE_DRYRUN':
42
+ case 'CONFIRM_REQUIRED':
43
+ case 'CONFIRM_EXPIRED':
44
+ case 'FORCE_REQUIRED':
45
+ case 'WRITE_BLOCKED':
46
+ case 'MULTI_STATEMENT_BLOCKED':
47
+ case 'WRITE_NOT_ALLOWED':
48
+ return 5;
49
+ case 'SQL_ERROR':
50
+ case 'DB_NOT_FOUND':
51
+ case 'TABLE_NOT_FOUND':
52
+ case 'COLUMN_NOT_FOUND':
53
+ case 'UNSUPPORTED':
54
+ case 'DRIVER_UNAVAILABLE':
55
+ case 'EXEC_ERROR':
56
+ return 6;
57
+ default:
58
+ return 1;
59
+ }
60
+ }
61
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../server/core/errors.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAeH,gCAgCC;AA7CD,MAAa,QAAS,SAAQ,KAAK;IACjC,IAAI,CAAS;IACb,IAAI,CAAU;IACd,OAAO,CAAO;IAEd,YAAY,IAAY,EAAE,OAAe,EAAE,IAAuC;QAChF,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,IAAI,GAAG,IAAI,EAAE,IAAI,CAAC;QACvB,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,OAAO,CAAC;IAC/B,CAAC;CACF;AAXD,4BAWC;AAED,SAAgB,UAAU,CAAC,IAAY;IACrC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,aAAa,CAAC;QACnB,KAAK,iBAAiB,CAAC;QACvB,KAAK,gBAAgB,CAAC;QACtB,KAAK,qBAAqB,CAAC;QAC3B,KAAK,gBAAgB;YACnB,OAAO,CAAC,CAAC;QACX,KAAK,gBAAgB,CAAC;QACtB,KAAK,iBAAiB;YACpB,OAAO,CAAC,CAAC;QACX,KAAK,WAAW;YACd,OAAO,CAAC,CAAC;QACX,KAAK,gBAAgB,CAAC;QACtB,KAAK,kBAAkB,CAAC;QACxB,KAAK,iBAAiB,CAAC;QACvB,KAAK,gBAAgB,CAAC;QACtB,KAAK,eAAe,CAAC;QACrB,KAAK,yBAAyB,CAAC;QAC/B,KAAK,mBAAmB;YACtB,OAAO,CAAC,CAAC;QACX,KAAK,WAAW,CAAC;QACjB,KAAK,cAAc,CAAC;QACpB,KAAK,iBAAiB,CAAC;QACvB,KAAK,kBAAkB,CAAC;QACxB,KAAK,aAAa,CAAC;QACnB,KAAK,oBAAoB,CAAC;QAC1B,KAAK,YAAY;YACf,OAAO,CAAC,CAAC;QACX;YACE,OAAO,CAAC,CAAC;IACb,CAAC;AACH,CAAC"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * CLI 统一错误码与错误类型
3
+ * 退出码:
4
+ * 0 成功
5
+ * 1 通用错误(GENERIC)
6
+ * 2 参数/用法错误(PARAM_ERROR、UNKNOWN_COMMAND、INVALID_FILTER)
7
+ * 3 连接不存在(CONN_NOT_FOUND、NO_DEFAULT_CONN)
8
+ * 4 未就绪(NOT_READY)
9
+ * 5 需确认/预演(REQUIRE_DRYRUN、CONFIRM_REQUIRED、CONFIRM_EXPIRED、FORCE_REQUIRED、WRITE_BLOCKED、MULTI_STATEMENT_BLOCKED)
10
+ * 6 SQL/数据库错误(SQL_ERROR、DB_NOT_FOUND、TABLE_NOT_FOUND、COLUMN_NOT_FOUND、UNSUPPORTED、DRIVER_UNAVAILABLE)
11
+ */
12
+
13
+ export class AppError extends Error {
14
+ code: string;
15
+ hint?: string;
16
+ details?: any;
17
+
18
+ constructor(code: string, message: string, opts?: { hint?: string; details?: any }) {
19
+ super(message);
20
+ this.code = code;
21
+ this.hint = opts?.hint;
22
+ this.details = opts?.details;
23
+ }
24
+ }
25
+
26
+ export function exitCodeOf(code: string): number {
27
+ switch (code) {
28
+ case 'PARAM_ERROR':
29
+ case 'UNKNOWN_COMMAND':
30
+ case 'INVALID_FILTER':
31
+ case 'INVALID_COLUMN_SPEC':
32
+ case 'INVALID_OPTION':
33
+ return 2;
34
+ case 'CONN_NOT_FOUND':
35
+ case 'NO_DEFAULT_CONN':
36
+ return 3;
37
+ case 'NOT_READY':
38
+ return 4;
39
+ case 'REQUIRE_DRYRUN':
40
+ case 'CONFIRM_REQUIRED':
41
+ case 'CONFIRM_EXPIRED':
42
+ case 'FORCE_REQUIRED':
43
+ case 'WRITE_BLOCKED':
44
+ case 'MULTI_STATEMENT_BLOCKED':
45
+ case 'WRITE_NOT_ALLOWED':
46
+ return 5;
47
+ case 'SQL_ERROR':
48
+ case 'DB_NOT_FOUND':
49
+ case 'TABLE_NOT_FOUND':
50
+ case 'COLUMN_NOT_FOUND':
51
+ case 'UNSUPPORTED':
52
+ case 'DRIVER_UNAVAILABLE':
53
+ case 'EXEC_ERROR':
54
+ return 6;
55
+ default:
56
+ return 1;
57
+ }
58
+ }
@@ -0,0 +1,39 @@
1
+ /**
2
+ * 过滤条件 DSL:把自然语言里的结构化筛选条件解析成条件树,
3
+ * 由 query-builder 编译为带白名单校验与参数绑定的 SQL。
4
+ *
5
+ * 行内语法 --filter "<field><op><value>"
6
+ * = != <> > >= < <=
7
+ * ~ 包含子串(模糊) ^ 前缀 $ 后缀
8
+ * ~c 区分大小写包含
9
+ * in/nin 集合 between 区间 null/notnull 空值
10
+ * 值中逗号用 \, 转义
11
+ *
12
+ * 复杂逻辑 --filter-json '{"or":[...],"and":[...]}'
13
+ */
14
+ export interface FilterLeaf {
15
+ field: string;
16
+ op: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'likeCase' | 'starts' | 'ends' | 'in' | 'nin' | 'between' | 'isNull' | 'notNull';
17
+ value?: any;
18
+ }
19
+ export type FilterNode = {
20
+ type: 'and';
21
+ children: FilterNode[];
22
+ } | {
23
+ type: 'or';
24
+ children: FilterNode[];
25
+ } | {
26
+ type: 'not';
27
+ child: FilterNode;
28
+ } | {
29
+ type: 'leaf';
30
+ leaf: FilterLeaf;
31
+ };
32
+ export declare function alwaysTrue(): FilterNode;
33
+ /** 单个条件文本解析 */
34
+ export declare function parseFilterExpr(expr: string): FilterLeaf;
35
+ /** 解析 --filter 重复参数(多个 AND) */
36
+ export declare function parseFilters(exprs: string[]): FilterNode;
37
+ /** 解析 --filter-json 复杂条件 */
38
+ export declare function parseFilterJson(jsonStr: string): FilterNode;
39
+ //# sourceMappingURL=filter-dsl.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-dsl.d.ts","sourceRoot":"","sources":["../../../server/core/filter-dsl.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,EAAE,EACE,IAAI,GAAG,KAAK,GACZ,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAC3B,MAAM,GAAG,UAAU,GAAG,QAAQ,GAAG,MAAM,GACvC,IAAI,GAAG,KAAK,GAAG,SAAS,GACxB,QAAQ,GAAG,SAAS,CAAC;IACzB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,UAAU,EAAE,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,UAAU,CAAA;CAAE,CAAC;AAEvC,wBAAgB,UAAU,IAAI,UAAU,CAEvC;AAED,eAAe;AACf,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAqDxD;AA4BD,+BAA+B;AAC/B,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,UAAU,CAKxD;AAED,4BAA4B;AAC5B,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,CAQ3D"}
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ /**
3
+ * 过滤条件 DSL:把自然语言里的结构化筛选条件解析成条件树,
4
+ * 由 query-builder 编译为带白名单校验与参数绑定的 SQL。
5
+ *
6
+ * 行内语法 --filter "<field><op><value>"
7
+ * = != <> > >= < <=
8
+ * ~ 包含子串(模糊) ^ 前缀 $ 后缀
9
+ * ~c 区分大小写包含
10
+ * in/nin 集合 between 区间 null/notnull 空值
11
+ * 值中逗号用 \, 转义
12
+ *
13
+ * 复杂逻辑 --filter-json '{"or":[...],"and":[...]}'
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.alwaysTrue = alwaysTrue;
17
+ exports.parseFilterExpr = parseFilterExpr;
18
+ exports.parseFilters = parseFilters;
19
+ exports.parseFilterJson = parseFilterJson;
20
+ function alwaysTrue() {
21
+ return { type: 'leaf', leaf: { field: '', op: 'eq', value: 1 } };
22
+ }
23
+ /** 单个条件文本解析 */
24
+ function parseFilterExpr(expr) {
25
+ if (expr == null || typeof expr !== 'string') {
26
+ throw new Error('条件为空');
27
+ }
28
+ const text = expr.trim();
29
+ if (!text) {
30
+ throw new Error('条件为空');
31
+ }
32
+ const nullMatch = /^([^\s=<>~^$!]+)\s*(null|notnull|isnull|notnull)$/i.exec(text);
33
+ if (nullMatch) {
34
+ const op = nullMatch[2].toLowerCase();
35
+ return { field: nullMatch[1], op: op === 'isnull' || op === 'null' ? 'isNull' : 'notNull' };
36
+ }
37
+ // 操作符顺序:多字符在前
38
+ const ops = [
39
+ ['!=', 'neq'],
40
+ ['<>', 'neq'],
41
+ ['>=', 'gte'],
42
+ ['<=', 'lte'],
43
+ ['~c', 'likeCase'],
44
+ ['~', 'like'],
45
+ ['like', 'like'],
46
+ ['starts', 'starts'],
47
+ ['ends', 'ends'],
48
+ ['in', 'in'],
49
+ ['nin', 'nin'],
50
+ ['between', 'between'],
51
+ ['>', 'gt'],
52
+ ['<', 'lt'],
53
+ ['=', 'eq'],
54
+ ['^', 'starts'],
55
+ ['$', 'ends']
56
+ ];
57
+ for (const [sym, op] of ops) {
58
+ const idx = text.indexOf(sym);
59
+ if (idx > 0) {
60
+ const field = text.slice(0, idx).trim();
61
+ let rawValue = text.slice(idx + sym.length).trim();
62
+ if (!field || rawValue === '') {
63
+ continue;
64
+ }
65
+ if (op === 'in' || op === 'nin' || op === 'between') {
66
+ const parts = splitEscaped(rawValue);
67
+ return { field, op: op, value: parts };
68
+ }
69
+ return { field, op: op, value: unescapeValue(rawValue) };
70
+ }
71
+ }
72
+ throw new Error(`无法解析条件: ${expr}(支持 = != > < >= <= ~ ^ $ in nin between null)`);
73
+ }
74
+ function splitEscaped(value) {
75
+ const parts = [];
76
+ let current = '';
77
+ let escaped = false;
78
+ for (const ch of value) {
79
+ if (escaped) {
80
+ current += ch;
81
+ escaped = false;
82
+ }
83
+ else if (ch === '\\') {
84
+ escaped = true;
85
+ }
86
+ else if (ch === ',') {
87
+ parts.push(current);
88
+ current = '';
89
+ }
90
+ else {
91
+ current += ch;
92
+ }
93
+ }
94
+ if (escaped)
95
+ current += '\\';
96
+ parts.push(current);
97
+ return parts;
98
+ }
99
+ function unescapeValue(value) {
100
+ return value.replace(/\\,/g, ',').trim();
101
+ }
102
+ /** 解析 --filter 重复参数(多个 AND) */
103
+ function parseFilters(exprs) {
104
+ const leaves = (exprs || []).filter(Boolean).map((e) => parseFilterExpr(e));
105
+ if (leaves.length === 0)
106
+ return alwaysTrue();
107
+ if (leaves.length === 1)
108
+ return { type: 'leaf', leaf: leaves[0] };
109
+ return { type: 'and', children: leaves.map((l) => ({ type: 'leaf', leaf: l })) };
110
+ }
111
+ /** 解析 --filter-json 复杂条件 */
112
+ function parseFilterJson(jsonStr) {
113
+ let raw;
114
+ try {
115
+ raw = JSON.parse(jsonStr);
116
+ }
117
+ catch (e) {
118
+ throw new Error('--filter-json 不是合法 JSON');
119
+ }
120
+ return parseJsonNode(raw);
121
+ }
122
+ function parseJsonNode(node) {
123
+ if (!node || typeof node !== 'object') {
124
+ throw new Error('filter-json 节点必须是对象');
125
+ }
126
+ if (node.and) {
127
+ return { type: 'and', children: (Array.isArray(node.and) ? node.and : [node.and]).map(parseJsonNode) };
128
+ }
129
+ if (node.or) {
130
+ return { type: 'or', children: (Array.isArray(node.or) ? node.or : [node.or]).map(parseJsonNode) };
131
+ }
132
+ if (node.not) {
133
+ return { type: 'not', child: parseJsonNode(node.not) };
134
+ }
135
+ const field = node.field ?? node.f;
136
+ if (!field)
137
+ throw new Error('filter-json 条件缺少 field');
138
+ const opRaw = (node.op ?? '=');
139
+ const value = node.value !== undefined ? node.value : node.v;
140
+ const leaf = {
141
+ field: String(field),
142
+ op: normalizeOp(opRaw),
143
+ value
144
+ };
145
+ return { type: 'leaf', leaf };
146
+ }
147
+ function normalizeOp(op) {
148
+ const map = {
149
+ '=': 'eq', '==': 'eq', eq: 'eq',
150
+ '!=': 'neq', '<>': 'neq', neq: 'neq',
151
+ '>': 'gt', gt: 'gt', '>=': 'gte', gte: 'gte',
152
+ '<': 'lt', lt: 'lt', '<=': 'lte', lte: 'lte',
153
+ '~': 'like', like: 'like', 'contains': 'like',
154
+ '~c': 'likeCase', likecase: 'likeCase',
155
+ '^': 'starts', starts: 'starts', 'starts_with': 'starts',
156
+ '$': 'ends', ends: 'ends', 'ends_with': 'ends',
157
+ in: 'in', 'not_in': 'nin', nin: 'nin',
158
+ between: 'between',
159
+ 'is_null': 'isNull', isnull: 'isNull', null: 'isNull', 'is null': 'isNull',
160
+ 'not_null': 'notNull', notnull: 'notNull', 'not null': 'notNull'
161
+ };
162
+ const key = String(op).toLowerCase();
163
+ if (map[key])
164
+ return map[key];
165
+ throw new Error(`不支持的操作符: ${op}`);
166
+ }
167
+ //# sourceMappingURL=filter-dsl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filter-dsl.js","sourceRoot":"","sources":["../../../server/core/filter-dsl.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * 过滤条件 DSL:把自然语言里的结构化筛选条件解析成条件树,
3
+ * 由 query-builder 编译为带白名单校验与参数绑定的 SQL。
4
+ *
5
+ * 行内语法 --filter "<field><op><value>"
6
+ * = != <> > >= < <=
7
+ * ~ 包含子串(模糊) ^ 前缀 $ 后缀
8
+ * ~c 区分大小写包含
9
+ * in/nin 集合 between 区间 null/notnull 空值
10
+ * 值中逗号用 \, 转义
11
+ *
12
+ * 复杂逻辑 --filter-json '{"or":[...],"and":[...]}'
13
+ */
14
+
15
+ export interface FilterLeaf {
16
+ field: string;
17
+ op:
18
+ | 'eq' | 'neq'
19
+ | 'gt' | 'gte' | 'lt' | 'lte'
20
+ | 'like' | 'likeCase' | 'starts' | 'ends'
21
+ | 'in' | 'nin' | 'between'
22
+ | 'isNull' | 'notNull';
23
+ value?: any;
24
+ }
25
+
26
+ export type FilterNode =
27
+ | { type: 'and'; children: FilterNode[] }
28
+ | { type: 'or'; children: FilterNode[] }
29
+ | { type: 'not'; child: FilterNode }
30
+ | { type: 'leaf'; leaf: FilterLeaf };
31
+
32
+ export function alwaysTrue(): FilterNode {
33
+ return { type: 'leaf', leaf: { field: '', op: 'eq', value: 1 } };
34
+ }
35
+
36
+ /** 单个条件文本解析 */
37
+ export function parseFilterExpr(expr: string): FilterLeaf {
38
+ if (expr == null || typeof expr !== 'string') {
39
+ throw new Error('条件为空');
40
+ }
41
+ const text = expr.trim();
42
+ if (!text) {
43
+ throw new Error('条件为空');
44
+ }
45
+
46
+ const nullMatch = /^([^\s=<>~^$!]+)\s*(null|notnull|isnull|notnull)$/i.exec(text);
47
+ if (nullMatch) {
48
+ const op = nullMatch[2].toLowerCase();
49
+ return { field: nullMatch[1], op: op === 'isnull' || op === 'null' ? 'isNull' : 'notNull' };
50
+ }
51
+
52
+ // 操作符顺序:多字符在前
53
+ const ops = [
54
+ ['!=', 'neq'],
55
+ ['<>', 'neq'],
56
+ ['>=', 'gte'],
57
+ ['<=', 'lte'],
58
+ ['~c', 'likeCase'],
59
+ ['~', 'like'],
60
+ ['like', 'like'],
61
+ ['starts', 'starts'],
62
+ ['ends', 'ends'],
63
+ ['in', 'in'],
64
+ ['nin', 'nin'],
65
+ ['between', 'between'],
66
+ ['>', 'gt'],
67
+ ['<', 'lt'],
68
+ ['=', 'eq'],
69
+ ['^', 'starts'],
70
+ ['$', 'ends']
71
+ ];
72
+
73
+ for (const [sym, op] of ops) {
74
+ const idx = text.indexOf(sym);
75
+ if (idx > 0) {
76
+ const field = text.slice(0, idx).trim();
77
+ let rawValue = text.slice(idx + sym.length).trim();
78
+ if (!field || rawValue === '') {
79
+ continue;
80
+ }
81
+ if (op === 'in' || op === 'nin' || op === 'between') {
82
+ const parts = splitEscaped(rawValue);
83
+ return { field, op: op as any, value: parts };
84
+ }
85
+ return { field, op: op as any, value: unescapeValue(rawValue) };
86
+ }
87
+ }
88
+
89
+ throw new Error(`无法解析条件: ${expr}(支持 = != > < >= <= ~ ^ $ in nin between null)`);
90
+ }
91
+
92
+ function splitEscaped(value: string): string[] {
93
+ const parts: string[] = [];
94
+ let current = '';
95
+ let escaped = false;
96
+ for (const ch of value) {
97
+ if (escaped) {
98
+ current += ch;
99
+ escaped = false;
100
+ } else if (ch === '\\') {
101
+ escaped = true;
102
+ } else if (ch === ',') {
103
+ parts.push(current);
104
+ current = '';
105
+ } else {
106
+ current += ch;
107
+ }
108
+ }
109
+ if (escaped) current += '\\';
110
+ parts.push(current);
111
+ return parts;
112
+ }
113
+
114
+ function unescapeValue(value: string): string {
115
+ return value.replace(/\\,/g, ',').trim();
116
+ }
117
+
118
+ /** 解析 --filter 重复参数(多个 AND) */
119
+ export function parseFilters(exprs: string[]): FilterNode {
120
+ const leaves = (exprs || []).filter(Boolean).map((e) => parseFilterExpr(e));
121
+ if (leaves.length === 0) return alwaysTrue();
122
+ if (leaves.length === 1) return { type: 'leaf', leaf: leaves[0] };
123
+ return { type: 'and', children: leaves.map((l) => ({ type: 'leaf' as const, leaf: l })) };
124
+ }
125
+
126
+ /** 解析 --filter-json 复杂条件 */
127
+ export function parseFilterJson(jsonStr: string): FilterNode {
128
+ let raw: any;
129
+ try {
130
+ raw = JSON.parse(jsonStr);
131
+ } catch (e) {
132
+ throw new Error('--filter-json 不是合法 JSON');
133
+ }
134
+ return parseJsonNode(raw);
135
+ }
136
+
137
+ function parseJsonNode(node: any): FilterNode {
138
+ if (!node || typeof node !== 'object') {
139
+ throw new Error('filter-json 节点必须是对象');
140
+ }
141
+ if (node.and) {
142
+ return { type: 'and', children: (Array.isArray(node.and) ? node.and : [node.and]).map(parseJsonNode) };
143
+ }
144
+ if (node.or) {
145
+ return { type: 'or', children: (Array.isArray(node.or) ? node.or : [node.or]).map(parseJsonNode) };
146
+ }
147
+ if (node.not) {
148
+ return { type: 'not', child: parseJsonNode(node.not) };
149
+ }
150
+ const field = node.field ?? node.f;
151
+ if (!field) throw new Error('filter-json 条件缺少 field');
152
+ const opRaw = (node.op ?? '=') as string;
153
+ const value = node.value !== undefined ? node.value : node.v;
154
+ const leaf: FilterLeaf = {
155
+ field: String(field),
156
+ op: normalizeOp(opRaw),
157
+ value
158
+ };
159
+ return { type: 'leaf', leaf };
160
+ }
161
+
162
+ function normalizeOp(op: string): FilterLeaf['op'] {
163
+ const map: Record<string, FilterLeaf['op']> = {
164
+ '=': 'eq', '==': 'eq', eq: 'eq',
165
+ '!=': 'neq', '<>': 'neq', neq: 'neq',
166
+ '>': 'gt', gt: 'gt', '>=': 'gte', gte: 'gte',
167
+ '<': 'lt', lt: 'lt', '<=': 'lte', lte: 'lte',
168
+ '~': 'like', like: 'like', 'contains': 'like',
169
+ '~c': 'likeCase', likecase: 'likeCase',
170
+ '^': 'starts', starts: 'starts', 'starts_with': 'starts',
171
+ '$': 'ends', ends: 'ends', 'ends_with': 'ends',
172
+ in: 'in', 'not_in': 'nin', nin: 'nin',
173
+ between: 'between',
174
+ 'is_null': 'isNull', isnull: 'isNull', null: 'isNull', 'is null': 'isNull',
175
+ 'not_null': 'notNull', notnull: 'notNull', 'not null': 'notNull'
176
+ };
177
+ const key = String(op).toLowerCase();
178
+ if (map[key]) return map[key];
179
+ throw new Error(`不支持的操作符: ${op}`);
180
+ }
@@ -0,0 +1,54 @@
1
+ export interface WriteOpts {
2
+ dryRun?: boolean;
3
+ confirm?: string | null;
4
+ yes?: boolean;
5
+ force?: boolean;
6
+ write?: boolean;
7
+ }
8
+ export declare function computeToken(op: string, sql: string, params: any[]): string;
9
+ export declare function verifyToken(token: string, op: string, sql: string, params: any[]): boolean;
10
+ /** 令牌是否已使用(一次性,防重放) */
11
+ export declare function isTokenUsed(token: string): boolean;
12
+ /** 标记令牌已使用,保留到时间窗结束以便过期清理 */
13
+ export declare function markTokenUsed(token: string): void;
14
+ /** 检查全局只读模式 */
15
+ export declare function checkReadonly(write: boolean | undefined): void;
16
+ /** 影响行数阈值 */
17
+ export declare function confirmThreshold(): number;
18
+ /** 检查行数是否超阈值(超阈值需 --force) */
19
+ export declare function checkThreshold(rows: number, force: boolean | undefined): void;
20
+ /**
21
+ * 写操作统一入口:
22
+ * - dryRun=true:估算行数,返回 token(不执行)
23
+ * - 有 confirm:校验 token 并放行
24
+ * - 破坏性操作(destructive=true)还需 --yes
25
+ */
26
+ export declare function gateWrite(opts: {
27
+ op: string;
28
+ sql: string;
29
+ params: any[];
30
+ estimatedRows?: number | null;
31
+ destructive?: boolean;
32
+ write?: boolean;
33
+ dryRun?: boolean;
34
+ confirm?: string | null;
35
+ yes?: boolean;
36
+ force?: boolean;
37
+ }): {
38
+ mode: 'execute' | 'dryrun';
39
+ token?: string;
40
+ };
41
+ /** 审计一个操作 */
42
+ export declare function audit(opts: {
43
+ action: string;
44
+ conn?: string | null;
45
+ database?: string | null;
46
+ table?: string | null;
47
+ kind?: string | null;
48
+ sql?: string | null;
49
+ params?: any;
50
+ rows?: number | null;
51
+ ok: boolean;
52
+ error?: string | null;
53
+ }): void;
54
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../../server/core/guard.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,SAAS;IACxB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,wBAAgB,YAAY,CAAC,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,CAK3E;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAY1F;AAsCD,uBAAuB;AACvB,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAGlD;AAED,6BAA6B;AAC7B,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAIjD;AAED,eAAe;AACf,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAO9D;AAED,aAAa;AACb,wBAAgB,gBAAgB,IAAI,MAAM,CAEzC;AAED,8BAA8B;AAC9B,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAM7E;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,IAAI,EAAE;IACJ,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,GAAG,EAAE,CAAC;IACd,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB,GACA;IAAE,IAAI,EAAE,SAAS,GAAG,QAAQ,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAiDhD;AAED,aAAa;AACb,wBAAgB,KAAK,CAAC,IAAI,EAAE;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,CAAC,EAAE,GAAG,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,EAAE,EAAE,OAAO,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB,GAAG,IAAI,CAIP"}