@sunshaobei/dsh-codex-auth 3.0.3 → 3.0.4
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/index.js +45 -0
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -384,6 +384,50 @@ function registerCodexAuthRpc(ctx, credentials, phase) {
|
|
|
384
384
|
};
|
|
385
385
|
ctx.effect(() => ctx.webServer.register(route), 'dsh-codex-auth: rpc channel');
|
|
386
386
|
}
|
|
387
|
+
// ---------------------------------------------------------------------------
|
|
388
|
+
// silent token refresh (runs once per app start; no timers)
|
|
389
|
+
// ---------------------------------------------------------------------------
|
|
390
|
+
const REFRESH_AHEAD_MS = 60 * 60 * 1000; // only refresh when < 1 hour left
|
|
391
|
+
|
|
392
|
+
async function silentRefresh(credentials) {
|
|
393
|
+
try {
|
|
394
|
+
const record = await credentials.readRecord(CRED_KEY);
|
|
395
|
+
const payload = record && record.kind === 'grant' ? record.payload : undefined;
|
|
396
|
+
if (!payload || payload.type !== 'oauth' || !payload.refresh)
|
|
397
|
+
return;
|
|
398
|
+
const msLeft = typeof payload.expires === 'number' ? payload.expires - Date.now() : 0;
|
|
399
|
+
if (msLeft > REFRESH_AHEAD_MS)
|
|
400
|
+
return; // still fresh; nothing to do
|
|
401
|
+
const res = await fetch(TOKEN_URL, {
|
|
402
|
+
method: 'POST',
|
|
403
|
+
signal: AbortSignal.timeout(30000),
|
|
404
|
+
headers: { 'content-type': 'application/x-www-form-urlencoded' },
|
|
405
|
+
body: new URLSearchParams({
|
|
406
|
+
grant_type: 'refresh_token',
|
|
407
|
+
client_id: CLIENT_ID,
|
|
408
|
+
refresh_token: payload.refresh,
|
|
409
|
+
}),
|
|
410
|
+
});
|
|
411
|
+
if (!res.ok)
|
|
412
|
+
return; // keep the old grant; user can re-authorize if it expires
|
|
413
|
+
const json = await res.json().catch(() => undefined);
|
|
414
|
+
if (!json || typeof json.access_token !== 'string' || json.access_token.length === 0)
|
|
415
|
+
return;
|
|
416
|
+
const next = {
|
|
417
|
+
...payload,
|
|
418
|
+
access: json.access_token,
|
|
419
|
+
refresh: typeof json.refresh_token === 'string' && json.refresh_token.length > 0 ? json.refresh_token : payload.refresh,
|
|
420
|
+
expires: Date.now() + Number(json.expires_in ?? 0) * 1000,
|
|
421
|
+
};
|
|
422
|
+
if (!(next.expires > Date.now()))
|
|
423
|
+
return;
|
|
424
|
+
await credentials.modifyRecord(CRED_KEY, async () => ({ kind: 'grant', payload: next }));
|
|
425
|
+
}
|
|
426
|
+
catch {
|
|
427
|
+
// silent: keep the old grant on any failure
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
387
431
|
// ---------------------------------------------------------------------------
|
|
388
432
|
// plugin entry
|
|
389
433
|
// ---------------------------------------------------------------------------
|
|
@@ -391,4 +435,5 @@ export function apply(ctx, _config = {}) {
|
|
|
391
435
|
const credentials = ctx.credentials;
|
|
392
436
|
const phase = { phase: 'idle' };
|
|
393
437
|
registerCodexAuthRpc(ctx, credentials, phase);
|
|
438
|
+
void silentRefresh(credentials);
|
|
394
439
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunshaobei/dsh-codex-auth",
|
|
3
3
|
"description": "Codex 订阅授权管理 for the dsh web surface: a dedicated settings page (authorization status, validity/expiry, one-click browser OAuth) plus an expired-credential modal when a GPT model is selected. Host half runs the full OpenAI OAuth flow (PKCE S256, localhost:1455 callback) and writes the llm-pi-ai/openai-codex grant record through ctx.credentials.",
|
|
4
|
-
"version": "3.0.
|
|
4
|
+
"version": "3.0.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|
|
7
7
|
"types": "lib/index.d.ts",
|