@goodandready/dsh-key-rotation 0.8.19 → 0.8.20
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 +5 -0
- package/lib/client.js +15 -15
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,11 @@
|
|
|
3
3
|
All notable changes to `@goodandready/dsh-key-rotation` are documented here.
|
|
4
4
|
User-facing feature notes also appear in README (en is source of truth).
|
|
5
5
|
|
|
6
|
+
## 0.8.20 - 2026-09-22
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
- **Settings card on current DSH** (#345): the client reads its settings namespace through `configForms` instead of the removed `settingsScope` service. The package manifest declares the settings and slots providers the card injects, so the fiber activates and the card mounts again.
|
|
10
|
+
|
|
6
11
|
## 0.8.19 - 2026-09-22
|
|
7
12
|
|
|
8
13
|
### Fixed
|
package/lib/client.js
CHANGED
|
@@ -644,7 +644,7 @@ window.__ModuleLoader__.load({
|
|
|
644
644
|
);
|
|
645
645
|
}
|
|
646
646
|
|
|
647
|
-
// Provider registration is not part of
|
|
647
|
+
// Provider registration is not part of configForms's value. Fetch it
|
|
648
648
|
// independently, and never turn an unavailable catalog into proof of absence.
|
|
649
649
|
function useProviderCatalog() {
|
|
650
650
|
const [catalog, setCatalog] = React.useState({ status: 'loading', providers: [] });
|
|
@@ -687,10 +687,10 @@ window.__ModuleLoader__.load({
|
|
|
687
687
|
|
|
688
688
|
function KeyRotationSection(props) {
|
|
689
689
|
const t = resolveT(props);
|
|
690
|
-
const
|
|
690
|
+
const configForms = React.useMemo(() => {
|
|
691
691
|
try {
|
|
692
|
-
if (props.ctx && props.ctx.
|
|
693
|
-
return props.ctx.
|
|
692
|
+
if (props.ctx && props.ctx.configForms) {
|
|
693
|
+
return props.ctx.configForms.get(NS);
|
|
694
694
|
}
|
|
695
695
|
} catch (_) {
|
|
696
696
|
return null;
|
|
@@ -700,10 +700,10 @@ window.__ModuleLoader__.load({
|
|
|
700
700
|
// #273: getSnapshot must be referentially stable or React 18 unmounts the tree
|
|
701
701
|
const scopeCacheRef = React.useRef({ has: false, value: null });
|
|
702
702
|
const getScopeSnapshot = React.useCallback(() => {
|
|
703
|
-
if (!
|
|
703
|
+
if (!configForms || typeof configForms.getSnapshot !== 'function') return null;
|
|
704
704
|
let next = null;
|
|
705
705
|
try {
|
|
706
|
-
next =
|
|
706
|
+
next = configForms.getSnapshot();
|
|
707
707
|
} catch (_) {
|
|
708
708
|
return null;
|
|
709
709
|
}
|
|
@@ -718,21 +718,21 @@ window.__ModuleLoader__.load({
|
|
|
718
718
|
}
|
|
719
719
|
scopeCacheRef.current = { has: true, value: next };
|
|
720
720
|
return next;
|
|
721
|
-
}, [
|
|
721
|
+
}, [configForms]);
|
|
722
722
|
const scopeSnapshot = React.useSyncExternalStore(
|
|
723
|
-
React.useMemo(() => (cb) => (
|
|
723
|
+
React.useMemo(() => (cb) => (configForms && typeof configForms.subscribe === 'function' ? configForms.subscribe(cb) : () => {}), [configForms]),
|
|
724
724
|
getScopeSnapshot
|
|
725
725
|
);
|
|
726
726
|
const [state, setState] = React.useState({ status: 'loading', value: null, revision: 0, error: '', providers: [] });
|
|
727
727
|
const catalog = useProviderCatalog();
|
|
728
728
|
const latestScopeSnapshot = React.useRef(scopeSnapshot);
|
|
729
729
|
latestScopeSnapshot.current = scopeSnapshot;
|
|
730
|
-
// #290: surface
|
|
730
|
+
// #290: surface configForms availability as card state
|
|
731
731
|
React.useEffect(() => {
|
|
732
|
-
if (!
|
|
732
|
+
if (!configForms) {
|
|
733
733
|
setState((s) => (s.status === 'unavailable' ? s : { ...s, status: 'unavailable' }));
|
|
734
734
|
}
|
|
735
|
-
}, [
|
|
735
|
+
}, [configForms]);
|
|
736
736
|
const [draft, setDraft] = React.useState(null);
|
|
737
737
|
// ── all hooks live ABOVE any early return (React error 310 otherwise) ──
|
|
738
738
|
const [search, setSearch] = React.useState('');
|
|
@@ -1014,7 +1014,7 @@ window.__ModuleLoader__.load({
|
|
|
1014
1014
|
React.createElement('button', { type: 'button', className: 'krot-btn', onClick: () => load() }, t('retry'))
|
|
1015
1015
|
);
|
|
1016
1016
|
}
|
|
1017
|
-
if (state.status === 'unavailable' || !
|
|
1017
|
+
if (state.status === 'unavailable' || !configForms) {
|
|
1018
1018
|
return React.createElement('div', { className: 'krot-state-block', role: 'status', style: { padding: '12px 0', display: 'flex', flexDirection: 'column', gap: '6px' } },
|
|
1019
1019
|
React.createElement('p', { style: { fontSize: 14, fontWeight: 600, color: 'var(--dsw-alias-label-primary)', margin: 0 } }, t('unavailableTitle')),
|
|
1020
1020
|
React.createElement('p', { className: 'krot-hint', style: { margin: 0 } }, t('unavailableDesc'))
|
|
@@ -1127,11 +1127,11 @@ window.__ModuleLoader__.load({
|
|
|
1127
1127
|
})
|
|
1128
1128
|
.catch((e) => setState((s) => ({ ...s, status: 'error', error: String(e) })));
|
|
1129
1129
|
};
|
|
1130
|
-
if (
|
|
1130
|
+
if (configForms && typeof configForms.set === 'function') {
|
|
1131
1131
|
(async () => {
|
|
1132
1132
|
try {
|
|
1133
1133
|
for (const [k, v] of Object.entries(draft)) {
|
|
1134
|
-
await
|
|
1134
|
+
await configForms.set(k, v);
|
|
1135
1135
|
}
|
|
1136
1136
|
setState((s) => ({ ...s, status: 'ready', value: draft, error: '' }));
|
|
1137
1137
|
setDraft(null);
|
|
@@ -1936,7 +1936,7 @@ window.__ModuleLoader__.load({
|
|
|
1936
1936
|
}
|
|
1937
1937
|
}
|
|
1938
1938
|
|
|
1939
|
-
module.exports = { apply, inject: ['slots', 'locale', '
|
|
1939
|
+
module.exports = { apply, inject: ['slots', 'locale', 'configForms'] };
|
|
1940
1940
|
return module.exports;
|
|
1941
1941
|
},
|
|
1942
1942
|
updateCheck: 'Check for updates',
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@goodandready/dsh-key-rotation",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.20",
|
|
4
4
|
"packageManager": "pnpm@10.33.2",
|
|
5
5
|
"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.",
|
|
6
6
|
"keywords": [
|
|
@@ -46,7 +46,8 @@
|
|
|
46
46
|
"platform": "web",
|
|
47
47
|
"inject": [
|
|
48
48
|
"@deepseek-ai/dsh-client-locale",
|
|
49
|
-
"@deepseek-ai/dsh-client-ui-settings"
|
|
49
|
+
"@deepseek-ai/dsh-client-ui-settings",
|
|
50
|
+
"@deepseek-ai/dsh-client-ui-slots"
|
|
50
51
|
]
|
|
51
52
|
}
|
|
52
53
|
},
|