dsh-keys-manager 0.2.2 → 0.2.4
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/CHANGELOG.md +91 -19
- package/lib/client/format.d.ts +11 -1
- package/lib/client/styles.d.ts +1 -1
- package/lib/client/types.d.ts +14 -2
- package/lib/client/ui.d.ts +14 -0
- package/lib/client.js +333 -51
- package/lib/core.d.ts +7 -8
- package/lib/core.js +7 -0
- package/lib/core.js.map +1 -1
- package/lib/domain.d.ts +23 -0
- package/lib/index.d.ts +170 -23
- package/lib/index.js +1078 -165
- package/lib/index.js.map +1 -1
- package/locale/en.json +18 -2
- package/locale/zh.json +18 -2
- package/package.json +2 -2
- package/scripts/prepare-release.mjs +318 -128
package/lib/client.js
CHANGED
|
@@ -44,9 +44,20 @@ var zh = {
|
|
|
44
44
|
title: "\u5BC6\u94A5\u7BA1\u7406",
|
|
45
45
|
subtitle: "\u4E3A\u540C\u4E00\u4E2A Provider \u914D\u7F6E\u591A\u4E2A API Key\u3002\u5355\u4F1A\u8BDD\u56FA\u5B9A\u4F7F\u7528\u4E00\u4E2A Key\uFF0C\u65B0\u4F1A\u8BDD\u8F6E\u6362\uFF1B\u5931\u8D25\u540E\u81EA\u52A8\u51B7\u5374\u5E76\u6062\u590D\u3002",
|
|
46
46
|
search: "\u641C\u7D22 Provider\uFF08\u540D\u79F0\u3001ID \u6216\u73AF\u5883\u53D8\u91CF\uFF09",
|
|
47
|
+
filterAll: "\u5168\u90E8",
|
|
48
|
+
filterBuiltin: "\u5185\u7F6E",
|
|
49
|
+
filterPlugin: "\u63D2\u4EF6",
|
|
50
|
+
filterOauth: "\u652F\u6301 OAuth",
|
|
51
|
+
filterTransport: "\u4F20\u8F93",
|
|
52
|
+
filterGroup: "\u7B5B\u9009",
|
|
53
|
+
// Unattributed requests (I-000120, D8): the compass's fixed copy, shared
|
|
54
|
+
// with the filter plan's dictionary task — one pair, never a second.
|
|
55
|
+
unattributed: "{n} \u65E0\u5F52\u5C5E",
|
|
56
|
+
unattributedHint: "\u8BE5\u8DEF\u7531\u5728\u5F52\u5C5E\u8BFB\u53D6\u5C1A\u672A\u843D\u5730\uFF08\u6216\u5DF2\u5931\u8D25\uFF09\u671F\u95F4\u5E94\u7B54\u7684\u6D41\u5C1D\u8BD5\u6570\uFF1B\u5931\u8D25\u8F6C\u79FB\u91CD\u8BD5\u4F1A\u5404\u8BA1\u4E00\u6B21\uFF0C\u6545\u5355\u4E2A\u8BF7\u6C42\u53EF\u80FD\u88AB\u8BA1\u591A\u6B21\u3002\u8BFB\u53D6\u5B8C\u6210\u5F52\u5C5E\u540E\u6E05\u96F6\u3002",
|
|
47
57
|
managed: "\u5DF2\u63A5\u7BA1",
|
|
48
58
|
available: "\u53EF\u6DFB\u52A0 Providers",
|
|
49
59
|
managedEmpty: "\u8FD8\u6CA1\u6709\u63A5\u7BA1\u7684 Provider\u3002\u4ECE\u4E0B\u65B9\u9009\u62E9\u4E00\u4E2A\u5F00\u59CB\u3002",
|
|
60
|
+
managedFilteredEmpty: "\u5F53\u524D\u7B5B\u9009\u4E0B\u6CA1\u6709\u5DF2\u63A5\u7BA1\u7684 Provider\u3002",
|
|
50
61
|
availableEmpty: "\u6CA1\u6709\u5339\u914D\u7684 Provider\u3002",
|
|
51
62
|
keys: "\u5BC6\u94A5",
|
|
52
63
|
healthy: "\u53EF\u7528",
|
|
@@ -194,7 +205,8 @@ var zh = {
|
|
|
194
205
|
deleteAccountBodyNoKeys: "\u8FD9\u4F1A\u4ECE\u51ED\u8BC1\u5E93\u4E2D\u5220\u9664\u8BE5\u8D26\u6237\u4FDD\u5B58\u7684 OAuth \u6388\u6743\u3002\u8BE5\u8DEF\u7531\u6CA1\u6709 API-key \u6C60\uFF0C\u5220\u9664\u540E\u5C06\u505C\u6B62\u670D\u52A1\uFF0C\u76F4\u5230\u91CD\u65B0\u767B\u5F55\u8D26\u6237\u3002",
|
|
195
206
|
// Transport accounts (llm-omp-transports/<route>): managed beside the
|
|
196
207
|
// pi-ai pool, so the copy never promises a key-pool fallback.
|
|
197
|
-
|
|
208
|
+
transportEmpty: "\u8FD8\u6CA1\u6709\u4F20\u8F93\u8D26\u6237\u3002",
|
|
209
|
+
transportProviderHint: "\u8BE5\u8DEF\u7531\u7531\u4F20\u8F93\u63D2\u4EF6\u63D0\u4F9B\uFF0C\u51ED\u8BC1\u5C31\u5728\u672C\u5361\u7247\u4E2D\u7BA1\u7406\u3002",
|
|
198
210
|
transportTag: "\u4F20\u8F93",
|
|
199
211
|
transportSignIn: "\u767B\u5F55",
|
|
200
212
|
transportExpires: "\u6709\u6548\u671F\u81F3 {time}",
|
|
@@ -203,16 +215,32 @@ var zh = {
|
|
|
203
215
|
transportStatusNeedsReauth: "\u9700\u91CD\u65B0\u767B\u5F55",
|
|
204
216
|
transportStatusSignedOut: "\u672A\u767B\u5F55",
|
|
205
217
|
transportRemoveTitle: "\u79FB\u9664 {name} \u4F20\u8F93\u8D26\u6237\uFF1F",
|
|
206
|
-
transportRemoveBody: "\u8FD9\u4F1A\u4ECE\u51ED\u8BC1\u5E93\u4E2D\u5220\u9664\u8BE5\u4F20\u8F93\u8DEF\u7531\u4FDD\u5B58\u7684\u6388\u6743\uFF0C\u5E76\u53D6\u6D88\u4ECD\u5728\u8FDB\u884C\u7684\u767B\u5F55\uFF1B\u8DEF\u7531\u81EA\u8EAB\u4E0D\u4F1A\u91CD\u5EFA\u5B83\u3002\u8981\u6062\u590D\u670D\u52A1\u9700\u8981\u91CD\u65B0\u767B\u5F55\u3002"
|
|
218
|
+
transportRemoveBody: "\u8FD9\u4F1A\u4ECE\u51ED\u8BC1\u5E93\u4E2D\u5220\u9664\u8BE5\u4F20\u8F93\u8DEF\u7531\u4FDD\u5B58\u7684\u6388\u6743\uFF0C\u5E76\u53D6\u6D88\u4ECD\u5728\u8FDB\u884C\u7684\u767B\u5F55\uFF1B\u8DEF\u7531\u81EA\u8EAB\u4E0D\u4F1A\u91CD\u5EFA\u5B83\u3002\u8981\u6062\u590D\u670D\u52A1\u9700\u8981\u91CD\u65B0\u767B\u5F55\u3002",
|
|
219
|
+
// The route's model allow-list, edited in the transport card.
|
|
220
|
+
transportModels: "\u6A21\u578B",
|
|
221
|
+
transportModelsAll: "\u5168\u90E8\u6A21\u578B",
|
|
222
|
+
transportModelsSelected: "\u5DF2\u9009 {n}/{total}",
|
|
223
|
+
transportModelsLoading: "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u2026",
|
|
224
|
+
transportModelsClear: "\u6E05\u9664\u9009\u62E9",
|
|
225
|
+
transportModelsHint: "\u4E0D\u52FE\u9009\u4EFB\u4F55\u6A21\u578B\u8868\u793A\u4F7F\u7528\u5168\u90E8\u6A21\u578B\uFF1B\u4FDD\u5B58\u540E\u8BE5\u8DEF\u7531\u7684\u6A21\u578B\u5217\u8868\u968F\u4E4B\u6536\u7A84\u3002"
|
|
207
226
|
};
|
|
208
227
|
var en = {
|
|
209
228
|
nav: "Keys Manager",
|
|
210
229
|
title: "Keys Manager",
|
|
211
230
|
subtitle: "Give one provider several API keys. A session keeps one key; new sessions rotate; failures cool down and recover automatically.",
|
|
212
231
|
search: "Search providers by name, id, or environment variable",
|
|
232
|
+
filterAll: "All",
|
|
233
|
+
filterBuiltin: "Built-in",
|
|
234
|
+
filterPlugin: "Plugin",
|
|
235
|
+
filterOauth: "OAuth-capable",
|
|
236
|
+
filterTransport: "Transport",
|
|
237
|
+
filterGroup: "Filters",
|
|
238
|
+
unattributed: "{n} unattributed",
|
|
239
|
+
unattributedHint: "Stream attempts this route served with no account owner because its ownership read had not landed (or had failed). A failover retry is a new attempt, so one request can be counted more than once. The count clears when a read attributes the route.",
|
|
213
240
|
managed: "Managed",
|
|
214
241
|
available: "Available providers",
|
|
215
242
|
managedEmpty: "No managed providers yet. Adopt one below to start.",
|
|
243
|
+
managedFilteredEmpty: "No managed providers match the current filter.",
|
|
216
244
|
availableEmpty: "No matching providers.",
|
|
217
245
|
keys: "keys",
|
|
218
246
|
healthy: "healthy",
|
|
@@ -359,7 +387,8 @@ var en = {
|
|
|
359
387
|
deleteAccountBody: "This removes the account\u2019s stored OAuth grant from the credential store. If it is the active account, the provider route stops serving it and falls back to its API-key pool; the provider stays managed.",
|
|
360
388
|
deleteAccountBodyNoKeys: "This removes the account\u2019s stored OAuth grant from the credential store. This route has no API-key pool, so it stops serving requests until an account is signed in again.",
|
|
361
389
|
// Transport accounts — same values as locale/en.json.
|
|
362
|
-
|
|
390
|
+
transportEmpty: "No transport accounts yet.",
|
|
391
|
+
transportProviderHint: "Served by a transport plugin: its credential is managed inside this card.",
|
|
363
392
|
transportTag: "Transport",
|
|
364
393
|
transportSignIn: "Sign in",
|
|
365
394
|
transportExpires: "Expires {time}",
|
|
@@ -368,7 +397,14 @@ var en = {
|
|
|
368
397
|
transportStatusNeedsReauth: "Sign in again",
|
|
369
398
|
transportStatusSignedOut: "Not signed in",
|
|
370
399
|
transportRemoveTitle: "Remove the {name} transport account?",
|
|
371
|
-
transportRemoveBody: "This removes the grant stored for this transport route from the credential store and cancels a sign-in still in progress; the route does not recreate it. Sign in again to restore service."
|
|
400
|
+
transportRemoveBody: "This removes the grant stored for this transport route from the credential store and cancels a sign-in still in progress; the route does not recreate it. Sign in again to restore service.",
|
|
401
|
+
// The route's model allow-list, edited in the transport card.
|
|
402
|
+
transportModels: "Models",
|
|
403
|
+
transportModelsAll: "All models",
|
|
404
|
+
transportModelsSelected: "{n} of {total} selected",
|
|
405
|
+
transportModelsLoading: "Loading models\u2026",
|
|
406
|
+
transportModelsClear: "Clear selection",
|
|
407
|
+
transportModelsHint: "Leave every model unchecked to use the full catalog; saving narrows the list this route advertises."
|
|
372
408
|
};
|
|
373
409
|
var LOCALE_DICTS = { zh, en };
|
|
374
410
|
|
|
@@ -386,6 +422,13 @@ var CSS = `
|
|
|
386
422
|
.km-stat{display:flex;flex-direction:column;gap:2px;padding:11px 14px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-1)}
|
|
387
423
|
.km-stat strong{font-size:19px;line-height:1.15;font-weight:650;font-variant-numeric:tabular-nums}
|
|
388
424
|
.km-stat span{color:var(--dsw-alias-label-secondary);font-size:12px}
|
|
425
|
+
.km-filters{display:flex;flex-wrap:wrap;gap:8px;margin:0 0 12px}
|
|
426
|
+
.km-chip{display:inline-flex;align-items:center;gap:6px;padding:5px 11px;border:1px solid var(--dsw-alias-border-l1);border-radius:999px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-secondary);font:inherit;font-size:12.5px;cursor:pointer}
|
|
427
|
+
.km-chip:hover{background:var(--dsw-alias-bg-layer-2);color:var(--dsw-alias-label-primary)}
|
|
428
|
+
.km-chip:focus-visible{border-color:var(--dsw-alias-state-business-primary);box-shadow:0 0 0 2px color-mix(in srgb,var(--dsw-alias-state-business-primary) 20%,transparent)}
|
|
429
|
+
.km-chip-on{border-color:color-mix(in srgb,var(--dsw-alias-state-business-primary) 55%,var(--dsw-alias-border-l1));background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 12%,var(--dsw-alias-bg-layer-1));color:var(--dsw-alias-label-primary)}
|
|
430
|
+
.km-chip-count{font-size:11.5px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
|
|
431
|
+
.km-chip-on .km-chip-count{color:inherit}
|
|
389
432
|
.km-search{position:relative;display:flex;align-items:center;margin:0 0 20px}
|
|
390
433
|
.km-search-icon{position:absolute;left:12px;color:var(--dsw-alias-label-secondary);pointer-events:none}
|
|
391
434
|
.km-search-input{width:100%;box-sizing:border-box;padding:10px 38px 10px 36px;border:1px solid var(--dsw-alias-border-l1);border-radius:10px;background:var(--dsw-alias-bg-layer-1);color:var(--dsw-alias-label-primary);font:inherit;outline:none}
|
|
@@ -428,6 +471,19 @@ var CSS = `
|
|
|
428
471
|
.km-account-row{position:relative;display:grid;grid-template-columns:minmax(0,1.35fr) minmax(150px,.8fr) minmax(150px,.9fr) 32px;gap:10px;align-items:center;padding:10px 11px 10px 14px;border-top:1px solid var(--dsw-alias-border-l1)}
|
|
429
472
|
.km-account-row:first-child{border-top:0}
|
|
430
473
|
.km-account-row::before{content:'';position:absolute;left:0;top:12px;bottom:12px;width:2px;border-radius:1px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 55%,transparent)}
|
|
474
|
+
.km-transport-row{grid-template-columns:minmax(0,1.35fr) minmax(150px,.8fr) minmax(150px,.9fr) auto}
|
|
475
|
+
.km-transport-body{display:flex;flex-direction:column;gap:10px}
|
|
476
|
+
.km-models{border:1px solid var(--dsw-alias-border-l1);border-radius:9px;background:var(--dsw-alias-bg-layer-1)}
|
|
477
|
+
.km-models-head{display:flex;align-items:center;gap:7px;width:100%;padding:9px 11px;border:0;border-radius:9px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;font-weight:550;text-align:left;cursor:pointer}
|
|
478
|
+
.km-models-head:hover{background:var(--dsw-alias-bg-layer-2)}
|
|
479
|
+
.km-models-title{font-weight:600}
|
|
480
|
+
.km-models-body{display:flex;flex-direction:column;gap:9px;padding:9px 11px 11px;border-top:1px solid var(--dsw-alias-border-l1)}
|
|
481
|
+
.km-models-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:3px 10px;max-height:220px;overflow:auto}
|
|
482
|
+
.km-model-option{display:flex;align-items:center;gap:7px;min-width:0;font-size:12px;color:var(--dsw-alias-label-primary);cursor:pointer}
|
|
483
|
+
.km-model-option input{flex:0 0 auto;margin:0;accent-color:var(--dsw-alias-state-business-primary)}
|
|
484
|
+
.km-model-option span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
485
|
+
.km-models-actions{display:flex;justify-content:flex-end;gap:8px}
|
|
486
|
+
.km-models-failure{display:flex;flex-direction:column;gap:8px;align-items:flex-start}
|
|
431
487
|
.km-account-glyph{display:inline-flex;align-items:center;justify-content:center;width:22px;height:22px;flex:0 0 22px;border-radius:50%;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 14%,var(--dsw-alias-bg-layer-2));color:var(--dsw-alias-state-business-primary)}
|
|
432
488
|
.km-key-identity{min-width:0;display:flex;flex-direction:column;gap:2px}
|
|
433
489
|
.km-key-alias-line{display:flex;align-items:center;gap:6px;min-width:0}
|
|
@@ -437,7 +493,7 @@ var CSS = `
|
|
|
437
493
|
.km-key-last{display:flex;flex-direction:column;gap:2px;min-width:0}
|
|
438
494
|
.km-key-time{font-size:11.5px;color:var(--dsw-alias-label-secondary);font-variant-numeric:tabular-nums}
|
|
439
495
|
.km-key-time.km-warn{color:var(--dsw-alias-state-warn-primary)}
|
|
440
|
-
.km-key-actions{position:relative;display:flex;justify-content:flex-end}
|
|
496
|
+
.km-key-actions{position:relative;display:flex;justify-content:flex-end;gap:6px}
|
|
441
497
|
.km-status{display:inline-flex;align-items:center;gap:5px;padding:2px 7px;border-radius:999px;border:1px solid var(--dsw-alias-border-l1);background:var(--dsw-alias-bg-layer-2);font-size:11px;white-space:nowrap;color:var(--dsw-alias-label-secondary)}
|
|
442
498
|
.km-status-success{color:var(--dsw-alias-state-success-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-success-primary) 26%,var(--dsw-alias-border-l1));background:color-mix(in srgb,var(--dsw-alias-state-success-primary) 8%,transparent)}
|
|
443
499
|
.km-status-warn{color:var(--dsw-alias-state-warn-primary);border-color:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 30%,var(--dsw-alias-border-l1));background:color-mix(in srgb,var(--dsw-alias-state-warn-primary) 8%,transparent)}
|
|
@@ -553,6 +609,8 @@ select.km-input{appearance:auto}
|
|
|
553
609
|
.km-key-row,.km-account-row{grid-template-columns:minmax(0,1fr) 32px;gap:6px}
|
|
554
610
|
.km-key-status,.km-key-last{grid-column:1;padding-left:0}
|
|
555
611
|
.km-key-actions{grid-column:2;grid-row:1}
|
|
612
|
+
.km-transport-row{grid-template-columns:minmax(0,1fr) auto}
|
|
613
|
+
.km-transport-row .km-key-actions{justify-content:flex-end;flex-wrap:wrap}
|
|
556
614
|
.km-settings-grid{grid-template-columns:1fr}
|
|
557
615
|
.km-form-grid{grid-template-columns:1fr}
|
|
558
616
|
.km-provider-side .km-status{display:none}
|
|
@@ -614,6 +672,37 @@ function wrapComponent(Component, runtime) {
|
|
|
614
672
|
};
|
|
615
673
|
}
|
|
616
674
|
|
|
675
|
+
// src/client/format.ts
|
|
676
|
+
function cooldownMinutes(ms) {
|
|
677
|
+
return ms / 6e4;
|
|
678
|
+
}
|
|
679
|
+
function cooldownMs(minutes) {
|
|
680
|
+
return Math.max(0.5, minutes) * 6e4;
|
|
681
|
+
}
|
|
682
|
+
function graceMinutes(ms) {
|
|
683
|
+
return ms / 6e4;
|
|
684
|
+
}
|
|
685
|
+
function graceMs(minutes) {
|
|
686
|
+
return Math.max(0, minutes) * 6e4;
|
|
687
|
+
}
|
|
688
|
+
function shapeTransportModels(value) {
|
|
689
|
+
const record = value !== null && typeof value === "object" ? value : {};
|
|
690
|
+
const catalog = [];
|
|
691
|
+
if (Array.isArray(record.catalog)) {
|
|
692
|
+
for (const row of record.catalog) {
|
|
693
|
+
if (row === null || typeof row !== "object") continue;
|
|
694
|
+
const { id, name } = row;
|
|
695
|
+
if (typeof id === "string" && id.length > 0 && typeof name === "string") catalog.push({ id, name });
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
const models = Array.isArray(record.models) ? record.models.filter((id) => typeof id === "string") : [];
|
|
699
|
+
return { catalog, models };
|
|
700
|
+
}
|
|
701
|
+
function modelPickerRows(view) {
|
|
702
|
+
const selected = new Set(view.models);
|
|
703
|
+
return view.catalog.map((row) => ({ id: row.id, name: row.name, selected: selected.has(row.id) }));
|
|
704
|
+
}
|
|
705
|
+
|
|
617
706
|
// src/client/store.ts
|
|
618
707
|
function messageOf(error) {
|
|
619
708
|
if (error instanceof Error && error.message.length > 0) return error.message;
|
|
@@ -713,6 +802,9 @@ function createStore(ctx) {
|
|
|
713
802
|
const attemptOutcome = (value) => {
|
|
714
803
|
return { ok: true, value: value ?? null };
|
|
715
804
|
};
|
|
805
|
+
const modelsOutcome = (value) => {
|
|
806
|
+
return { ok: true, value: shapeTransportModels(value) };
|
|
807
|
+
};
|
|
716
808
|
const testOutcome = (value) => {
|
|
717
809
|
const result = value ?? {};
|
|
718
810
|
return {
|
|
@@ -801,6 +893,14 @@ function createStore(ctx) {
|
|
|
801
893
|
removeTransportAccount(route) {
|
|
802
894
|
return send("removeTransportAccount", { provider: route }, stateOutcome);
|
|
803
895
|
},
|
|
896
|
+
async transportModels(route) {
|
|
897
|
+
const result = await rpcRead("transportModels", { provider: route });
|
|
898
|
+
if (!result.ok) return { ok: false, error: result.error.message };
|
|
899
|
+
return { ok: true, value: shapeTransportModels(result.value) };
|
|
900
|
+
},
|
|
901
|
+
saveTransportModels(route, models) {
|
|
902
|
+
return send("saveTransportModels", { provider: route, models }, modelsOutcome);
|
|
903
|
+
},
|
|
804
904
|
tick() {
|
|
805
905
|
update({ now: Date.now() });
|
|
806
906
|
if (snapshot.status === "ready" && snapshot.busy === null) void this.load({ keepError: true });
|
|
@@ -814,22 +914,6 @@ function createStore(ctx) {
|
|
|
814
914
|
|
|
815
915
|
// src/client/ui.ts
|
|
816
916
|
var import_react2 = __toESM(require("react"), 1);
|
|
817
|
-
|
|
818
|
-
// src/client/format.ts
|
|
819
|
-
function cooldownMinutes(ms) {
|
|
820
|
-
return ms / 6e4;
|
|
821
|
-
}
|
|
822
|
-
function cooldownMs(minutes) {
|
|
823
|
-
return Math.max(0.5, minutes) * 6e4;
|
|
824
|
-
}
|
|
825
|
-
function graceMinutes(ms) {
|
|
826
|
-
return ms / 6e4;
|
|
827
|
-
}
|
|
828
|
-
function graceMs(minutes) {
|
|
829
|
-
return Math.max(0, minutes) * 6e4;
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
// src/client/ui.ts
|
|
833
917
|
var h = import_react2.default.createElement;
|
|
834
918
|
function cx(...values) {
|
|
835
919
|
return values.filter(Boolean).join(" ");
|
|
@@ -873,6 +957,37 @@ function providerInitial(provider) {
|
|
|
873
957
|
function oauthCapable(provider) {
|
|
874
958
|
return provider.nativeAuth?.oauth === true && provider.accountSupported !== false;
|
|
875
959
|
}
|
|
960
|
+
function originOf(provider) {
|
|
961
|
+
return provider.origin ?? (provider.extra ? "plugin" : "dsh");
|
|
962
|
+
}
|
|
963
|
+
var FILTER_CHIPS = [
|
|
964
|
+
{ value: "all", label: "filterAll" },
|
|
965
|
+
{ value: "builtin", label: "filterBuiltin" },
|
|
966
|
+
{ value: "plugin", label: "filterPlugin" },
|
|
967
|
+
{ value: "oauth", label: "filterOauth" },
|
|
968
|
+
{ value: "transport", label: "filterTransport" }
|
|
969
|
+
];
|
|
970
|
+
function matchesFilter(provider, filter) {
|
|
971
|
+
switch (filter) {
|
|
972
|
+
case "transport":
|
|
973
|
+
return provider.transport === true;
|
|
974
|
+
case "builtin":
|
|
975
|
+
return provider.transport !== true && originOf(provider) === "dsh";
|
|
976
|
+
case "plugin":
|
|
977
|
+
return provider.transport !== true && originOf(provider) === "plugin";
|
|
978
|
+
case "oauth":
|
|
979
|
+
return provider.transport !== true && oauthCapable(provider);
|
|
980
|
+
default:
|
|
981
|
+
return true;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function orphanTransportAccounts(providers, transportAccounts) {
|
|
985
|
+
return transportAccounts.filter((account) => !providers.some((provider) => provider.transport === true && provider.provider === account.id));
|
|
986
|
+
}
|
|
987
|
+
function managedEntryCount(providers, transportAccounts) {
|
|
988
|
+
const cards = providers.filter((provider) => provider.managed || provider.transport === true).length;
|
|
989
|
+
return cards + orphanTransportAccounts(providers, transportAccounts).length;
|
|
990
|
+
}
|
|
876
991
|
function accountIdentityOf(key, provider) {
|
|
877
992
|
const oauth = key.oauth;
|
|
878
993
|
if (oauth !== null && oauth !== void 0) {
|
|
@@ -1648,7 +1763,118 @@ function TransportAccountRow({ account }) {
|
|
|
1648
1763
|
}) : null
|
|
1649
1764
|
);
|
|
1650
1765
|
}
|
|
1651
|
-
function
|
|
1766
|
+
function TransportModels({ route }) {
|
|
1767
|
+
const runtime = useRuntime();
|
|
1768
|
+
const t = useT();
|
|
1769
|
+
const [open, setOpen] = import_react2.default.useState(false);
|
|
1770
|
+
const [view, setView] = import_react2.default.useState(null);
|
|
1771
|
+
const [draft, setDraft] = import_react2.default.useState(/* @__PURE__ */ new Set());
|
|
1772
|
+
const [busy, setBusy] = import_react2.default.useState(false);
|
|
1773
|
+
const [error, setError] = import_react2.default.useState(null);
|
|
1774
|
+
const loading = import_react2.default.useRef(false);
|
|
1775
|
+
async function load() {
|
|
1776
|
+
if (loading.current) return;
|
|
1777
|
+
loading.current = true;
|
|
1778
|
+
setError(null);
|
|
1779
|
+
const result = await runtime.store.transportModels(route);
|
|
1780
|
+
loading.current = false;
|
|
1781
|
+
if (!result.ok) {
|
|
1782
|
+
setError(result.error);
|
|
1783
|
+
return;
|
|
1784
|
+
}
|
|
1785
|
+
setView(result.value);
|
|
1786
|
+
setDraft(new Set(result.value.models));
|
|
1787
|
+
}
|
|
1788
|
+
function toggle() {
|
|
1789
|
+
const next = !open;
|
|
1790
|
+
setOpen(next);
|
|
1791
|
+
if (next && view === null) void load();
|
|
1792
|
+
}
|
|
1793
|
+
function toggleModel(id) {
|
|
1794
|
+
setDraft((current) => {
|
|
1795
|
+
const next = new Set(current);
|
|
1796
|
+
if (next.has(id)) next.delete(id);
|
|
1797
|
+
else next.add(id);
|
|
1798
|
+
return next;
|
|
1799
|
+
});
|
|
1800
|
+
}
|
|
1801
|
+
async function save() {
|
|
1802
|
+
setBusy(true);
|
|
1803
|
+
setError(null);
|
|
1804
|
+
const result = await runtime.store.saveTransportModels(route, [...draft]);
|
|
1805
|
+
setBusy(false);
|
|
1806
|
+
if (!result.ok) {
|
|
1807
|
+
setError(result.error);
|
|
1808
|
+
return;
|
|
1809
|
+
}
|
|
1810
|
+
setView(result.value);
|
|
1811
|
+
setDraft(new Set(result.value.models));
|
|
1812
|
+
}
|
|
1813
|
+
const rows = view === null ? [] : modelPickerRows(view);
|
|
1814
|
+
const errorLine = error === null ? null : h("div", { className: "km-inline-error", role: "alert" }, error);
|
|
1815
|
+
return h(
|
|
1816
|
+
"div",
|
|
1817
|
+
{ className: "km-models" },
|
|
1818
|
+
h(
|
|
1819
|
+
"button",
|
|
1820
|
+
{
|
|
1821
|
+
type: "button",
|
|
1822
|
+
className: "km-models-head",
|
|
1823
|
+
onClick: toggle,
|
|
1824
|
+
"aria-expanded": open
|
|
1825
|
+
},
|
|
1826
|
+
h(Icon, { name: "chevron", size: 14, className: cx("km-chevron", open && "km-chevron-open") }),
|
|
1827
|
+
h("span", { className: "km-models-title" }, t("transportModels")),
|
|
1828
|
+
view === null ? null : h(
|
|
1829
|
+
"span",
|
|
1830
|
+
{ className: "km-muted" },
|
|
1831
|
+
draft.size === 0 ? t("transportModelsAll") : t("transportModelsSelected", { n: draft.size, total: view.catalog.length })
|
|
1832
|
+
)
|
|
1833
|
+
),
|
|
1834
|
+
open ? h(
|
|
1835
|
+
"div",
|
|
1836
|
+
{ className: "km-models-body" },
|
|
1837
|
+
// A failed load leaves no view: showing the loading line next to the
|
|
1838
|
+
// error would claim a request that already finished, and Save must stay
|
|
1839
|
+
// off without a view so a failed read cannot clear the saved selection.
|
|
1840
|
+
// A failed save keeps the loaded view and reports above the grid.
|
|
1841
|
+
view === null ? null : errorLine,
|
|
1842
|
+
view === null ? error !== null ? h(
|
|
1843
|
+
"div",
|
|
1844
|
+
{ className: "km-models-failure" },
|
|
1845
|
+
errorLine,
|
|
1846
|
+
h(Button, { size: "small", variant: "primary", onClick: () => void load() }, t("reload"))
|
|
1847
|
+
) : h("div", { className: "km-muted" }, t("transportModelsLoading")) : h("div", { className: "km-models-grid" }, rows.map((row) => h(
|
|
1848
|
+
"label",
|
|
1849
|
+
{ key: row.id, className: "km-model-option" },
|
|
1850
|
+
h("input", {
|
|
1851
|
+
type: "checkbox",
|
|
1852
|
+
checked: draft.has(row.id),
|
|
1853
|
+
onChange: () => toggleModel(row.id),
|
|
1854
|
+
disabled: busy
|
|
1855
|
+
}),
|
|
1856
|
+
h("span", null, row.name)
|
|
1857
|
+
))),
|
|
1858
|
+
h(
|
|
1859
|
+
"div",
|
|
1860
|
+
{ className: "km-models-actions" },
|
|
1861
|
+
h(
|
|
1862
|
+
Button,
|
|
1863
|
+
{ size: "small", variant: "primary", onClick: () => void save(), disabled: busy || view === null },
|
|
1864
|
+
busy ? t("saving") : t("save")
|
|
1865
|
+
),
|
|
1866
|
+
h(Button, {
|
|
1867
|
+
size: "small",
|
|
1868
|
+
variant: "ghost",
|
|
1869
|
+
onClick: () => setDraft(/* @__PURE__ */ new Set()),
|
|
1870
|
+
disabled: busy || view === null || draft.size === 0
|
|
1871
|
+
}, t("transportModelsClear"))
|
|
1872
|
+
),
|
|
1873
|
+
h("div", { className: "km-field-hint" }, t("transportModelsHint"))
|
|
1874
|
+
) : null
|
|
1875
|
+
);
|
|
1876
|
+
}
|
|
1877
|
+
function ProviderCard({ provider, expanded, onToggle, now, transportAccount }) {
|
|
1652
1878
|
const runtime = useRuntime();
|
|
1653
1879
|
const t = useT();
|
|
1654
1880
|
const [adding, setAdding] = import_react2.default.useState(false);
|
|
@@ -1663,11 +1889,15 @@ function ProviderCard({ provider, expanded, onToggle, now }) {
|
|
|
1663
1889
|
const keyCount = provider.keyCount;
|
|
1664
1890
|
const warning = provider.warning;
|
|
1665
1891
|
const isExtra = provider.extra;
|
|
1666
|
-
const
|
|
1667
|
-
const
|
|
1892
|
+
const transport = provider.transport === true;
|
|
1893
|
+
const origin = originOf(provider);
|
|
1894
|
+
const originLabel = transport || origin === "plugin" ? t("pluginBuiltin") : origin === "dsh" ? t("dshBuiltin") : t("customProvider");
|
|
1668
1895
|
const providerMeta = [
|
|
1669
1896
|
provider.provider,
|
|
1670
|
-
|
|
1897
|
+
// `active`/`configured` are read off the route's profile or the host's
|
|
1898
|
+
// provider list, neither of which describes a transport route: its state
|
|
1899
|
+
// is the account row it carries (signed out when the host lists none).
|
|
1900
|
+
transport ? t(transportStatusKey(transportAccount?.status ?? "signed-out")) : provider.active ? t("active") : provider.configured ? t("configured") : t("notConfigured"),
|
|
1671
1901
|
provider.api ?? null
|
|
1672
1902
|
].filter((value) => Boolean(value));
|
|
1673
1903
|
async function adopt() {
|
|
@@ -1719,7 +1949,7 @@ function ProviderCard({ provider, expanded, onToggle, now }) {
|
|
|
1719
1949
|
const adoptable = provider.supported || accountAdoptable;
|
|
1720
1950
|
return h(
|
|
1721
1951
|
"div",
|
|
1722
|
-
{ className: cx("km-card", "km-provider", expanded && "km-provider-open", managed && "km-provider-managed") },
|
|
1952
|
+
{ className: cx("km-card", "km-provider", expanded && "km-provider-open", (managed || transport) && "km-provider-managed") },
|
|
1723
1953
|
h(
|
|
1724
1954
|
"button",
|
|
1725
1955
|
{
|
|
@@ -1737,8 +1967,9 @@ function ProviderCard({ provider, expanded, onToggle, now }) {
|
|
|
1737
1967
|
{ className: "km-provider-title-line" },
|
|
1738
1968
|
h("span", { className: "km-provider-name" }, provider.displayName || provider.provider),
|
|
1739
1969
|
h("span", { className: "km-tag" }, originLabel),
|
|
1970
|
+
transport ? h("span", { className: "km-tag km-tag-accent" }, t("transportTag")) : null,
|
|
1740
1971
|
managed ? h("span", { className: "km-tag km-tag-accent" }, t("managedBadge")) : null,
|
|
1741
|
-
!managed && !provider.supported && !accountAdoptable ? h("span", { className: "km-tag km-tag-warn" }, t("unsupported")) : null
|
|
1972
|
+
!transport && !managed && !provider.supported && !accountAdoptable ? h("span", { className: "km-tag km-tag-warn" }, t("unsupported")) : null
|
|
1742
1973
|
),
|
|
1743
1974
|
h(
|
|
1744
1975
|
"span",
|
|
@@ -1752,7 +1983,14 @@ function ProviderCard({ provider, expanded, onToggle, now }) {
|
|
|
1752
1983
|
h(
|
|
1753
1984
|
"span",
|
|
1754
1985
|
{ className: "km-provider-side" },
|
|
1755
|
-
|
|
1986
|
+
// I-000120 / D8: requests this route served without an attributed
|
|
1987
|
+
// account. Rendered only above zero, and the visible label carries the
|
|
1988
|
+
// count so it is the accessible name; the hint stays a description.
|
|
1989
|
+
(provider.unattributedRequests ?? 0) > 0 ? h("span", {
|
|
1990
|
+
className: "km-tag km-tag-warn km-unattributed",
|
|
1991
|
+
title: t("unattributedHint")
|
|
1992
|
+
}, t("unattributed", { n: provider.unattributedRequests ?? 0 })) : null,
|
|
1993
|
+
transport ? null : managed ? h("span", { className: "km-count" }, countText(t, keyCount, "providerKeyOne", "providerKeys")) : h("span", { className: "km-count km-muted" }, adoptable ? t("unmanaged") : t("unsupported")),
|
|
1756
1994
|
managed ? h(StatusPill, { status: provider.status, t }) : null,
|
|
1757
1995
|
h(Icon, { name: "chevron", size: 16, className: cx("km-chevron", expanded && "km-chevron-open") })
|
|
1758
1996
|
)
|
|
@@ -1762,7 +2000,15 @@ function ProviderCard({ provider, expanded, onToggle, now }) {
|
|
|
1762
2000
|
{ className: "km-provider-body" },
|
|
1763
2001
|
error !== null ? h("div", { className: "km-inline-error", role: "alert" }, error) : null,
|
|
1764
2002
|
warning !== void 0 || broken ? h(Notice, { tone: "warn", title: t("warning") }, broken ? t("bindingBroken") : warning) : null,
|
|
1765
|
-
|
|
2003
|
+
// A transport route has no adopt step and no key pool: its whole
|
|
2004
|
+
// credential surface is the one account row its own plugin serves, plus
|
|
2005
|
+
// the model allow-list its adapter advertises.
|
|
2006
|
+
transport ? h(
|
|
2007
|
+
"div",
|
|
2008
|
+
{ className: "km-transport-body" },
|
|
2009
|
+
transportAccount !== void 0 ? h("div", { className: "km-keys" }, h(TransportAccountRow, { account: transportAccount })) : h("div", { className: "km-muted" }, t("transportProviderHint")),
|
|
2010
|
+
h(TransportModels, { route: provider.provider })
|
|
2011
|
+
) : !managed ? h(
|
|
1766
2012
|
"div",
|
|
1767
2013
|
{ className: "km-adopt" },
|
|
1768
2014
|
h(
|
|
@@ -2178,6 +2424,7 @@ function KeysManagerBody() {
|
|
|
2178
2424
|
const state = snapshot.state;
|
|
2179
2425
|
const now = snapshot.now;
|
|
2180
2426
|
const [query, setQuery] = import_react2.default.useState("");
|
|
2427
|
+
const [filter, setFilter] = import_react2.default.useState("all");
|
|
2181
2428
|
const [showAllAvailable, setShowAllAvailable] = import_react2.default.useState(false);
|
|
2182
2429
|
const [expanded, setExpanded] = import_react2.default.useState(() => /* @__PURE__ */ new Set());
|
|
2183
2430
|
const loadedRef = import_react2.default.useRef(false);
|
|
@@ -2201,9 +2448,23 @@ function KeysManagerBody() {
|
|
|
2201
2448
|
].filter((value) => Boolean(value)).join(" ").toLowerCase();
|
|
2202
2449
|
return haystack.includes(normalizedQuery);
|
|
2203
2450
|
};
|
|
2204
|
-
const managed = providers.filter((provider) => provider.managed && matches(provider));
|
|
2205
|
-
const available = providers.filter((provider) => !provider.managed && matches(provider));
|
|
2451
|
+
const managed = providers.filter((provider) => (provider.managed || provider.transport === true) && matchesFilter(provider, filter) && matches(provider));
|
|
2452
|
+
const available = providers.filter((provider) => !provider.managed && provider.transport !== true && matchesFilter(provider, filter) && matches(provider));
|
|
2206
2453
|
const visibleAvailable = showAllAvailable || normalizedQuery.length > 0 ? available : available.slice(0, 12);
|
|
2454
|
+
const matchesAccount = (account) => {
|
|
2455
|
+
if (normalizedQuery.length === 0) return true;
|
|
2456
|
+
const haystack = [account.id, account.scope, account.displayName].join(" ").toLowerCase();
|
|
2457
|
+
return haystack.includes(normalizedQuery);
|
|
2458
|
+
};
|
|
2459
|
+
const orphanAccounts = orphanTransportAccounts(providers, transportAccounts).filter(matchesAccount);
|
|
2460
|
+
const visibleOrphans = filter === "all" || filter === "transport" ? orphanAccounts : [];
|
|
2461
|
+
const filterCount = (value) => {
|
|
2462
|
+
const searchable = providers.filter(matches);
|
|
2463
|
+
if (value === "all") return searchable.length + orphanAccounts.length;
|
|
2464
|
+
if (value === "transport") return searchable.filter((provider) => provider.transport === true).length + orphanAccounts.length;
|
|
2465
|
+
return searchable.filter((provider) => matchesFilter(provider, value)).length;
|
|
2466
|
+
};
|
|
2467
|
+
const managedHiddenByChip = filter !== "all" && providers.some((provider) => provider.managed || provider.transport === true);
|
|
2207
2468
|
function toggle(provider) {
|
|
2208
2469
|
setExpanded((current) => {
|
|
2209
2470
|
const next = new Set(current);
|
|
@@ -2242,7 +2503,7 @@ function KeysManagerBody() {
|
|
|
2242
2503
|
h(
|
|
2243
2504
|
"div",
|
|
2244
2505
|
{ className: "km-summary" },
|
|
2245
|
-
h("div", { className: "km-stat" }, h("strong", null, loading ? "\u2014" :
|
|
2506
|
+
h("div", { className: "km-stat" }, h("strong", null, loading ? "\u2014" : managedEntryCount(providers, transportAccounts)), h("span", null, t("managed"))),
|
|
2246
2507
|
h("div", { className: "km-stat" }, h("strong", null, loading ? "\u2014" : state?.keyCount ?? 0), h("span", null, t("keys"))),
|
|
2247
2508
|
h("div", { className: "km-stat" }, h("strong", null, loading ? "\u2014" : state?.healthyKeyCount ?? 0), h("span", null, t("healthy"))),
|
|
2248
2509
|
h("div", { className: "km-stat" }, h("strong", null, loading ? "\u2014" : state?.coolingKeyCount ?? 0), h("span", null, t("cooling")))
|
|
@@ -2259,6 +2520,26 @@ function KeysManagerBody() {
|
|
|
2259
2520
|
}, h(Icon, { name: "refresh", size: 14 }), t("refresh"))
|
|
2260
2521
|
)
|
|
2261
2522
|
),
|
|
2523
|
+
// Quick filter: single select, view state only, composed with the text
|
|
2524
|
+
// search below. Counts are derived per predicate from the snapshot.
|
|
2525
|
+
!loading && !failed ? h("div", {
|
|
2526
|
+
className: "km-filters",
|
|
2527
|
+
role: "group",
|
|
2528
|
+
"aria-label": t("filterGroup")
|
|
2529
|
+
}, FILTER_CHIPS.map(
|
|
2530
|
+
(chip) => h(
|
|
2531
|
+
"button",
|
|
2532
|
+
{
|
|
2533
|
+
key: chip.value,
|
|
2534
|
+
type: "button",
|
|
2535
|
+
className: cx("km-chip", `km-chip-${chip.value}`, filter === chip.value && "km-chip-on"),
|
|
2536
|
+
"aria-pressed": filter === chip.value,
|
|
2537
|
+
onClick: () => setFilter(chip.value)
|
|
2538
|
+
},
|
|
2539
|
+
h("span", { className: "km-chip-label" }, t(chip.label)),
|
|
2540
|
+
h("span", { className: "km-chip-count" }, filterCount(chip.value))
|
|
2541
|
+
)
|
|
2542
|
+
)) : null,
|
|
2262
2543
|
h(
|
|
2263
2544
|
"div",
|
|
2264
2545
|
{ className: "km-search" },
|
|
@@ -2288,15 +2569,29 @@ function KeysManagerBody() {
|
|
|
2288
2569
|
"div",
|
|
2289
2570
|
{ className: "km-section-head" },
|
|
2290
2571
|
h("h2", { className: "km-section-title" }, t("managed")),
|
|
2291
|
-
|
|
2572
|
+
// What is below it, like the available section: the tile above keeps
|
|
2573
|
+
// the global total.
|
|
2574
|
+
h("span", { className: "km-section-count" }, managed.length + visibleOrphans.length)
|
|
2292
2575
|
),
|
|
2293
|
-
|
|
2576
|
+
// The placeholder only when the section renders neither a card nor a row
|
|
2577
|
+
// the active chip selects.
|
|
2578
|
+
managed.length === 0 && visibleOrphans.length === 0 ? h("div", { className: "km-empty" }, h(Icon, { name: "key", size: 20 }), h(
|
|
2579
|
+
"span",
|
|
2580
|
+
null,
|
|
2581
|
+
normalizedQuery.length > 0 ? t("noSearch") : filter === "transport" ? t("transportEmpty") : managedHiddenByChip ? t("managedFilteredEmpty") : t("managedEmpty")
|
|
2582
|
+
)) : null,
|
|
2583
|
+
managed.length > 0 ? h("div", { className: "km-provider-list" }, managed.map((provider) => h(ProviderCard, {
|
|
2294
2584
|
key: provider.provider,
|
|
2295
2585
|
provider,
|
|
2296
2586
|
now,
|
|
2587
|
+
transportAccount: provider.transport === true ? transportAccounts.find((account) => account.id === provider.provider) : void 0,
|
|
2297
2588
|
expanded: expanded.has(provider.provider),
|
|
2298
2589
|
onToggle: () => toggle(provider.provider)
|
|
2299
|
-
})))
|
|
2590
|
+
}))) : null,
|
|
2591
|
+
visibleOrphans.length > 0 ? h("div", { className: "km-provider-list" }, visibleOrphans.map((account) => h(TransportAccountRow, {
|
|
2592
|
+
key: account.scope,
|
|
2593
|
+
account
|
|
2594
|
+
}))) : null
|
|
2300
2595
|
) : null,
|
|
2301
2596
|
!loading && !failed ? h(
|
|
2302
2597
|
"section",
|
|
@@ -2324,20 +2619,6 @@ function KeysManagerBody() {
|
|
|
2324
2619
|
h(Button, { variant: "ghost", size: "small", onClick: () => setShowAllAvailable(false) }, t("showLess"))
|
|
2325
2620
|
) : null
|
|
2326
2621
|
) : null,
|
|
2327
|
-
!loading && !failed && transportAccounts.length > 0 ? h(
|
|
2328
|
-
"section",
|
|
2329
|
-
{ className: "km-section" },
|
|
2330
|
-
h(
|
|
2331
|
-
"div",
|
|
2332
|
-
{ className: "km-section-head" },
|
|
2333
|
-
h("h2", { className: "km-section-title" }, t("transportAccounts")),
|
|
2334
|
-
h("span", { className: "km-section-count" }, transportAccounts.length)
|
|
2335
|
-
),
|
|
2336
|
-
h("div", { className: "km-provider-list" }, transportAccounts.map((account) => h(TransportAccountRow, {
|
|
2337
|
-
key: account.scope,
|
|
2338
|
-
account
|
|
2339
|
-
})))
|
|
2340
|
-
) : null,
|
|
2341
2622
|
!loading && !failed ? h("section", { className: "km-section" }, h(SettingsCard)) : null,
|
|
2342
2623
|
h(
|
|
2343
2624
|
"footer",
|
|
@@ -2353,8 +2634,9 @@ function KeysManagerCard({ view }) {
|
|
|
2353
2634
|
if (view === "summary") {
|
|
2354
2635
|
const state = snapshot.state;
|
|
2355
2636
|
if (state === null) return h("span", { className: "km-summary-line" }, snapshot.status === "error" ? t("loadError") : t("loading"));
|
|
2356
|
-
|
|
2357
|
-
return h("span", { className: "km-summary-line" }, t("
|
|
2637
|
+
const managed = managedEntryCount(state.providers, state.transportAccounts ?? []);
|
|
2638
|
+
if (managed === 0) return h("span", { className: "km-summary-line" }, t("summaryEmpty"));
|
|
2639
|
+
return h("span", { className: "km-summary-line" }, t("summaryText", { providers: managed, keys: state.keyCount }));
|
|
2358
2640
|
}
|
|
2359
2641
|
return h(KeysManagerBody);
|
|
2360
2642
|
}
|
package/lib/core.d.ts
CHANGED
|
@@ -1,11 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure key-selection and cooldown policy for the Keys Manager.
|
|
3
|
-
*
|
|
4
|
-
* Nothing here touches Cordis, the filesystem, or a secret. The Host passes
|
|
5
|
-
* plain provider records in and gets the same records back, which keeps the
|
|
6
|
-
* round-robin, sticky-session, cooldown-escalation, and retry decisions
|
|
7
|
-
* unit-testable without a running Harness.
|
|
8
|
-
*/
|
|
9
1
|
import type { KeyRecord, KeyStatus, ManagerSettings, ProviderRecord, ProviderStatus } from './domain.js';
|
|
10
2
|
import type { LlmFailureLike } from './host-types.js';
|
|
11
3
|
/** Defaults also exposed in the manager's policy card. */
|
|
@@ -111,5 +103,12 @@ export declare function validateKeyPatch(patch: unknown): {
|
|
|
111
103
|
};
|
|
112
104
|
/** Maximum keys per provider (also used by the Host). */
|
|
113
105
|
export declare const KEY_LIMIT = 32;
|
|
106
|
+
/**
|
|
107
|
+
* Finish kinds a connection test reports as a completed request. The installed
|
|
108
|
+
* `@deepseek-ai/dsh-llm` union is `stop | tool-calls | max-tokens | aborted |
|
|
109
|
+
* error`, so `length`/`toolUse` were never completions. Shared with the tests
|
|
110
|
+
* so the implementation and its fixtures cannot drift apart again.
|
|
111
|
+
*/
|
|
112
|
+
export declare const TEST_SUCCESS_FINISH_KINDS: readonly ["stop", "tool-calls", "max-tokens"];
|
|
114
113
|
/** Re-export the shared update type for callers that only import core. */
|
|
115
114
|
export type { ManagerSettings };
|
package/lib/core.js
CHANGED
|
@@ -279,4 +279,11 @@ export function validateKeyPatch(patch) {
|
|
|
279
279
|
}
|
|
280
280
|
/** Maximum keys per provider (also used by the Host). */
|
|
281
281
|
export const KEY_LIMIT = MAX_KEYS_PER_PROVIDER;
|
|
282
|
+
/**
|
|
283
|
+
* Finish kinds a connection test reports as a completed request. The installed
|
|
284
|
+
* `@deepseek-ai/dsh-llm` union is `stop | tool-calls | max-tokens | aborted |
|
|
285
|
+
* error`, so `length`/`toolUse` were never completions. Shared with the tests
|
|
286
|
+
* so the implementation and its fixtures cannot drift apart again.
|
|
287
|
+
*/
|
|
288
|
+
export const TEST_SUCCESS_FINISH_KINDS = ['stop', 'tool-calls', 'max-tokens'];
|
|
282
289
|
//# sourceMappingURL=core.js.map
|