@vostride/agent-qa-subscription-auth 0.0.1 → 0.1.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/LICENSE.md ADDED
@@ -0,0 +1,105 @@
1
+ # Functional Source License, Version 1.1, ALv2 Future License
2
+
3
+ ## Abbreviation
4
+
5
+ FSL-1.1-ALv2
6
+
7
+ ## Notice
8
+
9
+ Copyright 2026 Pranshu Chittora
10
+
11
+ ## Terms and Conditions
12
+
13
+ ### Licensor ("We")
14
+
15
+ The party offering the Software under these Terms and Conditions.
16
+
17
+ ### The Software
18
+
19
+ The "Software" is each version of the software that we make available under
20
+ these Terms and Conditions, as indicated by our inclusion of these Terms and
21
+ Conditions with the Software.
22
+
23
+ ### License Grant
24
+
25
+ Subject to your compliance with this License Grant and the Patents,
26
+ Redistribution and Trademark clauses below, we hereby grant you the right to
27
+ use, copy, modify, create derivative works, publicly perform, publicly display
28
+ and redistribute the Software for any Permitted Purpose identified below.
29
+
30
+ ### Permitted Purpose
31
+
32
+ A Permitted Purpose is any purpose other than a Competing Use. A Competing Use
33
+ means making the Software available to others in a commercial product or
34
+ service that:
35
+
36
+ 1. substitutes for the Software;
37
+
38
+ 2. substitutes for any other product or service we offer using the Software
39
+ that exists as of the date we make the Software available; or
40
+
41
+ 3. offers the same or substantially similar functionality as the Software.
42
+
43
+ Permitted Purposes specifically include using the Software:
44
+
45
+ 1. for your internal use and access;
46
+
47
+ 2. for non-commercial education;
48
+
49
+ 3. for non-commercial research; and
50
+
51
+ 4. in connection with professional services that you provide to a licensee
52
+ using the Software in accordance with these Terms and Conditions.
53
+
54
+ ### Patents
55
+
56
+ To the extent your use for a Permitted Purpose would necessarily infringe our
57
+ patents, the license grant above includes a license under our patents. If you
58
+ make a claim against any party that the Software infringes or contributes to
59
+ the infringement of any patent, then your patent license to the Software ends
60
+ immediately.
61
+
62
+ ### Redistribution
63
+
64
+ The Terms and Conditions apply to all copies, modifications and derivatives of
65
+ the Software.
66
+
67
+ If you redistribute any copies, modifications or derivatives of the Software,
68
+ you must include a copy of or a link to these Terms and Conditions and not
69
+ remove any copyright notices provided in or with the Software.
70
+
71
+ ### Disclaimer
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR
74
+ IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR
75
+ PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
76
+
77
+ IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE
78
+ SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES,
79
+ EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
80
+
81
+ ### Trademarks
82
+
83
+ Except for displaying the License Details and identifying us as the origin of
84
+ the Software, you have no right under these Terms and Conditions to use our
85
+ trademarks, trade names, service marks or product names.
86
+
87
+ ## Grant of Future License
88
+
89
+ We hereby irrevocably grant you an additional license to use the Software under
90
+ the Apache License, Version 2.0 that is effective on the second anniversary of
91
+ the date we make the Software available. On or after that date, you may use the
92
+ Software under the Apache License, Version 2.0, in which case the following
93
+ will apply:
94
+
95
+ Licensed under the Apache License, Version 2.0 (the "License"); you may not use
96
+ this file except in compliance with the License.
97
+
98
+ You may obtain a copy of the License at
99
+
100
+ http://www.apache.org/licenses/LICENSE-2.0
101
+
102
+ Unless required by applicable law or agreed to in writing, software distributed
103
+ under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
104
+ CONDITIONS OF ANY KIND, either express or implied. See the License for the
105
+ specific language governing permissions and limitations under the License.
package/NOTICE.md ADDED
@@ -0,0 +1,11 @@
1
+ # AgentQA Subscription Auth Notice
2
+
3
+ AgentQA Subscription Auth is provided by Pranshu Chittora.
4
+
5
+ Copyright 2026 Pranshu Chittora
6
+
7
+ AgentQA Subscription Auth is licensed under the Functional Source License, Version 1.1, ALv2 Future License (FSL-1.1-ALv2). See `LICENSE.md` for the full license terms.
8
+
9
+ Under the Grant of Future License in `LICENSE.md`, each version of the Software is also granted under the Apache License, Version 2.0 effective on the second anniversary of the date that version was made available.
10
+
11
+ Third-party dependencies are distributed under their own license terms. This notice covers AgentQA Subscription Auth itself and does not replace or modify notices required by third-party dependency owners.
package/README.md ADDED
@@ -0,0 +1,44 @@
1
+ # agent-qa-subscription-auth
2
+
3
+ Subscription LLM auth providers for agent-qa.
4
+
5
+ Install this package next to `agent-qa` when you want to use `openai-subscription` or `anthropic-subscription` providers. `agent-qa init` writes the dependency into `package.json` for subscription-auth configs; install it with the package manager your project already uses.
6
+
7
+ ```json
8
+ {
9
+ "devDependencies": {
10
+ "@vostride/agent-qa-subscription-auth": "<agent-qa version>"
11
+ }
12
+ }
13
+ ```
14
+
15
+ Configure the `plugins.auth` array in `agent-qa.config.yaml`:
16
+
17
+ ```yaml
18
+ plugins:
19
+ auth:
20
+ - package: "@vostride/agent-qa-subscription-auth"
21
+ ```
22
+
23
+ Start `agent-qa dashboard` and authenticate subscription configs from the LLM configuration editor.
24
+
25
+ For local two-repo development, build this package and point AgentQA at the local entry file:
26
+
27
+ ```yaml
28
+ plugins:
29
+ auth:
30
+ - path: "../agent-qa-subscription-auth/dist/index.js"
31
+ ```
32
+
33
+ ## Compatibility
34
+
35
+ This package is released at the same version as `agent-qa` and declares the peer dependency `@vostride/agent-qa-core >=0.1.0`. Keep the installed `agent-qa` and subscription-auth versions aligned.
36
+
37
+ ## Release
38
+
39
+ Release operation, trusted publishing setup, and partial publish recovery are documented in [RELEASE.md](./RELEASE.md).
40
+
41
+ ## License
42
+
43
+ - [License](LICENSE.md)
44
+ - [Notice](NOTICE.md)
@@ -0,0 +1,46 @@
1
+ import { OAuthTokens, TokenRefreshFn, LLMAuthProviderPlugin } from '@vostride/agent-qa-core';
2
+
3
+ declare const ANTHROPIC_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
4
+ declare const ANTHROPIC_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
5
+ declare const ANTHROPIC_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
6
+ declare const ANTHROPIC_SCOPES = "org:create_api_key user:profile user:inference";
7
+ declare const ANTHROPIC_BETA_FLAGS = "oauth-2025-04-20,interleaved-thinking-2025-05-14";
8
+ declare function anthropicAuthorizeUrl(options: {
9
+ mode: 'max' | 'console';
10
+ pkce: {
11
+ verifier: string;
12
+ challenge: string;
13
+ };
14
+ }): string;
15
+ declare function anthropicExchangeCode(codeWithState: string, pkce: {
16
+ verifier: string;
17
+ }): Promise<OAuthTokens>;
18
+ declare const anthropicRefreshTokens: TokenRefreshFn;
19
+ declare function createAnthropicAuthFetch(getTokens: () => Promise<OAuthTokens>, onRefreshed: (tokens: OAuthTokens) => Promise<void>): typeof globalThis.fetch;
20
+
21
+ declare const CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
22
+ declare const CODEX_AUTH_BASE = "https://auth.openai.com";
23
+ declare const CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token";
24
+ declare const CODEX_SCOPES = "openid profile email offline_access";
25
+ declare const CODEX_API_URL = "https://chatgpt.com/backend-api/codex/responses";
26
+ declare const CODEX_DEFAULT_PORT = 1455;
27
+ declare function decodeJwtClaims(token: string): Record<string, unknown>;
28
+ declare function codexExchangeCode(code: string, redirectUri: string, pkce: {
29
+ verifier: string;
30
+ }): Promise<OAuthTokens>;
31
+ declare const codexRefreshTokens: TokenRefreshFn;
32
+ declare function codexBrowserAuth(options?: {
33
+ port?: number;
34
+ listenHost?: string;
35
+ }): Promise<{
36
+ authorizeUrl: string;
37
+ waitForCallback: Promise<OAuthTokens>;
38
+ cleanup: () => void;
39
+ }>;
40
+ declare function createCodexAuthFetch(getTokens: () => Promise<OAuthTokens>, onRefreshed: (tokens: OAuthTokens) => Promise<void>): typeof globalThis.fetch;
41
+
42
+ declare function createSubscriptionAuthPlugin(): {
43
+ providers: LLMAuthProviderPlugin[];
44
+ };
45
+
46
+ export { ANTHROPIC_BETA_FLAGS, ANTHROPIC_CLIENT_ID, ANTHROPIC_REDIRECT_URI, ANTHROPIC_SCOPES, ANTHROPIC_TOKEN_URL, CODEX_API_URL, CODEX_AUTH_BASE, CODEX_CLIENT_ID, CODEX_DEFAULT_PORT, CODEX_SCOPES, CODEX_TOKEN_URL, anthropicAuthorizeUrl, anthropicExchangeCode, anthropicRefreshTokens, codexBrowserAuth, codexExchangeCode, codexRefreshTokens, createAnthropicAuthFetch, createCodexAuthFetch, createSubscriptionAuthPlugin, decodeJwtClaims, createSubscriptionAuthPlugin as default };
package/dist/index.js ADDED
@@ -0,0 +1,693 @@
1
+ // src/anthropic.ts
2
+ import {
3
+ generatePKCE
4
+ } from "@vostride/agent-qa-core";
5
+ var ANTHROPIC_CLIENT_ID = "9d1c250a-e61b-44d9-88ed-5944d1962f5e";
6
+ var ANTHROPIC_TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
7
+ var ANTHROPIC_REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
8
+ var ANTHROPIC_SCOPES = "org:create_api_key user:profile user:inference";
9
+ var ANTHROPIC_BETA_FLAGS = "oauth-2025-04-20,interleaved-thinking-2025-05-14";
10
+ var SYSTEM_PREFIX = "You are Claude Code, Anthropic's official CLI for Claude.";
11
+ var TOOL_PREFIX = "mcp_";
12
+ var AUTH_BASES = {
13
+ max: "https://claude.ai/oauth/authorize",
14
+ console: "https://console.anthropic.com/oauth/authorize"
15
+ };
16
+ function anthropicAuthorizeUrl(options) {
17
+ const base = AUTH_BASES[options.mode];
18
+ const params = new URLSearchParams({
19
+ code: "true",
20
+ client_id: ANTHROPIC_CLIENT_ID,
21
+ response_type: "code",
22
+ redirect_uri: ANTHROPIC_REDIRECT_URI,
23
+ scope: ANTHROPIC_SCOPES,
24
+ code_challenge: options.pkce.challenge,
25
+ code_challenge_method: "S256",
26
+ state: options.pkce.verifier
27
+ });
28
+ return `${base}?${params.toString()}`;
29
+ }
30
+ function startAnthropicAuth() {
31
+ const pkce = generatePKCE();
32
+ return {
33
+ authorizeUrl: anthropicAuthorizeUrl({ mode: "max", pkce }),
34
+ sessionState: { verifier: pkce.verifier }
35
+ };
36
+ }
37
+ function readVerifier(sessionState) {
38
+ if (sessionState && typeof sessionState === "object" && typeof sessionState.verifier === "string") {
39
+ return sessionState.verifier;
40
+ }
41
+ throw new Error("Anthropic subscription auth session is missing PKCE verifier.");
42
+ }
43
+ async function exchangeAnthropicManualCode(ctx) {
44
+ return await anthropicExchangeCode(ctx.code, { verifier: readVerifier(ctx.sessionState) });
45
+ }
46
+ async function anthropicExchangeCode(codeWithState, pkce) {
47
+ const [code, state] = codeWithState.split("#");
48
+ const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {
49
+ method: "POST",
50
+ headers: { "Content-Type": "application/json" },
51
+ body: JSON.stringify({
52
+ code,
53
+ state: state ?? pkce.verifier,
54
+ grant_type: "authorization_code",
55
+ client_id: ANTHROPIC_CLIENT_ID,
56
+ redirect_uri: ANTHROPIC_REDIRECT_URI,
57
+ code_verifier: pkce.verifier
58
+ })
59
+ });
60
+ if (!res.ok) {
61
+ const text = await res.text();
62
+ throw new Error(`Anthropic token exchange failed: ${text}`);
63
+ }
64
+ const json = await res.json();
65
+ if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") {
66
+ throw new Error("Anthropic token exchange response is missing required fields");
67
+ }
68
+ return {
69
+ access: json.access_token,
70
+ refresh: json.refresh_token,
71
+ expires: Date.now() + json.expires_in * 1e3
72
+ };
73
+ }
74
+ var anthropicRefreshTokens = async (_provider, refreshToken) => {
75
+ const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {
76
+ method: "POST",
77
+ headers: { "Content-Type": "application/json" },
78
+ body: JSON.stringify({
79
+ grant_type: "refresh_token",
80
+ refresh_token: refreshToken,
81
+ client_id: ANTHROPIC_CLIENT_ID
82
+ })
83
+ });
84
+ if (!res.ok) {
85
+ const text = await res.text();
86
+ throw new Error(`Anthropic token refresh failed: ${text}`);
87
+ }
88
+ const json = await res.json();
89
+ if (typeof json.access_token !== "string" || typeof json.expires_in !== "number") {
90
+ throw new Error("Anthropic token refresh response is missing required fields");
91
+ }
92
+ return {
93
+ access: json.access_token,
94
+ refresh: typeof json.refresh_token === "string" ? json.refresh_token : refreshToken,
95
+ expires: Date.now() + json.expires_in * 1e3
96
+ };
97
+ };
98
+ function prefixToolName(name) {
99
+ return typeof name === "string" && !name.startsWith(TOOL_PREFIX) ? `${TOOL_PREFIX}${name}` : name;
100
+ }
101
+ function stripToolNamePrefix(name) {
102
+ return typeof name === "string" && name.startsWith(TOOL_PREFIX) ? name.slice(TOOL_PREFIX.length) : name;
103
+ }
104
+ function createAnthropicAuthFetch(getTokens, onRefreshed) {
105
+ return async (input, init) => {
106
+ let tokens = await getTokens();
107
+ if (tokens.expires < Date.now()) {
108
+ tokens = await anthropicRefreshTokens("anthropic-subscription", tokens.refresh);
109
+ await onRefreshed(tokens);
110
+ }
111
+ const headers = new Headers();
112
+ if (input instanceof Request) {
113
+ input.headers.forEach((value, key) => {
114
+ headers.set(key, value);
115
+ });
116
+ }
117
+ if (init?.headers) {
118
+ if (init.headers instanceof Headers) {
119
+ init.headers.forEach((value, key) => {
120
+ headers.set(key, value);
121
+ });
122
+ } else if (Array.isArray(init.headers)) {
123
+ for (const [key, value] of init.headers) {
124
+ if (value !== void 0) headers.set(key, String(value));
125
+ }
126
+ } else {
127
+ for (const [key, value] of Object.entries(init.headers)) {
128
+ if (value !== void 0) headers.set(key, String(value));
129
+ }
130
+ }
131
+ }
132
+ const incoming = (headers.get("anthropic-beta") || "").split(",").map((b) => b.trim()).filter(Boolean);
133
+ const required = ANTHROPIC_BETA_FLAGS.split(",");
134
+ const merged = [.../* @__PURE__ */ new Set([...required, ...incoming])].join(",");
135
+ headers.delete("authorization");
136
+ headers.delete("x-api-key");
137
+ headers.set("Authorization", `Bearer ${tokens.access}`);
138
+ headers.set("anthropic-beta", merged);
139
+ headers.set("user-agent", "claude-cli/2.1.2 (external, cli)");
140
+ let body = init?.body;
141
+ if (body && typeof body === "string") {
142
+ try {
143
+ const parsed = JSON.parse(body);
144
+ if (parsed.system && Array.isArray(parsed.system)) {
145
+ parsed.system = [{ type: "text", text: SYSTEM_PREFIX }, ...parsed.system];
146
+ } else if (typeof parsed.system === "string") {
147
+ parsed.system = SYSTEM_PREFIX + "\n\n" + parsed.system;
148
+ } else if (!parsed.system) {
149
+ parsed.system = [{ type: "text", text: SYSTEM_PREFIX }];
150
+ }
151
+ if (parsed.tools && Array.isArray(parsed.tools)) {
152
+ parsed.tools = parsed.tools.map((tool) => ({
153
+ ...tool,
154
+ name: prefixToolName(tool.name)
155
+ }));
156
+ }
157
+ if (parsed.messages && Array.isArray(parsed.messages)) {
158
+ parsed.messages = parsed.messages.map((msg) => {
159
+ if (msg.content && Array.isArray(msg.content)) {
160
+ msg.content = msg.content.map((block) => {
161
+ if (block.type === "tool_use" && block.name) {
162
+ return { ...block, name: prefixToolName(block.name) };
163
+ }
164
+ return block;
165
+ });
166
+ }
167
+ return msg;
168
+ });
169
+ }
170
+ body = JSON.stringify(parsed);
171
+ } catch {
172
+ }
173
+ }
174
+ let url;
175
+ if (typeof input === "string") url = input;
176
+ else if (input instanceof URL) url = input.toString();
177
+ else url = input.url;
178
+ try {
179
+ const parsed = new URL(url);
180
+ if (parsed.pathname === "/v1/messages" && !parsed.searchParams.has("beta")) {
181
+ parsed.searchParams.set("beta", "true");
182
+ url = parsed.toString();
183
+ }
184
+ } catch {
185
+ }
186
+ const response = await globalThis.fetch(url, {
187
+ ...init,
188
+ body,
189
+ headers
190
+ });
191
+ if (!response.ok) {
192
+ const text = await response.text();
193
+ return new Response(text, {
194
+ status: response.status,
195
+ statusText: response.statusText,
196
+ headers: response.headers
197
+ });
198
+ }
199
+ if (response.body) {
200
+ const stream = response.body.pipeThrough(createAnthropicToolNameTransform());
201
+ return new Response(stream, {
202
+ status: response.status,
203
+ statusText: response.statusText,
204
+ headers: response.headers
205
+ });
206
+ }
207
+ return response;
208
+ };
209
+ }
210
+ function createAnthropicToolNameTransform() {
211
+ const decoder = new TextDecoder();
212
+ const encoder = new TextEncoder();
213
+ let pending = "";
214
+ return new TransformStream({
215
+ transform(chunk, controller) {
216
+ pending += decoder.decode(chunk, { stream: true });
217
+ let newlineIndex = pending.indexOf("\n");
218
+ while (newlineIndex !== -1) {
219
+ const line = pending.slice(0, newlineIndex + 1);
220
+ pending = pending.slice(newlineIndex + 1);
221
+ controller.enqueue(encoder.encode(rewriteAnthropicEventLine(line)));
222
+ newlineIndex = pending.indexOf("\n");
223
+ }
224
+ },
225
+ flush(controller) {
226
+ pending += decoder.decode();
227
+ if (pending) {
228
+ controller.enqueue(encoder.encode(rewriteAnthropicEventLine(pending)));
229
+ pending = "";
230
+ }
231
+ }
232
+ });
233
+ }
234
+ function rewriteAnthropicEventLine(line) {
235
+ const match = /^(data:\s*)(.*?)(\r?\n?)$/.exec(line);
236
+ if (!match) return line;
237
+ const [, prefix, jsonText, suffix] = match;
238
+ if (!jsonText || jsonText === "[DONE]") return line;
239
+ try {
240
+ const event = JSON.parse(jsonText);
241
+ rewriteToolUseNames(event);
242
+ return `${prefix}${JSON.stringify(event)}${suffix}`;
243
+ } catch {
244
+ return line;
245
+ }
246
+ }
247
+ function rewriteToolUseNames(value) {
248
+ if (!value || typeof value !== "object") return;
249
+ if (Array.isArray(value)) {
250
+ for (const item of value) rewriteToolUseNames(item);
251
+ return;
252
+ }
253
+ const record = value;
254
+ if (record.type === "tool_use") {
255
+ record.name = stripToolNamePrefix(record.name);
256
+ }
257
+ for (const item of Object.values(record)) {
258
+ rewriteToolUseNames(item);
259
+ }
260
+ }
261
+
262
+ // src/openai-codex.ts
263
+ import { createServer } from "http";
264
+ import {
265
+ createAuthFetch,
266
+ generatePKCE as generatePKCE2,
267
+ generateState
268
+ } from "@vostride/agent-qa-core";
269
+ var CODEX_CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
270
+ var CODEX_AUTH_BASE = "https://auth.openai.com";
271
+ var CODEX_TOKEN_URL = "https://auth.openai.com/oauth/token";
272
+ var CODEX_SCOPES = "openid profile email offline_access";
273
+ var CODEX_API_URL = "https://chatgpt.com/backend-api/codex/responses";
274
+ var CODEX_DEFAULT_PORT = 1455;
275
+ var CODEX_CALLBACK_HOST = "localhost";
276
+ var CODEX_LISTEN_HOST = "127.0.0.1";
277
+ function decodeJwtClaims(token) {
278
+ const parts = token.split(".");
279
+ if (parts.length < 3) throw new Error("Invalid JWT: expected 3 segments");
280
+ const payload = parts[1];
281
+ const decoded = Buffer.from(payload, "base64url").toString("utf-8");
282
+ return JSON.parse(decoded);
283
+ }
284
+ function extractAccountId(idToken) {
285
+ try {
286
+ const claims = decodeJwtClaims(idToken);
287
+ const authClaim = claims["https://api.openai.com/auth"];
288
+ if (authClaim && typeof authClaim === "object") {
289
+ const userIdStr = authClaim.user_id ?? authClaim.account_id;
290
+ if (userIdStr) return userIdStr;
291
+ }
292
+ return claims.sub ?? void 0;
293
+ } catch {
294
+ return void 0;
295
+ }
296
+ }
297
+ async function codexExchangeCode(code, redirectUri, pkce) {
298
+ const body = new URLSearchParams({
299
+ grant_type: "authorization_code",
300
+ client_id: CODEX_CLIENT_ID,
301
+ code,
302
+ redirect_uri: redirectUri,
303
+ code_verifier: pkce.verifier
304
+ });
305
+ const res = await globalThis.fetch(CODEX_TOKEN_URL, {
306
+ method: "POST",
307
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
308
+ body: body.toString()
309
+ });
310
+ if (!res.ok) {
311
+ const text = await res.text();
312
+ throw new Error(`Codex token exchange failed: ${text}`);
313
+ }
314
+ const json = await res.json();
315
+ if (typeof json.access_token !== "string" || typeof json.refresh_token !== "string" || typeof json.expires_in !== "number") {
316
+ throw new Error("Codex token exchange response is missing required fields");
317
+ }
318
+ const accountId = typeof json.id_token === "string" ? extractAccountId(json.id_token) : void 0;
319
+ return {
320
+ access: json.access_token,
321
+ refresh: json.refresh_token,
322
+ expires: Date.now() + json.expires_in * 1e3,
323
+ accountId
324
+ };
325
+ }
326
+ var codexRefreshTokens = async (_provider, refreshToken) => {
327
+ const body = new URLSearchParams({
328
+ grant_type: "refresh_token",
329
+ client_id: CODEX_CLIENT_ID,
330
+ refresh_token: refreshToken
331
+ });
332
+ const res = await globalThis.fetch(CODEX_TOKEN_URL, {
333
+ method: "POST",
334
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
335
+ body: body.toString()
336
+ });
337
+ if (!res.ok) {
338
+ const text = await res.text();
339
+ throw new Error(`Codex token refresh failed: ${text}`);
340
+ }
341
+ const json = await res.json();
342
+ if (typeof json.access_token !== "string" || typeof json.expires_in !== "number") {
343
+ throw new Error("Codex token refresh response is missing required fields");
344
+ }
345
+ const accountId = typeof json.id_token === "string" ? extractAccountId(json.id_token) : void 0;
346
+ return {
347
+ access: json.access_token,
348
+ refresh: typeof json.refresh_token === "string" ? json.refresh_token : refreshToken,
349
+ expires: Date.now() + json.expires_in * 1e3,
350
+ accountId
351
+ };
352
+ };
353
+ async function codexBrowserAuth(options) {
354
+ const port = options?.port ?? CODEX_DEFAULT_PORT;
355
+ const listenHost = options?.listenHost ?? CODEX_LISTEN_HOST;
356
+ const redirectUri = `http://${CODEX_CALLBACK_HOST}:${port}/auth/callback`;
357
+ const pkce = generatePKCE2();
358
+ const state = generateState();
359
+ let server;
360
+ let resolveTokens;
361
+ let rejectTokens;
362
+ const waitForCallback = new Promise((resolve, reject) => {
363
+ resolveTokens = resolve;
364
+ rejectTokens = reject;
365
+ });
366
+ server = createServer(async (req, res) => {
367
+ const url = new URL(req.url ?? "/", redirectUri);
368
+ if (url.pathname === "/auth/callback") {
369
+ const code = url.searchParams.get("code");
370
+ const returnedState = url.searchParams.get("state");
371
+ if (returnedState !== state) {
372
+ res.writeHead(400, { "Content-Type": "text/html" });
373
+ res.end("<html><body>State mismatch. Please try again.</body></html>");
374
+ rejectTokens(new Error("OAuth state mismatch"));
375
+ return;
376
+ }
377
+ if (!code) {
378
+ res.writeHead(400, { "Content-Type": "text/html" });
379
+ res.end("<html><body>Missing authorization code.</body></html>");
380
+ rejectTokens(new Error("Missing authorization code"));
381
+ return;
382
+ }
383
+ try {
384
+ const tokens = await codexExchangeCode(code, redirectUri, {
385
+ verifier: pkce.verifier
386
+ });
387
+ res.writeHead(200, { "Content-Type": "text/html" });
388
+ res.end(
389
+ "<html><body>Authentication successful! You can close this tab.</body></html>"
390
+ );
391
+ resolveTokens(tokens);
392
+ } catch (err) {
393
+ res.writeHead(500, { "Content-Type": "text/html" });
394
+ res.end("<html><body>Token exchange failed.</body></html>");
395
+ rejectTokens(
396
+ err instanceof Error ? err : new Error("Token exchange failed")
397
+ );
398
+ }
399
+ } else {
400
+ res.writeHead(404);
401
+ res.end();
402
+ }
403
+ });
404
+ await new Promise((resolve, reject) => {
405
+ server.once("error", reject);
406
+ server.listen(port, listenHost, () => {
407
+ server.off("error", reject);
408
+ resolve();
409
+ });
410
+ });
411
+ const params = new URLSearchParams({
412
+ response_type: "code",
413
+ client_id: CODEX_CLIENT_ID,
414
+ redirect_uri: redirectUri,
415
+ scope: CODEX_SCOPES,
416
+ state,
417
+ code_challenge: pkce.challenge,
418
+ code_challenge_method: "S256"
419
+ });
420
+ const authorizeUrl = `${CODEX_AUTH_BASE}/oauth/authorize?${params.toString()}`;
421
+ const cleanup = () => {
422
+ server.close();
423
+ };
424
+ return { authorizeUrl, waitForCallback, cleanup };
425
+ }
426
+ function createCodexAuthFetch(getTokens, onRefreshed) {
427
+ const authFetch = createAuthFetch({
428
+ provider: "openai-codex",
429
+ getTokens,
430
+ refreshTokens: codexRefreshTokens,
431
+ onTokensRefreshed: onRefreshed,
432
+ headerTransform: (headers, tokens) => {
433
+ if (tokens.accountId) {
434
+ headers.set("ChatGPT-Account-Id", tokens.accountId);
435
+ }
436
+ },
437
+ urlTransform: (url) => {
438
+ if (url.includes("/v1/responses") || url.includes("/chat/completions")) {
439
+ return CODEX_API_URL;
440
+ }
441
+ return url;
442
+ }
443
+ });
444
+ return async (input, init) => {
445
+ const inputUrl = extractRequestUrl(input);
446
+ let forceStream = false;
447
+ let body = init?.body;
448
+ if (isCodexRequestUrl(inputUrl) && body && typeof body === "string") {
449
+ try {
450
+ const parsed = JSON.parse(body);
451
+ if (!parsed.stream) {
452
+ parsed.stream = true;
453
+ forceStream = true;
454
+ }
455
+ if (parsed.text?.format?.strict) {
456
+ parsed.text.format.strict = false;
457
+ }
458
+ body = JSON.stringify(parsed);
459
+ } catch {
460
+ }
461
+ }
462
+ const response = await authFetch(input, { ...init, body });
463
+ if (forceStream && response.ok && response.body) {
464
+ return bufferCodexSSEResponse(response);
465
+ }
466
+ return response;
467
+ };
468
+ }
469
+ function extractRequestUrl(input) {
470
+ if (typeof input === "string") return input;
471
+ if (input instanceof URL) return input.toString();
472
+ return input.url;
473
+ }
474
+ function isCodexRequestUrl(url) {
475
+ return url.includes("/v1/responses") || url.includes("/chat/completions") || url.includes("chatgpt.com/backend-api/codex");
476
+ }
477
+ async function bufferCodexSSEResponse(response) {
478
+ const reader = response.body.getReader();
479
+ const decoder = new TextDecoder();
480
+ let buffer = "";
481
+ let completedResponse = null;
482
+ let outputText = "";
483
+ const pendingOutputItems = /* @__PURE__ */ new Map();
484
+ const completedOutputItems = /* @__PURE__ */ new Map();
485
+ const functionCallArgumentDeltas = /* @__PURE__ */ new Map();
486
+ const customToolInputDeltas = /* @__PURE__ */ new Map();
487
+ const overallTimeout = setTimeout(() => {
488
+ try {
489
+ reader.cancel();
490
+ } catch {
491
+ }
492
+ }, 12e4);
493
+ try {
494
+ while (true) {
495
+ const chunkPromise = reader.read();
496
+ const timeoutPromise = new Promise(
497
+ (resolve) => setTimeout(() => resolve({ done: true, value: void 0 }), 3e4)
498
+ );
499
+ const { done, value } = await Promise.race([chunkPromise, timeoutPromise]);
500
+ if (done) break;
501
+ buffer += decoder.decode(value, { stream: true });
502
+ const lines = buffer.split("\n");
503
+ buffer = lines.pop() ?? "";
504
+ for (const line of lines) {
505
+ if (!line.startsWith("data: ")) continue;
506
+ const data = line.slice(6).trim();
507
+ if (data === "[DONE]") continue;
508
+ try {
509
+ const event = JSON.parse(data);
510
+ if (!isJSONRecord(event) || typeof event.type !== "string") continue;
511
+ if (event.type === "response.output_text.delta" && typeof event.delta === "string") {
512
+ outputText += event.delta;
513
+ }
514
+ if (event.type === "response.output_item.added" && typeof event.output_index === "number" && isJSONRecord(event.item)) {
515
+ pendingOutputItems.set(event.output_index, { ...event.item });
516
+ }
517
+ if (event.type === "response.function_call_arguments.delta" && typeof event.output_index === "number" && typeof event.delta === "string") {
518
+ const prev = functionCallArgumentDeltas.get(event.output_index) ?? "";
519
+ functionCallArgumentDeltas.set(event.output_index, prev + event.delta);
520
+ }
521
+ if (event.type === "response.custom_tool_call_input.delta" && typeof event.output_index === "number" && typeof event.delta === "string") {
522
+ const prev = customToolInputDeltas.get(event.output_index) ?? "";
523
+ customToolInputDeltas.set(event.output_index, prev + event.delta);
524
+ }
525
+ if (event.type === "response.output_item.done" && typeof event.output_index === "number" && isJSONRecord(event.item)) {
526
+ completedOutputItems.set(
527
+ event.output_index,
528
+ hydrateOutputItem(event.item, event.output_index, functionCallArgumentDeltas, customToolInputDeltas)
529
+ );
530
+ }
531
+ if ((event.type === "response.completed" || event.type === "response.incomplete") && isJSONRecord(event.response)) {
532
+ completedResponse = event.response;
533
+ }
534
+ } catch {
535
+ }
536
+ }
537
+ }
538
+ } finally {
539
+ clearTimeout(overallTimeout);
540
+ }
541
+ for (const [outputIndex, item] of pendingOutputItems) {
542
+ if (!completedOutputItems.has(outputIndex)) {
543
+ completedOutputItems.set(
544
+ outputIndex,
545
+ hydrateOutputItem(item, outputIndex, functionCallArgumentDeltas, customToolInputDeltas)
546
+ );
547
+ }
548
+ }
549
+ const bufferedOutput = [...completedOutputItems.entries()].sort(([left], [right]) => left - right).map(([, item]) => item);
550
+ const body = JSON.stringify(
551
+ ensureResponseMetadata(
552
+ completedResponse ? mergeBufferedOutputItems(completedResponse, bufferedOutput, outputText) : createBufferedResponse(bufferedOutput, outputText)
553
+ )
554
+ );
555
+ return new Response(body, {
556
+ status: 200,
557
+ headers: { "content-type": "application/json" }
558
+ });
559
+ }
560
+ function isJSONRecord(value) {
561
+ return value !== null && typeof value === "object" && !Array.isArray(value);
562
+ }
563
+ function hydrateOutputItem(item, outputIndex, functionCallArgumentDeltas, customToolInputDeltas) {
564
+ const hydrated = { ...item };
565
+ if (hydrated.type === "function_call" && typeof hydrated.arguments !== "string") {
566
+ hydrated.arguments = functionCallArgumentDeltas.get(outputIndex) ?? "";
567
+ }
568
+ if (hydrated.type === "custom_tool_call" && hydrated.input == null) {
569
+ const input = customToolInputDeltas.get(outputIndex);
570
+ if (input !== void 0) {
571
+ hydrated.input = safeParseJSON(input) ?? input;
572
+ }
573
+ }
574
+ return hydrated;
575
+ }
576
+ function mergeBufferedOutputItems(response, bufferedOutput, outputText) {
577
+ const existingOutput = Array.isArray(response.output) ? response.output.filter(isJSONRecord) : [];
578
+ if (bufferedOutput.length === 0) {
579
+ if (existingOutput.length > 0) return response;
580
+ return { ...response, output: [buildTextOutput(outputText)] };
581
+ }
582
+ const mergedOutput = [...existingOutput];
583
+ const seenKeys = new Set(existingOutput.map(getOutputItemKey).filter((key) => key !== null));
584
+ for (const item of bufferedOutput) {
585
+ const key = getOutputItemKey(item);
586
+ if (key && seenKeys.has(key)) continue;
587
+ if (key) seenKeys.add(key);
588
+ mergedOutput.push(item);
589
+ }
590
+ return { ...response, output: mergedOutput };
591
+ }
592
+ function createBufferedResponse(bufferedOutput, outputText) {
593
+ return {
594
+ id: "codex-buffered",
595
+ output: bufferedOutput.length > 0 ? bufferedOutput : [buildTextOutput(outputText)],
596
+ status: "completed"
597
+ };
598
+ }
599
+ function ensureResponseMetadata(response) {
600
+ if (typeof response.created_at === "number") return response;
601
+ return {
602
+ ...response,
603
+ created_at: Math.floor(Date.now() / 1e3)
604
+ };
605
+ }
606
+ function buildTextOutput(outputText) {
607
+ return {
608
+ type: "message",
609
+ role: "assistant",
610
+ content: [{ type: "output_text", text: outputText, annotations: [] }]
611
+ };
612
+ }
613
+ function getOutputItemKey(item) {
614
+ const type = typeof item.type === "string" ? item.type : "unknown";
615
+ if (typeof item.id === "string") return `${type}:${item.id}`;
616
+ if (typeof item.call_id === "string") return `${type}:${item.call_id}`;
617
+ return null;
618
+ }
619
+ function safeParseJSON(text) {
620
+ try {
621
+ return JSON.parse(text);
622
+ } catch {
623
+ return void 0;
624
+ }
625
+ }
626
+
627
+ // src/index.ts
628
+ function createSubscriptionAuthPlugin() {
629
+ return {
630
+ providers: [
631
+ {
632
+ providerId: "openai-subscription",
633
+ credentialProviderId: "openai-subscription-oauth",
634
+ label: "OpenAI subscription",
635
+ modelAdapter: "openai-responses",
636
+ dashboardAuth: { mode: "browser-poll", buttonLabel: "Login with OpenAI subscription" },
637
+ async startAuth() {
638
+ const result = await codexBrowserAuth();
639
+ return {
640
+ authorizeUrl: result.authorizeUrl,
641
+ waitForTokens: result.waitForCallback,
642
+ cleanup: result.cleanup
643
+ };
644
+ },
645
+ createAuthFetch({ getTokens, onRefreshed }) {
646
+ return createCodexAuthFetch(getTokens, onRefreshed);
647
+ }
648
+ },
649
+ {
650
+ providerId: "anthropic-subscription",
651
+ credentialProviderId: "anthropic-subscription",
652
+ label: "Anthropic subscription",
653
+ modelAdapter: "anthropic-messages",
654
+ dashboardAuth: { mode: "manual-code", buttonLabel: "Login with Anthropic subscription" },
655
+ async startAuth() {
656
+ return startAnthropicAuth();
657
+ },
658
+ async exchangeCode(ctx) {
659
+ return await exchangeAnthropicManualCode(ctx);
660
+ },
661
+ createAuthFetch({ getTokens, onRefreshed }) {
662
+ return createAnthropicAuthFetch(getTokens, onRefreshed);
663
+ }
664
+ }
665
+ ]
666
+ };
667
+ }
668
+ var index_default = createSubscriptionAuthPlugin;
669
+ export {
670
+ ANTHROPIC_BETA_FLAGS,
671
+ ANTHROPIC_CLIENT_ID,
672
+ ANTHROPIC_REDIRECT_URI,
673
+ ANTHROPIC_SCOPES,
674
+ ANTHROPIC_TOKEN_URL,
675
+ CODEX_API_URL,
676
+ CODEX_AUTH_BASE,
677
+ CODEX_CLIENT_ID,
678
+ CODEX_DEFAULT_PORT,
679
+ CODEX_SCOPES,
680
+ CODEX_TOKEN_URL,
681
+ anthropicAuthorizeUrl,
682
+ anthropicExchangeCode,
683
+ anthropicRefreshTokens,
684
+ codexBrowserAuth,
685
+ codexExchangeCode,
686
+ codexRefreshTokens,
687
+ createAnthropicAuthFetch,
688
+ createCodexAuthFetch,
689
+ createSubscriptionAuthPlugin,
690
+ decodeJwtClaims,
691
+ index_default as default
692
+ };
693
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/anthropic.ts","../src/openai-codex.ts","../src/index.ts"],"sourcesContent":["import {\n generatePKCE,\n type AuthProvider,\n type OAuthTokens,\n type TokenRefreshFn,\n} from '@vostride/agent-qa-core'\n\nexport const ANTHROPIC_CLIENT_ID = '9d1c250a-e61b-44d9-88ed-5944d1962f5e'\nexport const ANTHROPIC_TOKEN_URL = 'https://console.anthropic.com/v1/oauth/token'\nexport const ANTHROPIC_REDIRECT_URI = 'https://console.anthropic.com/oauth/code/callback'\nexport const ANTHROPIC_SCOPES = 'org:create_api_key user:profile user:inference'\nexport const ANTHROPIC_BETA_FLAGS = 'oauth-2025-04-20,interleaved-thinking-2025-05-14'\n\nconst SYSTEM_PREFIX = \"You are Claude Code, Anthropic's official CLI for Claude.\"\nconst TOOL_PREFIX = 'mcp_'\n\nconst AUTH_BASES: Record<string, string> = {\n max: 'https://claude.ai/oauth/authorize',\n console: 'https://console.anthropic.com/oauth/authorize',\n}\n\nexport function anthropicAuthorizeUrl(options: {\n mode: 'max' | 'console'\n pkce: { verifier: string; challenge: string }\n}): string {\n const base = AUTH_BASES[options.mode]\n const params = new URLSearchParams({\n code: 'true',\n client_id: ANTHROPIC_CLIENT_ID,\n response_type: 'code',\n redirect_uri: ANTHROPIC_REDIRECT_URI,\n scope: ANTHROPIC_SCOPES,\n code_challenge: options.pkce.challenge,\n code_challenge_method: 'S256',\n state: options.pkce.verifier,\n })\n return `${base}?${params.toString()}`\n}\n\nexport function startAnthropicAuth(): {\n authorizeUrl: string\n sessionState: { verifier: string }\n} {\n const pkce = generatePKCE()\n return {\n authorizeUrl: anthropicAuthorizeUrl({ mode: 'max', pkce }),\n sessionState: { verifier: pkce.verifier },\n }\n}\n\nfunction readVerifier(sessionState: unknown): string {\n if (\n sessionState\n && typeof sessionState === 'object'\n && typeof (sessionState as { verifier?: unknown }).verifier === 'string'\n ) {\n return (sessionState as { verifier: string }).verifier\n }\n throw new Error('Anthropic subscription auth session is missing PKCE verifier.')\n}\n\nexport async function exchangeAnthropicManualCode(ctx: {\n code: string\n sessionState: unknown\n}): Promise<OAuthTokens> {\n return await anthropicExchangeCode(ctx.code, { verifier: readVerifier(ctx.sessionState) })\n}\n\nexport async function anthropicExchangeCode(\n codeWithState: string,\n pkce: { verifier: string },\n): Promise<OAuthTokens> {\n const [code, state] = codeWithState.split('#')\n\n const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n code,\n state: state ?? pkce.verifier,\n grant_type: 'authorization_code',\n client_id: ANTHROPIC_CLIENT_ID,\n redirect_uri: ANTHROPIC_REDIRECT_URI,\n code_verifier: pkce.verifier,\n }),\n })\n\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`Anthropic token exchange failed: ${text}`)\n }\n\n const json = (await res.json()) as {\n access_token?: unknown\n refresh_token?: unknown\n expires_in?: unknown\n }\n\n if (\n typeof json.access_token !== 'string'\n || typeof json.refresh_token !== 'string'\n || typeof json.expires_in !== 'number'\n ) {\n throw new Error('Anthropic token exchange response is missing required fields')\n }\n\n return {\n access: json.access_token,\n refresh: json.refresh_token,\n expires: Date.now() + json.expires_in * 1000,\n }\n}\n\nexport const anthropicRefreshTokens: TokenRefreshFn = async (\n _provider: AuthProvider,\n refreshToken: string,\n): Promise<OAuthTokens> => {\n const res = await globalThis.fetch(ANTHROPIC_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({\n grant_type: 'refresh_token',\n refresh_token: refreshToken,\n client_id: ANTHROPIC_CLIENT_ID,\n }),\n })\n\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`Anthropic token refresh failed: ${text}`)\n }\n\n const json = (await res.json()) as {\n access_token?: unknown\n refresh_token?: unknown\n expires_in?: unknown\n }\n\n if (\n typeof json.access_token !== 'string'\n || typeof json.expires_in !== 'number'\n ) {\n throw new Error('Anthropic token refresh response is missing required fields')\n }\n\n return {\n access: json.access_token,\n refresh: typeof json.refresh_token === 'string' ? json.refresh_token : refreshToken,\n expires: Date.now() + json.expires_in * 1000,\n }\n}\n\nfunction prefixToolName(name: unknown): unknown {\n return typeof name === 'string' && !name.startsWith(TOOL_PREFIX) ? `${TOOL_PREFIX}${name}` : name\n}\n\nfunction stripToolNamePrefix(name: unknown): unknown {\n return typeof name === 'string' && name.startsWith(TOOL_PREFIX) ? name.slice(TOOL_PREFIX.length) : name\n}\n\nexport function createAnthropicAuthFetch(\n getTokens: () => Promise<OAuthTokens>,\n onRefreshed: (tokens: OAuthTokens) => Promise<void>,\n): typeof globalThis.fetch {\n return async (input: string | URL | Request, init?: RequestInit): Promise<Response> => {\n let tokens = await getTokens()\n\n if (tokens.expires < Date.now()) {\n tokens = await anthropicRefreshTokens('anthropic-subscription', tokens.refresh)\n await onRefreshed(tokens)\n }\n\n const headers = new Headers()\n if (input instanceof Request) {\n input.headers.forEach((value, key) => { headers.set(key, value) })\n }\n if (init?.headers) {\n if (init.headers instanceof Headers) {\n init.headers.forEach((value, key) => { headers.set(key, value) })\n } else if (Array.isArray(init.headers)) {\n for (const [key, value] of init.headers) {\n if (value !== undefined) headers.set(key, String(value))\n }\n } else {\n for (const [key, value] of Object.entries(init.headers)) {\n if (value !== undefined) headers.set(key, String(value))\n }\n }\n }\n\n const incoming = (headers.get('anthropic-beta') || '').split(',').map((b) => b.trim()).filter(Boolean)\n const required = ANTHROPIC_BETA_FLAGS.split(',')\n const merged = [...new Set([...required, ...incoming])].join(',')\n\n headers.delete('authorization')\n headers.delete('x-api-key')\n headers.set('Authorization', `Bearer ${tokens.access}`)\n headers.set('anthropic-beta', merged)\n headers.set('user-agent', 'claude-cli/2.1.2 (external, cli)')\n\n let body = init?.body\n if (body && typeof body === 'string') {\n try {\n const parsed = JSON.parse(body)\n\n if (parsed.system && Array.isArray(parsed.system)) {\n parsed.system = [{ type: 'text', text: SYSTEM_PREFIX }, ...parsed.system]\n } else if (typeof parsed.system === 'string') {\n parsed.system = SYSTEM_PREFIX + '\\n\\n' + parsed.system\n } else if (!parsed.system) {\n parsed.system = [{ type: 'text', text: SYSTEM_PREFIX }]\n }\n\n if (parsed.tools && Array.isArray(parsed.tools)) {\n parsed.tools = parsed.tools.map((tool: Record<string, unknown>) => ({\n ...tool,\n name: prefixToolName(tool.name),\n }))\n }\n\n if (parsed.messages && Array.isArray(parsed.messages)) {\n parsed.messages = parsed.messages.map((msg: Record<string, unknown>) => {\n if (msg.content && Array.isArray(msg.content)) {\n msg.content = msg.content.map((block: Record<string, unknown>) => {\n if (block.type === 'tool_use' && block.name) {\n return { ...block, name: prefixToolName(block.name) }\n }\n return block\n })\n }\n return msg\n })\n }\n\n body = JSON.stringify(parsed)\n } catch {\n // Leave non-JSON request bodies unchanged.\n }\n }\n\n let url: string\n if (typeof input === 'string') url = input\n else if (input instanceof URL) url = input.toString()\n else url = input.url\n\n try {\n const parsed = new URL(url)\n if (parsed.pathname === '/v1/messages' && !parsed.searchParams.has('beta')) {\n parsed.searchParams.set('beta', 'true')\n url = parsed.toString()\n }\n } catch {\n // Leave invalid URLs unchanged.\n }\n\n const response = await globalThis.fetch(url, {\n ...init,\n body,\n headers,\n })\n\n if (!response.ok) {\n const text = await response.text()\n return new Response(text, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n }\n\n if (response.body) {\n const stream = response.body.pipeThrough(createAnthropicToolNameTransform())\n\n return new Response(stream, {\n status: response.status,\n statusText: response.statusText,\n headers: response.headers,\n })\n }\n\n return response\n }\n}\n\nfunction createAnthropicToolNameTransform(): TransformStream<Uint8Array, Uint8Array> {\n const decoder = new TextDecoder()\n const encoder = new TextEncoder()\n let pending = ''\n\n return new TransformStream({\n transform(chunk, controller) {\n pending += decoder.decode(chunk, { stream: true })\n\n let newlineIndex = pending.indexOf('\\n')\n while (newlineIndex !== -1) {\n const line = pending.slice(0, newlineIndex + 1)\n pending = pending.slice(newlineIndex + 1)\n controller.enqueue(encoder.encode(rewriteAnthropicEventLine(line)))\n newlineIndex = pending.indexOf('\\n')\n }\n },\n flush(controller) {\n pending += decoder.decode()\n if (pending) {\n controller.enqueue(encoder.encode(rewriteAnthropicEventLine(pending)))\n pending = ''\n }\n },\n })\n}\n\nfunction rewriteAnthropicEventLine(line: string): string {\n const match = /^(data:\\s*)(.*?)(\\r?\\n?)$/.exec(line)\n if (!match) return line\n\n const [, prefix, jsonText, suffix] = match\n if (!jsonText || jsonText === '[DONE]') return line\n\n try {\n const event = JSON.parse(jsonText)\n rewriteToolUseNames(event)\n return `${prefix}${JSON.stringify(event)}${suffix}`\n } catch {\n return line\n }\n}\n\nfunction rewriteToolUseNames(value: unknown): void {\n if (!value || typeof value !== 'object') return\n\n if (Array.isArray(value)) {\n for (const item of value) rewriteToolUseNames(item)\n return\n }\n\n const record = value as Record<string, unknown>\n if (record.type === 'tool_use') {\n record.name = stripToolNamePrefix(record.name)\n }\n\n for (const item of Object.values(record)) {\n rewriteToolUseNames(item)\n }\n}\n","import { createServer, type Server } from 'node:http'\nimport {\n createAuthFetch,\n generatePKCE,\n generateState,\n type AuthProvider,\n type OAuthTokens,\n type TokenRefreshFn,\n} from '@vostride/agent-qa-core'\n\nexport const CODEX_CLIENT_ID = 'app_EMoamEEZ73f0CkXaXp7hrann'\nexport const CODEX_AUTH_BASE = 'https://auth.openai.com'\nexport const CODEX_TOKEN_URL = 'https://auth.openai.com/oauth/token'\nexport const CODEX_SCOPES = 'openid profile email offline_access'\nexport const CODEX_API_URL = 'https://chatgpt.com/backend-api/codex/responses'\nexport const CODEX_DEFAULT_PORT = 1455\nexport const CODEX_CALLBACK_HOST = 'localhost'\nexport const CODEX_LISTEN_HOST = '127.0.0.1'\n\ntype JSONRecord = Record<string, unknown>\n\nexport function decodeJwtClaims(token: string): Record<string, unknown> {\n const parts = token.split('.')\n if (parts.length < 3) throw new Error('Invalid JWT: expected 3 segments')\n const payload = parts[1]\n const decoded = Buffer.from(payload, 'base64url').toString('utf-8')\n return JSON.parse(decoded)\n}\n\nfunction extractAccountId(idToken: string): string | undefined {\n try {\n const claims = decodeJwtClaims(idToken)\n const authClaim = claims['https://api.openai.com/auth'] as\n | Record<string, unknown>\n | undefined\n if (authClaim && typeof authClaim === 'object') {\n const userIdStr =\n (authClaim.user_id as string) ?? (authClaim.account_id as string)\n if (userIdStr) return userIdStr\n }\n return (claims.sub as string) ?? undefined\n } catch {\n return undefined\n }\n}\n\nexport async function codexExchangeCode(\n code: string,\n redirectUri: string,\n pkce: { verifier: string },\n): Promise<OAuthTokens> {\n const body = new URLSearchParams({\n grant_type: 'authorization_code',\n client_id: CODEX_CLIENT_ID,\n code,\n redirect_uri: redirectUri,\n code_verifier: pkce.verifier,\n })\n\n const res = await globalThis.fetch(CODEX_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n })\n\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`Codex token exchange failed: ${text}`)\n }\n\n const json = (await res.json()) as {\n access_token?: unknown\n refresh_token?: unknown\n expires_in?: unknown\n id_token?: unknown\n }\n\n if (\n typeof json.access_token !== 'string'\n || typeof json.refresh_token !== 'string'\n || typeof json.expires_in !== 'number'\n ) {\n throw new Error('Codex token exchange response is missing required fields')\n }\n\n const accountId = typeof json.id_token === 'string'\n ? extractAccountId(json.id_token)\n : undefined\n\n return {\n access: json.access_token,\n refresh: json.refresh_token,\n expires: Date.now() + json.expires_in * 1000,\n accountId,\n }\n}\n\nexport const codexRefreshTokens: TokenRefreshFn = async (\n _provider: AuthProvider,\n refreshToken: string,\n): Promise<OAuthTokens> => {\n const body = new URLSearchParams({\n grant_type: 'refresh_token',\n client_id: CODEX_CLIENT_ID,\n refresh_token: refreshToken,\n })\n\n const res = await globalThis.fetch(CODEX_TOKEN_URL, {\n method: 'POST',\n headers: { 'Content-Type': 'application/x-www-form-urlencoded' },\n body: body.toString(),\n })\n\n if (!res.ok) {\n const text = await res.text()\n throw new Error(`Codex token refresh failed: ${text}`)\n }\n\n const json = (await res.json()) as {\n access_token?: unknown\n refresh_token?: unknown\n expires_in?: unknown\n id_token?: unknown\n }\n\n if (\n typeof json.access_token !== 'string'\n || typeof json.expires_in !== 'number'\n ) {\n throw new Error('Codex token refresh response is missing required fields')\n }\n\n const accountId = typeof json.id_token === 'string'\n ? extractAccountId(json.id_token)\n : undefined\n\n return {\n access: json.access_token,\n refresh: typeof json.refresh_token === 'string' ? json.refresh_token : refreshToken,\n expires: Date.now() + json.expires_in * 1000,\n accountId,\n }\n}\n\nexport async function codexBrowserAuth(options?: {\n port?: number\n listenHost?: string\n}): Promise<{\n authorizeUrl: string\n waitForCallback: Promise<OAuthTokens>\n cleanup: () => void\n}> {\n const port = options?.port ?? CODEX_DEFAULT_PORT\n const listenHost = options?.listenHost ?? CODEX_LISTEN_HOST\n const redirectUri = `http://${CODEX_CALLBACK_HOST}:${port}/auth/callback`\n const pkce = generatePKCE()\n const state = generateState()\n\n let server: Server\n let resolveTokens: (tokens: OAuthTokens) => void\n let rejectTokens: (err: Error) => void\n\n const waitForCallback = new Promise<OAuthTokens>((resolve, reject) => {\n resolveTokens = resolve\n rejectTokens = reject\n })\n\n server = createServer(async (req, res) => {\n const url = new URL(req.url ?? '/', redirectUri)\n\n if (url.pathname === '/auth/callback') {\n const code = url.searchParams.get('code')\n const returnedState = url.searchParams.get('state')\n\n if (returnedState !== state) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end('<html><body>State mismatch. Please try again.</body></html>')\n rejectTokens(new Error('OAuth state mismatch'))\n return\n }\n\n if (!code) {\n res.writeHead(400, { 'Content-Type': 'text/html' })\n res.end('<html><body>Missing authorization code.</body></html>')\n rejectTokens(new Error('Missing authorization code'))\n return\n }\n\n try {\n const tokens = await codexExchangeCode(code, redirectUri, {\n verifier: pkce.verifier,\n })\n res.writeHead(200, { 'Content-Type': 'text/html' })\n res.end(\n '<html><body>Authentication successful! You can close this tab.</body></html>',\n )\n resolveTokens(tokens)\n } catch (err) {\n res.writeHead(500, { 'Content-Type': 'text/html' })\n res.end('<html><body>Token exchange failed.</body></html>')\n rejectTokens(\n err instanceof Error ? err : new Error('Token exchange failed'),\n )\n }\n } else {\n res.writeHead(404)\n res.end()\n }\n })\n\n await new Promise<void>((resolve, reject) => {\n server.once('error', reject)\n server.listen(port, listenHost, () => {\n server.off('error', reject)\n resolve()\n })\n })\n\n const params = new URLSearchParams({\n response_type: 'code',\n client_id: CODEX_CLIENT_ID,\n redirect_uri: redirectUri,\n scope: CODEX_SCOPES,\n state,\n code_challenge: pkce.challenge,\n code_challenge_method: 'S256',\n })\n\n const authorizeUrl = `${CODEX_AUTH_BASE}/oauth/authorize?${params.toString()}`\n\n const cleanup = () => {\n server.close()\n }\n\n return { authorizeUrl, waitForCallback, cleanup }\n}\n\nexport function createCodexAuthFetch(\n getTokens: () => Promise<OAuthTokens>,\n onRefreshed: (tokens: OAuthTokens) => Promise<void>,\n): typeof globalThis.fetch {\n const authFetch = createAuthFetch({\n provider: 'openai-codex',\n getTokens,\n refreshTokens: codexRefreshTokens,\n onTokensRefreshed: onRefreshed,\n headerTransform: (headers, tokens) => {\n if (tokens.accountId) {\n headers.set('ChatGPT-Account-Id', tokens.accountId)\n }\n },\n urlTransform: (url) => {\n if (url.includes('/v1/responses') || url.includes('/chat/completions')) {\n return CODEX_API_URL\n }\n return url\n },\n })\n\n return async (input, init) => {\n const inputUrl = extractRequestUrl(input)\n let forceStream = false\n let body = init?.body\n\n if (isCodexRequestUrl(inputUrl) && body && typeof body === 'string') {\n try {\n const parsed = JSON.parse(body)\n if (!parsed.stream) {\n parsed.stream = true\n forceStream = true\n }\n if (parsed.text?.format?.strict) {\n parsed.text.format.strict = false\n }\n body = JSON.stringify(parsed)\n } catch {\n // Leave non-JSON request bodies unchanged.\n }\n }\n\n const response = await authFetch(input, { ...init, body })\n if (forceStream && response.ok && response.body) {\n return bufferCodexSSEResponse(response)\n }\n return response\n }\n}\n\nfunction extractRequestUrl(input: string | URL | Request): string {\n if (typeof input === 'string') return input\n if (input instanceof URL) return input.toString()\n return input.url\n}\n\nfunction isCodexRequestUrl(url: string): boolean {\n return url.includes('/v1/responses')\n || url.includes('/chat/completions')\n || url.includes('chatgpt.com/backend-api/codex')\n}\n\nasync function bufferCodexSSEResponse(response: Response): Promise<Response> {\n const reader = response.body!.getReader()\n const decoder = new TextDecoder()\n let buffer = ''\n let completedResponse: JSONRecord | null = null\n let outputText = ''\n const pendingOutputItems = new Map<number, JSONRecord>()\n const completedOutputItems = new Map<number, JSONRecord>()\n const functionCallArgumentDeltas = new Map<number, string>()\n const customToolInputDeltas = new Map<number, string>()\n\n const overallTimeout = setTimeout(() => {\n try { reader.cancel() } catch { /* ignore */ }\n }, 120_000)\n\n try {\n while (true) {\n const chunkPromise = reader.read()\n const timeoutPromise = new Promise<{ done: true; value: undefined }>((resolve) =>\n setTimeout(() => resolve({ done: true, value: undefined }), 30_000)\n )\n const { done, value } = await Promise.race([chunkPromise, timeoutPromise])\n if (done) break\n buffer += decoder.decode(value, { stream: true })\n\n const lines = buffer.split('\\n')\n buffer = lines.pop() ?? ''\n for (const line of lines) {\n if (!line.startsWith('data: ')) continue\n const data = line.slice(6).trim()\n if (data === '[DONE]') continue\n try {\n const event = JSON.parse(data)\n if (!isJSONRecord(event) || typeof event.type !== 'string') continue\n\n if (event.type === 'response.output_text.delta' && typeof event.delta === 'string') {\n outputText += event.delta\n }\n\n if (event.type === 'response.output_item.added'\n && typeof event.output_index === 'number'\n && isJSONRecord(event.item)\n ) {\n pendingOutputItems.set(event.output_index, { ...event.item })\n }\n\n if (event.type === 'response.function_call_arguments.delta'\n && typeof event.output_index === 'number'\n && typeof event.delta === 'string'\n ) {\n const prev = functionCallArgumentDeltas.get(event.output_index) ?? ''\n functionCallArgumentDeltas.set(event.output_index, prev + event.delta)\n }\n\n if (event.type === 'response.custom_tool_call_input.delta'\n && typeof event.output_index === 'number'\n && typeof event.delta === 'string'\n ) {\n const prev = customToolInputDeltas.get(event.output_index) ?? ''\n customToolInputDeltas.set(event.output_index, prev + event.delta)\n }\n\n if (event.type === 'response.output_item.done'\n && typeof event.output_index === 'number'\n && isJSONRecord(event.item)\n ) {\n completedOutputItems.set(\n event.output_index,\n hydrateOutputItem(event.item, event.output_index, functionCallArgumentDeltas, customToolInputDeltas),\n )\n }\n\n if ((event.type === 'response.completed' || event.type === 'response.incomplete')\n && isJSONRecord(event.response)\n ) {\n completedResponse = event.response\n }\n } catch {\n // Ignore malformed SSE payloads.\n }\n }\n }\n } finally {\n clearTimeout(overallTimeout)\n }\n\n for (const [outputIndex, item] of pendingOutputItems) {\n if (!completedOutputItems.has(outputIndex)) {\n completedOutputItems.set(\n outputIndex,\n hydrateOutputItem(item, outputIndex, functionCallArgumentDeltas, customToolInputDeltas),\n )\n }\n }\n\n const bufferedOutput = [...completedOutputItems.entries()]\n .sort(([left], [right]) => left - right)\n .map(([, item]) => item)\n\n const body = JSON.stringify(\n ensureResponseMetadata(\n completedResponse\n ? mergeBufferedOutputItems(completedResponse, bufferedOutput, outputText)\n : createBufferedResponse(bufferedOutput, outputText),\n ),\n )\n\n return new Response(body, {\n status: 200,\n headers: { 'content-type': 'application/json' },\n })\n}\n\nfunction isJSONRecord(value: unknown): value is JSONRecord {\n return value !== null && typeof value === 'object' && !Array.isArray(value)\n}\n\nfunction hydrateOutputItem(\n item: JSONRecord,\n outputIndex: number,\n functionCallArgumentDeltas: Map<number, string>,\n customToolInputDeltas: Map<number, string>,\n): JSONRecord {\n const hydrated = { ...item }\n\n if (hydrated.type === 'function_call' && typeof hydrated.arguments !== 'string') {\n hydrated.arguments = functionCallArgumentDeltas.get(outputIndex) ?? ''\n }\n\n if (hydrated.type === 'custom_tool_call' && hydrated.input == null) {\n const input = customToolInputDeltas.get(outputIndex)\n if (input !== undefined) {\n hydrated.input = safeParseJSON(input) ?? input\n }\n }\n\n return hydrated\n}\n\nfunction mergeBufferedOutputItems(\n response: JSONRecord,\n bufferedOutput: JSONRecord[],\n outputText: string,\n): JSONRecord {\n const existingOutput = Array.isArray(response.output)\n ? response.output.filter(isJSONRecord)\n : []\n\n if (bufferedOutput.length === 0) {\n if (existingOutput.length > 0) return response\n return { ...response, output: [buildTextOutput(outputText)] }\n }\n\n const mergedOutput = [...existingOutput]\n const seenKeys = new Set(existingOutput.map(getOutputItemKey).filter((key): key is string => key !== null))\n\n for (const item of bufferedOutput) {\n const key = getOutputItemKey(item)\n if (key && seenKeys.has(key)) continue\n if (key) seenKeys.add(key)\n mergedOutput.push(item)\n }\n\n return { ...response, output: mergedOutput }\n}\n\nfunction createBufferedResponse(bufferedOutput: JSONRecord[], outputText: string): JSONRecord {\n return {\n id: 'codex-buffered',\n output: bufferedOutput.length > 0 ? bufferedOutput : [buildTextOutput(outputText)],\n status: 'completed',\n }\n}\n\nfunction ensureResponseMetadata(response: JSONRecord): JSONRecord {\n if (typeof response.created_at === 'number') return response\n\n return {\n ...response,\n created_at: Math.floor(Date.now() / 1000),\n }\n}\n\nfunction buildTextOutput(outputText: string): JSONRecord {\n return {\n type: 'message',\n role: 'assistant',\n content: [{ type: 'output_text', text: outputText, annotations: [] }],\n }\n}\n\nfunction getOutputItemKey(item: JSONRecord): string | null {\n const type = typeof item.type === 'string' ? item.type : 'unknown'\n\n if (typeof item.id === 'string') return `${type}:${item.id}`\n if (typeof item.call_id === 'string') return `${type}:${item.call_id}`\n\n return null\n}\n\nfunction safeParseJSON(text: string): unknown {\n try {\n return JSON.parse(text)\n } catch {\n return undefined\n }\n}\n","import type { LLMAuthProviderPlugin } from '@vostride/agent-qa-core'\nimport { createAnthropicAuthFetch, exchangeAnthropicManualCode, startAnthropicAuth } from './anthropic.js'\nimport { codexBrowserAuth, createCodexAuthFetch } from './openai-codex.js'\n\nexport function createSubscriptionAuthPlugin(): { providers: LLMAuthProviderPlugin[] } {\n return {\n providers: [\n {\n providerId: 'openai-subscription',\n credentialProviderId: 'openai-subscription-oauth',\n label: 'OpenAI subscription',\n modelAdapter: 'openai-responses',\n dashboardAuth: { mode: 'browser-poll', buttonLabel: 'Login with OpenAI subscription' },\n async startAuth() {\n const result = await codexBrowserAuth()\n return {\n authorizeUrl: result.authorizeUrl,\n waitForTokens: result.waitForCallback,\n cleanup: result.cleanup,\n }\n },\n createAuthFetch({ getTokens, onRefreshed }) {\n return createCodexAuthFetch(getTokens, onRefreshed)\n },\n },\n {\n providerId: 'anthropic-subscription',\n credentialProviderId: 'anthropic-subscription',\n label: 'Anthropic subscription',\n modelAdapter: 'anthropic-messages',\n dashboardAuth: { mode: 'manual-code', buttonLabel: 'Login with Anthropic subscription' },\n async startAuth() {\n return startAnthropicAuth()\n },\n async exchangeCode(ctx) {\n return await exchangeAnthropicManualCode(ctx)\n },\n createAuthFetch({ getTokens, onRefreshed }) {\n return createAnthropicAuthFetch(getTokens, onRefreshed)\n },\n },\n ],\n }\n}\n\nexport default createSubscriptionAuthPlugin\n\nexport {\n ANTHROPIC_BETA_FLAGS,\n ANTHROPIC_CLIENT_ID,\n ANTHROPIC_REDIRECT_URI,\n ANTHROPIC_SCOPES,\n ANTHROPIC_TOKEN_URL,\n anthropicAuthorizeUrl,\n anthropicExchangeCode,\n anthropicRefreshTokens,\n createAnthropicAuthFetch,\n} from './anthropic.js'\n\nexport {\n CODEX_API_URL,\n CODEX_AUTH_BASE,\n CODEX_CLIENT_ID,\n CODEX_DEFAULT_PORT,\n CODEX_SCOPES,\n CODEX_TOKEN_URL,\n codexBrowserAuth,\n codexExchangeCode,\n codexRefreshTokens,\n createCodexAuthFetch,\n decodeJwtClaims,\n} from './openai-codex.js'\n"],"mappings":"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","names":["generatePKCE"]}
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "@vostride/agent-qa-subscription-auth",
3
- "version": "0.0.1",
4
- "main": "index.js",
5
- "files": []
3
+ "version": "0.1.9",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Subscription LLM auth providers for agent-qa.",
7
+ "engines": {
8
+ "node": ">=24"
9
+ },
10
+ "main": "./dist/index.js",
11
+ "types": "./dist/index.d.ts",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./dist/index.d.ts",
15
+ "import": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": [
19
+ "dist",
20
+ "LICENSE.md",
21
+ "NOTICE.md"
22
+ ],
23
+ "publishConfig": {
24
+ "access": "public",
25
+ "registry": "https://registry.npmjs.org/"
26
+ },
27
+ "peerDependencies": {
28
+ "@vostride/agent-qa-core": ">=0.1.0"
29
+ },
30
+ "license": "SEE LICENSE IN LICENSE.md",
31
+ "homepage": "https://github.com/vostride/agent-qa-subscription-auth#readme",
32
+ "bugs": {
33
+ "url": "https://github.com/vostride/agent-qa-subscription-auth/issues"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "git+https://github.com/vostride/agent-qa-subscription-auth.git"
38
+ }
6
39
  }