@goodandready/dsh-key-rotation 0.7.4 → 0.7.6
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/lib/client.js +30 -27
- package/package.json +1 -4
package/lib/client.js
CHANGED
|
@@ -250,6 +250,31 @@ window.__ModuleLoader__.load({
|
|
|
250
250
|
const t = makeT(DICT, en);
|
|
251
251
|
const [state, setState] = React.useState({ status: 'loading', value: null, revision: 0, error: '', providers: [] });
|
|
252
252
|
const [draft, setDraft] = React.useState(null);
|
|
253
|
+
// ── all hooks live ABOVE any early return (React error 310 otherwise) ──
|
|
254
|
+
const [search, setSearch] = React.useState('');
|
|
255
|
+
const [selected, setSelected] = React.useState(new Set());
|
|
256
|
+
const [bulkCooldown, setBulkCooldown] = React.useState('');
|
|
257
|
+
const [undo, setUndo] = React.useState(null);
|
|
258
|
+
const undoTimer = React.useRef(null);
|
|
259
|
+
const [testing, setTesting] = React.useState('');
|
|
260
|
+
const [testResult, setTestResult] = React.useState({});
|
|
261
|
+
const [secretDraft, setSecretDraft] = React.useState({});
|
|
262
|
+
const [secretError, setSecretError] = React.useState('');
|
|
263
|
+
const stashUndo = (u) => { setUndo(u); if (undoTimer.current) clearTimeout(undoTimer.current); undoTimer.current = setTimeout(() => setUndo(null), 5000); };
|
|
264
|
+
const doUndo = () => { if (!undo) return; const u = undo; setUndo(null); setField((cur) => {
|
|
265
|
+
const providers = [...(cur.providers ?? [])];
|
|
266
|
+
if (u.type === 'provider') providers.splice(Math.min(u.index, providers.length), 0, u.entry);
|
|
267
|
+
else if (providers[u.index]) { const keys=[...providers[u.index].keys]; keys.splice(Math.min(u.kIndex, keys.length), 0, u.key); providers[u.index] = { ...providers[u.index], keys }; }
|
|
268
|
+
return { ...cur, providers };
|
|
269
|
+
}); };
|
|
270
|
+
const doTest = (ref) => {
|
|
271
|
+
setTesting(ref); setTestResult((m) => ({ ...m, [ref]: null }));
|
|
272
|
+
fetch('/dsh-key-rotation/test', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ ref }) })
|
|
273
|
+
.then((r) => r.json())
|
|
274
|
+
.then((data) => setTestResult((m) => ({ ...m, [ref]: data })))
|
|
275
|
+
.catch((e) => setTestResult((m) => ({ ...m, [ref]: { ok: false, message: String(e?.message ?? e) } })))
|
|
276
|
+
.finally(() => setTesting(''));
|
|
277
|
+
};
|
|
253
278
|
|
|
254
279
|
const load = React.useCallback(() => {
|
|
255
280
|
setState((s) => ({ ...s, status: 'loading', error: '' }));
|
|
@@ -272,10 +297,6 @@ window.__ModuleLoader__.load({
|
|
|
272
297
|
|
|
273
298
|
const val = draft ?? state.value;
|
|
274
299
|
const status = useRotationStatus();
|
|
275
|
-
// Значения ключей живут только здесь, до нажатия «сохранить»: обратно из
|
|
276
|
-
// хоста они не приходят, в карточке видны лишь последние символы.
|
|
277
|
-
const [secretDraft, setSecretDraft] = React.useState({});
|
|
278
|
-
const [secretError, setSecretError] = React.useState('');
|
|
279
300
|
const [resetting, setResetting] = React.useState('');
|
|
280
301
|
const doReset = (providerId) => {
|
|
281
302
|
setResetting(providerId);
|
|
@@ -286,16 +307,7 @@ window.__ModuleLoader__.load({
|
|
|
286
307
|
.catch((e) => setSecretError(t('keyWriteFailed').replace('{msg}', String(e?.message ?? e))))
|
|
287
308
|
.finally(() => setResetting(''));
|
|
288
309
|
};
|
|
289
|
-
|
|
290
|
-
const [testResult, setTestResult] = React.useState({});
|
|
291
|
-
const doTest = (ref) => {
|
|
292
|
-
setTesting(ref); setTestResult((m) => ({ ...m, [ref]: null }));
|
|
293
|
-
fetch('/dsh-key-rotation/test', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ ref }) })
|
|
294
|
-
.then((r) => r.json())
|
|
295
|
-
.then((data) => setTestResult((m) => ({ ...m, [ref]: data })))
|
|
296
|
-
.catch((e) => setTestResult((m) => ({ ...m, [ref]: { ok: false, message: String(e?.message ?? e) } })))
|
|
297
|
-
.finally(() => setTesting(''));
|
|
298
|
-
};
|
|
310
|
+
|
|
299
311
|
|
|
300
312
|
const keyInfo = (providerId, ref) => {
|
|
301
313
|
const entryStatus = status[providerId];
|
|
@@ -331,18 +343,6 @@ window.__ModuleLoader__.load({
|
|
|
331
343
|
const providerById = new Map(providers.map((p) => [p.id, p.name]));
|
|
332
344
|
|
|
333
345
|
const setField = (fn) => setDraft(fn(val));
|
|
334
|
-
const [search, setSearch] = React.useState('');
|
|
335
|
-
const [selected, setSelected] = React.useState(new Set());
|
|
336
|
-
const [undo, setUndo] = React.useState(null); // {type, provider, index, entry}
|
|
337
|
-
const undoTimer = React.useRef(null);
|
|
338
|
-
const stashUndo = (u) => { setUndo(u); if (undoTimer.current) clearTimeout(undoTimer.current); undoTimer.current = setTimeout(() => setUndo(null), 5000); };
|
|
339
|
-
const doUndo = () => { if (!undo) return; const u = undo; setUndo(null); setField((cur) => {
|
|
340
|
-
const providers = [...(cur.providers ?? [])];
|
|
341
|
-
if (u.type === 'provider') providers.splice(Math.min(u.index, providers.length), 0, u.entry);
|
|
342
|
-
else if (providers[u.index]) { const keys=[...providers[u.index].keys]; keys.splice(Math.min(u.kIndex, keys.length), 0, u.key); providers[u.index] = { ...providers[u.index], keys }; }
|
|
343
|
-
return { ...cur, providers };
|
|
344
|
-
}); };
|
|
345
|
-
const [bulkCooldown, setBulkCooldown] = React.useState('');
|
|
346
346
|
const providerList = Array.isArray(val.providers) ? val.providers.filter((p) => Array.isArray(p.keys) && p.keys.length > 0).filter((p) => !search || p.provider.toLowerCase().includes(search.toLowerCase())) : [];
|
|
347
347
|
|
|
348
348
|
const setProvider = (index, id) => setField((cur) => {
|
|
@@ -507,7 +507,10 @@ window.__ModuleLoader__.load({
|
|
|
507
507
|
if (info && info.lastUsedAt) meta.push(h('span', { key: 'lu', className: 'krot-tail', title: 'last used' }, formatAgo((k)=>t(k), info.lastUsedAt)));
|
|
508
508
|
if (info && typeof info.cost === 'number' && info.cost > 0) meta.push(h('span', { key: 'c', className: 'krot-tail', title: 'cost' }, '$' + info.cost.toFixed(2)));
|
|
509
509
|
const tr = testResult[key];
|
|
510
|
-
if (tr) meta.push(h('span', { key: 'tr', className: 'krot-tail',
|
|
510
|
+
if (tr) meta.push(h('span', { key: 'tr', className: 'krot-tail',
|
|
511
|
+
title: tr.message || (tr.ok ? t('testOk') : t('testFail')),
|
|
512
|
+
style: { color: tr.ok ? 'var(--dsw-alias-state-success-primary)' : 'var(--dsw-alias-state-error-primary)', fontWeight: 700 } },
|
|
513
|
+
tr.ok ? '✓' : '✕'));
|
|
511
514
|
meta.push(h('button', { key: 't', className: 'krot-btn', onClick: () => doTest(key), disabled: testing === key, title: t('testKey') }, testing === key ? '…' : t('testKey')));
|
|
512
515
|
meta.push(h('span', { key: 'a', className: 'krot-acts' },
|
|
513
516
|
btn('↑', () => moveKey(pIndex, kIndex, -1), { disabled: kIndex === 0, title: t('moveUp') }),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-key-rotation",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.6",
|
|
4
4
|
"description": "Per-provider API key rotation for DeepSeek Harness: a key pool per provider, auto-created clone routes, and switching to the next key on quota/rate-limit errors. Includes a Settings section (Key Rotation) to edit the key pools, cooldown and switch codes.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
|
@@ -54,8 +54,5 @@
|
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"test": "node --test test/*.test.js"
|
|
57
|
-
},
|
|
58
|
-
"publishConfig": {
|
|
59
|
-
"access": "public"
|
|
60
57
|
}
|
|
61
58
|
}
|