@dungsil/dsh-plugin-cli-proxy-api 0.2.1 → 0.2.2

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.
Files changed (2) hide show
  1. package/dist/client.js +33 -20
  2. package/package.json +3 -1
package/dist/client.js CHANGED
@@ -115,7 +115,7 @@ const copy = {
115
115
  quotaLoadTitle: "Accounts are not available yet",
116
116
  quotaLoadHint: "Accounts and quota load automatically with a saved management key. If loading fails, refresh accounts to try again.",
117
117
  accountsObservedAt: "Accounts checked at",
118
- quotaHint: "Accounts and quota load automatically. The memory cache is valid for 5 minutes. Expired results update when you reopen this panel. Refresh accounts to update all results now. Cooldown reset only clears proxy routing blocks; it does not refill quota. No paid inference or reset credits are used.",
118
+ quotaHint: "Accounts and quota load once and stay cached in memory when you reopen this panel. Refresh accounts to update all results. Connection changes clear the cache. Cooldown reset only clears proxy routing blocks; it does not refill quota. No paid inference or reset credits are used.",
119
119
  refreshQuotaAccounts: "Refresh accounts",
120
120
  searchAccounts: "Search name / provider",
121
121
  refreshQuota: "Refresh quota",
@@ -184,7 +184,7 @@ const copy = {
184
184
  quotaLoadTitle: "아직 계정 정보를 불러오지 못했습니다",
185
185
  quotaLoadHint: "관리 키가 저장되어 있으면 계정과 할당량을 자동으로 불러옵니다. 불러오기에 실패했다면 계정을 새로고침하세요.",
186
186
  accountsObservedAt: "계정 확인 시각",
187
- quotaHint: "계정과 할당량을 자동으로 불러옵니다. 메모리 캐시는 5분간 유효하며, 화면을 다시 열 때 만료된 결과를 갱신합니다. 계정을 새로고침하면 전체 결과를 즉시 갱신합니다. 대기 시간 초기화는 프록시의 라우팅 차단만 해제하며 할당량을 충전하지 않습니다. 유료 추론이나 초기화 크레딧을 사용하지 않습니다.",
187
+ quotaHint: "계정과 할당량은 한 번 불러온 뒤 메모리에 캐시하며, 화면을 다시 열 때 그대로 표시합니다. 계정을 새로고침하면 전체 결과를 갱신합니다. 연결이 변경되면 캐시를 비웁니다. 대기 시간 초기화는 프록시의 라우팅 차단만 해제하며 할당량을 충전하지 않습니다. 유료 추론이나 초기화 크레딧을 사용하지 않습니다.",
188
188
  refreshQuotaAccounts: "계정 새로고침",
189
189
  searchAccounts: "이름 / 공급자 검색",
190
190
  refreshQuota: "할당량 새로고침",
@@ -253,7 +253,7 @@ const copy = {
253
253
  quotaLoadTitle: "暂未加载账户信息",
254
254
  quotaLoadHint: "保存管理密钥后,账户和配额会自动加载。加载失败时,请刷新账户重试。",
255
255
  accountsObservedAt: "账户检查时间",
256
- quotaHint: "账户和配额会自动加载。内存缓存有效期为 5 分钟,重新打开此面板时会更新已过期的结果。刷新账户可立即更新全部结果。重置冷却时间仅解除代理路由限制,不会补充配额。不会使用付费推理或重置额度。",
256
+ quotaHint: "账户和配额加载一次后会缓存在内存中,重新打开此面板时直接显示。刷新账户可更新全部结果。连接变更会清除缓存。重置冷却时间仅解除代理路由限制,不会补充配额。不会使用付费推理或重置额度。",
257
257
  refreshQuotaAccounts: "刷新账户",
258
258
  searchAccounts: "搜索名称 / 提供商",
259
259
  refreshQuota: "刷新配额",
@@ -684,6 +684,7 @@ function QuotaPanel({ accounts, quotas, fetchedAt, language, text, busy, canLoad
684
684
  ]
685
685
  });
686
686
  }
687
+ // src/quota-cache.ts
687
688
  const quotaKey = (account) => JSON.stringify([account.name, account.authIndex]);
688
689
  const connectionKey = (view) => JSON.stringify([
689
690
  view.baseURL,
@@ -692,6 +693,9 @@ const connectionKey = (view) => JSON.stringify([
692
693
  ]);
693
694
  var QuotaCache = class {
694
695
  entry;
696
+ get connection() {
697
+ return this.entry?.view;
698
+ }
695
699
  read(view) {
696
700
  if (this.entry?.key !== connectionKey(view)) {
697
701
  this.clear();
@@ -702,6 +706,7 @@ var QuotaCache = class {
702
706
  write(view, snapshot) {
703
707
  this.entry = {
704
708
  key: connectionKey(view),
709
+ view,
705
710
  snapshot
706
711
  };
707
712
  }
@@ -726,10 +731,6 @@ function subscribeQuotaGeneration(generation, cache, cancel, changed) {
726
731
  changed(!!generation.getSnapshot());
727
732
  });
728
733
  }
729
- function isQuotaCacheFresh(snapshot, now = Date.now()) {
730
- const age = now - snapshot.fetchedAt;
731
- return age >= 0 && age < 3e5;
732
- }
733
734
  async function loadQuotaSnapshot(list, fetch, signal, publish) {
734
735
  signal.throwIfAborted();
735
736
  const accounts = await list();
@@ -807,18 +808,20 @@ function ProxyPage({ ctx, cache, settings = false }) {
807
808
  const id = (0, react.useId)();
808
809
  const [connectionVersion, setConnectionVersion] = (0, react.useState)(0);
809
810
  const connection = ctx.get("connection");
810
- const [view, setView] = (0, react.useState)();
811
- const [baseURL, setBaseURL] = (0, react.useState)("");
811
+ const cachedView = settings ? void 0 : cache.connection;
812
+ const cached = cachedView && cache.read(cachedView);
813
+ const [view, setView] = (0, react.useState)(cachedView);
814
+ const [baseURL, setBaseURL] = (0, react.useState)(cachedView?.baseURL ?? "");
812
815
  const [apiKey, setAPIKey] = (0, react.useState)("");
813
816
  const [managementKey, setManagementKey] = (0, react.useState)("");
814
817
  const [removeAPIKey, setRemoveAPIKey] = (0, react.useState)(false);
815
818
  const [removeManagementKey, setRemoveManagementKey] = (0, react.useState)(false);
816
- const [synchronized, setSynchronized] = (0, react.useState)(false);
817
- const [busy, setBusy] = (0, react.useState)(true);
819
+ const [synchronized, setSynchronized] = (0, react.useState)(!!cached);
820
+ const [busy, setBusy] = (0, react.useState)(!cached);
818
821
  const [notice, setNotice] = (0, react.useState)();
819
- const [quotaAccounts, setQuotaAccounts] = (0, react.useState)();
820
- const [quotas, setQuotas] = (0, react.useState)({});
821
- const [fetchedAt, setFetchedAt] = (0, react.useState)();
822
+ const [quotaAccounts, setQuotaAccounts] = (0, react.useState)(cached?.accounts);
823
+ const [quotas, setQuotas] = (0, react.useState)(cached?.quotas ?? {});
824
+ const [fetchedAt, setFetchedAt] = (0, react.useState)(cached?.fetchedAt);
822
825
  const [uncertain, setUncertain] = (0, react.useState)(false);
823
826
  const lock = (0, react.useRef)(true);
824
827
  const lifetime = (0, react.useRef)();
@@ -831,6 +834,7 @@ function ProxyPage({ ctx, cache, settings = false }) {
831
834
  const describe = (0, react.useCallback)(async (controller) => {
832
835
  setSynchronized(false);
833
836
  const next = await call("describe", {}, controller);
837
+ cache.read(next);
834
838
  setView(next);
835
839
  setBaseURL(next.baseURL);
836
840
  setSynchronized(true);
@@ -842,7 +846,7 @@ function ProxyPage({ ctx, cache, settings = false }) {
842
846
  setQuotas({});
843
847
  setFetchedAt(void 0);
844
848
  return next;
845
- }, [call]);
849
+ }, [call, cache]);
846
850
  const showSnapshot = (0, react.useCallback)((snapshot) => {
847
851
  setQuotaAccounts(snapshot.accounts);
848
852
  setQuotas(snapshot.quotas);
@@ -898,6 +902,20 @@ function ProxyPage({ ctx, cache, settings = false }) {
898
902
  (0, react.useEffect)(() => {
899
903
  const controller = new AbortController();
900
904
  lifetime.current = controller;
905
+ const restoreView = settings ? void 0 : cache.connection;
906
+ const restore = restoreView && cache.read(restoreView);
907
+ if (restore && restoreView) {
908
+ setView(restoreView);
909
+ setBaseURL(restoreView.baseURL);
910
+ setSynchronized(true);
911
+ showSnapshot(restore);
912
+ lock.current = false;
913
+ setBusy(false);
914
+ return () => {
915
+ controller.abort();
916
+ if (lifetime.current === controller) lifetime.current = void 0;
917
+ };
918
+ }
901
919
  lock.current = true;
902
920
  setBusy(true);
903
921
  setSynchronized(false);
@@ -911,12 +929,7 @@ function ProxyPage({ ctx, cache, settings = false }) {
911
929
  setNotice(void 0);
912
930
  describe(controller).then(async (next) => {
913
931
  if (settings) return;
914
- const cached = cache.read(next);
915
932
  if (!next.managementKeySaved) return;
916
- if (cached) {
917
- showSnapshot(cached);
918
- if (isQuotaCacheFresh(cached)) return;
919
- }
920
933
  await loadAccounts(next, controller);
921
934
  }).catch(() => {
922
935
  if (!controller.signal.aborted && lifetime.current === controller) setNotice("error");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dungsil/dsh-plugin-cli-proxy-api",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "CLIProxyAPI model provider and owner-only management settings for DeepSeek Harness.",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -43,7 +43,9 @@
43
43
  "@dungsil/dsh-tsdown": "0.0.0",
44
44
  "@dungsil/dsh-ui": "0.0.0",
45
45
  "@types/react": "18.3.31",
46
+ "happy-dom": "21.0.4",
46
47
  "react": "18.3.1",
48
+ "react-dom": "18.3.1",
47
49
  "tsdown": "0.23.4"
48
50
  },
49
51
  "peerDependencies": {