@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.
@@ -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
- const { createServer } = await import("node:http");
21
- const { randomBytes } = await import("node:crypto");
22
- const base = normalizeBaseUrl(baseUrl);
23
- const port = options?.port ?? DEFAULT_REDIRECT_PORT;
24
- const scope = options?.scope ?? DEFAULT_SCOPE;
25
- const redirectUri = `http://127.0.0.1:${port}/callback`;
26
- // Step 1: Ensure registered client
27
- let client = loadClientConfig(base);
28
- if (!client?.clientId) {
29
- client = await registerOAuth2Client(base, redirectUri, scope);
30
- saveClientConfig(base, client);
31
- }
32
- // Step 2: Generate CSRF state
33
- const state = randomBytes(12).toString("hex");
34
- // Step 3: Build authorization URL
35
- const authParams = new URLSearchParams({
36
- redirect_uri: redirectUri,
37
- "x-forwarded-prefix": "",
38
- client_id: client.clientId,
39
- scope,
40
- response_type: "code",
41
- state,
42
- lang: "zh-cn",
43
- product: "adp",
44
- });
45
- const authUrl = `${base}/oauth2/auth?${authParams.toString()}`;
46
- // Step 4: Start local callback server, wait for code
47
- const code = await new Promise((resolve, reject) => {
48
- const timeoutId = setTimeout(() => {
49
- server.close();
50
- reject(new Error("OAuth2 login timed out (120s). No authorization code received."));
51
- }, 120_000);
52
- const server = createServer((req, res) => {
53
- const url = new URL(req.url ?? "/", `http://127.0.0.1:${port}`);
54
- if (url.pathname === "/callback") {
55
- const receivedState = url.searchParams.get("state");
56
- const receivedCode = url.searchParams.get("code");
57
- res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
58
- res.end("<html><body><h2>Login successful. You can close this tab.</h2></body></html>");
59
- clearTimeout(timeoutId);
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
- if (receivedState !== state) {
62
- reject(new Error("OAuth2 state mismatch — possible CSRF attack."));
63
- }
64
- else if (!receivedCode) {
65
- reject(new Error("No authorization code received in callback."));
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
- resolve(receivedCode);
125
+ res.writeHead(404);
126
+ res.end();
69
127
  }
70
- }
71
- else {
72
- res.writeHead(404);
73
- res.end();
74
- }
75
- });
76
- server.listen(port, "127.0.0.1", () => {
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 credentials = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
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
- Authorization: `Basic ${credentials}`,
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
- const { createServer } = await import("node:http");
175
- const { randomBytes } = await import("node:crypto");
176
- let chromium;
177
- try {
178
- const modName = "playwright";
179
- const pw = await import(/* webpackIgnore: true */ modName);
180
- chromium = pw.chromium;
181
- }
182
- catch {
183
- throw new Error("Playwright is not installed. Run:\n npm install playwright && npx playwright install chromium");
184
- }
185
- const base = normalizeBaseUrl(baseUrl);
186
- const port = options?.port ?? DEFAULT_REDIRECT_PORT;
187
- const scope = options?.scope ?? DEFAULT_SCOPE;
188
- const redirectUri = `http://127.0.0.1:${port}/callback`;
189
- const hasCredentials = !!(options?.username && options?.password);
190
- // Step 1: Ensure registered OAuth2 client
191
- let client = loadClientConfig(base);
192
- if (!client?.clientId) {
193
- client = await registerOAuth2Client(base, redirectUri, scope);
194
- saveClientConfig(base, client);
195
- }
196
- // Step 2: Generate CSRF state
197
- const state = randomBytes(12).toString("hex");
198
- // Step 3: Build authorization URL
199
- const authParams = new URLSearchParams({
200
- redirect_uri: redirectUri,
201
- "x-forwarded-prefix": "",
202
- client_id: client.clientId,
203
- scope,
204
- response_type: "code",
205
- state,
206
- lang: "zh-cn",
207
- product: "adp",
208
- });
209
- const authUrl = `${base}/oauth2/auth?${authParams.toString()}`;
210
- // Step 4: Start local callback server to capture the authorization code
211
- const code = await new Promise((resolve, reject) => {
212
- const TIMEOUT_MS = hasCredentials ? 30_000 : 120_000;
213
- const timeoutId = setTimeout(() => {
214
- server.close();
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
- if (receivedState !== state) {
229
- reject(new Error("OAuth2 state mismatch — possible CSRF attack."));
230
- }
231
- else if (!receivedCode) {
232
- reject(new Error("No authorization code received in callback."));
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
- resolve(receivedCode);
307
+ res.writeHead(404);
308
+ res.end();
236
309
  }
237
- }
238
- else {
239
- res.writeHead(404);
240
- res.end();
241
- }
242
- });
243
- let browser;
244
- server.listen(port, "127.0.0.1", async () => {
245
- try {
246
- browser = await chromium.launch({ headless: hasCredentials });
247
- const context = await browser.newContext();
248
- const page = await context.newPage();
249
- // Navigate to OAuth2 auth URL — redirects to signin page
250
- await page.goto(authUrl, { waitUntil: "networkidle", timeout: 30_000 });
251
- if (hasCredentials) {
252
- // Auto-fill credentials
253
- await page.waitForSelector('input[name="account"]', { timeout: 10_000 });
254
- await page.fill('input[name="account"]', options.username);
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
- // else: visible browser — user logs in manually
259
- // The OAuth2 callback will fire when login completes, resolving the promise above
260
- }
261
- catch (err) {
262
- clearTimeout(timeoutId);
263
- server.close();
264
- browser?.close();
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({