@kweaver-ai/kweaver-sdk 0.4.4 → 0.4.5
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/dist/api/agent-chat.js +4 -2
- package/dist/api/context-loader.js +6 -2
- package/dist/api/conversations.js +2 -2
- package/dist/api/datasources.js +2 -1
- package/dist/auth/oauth.d.ts +13 -0
- package/dist/auth/oauth.js +142 -12
- package/dist/commands/agent.js +9 -18
- package/dist/commands/bkn.js +9 -20
- package/dist/commands/call.js +2 -12
- package/dist/commands/context-loader.js +9 -18
- package/dist/commands/ds.js +9 -18
- package/dist/commands/vega.js +9 -18
- package/dist/config/store.d.ts +14 -0
- package/dist/config/store.js +13 -0
- package/package.json +1 -1
package/dist/api/agent-chat.js
CHANGED
|
@@ -254,7 +254,8 @@ export async function sendChatRequest(options) {
|
|
|
254
254
|
};
|
|
255
255
|
if (verbose) {
|
|
256
256
|
console.error(`POST ${url}`);
|
|
257
|
-
|
|
257
|
+
const safeHeaders = Object.fromEntries(Object.entries(headers).map(([k, v]) => k.toLowerCase() === "authorization" ? [k, "Bearer ***"] : [k, v]));
|
|
258
|
+
console.error(`Headers: ${JSON.stringify(safeHeaders)}`);
|
|
258
259
|
console.error(`Body: ${JSON.stringify(body)}`);
|
|
259
260
|
}
|
|
260
261
|
let response;
|
|
@@ -312,7 +313,8 @@ export async function sendChatRequestStream(options, callbacks) {
|
|
|
312
313
|
};
|
|
313
314
|
if (verbose) {
|
|
314
315
|
console.error(`POST ${url}`);
|
|
315
|
-
|
|
316
|
+
const safeHeaders = Object.fromEntries(Object.entries(headers).map(([k, v]) => k.toLowerCase() === "authorization" ? [k, "Bearer ***"] : [k, v]));
|
|
317
|
+
console.error(`Headers: ${JSON.stringify(safeHeaders)}`);
|
|
316
318
|
console.error(`Body: ${JSON.stringify(body)}`);
|
|
317
319
|
}
|
|
318
320
|
let response;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { fetchTextOrThrow } from "../utils/http.js";
|
|
2
2
|
const MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
3
|
+
const SESSION_TTL_MS = 300_000; // 5 minutes
|
|
3
4
|
const sessionCache = new Map();
|
|
4
5
|
function sessionKey(options) {
|
|
5
6
|
return `${options.mcpUrl}:${options.knId}`;
|
|
@@ -20,8 +21,11 @@ function buildHeaders(options, sessionId) {
|
|
|
20
21
|
async function ensureSession(options) {
|
|
21
22
|
const key = sessionKey(options);
|
|
22
23
|
const cached = sessionCache.get(key);
|
|
24
|
+
if (cached && Date.now() - cached.createdAt < SESSION_TTL_MS)
|
|
25
|
+
return cached.id;
|
|
26
|
+
// Remove stale entry if expired
|
|
23
27
|
if (cached)
|
|
24
|
-
|
|
28
|
+
sessionCache.delete(key);
|
|
25
29
|
const initBody = JSON.stringify({
|
|
26
30
|
jsonrpc: "2.0",
|
|
27
31
|
id: 1,
|
|
@@ -50,7 +54,7 @@ async function ensureSession(options) {
|
|
|
50
54
|
headers: buildHeaders(options, sessionId),
|
|
51
55
|
body: initNotifBody,
|
|
52
56
|
});
|
|
53
|
-
sessionCache.set(key, sessionId);
|
|
57
|
+
sessionCache.set(key, { id: sessionId, createdAt: Date.now() });
|
|
54
58
|
return sessionId;
|
|
55
59
|
}
|
|
56
60
|
function isMissingInputParams(obj) {
|
|
@@ -30,7 +30,7 @@ export async function listConversations(opts) {
|
|
|
30
30
|
}
|
|
31
31
|
const body = await response.text();
|
|
32
32
|
if (!response.ok) {
|
|
33
|
-
|
|
33
|
+
throw new Error(`listConversations failed: HTTP ${response.status} ${response.statusText} — ${body.slice(0, 200)}`);
|
|
34
34
|
}
|
|
35
35
|
return body || "[]";
|
|
36
36
|
}
|
|
@@ -58,7 +58,7 @@ export async function listMessages(opts) {
|
|
|
58
58
|
}
|
|
59
59
|
const body = await response.text();
|
|
60
60
|
if (!response.ok) {
|
|
61
|
-
|
|
61
|
+
throw new Error(`listMessages failed: HTTP ${response.status} ${response.statusText} — ${body.slice(0, 200)}`);
|
|
62
62
|
}
|
|
63
63
|
return body || "[]";
|
|
64
64
|
}
|
package/dist/api/datasources.js
CHANGED
|
@@ -204,7 +204,8 @@ export async function scanMetadata(options) {
|
|
|
204
204
|
const scanResult = await scanResponse.json();
|
|
205
205
|
const taskId = scanResult.id ?? "";
|
|
206
206
|
for (let i = 0; i < 30; i += 1) {
|
|
207
|
-
|
|
207
|
+
const delay = Math.min(2000 * Math.pow(1.5, i), 15000);
|
|
208
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
208
209
|
const statusResponse = await fetch(statusUrl(taskId), {
|
|
209
210
|
method: "GET",
|
|
210
211
|
headers: buildHeaders(accessToken, businessDomain),
|
package/dist/auth/oauth.d.ts
CHANGED
|
@@ -4,8 +4,21 @@ export declare function playwrightLogin(baseUrl: string, options?: {
|
|
|
4
4
|
username?: string;
|
|
5
5
|
password?: string;
|
|
6
6
|
}): Promise<TokenConfig>;
|
|
7
|
+
/**
|
|
8
|
+
* Exchange refresh_token for a new access token (OAuth2 password grant style, same as Python ConfigAuth).
|
|
9
|
+
* Persists the new token to ~/.kweaver/ and returns it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function refreshAccessToken(token: TokenConfig): Promise<TokenConfig>;
|
|
7
12
|
export declare function ensureValidToken(opts?: {
|
|
8
13
|
forceRefresh?: boolean;
|
|
9
14
|
}): Promise<TokenConfig>;
|
|
15
|
+
/**
|
|
16
|
+
* Run an operation; on HTTP 401, refresh the access token once and retry.
|
|
17
|
+
* Does not call `ensureValidToken` first — use for CLI routers so `--help` works without login.
|
|
18
|
+
*/
|
|
19
|
+
export declare function with401RefreshRetry<T>(fn: () => Promise<T>): Promise<T>;
|
|
20
|
+
/**
|
|
21
|
+
* Load a valid token, run `fn(token)`, and on 401 refresh once and retry with the new token.
|
|
22
|
+
*/
|
|
10
23
|
export declare function withTokenRetry<T>(fn: (token: TokenConfig) => Promise<T>): Promise<T>;
|
|
11
24
|
export declare function formatHttpError(error: unknown): string;
|
package/dist/auth/oauth.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { getCurrentPlatform, loadTokenConfig, saveTokenConfig, setCurrentPlatform, } from "../config/store.js";
|
|
1
|
+
import { getCurrentPlatform, loadClientConfig, loadTokenConfig, saveTokenConfig, setCurrentPlatform, } from "../config/store.js";
|
|
2
2
|
import { HttpError, NetworkRequestError } from "../utils/http.js";
|
|
3
3
|
const TOKEN_TTL_SECONDS = 3600;
|
|
4
|
+
/** Seconds before access token expiry to trigger refresh (matches Python ConfigAuth). */
|
|
5
|
+
const REFRESH_THRESHOLD_SEC = 60;
|
|
4
6
|
export function normalizeBaseUrl(value) {
|
|
5
7
|
return value.replace(/\/+$/, "");
|
|
6
8
|
}
|
|
@@ -80,6 +82,85 @@ export async function playwrightLogin(baseUrl, options) {
|
|
|
80
82
|
await browser.close();
|
|
81
83
|
}
|
|
82
84
|
}
|
|
85
|
+
function tokenNeedsRefresh(token) {
|
|
86
|
+
if (!token.expiresAt) {
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const expiresAtMs = Date.parse(token.expiresAt);
|
|
90
|
+
if (Number.isNaN(expiresAtMs)) {
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
const thresholdMs = REFRESH_THRESHOLD_SEC * 1000;
|
|
94
|
+
return expiresAtMs - thresholdMs <= Date.now();
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Exchange refresh_token for a new access token (OAuth2 password grant style, same as Python ConfigAuth).
|
|
98
|
+
* Persists the new token to ~/.kweaver/ and returns it.
|
|
99
|
+
*/
|
|
100
|
+
export async function refreshAccessToken(token) {
|
|
101
|
+
const baseUrl = normalizeBaseUrl(token.baseUrl);
|
|
102
|
+
const refreshToken = token.refreshToken?.trim();
|
|
103
|
+
if (!refreshToken) {
|
|
104
|
+
throw new Error(`Token expired and no refresh_token available for ${baseUrl}. Run \`kweaver auth login ${baseUrl}\` again.`);
|
|
105
|
+
}
|
|
106
|
+
const client = loadClientConfig(baseUrl);
|
|
107
|
+
const clientId = client?.clientId?.trim() ?? "";
|
|
108
|
+
const clientSecret = client?.clientSecret?.trim() ?? "";
|
|
109
|
+
if (!clientId || !clientSecret) {
|
|
110
|
+
throw new Error(`Token refresh requires OAuth client credentials (client.json). Run \`kweaver auth login ${baseUrl}\` again.`);
|
|
111
|
+
}
|
|
112
|
+
const credentials = Buffer.from(`${clientId}:${clientSecret}`).toString("base64");
|
|
113
|
+
const url = `${baseUrl}/oauth2/token`;
|
|
114
|
+
const body = new URLSearchParams({
|
|
115
|
+
grant_type: "refresh_token",
|
|
116
|
+
refresh_token: refreshToken,
|
|
117
|
+
});
|
|
118
|
+
let response;
|
|
119
|
+
try {
|
|
120
|
+
response = await fetch(url, {
|
|
121
|
+
method: "POST",
|
|
122
|
+
headers: {
|
|
123
|
+
Authorization: `Basic ${credentials}`,
|
|
124
|
+
"Content-Type": "application/x-www-form-urlencoded",
|
|
125
|
+
Accept: "application/json",
|
|
126
|
+
},
|
|
127
|
+
body: body.toString(),
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (cause) {
|
|
131
|
+
const hint = cause instanceof Error ? cause.message : String(cause);
|
|
132
|
+
throw new NetworkRequestError("POST", url, hint, "Check network connectivity and that the platform exposes /oauth2/token.");
|
|
133
|
+
}
|
|
134
|
+
const text = await response.text();
|
|
135
|
+
if (!response.ok) {
|
|
136
|
+
throw new HttpError(response.status, response.statusText, text);
|
|
137
|
+
}
|
|
138
|
+
let data;
|
|
139
|
+
try {
|
|
140
|
+
data = JSON.parse(text);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
throw new Error(`Invalid JSON from ${url} during token refresh.`);
|
|
144
|
+
}
|
|
145
|
+
if (typeof data.access_token !== "string") {
|
|
146
|
+
throw new Error(`Token refresh response missing access_token from ${url}.`);
|
|
147
|
+
}
|
|
148
|
+
const now = new Date();
|
|
149
|
+
const expiresIn = typeof data.expires_in === "number" ? data.expires_in : 3600;
|
|
150
|
+
const newToken = {
|
|
151
|
+
baseUrl,
|
|
152
|
+
accessToken: data.access_token,
|
|
153
|
+
tokenType: data.token_type ?? "Bearer",
|
|
154
|
+
scope: data.scope ?? token.scope ?? "",
|
|
155
|
+
expiresIn,
|
|
156
|
+
expiresAt: new Date(now.getTime() + expiresIn * 1000).toISOString(),
|
|
157
|
+
refreshToken: data.refresh_token ?? refreshToken,
|
|
158
|
+
idToken: data.id_token ?? token.idToken ?? "",
|
|
159
|
+
obtainedAt: now.toISOString(),
|
|
160
|
+
};
|
|
161
|
+
saveTokenConfig(newToken);
|
|
162
|
+
return newToken;
|
|
163
|
+
}
|
|
83
164
|
export async function ensureValidToken(opts) {
|
|
84
165
|
const envToken = process.env.KWEAVER_TOKEN;
|
|
85
166
|
const envBaseUrl = process.env.KWEAVER_BASE_URL;
|
|
@@ -97,21 +178,61 @@ export async function ensureValidToken(opts) {
|
|
|
97
178
|
if (!currentPlatform) {
|
|
98
179
|
throw new Error("No active platform selected. Run `kweaver auth login <platform-url>` first.");
|
|
99
180
|
}
|
|
100
|
-
|
|
101
|
-
throw new Error(`Token refresh is not supported. Run \`kweaver auth login ${currentPlatform}\` again.`);
|
|
102
|
-
}
|
|
103
|
-
const token = loadTokenConfig(currentPlatform);
|
|
181
|
+
let token = loadTokenConfig(currentPlatform);
|
|
104
182
|
if (!token) {
|
|
105
183
|
throw new Error(`No saved token for ${currentPlatform}. Run \`kweaver auth login ${currentPlatform}\` first.`);
|
|
106
184
|
}
|
|
107
|
-
if (
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
185
|
+
if (opts?.forceRefresh) {
|
|
186
|
+
return refreshAccessToken(token);
|
|
187
|
+
}
|
|
188
|
+
if (tokenNeedsRefresh(token)) {
|
|
189
|
+
try {
|
|
190
|
+
return await refreshAccessToken(token);
|
|
191
|
+
}
|
|
192
|
+
catch (err) {
|
|
193
|
+
throw new Error(`Access token expired or near expiry and refresh failed for ${currentPlatform}.\n` +
|
|
194
|
+
(err instanceof Error ? `${err.message}\n` : "") +
|
|
195
|
+
`Run \`kweaver auth login ${currentPlatform}\` again.`, { cause: err });
|
|
111
196
|
}
|
|
112
197
|
}
|
|
113
198
|
return token;
|
|
114
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Run an operation; on HTTP 401, refresh the access token once and retry.
|
|
202
|
+
* Does not call `ensureValidToken` first — use for CLI routers so `--help` works without login.
|
|
203
|
+
*/
|
|
204
|
+
export async function with401RefreshRetry(fn) {
|
|
205
|
+
try {
|
|
206
|
+
return await fn();
|
|
207
|
+
}
|
|
208
|
+
catch (error) {
|
|
209
|
+
if (error instanceof HttpError && error.status === 401) {
|
|
210
|
+
const currentPlatform = getCurrentPlatform();
|
|
211
|
+
if (!currentPlatform) {
|
|
212
|
+
throw error;
|
|
213
|
+
}
|
|
214
|
+
const platformUrl = normalizeBaseUrl(currentPlatform);
|
|
215
|
+
const latest = loadTokenConfig(platformUrl);
|
|
216
|
+
if (!latest) {
|
|
217
|
+
throw error;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
220
|
+
await refreshAccessToken(latest);
|
|
221
|
+
}
|
|
222
|
+
catch (retryErr) {
|
|
223
|
+
const oauthHint = formatOAuthErrorBody(retryErr instanceof HttpError ? retryErr.body : "");
|
|
224
|
+
const extra = oauthHint ? `\n\n${oauthHint}` : "";
|
|
225
|
+
throw new Error(`Authentication failed (401). Token refresh did not succeed for ${platformUrl}.${extra}\n` +
|
|
226
|
+
`Run \`kweaver auth login ${platformUrl}\` again.`, { cause: retryErr });
|
|
227
|
+
}
|
|
228
|
+
return await fn();
|
|
229
|
+
}
|
|
230
|
+
throw error;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Load a valid token, run `fn(token)`, and on 401 refresh once and retry with the new token.
|
|
235
|
+
*/
|
|
115
236
|
export async function withTokenRetry(fn) {
|
|
116
237
|
const token = await ensureValidToken();
|
|
117
238
|
try {
|
|
@@ -119,9 +240,18 @@ export async function withTokenRetry(fn) {
|
|
|
119
240
|
}
|
|
120
241
|
catch (error) {
|
|
121
242
|
if (error instanceof HttpError && error.status === 401) {
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
243
|
+
const platformUrl = normalizeBaseUrl(token.baseUrl);
|
|
244
|
+
const latest = loadTokenConfig(platformUrl) ?? token;
|
|
245
|
+
try {
|
|
246
|
+
const refreshed = await refreshAccessToken(latest);
|
|
247
|
+
return await fn(refreshed);
|
|
248
|
+
}
|
|
249
|
+
catch (retryErr) {
|
|
250
|
+
const oauthHint = formatOAuthErrorBody(retryErr instanceof HttpError ? retryErr.body : "");
|
|
251
|
+
const extra = oauthHint ? `\n\n${oauthHint}` : "";
|
|
252
|
+
throw new Error(`Authentication failed (401). Token refresh did not succeed for ${platformUrl}.${extra}\n` +
|
|
253
|
+
`Run \`kweaver auth login ${platformUrl}\` again.`, { cause: retryErr });
|
|
254
|
+
}
|
|
125
255
|
}
|
|
126
256
|
throw error;
|
|
127
257
|
}
|
package/dist/commands/agent.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
2
|
-
import { HttpError } from "../utils/http.js";
|
|
1
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
3
2
|
import { runAgentChatCommand } from "./agent-chat.js";
|
|
4
3
|
import { listAgents, getAgent, getAgentByKey, createAgent, updateAgent, deleteAgent, publishAgent, unpublishAgent, } from "../api/agent-list.js";
|
|
5
4
|
import { listConversations, listMessages } from "../api/conversations.js";
|
|
@@ -347,24 +346,16 @@ Options:
|
|
|
347
346
|
}
|
|
348
347
|
}
|
|
349
348
|
try {
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
}
|
|
355
|
-
return code;
|
|
356
|
-
}
|
|
357
|
-
catch (error) {
|
|
358
|
-
if (error instanceof HttpError && error.status === 401) {
|
|
359
|
-
try {
|
|
360
|
-
await ensureValidToken({ forceRefresh: true });
|
|
361
|
-
return await dispatch();
|
|
362
|
-
}
|
|
363
|
-
catch (retryError) {
|
|
364
|
-
console.error(formatHttpError(retryError));
|
|
349
|
+
return await with401RefreshRetry(async () => {
|
|
350
|
+
const code = await dispatch();
|
|
351
|
+
if (code === -1) {
|
|
352
|
+
console.error(`Unknown agent subcommand: ${subcommand}`);
|
|
365
353
|
return 1;
|
|
366
354
|
}
|
|
367
|
-
|
|
355
|
+
return code;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
catch (error) {
|
|
368
359
|
console.error(formatHttpError(error));
|
|
369
360
|
return 1;
|
|
370
361
|
}
|
package/dist/commands/bkn.js
CHANGED
|
@@ -3,8 +3,7 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import { mkdirSync, readFileSync, readdirSync, statSync } from "node:fs";
|
|
4
4
|
import { resolve } from "node:path";
|
|
5
5
|
import { loadNetwork, allObjects, allRelations, allActions, generateChecksum, validateNetwork } from "@kweaver-ai/bkn";
|
|
6
|
-
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
7
|
-
import { HttpError } from "../utils/http.js";
|
|
6
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
8
7
|
import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, getObjectType, createObjectTypes, updateObjectType, deleteObjectTypes, getRelationType, createRelationTypes, updateRelationType, deleteRelationTypes, buildKnowledgeNetwork, getBuildStatus, } from "../api/knowledge-networks.js";
|
|
9
8
|
import { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actionTypeExecute, actionExecutionGet, actionLogsList, actionLogGet, actionLogCancel, } from "../api/ontology-query.js";
|
|
10
9
|
import { semanticSearch } from "../api/semantic-search.js";
|
|
@@ -627,26 +626,16 @@ export async function runKnCommand(args) {
|
|
|
627
626
|
return Promise.resolve(-1);
|
|
628
627
|
};
|
|
629
628
|
try {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
}
|
|
635
|
-
return code;
|
|
636
|
-
}
|
|
637
|
-
catch (error) {
|
|
638
|
-
// Auto-retry on 401: force-refresh the token and re-run the subcommand.
|
|
639
|
-
// The subcommand will call ensureValidToken() again and pick up the fresh token.
|
|
640
|
-
if (error instanceof HttpError && error.status === 401) {
|
|
641
|
-
try {
|
|
642
|
-
await ensureValidToken({ forceRefresh: true });
|
|
643
|
-
return await dispatch();
|
|
644
|
-
}
|
|
645
|
-
catch (retryError) {
|
|
646
|
-
console.error(formatHttpError(retryError));
|
|
629
|
+
return await with401RefreshRetry(async () => {
|
|
630
|
+
const code = await dispatch();
|
|
631
|
+
if (code === -1) {
|
|
632
|
+
console.error(`Unknown bkn subcommand: ${subcommand}`);
|
|
647
633
|
return 1;
|
|
648
634
|
}
|
|
649
|
-
|
|
635
|
+
return code;
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
catch (error) {
|
|
650
639
|
console.error(formatHttpError(error));
|
|
651
640
|
return 1;
|
|
652
641
|
}
|
package/dist/commands/call.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
1
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
2
2
|
import { HttpError } from "../utils/http.js";
|
|
3
3
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
4
4
|
export function parseCallArgs(args) {
|
|
@@ -168,19 +168,9 @@ Options:
|
|
|
168
168
|
return 0;
|
|
169
169
|
};
|
|
170
170
|
try {
|
|
171
|
-
return await execute();
|
|
171
|
+
return await with401RefreshRetry(async () => execute());
|
|
172
172
|
}
|
|
173
173
|
catch (error) {
|
|
174
|
-
if (error instanceof HttpError && error.status === 401) {
|
|
175
|
-
try {
|
|
176
|
-
await ensureValidToken({ forceRefresh: true });
|
|
177
|
-
return await execute();
|
|
178
|
-
}
|
|
179
|
-
catch (retryError) {
|
|
180
|
-
console.error(formatHttpError(retryError));
|
|
181
|
-
return 1;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
174
|
console.error(formatHttpError(error));
|
|
185
175
|
return 1;
|
|
186
176
|
}
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
2
|
-
import { HttpError } from "../utils/http.js";
|
|
1
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
3
2
|
import { knSearch, knSchemaSearch, queryObjectInstance, queryInstanceSubgraph, getLogicPropertiesValues, getActionInfo, listTools, listResources, readResource, listResourceTemplates, listPrompts, getPrompt, } from "../api/context-loader.js";
|
|
4
3
|
import { addContextLoaderEntry, getCurrentContextLoaderKn, getCurrentPlatform, loadContextLoaderConfig, removeContextLoaderEntry, setCurrentContextLoader, } from "../config/store.js";
|
|
5
4
|
const MCP_NOT_CONFIGURED = "Context-loader MCP is not configured. Run: kweaver context-loader config set --kn-id <kn-id>";
|
|
@@ -92,24 +91,16 @@ Examples:
|
|
|
92
91
|
return -1;
|
|
93
92
|
};
|
|
94
93
|
try {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
return code;
|
|
101
|
-
}
|
|
102
|
-
catch (error) {
|
|
103
|
-
if (error instanceof HttpError && error.status === 401) {
|
|
104
|
-
try {
|
|
105
|
-
await ensureValidToken({ forceRefresh: true });
|
|
106
|
-
return await dispatch();
|
|
107
|
-
}
|
|
108
|
-
catch (retryError) {
|
|
109
|
-
console.error(formatHttpError(retryError));
|
|
94
|
+
return await with401RefreshRetry(async () => {
|
|
95
|
+
const code = await dispatch();
|
|
96
|
+
if (code === -1) {
|
|
97
|
+
console.error(`Unknown context-loader subcommand: ${subcommand}`);
|
|
110
98
|
return 1;
|
|
111
99
|
}
|
|
112
|
-
|
|
100
|
+
return code;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
113
104
|
console.error(formatHttpError(error));
|
|
114
105
|
return 1;
|
|
115
106
|
}
|
package/dist/commands/ds.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { createInterface } from "node:readline";
|
|
2
|
-
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
3
|
-
import { HttpError } from "../utils/http.js";
|
|
2
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
4
3
|
import { testDatasource, createDatasource, listDatasources, getDatasource, deleteDatasource, listTablesWithColumns, } from "../api/datasources.js";
|
|
5
4
|
import { formatCallOutput } from "./call.js";
|
|
6
5
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
@@ -50,24 +49,16 @@ Subcommands:
|
|
|
50
49
|
return Promise.resolve(-1);
|
|
51
50
|
};
|
|
52
51
|
try {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
return code;
|
|
59
|
-
}
|
|
60
|
-
catch (error) {
|
|
61
|
-
if (error instanceof HttpError && error.status === 401) {
|
|
62
|
-
try {
|
|
63
|
-
await ensureValidToken({ forceRefresh: true });
|
|
64
|
-
return await dispatch();
|
|
65
|
-
}
|
|
66
|
-
catch (retryError) {
|
|
67
|
-
console.error(formatHttpError(retryError));
|
|
52
|
+
return await with401RefreshRetry(async () => {
|
|
53
|
+
const code = await dispatch();
|
|
54
|
+
if (code === -1) {
|
|
55
|
+
console.error(`Unknown ds subcommand: ${subcommand}`);
|
|
68
56
|
return 1;
|
|
69
57
|
}
|
|
70
|
-
|
|
58
|
+
return code;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
catch (error) {
|
|
71
62
|
console.error(formatHttpError(error));
|
|
72
63
|
return 1;
|
|
73
64
|
}
|
package/dist/commands/vega.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { ensureValidToken, formatHttpError } from "../auth/oauth.js";
|
|
2
|
-
import { HttpError } from "../utils/http.js";
|
|
1
|
+
import { ensureValidToken, formatHttpError, with401RefreshRetry } from "../auth/oauth.js";
|
|
3
2
|
import { vegaHealth, listVegaCatalogs, getVegaCatalog, vegaCatalogHealthStatus, testVegaCatalogConnection, discoverVegaCatalog, listVegaCatalogResources, listVegaResources, getVegaResource, queryVegaResourceData, previewVegaResource, listVegaConnectorTypes, getVegaConnectorType, listVegaDiscoverTasks, } from "../api/vega.js";
|
|
4
3
|
import { formatCallOutput } from "./call.js";
|
|
5
4
|
import { resolveBusinessDomain } from "../config/store.js";
|
|
@@ -78,24 +77,16 @@ export async function runVegaCommand(args) {
|
|
|
78
77
|
return Promise.resolve(-1);
|
|
79
78
|
};
|
|
80
79
|
try {
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
86
|
-
return code;
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
if (error instanceof HttpError && error.status === 401) {
|
|
90
|
-
try {
|
|
91
|
-
await ensureValidToken({ forceRefresh: true });
|
|
92
|
-
return await dispatch();
|
|
93
|
-
}
|
|
94
|
-
catch (retryError) {
|
|
95
|
-
console.error(formatHttpError(retryError));
|
|
80
|
+
return await with401RefreshRetry(async () => {
|
|
81
|
+
const code = await dispatch();
|
|
82
|
+
if (code === -1) {
|
|
83
|
+
console.error(`Unknown vega subcommand: ${subcommand}`);
|
|
96
84
|
return 1;
|
|
97
85
|
}
|
|
98
|
-
|
|
86
|
+
return code;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
99
90
|
console.error(formatHttpError(error));
|
|
100
91
|
return 1;
|
|
101
92
|
}
|
package/dist/config/store.d.ts
CHANGED
|
@@ -9,6 +9,18 @@ export interface TokenConfig {
|
|
|
9
9
|
idToken?: string;
|
|
10
10
|
obtainedAt: string;
|
|
11
11
|
}
|
|
12
|
+
/** OAuth2 client registration (per platform), used for refresh_token grant. */
|
|
13
|
+
export interface ClientConfig {
|
|
14
|
+
baseUrl: string;
|
|
15
|
+
clientId: string;
|
|
16
|
+
clientSecret: string;
|
|
17
|
+
redirectUri?: string;
|
|
18
|
+
logoutRedirectUri?: string;
|
|
19
|
+
scope?: string;
|
|
20
|
+
lang?: string;
|
|
21
|
+
product?: string;
|
|
22
|
+
xForwardedPrefix?: string;
|
|
23
|
+
}
|
|
12
24
|
/** Single context-loader entry (named kn_id). */
|
|
13
25
|
export interface ContextLoaderEntry {
|
|
14
26
|
name: string;
|
|
@@ -34,6 +46,8 @@ export declare function getPlatformAlias(baseUrl: string): string | null;
|
|
|
34
46
|
export declare function resolvePlatformIdentifier(value: string): string | null;
|
|
35
47
|
export declare function loadTokenConfig(baseUrl?: string): TokenConfig | null;
|
|
36
48
|
export declare function saveTokenConfig(config: TokenConfig): void;
|
|
49
|
+
export declare function loadClientConfig(baseUrl?: string): ClientConfig | null;
|
|
50
|
+
export declare function saveClientConfig(baseUrl: string, config: ClientConfig): void;
|
|
37
51
|
export declare function loadContextLoaderConfig(baseUrl?: string): ContextLoaderConfig | null;
|
|
38
52
|
export declare function saveContextLoaderConfig(baseUrl: string, config: ContextLoaderConfig): void;
|
|
39
53
|
export interface CurrentContextLoaderKn {
|
package/dist/config/store.js
CHANGED
|
@@ -188,6 +188,19 @@ export function saveTokenConfig(config) {
|
|
|
188
188
|
ensurePlatformDir(config.baseUrl);
|
|
189
189
|
writeJsonFile(getPlatformFile(config.baseUrl, "token.json"), config);
|
|
190
190
|
}
|
|
191
|
+
export function loadClientConfig(baseUrl) {
|
|
192
|
+
ensureStoreReady();
|
|
193
|
+
const targetBaseUrl = baseUrl ?? getCurrentPlatform();
|
|
194
|
+
if (!targetBaseUrl) {
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
return readJsonFile(getPlatformFile(targetBaseUrl, "client.json"));
|
|
198
|
+
}
|
|
199
|
+
export function saveClientConfig(baseUrl, config) {
|
|
200
|
+
ensureStoreReady();
|
|
201
|
+
ensurePlatformDir(baseUrl);
|
|
202
|
+
writeJsonFile(getPlatformFile(baseUrl, "client.json"), { ...config, baseUrl });
|
|
203
|
+
}
|
|
191
204
|
function migrateLegacyContextLoader(raw) {
|
|
192
205
|
const leg = raw;
|
|
193
206
|
if (leg?.knId && !Array.isArray(raw.configs)) {
|
package/package.json
CHANGED