@openbkn/bkn-sdk 0.1.1-alpha.8 → 0.1.1
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/LICENSE +1 -0
- package/NOTICE +21 -0
- package/README.md +31 -25
- package/README.zh.md +10 -12
- package/dist/{chunk-DTU5DGJW.js → chunk-NC6DZ2AU.js} +648 -194
- package/dist/cli.js +504 -179
- package/dist/index.d.ts +383 -64
- package/dist/index.js +1 -1
- package/package.json +5 -4
- package/dist/chunk-DTU5DGJW.js.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/index.js.map +0 -1
|
@@ -9,12 +9,15 @@ var HttpError = class extends Error {
|
|
|
9
9
|
status;
|
|
10
10
|
statusText;
|
|
11
11
|
body;
|
|
12
|
-
|
|
12
|
+
/** Optional next-step guidance, overriding the status default (e.g. AppKey re-issue). */
|
|
13
|
+
hint;
|
|
14
|
+
constructor(status2, statusText, body, hint) {
|
|
13
15
|
super(`HTTP ${status2} ${statusText}`);
|
|
14
16
|
this.name = "HttpError";
|
|
15
17
|
this.status = status2;
|
|
16
18
|
this.statusText = statusText;
|
|
17
19
|
this.body = body;
|
|
20
|
+
this.hint = hint;
|
|
18
21
|
}
|
|
19
22
|
};
|
|
20
23
|
var InputError = class extends Error {
|
|
@@ -35,7 +38,8 @@ function formatError(err) {
|
|
|
35
38
|
if (err instanceof HttpError) {
|
|
36
39
|
const serverMsg = serverError(err.body);
|
|
37
40
|
if (err.status === 401) {
|
|
38
|
-
|
|
41
|
+
const next = err.hint ?? "Run `openbkn auth login` and retry.";
|
|
42
|
+
return `Not authorized (HTTP 401)${serverMsg ? `: ${serverMsg}` : ""}. ${next}`;
|
|
39
43
|
}
|
|
40
44
|
if (err.status === 403) {
|
|
41
45
|
return `Forbidden (HTTP 403)${serverMsg ? `: ${serverMsg}` : " \u2014 admin privileges required"}.`;
|
|
@@ -74,6 +78,23 @@ function truncate(s, n) {
|
|
|
74
78
|
|
|
75
79
|
// src/auth/oauth.ts
|
|
76
80
|
import { spawn } from "child_process";
|
|
81
|
+
|
|
82
|
+
// src/api/tls.ts
|
|
83
|
+
import { Agent, fetch as undiciFetch } from "undici";
|
|
84
|
+
var insecureAgent;
|
|
85
|
+
function insecureDispatcher() {
|
|
86
|
+
insecureAgent ??= new Agent({ connect: { rejectUnauthorized: false } });
|
|
87
|
+
return insecureAgent;
|
|
88
|
+
}
|
|
89
|
+
function tlsFetch(insecure, url, init) {
|
|
90
|
+
if (!insecure) return fetch(url, init);
|
|
91
|
+
return undiciFetch(url, {
|
|
92
|
+
...init,
|
|
93
|
+
dispatcher: insecureDispatcher()
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/auth/oauth.ts
|
|
77
98
|
function normalizeBaseUrl(value) {
|
|
78
99
|
return value.replace(/\/+$/, "");
|
|
79
100
|
}
|
|
@@ -114,22 +135,9 @@ function mergeCookies(existing, res) {
|
|
|
114
135
|
for (const sc of setCookies) add(sc.split(";")[0]?.trim() ?? "");
|
|
115
136
|
return [...map.entries()].map(([k, v]) => `${k}=${v}`).join("; ");
|
|
116
137
|
}
|
|
117
|
-
async function
|
|
118
|
-
try {
|
|
119
|
-
const res = await fetch(`${normalizeBaseUrl(baseUrl)}/install-status.json`, {
|
|
120
|
-
headers: { Accept: "application/json" }
|
|
121
|
-
});
|
|
122
|
-
if (!res.ok) return null;
|
|
123
|
-
const j = await res.json();
|
|
124
|
-
if (!j.auth) return null;
|
|
125
|
-
return { enabled: Boolean(j.auth.enabled), stack: j.auth.stack };
|
|
126
|
-
} catch {
|
|
127
|
-
return null;
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
async function refreshAccessToken(baseUrl, refreshToken, clientId = "openbkn-sdk") {
|
|
138
|
+
async function refreshAccessToken(baseUrl, refreshToken, clientId = "openbkn-sdk", insecure) {
|
|
131
139
|
const base = normalizeBaseUrl(baseUrl);
|
|
132
|
-
const res = await
|
|
140
|
+
const res = await tlsFetch(insecure, `${base}/oauth2/token`, {
|
|
133
141
|
method: "POST",
|
|
134
142
|
headers: {
|
|
135
143
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
@@ -159,10 +167,10 @@ var form = (body) => ({
|
|
|
159
167
|
},
|
|
160
168
|
body: new URLSearchParams(body).toString()
|
|
161
169
|
});
|
|
162
|
-
async function requestDeviceCode(base, clientId, scope, audience) {
|
|
170
|
+
async function requestDeviceCode(base, clientId, scope, audience, insecure) {
|
|
163
171
|
const params = { client_id: clientId, scope };
|
|
164
172
|
if (audience) params.audience = audience;
|
|
165
|
-
const res = await
|
|
173
|
+
const res = await tlsFetch(insecure, `${base}/oauth2/device/auth`, form(params));
|
|
166
174
|
if (!res.ok) {
|
|
167
175
|
throw new Error(`Device auth failed (${res.status}): ${await res.text() || res.statusText}`);
|
|
168
176
|
}
|
|
@@ -174,12 +182,13 @@ async function requestDeviceCode(base, clientId, scope, audience) {
|
|
|
174
182
|
}
|
|
175
183
|
return da;
|
|
176
184
|
}
|
|
177
|
-
async function pollDeviceToken(base, deviceCode, clientId, intervalMs, windowMs) {
|
|
185
|
+
async function pollDeviceToken(base, deviceCode, clientId, intervalMs, windowMs, insecure) {
|
|
178
186
|
let interval = intervalMs;
|
|
179
187
|
const deadline = Date.now() + windowMs;
|
|
180
188
|
while (Date.now() < deadline) {
|
|
181
189
|
await new Promise((r) => setTimeout(r, interval));
|
|
182
|
-
const tokRes = await
|
|
190
|
+
const tokRes = await tlsFetch(
|
|
191
|
+
insecure,
|
|
183
192
|
`${base}/oauth2/token`,
|
|
184
193
|
form({ grant_type: DEVICE_GRANT, device_code: deviceCode, client_id: clientId })
|
|
185
194
|
);
|
|
@@ -205,14 +214,27 @@ async function pollDeviceToken(base, deviceCode, clientId, intervalMs, windowMs)
|
|
|
205
214
|
async function deviceLogin(baseUrl, opts = {}) {
|
|
206
215
|
const base = normalizeBaseUrl(baseUrl);
|
|
207
216
|
const clientId = opts.clientId ?? DEFAULT_DEVICE_CLIENT_ID;
|
|
208
|
-
const da = await requestDeviceCode(
|
|
217
|
+
const da = await requestDeviceCode(
|
|
218
|
+
base,
|
|
219
|
+
clientId,
|
|
220
|
+
opts.scope ?? DEVICE_SCOPE,
|
|
221
|
+
opts.audience,
|
|
222
|
+
opts.insecure
|
|
223
|
+
);
|
|
209
224
|
opts.onPrompt?.({
|
|
210
225
|
userCode: da.user_code,
|
|
211
226
|
verificationUri: onBaseHost(base, da.verification_uri),
|
|
212
227
|
verificationUriComplete: da.verification_uri_complete ? onBaseHost(base, da.verification_uri_complete) : void 0
|
|
213
228
|
});
|
|
214
229
|
const windowMs = Math.min(opts.timeoutMs ?? Number.POSITIVE_INFINITY, da.expires_in * 1e3);
|
|
215
|
-
return pollDeviceToken(
|
|
230
|
+
return pollDeviceToken(
|
|
231
|
+
base,
|
|
232
|
+
da.device_code,
|
|
233
|
+
clientId,
|
|
234
|
+
(da.interval ?? 5) * 1e3,
|
|
235
|
+
windowMs,
|
|
236
|
+
opts.insecure
|
|
237
|
+
);
|
|
216
238
|
}
|
|
217
239
|
function onBaseHost(base, uri) {
|
|
218
240
|
try {
|
|
@@ -226,10 +248,16 @@ function onBaseHost(base, uri) {
|
|
|
226
248
|
async function credentialDeviceLogin(baseUrl, username, password, opts = {}) {
|
|
227
249
|
const base = normalizeBaseUrl(baseUrl);
|
|
228
250
|
const clientId = opts.clientId ?? DEFAULT_DEVICE_CLIENT_ID;
|
|
229
|
-
const da = await requestDeviceCode(
|
|
251
|
+
const da = await requestDeviceCode(
|
|
252
|
+
base,
|
|
253
|
+
clientId,
|
|
254
|
+
opts.scope ?? DEVICE_SCOPE,
|
|
255
|
+
opts.audience,
|
|
256
|
+
opts.insecure
|
|
257
|
+
);
|
|
230
258
|
let jar = "";
|
|
231
259
|
const hop = async (url, init) => {
|
|
232
|
-
const r = await
|
|
260
|
+
const r = await tlsFetch(opts.insecure, url, {
|
|
233
261
|
method: init?.method ?? "GET",
|
|
234
262
|
headers: { Cookie: jar, Accept: "text/html,*/*;q=0.8", ...init?.headers ?? {} },
|
|
235
263
|
body: init?.body,
|
|
@@ -267,38 +295,40 @@ async function credentialDeviceLogin(baseUrl, username, password, opts = {}) {
|
|
|
267
295
|
loc = r.headers.get("location");
|
|
268
296
|
}
|
|
269
297
|
const windowMs = Math.min(opts.timeoutMs ?? Number.POSITIVE_INFINITY, da.expires_in * 1e3);
|
|
270
|
-
return pollDeviceToken(
|
|
298
|
+
return pollDeviceToken(
|
|
299
|
+
base,
|
|
300
|
+
da.device_code,
|
|
301
|
+
clientId,
|
|
302
|
+
(da.interval ?? 5) * 1e3,
|
|
303
|
+
windowMs,
|
|
304
|
+
opts.insecure
|
|
305
|
+
);
|
|
271
306
|
}
|
|
272
307
|
|
|
273
308
|
// src/api/headers.ts
|
|
274
309
|
function buildHeaders(ctx, extra) {
|
|
275
310
|
return {
|
|
276
|
-
|
|
277
|
-
...ctx.token ? { authorization: `Bearer ${ctx.token}`, token: ctx.token } : {},
|
|
311
|
+
authorization: `Bearer ${ctx.token}`,
|
|
278
312
|
"x-business-domain": ctx.businessDomain,
|
|
279
313
|
...extra
|
|
280
314
|
};
|
|
281
315
|
}
|
|
282
316
|
|
|
283
|
-
// src/api/tls.ts
|
|
284
|
-
function applyTls(ctx) {
|
|
285
|
-
if (ctx.insecure && process.env.NODE_TLS_REJECT_UNAUTHORIZED !== "0") {
|
|
286
|
-
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
317
|
// src/api/http.ts
|
|
291
318
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
292
319
|
async function request(ctx, path, init = {}) {
|
|
293
320
|
const url = new URL(path.startsWith("http") ? path : `${ctx.baseUrl}${path}`);
|
|
294
321
|
for (const [k, v] of Object.entries(init.query ?? {})) {
|
|
295
|
-
if (
|
|
322
|
+
if (Array.isArray(v)) {
|
|
323
|
+
for (const item of v) url.searchParams.append(k, String(item));
|
|
324
|
+
} else if (v !== void 0) {
|
|
325
|
+
url.searchParams.set(k, String(v));
|
|
326
|
+
}
|
|
296
327
|
}
|
|
297
|
-
applyTls(ctx);
|
|
298
328
|
const hasBody = init.body !== void 0;
|
|
299
329
|
const controller = new AbortController();
|
|
300
330
|
const timer = setTimeout(() => controller.abort(), init.timeoutMs ?? DEFAULT_TIMEOUT_MS);
|
|
301
|
-
const send = () =>
|
|
331
|
+
const send = () => tlsFetch(ctx.insecure, url, {
|
|
302
332
|
method: init.method ?? (hasBody ? "POST" : "GET"),
|
|
303
333
|
headers: buildHeaders(ctx, {
|
|
304
334
|
...hasBody ? { "content-type": "application/json" } : {},
|
|
@@ -313,16 +343,27 @@ async function request(ctx, path, init = {}) {
|
|
|
313
343
|
res = await send();
|
|
314
344
|
}
|
|
315
345
|
const text = await res.text();
|
|
316
|
-
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
346
|
+
if (!res.ok) throw new HttpError(res.status, res.statusText, text, hintFor(ctx, res.status));
|
|
317
347
|
return text ? JSON.parse(text) : void 0;
|
|
318
348
|
} finally {
|
|
319
349
|
clearTimeout(timer);
|
|
320
350
|
}
|
|
321
351
|
}
|
|
352
|
+
function hintFor(ctx, status2) {
|
|
353
|
+
if (status2 === 401 && ctx.token.startsWith("bak_")) {
|
|
354
|
+
return "AppKey invalid / expired / revoked / owner disabled \u2014 re-issue with `openbkn appkey create` (or `appkey regenerate <id>`). Do not auto-retry.";
|
|
355
|
+
}
|
|
356
|
+
return void 0;
|
|
357
|
+
}
|
|
322
358
|
async function tryRefresh(ctx) {
|
|
323
359
|
if (!ctx.refresh) return false;
|
|
324
360
|
try {
|
|
325
|
-
const t = await refreshAccessToken(
|
|
361
|
+
const t = await refreshAccessToken(
|
|
362
|
+
ctx.baseUrl,
|
|
363
|
+
ctx.refresh.refreshToken,
|
|
364
|
+
ctx.refresh.clientId,
|
|
365
|
+
ctx.insecure
|
|
366
|
+
);
|
|
326
367
|
ctx.token = t.accessToken;
|
|
327
368
|
if (t.refreshToken) ctx.refresh.refreshToken = t.refreshToken;
|
|
328
369
|
ctx.refresh.persist(t);
|
|
@@ -367,6 +408,7 @@ function isExpired(claims, nowMs = Date.now()) {
|
|
|
367
408
|
|
|
368
409
|
// src/config/store.ts
|
|
369
410
|
var PROFILE_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
411
|
+
var USER_ID_RE = /^[A-Za-z0-9._@-]{1,128}$/;
|
|
370
412
|
var IS_WIN = process.platform === "win32";
|
|
371
413
|
function configDir() {
|
|
372
414
|
return process.env.BKN_CONFIG_DIR ?? join(homedir(), ".bkn");
|
|
@@ -393,7 +435,14 @@ function userDir(baseUrl, userId) {
|
|
|
393
435
|
return join(platformDir(baseUrl), "users", userId);
|
|
394
436
|
}
|
|
395
437
|
function userIdFromToken(token) {
|
|
396
|
-
|
|
438
|
+
const sub = decodeJwt(token.idToken ?? "")?.sub ?? decodeJwt(token.accessToken)?.sub;
|
|
439
|
+
if (sub === void 0) return "default";
|
|
440
|
+
if (typeof sub !== "string" || !USER_ID_RE.test(sub) || sub === "." || sub === "..") {
|
|
441
|
+
throw new Error(
|
|
442
|
+
`Token subject '${String(sub)}' is not a usable user id (expected 1-128 chars from [A-Za-z0-9._@-]). Refusing to store this token.`
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
return sub;
|
|
397
446
|
}
|
|
398
447
|
function readState() {
|
|
399
448
|
return readJson(statePath()) ?? {};
|
|
@@ -418,10 +467,10 @@ function readToken(baseUrl, userId = activeUserId(baseUrl)) {
|
|
|
418
467
|
if (!userId) return void 0;
|
|
419
468
|
return readJson(join(userDir(baseUrl, userId), "token.json")) ?? void 0;
|
|
420
469
|
}
|
|
421
|
-
function writeToken(baseUrl, token) {
|
|
470
|
+
function writeToken(baseUrl, token, opts = {}) {
|
|
422
471
|
const userId = userIdFromToken(token);
|
|
423
472
|
writeJson(join(userDir(baseUrl, userId), "token.json"), token, 384);
|
|
424
|
-
setActiveUser(baseUrl, userId);
|
|
473
|
+
if (opts.setActive !== false) setActiveUser(baseUrl, userId);
|
|
425
474
|
return userId;
|
|
426
475
|
}
|
|
427
476
|
function deleteToken(baseUrl, userId = activeUserId(baseUrl)) {
|
|
@@ -460,6 +509,14 @@ function listPlatforms() {
|
|
|
460
509
|
}
|
|
461
510
|
return out;
|
|
462
511
|
}
|
|
512
|
+
function findUserId(baseUrl, userOrName) {
|
|
513
|
+
const users = listPlatforms().find((p) => p.baseUrl === baseUrl)?.users ?? [];
|
|
514
|
+
const match = users.find((u) => u.userId === userOrName) ?? users.find((u) => (u.username ?? u.displayName) === userOrName);
|
|
515
|
+
return match?.userId ?? null;
|
|
516
|
+
}
|
|
517
|
+
function usersOfPlatform(baseUrl) {
|
|
518
|
+
return listPlatforms().find((p) => p.baseUrl === baseUrl)?.users ?? [];
|
|
519
|
+
}
|
|
463
520
|
function decodeKey(key) {
|
|
464
521
|
try {
|
|
465
522
|
const b64 = key.replace(/-/g, "+").replace(/_/g, "/");
|
|
@@ -485,6 +542,14 @@ function writeJson(path, value, mode = 384) {
|
|
|
485
542
|
}
|
|
486
543
|
|
|
487
544
|
// src/config/resolve.ts
|
|
545
|
+
function resolveUserId(baseUrl, userOrName) {
|
|
546
|
+
const id = findUserId(baseUrl, userOrName);
|
|
547
|
+
if (id) return id;
|
|
548
|
+
const known = usersOfPlatform(baseUrl).map((u) => u.username ?? u.userId).join(", ");
|
|
549
|
+
throw new InputError(
|
|
550
|
+
`No saved user '${userOrName}' on ${baseUrl}. Saved: ${known || "(none)"}. See \`openbkn auth users ${baseUrl}\`.`
|
|
551
|
+
);
|
|
552
|
+
}
|
|
488
553
|
function resolveContext(opts = {}) {
|
|
489
554
|
const baseUrl = opts.baseUrl ?? process.env.BKN_BASE_URL ?? activePlatform();
|
|
490
555
|
if (!baseUrl) {
|
|
@@ -493,22 +558,29 @@ function resolveContext(opts = {}) {
|
|
|
493
558
|
);
|
|
494
559
|
}
|
|
495
560
|
const normalized = baseUrl.replace(/\/+$/, "");
|
|
496
|
-
const
|
|
561
|
+
const user = opts.user ?? process.env.BKN_USER;
|
|
562
|
+
const stored = user ? readToken(normalized, resolveUserId(normalized, user)) : readToken(normalized);
|
|
497
563
|
const explicit = opts.token ?? process.env.BKN_TOKEN;
|
|
498
564
|
const token = explicit ?? stored?.accessToken ?? "";
|
|
499
|
-
if (!token
|
|
565
|
+
if (!token) {
|
|
500
566
|
throw new InputError("No access token. Set BKN_TOKEN or run `openbkn auth login`.");
|
|
501
567
|
}
|
|
502
568
|
const insecure = opts.insecure ?? stored?.tlsInsecure ?? false;
|
|
503
569
|
const refresh = !explicit && stored?.refreshToken ? {
|
|
504
570
|
refreshToken: stored.refreshToken,
|
|
505
571
|
persist: (t) => {
|
|
506
|
-
writeToken(
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
572
|
+
writeToken(
|
|
573
|
+
normalized,
|
|
574
|
+
{
|
|
575
|
+
...stored,
|
|
576
|
+
accessToken: t.accessToken,
|
|
577
|
+
refreshToken: t.refreshToken ?? stored.refreshToken,
|
|
578
|
+
idToken: t.idToken ?? stored.idToken
|
|
579
|
+
},
|
|
580
|
+
// `--user` picks an identity for this command only; a refresh
|
|
581
|
+
// must not promote it to the default for the next one.
|
|
582
|
+
{ setActive: !user }
|
|
583
|
+
);
|
|
512
584
|
}
|
|
513
585
|
} : void 0;
|
|
514
586
|
return {
|
|
@@ -571,6 +643,13 @@ async function setUserPasswordSafe(ctx, userId, password) {
|
|
|
571
643
|
});
|
|
572
644
|
return { ok: true };
|
|
573
645
|
}
|
|
646
|
+
async function changePasswordSafe(ctx, account, oldPassword, newPassword) {
|
|
647
|
+
await request(ctx, "/api/safe/v1/auth/change-password", {
|
|
648
|
+
method: "POST",
|
|
649
|
+
body: { account, old_password: oldPassword, new_password: newPassword }
|
|
650
|
+
});
|
|
651
|
+
return { ok: true };
|
|
652
|
+
}
|
|
574
653
|
function getUserRolesSafe(ctx, userId) {
|
|
575
654
|
return request(ctx, `${ADMIN}/role-bindings`, { query: { accessor_id: userId } });
|
|
576
655
|
}
|
|
@@ -684,6 +763,43 @@ async function setRolePermissionSafe(ctx, roleId, grant, perm) {
|
|
|
684
763
|
});
|
|
685
764
|
return { ok: true };
|
|
686
765
|
}
|
|
766
|
+
function getLicenseSafe(ctx) {
|
|
767
|
+
return request(ctx, `${ADMIN}/license`);
|
|
768
|
+
}
|
|
769
|
+
async function importLicenseSafe(ctx, licenseText, opts = {}) {
|
|
770
|
+
const text = licenseText.trim();
|
|
771
|
+
if (!text) throw new InputError("license text is empty");
|
|
772
|
+
try {
|
|
773
|
+
return await request(ctx, `${ADMIN}/license/${opts.receipt ? "receipt" : "import"}`, {
|
|
774
|
+
method: "POST",
|
|
775
|
+
body: { license: text }
|
|
776
|
+
});
|
|
777
|
+
} catch (err) {
|
|
778
|
+
if (err instanceof HttpError) {
|
|
779
|
+
const stored = storedImport(err.body);
|
|
780
|
+
if (stored) return stored;
|
|
781
|
+
}
|
|
782
|
+
throw err;
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
function storedImport(body) {
|
|
786
|
+
try {
|
|
787
|
+
const parsed = JSON.parse(body);
|
|
788
|
+
if (parsed && parsed.stored === true) return parsed;
|
|
789
|
+
} catch {
|
|
790
|
+
}
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
function activateLicenseSafe(ctx) {
|
|
794
|
+
return request(ctx, `${ADMIN}/license/activate`, { method: "POST" });
|
|
795
|
+
}
|
|
796
|
+
async function removeLicenseSafe(ctx) {
|
|
797
|
+
await request(ctx, `${ADMIN}/license`, { method: "DELETE" });
|
|
798
|
+
return { ok: true };
|
|
799
|
+
}
|
|
800
|
+
function getLicenseFingerprintSafe(ctx) {
|
|
801
|
+
return request(ctx, `${ADMIN}/license/fingerprint`);
|
|
802
|
+
}
|
|
687
803
|
|
|
688
804
|
// src/resources/admin.ts
|
|
689
805
|
var DEFAULT_NEW_USER_PASSWORD = "openbkn";
|
|
@@ -744,10 +860,25 @@ function admin(ctx) {
|
|
|
744
860
|
roleUpdate: (roleId, input) => updateRoleSafe(ctx, roleId, input),
|
|
745
861
|
roleDelete: (roleId) => deleteRoleSafe(ctx, roleId),
|
|
746
862
|
rolePermission: (roleId, grant, resourceType, resourceId, operations) => setRolePermissionSafe(ctx, roleId, grant, { resourceType, resourceId, operations }),
|
|
747
|
-
auditList: (_opts) => notOnSafe("audit list")
|
|
863
|
+
auditList: (_opts) => notOnSafe("audit list"),
|
|
864
|
+
// ── license (cluster license hub; weak judgements — display/ops only) ──
|
|
865
|
+
licenseGet: () => getLicenseSafe(ctx),
|
|
866
|
+
licenseImport: (licenseText, opts) => importLicenseSafe(ctx, licenseText, opts),
|
|
867
|
+
licenseActivate: () => activateLicenseSafe(ctx),
|
|
868
|
+
licenseRemove: () => removeLicenseSafe(ctx),
|
|
869
|
+
licenseFingerprint: () => getLicenseFingerprintSafe(ctx)
|
|
748
870
|
};
|
|
749
871
|
}
|
|
750
872
|
|
|
873
|
+
// src/api/auth-fetch.ts
|
|
874
|
+
async function authFetch(ctx, send) {
|
|
875
|
+
let res = await send();
|
|
876
|
+
if (res.status === 401 && ctx.refresh && await tryRefresh(ctx)) {
|
|
877
|
+
res = await send();
|
|
878
|
+
}
|
|
879
|
+
return res;
|
|
880
|
+
}
|
|
881
|
+
|
|
751
882
|
// src/api/agent-chat.ts
|
|
752
883
|
var FACTORY = "/api/agent-factory";
|
|
753
884
|
async function fetchAgentInfo(ctx, agentId, version = "v0") {
|
|
@@ -807,7 +938,6 @@ function extractText(result) {
|
|
|
807
938
|
return "";
|
|
808
939
|
}
|
|
809
940
|
async function sendChat(ctx, info, query, opts = {}) {
|
|
810
|
-
applyTls(ctx);
|
|
811
941
|
const body = {
|
|
812
942
|
agent_id: info.id,
|
|
813
943
|
agent_key: info.key,
|
|
@@ -816,16 +946,19 @@ async function sendChat(ctx, info, query, opts = {}) {
|
|
|
816
946
|
stream: Boolean(opts.stream)
|
|
817
947
|
};
|
|
818
948
|
if (opts.conversationId) body.conversation_id = opts.conversationId;
|
|
819
|
-
const res = await
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
949
|
+
const res = await authFetch(
|
|
950
|
+
ctx,
|
|
951
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${FACTORY}/v1/app/${info.key}/chat/completion`, {
|
|
952
|
+
method: "POST",
|
|
953
|
+
headers: {
|
|
954
|
+
...buildHeaders(ctx),
|
|
955
|
+
"content-type": "application/json",
|
|
956
|
+
accept: opts.stream ? "text/event-stream" : "application/json",
|
|
957
|
+
"x-language": "zh-CN"
|
|
958
|
+
},
|
|
959
|
+
body: JSON.stringify(body)
|
|
960
|
+
})
|
|
961
|
+
);
|
|
829
962
|
if (!res.ok) throw new HttpError(res.status, res.statusText, await res.text());
|
|
830
963
|
const contentType = res.headers.get("content-type") ?? "";
|
|
831
964
|
if (opts.stream && contentType.includes("text/event-stream")) {
|
|
@@ -1017,6 +1150,9 @@ function nextId() {
|
|
|
1017
1150
|
function mcpUrl(ctx) {
|
|
1018
1151
|
return `${ctx.baseUrl}${MCP_PATH}`;
|
|
1019
1152
|
}
|
|
1153
|
+
function mcpInfo(ctx) {
|
|
1154
|
+
return request(ctx, `${MCP_PATH}/info`);
|
|
1155
|
+
}
|
|
1020
1156
|
function headers(ctx, knId, sessionId) {
|
|
1021
1157
|
const h = {
|
|
1022
1158
|
"content-type": "application/json",
|
|
@@ -1038,12 +1174,14 @@ function parseBody(text) {
|
|
|
1038
1174
|
}
|
|
1039
1175
|
}
|
|
1040
1176
|
async function post(ctx, knId, sessionId, body) {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1177
|
+
const res = await authFetch(
|
|
1178
|
+
ctx,
|
|
1179
|
+
() => tlsFetch(ctx.insecure, mcpUrl(ctx), {
|
|
1180
|
+
method: "POST",
|
|
1181
|
+
headers: headers(ctx, knId, sessionId),
|
|
1182
|
+
body: JSON.stringify(body)
|
|
1183
|
+
})
|
|
1184
|
+
);
|
|
1047
1185
|
const text = await res.text();
|
|
1048
1186
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
1049
1187
|
return { res, text };
|
|
@@ -1120,6 +1258,17 @@ function findSkills(ctx, knId, objectTypeId, topK) {
|
|
|
1120
1258
|
if (topK !== void 0) args.top_k = topK;
|
|
1121
1259
|
return callTool(ctx, knId, "find_skills", args);
|
|
1122
1260
|
}
|
|
1261
|
+
function getKnDetail(ctx, knId, detailLevel) {
|
|
1262
|
+
const args = { response_format: "json" };
|
|
1263
|
+
if (detailLevel) args.detail_level = detailLevel;
|
|
1264
|
+
return callTool(ctx, knId, "get_kn_detail", args);
|
|
1265
|
+
}
|
|
1266
|
+
function getObjectTypes(ctx, knId, ids) {
|
|
1267
|
+
return callTool(ctx, knId, "get_object_types", { ids, response_format: "json" });
|
|
1268
|
+
}
|
|
1269
|
+
function getRelationTypes(ctx, knId, ids) {
|
|
1270
|
+
return callTool(ctx, knId, "get_relation_types", { ids, response_format: "json" });
|
|
1271
|
+
}
|
|
1123
1272
|
function listTools(ctx, knId) {
|
|
1124
1273
|
return callMethod(ctx, knId, "tools/list");
|
|
1125
1274
|
}
|
|
@@ -1154,8 +1303,16 @@ function context(ctx) {
|
|
|
1154
1303
|
searchSchema: (knId, query, opts) => searchSchema(ctx, knId, query, opts),
|
|
1155
1304
|
queryObjectInstance: (knId, args) => queryObjectInstance(ctx, knId, args),
|
|
1156
1305
|
findSkills: (knId, objectTypeId, topK) => findSkills(ctx, knId, objectTypeId, topK),
|
|
1306
|
+
// Progressive schema disclosure: skeleton first (summary), then drill down.
|
|
1307
|
+
knDetail: (knId, detailLevel) => getKnDetail(ctx, knId, detailLevel),
|
|
1308
|
+
objectTypes: (knId, ids) => getObjectTypes(ctx, knId, ids),
|
|
1309
|
+
relationTypes: (knId, ids) => getRelationTypes(ctx, knId, ids),
|
|
1310
|
+
info: () => mcpInfo(ctx),
|
|
1157
1311
|
tools: (knId) => listTools(ctx, knId),
|
|
1158
1312
|
toolCall: (knId, name, args) => callTool(ctx, knId, name, args),
|
|
1313
|
+
// Generic MCP method passthrough — covers methods not yet wrapped, so the
|
|
1314
|
+
// surface doesn't have to grow every time the server adds one.
|
|
1315
|
+
callMethod: (knId, method, params) => callMethod(ctx, knId, method, params),
|
|
1159
1316
|
queryInstanceSubgraph: (knId, args) => queryInstanceSubgraph(ctx, knId, args),
|
|
1160
1317
|
logicProperties: (knId, args) => getLogicProperties(ctx, knId, args),
|
|
1161
1318
|
actionInfo: (knId, args) => getActionInfo(ctx, knId, args),
|
|
@@ -1475,7 +1632,16 @@ function listResources2(ctx, opts = {}) {
|
|
|
1475
1632
|
catalog_id: opts.datasourceId || void 0,
|
|
1476
1633
|
name: opts.name || void 0,
|
|
1477
1634
|
category: opts.category || void 0,
|
|
1478
|
-
|
|
1635
|
+
status: opts.status || void 0,
|
|
1636
|
+
database: opts.database || void 0,
|
|
1637
|
+
limit: opts.limit && opts.limit > 0 ? opts.limit : void 0,
|
|
1638
|
+
offset: opts.offset,
|
|
1639
|
+
sort: opts.sort,
|
|
1640
|
+
direction: opts.direction,
|
|
1641
|
+
include_extensions: opts.includeExtensions === void 0 ? void 0 : String(opts.includeExtensions),
|
|
1642
|
+
include_extension_keys: opts.includeExtensionKeys || void 0,
|
|
1643
|
+
extension_key: opts.extensionPairs?.map((p) => p.key),
|
|
1644
|
+
extension_value: opts.extensionPairs?.map((p) => p.value)
|
|
1479
1645
|
}
|
|
1480
1646
|
});
|
|
1481
1647
|
}
|
|
@@ -1485,18 +1651,103 @@ function getResource(ctx, id) {
|
|
|
1485
1651
|
function createResourceRaw(ctx, body) {
|
|
1486
1652
|
return request(ctx, BASE3, { method: "POST", body });
|
|
1487
1653
|
}
|
|
1488
|
-
function
|
|
1654
|
+
function updateResourceRaw(ctx, id, body) {
|
|
1655
|
+
return request(ctx, `${BASE3}/${encodeURIComponent(id)}`, { method: "PUT", body });
|
|
1656
|
+
}
|
|
1657
|
+
async function updateResource(ctx, id, patch) {
|
|
1658
|
+
const current = firstResource(await getResource(ctx, id));
|
|
1659
|
+
return updateResourceRaw(ctx, id, resourceUpdateBody(id, current, patch));
|
|
1660
|
+
}
|
|
1661
|
+
async function configureResourceIndex(ctx, id, opts) {
|
|
1662
|
+
const current = firstResource(await getResource(ctx, id));
|
|
1663
|
+
const schema = (current.schema_definition ?? []).map((prop) => ({ ...prop }));
|
|
1664
|
+
const indexConfig = {
|
|
1665
|
+
...current.index_config ?? {},
|
|
1666
|
+
...opts.buildKeyFields?.length ? { build_key_fields: opts.buildKeyFields } : {},
|
|
1667
|
+
...opts.embeddingModel ? { default_embedding_model: opts.embeddingModel } : {},
|
|
1668
|
+
...opts.fulltextAnalyzer ? { default_fulltext_analyzer: opts.fulltextAnalyzer } : {}
|
|
1669
|
+
};
|
|
1670
|
+
for (const field of opts.embeddingFields ?? []) {
|
|
1671
|
+
ensureFeature(
|
|
1672
|
+
schema,
|
|
1673
|
+
field,
|
|
1674
|
+
"vector",
|
|
1675
|
+
opts.embeddingModel ? { embedding_model: opts.embeddingModel } : void 0
|
|
1676
|
+
);
|
|
1677
|
+
}
|
|
1678
|
+
for (const field of opts.fulltextFields ?? []) {
|
|
1679
|
+
ensureFeature(
|
|
1680
|
+
schema,
|
|
1681
|
+
field,
|
|
1682
|
+
"fulltext",
|
|
1683
|
+
opts.fulltextAnalyzer ? { analyzer: opts.fulltextAnalyzer } : void 0
|
|
1684
|
+
);
|
|
1685
|
+
}
|
|
1686
|
+
return updateResourceRaw(
|
|
1687
|
+
ctx,
|
|
1688
|
+
id,
|
|
1689
|
+
resourceUpdateBody(id, current, { schemaDefinition: schema, indexConfig })
|
|
1690
|
+
);
|
|
1691
|
+
}
|
|
1692
|
+
function resourceUpdateBody(id, current, patch) {
|
|
1489
1693
|
const body = {
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1694
|
+
id,
|
|
1695
|
+
name: patch.name ?? current.name,
|
|
1696
|
+
catalog_id: patch.catalogId ?? current.catalog_id,
|
|
1697
|
+
tags: patch.tags ?? current.tags ?? [],
|
|
1698
|
+
description: patch.description ?? current.description ?? "",
|
|
1699
|
+
category: patch.category ?? current.category,
|
|
1700
|
+
status: patch.status ?? current.status,
|
|
1701
|
+
database: patch.database ?? current.database,
|
|
1702
|
+
source_identifier: patch.sourceIdentifier ?? current.source_identifier,
|
|
1703
|
+
source_metadata: patch.sourceMetadata ?? current.source_metadata,
|
|
1704
|
+
schema_definition: patch.schemaDefinition ?? current.schema_definition,
|
|
1705
|
+
index_config: patch.indexConfig === void 0 ? current.index_config : patch.indexConfig,
|
|
1706
|
+
logic_definition: patch.logicDefinition ?? current.logic_definition
|
|
1494
1707
|
};
|
|
1495
|
-
if (
|
|
1496
|
-
|
|
1708
|
+
if (patch.extensions !== void 0 || current.extensions !== void 0) {
|
|
1709
|
+
body.extensions = patch.extensions ?? current.extensions;
|
|
1710
|
+
}
|
|
1711
|
+
return body;
|
|
1712
|
+
}
|
|
1713
|
+
function ensureFeature(schema, field, featureType, config) {
|
|
1714
|
+
const prop = schema.find((p) => p.name === field);
|
|
1715
|
+
if (!prop) throw new Error(`resource field '${field}' not found in schema_definition`);
|
|
1716
|
+
const features = [...prop.features ?? []];
|
|
1717
|
+
const existing = features.find(
|
|
1718
|
+
(f) => f.feature_type === featureType && (f.ref_property || field) === field
|
|
1719
|
+
);
|
|
1720
|
+
if (existing) {
|
|
1721
|
+
existing.ref_property = existing.ref_property || field;
|
|
1722
|
+
existing.config = { ...existing.config ?? {}, ...config ?? {} };
|
|
1723
|
+
} else {
|
|
1724
|
+
features.push({
|
|
1725
|
+
name: `${field}_${featureType}`,
|
|
1726
|
+
feature_type: featureType,
|
|
1727
|
+
ref_property: field,
|
|
1728
|
+
is_default: false,
|
|
1729
|
+
is_native: false,
|
|
1730
|
+
...config ? { config } : {}
|
|
1731
|
+
});
|
|
1732
|
+
}
|
|
1733
|
+
prop.features = features;
|
|
1734
|
+
}
|
|
1735
|
+
function firstResource(result) {
|
|
1736
|
+
if (result && typeof result === "object") {
|
|
1737
|
+
const o = result;
|
|
1738
|
+
if (Array.isArray(o.entries)) return o.entries[0] ?? {};
|
|
1739
|
+
return o;
|
|
1740
|
+
}
|
|
1741
|
+
return {};
|
|
1497
1742
|
}
|
|
1498
|
-
function deleteResource(ctx, id) {
|
|
1499
|
-
|
|
1743
|
+
function deleteResource(ctx, id, opts = {}) {
|
|
1744
|
+
const ids = Array.isArray(id) ? id : [id];
|
|
1745
|
+
return request(ctx, `${BASE3}/${ids.map(encodeURIComponent).join(",")}`, {
|
|
1746
|
+
method: "DELETE",
|
|
1747
|
+
query: {
|
|
1748
|
+
ignore_missing: opts.ignoreMissing === void 0 ? void 0 : String(opts.ignoreMissing)
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1500
1751
|
}
|
|
1501
1752
|
async function findResource(ctx, name, opts = {}) {
|
|
1502
1753
|
const result = await listResources2(ctx, { name, datasourceId: opts.datasourceId });
|
|
@@ -2718,7 +2969,6 @@ function knPath(knId, path) {
|
|
|
2718
2969
|
return `${BASE4}/${encodeURIComponent(knId)}/${path}`;
|
|
2719
2970
|
}
|
|
2720
2971
|
async function uploadBkn(ctx, tarBuffer, opts = {}) {
|
|
2721
|
-
applyTls(ctx);
|
|
2722
2972
|
const url = new URL(`${ctx.baseUrl}${BKNS}`);
|
|
2723
2973
|
url.searchParams.set("branch", opts.branch ?? "main");
|
|
2724
2974
|
const form2 = new FormData();
|
|
@@ -2727,16 +2977,21 @@ async function uploadBkn(ctx, tarBuffer, opts = {}) {
|
|
|
2727
2977
|
new Blob([new Uint8Array(tarBuffer)], { type: "application/octet-stream" }),
|
|
2728
2978
|
"bkn.tar"
|
|
2729
2979
|
);
|
|
2730
|
-
const res = await
|
|
2980
|
+
const res = await authFetch(
|
|
2981
|
+
ctx,
|
|
2982
|
+
() => tlsFetch(ctx.insecure, url, { method: "POST", headers: buildHeaders(ctx), body: form2 })
|
|
2983
|
+
);
|
|
2731
2984
|
const text = await res.text();
|
|
2732
2985
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
2733
2986
|
return text ? JSON.parse(text) : void 0;
|
|
2734
2987
|
}
|
|
2735
2988
|
async function downloadBkn(ctx, knId, opts = {}) {
|
|
2736
|
-
applyTls(ctx);
|
|
2737
2989
|
const url = new URL(`${ctx.baseUrl}${BKNS}/${encodeURIComponent(knId)}`);
|
|
2738
2990
|
url.searchParams.set("branch", opts.branch ?? "main");
|
|
2739
|
-
const res = await
|
|
2991
|
+
const res = await authFetch(
|
|
2992
|
+
ctx,
|
|
2993
|
+
() => tlsFetch(ctx.insecure, url, { method: "GET", headers: buildHeaders(ctx) })
|
|
2994
|
+
);
|
|
2740
2995
|
if (!res.ok) throw new HttpError(res.status, res.statusText, await res.text());
|
|
2741
2996
|
return Buffer.from(await res.arrayBuffer());
|
|
2742
2997
|
}
|
|
@@ -2825,10 +3080,7 @@ var BuildMode = z.enum(["batch", "streaming"]);
|
|
|
2825
3080
|
var CreateBuildTaskRequest = z.object({
|
|
2826
3081
|
resource_id: z.string().min(1),
|
|
2827
3082
|
mode: BuildMode,
|
|
2828
|
-
|
|
2829
|
-
build_key_fields: z.array(z.string()).optional(),
|
|
2830
|
-
embedding_model: z.string().optional(),
|
|
2831
|
-
model_dimensions: z.number().int().positive().optional()
|
|
3083
|
+
execute_type: z.enum(["incremental", "full"]).optional()
|
|
2832
3084
|
});
|
|
2833
3085
|
var BuildTask = z.object({
|
|
2834
3086
|
id: z.string(),
|
|
@@ -2839,31 +3091,83 @@ var BuildTask = z.object({
|
|
|
2839
3091
|
total_count: z.number().optional(),
|
|
2840
3092
|
synced_count: z.number().optional(),
|
|
2841
3093
|
vectorized_count: z.number().optional(),
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
3094
|
+
index_config: z.unknown().optional(),
|
|
3095
|
+
catalog_id: z.string().optional(),
|
|
3096
|
+
index_health: z.object({
|
|
3097
|
+
embedding: z.string(),
|
|
3098
|
+
fulltext: z.string(),
|
|
3099
|
+
usable: z.boolean()
|
|
3100
|
+
}).passthrough().optional()
|
|
2846
3101
|
}).passthrough();
|
|
2847
3102
|
async function createBuildTask(ctx, req) {
|
|
2848
3103
|
const p = CreateBuildTaskRequest.parse(req);
|
|
2849
3104
|
const body = {
|
|
2850
3105
|
resource_id: p.resource_id,
|
|
2851
3106
|
mode: p.mode,
|
|
2852
|
-
...p.
|
|
2853
|
-
...p.build_key_fields?.length ? { build_key_fields: p.build_key_fields.join(",") } : {},
|
|
2854
|
-
...p.embedding_model ? { embedding_model: p.embedding_model } : {},
|
|
2855
|
-
...p.model_dimensions ? { model_dimensions: p.model_dimensions } : {}
|
|
3107
|
+
...p.execute_type ? { execute_type: p.execute_type } : {}
|
|
2856
3108
|
};
|
|
2857
3109
|
const res = await request(ctx, `${VEGA_BASE}/build-tasks`, { method: "POST", body });
|
|
2858
3110
|
return BuildTask.parse(res);
|
|
2859
3111
|
}
|
|
3112
|
+
function listBuildTasks(ctx, opts = {}) {
|
|
3113
|
+
return request(ctx, `${VEGA_BASE}/build-tasks`, {
|
|
3114
|
+
query: {
|
|
3115
|
+
limit: opts.limit,
|
|
3116
|
+
offset: opts.offset,
|
|
3117
|
+
resource_id: opts.resourceId || void 0,
|
|
3118
|
+
catalog_id: opts.catalogId || void 0,
|
|
3119
|
+
status: Array.isArray(opts.status) ? opts.status.join(",") : opts.status || void 0,
|
|
3120
|
+
active: opts.active === void 0 ? void 0 : String(opts.active),
|
|
3121
|
+
mode: opts.mode,
|
|
3122
|
+
order_by: opts.orderBy,
|
|
3123
|
+
order: opts.order
|
|
3124
|
+
}
|
|
3125
|
+
});
|
|
3126
|
+
}
|
|
2860
3127
|
async function getBuildTask(ctx, taskId) {
|
|
2861
3128
|
const res = await request(ctx, `${VEGA_BASE}/build-tasks/${encodeURIComponent(taskId)}`);
|
|
2862
3129
|
return BuildTask.parse(res);
|
|
2863
3130
|
}
|
|
3131
|
+
function deleteBuildTasks(ctx, ids, opts = {}) {
|
|
3132
|
+
return request(ctx, `${VEGA_BASE}/build-tasks/${ids.map(encodeURIComponent).join(",")}`, {
|
|
3133
|
+
method: "DELETE",
|
|
3134
|
+
query: {
|
|
3135
|
+
ignore_missing: opts.ignoreMissing === void 0 ? void 0 : String(opts.ignoreMissing),
|
|
3136
|
+
delete_active_index: opts.deleteActiveIndex === void 0 ? void 0 : String(opts.deleteActiveIndex)
|
|
3137
|
+
}
|
|
3138
|
+
});
|
|
3139
|
+
}
|
|
3140
|
+
function startBuildTask(ctx, taskId, opts = {}) {
|
|
3141
|
+
return request(ctx, `${VEGA_BASE}/build-tasks/${encodeURIComponent(taskId)}/start`, {
|
|
3142
|
+
method: "POST",
|
|
3143
|
+
body: opts.reset === void 0 ? {} : { reset: opts.reset }
|
|
3144
|
+
});
|
|
3145
|
+
}
|
|
3146
|
+
function stopBuildTask(ctx, taskId) {
|
|
3147
|
+
return request(ctx, `${VEGA_BASE}/build-tasks/${encodeURIComponent(taskId)}/stop`, {
|
|
3148
|
+
method: "POST"
|
|
3149
|
+
});
|
|
3150
|
+
}
|
|
3151
|
+
function runSql(ctx, body) {
|
|
3152
|
+
return request(ctx, `${VEGA_BASE}/resources/query`, { method: "POST", body });
|
|
3153
|
+
}
|
|
2864
3154
|
async function listCatalogs(ctx, opts = {}) {
|
|
2865
3155
|
return request(ctx, `${VEGA_BASE}/catalogs`, {
|
|
2866
|
-
query: {
|
|
3156
|
+
query: {
|
|
3157
|
+
limit: opts.limit,
|
|
3158
|
+
offset: opts.offset,
|
|
3159
|
+
name: opts.name || void 0,
|
|
3160
|
+
tag: opts.tag || void 0,
|
|
3161
|
+
type: opts.type || void 0,
|
|
3162
|
+
enabled: opts.enabled === void 0 ? void 0 : String(opts.enabled),
|
|
3163
|
+
health_check_status: opts.healthCheckStatus || void 0,
|
|
3164
|
+
include_extensions: opts.includeExtensions === void 0 ? void 0 : String(opts.includeExtensions),
|
|
3165
|
+
include_extension_keys: opts.includeExtensionKeys || void 0,
|
|
3166
|
+
extension_key: opts.extensionPairs?.map((p) => p.key),
|
|
3167
|
+
extension_value: opts.extensionPairs?.map((p) => p.value),
|
|
3168
|
+
sort: opts.sort,
|
|
3169
|
+
direction: opts.direction
|
|
3170
|
+
}
|
|
2867
3171
|
});
|
|
2868
3172
|
}
|
|
2869
3173
|
function getCatalog(ctx, id) {
|
|
@@ -2873,18 +3177,49 @@ function createCatalog(ctx, req) {
|
|
|
2873
3177
|
return request(ctx, `${VEGA_BASE}/catalogs`, {
|
|
2874
3178
|
method: "POST",
|
|
2875
3179
|
body: {
|
|
3180
|
+
...req.id ? { id: req.id } : {},
|
|
2876
3181
|
name: req.name,
|
|
2877
3182
|
connector_type: req.connectorType,
|
|
2878
3183
|
connector_config: req.connectorConfig,
|
|
2879
3184
|
...req.tags ? { tags: req.tags } : {},
|
|
2880
3185
|
...req.description ? { description: req.description } : {},
|
|
2881
|
-
...req.enabled !== void 0 ? { enabled: req.enabled } : {}
|
|
3186
|
+
...req.enabled !== void 0 ? { enabled: req.enabled } : {},
|
|
3187
|
+
...req.internal !== void 0 ? { internal: req.internal } : {},
|
|
3188
|
+
...req.extensions ? { extensions: req.extensions } : {}
|
|
3189
|
+
}
|
|
3190
|
+
});
|
|
3191
|
+
}
|
|
3192
|
+
function updateCatalog(ctx, id, req) {
|
|
3193
|
+
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}`, {
|
|
3194
|
+
method: "PUT",
|
|
3195
|
+
body: {
|
|
3196
|
+
...req.id ? { id: req.id } : {},
|
|
3197
|
+
...req.name ? { name: req.name } : {},
|
|
3198
|
+
...req.connectorType ? { connector_type: req.connectorType } : {},
|
|
3199
|
+
...req.connectorConfig !== void 0 ? { connector_config: req.connectorConfig } : {},
|
|
3200
|
+
...req.tags ? { tags: req.tags } : {},
|
|
3201
|
+
...req.description !== void 0 ? { description: req.description } : {},
|
|
3202
|
+
...req.enabled !== void 0 ? { enabled: req.enabled } : {},
|
|
3203
|
+
...req.extensions ? { extensions: req.extensions } : {}
|
|
2882
3204
|
}
|
|
2883
3205
|
});
|
|
2884
3206
|
}
|
|
2885
3207
|
function enableCatalog(ctx, id) {
|
|
2886
3208
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/enable`, { method: "POST" });
|
|
2887
3209
|
}
|
|
3210
|
+
function disableCatalog(ctx, id) {
|
|
3211
|
+
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/disable`, {
|
|
3212
|
+
method: "POST"
|
|
3213
|
+
});
|
|
3214
|
+
}
|
|
3215
|
+
function deleteCatalog(ctx, id) {
|
|
3216
|
+
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
3217
|
+
}
|
|
3218
|
+
function testCatalogConnection(ctx, id) {
|
|
3219
|
+
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/test-connection`, {
|
|
3220
|
+
method: "POST"
|
|
3221
|
+
});
|
|
3222
|
+
}
|
|
2888
3223
|
function discoverCatalog(ctx, id, wait = true) {
|
|
2889
3224
|
return request(ctx, `${VEGA_BASE}/catalogs/${encodeURIComponent(id)}/discover`, {
|
|
2890
3225
|
method: "POST",
|
|
@@ -3354,7 +3689,7 @@ async function createFromCatalog(ctx, opts) {
|
|
|
3354
3689
|
}
|
|
3355
3690
|
tablePk[t.name] = res.pk;
|
|
3356
3691
|
}
|
|
3357
|
-
log(`
|
|
3692
|
+
log(`Resolving discovered resources for ${targets.length} table(s)...`);
|
|
3358
3693
|
const viewMap = {};
|
|
3359
3694
|
for (const t of targets) {
|
|
3360
3695
|
const found = asArray(
|
|
@@ -3364,13 +3699,9 @@ async function createFromCatalog(ctx, opts) {
|
|
|
3364
3699
|
if (existingId) {
|
|
3365
3700
|
viewMap[t.name] = existingId;
|
|
3366
3701
|
} else {
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
sourceIdentifier: t.name,
|
|
3371
|
-
fields: t.columns.map((c) => ({ name: c.name, type: c.type }))
|
|
3372
|
-
});
|
|
3373
|
-
viewMap[t.name] = String(created.id ?? "");
|
|
3702
|
+
throw new Error(
|
|
3703
|
+
`Table '${t.name}' has no discovered Vega resource. Run catalog discover and retry.`
|
|
3704
|
+
);
|
|
3374
3705
|
}
|
|
3375
3706
|
}
|
|
3376
3707
|
const knCreated = await createKnowledgeNetwork(ctx, { name: opts.name });
|
|
@@ -3402,12 +3733,14 @@ async function createFromCatalog(ctx, opts) {
|
|
|
3402
3733
|
log("Submitting build tasks...");
|
|
3403
3734
|
for (const t of targets) {
|
|
3404
3735
|
const embedding = opts.embeddingFields?.[t.name];
|
|
3736
|
+
await configureResourceIndex(ctx, viewMap[t.name], {
|
|
3737
|
+
buildKeyFields: [tablePk[t.name]],
|
|
3738
|
+
...embedding && embedding.length > 0 ? { embeddingFields: embedding } : {},
|
|
3739
|
+
...opts.embeddingModel ? { embeddingModel: opts.embeddingModel } : {}
|
|
3740
|
+
});
|
|
3405
3741
|
const task = await createBuildTask(ctx, {
|
|
3406
3742
|
resource_id: viewMap[t.name],
|
|
3407
|
-
mode: "batch"
|
|
3408
|
-
build_key_fields: [tablePk[t.name]],
|
|
3409
|
-
...embedding && embedding.length > 0 ? { embedding_fields: embedding } : {},
|
|
3410
|
-
...opts.embeddingModel ? { embedding_model: opts.embeddingModel } : {}
|
|
3743
|
+
mode: "batch"
|
|
3411
3744
|
});
|
|
3412
3745
|
builds.push({ table: t.name, taskId: String(task.id ?? "") });
|
|
3413
3746
|
}
|
|
@@ -3585,12 +3918,19 @@ function kn(ctx) {
|
|
|
3585
3918
|
const targets = collectIndexTargets(dir);
|
|
3586
3919
|
const buildTasks = [];
|
|
3587
3920
|
for (const t of targets) {
|
|
3921
|
+
if (!t.buildKey) {
|
|
3922
|
+
throw new Error(
|
|
3923
|
+
`Object type '${t.objectType}' declares a vector index but no build key; batch Vega builds require resource index_config.build_key_fields.`
|
|
3924
|
+
);
|
|
3925
|
+
}
|
|
3926
|
+
await configureResourceIndex(ctx, t.resourceId, {
|
|
3927
|
+
buildKeyFields: [t.buildKey],
|
|
3928
|
+
embeddingFields: t.embeddingFields,
|
|
3929
|
+
...t.embeddingModel ?? opts.embeddingModel ? { embeddingModel: t.embeddingModel ?? opts.embeddingModel } : {}
|
|
3930
|
+
});
|
|
3588
3931
|
const task = await createBuildTask(ctx, {
|
|
3589
3932
|
resource_id: t.resourceId,
|
|
3590
|
-
mode: "batch"
|
|
3591
|
-
embedding_fields: t.embeddingFields,
|
|
3592
|
-
...t.buildKey ? { build_key_fields: [t.buildKey] } : {},
|
|
3593
|
-
...t.embeddingModel ?? opts.embeddingModel ? { embedding_model: t.embeddingModel ?? opts.embeddingModel } : {}
|
|
3933
|
+
mode: "batch"
|
|
3594
3934
|
});
|
|
3595
3935
|
buildTasks.push({
|
|
3596
3936
|
objectType: t.objectType,
|
|
@@ -3645,16 +3985,18 @@ function deltaContent(chunk) {
|
|
|
3645
3985
|
return typeof c === "string" ? c : "";
|
|
3646
3986
|
}
|
|
3647
3987
|
async function chatCompletionsStream(ctx, model, messages, onDelta) {
|
|
3648
|
-
|
|
3649
|
-
|
|
3650
|
-
|
|
3651
|
-
|
|
3652
|
-
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3988
|
+
const res = await authFetch(
|
|
3989
|
+
ctx,
|
|
3990
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${API}/chat/completions`, {
|
|
3991
|
+
method: "POST",
|
|
3992
|
+
headers: {
|
|
3993
|
+
...buildHeaders(ctx),
|
|
3994
|
+
"content-type": "application/json",
|
|
3995
|
+
accept: "text/event-stream"
|
|
3996
|
+
},
|
|
3997
|
+
body: JSON.stringify({ model, messages, stream: true })
|
|
3998
|
+
})
|
|
3999
|
+
);
|
|
3658
4000
|
if (!res.ok) throw new HttpError(res.status, res.statusText, await res.text());
|
|
3659
4001
|
const reader = res.body?.getReader();
|
|
3660
4002
|
if (!reader) throw new Error("No response body for stream");
|
|
@@ -3704,6 +4046,23 @@ function deleteModels(ctx, kind, modelIds) {
|
|
|
3704
4046
|
function testModel(ctx, kind, body) {
|
|
3705
4047
|
return request(ctx, `${MANAGER}/${kind}/test`, { method: "POST", body });
|
|
3706
4048
|
}
|
|
4049
|
+
function setDefaultLlm(ctx, modelId, isDefault = true) {
|
|
4050
|
+
return request(ctx, `${MANAGER}/llm/default/edit`, {
|
|
4051
|
+
method: "POST",
|
|
4052
|
+
body: { model_id: modelId, default: isDefault }
|
|
4053
|
+
});
|
|
4054
|
+
}
|
|
4055
|
+
function setDefaultSmallModel(ctx, modelId, isDefault = true) {
|
|
4056
|
+
return request(ctx, `${MANAGER}/small-model/set-default`, {
|
|
4057
|
+
method: "POST",
|
|
4058
|
+
body: { model_id: modelId, default: isDefault }
|
|
4059
|
+
});
|
|
4060
|
+
}
|
|
4061
|
+
function getDefaultSmallModel(ctx, modelType = "embedding") {
|
|
4062
|
+
return request(ctx, `${MANAGER}/small-model/get_default`, {
|
|
4063
|
+
query: { model_type: modelType }
|
|
4064
|
+
});
|
|
4065
|
+
}
|
|
3707
4066
|
function rerank(ctx, model, query, documents) {
|
|
3708
4067
|
return request(ctx, `${API}/small-model/reranker`, {
|
|
3709
4068
|
method: "POST",
|
|
@@ -3722,7 +4081,9 @@ function models(ctx) {
|
|
|
3722
4081
|
add: (body) => addModel(ctx, "llm", body),
|
|
3723
4082
|
edit: (body) => editModel(ctx, "llm", body),
|
|
3724
4083
|
delete: (modelIds) => deleteModels(ctx, "llm", modelIds),
|
|
3725
|
-
test: (body) => testModel(ctx, "llm", body)
|
|
4084
|
+
test: (body) => testModel(ctx, "llm", body),
|
|
4085
|
+
/** Set (or clear) the system default LLM. */
|
|
4086
|
+
setDefault: (modelId, isDefault = true) => setDefaultLlm(ctx, modelId, isDefault)
|
|
3726
4087
|
},
|
|
3727
4088
|
small: {
|
|
3728
4089
|
list: (opts) => listSmallModels(ctx, opts),
|
|
@@ -3732,7 +4093,11 @@ function models(ctx) {
|
|
|
3732
4093
|
add: (body) => addModel(ctx, "small-model", body),
|
|
3733
4094
|
edit: (body) => editModel(ctx, "small-model", body),
|
|
3734
4095
|
delete: (modelIds) => deleteModels(ctx, "small-model", modelIds),
|
|
3735
|
-
test: (body) => testModel(ctx, "small-model", body)
|
|
4096
|
+
test: (body) => testModel(ctx, "small-model", body),
|
|
4097
|
+
/** Set (or clear) the system default small model (type inferred from the model). */
|
|
4098
|
+
setDefault: (modelId, isDefault = true) => setDefaultSmallModel(ctx, modelId, isDefault),
|
|
4099
|
+
/** Get the system default small model for a type (default "embedding"). */
|
|
4100
|
+
getDefault: (modelType) => getDefaultSmallModel(ctx, modelType)
|
|
3736
4101
|
}
|
|
3737
4102
|
};
|
|
3738
4103
|
}
|
|
@@ -3743,6 +4108,8 @@ function resources(ctx) {
|
|
|
3743
4108
|
list: (opts) => listResources2(ctx, opts),
|
|
3744
4109
|
get: (id) => getResource(ctx, id),
|
|
3745
4110
|
delete: (id) => deleteResource(ctx, id),
|
|
4111
|
+
update: (id, patch) => updateResource(ctx, id, patch),
|
|
4112
|
+
configureIndex: (id, opts) => configureResourceIndex(ctx, id, opts),
|
|
3746
4113
|
find: (name, opts) => findResource(ctx, name, opts),
|
|
3747
4114
|
query: (id, opts) => queryResource(ctx, id, opts)
|
|
3748
4115
|
};
|
|
@@ -3755,40 +4122,46 @@ import { basename as basename2, dirname as dirname3, resolve as resolve5 } from
|
|
|
3755
4122
|
// src/api/skills.ts
|
|
3756
4123
|
var BASE5 = "/api/agent-operator-integration/v1";
|
|
3757
4124
|
async function registerSkillZip(ctx, bytes, opts = {}) {
|
|
3758
|
-
applyTls(ctx);
|
|
3759
4125
|
const form2 = new FormData();
|
|
3760
4126
|
form2.set("file_type", "zip");
|
|
3761
4127
|
form2.set("file", new Blob([bytes]), opts.filename ?? "skill.zip");
|
|
3762
4128
|
if (opts.source) form2.set("source", opts.source);
|
|
3763
4129
|
if (opts.extendInfo) form2.set("extend_info", JSON.stringify(opts.extendInfo));
|
|
3764
|
-
const res = await
|
|
3765
|
-
|
|
3766
|
-
|
|
3767
|
-
|
|
3768
|
-
|
|
4130
|
+
const res = await authFetch(
|
|
4131
|
+
ctx,
|
|
4132
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${BASE5}/skills`, {
|
|
4133
|
+
method: "POST",
|
|
4134
|
+
headers: buildHeaders(ctx),
|
|
4135
|
+
body: form2
|
|
4136
|
+
})
|
|
4137
|
+
);
|
|
3769
4138
|
const text = await res.text();
|
|
3770
4139
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
3771
4140
|
return text ? JSON.parse(text) : void 0;
|
|
3772
4141
|
}
|
|
3773
4142
|
async function updateSkillPackageZip(ctx, skillId, bytes, filename = "skill.zip") {
|
|
3774
|
-
applyTls(ctx);
|
|
3775
4143
|
const form2 = new FormData();
|
|
3776
4144
|
form2.set("file_type", "zip");
|
|
3777
4145
|
form2.set("file", new Blob([bytes]), filename);
|
|
3778
|
-
const res = await
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
3782
|
-
|
|
4146
|
+
const res = await authFetch(
|
|
4147
|
+
ctx,
|
|
4148
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${BASE5}/skills/${encodeURIComponent(skillId)}/package`, {
|
|
4149
|
+
method: "PUT",
|
|
4150
|
+
headers: buildHeaders(ctx),
|
|
4151
|
+
body: form2
|
|
4152
|
+
})
|
|
4153
|
+
);
|
|
3783
4154
|
const text = await res.text();
|
|
3784
4155
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
3785
4156
|
return text ? JSON.parse(text) : void 0;
|
|
3786
4157
|
}
|
|
3787
4158
|
async function downloadSkill(ctx, skillId) {
|
|
3788
|
-
|
|
3789
|
-
|
|
3790
|
-
|
|
3791
|
-
|
|
4159
|
+
const res = await authFetch(
|
|
4160
|
+
ctx,
|
|
4161
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${BASE5}/skills/${encodeURIComponent(skillId)}/download`, {
|
|
4162
|
+
headers: buildHeaders(ctx)
|
|
4163
|
+
})
|
|
4164
|
+
);
|
|
3792
4165
|
if (!res.ok) throw new HttpError(res.status, res.statusText, await res.text());
|
|
3793
4166
|
return new Uint8Array(await res.arrayBuffer());
|
|
3794
4167
|
}
|
|
@@ -3941,40 +4314,49 @@ import { basename as basename3 } from "path";
|
|
|
3941
4314
|
var PATH = "/api/agent-operator-integration/v1/tool-box";
|
|
3942
4315
|
var IMPEX = "/api/agent-operator-integration/v1/impex";
|
|
3943
4316
|
async function exportConfig(ctx, id, type = "toolbox") {
|
|
3944
|
-
|
|
3945
|
-
|
|
3946
|
-
|
|
3947
|
-
|
|
4317
|
+
const res = await authFetch(
|
|
4318
|
+
ctx,
|
|
4319
|
+
() => tlsFetch(
|
|
4320
|
+
ctx.insecure,
|
|
4321
|
+
`${ctx.baseUrl}${IMPEX}/export/${encodeURIComponent(type)}/${encodeURIComponent(id)}`,
|
|
4322
|
+
{
|
|
4323
|
+
headers: buildHeaders(ctx)
|
|
4324
|
+
}
|
|
4325
|
+
)
|
|
3948
4326
|
);
|
|
3949
4327
|
const buf = new Uint8Array(await res.arrayBuffer());
|
|
3950
4328
|
if (!res.ok) throw new HttpError(res.status, res.statusText, new TextDecoder().decode(buf));
|
|
3951
4329
|
return buf;
|
|
3952
4330
|
}
|
|
3953
4331
|
async function importConfig(ctx, filePath, type = "toolbox") {
|
|
3954
|
-
applyTls(ctx);
|
|
3955
4332
|
const buf = await readFile2(filePath);
|
|
3956
4333
|
const form2 = new FormData();
|
|
3957
4334
|
form2.append("data", new Blob([new Uint8Array(buf)]), basename3(filePath));
|
|
3958
|
-
const res = await
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
|
|
4335
|
+
const res = await authFetch(
|
|
4336
|
+
ctx,
|
|
4337
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${IMPEX}/import/${encodeURIComponent(type)}`, {
|
|
4338
|
+
method: "POST",
|
|
4339
|
+
headers: buildHeaders(ctx),
|
|
4340
|
+
body: form2
|
|
4341
|
+
})
|
|
4342
|
+
);
|
|
3963
4343
|
const text = await res.text();
|
|
3964
4344
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
3965
4345
|
return text ? JSON.parse(text) : text;
|
|
3966
4346
|
}
|
|
3967
4347
|
async function uploadTool(ctx, boxId, filePath, metadataType = "openapi") {
|
|
3968
|
-
applyTls(ctx);
|
|
3969
4348
|
const buf = await readFile2(filePath);
|
|
3970
4349
|
const form2 = new FormData();
|
|
3971
4350
|
form2.append("metadata_type", metadataType);
|
|
3972
4351
|
form2.append("data", new Blob([new Uint8Array(buf)]), basename3(filePath));
|
|
3973
|
-
const res = await
|
|
3974
|
-
|
|
3975
|
-
|
|
3976
|
-
|
|
3977
|
-
|
|
4352
|
+
const res = await authFetch(
|
|
4353
|
+
ctx,
|
|
4354
|
+
() => tlsFetch(ctx.insecure, `${ctx.baseUrl}${PATH}/${encodeURIComponent(boxId)}/tool`, {
|
|
4355
|
+
method: "POST",
|
|
4356
|
+
headers: buildHeaders(ctx),
|
|
4357
|
+
body: form2
|
|
4358
|
+
})
|
|
4359
|
+
);
|
|
3978
4360
|
const text = await res.text();
|
|
3979
4361
|
if (!res.ok) throw new HttpError(res.status, res.statusText, text);
|
|
3980
4362
|
return text ? JSON.parse(text) : text;
|
|
@@ -4138,7 +4520,7 @@ async function getSpansByConversation(ctx, conversationId, opts = {}) {
|
|
|
4138
4520
|
return (spans.hits?.hits ?? []).map((h) => h._source ?? {});
|
|
4139
4521
|
}
|
|
4140
4522
|
|
|
4141
|
-
// src/trace
|
|
4523
|
+
// src/bkn-trace/claude-judge.ts
|
|
4142
4524
|
import { spawn as spawn2, spawnSync as spawnSync2 } from "child_process";
|
|
4143
4525
|
var ClaudeJudgeError = class extends Error {
|
|
4144
4526
|
constructor(message, reason) {
|
|
@@ -4220,7 +4602,7 @@ async function judgeJson(prompt, opts = {}) {
|
|
|
4220
4602
|
return JSON.parse(extractJsonObject(text));
|
|
4221
4603
|
}
|
|
4222
4604
|
|
|
4223
|
-
// src/trace
|
|
4605
|
+
// src/bkn-trace/diagnose.ts
|
|
4224
4606
|
var KIND_MAP = {
|
|
4225
4607
|
chat: "llm",
|
|
4226
4608
|
text_completion: "llm",
|
|
@@ -4614,7 +4996,7 @@ function renderReportMarkdown(r) {
|
|
|
4614
4996
|
return lines.join("\n");
|
|
4615
4997
|
}
|
|
4616
4998
|
|
|
4617
|
-
// src/trace
|
|
4999
|
+
// src/bkn-trace/eval-set.ts
|
|
4618
5000
|
function hashId(s) {
|
|
4619
5001
|
let h = 5381;
|
|
4620
5002
|
for (let i = 0; i < s.length; i++) h = h * 33 ^ s.charCodeAt(i);
|
|
@@ -4878,19 +5260,29 @@ function vega(ctx) {
|
|
|
4878
5260
|
catalogs: (opts) => listCatalogs(ctx, opts),
|
|
4879
5261
|
getCatalog: (id) => getCatalog(ctx, id),
|
|
4880
5262
|
createCatalog: (req) => createCatalog(ctx, req),
|
|
5263
|
+
updateCatalog: (id, req) => updateCatalog(ctx, id, req),
|
|
4881
5264
|
enableCatalog: (id) => enableCatalog(ctx, id),
|
|
5265
|
+
disableCatalog: (id) => disableCatalog(ctx, id),
|
|
5266
|
+
deleteCatalog: (id) => deleteCatalog(ctx, id),
|
|
5267
|
+
testCatalogConnection: (id) => testCatalogConnection(ctx, id),
|
|
4882
5268
|
discoverCatalog: (id, wait = false) => discoverCatalog(ctx, id, wait),
|
|
4883
5269
|
catalogResources: (id, category) => listCatalogResources(ctx, id, category),
|
|
4884
5270
|
catalogHealth: (ids) => catalogHealthStatus(ctx, ids),
|
|
4885
5271
|
connectorTypes: () => listConnectorTypes(ctx),
|
|
4886
5272
|
connectorType: (type) => getConnectorType(ctx, type),
|
|
5273
|
+
/** Run SQL / OpenSearch DSL directly against a data source. */
|
|
5274
|
+
sql: (body) => runSql(ctx, body),
|
|
4887
5275
|
/** Build a resource's index. With `wait`, polls until terminal. */
|
|
4888
5276
|
build: async (req, opts = {}) => {
|
|
4889
5277
|
const task = await createBuildTask(ctx, req);
|
|
4890
5278
|
if (!opts.wait) return task;
|
|
4891
5279
|
return pollBuildTask(ctx, task.id, opts.timeoutMs ?? 3e5, opts.intervalMs ?? 2e3);
|
|
4892
5280
|
},
|
|
4893
|
-
buildStatus: (taskId) => getBuildTask(ctx, taskId)
|
|
5281
|
+
buildStatus: (taskId) => getBuildTask(ctx, taskId),
|
|
5282
|
+
buildTasks: (opts) => listBuildTasks(ctx, opts),
|
|
5283
|
+
deleteBuildTasks: (ids, opts) => deleteBuildTasks(ctx, ids, opts),
|
|
5284
|
+
startBuildTask: (taskId, opts) => startBuildTask(ctx, taskId, opts),
|
|
5285
|
+
stopBuildTask: (taskId) => stopBuildTask(ctx, taskId)
|
|
4894
5286
|
};
|
|
4895
5287
|
}
|
|
4896
5288
|
async function pollBuildTask(ctx, taskId, timeoutMs, intervalMs) {
|
|
@@ -4926,7 +5318,6 @@ function resolveUrl(ctx, path) {
|
|
|
4926
5318
|
return path.startsWith("http") ? path : `${ctx.baseUrl}${path.startsWith("/") ? "" : "/"}${path}`;
|
|
4927
5319
|
}
|
|
4928
5320
|
async function rawCall(ctx, path, opts = {}) {
|
|
4929
|
-
applyTls(ctx);
|
|
4930
5321
|
const url = resolveUrl(ctx, path);
|
|
4931
5322
|
const extra = {};
|
|
4932
5323
|
for (const h of opts.header ?? []) {
|
|
@@ -4952,18 +5343,69 @@ async function rawCall(ctx, path, opts = {}) {
|
|
|
4952
5343
|
`);
|
|
4953
5344
|
const controller = new AbortController();
|
|
4954
5345
|
const timer = setTimeout(() => controller.abort(), opts.timeoutMs ?? 3e4);
|
|
4955
|
-
const send = () => fetch(url, { method, headers: headersFor(), body, signal: controller.signal });
|
|
4956
5346
|
try {
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
5347
|
+
const res = await authFetch(
|
|
5348
|
+
ctx,
|
|
5349
|
+
() => tlsFetch(ctx.insecure, url, {
|
|
5350
|
+
method,
|
|
5351
|
+
headers: headersFor(),
|
|
5352
|
+
body,
|
|
5353
|
+
signal: controller.signal
|
|
5354
|
+
})
|
|
5355
|
+
);
|
|
4961
5356
|
return { status: res.status, statusText: res.statusText, body: await res.text() };
|
|
4962
5357
|
} finally {
|
|
4963
5358
|
clearTimeout(timer);
|
|
4964
5359
|
}
|
|
4965
5360
|
}
|
|
4966
5361
|
|
|
5362
|
+
// src/api/app-keys.ts
|
|
5363
|
+
var ME = "/api/safe/v1/me/api-keys";
|
|
5364
|
+
var ADMIN2 = "/api/safe/v1/admin/api-keys";
|
|
5365
|
+
function listMyApiKeys(ctx) {
|
|
5366
|
+
return request(ctx, ME);
|
|
5367
|
+
}
|
|
5368
|
+
function createMyApiKey(ctx, input) {
|
|
5369
|
+
return request(ctx, ME, {
|
|
5370
|
+
method: "POST",
|
|
5371
|
+
body: {
|
|
5372
|
+
name: input.name,
|
|
5373
|
+
...input.expiresAt ? { expires_at: input.expiresAt } : {},
|
|
5374
|
+
...input.neverExpire ? { never_expire: true } : {}
|
|
5375
|
+
}
|
|
5376
|
+
});
|
|
5377
|
+
}
|
|
5378
|
+
async function revokeMyApiKey(ctx, id) {
|
|
5379
|
+
await request(ctx, `${ME}/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
5380
|
+
}
|
|
5381
|
+
function regenerateMyApiKey(ctx, id) {
|
|
5382
|
+
return request(ctx, `${ME}/${encodeURIComponent(id)}/regenerate`, { method: "POST" });
|
|
5383
|
+
}
|
|
5384
|
+
function listApiKeysAdmin(ctx, ownerId) {
|
|
5385
|
+
return request(ctx, ADMIN2, { query: { owner_id: ownerId || void 0 } });
|
|
5386
|
+
}
|
|
5387
|
+
async function revokeApiKeyAdmin(ctx, id) {
|
|
5388
|
+
await request(ctx, `${ADMIN2}/${encodeURIComponent(id)}`, { method: "DELETE" });
|
|
5389
|
+
}
|
|
5390
|
+
|
|
5391
|
+
// src/resources/app-keys.ts
|
|
5392
|
+
function appKeys(ctx) {
|
|
5393
|
+
return {
|
|
5394
|
+
/** List the caller's own keys (no secrets). */
|
|
5395
|
+
list: () => listMyApiKeys(ctx),
|
|
5396
|
+
/** Issue a key — the result's `key` is the plaintext, shown only once. */
|
|
5397
|
+
create: (input) => createMyApiKey(ctx, input),
|
|
5398
|
+
/** Revoke one of the caller's keys (immediate). */
|
|
5399
|
+
revoke: (id) => revokeMyApiKey(ctx, id),
|
|
5400
|
+
/** Rotate a key in place — new plaintext (shown once); old secret dies now. */
|
|
5401
|
+
regenerate: (id) => regenerateMyApiKey(ctx, id),
|
|
5402
|
+
/** Admin: list all keys, or one owner's (adds `owner_user_id`). */
|
|
5403
|
+
adminList: (ownerId) => listApiKeysAdmin(ctx, ownerId),
|
|
5404
|
+
/** Admin: revoke any key. */
|
|
5405
|
+
adminRevoke: (id) => revokeApiKeyAdmin(ctx, id)
|
|
5406
|
+
};
|
|
5407
|
+
}
|
|
5408
|
+
|
|
4967
5409
|
// src/client.ts
|
|
4968
5410
|
function createClient(opts = {}) {
|
|
4969
5411
|
const ctx = resolveContext(opts);
|
|
@@ -4979,6 +5421,7 @@ function createClient(opts = {}) {
|
|
|
4979
5421
|
toolboxes: toolboxes(ctx),
|
|
4980
5422
|
trace: trace(ctx),
|
|
4981
5423
|
admin: admin(ctx),
|
|
5424
|
+
appKeys: appKeys(ctx),
|
|
4982
5425
|
vega: vega(ctx),
|
|
4983
5426
|
call: (path, callOpts) => rawCall(ctx, path, callOpts)
|
|
4984
5427
|
};
|
|
@@ -4987,7 +5430,6 @@ function createClient(opts = {}) {
|
|
|
4987
5430
|
// src/resources/auth.ts
|
|
4988
5431
|
var auth_exports = {};
|
|
4989
5432
|
__export(auth_exports, {
|
|
4990
|
-
attachNoAuth: () => attachNoAuth,
|
|
4991
5433
|
attachToken: () => attachToken,
|
|
4992
5434
|
currentToken: () => currentToken,
|
|
4993
5435
|
currentTokenFresh: () => currentTokenFresh,
|
|
@@ -5025,7 +5467,8 @@ function attachToken(baseUrl, accessToken, opts = {}) {
|
|
|
5025
5467
|
accessToken,
|
|
5026
5468
|
refreshToken: opts.refreshToken,
|
|
5027
5469
|
idToken: opts.idToken,
|
|
5028
|
-
|
|
5470
|
+
// Remember `-k` so a self-signed platform needn't repeat it every command.
|
|
5471
|
+
tlsInsecure: opts.insecure ? true : void 0,
|
|
5029
5472
|
// Prefer the account the user typed (-u); device tokens carry no username.
|
|
5030
5473
|
username: opts.username ?? decodeJwt(opts.idToken ?? accessToken)?.preferred_username
|
|
5031
5474
|
};
|
|
@@ -5033,33 +5476,40 @@ function attachToken(baseUrl, accessToken, opts = {}) {
|
|
|
5033
5476
|
setActivePlatform(url);
|
|
5034
5477
|
return { baseUrl: url, userId, username: usernameOf(token) };
|
|
5035
5478
|
}
|
|
5036
|
-
function
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5479
|
+
function targetUser(baseUrl, userOrName) {
|
|
5480
|
+
if (!userOrName) return activeUserId(baseUrl);
|
|
5481
|
+
const id = findUserId(baseUrl, userOrName);
|
|
5482
|
+
if (!id) {
|
|
5483
|
+
const known = usersOfPlatform(baseUrl).map((u) => u.username ?? u.userId).join(", ");
|
|
5484
|
+
throw new InputError(
|
|
5485
|
+
`No saved user '${userOrName}' on ${baseUrl}. Saved: ${known || "(none)"}.`
|
|
5486
|
+
);
|
|
5487
|
+
}
|
|
5488
|
+
return id;
|
|
5041
5489
|
}
|
|
5042
|
-
function status() {
|
|
5490
|
+
function status(opts = {}) {
|
|
5043
5491
|
const baseUrl = activePlatform();
|
|
5044
5492
|
if (!baseUrl) return { hasToken: false };
|
|
5045
|
-
const
|
|
5493
|
+
const userId = targetUser(baseUrl, opts.user);
|
|
5494
|
+
const token = readToken(baseUrl, userId);
|
|
5046
5495
|
return {
|
|
5047
5496
|
baseUrl,
|
|
5048
|
-
userId
|
|
5497
|
+
userId,
|
|
5049
5498
|
hasToken: token !== void 0,
|
|
5050
5499
|
username: usernameOf(token),
|
|
5051
5500
|
expired: token ? isExpired(decodeJwt(token.accessToken)) : void 0
|
|
5052
5501
|
};
|
|
5053
5502
|
}
|
|
5054
|
-
function currentToken() {
|
|
5503
|
+
function currentToken(opts = {}) {
|
|
5055
5504
|
const baseUrl = activePlatform();
|
|
5056
|
-
const token = baseUrl ? readToken(baseUrl) : void 0;
|
|
5505
|
+
const token = baseUrl ? readToken(baseUrl, targetUser(baseUrl, opts.user)) : void 0;
|
|
5057
5506
|
if (!token) throw new InputError("Not logged in. Run `openbkn auth login <url> --token <t>`.");
|
|
5058
5507
|
return token.accessToken;
|
|
5059
5508
|
}
|
|
5060
|
-
async function currentTokenFresh() {
|
|
5509
|
+
async function currentTokenFresh(opts = {}) {
|
|
5061
5510
|
const baseUrl = activePlatform();
|
|
5062
|
-
const
|
|
5511
|
+
const userId = baseUrl ? targetUser(baseUrl, opts.user) : void 0;
|
|
5512
|
+
const token = baseUrl ? readToken(baseUrl, userId) : void 0;
|
|
5063
5513
|
if (!baseUrl || !token) {
|
|
5064
5514
|
throw new InputError("Not logged in. Run `openbkn auth login <url> --token <t>`.");
|
|
5065
5515
|
}
|
|
@@ -5068,22 +5518,27 @@ async function currentTokenFresh() {
|
|
|
5068
5518
|
const needsRefresh = decodable ? isExpired(claims) : true;
|
|
5069
5519
|
if (token.refreshToken && needsRefresh) {
|
|
5070
5520
|
try {
|
|
5071
|
-
const t = await refreshAccessToken(baseUrl, token.refreshToken);
|
|
5072
|
-
writeToken(
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5521
|
+
const t = await refreshAccessToken(baseUrl, token.refreshToken, void 0, opts.insecure);
|
|
5522
|
+
writeToken(
|
|
5523
|
+
baseUrl,
|
|
5524
|
+
{
|
|
5525
|
+
...token,
|
|
5526
|
+
accessToken: t.accessToken,
|
|
5527
|
+
refreshToken: t.refreshToken ?? token.refreshToken,
|
|
5528
|
+
idToken: t.idToken ?? token.idToken
|
|
5529
|
+
},
|
|
5530
|
+
{ setActive: !opts.user }
|
|
5531
|
+
);
|
|
5078
5532
|
return t.accessToken;
|
|
5079
5533
|
} catch {
|
|
5080
5534
|
}
|
|
5081
5535
|
}
|
|
5082
5536
|
return token.accessToken;
|
|
5083
5537
|
}
|
|
5084
|
-
function whoami() {
|
|
5538
|
+
function whoami(opts = {}) {
|
|
5085
5539
|
const baseUrl = activePlatform();
|
|
5086
|
-
const
|
|
5540
|
+
const userId = baseUrl ? targetUser(baseUrl, opts.user) : void 0;
|
|
5541
|
+
const token = baseUrl ? readToken(baseUrl, userId) : void 0;
|
|
5087
5542
|
const claims = decodeJwt(token?.idToken ?? "") ?? decodeJwt(token?.accessToken ?? "");
|
|
5088
5543
|
if (!claims) {
|
|
5089
5544
|
throw new InputError(
|
|
@@ -5093,7 +5548,7 @@ function whoami() {
|
|
|
5093
5548
|
return {
|
|
5094
5549
|
...claims,
|
|
5095
5550
|
baseUrl: baseUrl ?? void 0,
|
|
5096
|
-
userId
|
|
5551
|
+
userId,
|
|
5097
5552
|
username: usernameOf(token)
|
|
5098
5553
|
};
|
|
5099
5554
|
}
|
|
@@ -5157,7 +5612,6 @@ export {
|
|
|
5157
5612
|
formatError,
|
|
5158
5613
|
isHeadless,
|
|
5159
5614
|
openBrowser,
|
|
5160
|
-
fetchAuthStatus,
|
|
5161
5615
|
deviceLogin,
|
|
5162
5616
|
credentialDeviceLogin,
|
|
5163
5617
|
request,
|
|
@@ -5172,6 +5626,7 @@ export {
|
|
|
5172
5626
|
writePlatformConfig,
|
|
5173
5627
|
resolveContext,
|
|
5174
5628
|
getUserSafe,
|
|
5629
|
+
changePasswordSafe,
|
|
5175
5630
|
admin,
|
|
5176
5631
|
agents,
|
|
5177
5632
|
context,
|
|
@@ -5188,7 +5643,6 @@ export {
|
|
|
5188
5643
|
vega,
|
|
5189
5644
|
createClient,
|
|
5190
5645
|
attachToken,
|
|
5191
|
-
attachNoAuth,
|
|
5192
5646
|
status,
|
|
5193
5647
|
currentToken,
|
|
5194
5648
|
currentTokenFresh,
|
|
@@ -5201,4 +5655,4 @@ export {
|
|
|
5201
5655
|
exportCreds,
|
|
5202
5656
|
auth_exports
|
|
5203
5657
|
};
|
|
5204
|
-
//# sourceMappingURL=chunk-
|
|
5658
|
+
//# sourceMappingURL=chunk-NC6DZ2AU.js.map
|