@sunshaobei/dsh-codex-auth 3.0.2 → 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/cordis.patch.yml CHANGED
@@ -8,5 +8,5 @@
8
8
 
9
9
  - insert:
10
10
  - id: dsh-codex-auth
11
- name: 'dsh-codex-auth'
11
+ name: '@sunshaobei/dsh-codex-auth'
12
12
  config: {}
package/lib/client.js CHANGED
@@ -13,7 +13,7 @@
13
13
  * `/dsh-codex-auth` (status / login / logout).
14
14
  */
15
15
  window.__ModuleLoader__.load({
16
- id: "dsh-codex-auth",
16
+ id: "@sunshaobei/dsh-codex-auth",
17
17
  factory: (require) => {
18
18
  var module = { exports: {} };
19
19
  var exports = module.exports;
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.2",
4
+ "version": "3.0.4",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
7
7
  "types": "lib/index.d.ts",