@victor-software-house/pi-multicodex 2.0.8 → 2.0.9
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/account-manager.ts +68 -0
- package/package.json +2 -1
package/account-manager.ts
CHANGED
|
@@ -2,6 +2,7 @@ import {
|
|
|
2
2
|
type OAuthCredentials,
|
|
3
3
|
refreshOpenAICodexToken,
|
|
4
4
|
} from "@mariozechner/pi-ai/oauth";
|
|
5
|
+
import { AuthStorage } from "@mariozechner/pi-coding-agent";
|
|
5
6
|
import { normalizeUnknownError } from "pi-provider-utils/streams";
|
|
6
7
|
import { loadImportedOpenAICodexAuth } from "./auth";
|
|
7
8
|
import { isAccountAvailable, pickBestAccount } from "./selection";
|
|
@@ -343,6 +344,12 @@ export class AccountManager {
|
|
|
343
344
|
return account.accessToken;
|
|
344
345
|
}
|
|
345
346
|
|
|
347
|
+
// For the imported pi account, delegate to AuthStorage so we share pi's
|
|
348
|
+
// file lock and never race with pi's own refresh path.
|
|
349
|
+
if (account.importSource === "pi-openai-codex") {
|
|
350
|
+
return this.ensureValidTokenForImportedAccount(account);
|
|
351
|
+
}
|
|
352
|
+
|
|
346
353
|
const inflight = this.refreshPromises.get(account.email);
|
|
347
354
|
if (inflight) {
|
|
348
355
|
return inflight;
|
|
@@ -370,4 +377,65 @@ export class AccountManager {
|
|
|
370
377
|
this.refreshPromises.set(account.email, promise);
|
|
371
378
|
return promise;
|
|
372
379
|
}
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Refresh path for the imported pi account.
|
|
383
|
+
*
|
|
384
|
+
* Uses AuthStorage so our refresh is serialised by the same file lock that
|
|
385
|
+
* pi's own credential refresh uses. This prevents "refresh_token_reused"
|
|
386
|
+
* errors caused by pi and multicodex both refreshing the same token
|
|
387
|
+
* simultaneously.
|
|
388
|
+
*/
|
|
389
|
+
private async ensureValidTokenForImportedAccount(
|
|
390
|
+
account: Account,
|
|
391
|
+
): Promise<string> {
|
|
392
|
+
// Check if pi already refreshed since our last sync.
|
|
393
|
+
const latest = await loadImportedOpenAICodexAuth();
|
|
394
|
+
if (latest && Date.now() < latest.credentials.expires - 5 * 60 * 1000) {
|
|
395
|
+
account.accessToken = latest.credentials.access;
|
|
396
|
+
account.refreshToken = latest.credentials.refresh;
|
|
397
|
+
account.expiresAt = latest.credentials.expires;
|
|
398
|
+
account.importFingerprint = latest.fingerprint;
|
|
399
|
+
const accountId =
|
|
400
|
+
typeof latest.credentials.accountId === "string"
|
|
401
|
+
? latest.credentials.accountId
|
|
402
|
+
: undefined;
|
|
403
|
+
if (accountId) {
|
|
404
|
+
account.accountId = accountId;
|
|
405
|
+
}
|
|
406
|
+
this.save();
|
|
407
|
+
this.notifyStateChanged();
|
|
408
|
+
return account.accessToken;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// Both our copy and auth.json are expired — let AuthStorage refresh with
|
|
412
|
+
// its file lock so only one caller (us or pi) fires the API call.
|
|
413
|
+
const authStorage = AuthStorage.create();
|
|
414
|
+
const apiKey = await authStorage.getApiKey("openai-codex");
|
|
415
|
+
if (!apiKey) {
|
|
416
|
+
throw new Error(
|
|
417
|
+
"OpenAI Codex: token refresh failed — please re-authenticate with /login",
|
|
418
|
+
);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
// Read the refreshed tokens back from auth.json.
|
|
422
|
+
const refreshed = await loadImportedOpenAICodexAuth();
|
|
423
|
+
if (refreshed) {
|
|
424
|
+
account.accessToken = refreshed.credentials.access;
|
|
425
|
+
account.refreshToken = refreshed.credentials.refresh;
|
|
426
|
+
account.expiresAt = refreshed.credentials.expires;
|
|
427
|
+
account.importFingerprint = refreshed.fingerprint;
|
|
428
|
+
const accountId =
|
|
429
|
+
typeof refreshed.credentials.accountId === "string"
|
|
430
|
+
? refreshed.credentials.accountId
|
|
431
|
+
: undefined;
|
|
432
|
+
if (accountId) {
|
|
433
|
+
account.accountId = accountId;
|
|
434
|
+
}
|
|
435
|
+
this.save();
|
|
436
|
+
this.notifyStateChanged();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
return apiKey;
|
|
440
|
+
}
|
|
373
441
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@victor-software-house/pi-multicodex",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "Codex account rotation extension for pi",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -89,6 +89,7 @@
|
|
|
89
89
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
90
90
|
"@types/node": "^25.5.0",
|
|
91
91
|
"@typescript/native-preview": "7.0.0-dev.20260314.1",
|
|
92
|
+
"conventional-changelog-conventionalcommits": "^9.3.0",
|
|
92
93
|
"semantic-release": "^25.0.3",
|
|
93
94
|
"typescript": "^5.9.3",
|
|
94
95
|
"vitest": "^4.1.0"
|