@sunshaobei/dsh-balance-panel 3.0.5 → 3.0.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 CHANGED
@@ -25,7 +25,7 @@
25
25
  * follows the product theme (light/dark) instead of carrying its own palette.
26
26
  */
27
27
  window.__ModuleLoader__.load({
28
- id: "@sunshaobei/dsh-balance-panel",
28
+ id: "dsh-balance-panel",
29
29
  factory: (require) => {
30
30
  var module = { exports: {} };
31
31
  var exports = module.exports;
@@ -95,9 +95,12 @@ window.__ModuleLoader__.load({
95
95
  }
96
96
  if (family.length === 0) {
97
97
  var prov = String(sel.provider || "").toLowerCase();
98
- // DOM-fallback selection (no provider) matching no family:
99
- // show nothing — an empty prov would substring-match EVERY row.
100
- if (!prov) return null;
98
+ // A DOM-fallback selection has no provider: the model name alone
99
+ // matched no known family, so this model has no known quota
100
+ // source. Show nothing rather than a wrong provider — an empty
101
+ // prov would otherwise substring-match EVERY row.
102
+ if (!prov)
103
+ return null;
101
104
  for (var j = 0; j < specs.rows.length; j++) {
102
105
  var id = String(specs.rows[j].id || "").toLowerCase();
103
106
  if (prov.indexOf(id) > -1 || id.indexOf(prov) > -1)
package/lib/index.js CHANGED
@@ -264,6 +264,10 @@ async function chatgptAuthExists() {
264
264
  }
265
265
  /** In-memory token cache; refreshed on expiry or on auth failure. */
266
266
  let chatgptTokenCache = null;
267
+ // Live handle onto the credentials service — set in apply(). Lets the
268
+ // ChatGPT/Codex token resolver read the shared grant record that
269
+ // dsh-codex-auth writes (llm-pi-ai/openai-codex).
270
+ let codexCredentialsRef = null;
267
271
  async function readChatGPTAuthFile() {
268
272
  const authJson = chatgptAuthJsonPath();
269
273
  let raw;
@@ -632,6 +636,31 @@ function chatgptLoginStatus() {
632
636
  async function resolveChatGPTToken(timeoutMs, proxyUrl) {
633
637
  const now = Date.now();
634
638
  const cached = chatgptTokenCache?.bundle;
639
+ // Source 0: the shared grant record written by dsh-codex-auth
640
+ // (llm-pi-ai/openai-codex). Preferred when present and fresh: the user
641
+ // authorized through the Codex subscription settings page, so the panel
642
+ // should reflect THAT credential instead of ~/.codex/auth.json.
643
+ try {
644
+ if (codexCredentialsRef?.readRecord) {
645
+ const rec = await codexCredentialsRef.readRecord('llm-pi-ai/openai-codex');
646
+ const p = rec && rec.kind === 'grant' ? rec.payload : undefined;
647
+ if (p && p.access) {
648
+ if (!p.expires || p.expires - now > 30000) {
649
+ chatgptTokenCache = { bundle: { access_token: p.access, refresh_token: p.refresh, expires_at_ms: p.expires, account_id: p.accountId } };
650
+ return { accessToken: p.access, accountId: p.accountId };
651
+ }
652
+ if (p.refresh) {
653
+ const refreshed = await refreshChatGPTToken(p.refresh, timeoutMs, proxyUrl);
654
+ if (!refreshed.account_id)
655
+ refreshed.account_id = p.accountId;
656
+ await codexCredentialsRef.modifyRecord('llm-pi-ai/openai-codex', async () => ({ kind: 'grant', payload: { ...p, access: refreshed.access_token, refresh: refreshed.refresh_token || p.refresh, expires: refreshed.expires_at_ms } })).catch(() => { });
657
+ chatgptTokenCache = { bundle: refreshed };
658
+ return { accessToken: refreshed.access_token, accountId: refreshed.account_id };
659
+ }
660
+ }
661
+ }
662
+ }
663
+ catch { /* record absent or unreadable — fall through to the other sources */ }
635
664
  if (cached && cached.access_token && (!cached.expires_at_ms || cached.expires_at_ms - now > 30000)) {
636
665
  return { accessToken: cached.access_token, accountId: cached.account_id };
637
666
  }
@@ -1880,6 +1909,7 @@ function registerQuotaRpc(ctx, handler) {
1880
1909
  * @param config - raw plugin config (schema-processed by the loader).
1881
1910
  */
1882
1911
  export function apply(ctx, config = {}) {
1912
+ codexCredentialsRef = ctx.credentials;
1883
1913
  const raw = config && typeof config === 'object' ? config : {};
1884
1914
  const refreshMs = numOf(raw.refreshMs, 60000);
1885
1915
  if (!(refreshMs >= 5000))
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sunshaobei/dsh-balance-panel",
3
3
  "description": "Provider quota/balance widget for the dsh web surface: an inline sidebar card above the Settings row (collapsed glanceable row expanding into a Harness-native card with a settings panel), fed by a loopback Connection RPC channel whose host half proxies each provider with credentials that never reach the browser.",
4
- "version": "3.0.5",
4
+ "version": "3.0.6",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",
package/src/index.ts CHANGED
@@ -287,6 +287,10 @@ interface ChatGPTTokenBundle {
287
287
 
288
288
  /** In-memory token cache; refreshed on expiry or on auth failure. */
289
289
  let chatgptTokenCache: { bundle: ChatGPTTokenBundle } | null = null;
290
+ // Live handle onto the credentials service — set in apply(). Lets the
291
+ // ChatGPT/Codex token resolver read the shared grant record that
292
+ // dsh-codex-auth writes (llm-pi-ai/openai-codex).
293
+ let codexCredentialsRef: any = null;
290
294
 
291
295
  async function readChatGPTAuthFile(): Promise<ChatGPTTokenBundle> {
292
296
  const authJson = chatgptAuthJsonPath();
@@ -653,6 +657,29 @@ function chatgptLoginStatus(): { active: boolean; verificationUrl?: string; user
653
657
  async function resolveChatGPTToken(timeoutMs: number, proxyUrl?: string): Promise<{ accessToken: string; accountId?: string }> {
654
658
  const now = Date.now();
655
659
  const cached = chatgptTokenCache?.bundle;
660
+ // Source 0: the shared grant record written by dsh-codex-auth
661
+ // (llm-pi-ai/openai-codex). Preferred when present and fresh: the user
662
+ // authorized through the Codex subscription settings page, so the panel
663
+ // should reflect THAT credential instead of ~/.codex/auth.json.
664
+ try {
665
+ if (codexCredentialsRef?.readRecord) {
666
+ const rec: any = await codexCredentialsRef.readRecord('llm-pi-ai/openai-codex');
667
+ const p = rec && rec.kind === 'grant' ? rec.payload : undefined;
668
+ if (p && p.access) {
669
+ if (!p.expires || p.expires - now > 30_000) {
670
+ chatgptTokenCache = { bundle: { access_token: p.access, refresh_token: p.refresh, expires_at_ms: p.expires, account_id: p.accountId } };
671
+ return { accessToken: p.access, accountId: p.accountId };
672
+ }
673
+ if (p.refresh) {
674
+ const refreshed = await refreshChatGPTToken(p.refresh, timeoutMs, proxyUrl);
675
+ if (!refreshed.account_id) refreshed.account_id = p.accountId;
676
+ await codexCredentialsRef.modifyRecord('llm-pi-ai/openai-codex', async () => ({ kind: 'grant', payload: { ...p, access: refreshed.access_token, refresh: refreshed.refresh_token || p.refresh, expires: refreshed.expires_at_ms } })).catch(() => {});
677
+ chatgptTokenCache = { bundle: refreshed };
678
+ return { accessToken: refreshed.access_token, accountId: refreshed.account_id };
679
+ }
680
+ }
681
+ }
682
+ } catch { /* record absent or unreadable — fall through to the other sources */ }
656
683
  if (cached && cached.access_token && (!cached.expires_at_ms || cached.expires_at_ms - now > 30_000)) {
657
684
  return { accessToken: cached.access_token, accountId: cached.account_id };
658
685
  }
@@ -1830,6 +1857,7 @@ async function fetchRow(ctx, provider, proxies, clientProxyUrl) {
1830
1857
  * @param config - raw plugin config (schema-processed by the loader).
1831
1858
  */
1832
1859
  export function apply(ctx, config: Record<string, any> = {}) {
1860
+ codexCredentialsRef = ctx.credentials;
1833
1861
  const raw: Record<string, any> = config && typeof config === 'object' ? config : {};
1834
1862
  const refreshMs = numOf(raw.refreshMs, 60000);
1835
1863
  if (!(refreshMs >= 5000)) throw new Error('quota-panel: config.refreshMs must be >= 5000');