@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 +7 -4
- package/lib/index.js +30 -0
- package/package.json +1 -1
- package/src/index.ts +28 -0
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: "
|
|
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
|
|
99
|
-
//
|
|
100
|
-
|
|
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.
|
|
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');
|