@kweaver-ai/kweaver-sdk 0.4.10 → 0.4.12
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 +61 -3
- package/README.zh.md +42 -1
- package/dist/api/dataflow.d.ts +78 -0
- package/dist/api/dataflow.js +135 -0
- package/dist/api/dataviews.d.ts +58 -1
- package/dist/api/dataviews.js +150 -1
- package/dist/auth/oauth.d.ts +6 -1
- package/dist/auth/oauth.js +240 -166
- package/dist/cli.js +13 -1
- package/dist/client.d.ts +12 -0
- package/dist/client.js +18 -0
- package/dist/commands/auth.js +36 -16
- package/dist/commands/bkn.js +214 -21
- package/dist/commands/dataview.d.ts +1 -0
- package/dist/commands/dataview.js +244 -0
- package/dist/commands/ds.d.ts +16 -0
- package/dist/commands/ds.js +204 -1
- package/dist/commands/import-csv.d.ts +47 -0
- package/dist/commands/import-csv.js +111 -0
- package/dist/config/store.d.ts +2 -0
- package/dist/config/tls-env.d.ts +8 -0
- package/dist/config/tls-env.js +22 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/resources/dataflows.d.ts +17 -0
- package/dist/resources/dataflows.js +22 -0
- package/dist/resources/datasources.d.ts +52 -0
- package/dist/resources/datasources.js +54 -0
- package/dist/resources/dataviews.d.ts +28 -0
- package/dist/resources/dataviews.js +34 -0
- package/dist/resources/vega.d.ts +41 -0
- package/dist/resources/vega.js +80 -0
- package/package.json +2 -1
package/dist/auth/oauth.js
CHANGED
|
@@ -8,82 +8,137 @@ const DEFAULT_SCOPE = "openid offline all";
|
|
|
8
8
|
export function normalizeBaseUrl(value) {
|
|
9
9
|
return value.replace(/\/+$/, "");
|
|
10
10
|
}
|
|
11
|
+
/**
|
|
12
|
+
* Temporarily disable TLS certificate verification for Node `fetch` (sets
|
|
13
|
+
* NODE_TLS_REJECT_UNAUTHORIZED). Used for `--insecure` login and token refresh.
|
|
14
|
+
*/
|
|
15
|
+
async function runWithTlsInsecure(tlsInsecure, fn) {
|
|
16
|
+
if (!tlsInsecure) {
|
|
17
|
+
return fn();
|
|
18
|
+
}
|
|
19
|
+
const prev = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
|
20
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
21
|
+
try {
|
|
22
|
+
return await fn();
|
|
23
|
+
}
|
|
24
|
+
finally {
|
|
25
|
+
if (prev === undefined) {
|
|
26
|
+
delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
process.env.NODE_TLS_REJECT_UNAUTHORIZED = prev;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Generate a PKCE code_verifier and code_challenge (S256). */
|
|
34
|
+
async function generatePkce() {
|
|
35
|
+
const { randomBytes, createHash } = await import("node:crypto");
|
|
36
|
+
const verifier = randomBytes(48).toString("base64url");
|
|
37
|
+
const challenge = createHash("sha256").update(verifier).digest("base64url");
|
|
38
|
+
return { verifier, challenge };
|
|
39
|
+
}
|
|
11
40
|
/**
|
|
12
41
|
* OAuth2 Authorization Code login flow.
|
|
13
|
-
* 1. Register client (if not already registered)
|
|
42
|
+
* 1. Register client (if not already registered), OR use a provided client ID
|
|
14
43
|
* 2. Open browser to /oauth2/auth
|
|
15
44
|
* 3. Receive authorization code via local HTTP callback
|
|
16
45
|
* 4. Exchange code for access_token + refresh_token
|
|
17
46
|
* 5. Save token.json + client.json to ~/.kweaver/
|
|
18
47
|
*/
|
|
19
48
|
export async function oauth2Login(baseUrl, options) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
return runWithTlsInsecure(options?.tlsInsecure, async () => {
|
|
50
|
+
const { createServer } = await import("node:http");
|
|
51
|
+
const { randomBytes } = await import("node:crypto");
|
|
52
|
+
const base = normalizeBaseUrl(baseUrl);
|
|
53
|
+
const port = options?.port ?? DEFAULT_REDIRECT_PORT;
|
|
54
|
+
const scope = options?.scope ?? DEFAULT_SCOPE;
|
|
55
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
56
|
+
// Step 1: Determine client — use provided client ID or fall back to dynamic registration
|
|
57
|
+
let client = loadClientConfig(base);
|
|
58
|
+
if (options?.clientId) {
|
|
59
|
+
// Use the platform's existing client (e.g. the web app client).
|
|
60
|
+
// Persist it so future logins reuse it without re-registering.
|
|
61
|
+
client = {
|
|
62
|
+
baseUrl: base,
|
|
63
|
+
clientId: options.clientId,
|
|
64
|
+
clientSecret: options.clientSecret ?? "",
|
|
65
|
+
redirectUri,
|
|
66
|
+
logoutRedirectUri: redirectUri.replace("/callback", "/successful-logout"),
|
|
67
|
+
scope,
|
|
68
|
+
lang: "zh-cn",
|
|
69
|
+
product: "adp",
|
|
70
|
+
xForwardedPrefix: "",
|
|
71
|
+
};
|
|
72
|
+
saveClientConfig(base, client);
|
|
73
|
+
}
|
|
74
|
+
else if (!client?.clientId) {
|
|
75
|
+
client = await registerOAuth2Client(base, redirectUri, scope);
|
|
76
|
+
saveClientConfig(base, client);
|
|
77
|
+
}
|
|
78
|
+
// Use PKCE when no client secret is available (public client / platform client).
|
|
79
|
+
const usePkce = !client.clientSecret;
|
|
80
|
+
const pkce = usePkce ? await generatePkce() : null;
|
|
81
|
+
// Step 2: Generate CSRF state
|
|
82
|
+
const state = randomBytes(12).toString("hex");
|
|
83
|
+
// Step 3: Build authorization URL
|
|
84
|
+
const authParams = new URLSearchParams({
|
|
85
|
+
redirect_uri: redirectUri,
|
|
86
|
+
"x-forwarded-prefix": "",
|
|
87
|
+
client_id: client.clientId,
|
|
88
|
+
scope,
|
|
89
|
+
response_type: "code",
|
|
90
|
+
state,
|
|
91
|
+
lang: "zh-cn",
|
|
92
|
+
product: "adp",
|
|
93
|
+
});
|
|
94
|
+
if (pkce) {
|
|
95
|
+
authParams.set("code_challenge", pkce.challenge);
|
|
96
|
+
authParams.set("code_challenge_method", "S256");
|
|
97
|
+
}
|
|
98
|
+
const authUrl = `${base}/oauth2/auth?${authParams.toString()}`;
|
|
99
|
+
// Step 4: Start local callback server, wait for code
|
|
100
|
+
const code = await new Promise((resolve, reject) => {
|
|
101
|
+
const timeoutId = setTimeout(() => {
|
|
60
102
|
server.close();
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
103
|
+
reject(new Error("OAuth2 login timed out (120s). No authorization code received."));
|
|
104
|
+
}, 120_000);
|
|
105
|
+
const server = createServer((req, res) => {
|
|
106
|
+
const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
|
|
107
|
+
if (url.pathname === "/callback") {
|
|
108
|
+
const receivedState = url.searchParams.get("state");
|
|
109
|
+
const receivedCode = url.searchParams.get("code");
|
|
110
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
111
|
+
res.end("<html><body><h2>Login successful. You can close this tab.</h2></body></html>");
|
|
112
|
+
clearTimeout(timeoutId);
|
|
113
|
+
server.close();
|
|
114
|
+
if (receivedState !== state) {
|
|
115
|
+
reject(new Error("OAuth2 state mismatch — possible CSRF attack."));
|
|
116
|
+
}
|
|
117
|
+
else if (!receivedCode) {
|
|
118
|
+
reject(new Error("No authorization code received in callback."));
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
resolve(receivedCode);
|
|
122
|
+
}
|
|
66
123
|
}
|
|
67
124
|
else {
|
|
68
|
-
|
|
125
|
+
res.writeHead(404);
|
|
126
|
+
res.end();
|
|
69
127
|
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
// Step 5: Open browser (uses spawn with proper Windows quoting)
|
|
78
|
-
import("../utils/browser.js").then(({ openBrowser }) => {
|
|
79
|
-
openBrowser(authUrl);
|
|
128
|
+
});
|
|
129
|
+
server.listen(port, "127.0.0.1", () => {
|
|
130
|
+
// Step 5: Open browser (uses spawn with proper Windows quoting)
|
|
131
|
+
import("../utils/browser.js").then(({ openBrowser }) => {
|
|
132
|
+
openBrowser(authUrl);
|
|
133
|
+
});
|
|
134
|
+
process.stderr.write(`If the wrong browser opens, copy this URL to your correct browser:\n ${authUrl}\n`);
|
|
80
135
|
});
|
|
81
136
|
});
|
|
137
|
+
// Step 6: Exchange code for tokens
|
|
138
|
+
const token = await exchangeCodeForToken(base, code, client.clientId, client.clientSecret, redirectUri, pkce?.verifier, options?.tlsInsecure);
|
|
139
|
+
setCurrentPlatform(base);
|
|
140
|
+
return token;
|
|
82
141
|
});
|
|
83
|
-
// Step 6: Exchange code for tokens
|
|
84
|
-
const token = await exchangeCodeForToken(base, code, client.clientId, client.clientSecret, redirectUri);
|
|
85
|
-
setCurrentPlatform(base);
|
|
86
|
-
return token;
|
|
87
142
|
}
|
|
88
143
|
async function registerOAuth2Client(baseUrl, redirectUri, scope) {
|
|
89
144
|
const logoutUri = redirectUri.replace("/callback", "/successful-logout");
|
|
@@ -123,20 +178,31 @@ async function registerOAuth2Client(baseUrl, redirectUri, scope) {
|
|
|
123
178
|
xForwardedPrefix: "",
|
|
124
179
|
};
|
|
125
180
|
}
|
|
126
|
-
async function exchangeCodeForToken(baseUrl, code, clientId, clientSecret, redirectUri) {
|
|
127
|
-
const
|
|
181
|
+
async function exchangeCodeForToken(baseUrl, code, clientId, clientSecret, redirectUri, codeVerifier, tlsInsecure) {
|
|
182
|
+
const params = {
|
|
183
|
+
grant_type: "authorization_code",
|
|
184
|
+
code,
|
|
185
|
+
redirect_uri: redirectUri,
|
|
186
|
+
};
|
|
187
|
+
if (codeVerifier) {
|
|
188
|
+
params.code_verifier = codeVerifier;
|
|
189
|
+
}
|
|
190
|
+
const headers = {
|
|
191
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
192
|
+
Accept: "application/json",
|
|
193
|
+
};
|
|
194
|
+
if (clientSecret) {
|
|
195
|
+
// Confidential client: use HTTP Basic auth
|
|
196
|
+
headers.Authorization = `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString("base64")}`;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
// Public client (PKCE): send client_id in body
|
|
200
|
+
params.client_id = clientId;
|
|
201
|
+
}
|
|
128
202
|
const response = await fetch(`${baseUrl}/oauth2/token`, {
|
|
129
203
|
method: "POST",
|
|
130
|
-
headers
|
|
131
|
-
|
|
132
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
133
|
-
Accept: "application/json",
|
|
134
|
-
},
|
|
135
|
-
body: new URLSearchParams({
|
|
136
|
-
grant_type: "authorization_code",
|
|
137
|
-
code,
|
|
138
|
-
redirect_uri: redirectUri,
|
|
139
|
-
}).toString(),
|
|
204
|
+
headers,
|
|
205
|
+
body: new URLSearchParams(params).toString(),
|
|
140
206
|
});
|
|
141
207
|
const text = await response.text();
|
|
142
208
|
if (!response.ok) {
|
|
@@ -155,6 +221,7 @@ async function exchangeCodeForToken(baseUrl, code, clientId, clientSecret, redir
|
|
|
155
221
|
refreshToken: data.refresh_token ?? "",
|
|
156
222
|
idToken: data.id_token ?? "",
|
|
157
223
|
obtainedAt: now.toISOString(),
|
|
224
|
+
...(tlsInsecure ? { tlsInsecure: true } : {}),
|
|
158
225
|
};
|
|
159
226
|
saveTokenConfig(token);
|
|
160
227
|
return token;
|
|
@@ -171,105 +238,107 @@ async function exchangeCodeForToken(baseUrl, code, clientId, clientSecret, redir
|
|
|
171
238
|
* window for manual login (same UX as the old cookie-based flow).
|
|
172
239
|
*/
|
|
173
240
|
export async function playwrightLogin(baseUrl, options) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
browser?.close();
|
|
216
|
-
reject(new Error(`OAuth2 login timed out (${TIMEOUT_MS / 1000}s). No authorization code received.`));
|
|
217
|
-
}, TIMEOUT_MS);
|
|
218
|
-
const server = createServer((req, res) => {
|
|
219
|
-
const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
|
|
220
|
-
if (url.pathname === "/callback") {
|
|
221
|
-
const receivedState = url.searchParams.get("state");
|
|
222
|
-
const receivedCode = url.searchParams.get("code");
|
|
223
|
-
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
224
|
-
res.end("<html><body><h2>Login successful. You can close this tab.</h2></body></html>");
|
|
225
|
-
clearTimeout(timeoutId);
|
|
241
|
+
return runWithTlsInsecure(options?.tlsInsecure, async () => {
|
|
242
|
+
const { createServer } = await import("node:http");
|
|
243
|
+
const { randomBytes } = await import("node:crypto");
|
|
244
|
+
let chromium;
|
|
245
|
+
try {
|
|
246
|
+
const modName = "playwright";
|
|
247
|
+
const pw = await import(/* webpackIgnore: true */ modName);
|
|
248
|
+
chromium = pw.chromium;
|
|
249
|
+
}
|
|
250
|
+
catch {
|
|
251
|
+
throw new Error("Playwright is not installed. Run:\n npm install playwright && npx playwright install chromium");
|
|
252
|
+
}
|
|
253
|
+
const base = normalizeBaseUrl(baseUrl);
|
|
254
|
+
const port = options?.port ?? DEFAULT_REDIRECT_PORT;
|
|
255
|
+
const scope = options?.scope ?? DEFAULT_SCOPE;
|
|
256
|
+
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
257
|
+
const hasCredentials = !!(options?.username && options?.password);
|
|
258
|
+
// Step 1: Ensure registered OAuth2 client
|
|
259
|
+
let client = loadClientConfig(base);
|
|
260
|
+
if (!client?.clientId) {
|
|
261
|
+
client = await registerOAuth2Client(base, redirectUri, scope);
|
|
262
|
+
saveClientConfig(base, client);
|
|
263
|
+
}
|
|
264
|
+
// Step 2: Generate CSRF state
|
|
265
|
+
const state = randomBytes(12).toString("hex");
|
|
266
|
+
// Step 3: Build authorization URL
|
|
267
|
+
const authParams = new URLSearchParams({
|
|
268
|
+
redirect_uri: redirectUri,
|
|
269
|
+
"x-forwarded-prefix": "",
|
|
270
|
+
client_id: client.clientId,
|
|
271
|
+
scope,
|
|
272
|
+
response_type: "code",
|
|
273
|
+
state,
|
|
274
|
+
lang: "zh-cn",
|
|
275
|
+
product: "adp",
|
|
276
|
+
});
|
|
277
|
+
const authUrl = `${base}/oauth2/auth?${authParams.toString()}`;
|
|
278
|
+
// Step 4: Start local callback server to capture the authorization code
|
|
279
|
+
const code = await new Promise((resolve, reject) => {
|
|
280
|
+
const TIMEOUT_MS = hasCredentials ? 30_000 : 120_000;
|
|
281
|
+
const timeoutId = setTimeout(() => {
|
|
226
282
|
server.close();
|
|
227
283
|
browser?.close();
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
284
|
+
reject(new Error(`OAuth2 login timed out (${TIMEOUT_MS / 1000}s). No authorization code received.`));
|
|
285
|
+
}, TIMEOUT_MS);
|
|
286
|
+
const server = createServer((req, res) => {
|
|
287
|
+
const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
|
|
288
|
+
if (url.pathname === "/callback") {
|
|
289
|
+
const receivedState = url.searchParams.get("state");
|
|
290
|
+
const receivedCode = url.searchParams.get("code");
|
|
291
|
+
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
292
|
+
res.end("<html><body><h2>Login successful. You can close this tab.</h2></body></html>");
|
|
293
|
+
clearTimeout(timeoutId);
|
|
294
|
+
server.close();
|
|
295
|
+
browser?.close();
|
|
296
|
+
if (receivedState !== state) {
|
|
297
|
+
reject(new Error("OAuth2 state mismatch — possible CSRF attack."));
|
|
298
|
+
}
|
|
299
|
+
else if (!receivedCode) {
|
|
300
|
+
reject(new Error("No authorization code received in callback."));
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
resolve(receivedCode);
|
|
304
|
+
}
|
|
233
305
|
}
|
|
234
306
|
else {
|
|
235
|
-
|
|
307
|
+
res.writeHead(404);
|
|
308
|
+
res.end();
|
|
236
309
|
}
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
await page.fill('input[name="password"]', options.password);
|
|
256
|
-
await page.click("button.ant-btn-primary");
|
|
310
|
+
});
|
|
311
|
+
let browser;
|
|
312
|
+
server.listen(port, "127.0.0.1", async () => {
|
|
313
|
+
try {
|
|
314
|
+
browser = await chromium.launch({ headless: hasCredentials });
|
|
315
|
+
const context = await browser.newContext({ ignoreHTTPSErrors: !!options?.tlsInsecure });
|
|
316
|
+
const page = await context.newPage();
|
|
317
|
+
// Navigate to OAuth2 auth URL — redirects to signin page
|
|
318
|
+
await page.goto(authUrl, { waitUntil: "networkidle", timeout: 30_000 });
|
|
319
|
+
if (hasCredentials) {
|
|
320
|
+
// Auto-fill credentials
|
|
321
|
+
await page.waitForSelector('input[name="account"]', { timeout: 10_000 });
|
|
322
|
+
await page.fill('input[name="account"]', options.username);
|
|
323
|
+
await page.fill('input[name="password"]', options.password);
|
|
324
|
+
await page.click("button.ant-btn-primary");
|
|
325
|
+
}
|
|
326
|
+
// else: visible browser — user logs in manually
|
|
327
|
+
// The OAuth2 callback will fire when login completes, resolving the promise above
|
|
257
328
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
reject(err);
|
|
266
|
-
}
|
|
329
|
+
catch (err) {
|
|
330
|
+
clearTimeout(timeoutId);
|
|
331
|
+
server.close();
|
|
332
|
+
browser?.close();
|
|
333
|
+
reject(err);
|
|
334
|
+
}
|
|
335
|
+
});
|
|
267
336
|
});
|
|
337
|
+
// Step 5: Exchange authorization code for tokens (includes refresh_token)
|
|
338
|
+
const token = await exchangeCodeForToken(base, code, client.clientId, client.clientSecret, redirectUri, undefined, options?.tlsInsecure);
|
|
339
|
+
setCurrentPlatform(base);
|
|
340
|
+
return token;
|
|
268
341
|
});
|
|
269
|
-
// Step 5: Exchange authorization code for tokens (includes refresh_token)
|
|
270
|
-
const token = await exchangeCodeForToken(base, code, client.clientId, client.clientSecret, redirectUri);
|
|
271
|
-
setCurrentPlatform(base);
|
|
272
|
-
return token;
|
|
273
342
|
}
|
|
274
343
|
function tokenNeedsRefresh(token) {
|
|
275
344
|
if (!token.expiresAt) {
|
|
@@ -306,7 +375,7 @@ export async function refreshAccessToken(token) {
|
|
|
306
375
|
});
|
|
307
376
|
let response;
|
|
308
377
|
try {
|
|
309
|
-
response = await fetch(url, {
|
|
378
|
+
response = await runWithTlsInsecure(token.tlsInsecure, () => fetch(url, {
|
|
310
379
|
method: "POST",
|
|
311
380
|
headers: {
|
|
312
381
|
Authorization: `Basic ${credentials}`,
|
|
@@ -314,7 +383,7 @@ export async function refreshAccessToken(token) {
|
|
|
314
383
|
Accept: "application/json",
|
|
315
384
|
},
|
|
316
385
|
body: body.toString(),
|
|
317
|
-
});
|
|
386
|
+
}));
|
|
318
387
|
}
|
|
319
388
|
catch (cause) {
|
|
320
389
|
const hint = cause instanceof Error ? cause.message : String(cause);
|
|
@@ -346,6 +415,7 @@ export async function refreshAccessToken(token) {
|
|
|
346
415
|
refreshToken: data.refresh_token ?? refreshToken,
|
|
347
416
|
idToken: data.id_token ?? token.idToken ?? "",
|
|
348
417
|
obtainedAt: now.toISOString(),
|
|
418
|
+
...(token.tlsInsecure ? { tlsInsecure: true } : {}),
|
|
349
419
|
};
|
|
350
420
|
saveTokenConfig(newToken);
|
|
351
421
|
return newToken;
|
|
@@ -486,6 +556,10 @@ export function formatHttpError(error) {
|
|
|
486
556
|
].join("\n").trim();
|
|
487
557
|
}
|
|
488
558
|
if (error instanceof Error) {
|
|
559
|
+
const cause = "cause" in error && error.cause instanceof Error ? error.cause.message : "";
|
|
560
|
+
if (cause && error.message === "fetch failed") {
|
|
561
|
+
return `${error.message}: ${cause}\nHint: use --insecure (-k) to skip TLS verification for self-signed certificates.`;
|
|
562
|
+
}
|
|
489
563
|
return error.message;
|
|
490
564
|
}
|
|
491
565
|
return String(error);
|
package/dist/cli.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { applyTlsEnvFromSavedTokens } from "./config/tls-env.js";
|
|
1
2
|
import { runAgentCommand } from "./commands/agent.js";
|
|
2
3
|
import { runAuthCommand } from "./commands/auth.js";
|
|
3
4
|
import { runKnCommand } from "./commands/bkn.js";
|
|
@@ -5,6 +6,7 @@ import { runCallCommand } from "./commands/call.js";
|
|
|
5
6
|
import { runConfigCommand } from "./commands/config.js";
|
|
6
7
|
import { runContextLoaderCommand } from "./commands/context-loader.js";
|
|
7
8
|
import { runDsCommand } from "./commands/ds.js";
|
|
9
|
+
import { runDataviewCommand } from "./commands/dataview.js";
|
|
8
10
|
import { runTokenCommand } from "./commands/token.js";
|
|
9
11
|
import { runVegaCommand } from "./commands/vega.js";
|
|
10
12
|
function printHelp() {
|
|
@@ -14,7 +16,7 @@ Usage:
|
|
|
14
16
|
kweaver --version | -V
|
|
15
17
|
kweaver --help | -h
|
|
16
18
|
|
|
17
|
-
kweaver auth <platform-url> [--alias name] [-u user] [-p pass] [--playwright]
|
|
19
|
+
kweaver auth <platform-url> [--alias name] [-u user] [-p pass] [--playwright] [--insecure|-k]
|
|
18
20
|
kweaver auth login <platform-url> (alias for auth <url>)
|
|
19
21
|
kweaver auth status [platform-url|alias]
|
|
20
22
|
kweaver auth list
|
|
@@ -46,6 +48,11 @@ Usage:
|
|
|
46
48
|
kweaver ds tables <id> [--keyword X] [--pretty]
|
|
47
49
|
kweaver ds connect <db_type> <host> <port> <database> --account X --password Y [--schema S] [--name N]
|
|
48
50
|
|
|
51
|
+
kweaver dataview list [--datasource-id id] [--type atomic|custom] [--limit n] [-bd value] [--pretty]
|
|
52
|
+
kweaver dataview find --name <name> [--exact] [--datasource-id id] [--wait] [--timeout ms] [-bd value] [--pretty]
|
|
53
|
+
kweaver dataview get <id> [-bd value] [--pretty]
|
|
54
|
+
kweaver dataview delete <id> [-y] [-bd value]
|
|
55
|
+
|
|
49
56
|
kweaver bkn list [options]
|
|
50
57
|
kweaver bkn get <kn-id> [options]
|
|
51
58
|
kweaver bkn search <kn-id> <query> [--max-concepts N] [--mode M] [--pretty] [-bd value]
|
|
@@ -89,6 +96,7 @@ Commands:
|
|
|
89
96
|
call (curl) Call an API with curl-style flags and auto-injected token headers
|
|
90
97
|
agent Agent CRUD, chat, sessions, history, publish/unpublish
|
|
91
98
|
ds Manage datasources (list, get, delete, tables, connect)
|
|
99
|
+
dataview List, find, get, delete data views (atomic / custom)
|
|
92
100
|
bkn Knowledge network (CRUD, build, validate, export, stats, push/pull,
|
|
93
101
|
object-type, relation-type, subgraph, action-type, action-execution, action-log)
|
|
94
102
|
config Per-platform configuration (business domain)
|
|
@@ -97,6 +105,7 @@ Commands:
|
|
|
97
105
|
help Show this message`);
|
|
98
106
|
}
|
|
99
107
|
export async function run(argv) {
|
|
108
|
+
applyTlsEnvFromSavedTokens();
|
|
100
109
|
const [command, ...rest] = argv;
|
|
101
110
|
if (command === "--version" || command === "-V" || command === "version") {
|
|
102
111
|
const { createRequire } = await import("node:module");
|
|
@@ -118,6 +127,9 @@ export async function run(argv) {
|
|
|
118
127
|
if (command === "ds") {
|
|
119
128
|
return runDsCommand(rest);
|
|
120
129
|
}
|
|
130
|
+
if (command === "dataview") {
|
|
131
|
+
return runDataviewCommand(rest);
|
|
132
|
+
}
|
|
121
133
|
if (command === "token") {
|
|
122
134
|
return runTokenCommand(rest);
|
|
123
135
|
}
|
package/dist/client.d.ts
CHANGED
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { AgentsResource } from "./resources/agents.js";
|
|
2
2
|
import { ConversationsResource } from "./resources/conversations.js";
|
|
3
3
|
import { ContextLoaderResource } from "./resources/context-loader.js";
|
|
4
|
+
import { DataflowsResource } from "./resources/dataflows.js";
|
|
5
|
+
import { DataSourcesResource } from "./resources/datasources.js";
|
|
6
|
+
import { DataViewsResource } from "./resources/dataviews.js";
|
|
4
7
|
import { KnowledgeNetworksResource } from "./resources/knowledge-networks.js";
|
|
5
8
|
import { BknResource } from "./resources/bkn.js";
|
|
9
|
+
import { VegaResource } from "./resources/vega.js";
|
|
6
10
|
/**
|
|
7
11
|
* Shared credentials passed to every resource method.
|
|
8
12
|
* Internal — use KWeaverClient.
|
|
@@ -78,6 +82,14 @@ export declare class KWeaverClient implements ClientContext {
|
|
|
78
82
|
readonly bkn: BknResource;
|
|
79
83
|
/** Conversation and message history. */
|
|
80
84
|
readonly conversations: ConversationsResource;
|
|
85
|
+
/** Dataflow DAG automation (create/run/poll/delete). */
|
|
86
|
+
readonly dataflows: DataflowsResource;
|
|
87
|
+
/** Data source management (connect, test, list tables). */
|
|
88
|
+
readonly datasources: DataSourcesResource;
|
|
89
|
+
/** Data view creation and retrieval. */
|
|
90
|
+
readonly dataviews: DataViewsResource;
|
|
91
|
+
/** Vega observability platform (catalogs, resources, connector types). */
|
|
92
|
+
readonly vega: VegaResource;
|
|
81
93
|
constructor(opts?: KWeaverClientOptions);
|
|
82
94
|
/**
|
|
83
95
|
* Async factory that auto-refreshes expired or revoked tokens.
|
package/dist/client.js
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
|
+
import { applyTlsEnvFromSavedTokens } from "./config/tls-env.js";
|
|
1
2
|
import { getCurrentPlatform, loadTokenConfig, } from "./config/store.js";
|
|
2
3
|
import { ensureValidToken } from "./auth/oauth.js";
|
|
3
4
|
import { AgentsResource } from "./resources/agents.js";
|
|
4
5
|
import { ConversationsResource } from "./resources/conversations.js";
|
|
5
6
|
import { ContextLoaderResource } from "./resources/context-loader.js";
|
|
7
|
+
import { DataflowsResource } from "./resources/dataflows.js";
|
|
8
|
+
import { DataSourcesResource } from "./resources/datasources.js";
|
|
9
|
+
import { DataViewsResource } from "./resources/dataviews.js";
|
|
6
10
|
import { KnowledgeNetworksResource } from "./resources/knowledge-networks.js";
|
|
7
11
|
import { BknResource } from "./resources/bkn.js";
|
|
12
|
+
import { VegaResource } from "./resources/vega.js";
|
|
8
13
|
// ── KWeaverClient ─────────────────────────────────────────────────────────────
|
|
9
14
|
/**
|
|
10
15
|
* Main entry point for the KWeaver TypeScript SDK.
|
|
@@ -46,6 +51,14 @@ export class KWeaverClient {
|
|
|
46
51
|
bkn;
|
|
47
52
|
/** Conversation and message history. */
|
|
48
53
|
conversations;
|
|
54
|
+
/** Dataflow DAG automation (create/run/poll/delete). */
|
|
55
|
+
dataflows;
|
|
56
|
+
/** Data source management (connect, test, list tables). */
|
|
57
|
+
datasources;
|
|
58
|
+
/** Data view creation and retrieval. */
|
|
59
|
+
dataviews;
|
|
60
|
+
/** Vega observability platform (catalogs, resources, connector types). */
|
|
61
|
+
vega;
|
|
49
62
|
constructor(opts = {}) {
|
|
50
63
|
const envDomain = process.env.KWEAVER_BUSINESS_DOMAIN;
|
|
51
64
|
let baseUrl;
|
|
@@ -97,6 +110,10 @@ export class KWeaverClient {
|
|
|
97
110
|
this.agents = new AgentsResource(this);
|
|
98
111
|
this.bkn = new BknResource(this);
|
|
99
112
|
this.conversations = new ConversationsResource(this);
|
|
113
|
+
this.dataflows = new DataflowsResource(this);
|
|
114
|
+
this.datasources = new DataSourcesResource(this);
|
|
115
|
+
this.dataviews = new DataViewsResource(this);
|
|
116
|
+
this.vega = new VegaResource(this);
|
|
100
117
|
}
|
|
101
118
|
/**
|
|
102
119
|
* Async factory that auto-refreshes expired or revoked tokens.
|
|
@@ -111,6 +128,7 @@ export class KWeaverClient {
|
|
|
111
128
|
* ```
|
|
112
129
|
*/
|
|
113
130
|
static async connect(opts = {}) {
|
|
131
|
+
applyTlsEnvFromSavedTokens();
|
|
114
132
|
// Try with current token first
|
|
115
133
|
let token = await ensureValidToken();
|
|
116
134
|
const client = new KWeaverClient({
|