@kweaver-ai/kweaver-sdk 0.5.1 → 0.6.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 +25 -2
- package/README.zh.md +24 -1
- package/dist/api/agent-chat.d.ts +8 -2
- package/dist/api/agent-chat.js +150 -44
- package/dist/api/agent-list.d.ts +35 -0
- package/dist/api/agent-list.js +95 -21
- package/dist/api/bkn-backend.d.ts +60 -0
- package/dist/api/bkn-backend.js +103 -10
- package/dist/api/business-domains.js +9 -5
- package/dist/api/context-loader.js +4 -1
- package/dist/api/conversations.d.ts +6 -3
- package/dist/api/conversations.js +29 -35
- package/dist/api/dataflow.js +1 -10
- package/dist/api/dataflow2.d.ts +95 -0
- package/dist/api/dataflow2.js +80 -0
- package/dist/api/datasources.js +1 -10
- package/dist/api/dataviews.js +1 -10
- package/dist/api/headers.d.ts +11 -0
- package/dist/api/headers.js +30 -0
- package/dist/api/knowledge-networks.d.ts +41 -0
- package/dist/api/knowledge-networks.js +69 -22
- package/dist/api/ontology-query.d.ts +14 -1
- package/dist/api/ontology-query.js +63 -49
- package/dist/api/semantic-search.js +2 -12
- package/dist/api/skills.d.ts +141 -0
- package/dist/api/skills.js +208 -0
- package/dist/api/vega.d.ts +54 -7
- package/dist/api/vega.js +112 -25
- package/dist/auth/oauth.d.ts +5 -1
- package/dist/auth/oauth.js +351 -95
- package/dist/cli.js +49 -5
- package/dist/client.d.ts +12 -0
- package/dist/client.js +52 -8
- package/dist/commands/agent.d.ts +33 -1
- package/dist/commands/agent.js +721 -49
- package/dist/commands/auth.js +226 -55
- package/dist/commands/bkn-ops.d.ts +77 -0
- package/dist/commands/bkn-ops.js +1056 -0
- package/dist/commands/bkn-query.d.ts +14 -0
- package/dist/commands/bkn-query.js +370 -0
- package/dist/commands/bkn-schema.d.ts +135 -0
- package/dist/commands/bkn-schema.js +1483 -0
- package/dist/commands/bkn-utils.d.ts +36 -0
- package/dist/commands/bkn-utils.js +102 -0
- package/dist/commands/bkn.d.ts +7 -113
- package/dist/commands/bkn.js +175 -2429
- package/dist/commands/call.js +8 -5
- package/dist/commands/dataflow.d.ts +1 -0
- package/dist/commands/dataflow.js +251 -0
- package/dist/commands/dataview.d.ts +7 -0
- package/dist/commands/dataview.js +38 -2
- package/dist/commands/ds.d.ts +1 -0
- package/dist/commands/ds.js +8 -1
- package/dist/commands/explore-bkn.d.ts +79 -0
- package/dist/commands/explore-bkn.js +273 -0
- package/dist/commands/explore-chat.d.ts +3 -0
- package/dist/commands/explore-chat.js +193 -0
- package/dist/commands/explore-vega.d.ts +3 -0
- package/dist/commands/explore-vega.js +71 -0
- package/dist/commands/explore.d.ts +9 -0
- package/dist/commands/explore.js +258 -0
- package/dist/commands/import-csv.d.ts +2 -0
- package/dist/commands/import-csv.js +3 -2
- package/dist/commands/skill.d.ts +26 -0
- package/dist/commands/skill.js +524 -0
- package/dist/commands/vega.js +372 -117
- package/dist/config/jwt.d.ts +6 -0
- package/dist/config/jwt.js +21 -0
- package/dist/config/no-auth.d.ts +3 -0
- package/dist/config/no-auth.js +5 -0
- package/dist/config/store.d.ts +45 -5
- package/dist/config/store.js +385 -30
- package/dist/index.d.ts +6 -1
- package/dist/index.js +5 -1
- package/dist/kweaver.d.ts +5 -0
- package/dist/kweaver.js +32 -2
- package/dist/resources/bkn.d.ts +4 -0
- package/dist/resources/bkn.js +6 -3
- package/dist/resources/conversations.d.ts +5 -2
- package/dist/resources/conversations.js +17 -3
- package/dist/resources/knowledge-networks.js +3 -8
- package/dist/resources/skills.d.ts +47 -0
- package/dist/resources/skills.js +47 -0
- package/dist/resources/vega.d.ts +11 -6
- package/dist/resources/vega.js +37 -10
- package/dist/templates/explorer/app.js +136 -0
- package/dist/templates/explorer/bkn.js +747 -0
- package/dist/templates/explorer/chat.js +980 -0
- package/dist/templates/explorer/dashboard.js +82 -0
- package/dist/templates/explorer/index.html +35 -0
- package/dist/templates/explorer/style.css +2440 -0
- package/dist/templates/explorer/vega.js +291 -0
- package/dist/utils/http.d.ts +3 -0
- package/dist/utils/http.js +37 -1
- package/package.json +9 -5
package/dist/commands/call.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
2
|
+
import { isNoAuth } from "../config/no-auth.js";
|
|
2
3
|
import { HttpError } from "../utils/http.js";
|
|
3
4
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
4
5
|
export function parseCallArgs(args) {
|
|
@@ -74,11 +75,13 @@ export function parseCallArgs(args) {
|
|
|
74
75
|
return { url, method, headers, body, pretty, verbose, businessDomain };
|
|
75
76
|
}
|
|
76
77
|
function injectAuthHeaders(headers, accessToken, businessDomain) {
|
|
77
|
-
if (!
|
|
78
|
-
headers.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
headers.
|
|
78
|
+
if (!isNoAuth(accessToken)) {
|
|
79
|
+
if (!headers.has("authorization")) {
|
|
80
|
+
headers.set("authorization", `Bearer ${accessToken}`);
|
|
81
|
+
}
|
|
82
|
+
if (!headers.has("token")) {
|
|
83
|
+
headers.set("token", accessToken);
|
|
84
|
+
}
|
|
82
85
|
}
|
|
83
86
|
if (!headers.has("x-business-domain")) {
|
|
84
87
|
headers.set("x-business-domain", businessDomain);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runDataflowCommand(args: string[]): Promise<number>;
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { access, readFile } from "node:fs/promises";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import columnify from "columnify";
|
|
4
|
+
import stringWidth from "string-width";
|
|
5
|
+
import yargs from "yargs";
|
|
6
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
7
|
+
import { resolveBusinessDomain } from "../config/store.js";
|
|
8
|
+
import { getDataflowLogsPage, listDataflowRuns, listDataflows, runDataflowWithFile, runDataflowWithRemoteUrl, } from "../api/dataflow2.js";
|
|
9
|
+
function renderTable(rows) {
|
|
10
|
+
if (rows.length === 0)
|
|
11
|
+
return "";
|
|
12
|
+
return columnify(rows, {
|
|
13
|
+
showHeaders: true,
|
|
14
|
+
preserveNewLines: true,
|
|
15
|
+
stringLength: stringWidth,
|
|
16
|
+
headingTransform: (heading) => heading,
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function buildListTableRows(items) {
|
|
20
|
+
return items.map((item) => ({
|
|
21
|
+
"ID": item.id,
|
|
22
|
+
"Title": item.title ?? "",
|
|
23
|
+
"Status": item.status ?? "",
|
|
24
|
+
"Trigger": item.trigger ?? "",
|
|
25
|
+
"Creator": item.creator ?? "",
|
|
26
|
+
"Updated At": item.updated_at != null ? String(item.updated_at) : "",
|
|
27
|
+
"Version ID": item.version_id ?? "",
|
|
28
|
+
}));
|
|
29
|
+
}
|
|
30
|
+
function buildRunTableRows(items) {
|
|
31
|
+
return items.map((item) => ({
|
|
32
|
+
"ID": item.id,
|
|
33
|
+
"Status": item.status ?? "",
|
|
34
|
+
"Started At": item.started_at != null ? String(item.started_at) : "",
|
|
35
|
+
"Ended At": item.ended_at != null ? String(item.ended_at) : "",
|
|
36
|
+
"Source Name": item.source?.name != null ? String(item.source.name) : "",
|
|
37
|
+
"Content Type": item.source?.content_type != null ? String(item.source.content_type) : "",
|
|
38
|
+
"Size": item.source?.size != null ? String(item.source.size) : "",
|
|
39
|
+
"Reason": item.reason ?? "",
|
|
40
|
+
}));
|
|
41
|
+
}
|
|
42
|
+
function parseSinceToLocalDayRange(value) {
|
|
43
|
+
// 只支持 YYYY-MM-DD 格式,解析为本地时区的一整天范围
|
|
44
|
+
const match = value.match(/^(\d{4})-(\d{2})-(\d{2})$/);
|
|
45
|
+
if (!match)
|
|
46
|
+
return null;
|
|
47
|
+
const year = parseInt(match[1], 10);
|
|
48
|
+
const month = parseInt(match[2], 10) - 1; // Date month is 0-indexed
|
|
49
|
+
const day = parseInt(match[3], 10);
|
|
50
|
+
const start = new Date(year, month, day, 0, 0, 0);
|
|
51
|
+
const end = new Date(year, month, day, 23, 59, 59);
|
|
52
|
+
return {
|
|
53
|
+
startTime: Math.floor(start.getTime() / 1000),
|
|
54
|
+
endTime: Math.floor(end.getTime() / 1000),
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function formatDataflowLogSummary(item) {
|
|
58
|
+
const duration = item.metadata?.duration ?? "-";
|
|
59
|
+
return [
|
|
60
|
+
`[${item.id}] ${item.taskId ?? ""} ${item.operator ?? ""}`,
|
|
61
|
+
`Status: ${item.status ?? ""}`,
|
|
62
|
+
`Started At: ${item.started_at ?? ""}`,
|
|
63
|
+
`Updated At: ${item.updated_at ?? ""}`,
|
|
64
|
+
`Duration: ${duration}`
|
|
65
|
+
].join("\n");
|
|
66
|
+
}
|
|
67
|
+
function formatIndentedJsonBlock(label, value) {
|
|
68
|
+
const pretty = JSON.stringify(value ?? {}, null, 4) ?? "{}";
|
|
69
|
+
const indented = pretty
|
|
70
|
+
.split("\n")
|
|
71
|
+
.map((line) => ` ${line}`)
|
|
72
|
+
.join("\n");
|
|
73
|
+
return ` ${label}:\n${indented}`;
|
|
74
|
+
}
|
|
75
|
+
function formatDataflowLogOutput(item, detail) {
|
|
76
|
+
const parts = [formatDataflowLogSummary(item)];
|
|
77
|
+
if (detail) {
|
|
78
|
+
parts.push("");
|
|
79
|
+
parts.push(formatIndentedJsonBlock("input", item.inputs ?? {}));
|
|
80
|
+
parts.push("");
|
|
81
|
+
parts.push(formatIndentedJsonBlock("output", item.outputs ?? {}));
|
|
82
|
+
}
|
|
83
|
+
return parts.join("\n");
|
|
84
|
+
}
|
|
85
|
+
async function requireTokenAndBusinessDomain(businessDomain) {
|
|
86
|
+
const token = await ensureValidToken();
|
|
87
|
+
return {
|
|
88
|
+
baseUrl: token.baseUrl,
|
|
89
|
+
accessToken: token.accessToken,
|
|
90
|
+
businessDomain: businessDomain || resolveBusinessDomain(),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
export async function runDataflowCommand(args) {
|
|
94
|
+
let exitCode = 0;
|
|
95
|
+
const parser = yargs(args)
|
|
96
|
+
.scriptName("kweaver dataflow")
|
|
97
|
+
.exitProcess(false)
|
|
98
|
+
.help()
|
|
99
|
+
.version(false)
|
|
100
|
+
.strict()
|
|
101
|
+
.fail((message, error) => {
|
|
102
|
+
throw error ?? new Error(message);
|
|
103
|
+
})
|
|
104
|
+
.command("list", "List all dataflows", (command) => command.option("biz-domain", {
|
|
105
|
+
alias: "bd",
|
|
106
|
+
type: "string",
|
|
107
|
+
}), async (argv) => {
|
|
108
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
109
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
110
|
+
const body = await listDataflows(base);
|
|
111
|
+
const table = renderTable(buildListTableRows(body.dags));
|
|
112
|
+
if (table) {
|
|
113
|
+
console.log(table);
|
|
114
|
+
}
|
|
115
|
+
return 0;
|
|
116
|
+
});
|
|
117
|
+
})
|
|
118
|
+
.command("run <dagId>", "Trigger one dataflow run", (command) => command
|
|
119
|
+
.positional("dagId", { type: "string" })
|
|
120
|
+
.option("file", { type: "string" })
|
|
121
|
+
.option("url", { type: "string" })
|
|
122
|
+
.option("name", { type: "string" })
|
|
123
|
+
.option("biz-domain", { alias: "bd", type: "string" })
|
|
124
|
+
.check((argv) => {
|
|
125
|
+
const hasFile = typeof argv.file === "string";
|
|
126
|
+
const hasUrl = typeof argv.url === "string";
|
|
127
|
+
if (hasFile === hasUrl) {
|
|
128
|
+
throw new Error("Exactly one of --file or --url is required.");
|
|
129
|
+
}
|
|
130
|
+
if (hasUrl && typeof argv.name !== "string") {
|
|
131
|
+
throw new Error("--url requires --name.");
|
|
132
|
+
}
|
|
133
|
+
return true;
|
|
134
|
+
}), async (argv) => {
|
|
135
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
136
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
137
|
+
if (typeof argv.file === "string") {
|
|
138
|
+
await access(argv.file, constants.R_OK);
|
|
139
|
+
const fileBytes = await readFile(argv.file);
|
|
140
|
+
const fileName = argv.file.split(/[\\/]/).pop() || "upload.bin";
|
|
141
|
+
const body = await runDataflowWithFile({
|
|
142
|
+
...base,
|
|
143
|
+
dagId: argv.dagId,
|
|
144
|
+
fileName,
|
|
145
|
+
fileBytes,
|
|
146
|
+
});
|
|
147
|
+
console.log(body.dag_instance_id);
|
|
148
|
+
return 0;
|
|
149
|
+
}
|
|
150
|
+
const body = await runDataflowWithRemoteUrl({
|
|
151
|
+
...base,
|
|
152
|
+
dagId: argv.dagId,
|
|
153
|
+
url: String(argv.url),
|
|
154
|
+
name: String(argv.name),
|
|
155
|
+
});
|
|
156
|
+
console.log(body.dag_instance_id);
|
|
157
|
+
return 0;
|
|
158
|
+
});
|
|
159
|
+
})
|
|
160
|
+
.command("runs <dagId>", "List run records for one dataflow", (command) => command
|
|
161
|
+
.positional("dagId", { type: "string" })
|
|
162
|
+
.option("since", { type: "string" })
|
|
163
|
+
.option("biz-domain", { alias: "bd", type: "string" }), async (argv) => {
|
|
164
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
165
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
166
|
+
const dayRange = typeof argv.since === "string" ? parseSinceToLocalDayRange(argv.since) : null;
|
|
167
|
+
let results = [];
|
|
168
|
+
if (!dayRange) {
|
|
169
|
+
const body = await listDataflowRuns({
|
|
170
|
+
...base,
|
|
171
|
+
dagId: argv.dagId,
|
|
172
|
+
page: 0,
|
|
173
|
+
limit: 20,
|
|
174
|
+
sortBy: "started_at",
|
|
175
|
+
order: "desc",
|
|
176
|
+
});
|
|
177
|
+
results = body.results;
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
const first = await listDataflowRuns({
|
|
181
|
+
...base,
|
|
182
|
+
dagId: argv.dagId,
|
|
183
|
+
page: 0,
|
|
184
|
+
limit: 20,
|
|
185
|
+
sortBy: "started_at",
|
|
186
|
+
order: "desc",
|
|
187
|
+
startTime: dayRange.startTime,
|
|
188
|
+
endTime: dayRange.endTime,
|
|
189
|
+
});
|
|
190
|
+
results = [...first.results];
|
|
191
|
+
const total = first.total ?? first.results.length;
|
|
192
|
+
for (let page = 1; page * 20 < total; page += 1) {
|
|
193
|
+
const next = await listDataflowRuns({
|
|
194
|
+
...base,
|
|
195
|
+
dagId: argv.dagId,
|
|
196
|
+
page,
|
|
197
|
+
limit: 20,
|
|
198
|
+
sortBy: "started_at",
|
|
199
|
+
order: "desc",
|
|
200
|
+
startTime: dayRange.startTime,
|
|
201
|
+
endTime: dayRange.endTime,
|
|
202
|
+
});
|
|
203
|
+
results = results.concat(next.results);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
const table = renderTable(buildRunTableRows(results));
|
|
207
|
+
if (table) {
|
|
208
|
+
console.log(table);
|
|
209
|
+
}
|
|
210
|
+
return 0;
|
|
211
|
+
});
|
|
212
|
+
})
|
|
213
|
+
.command("logs <dagId> <instanceId>", "Show logs for one run in summary or detail mode", (command) => command
|
|
214
|
+
.positional("dagId", { type: "string" })
|
|
215
|
+
.positional("instanceId", { type: "string" })
|
|
216
|
+
.option("detail", { type: "boolean", default: false })
|
|
217
|
+
.option("biz-domain", { alias: "bd", type: "string" }), async (argv) => {
|
|
218
|
+
exitCode = await with401RefreshRetry(async () => {
|
|
219
|
+
const base = await requireTokenAndBusinessDomain(argv.bizDomain);
|
|
220
|
+
let seen = 0;
|
|
221
|
+
for (let page = 0;; page += 1) {
|
|
222
|
+
const body = await getDataflowLogsPage({
|
|
223
|
+
...base,
|
|
224
|
+
dagId: argv.dagId,
|
|
225
|
+
instanceId: argv.instanceId,
|
|
226
|
+
page,
|
|
227
|
+
limit: 100,
|
|
228
|
+
});
|
|
229
|
+
if (body.results.length === 0)
|
|
230
|
+
break;
|
|
231
|
+
for (const item of body.results) {
|
|
232
|
+
console.log(formatDataflowLogOutput(item, argv.detail === true));
|
|
233
|
+
console.log("");
|
|
234
|
+
}
|
|
235
|
+
seen += body.results.length;
|
|
236
|
+
if ((body.total ?? 0) > 0 && seen >= (body.total ?? 0))
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
return 0;
|
|
240
|
+
});
|
|
241
|
+
})
|
|
242
|
+
.demandCommand(1);
|
|
243
|
+
try {
|
|
244
|
+
await parser.parseAsync();
|
|
245
|
+
return exitCode;
|
|
246
|
+
}
|
|
247
|
+
catch (error) {
|
|
248
|
+
console.error(formatHttpError(error));
|
|
249
|
+
return 1;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
@@ -1 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strip SQL line/block comments and leading whitespace, then return the first identifier token (lowercase).
|
|
3
|
+
* Used to reject DDL/DML passed to dataview query (server applies LIMIT semantics).
|
|
4
|
+
*/
|
|
5
|
+
export declare function getFirstSqlTokenAfterComments(sql: string): string;
|
|
6
|
+
/** True if ad-hoc SQL is safe for dataview query (SELECT / WITH only). */
|
|
7
|
+
export declare function isDataviewSelectLikeSql(sql: string): boolean;
|
|
1
8
|
export declare function runDataviewCommand(args: string[]): Promise<number>;
|
|
@@ -3,6 +3,33 @@ import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/
|
|
|
3
3
|
import { deleteDataView, findDataView, getDataView, listDataViews, queryDataView, } from "../api/dataviews.js";
|
|
4
4
|
import { formatCallOutput } from "./call.js";
|
|
5
5
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
6
|
+
/**
|
|
7
|
+
* Strip SQL line/block comments and leading whitespace, then return the first identifier token (lowercase).
|
|
8
|
+
* Used to reject DDL/DML passed to dataview query (server applies LIMIT semantics).
|
|
9
|
+
*/
|
|
10
|
+
export function getFirstSqlTokenAfterComments(sql) {
|
|
11
|
+
let s = sql.replace(/\/\*[\s\S]*?\*\//g, " ");
|
|
12
|
+
const lines = s.split("\n").map((line) => {
|
|
13
|
+
const idx = line.indexOf("--");
|
|
14
|
+
return idx >= 0 ? line.slice(0, idx) : line;
|
|
15
|
+
});
|
|
16
|
+
s = lines.join("\n");
|
|
17
|
+
s = s.replace(/\s+/g, " ").trim();
|
|
18
|
+
if (!s)
|
|
19
|
+
return "";
|
|
20
|
+
const match = /^([a-zA-Z_][a-zA-Z0-9_]*|"(?:[^"]|"")*")/.exec(s);
|
|
21
|
+
if (!match)
|
|
22
|
+
return "";
|
|
23
|
+
const tok = match[1];
|
|
24
|
+
if (tok.startsWith('"'))
|
|
25
|
+
return tok.slice(1, -1).replace(/""/g, '"').toLowerCase();
|
|
26
|
+
return tok.toLowerCase();
|
|
27
|
+
}
|
|
28
|
+
/** True if ad-hoc SQL is safe for dataview query (SELECT / WITH only). */
|
|
29
|
+
export function isDataviewSelectLikeSql(sql) {
|
|
30
|
+
const kw = getFirstSqlTokenAfterComments(sql);
|
|
31
|
+
return kw === "select" || kw === "with";
|
|
32
|
+
}
|
|
6
33
|
function confirmYes(prompt) {
|
|
7
34
|
return new Promise((resolve) => {
|
|
8
35
|
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
@@ -27,7 +54,7 @@ Subcommands:
|
|
|
27
54
|
|
|
28
55
|
list — list all data views (no keyword search)
|
|
29
56
|
find — search by name; default fuzzy, --exact for strict match, --wait to poll
|
|
30
|
-
query — run SQL query against a data view (mdl-uniquery); omit --sql to use view default SQL`);
|
|
57
|
+
query — run SQL query against a data view (mdl-uniquery); omit --sql to use view default SQL; only SELECT/WITH unless --raw-sql`);
|
|
31
58
|
return 0;
|
|
32
59
|
}
|
|
33
60
|
const dispatch = () => {
|
|
@@ -214,8 +241,9 @@ async function runDataviewQueryCommand(args) {
|
|
|
214
241
|
let limit = 50;
|
|
215
242
|
let offset = 0;
|
|
216
243
|
let needTotal = false;
|
|
244
|
+
let rawSql = false;
|
|
217
245
|
if (args.length === 0 || args[0].startsWith("-")) {
|
|
218
|
-
console.error("Usage: kweaver dataview query <id> [--sql <sql>] [--limit <n>] [--offset <n>] [--need-total] [-bd value] [--pretty]");
|
|
246
|
+
console.error("Usage: kweaver dataview query <id> [--sql <sql>] [--limit <n>] [--offset <n>] [--need-total] [--raw-sql] [-bd value] [--pretty]");
|
|
219
247
|
return 1;
|
|
220
248
|
}
|
|
221
249
|
const id = args[0];
|
|
@@ -228,6 +256,10 @@ async function runDataviewQueryCommand(args) {
|
|
|
228
256
|
}
|
|
229
257
|
if (arg === "--pretty")
|
|
230
258
|
continue;
|
|
259
|
+
if (arg === "--raw-sql") {
|
|
260
|
+
rawSql = true;
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
231
263
|
if ((arg === "--sql" || arg === "-s") && tail[i + 1]) {
|
|
232
264
|
sql = tail[++i];
|
|
233
265
|
continue;
|
|
@@ -249,6 +281,10 @@ async function runDataviewQueryCommand(args) {
|
|
|
249
281
|
continue;
|
|
250
282
|
}
|
|
251
283
|
}
|
|
284
|
+
if (sql !== undefined && sql !== "" && !rawSql && !isDataviewSelectLikeSql(sql)) {
|
|
285
|
+
console.error("dataview query only supports SELECT statements (or WITH for CTEs). Use --raw-sql to send other SQL at your own risk.");
|
|
286
|
+
return 1;
|
|
287
|
+
}
|
|
252
288
|
const token = await ensureValidToken();
|
|
253
289
|
const result = await queryDataView({
|
|
254
290
|
baseUrl: token.baseUrl,
|
package/dist/commands/ds.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ export declare function parseImportCsvArgs(args: string[]): {
|
|
|
11
11
|
tablePrefix: string;
|
|
12
12
|
batchSize: number;
|
|
13
13
|
businessDomain: string;
|
|
14
|
+
recreate: boolean;
|
|
14
15
|
};
|
|
15
16
|
export declare function resolveFiles(pattern: string): Promise<string[]>;
|
|
16
17
|
export interface ImportCsvResult {
|
package/dist/commands/ds.js
CHANGED
|
@@ -306,6 +306,7 @@ Options:
|
|
|
306
306
|
--files <s> CSV file paths (comma-separated or glob pattern, required)
|
|
307
307
|
--table-prefix <s> Table name prefix (default: none)
|
|
308
308
|
--batch-size <n> Rows per batch (default: 500, range: 1-10000)
|
|
309
|
+
--recreate First batch uses overwrite (drop/recreate table) then append; use when schema changed
|
|
309
310
|
-bd, --biz-domain Business domain (default: bd_public)`;
|
|
310
311
|
export function parseImportCsvArgs(args) {
|
|
311
312
|
let datasourceId = "";
|
|
@@ -313,6 +314,7 @@ export function parseImportCsvArgs(args) {
|
|
|
313
314
|
let tablePrefix = "";
|
|
314
315
|
let batchSize = 500;
|
|
315
316
|
let businessDomain = "";
|
|
317
|
+
let recreate = false;
|
|
316
318
|
for (let i = 0; i < args.length; i += 1) {
|
|
317
319
|
const arg = args[i];
|
|
318
320
|
if (arg === "--help" || arg === "-h")
|
|
@@ -321,6 +323,10 @@ export function parseImportCsvArgs(args) {
|
|
|
321
323
|
files = args[++i];
|
|
322
324
|
continue;
|
|
323
325
|
}
|
|
326
|
+
if (arg === "--recreate") {
|
|
327
|
+
recreate = true;
|
|
328
|
+
continue;
|
|
329
|
+
}
|
|
324
330
|
if (arg === "--table-prefix" && args[i + 1]) {
|
|
325
331
|
tablePrefix = args[++i];
|
|
326
332
|
continue;
|
|
@@ -343,7 +349,7 @@ export function parseImportCsvArgs(args) {
|
|
|
343
349
|
}
|
|
344
350
|
if (!businessDomain)
|
|
345
351
|
businessDomain = resolveBusinessDomain();
|
|
346
|
-
return { datasourceId, files, tablePrefix, batchSize, businessDomain };
|
|
352
|
+
return { datasourceId, files, tablePrefix, batchSize, businessDomain, recreate };
|
|
347
353
|
}
|
|
348
354
|
export async function resolveFiles(pattern) {
|
|
349
355
|
const parts = pattern.split(",").map((p) => p.trim()).filter(Boolean);
|
|
@@ -446,6 +452,7 @@ export async function runDsImportCsv(args) {
|
|
|
446
452
|
tableExist,
|
|
447
453
|
data: batch,
|
|
448
454
|
fieldMappings,
|
|
455
|
+
recreate: options.recreate,
|
|
449
456
|
});
|
|
450
457
|
const t0 = Date.now();
|
|
451
458
|
process.stderr.write(`[${tableName}] batch ${batchLabel} (${rowCount} rows)... `);
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
export interface ExploreMeta {
|
|
3
|
+
bkn: {
|
|
4
|
+
id: string;
|
|
5
|
+
name: string;
|
|
6
|
+
};
|
|
7
|
+
statistics: {
|
|
8
|
+
object_count: number;
|
|
9
|
+
relation_count: number;
|
|
10
|
+
};
|
|
11
|
+
objectTypes: Array<{
|
|
12
|
+
id: string;
|
|
13
|
+
name: string;
|
|
14
|
+
displayKey: string;
|
|
15
|
+
propertyCount: number;
|
|
16
|
+
properties: Array<{
|
|
17
|
+
name: string;
|
|
18
|
+
type?: string;
|
|
19
|
+
}>;
|
|
20
|
+
}>;
|
|
21
|
+
relationTypes: Array<{
|
|
22
|
+
id: string;
|
|
23
|
+
name: string;
|
|
24
|
+
sourceOtId: string;
|
|
25
|
+
targetOtId: string;
|
|
26
|
+
sourceOtName: string;
|
|
27
|
+
targetOtName: string;
|
|
28
|
+
}>;
|
|
29
|
+
actionTypes: Array<{
|
|
30
|
+
id: string;
|
|
31
|
+
name: string;
|
|
32
|
+
}>;
|
|
33
|
+
}
|
|
34
|
+
export interface ExploreOt {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
displayKey: string;
|
|
38
|
+
propertyCount: number;
|
|
39
|
+
properties: Array<{
|
|
40
|
+
name: string;
|
|
41
|
+
type?: string;
|
|
42
|
+
}>;
|
|
43
|
+
}
|
|
44
|
+
export interface ExploreRt {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
sourceOtId: string;
|
|
48
|
+
targetOtId: string;
|
|
49
|
+
sourceOtName: string;
|
|
50
|
+
targetOtName: string;
|
|
51
|
+
}
|
|
52
|
+
export interface ExploreAt {
|
|
53
|
+
id: string;
|
|
54
|
+
name: string;
|
|
55
|
+
}
|
|
56
|
+
export interface ExploreBkn {
|
|
57
|
+
id: string;
|
|
58
|
+
name: string;
|
|
59
|
+
}
|
|
60
|
+
export interface ExploreStats {
|
|
61
|
+
object_count: number;
|
|
62
|
+
relation_count: number;
|
|
63
|
+
}
|
|
64
|
+
export declare const EXPLORE_BOOTSTRAP_RETRY_DELAY_MS = 300;
|
|
65
|
+
export declare const EXPLORE_BOOTSTRAP_MAX_ATTEMPTS = 2;
|
|
66
|
+
export declare function buildMeta(knRaw: string, otRaw: string, rtRaw: string, atRaw: string): ExploreMeta;
|
|
67
|
+
export declare function isRetryableExploreBootstrapError(error: unknown): boolean;
|
|
68
|
+
export declare function loadExploreMetaWithRetry(token: {
|
|
69
|
+
baseUrl: string;
|
|
70
|
+
accessToken: string;
|
|
71
|
+
}, knId: string, businessDomain: string): Promise<ExploreMeta>;
|
|
72
|
+
export declare function readBody(req: IncomingMessage): Promise<string>;
|
|
73
|
+
export declare function jsonResponse(res: ServerResponse, status: number, data: unknown): void;
|
|
74
|
+
export declare function handleApiError(res: ServerResponse, error: unknown): void;
|
|
75
|
+
export type TokenProvider = () => Promise<{
|
|
76
|
+
baseUrl: string;
|
|
77
|
+
accessToken: string;
|
|
78
|
+
}>;
|
|
79
|
+
export declare function registerBknRoutes(meta: ExploreMeta, getToken: TokenProvider, businessDomain: string): Map<string, (req: IncomingMessage, res: ServerResponse) => void>;
|