@narumitw/pi-usage 0.60.10 → 0.60.11
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/README.md +4 -3
- package/dist/index.ts +39 -5
- package/dist/index.ts.map +2 -2
- package/package.json +1 -1
- package/src/codex-resets.ts +7 -4
- package/src/oauth-credential-source.ts +39 -2
- package/src/query.ts +9 -2
package/package.json
CHANGED
package/src/codex-resets.ts
CHANGED
|
@@ -101,11 +101,18 @@ export async function resolveCodexResetAuth(
|
|
|
101
101
|
const expectedModel = `${model.provider}/${model.id}`;
|
|
102
102
|
const adapter = adapterForProvider("openai-codex");
|
|
103
103
|
if (!adapter) throw new Error("OpenAI Codex usage support is unavailable.");
|
|
104
|
+
if (candidateReader?.waitUntilReady && !(await candidateReader.waitUntilReady(ctx, "openai-codex"))) {
|
|
105
|
+
throw new Error("OpenAI Codex OAuth credential readiness failed closed.");
|
|
106
|
+
}
|
|
104
107
|
const auth = await resolveUsageAuth(ctx, adapter, salt, credentialReader);
|
|
105
108
|
if (`${ctx.model?.provider}/${ctx.model?.id}` !== expectedModel) {
|
|
106
109
|
throw new Error("The current model changed while resolving Codex reset authentication.");
|
|
107
110
|
}
|
|
108
111
|
if (!auth) throw new Error("No runtime credential is configured for OpenAI Codex.");
|
|
112
|
+
const offered = candidateReader
|
|
113
|
+
? await candidateReader(ctx, "openai-codex")
|
|
114
|
+
: fallbackOAuthCredentialCandidates("openai-codex", credentialReader);
|
|
115
|
+
if (!offered.ok) throw new Error("OpenAI Codex OAuth credential discovery failed closed.");
|
|
109
116
|
|
|
110
117
|
const resolvedAccess = bearerToken(headerValue(auth.headers, "Authorization")) ?? auth.apiKey;
|
|
111
118
|
if (!resolvedAccess) throw new Error("OpenAI Codex OAuth credentials were incomplete.");
|
|
@@ -113,10 +120,6 @@ export async function resolveCodexResetAuth(
|
|
|
113
120
|
if (!resolvedAccountId) {
|
|
114
121
|
throw new Error("The active OpenAI Codex access token did not contain a valid account ID.");
|
|
115
122
|
}
|
|
116
|
-
const offered = candidateReader
|
|
117
|
-
? candidateReader(ctx, "openai-codex")
|
|
118
|
-
: fallbackOAuthCredentialCandidates("openai-codex", credentialReader);
|
|
119
|
-
if (!offered.ok) throw new Error("OpenAI Codex OAuth credential discovery failed closed.");
|
|
120
123
|
const { accountId, storedAccess } = selectCodexResetCredential(
|
|
121
124
|
offered.candidates,
|
|
122
125
|
resolvedAccess,
|
|
@@ -2,6 +2,7 @@ import type { OAuthCredential } from "@earendil-works/pi-ai";
|
|
|
2
2
|
import { type ExtensionAPI, type ExtensionContext, readStoredCredential } from "@earendil-works/pi-coding-agent";
|
|
3
3
|
|
|
4
4
|
export const OAUTH_CREDENTIAL_SOURCE_CHANNEL = "oauth:credential-source:v1";
|
|
5
|
+
export const OAUTH_CREDENTIAL_READINESS_CHANNEL = "oauth:credential-readiness:v1";
|
|
5
6
|
|
|
6
7
|
export type StoredCredentialReader = (providerId: string) => unknown;
|
|
7
8
|
|
|
@@ -9,13 +10,19 @@ export type OAuthCredentialCandidates =
|
|
|
9
10
|
| { ok: true; candidates: readonly OAuthCredential[]; offeredCount?: number }
|
|
10
11
|
| { ok: false };
|
|
11
12
|
|
|
12
|
-
export type OAuthCredentialCandidateReader =
|
|
13
|
+
export type OAuthCredentialCandidateReader = {
|
|
14
|
+
(ctx: ExtensionContext, providerId: string): OAuthCredentialCandidates | Promise<OAuthCredentialCandidates>;
|
|
15
|
+
waitUntilReady?(ctx: ExtensionContext, providerId: string): Promise<boolean>;
|
|
16
|
+
};
|
|
13
17
|
|
|
14
18
|
export function createOAuthCredentialCandidateReader(
|
|
15
19
|
pi: ExtensionAPI,
|
|
16
20
|
credentialReader: StoredCredentialReader = readStoredCredential,
|
|
17
21
|
): OAuthCredentialCandidateReader {
|
|
18
|
-
|
|
22
|
+
const reader: OAuthCredentialCandidateReader = (ctx, providerId) =>
|
|
23
|
+
collectOAuthCredentialCandidates(pi, ctx, providerId, credentialReader);
|
|
24
|
+
reader.waitUntilReady = (ctx, providerId) => waitForOAuthCredentialSources(pi, ctx, providerId);
|
|
25
|
+
return reader;
|
|
19
26
|
}
|
|
20
27
|
|
|
21
28
|
export function collectOAuthCredentialCandidates(
|
|
@@ -52,6 +59,36 @@ export function collectOAuthCredentialCandidates(
|
|
|
52
59
|
return { ok: true, candidates, offeredCount };
|
|
53
60
|
}
|
|
54
61
|
|
|
62
|
+
async function waitForOAuthCredentialSources(
|
|
63
|
+
pi: Pick<ExtensionAPI, "events">,
|
|
64
|
+
ctx: ExtensionContext,
|
|
65
|
+
providerId: string,
|
|
66
|
+
): Promise<boolean> {
|
|
67
|
+
const pending: Promise<unknown>[] = [];
|
|
68
|
+
let collecting = true;
|
|
69
|
+
const request = Object.freeze({
|
|
70
|
+
session: ctx.sessionManager,
|
|
71
|
+
provider: providerId,
|
|
72
|
+
waitUntil(value: unknown) {
|
|
73
|
+
if (!collecting || !(value instanceof Promise)) return;
|
|
74
|
+
pending.push(value);
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
try {
|
|
78
|
+
pi.events.emit(OAUTH_CREDENTIAL_READINESS_CHANNEL, request);
|
|
79
|
+
} catch {
|
|
80
|
+
return false;
|
|
81
|
+
} finally {
|
|
82
|
+
collecting = false;
|
|
83
|
+
}
|
|
84
|
+
try {
|
|
85
|
+
await Promise.all(pending);
|
|
86
|
+
return true;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
55
92
|
export function fallbackOAuthCredentialCandidates(
|
|
56
93
|
providerId: string,
|
|
57
94
|
credentialReader: StoredCredentialReader,
|
package/src/query.ts
CHANGED
|
@@ -343,6 +343,13 @@ export async function resolveUsageAuth(
|
|
|
343
343
|
|
|
344
344
|
const model = candidateModels(ctx, adapter.id).find((candidate) => hasOfficialOrigin(candidate, adapter.id));
|
|
345
345
|
if (!model) return undefined;
|
|
346
|
+
if (
|
|
347
|
+
["github-copilot", "xai"].includes(adapter.id) &&
|
|
348
|
+
candidateReader?.waitUntilReady &&
|
|
349
|
+
!(await candidateReader.waitUntilReady(ctx, adapter.id))
|
|
350
|
+
) {
|
|
351
|
+
throw new Error(`${adapter.displayName} OAuth credential readiness failed closed.`);
|
|
352
|
+
}
|
|
346
353
|
// SAFETY: Pi exposes the required auth methods at runtime, and checks below narrow them before use.
|
|
347
354
|
const registry = ctx.modelRegistry as unknown as UsageAuthRegistry;
|
|
348
355
|
const provider = registry.getProvider?.(adapter.id);
|
|
@@ -416,7 +423,7 @@ export async function resolveUsageAuth(
|
|
|
416
423
|
};
|
|
417
424
|
if (adapter.id === "github-copilot") {
|
|
418
425
|
const offered = candidateReader
|
|
419
|
-
? candidateReader(ctx, adapter.id)
|
|
426
|
+
? await candidateReader(ctx, adapter.id)
|
|
420
427
|
: fallbackOAuthCredentialCandidates(adapter.id, credentialReader);
|
|
421
428
|
if (!offered.ok) {
|
|
422
429
|
throw new Error("GitHub Copilot OAuth credential discovery failed closed.");
|
|
@@ -425,7 +432,7 @@ export async function resolveUsageAuth(
|
|
|
425
432
|
}
|
|
426
433
|
if (adapter.id === "xai") {
|
|
427
434
|
const offered = candidateReader
|
|
428
|
-
? candidateReader(ctx, adapter.id)
|
|
435
|
+
? await candidateReader(ctx, adapter.id)
|
|
429
436
|
: fallbackOAuthCredentialCandidates(adapter.id, credentialReader);
|
|
430
437
|
if (!offered.ok) throw new Error("xAI OAuth credential discovery failed closed.");
|
|
431
438
|
return finalize(resolveXaiUsageAuth(auth, model, salt, offered.candidates));
|