opencode-openai-multi-auth 5.0.0
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 +37 -0
- package/README.md +145 -0
- package/assets/opencode-logo-ornate-dark.svg +18 -0
- package/assets/readme-hero.svg +31 -0
- package/config/README.md +103 -0
- package/config/minimal-opencode.json +12 -0
- package/config/opencode-legacy.json +571 -0
- package/config/opencode-modern.json +239 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +321 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/accounts/index.d.ts +4 -0
- package/dist/lib/accounts/index.d.ts.map +1 -0
- package/dist/lib/accounts/index.js +3 -0
- package/dist/lib/accounts/index.js.map +1 -0
- package/dist/lib/accounts/manager.d.ts +23 -0
- package/dist/lib/accounts/manager.d.ts.map +1 -0
- package/dist/lib/accounts/manager.js +270 -0
- package/dist/lib/accounts/manager.js.map +1 -0
- package/dist/lib/accounts/types.d.ts +35 -0
- package/dist/lib/accounts/types.d.ts.map +1 -0
- package/dist/lib/accounts/types.js +10 -0
- package/dist/lib/accounts/types.js.map +1 -0
- package/dist/lib/auth/auth.d.ts +43 -0
- package/dist/lib/auth/auth.d.ts.map +1 -0
- package/dist/lib/auth/auth.js +163 -0
- package/dist/lib/auth/auth.js.map +1 -0
- package/dist/lib/auth/browser.d.ts +17 -0
- package/dist/lib/auth/browser.d.ts.map +1 -0
- package/dist/lib/auth/browser.js +76 -0
- package/dist/lib/auth/browser.js.map +1 -0
- package/dist/lib/auth/server.d.ts +10 -0
- package/dist/lib/auth/server.d.ts.map +1 -0
- package/dist/lib/auth/server.js +78 -0
- package/dist/lib/auth/server.js.map +1 -0
- package/dist/lib/config.d.ts +17 -0
- package/dist/lib/config.d.ts.map +1 -0
- package/dist/lib/config.js +51 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/constants.d.ts +67 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +67 -0
- package/dist/lib/constants.js.map +1 -0
- package/dist/lib/logger.d.ts +21 -0
- package/dist/lib/logger.d.ts.map +1 -0
- package/dist/lib/logger.js +77 -0
- package/dist/lib/logger.js.map +1 -0
- package/dist/lib/oauth-success.html +712 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts +19 -0
- package/dist/lib/prompts/codex-opencode-bridge.d.ts.map +1 -0
- package/dist/lib/prompts/codex-opencode-bridge.js +152 -0
- package/dist/lib/prompts/codex-opencode-bridge.js.map +1 -0
- package/dist/lib/prompts/codex.d.ts +27 -0
- package/dist/lib/prompts/codex.d.ts.map +1 -0
- package/dist/lib/prompts/codex.js +241 -0
- package/dist/lib/prompts/codex.js.map +1 -0
- package/dist/lib/prompts/opencode-codex.d.ts +21 -0
- package/dist/lib/prompts/opencode-codex.d.ts.map +1 -0
- package/dist/lib/prompts/opencode-codex.js +91 -0
- package/dist/lib/prompts/opencode-codex.js.map +1 -0
- package/dist/lib/request/fetch-helpers.d.ts +73 -0
- package/dist/lib/request/fetch-helpers.d.ts.map +1 -0
- package/dist/lib/request/fetch-helpers.js +221 -0
- package/dist/lib/request/fetch-helpers.js.map +1 -0
- package/dist/lib/request/helpers/input-utils.d.ts +6 -0
- package/dist/lib/request/helpers/input-utils.d.ts.map +1 -0
- package/dist/lib/request/helpers/input-utils.js +174 -0
- package/dist/lib/request/helpers/input-utils.js.map +1 -0
- package/dist/lib/request/helpers/model-map.d.ts +28 -0
- package/dist/lib/request/helpers/model-map.d.ts.map +1 -0
- package/dist/lib/request/helpers/model-map.js +109 -0
- package/dist/lib/request/helpers/model-map.js.map +1 -0
- package/dist/lib/request/request-transformer.d.ts +93 -0
- package/dist/lib/request/request-transformer.d.ts.map +1 -0
- package/dist/lib/request/request-transformer.js +403 -0
- package/dist/lib/request/request-transformer.js.map +1 -0
- package/dist/lib/request/response-handler.d.ts +14 -0
- package/dist/lib/request/response-handler.d.ts.map +1 -0
- package/dist/lib/request/response-handler.js +88 -0
- package/dist/lib/request/response-handler.js.map +1 -0
- package/dist/lib/types.d.ts +167 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/types.js +2 -0
- package/dist/lib/types.js.map +1 -0
- package/package.json +73 -0
- package/scripts/install-opencode-codex-auth.js +430 -0
- package/scripts/test-all-models.sh +259 -0
- package/scripts/validate-model-map.sh +97 -0
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { decodeJWT, refreshAccessToken } from "../auth/auth.js";
|
|
5
|
+
import { DEFAULT_MULTI_ACCOUNT_CONFIG } from "./types.js";
|
|
6
|
+
const JWT_CLAIM_PATH = "https://api.openai.com/auth";
|
|
7
|
+
const ACCOUNTS_FILE = join(homedir(), ".config", "opencode", "openai-accounts.json");
|
|
8
|
+
const OPENCODE_AUTH_FILE = join(homedir(), ".local", "share", "opencode", "auth.json");
|
|
9
|
+
export class AccountManager {
|
|
10
|
+
accounts = [];
|
|
11
|
+
activeIndex = 0;
|
|
12
|
+
config;
|
|
13
|
+
constructor(config = {}) {
|
|
14
|
+
this.config = { ...DEFAULT_MULTI_ACCOUNT_CONFIG, ...config };
|
|
15
|
+
}
|
|
16
|
+
async loadFromDisk() {
|
|
17
|
+
if (!existsSync(ACCOUNTS_FILE))
|
|
18
|
+
return;
|
|
19
|
+
try {
|
|
20
|
+
const data = JSON.parse(readFileSync(ACCOUNTS_FILE, "utf-8"));
|
|
21
|
+
if (data.version === 1 && Array.isArray(data.accounts)) {
|
|
22
|
+
this.accounts = data.accounts;
|
|
23
|
+
this.activeIndex = data.activeAccountIndex || 0;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
this.accounts = [];
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
async saveToDisk() {
|
|
31
|
+
const dir = dirname(ACCOUNTS_FILE);
|
|
32
|
+
if (!existsSync(dir)) {
|
|
33
|
+
mkdirSync(dir, { recursive: true });
|
|
34
|
+
}
|
|
35
|
+
const data = {
|
|
36
|
+
version: 1,
|
|
37
|
+
accounts: this.accounts,
|
|
38
|
+
activeAccountIndex: this.activeIndex,
|
|
39
|
+
};
|
|
40
|
+
writeFileSync(ACCOUNTS_FILE, JSON.stringify(data, null, 2), "utf-8");
|
|
41
|
+
}
|
|
42
|
+
async importFromOpenCodeAuth() {
|
|
43
|
+
if (!existsSync(OPENCODE_AUTH_FILE))
|
|
44
|
+
return;
|
|
45
|
+
try {
|
|
46
|
+
const authData = JSON.parse(readFileSync(OPENCODE_AUTH_FILE, "utf-8"));
|
|
47
|
+
const openaiAuth = authData?.openai;
|
|
48
|
+
if (openaiAuth?.type === "oauth" && openaiAuth?.refresh) {
|
|
49
|
+
const existingAccount = this.accounts.find((a) => a.parts.refreshToken === openaiAuth.refresh);
|
|
50
|
+
if (!existingAccount) {
|
|
51
|
+
await this.addAccount(undefined, openaiAuth.refresh, openaiAuth.access, openaiAuth.expires);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
catch { }
|
|
56
|
+
}
|
|
57
|
+
async addAccount(email, refreshToken, accessToken, expires) {
|
|
58
|
+
let accountId;
|
|
59
|
+
let userId;
|
|
60
|
+
let extractedEmail = email;
|
|
61
|
+
let planType;
|
|
62
|
+
if (accessToken) {
|
|
63
|
+
const decoded = decodeJWT(accessToken);
|
|
64
|
+
if (decoded) {
|
|
65
|
+
const authClaims = decoded[JWT_CLAIM_PATH];
|
|
66
|
+
accountId = authClaims?.chatgpt_account_id;
|
|
67
|
+
userId = authClaims?.chatgpt_user_id;
|
|
68
|
+
planType = authClaims?.chatgpt_plan_type;
|
|
69
|
+
const profile = decoded["https://api.openai.com/profile"];
|
|
70
|
+
if (!extractedEmail && profile?.email) {
|
|
71
|
+
extractedEmail = profile.email;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Deduplicate by userId + accountId (unique per user per workspace) or fallback to refreshToken
|
|
76
|
+
const existingIndex = this.accounts.findIndex((a) => {
|
|
77
|
+
if (userId && a.userId) {
|
|
78
|
+
return a.userId === userId && a.accountId === accountId;
|
|
79
|
+
}
|
|
80
|
+
return a.parts.refreshToken === refreshToken;
|
|
81
|
+
});
|
|
82
|
+
if (existingIndex >= 0) {
|
|
83
|
+
const existing = this.accounts[existingIndex];
|
|
84
|
+
if (accessToken)
|
|
85
|
+
existing.access = accessToken;
|
|
86
|
+
if (refreshToken)
|
|
87
|
+
existing.parts.refreshToken = refreshToken;
|
|
88
|
+
if (expires)
|
|
89
|
+
existing.expires = expires;
|
|
90
|
+
if (userId)
|
|
91
|
+
existing.userId = userId;
|
|
92
|
+
if (accountId)
|
|
93
|
+
existing.accountId = accountId;
|
|
94
|
+
if (planType)
|
|
95
|
+
existing.planType = planType;
|
|
96
|
+
if (extractedEmail)
|
|
97
|
+
existing.email = extractedEmail;
|
|
98
|
+
existing.consecutiveFailures = 0;
|
|
99
|
+
await this.saveToDisk();
|
|
100
|
+
if (!this.config.quietMode) {
|
|
101
|
+
console.log(`[openai-multi-auth] Updated account ${extractedEmail || existing.index}`);
|
|
102
|
+
}
|
|
103
|
+
return existing;
|
|
104
|
+
}
|
|
105
|
+
const account = {
|
|
106
|
+
index: this.accounts.length,
|
|
107
|
+
email: extractedEmail,
|
|
108
|
+
userId,
|
|
109
|
+
planType,
|
|
110
|
+
accountId,
|
|
111
|
+
addedAt: Date.now(),
|
|
112
|
+
parts: { refreshToken },
|
|
113
|
+
access: accessToken,
|
|
114
|
+
expires,
|
|
115
|
+
rateLimitResets: {},
|
|
116
|
+
consecutiveFailures: 0,
|
|
117
|
+
};
|
|
118
|
+
this.accounts.push(account);
|
|
119
|
+
await this.saveToDisk();
|
|
120
|
+
if (!this.config.quietMode) {
|
|
121
|
+
console.log(`[openai-multi-auth] Added account ${extractedEmail || account.index}`);
|
|
122
|
+
}
|
|
123
|
+
return account;
|
|
124
|
+
}
|
|
125
|
+
getAllAccounts() {
|
|
126
|
+
return this.accounts;
|
|
127
|
+
}
|
|
128
|
+
getAccountCount() {
|
|
129
|
+
return this.accounts.length;
|
|
130
|
+
}
|
|
131
|
+
async getNextAvailableAccount(model) {
|
|
132
|
+
if (this.accounts.length === 0)
|
|
133
|
+
return null;
|
|
134
|
+
const now = Date.now();
|
|
135
|
+
const startIndex = this.activeIndex;
|
|
136
|
+
let attempts = 0;
|
|
137
|
+
while (attempts < this.accounts.length) {
|
|
138
|
+
const index = (startIndex + attempts) % this.accounts.length;
|
|
139
|
+
const account = this.accounts[index];
|
|
140
|
+
if (this.isAccountAvailable(account, model, now)) {
|
|
141
|
+
this.activeIndex = index;
|
|
142
|
+
account.lastUsed = now;
|
|
143
|
+
return account;
|
|
144
|
+
}
|
|
145
|
+
attempts++;
|
|
146
|
+
}
|
|
147
|
+
return this.getLeastRateLimitedAccount(model);
|
|
148
|
+
}
|
|
149
|
+
isAccountAvailable(account, model, now) {
|
|
150
|
+
if (account.consecutiveFailures >= 3)
|
|
151
|
+
return false;
|
|
152
|
+
if (account.globalRateLimitReset && account.globalRateLimitReset > now) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
if (model && this.config.perModelRateLimits) {
|
|
156
|
+
const modelReset = account.rateLimitResets[model];
|
|
157
|
+
if (modelReset && modelReset > now) {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
return true;
|
|
162
|
+
}
|
|
163
|
+
getLeastRateLimitedAccount(model) {
|
|
164
|
+
if (this.accounts.length === 0)
|
|
165
|
+
return null;
|
|
166
|
+
const now = Date.now();
|
|
167
|
+
let bestAccount = null;
|
|
168
|
+
let earliestReset = Infinity;
|
|
169
|
+
for (const account of this.accounts) {
|
|
170
|
+
if (account.consecutiveFailures >= 3)
|
|
171
|
+
continue;
|
|
172
|
+
let resetTime = account.globalRateLimitReset || 0;
|
|
173
|
+
if (model && this.config.perModelRateLimits) {
|
|
174
|
+
const modelReset = account.rateLimitResets[model] || 0;
|
|
175
|
+
resetTime = Math.max(resetTime, modelReset);
|
|
176
|
+
}
|
|
177
|
+
if (resetTime < earliestReset) {
|
|
178
|
+
earliestReset = resetTime;
|
|
179
|
+
bestAccount = account;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return bestAccount;
|
|
183
|
+
}
|
|
184
|
+
markRateLimited(account, retryAfterMs, model) {
|
|
185
|
+
const resetTime = Date.now() + retryAfterMs;
|
|
186
|
+
if (model && this.config.perModelRateLimits) {
|
|
187
|
+
account.rateLimitResets[model] = resetTime;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
account.globalRateLimitReset = resetTime;
|
|
191
|
+
}
|
|
192
|
+
if (this.config.debug) {
|
|
193
|
+
const identifier = account.email || `account-${account.index}`;
|
|
194
|
+
console.log(`[openai-multi-auth] ${identifier} rate limited until ${new Date(resetTime).toISOString()}`);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
markRefreshFailed(account, error) {
|
|
198
|
+
account.consecutiveFailures++;
|
|
199
|
+
account.lastRefreshError = error;
|
|
200
|
+
account.isRefreshing = false;
|
|
201
|
+
if (this.config.removeOnInvalidGrant && error.includes("invalid_grant")) {
|
|
202
|
+
this.removeAccount(account);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
removeAccount(account) {
|
|
206
|
+
const index = this.accounts.findIndex((a) => a.index === account.index);
|
|
207
|
+
if (index >= 0) {
|
|
208
|
+
this.accounts.splice(index, 1);
|
|
209
|
+
this.accounts.forEach((a, i) => (a.index = i));
|
|
210
|
+
if (this.activeIndex >= this.accounts.length) {
|
|
211
|
+
this.activeIndex = Math.max(0, this.accounts.length - 1);
|
|
212
|
+
}
|
|
213
|
+
this.saveToDisk();
|
|
214
|
+
if (!this.config.quietMode) {
|
|
215
|
+
console.log(`[openai-multi-auth] Removed account ${account.email || account.index}`);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
async updateAccountTokens(account, accessToken, refreshToken, expires) {
|
|
220
|
+
account.access = accessToken;
|
|
221
|
+
account.parts.refreshToken = refreshToken;
|
|
222
|
+
account.expires = expires;
|
|
223
|
+
account.consecutiveFailures = 0;
|
|
224
|
+
account.isRefreshing = false;
|
|
225
|
+
account.lastRefreshError = undefined;
|
|
226
|
+
const decoded = decodeJWT(accessToken);
|
|
227
|
+
if (decoded) {
|
|
228
|
+
const authClaims = decoded[JWT_CLAIM_PATH];
|
|
229
|
+
if (authClaims?.chatgpt_account_id) {
|
|
230
|
+
account.accountId = authClaims.chatgpt_account_id;
|
|
231
|
+
}
|
|
232
|
+
if (authClaims?.chatgpt_user_id) {
|
|
233
|
+
account.userId = authClaims.chatgpt_user_id;
|
|
234
|
+
}
|
|
235
|
+
if (authClaims?.chatgpt_plan_type) {
|
|
236
|
+
account.planType = authClaims.chatgpt_plan_type;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
await this.saveToDisk();
|
|
240
|
+
}
|
|
241
|
+
async ensureValidToken(account) {
|
|
242
|
+
if (!account.expires ||
|
|
243
|
+
account.expires > Date.now() + this.config.proactiveRefreshThresholdMs) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
if (account.isRefreshing) {
|
|
247
|
+
return !!account.access;
|
|
248
|
+
}
|
|
249
|
+
account.isRefreshing = true;
|
|
250
|
+
try {
|
|
251
|
+
const result = await refreshAccessToken(account.parts.refreshToken);
|
|
252
|
+
if (result.type === "success") {
|
|
253
|
+
await this.updateAccountTokens(account, result.access, result.refresh, result.expires);
|
|
254
|
+
return true;
|
|
255
|
+
}
|
|
256
|
+
this.markRefreshFailed(account, "Token refresh failed");
|
|
257
|
+
return false;
|
|
258
|
+
}
|
|
259
|
+
catch (err) {
|
|
260
|
+
this.markRefreshFailed(account, String(err));
|
|
261
|
+
return false;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
getActiveAccount() {
|
|
265
|
+
if (this.accounts.length === 0)
|
|
266
|
+
return null;
|
|
267
|
+
return this.accounts[this.activeIndex] || this.accounts[0];
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../lib/accounts/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface ManagedAccount {
|
|
2
|
+
index: number;
|
|
3
|
+
email?: string;
|
|
4
|
+
userId?: string;
|
|
5
|
+
accountId?: string;
|
|
6
|
+
planType?: string;
|
|
7
|
+
addedAt: number;
|
|
8
|
+
lastUsed?: number;
|
|
9
|
+
parts: {
|
|
10
|
+
refreshToken: string;
|
|
11
|
+
};
|
|
12
|
+
access?: string;
|
|
13
|
+
expires?: number;
|
|
14
|
+
rateLimitResets: Record<string, number>;
|
|
15
|
+
globalRateLimitReset?: number;
|
|
16
|
+
consecutiveFailures: number;
|
|
17
|
+
isRefreshing?: boolean;
|
|
18
|
+
lastRefreshError?: string;
|
|
19
|
+
}
|
|
20
|
+
export interface AccountsStorage {
|
|
21
|
+
version: 1;
|
|
22
|
+
accounts: ManagedAccount[];
|
|
23
|
+
activeAccountIndex: number;
|
|
24
|
+
}
|
|
25
|
+
export interface MultiAccountConfig {
|
|
26
|
+
accountSelectionStrategy: "sticky" | "round-robin" | "hybrid";
|
|
27
|
+
debug: boolean;
|
|
28
|
+
quietMode: boolean;
|
|
29
|
+
pidOffsetEnabled: boolean;
|
|
30
|
+
proactiveRefreshThresholdMs: number;
|
|
31
|
+
removeOnInvalidGrant: boolean;
|
|
32
|
+
perModelRateLimits: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare const DEFAULT_MULTI_ACCOUNT_CONFIG: MultiAccountConfig;
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../lib/accounts/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE;QACL,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACxC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,CAAC,CAAC;IACX,QAAQ,EAAE,cAAc,EAAE,CAAC;IAC3B,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,wBAAwB,EAAE,QAAQ,GAAG,aAAa,GAAG,QAAQ,CAAC;IAC9D,KAAK,EAAE,OAAO,CAAC;IACf,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,2BAA2B,EAAE,MAAM,CAAC;IACpC,oBAAoB,EAAE,OAAO,CAAC;IAC9B,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AAED,eAAO,MAAM,4BAA4B,EAAE,kBAQ1C,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const DEFAULT_MULTI_ACCOUNT_CONFIG = {
|
|
2
|
+
accountSelectionStrategy: "sticky",
|
|
3
|
+
debug: false,
|
|
4
|
+
quietMode: false,
|
|
5
|
+
pidOffsetEnabled: false,
|
|
6
|
+
proactiveRefreshThresholdMs: 5 * 60 * 1000,
|
|
7
|
+
removeOnInvalidGrant: true,
|
|
8
|
+
perModelRateLimits: true,
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../lib/accounts/types.ts"],"names":[],"mappings":"AAoCA,MAAM,CAAC,MAAM,4BAA4B,GAAuB;IAC9D,wBAAwB,EAAE,QAAQ;IAClC,KAAK,EAAE,KAAK;IACZ,SAAS,EAAE,KAAK;IAChB,gBAAgB,EAAE,KAAK;IACvB,2BAA2B,EAAE,CAAC,GAAG,EAAE,GAAG,IAAI;IAC1C,oBAAoB,EAAE,IAAI;IAC1B,kBAAkB,EAAE,IAAI;CACzB,CAAC"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { AuthorizationFlow, TokenResult, ParsedAuthInput, JWTPayload } from "../types.js";
|
|
2
|
+
export declare const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
3
|
+
export declare const AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
4
|
+
export declare const TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
5
|
+
export declare const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
6
|
+
export declare const SCOPE = "openid profile email offline_access";
|
|
7
|
+
/**
|
|
8
|
+
* Generate a random state value for OAuth flow
|
|
9
|
+
* @returns Random hex string
|
|
10
|
+
*/
|
|
11
|
+
export declare function createState(): string;
|
|
12
|
+
/**
|
|
13
|
+
* Parse authorization code and state from user input
|
|
14
|
+
* @param input - User input (URL, code#state, or just code)
|
|
15
|
+
* @returns Parsed authorization data
|
|
16
|
+
*/
|
|
17
|
+
export declare function parseAuthorizationInput(input: string): ParsedAuthInput;
|
|
18
|
+
/**
|
|
19
|
+
* Exchange authorization code for access and refresh tokens
|
|
20
|
+
* @param code - Authorization code from OAuth flow
|
|
21
|
+
* @param verifier - PKCE verifier
|
|
22
|
+
* @param redirectUri - OAuth redirect URI
|
|
23
|
+
* @returns Token result
|
|
24
|
+
*/
|
|
25
|
+
export declare function exchangeAuthorizationCode(code: string, verifier: string, redirectUri?: string): Promise<TokenResult>;
|
|
26
|
+
/**
|
|
27
|
+
* Decode a JWT token to extract payload
|
|
28
|
+
* @param token - JWT token to decode
|
|
29
|
+
* @returns Decoded payload or null if invalid
|
|
30
|
+
*/
|
|
31
|
+
export declare function decodeJWT(token: string): JWTPayload | null;
|
|
32
|
+
/**
|
|
33
|
+
* Refresh access token using refresh token
|
|
34
|
+
* @param refreshToken - Refresh token
|
|
35
|
+
* @returns Token result
|
|
36
|
+
*/
|
|
37
|
+
export declare function refreshAccessToken(refreshToken: string): Promise<TokenResult>;
|
|
38
|
+
/**
|
|
39
|
+
* Create OAuth authorization flow
|
|
40
|
+
* @returns Authorization flow details
|
|
41
|
+
*/
|
|
42
|
+
export declare function createAuthorizationFlow(): Promise<AuthorizationFlow>;
|
|
43
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAY,iBAAiB,EAAE,WAAW,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzG,eAAO,MAAM,SAAS,iCAAiC,CAAC;AACxD,eAAO,MAAM,aAAa,4CAA4C,CAAC;AACvE,eAAO,MAAM,SAAS,wCAAwC,CAAC;AAC/D,eAAO,MAAM,YAAY,wCAAwC,CAAC;AAClE,eAAO,MAAM,KAAK,wCAAwC,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,eAAe,CAwBtE;AAED;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAC9C,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,WAAW,GAAE,MAAqB,GAChC,OAAO,CAAC,WAAW,CAAC,CAoCtB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAU1D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAkDnF;AAED;;;GAGG;AACH,wBAAsB,uBAAuB,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAiB1E"}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
import { generatePKCE } from "@openauthjs/openauth/pkce";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
// OAuth constants (from openai/codex)
|
|
4
|
+
export const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
|
|
5
|
+
export const AUTHORIZE_URL = "https://auth.openai.com/oauth/authorize";
|
|
6
|
+
export const TOKEN_URL = "https://auth.openai.com/oauth/token";
|
|
7
|
+
export const REDIRECT_URI = "http://localhost:1455/auth/callback";
|
|
8
|
+
export const SCOPE = "openid profile email offline_access";
|
|
9
|
+
/**
|
|
10
|
+
* Generate a random state value for OAuth flow
|
|
11
|
+
* @returns Random hex string
|
|
12
|
+
*/
|
|
13
|
+
export function createState() {
|
|
14
|
+
return randomBytes(16).toString("hex");
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Parse authorization code and state from user input
|
|
18
|
+
* @param input - User input (URL, code#state, or just code)
|
|
19
|
+
* @returns Parsed authorization data
|
|
20
|
+
*/
|
|
21
|
+
export function parseAuthorizationInput(input) {
|
|
22
|
+
const value = (input || "").trim();
|
|
23
|
+
if (!value)
|
|
24
|
+
return {};
|
|
25
|
+
try {
|
|
26
|
+
const url = new URL(value);
|
|
27
|
+
return {
|
|
28
|
+
code: url.searchParams.get("code") ?? undefined,
|
|
29
|
+
state: url.searchParams.get("state") ?? undefined,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
catch { }
|
|
33
|
+
if (value.includes("#")) {
|
|
34
|
+
const [code, state] = value.split("#", 2);
|
|
35
|
+
return { code, state };
|
|
36
|
+
}
|
|
37
|
+
if (value.includes("code=")) {
|
|
38
|
+
const params = new URLSearchParams(value);
|
|
39
|
+
return {
|
|
40
|
+
code: params.get("code") ?? undefined,
|
|
41
|
+
state: params.get("state") ?? undefined,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return { code: value };
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Exchange authorization code for access and refresh tokens
|
|
48
|
+
* @param code - Authorization code from OAuth flow
|
|
49
|
+
* @param verifier - PKCE verifier
|
|
50
|
+
* @param redirectUri - OAuth redirect URI
|
|
51
|
+
* @returns Token result
|
|
52
|
+
*/
|
|
53
|
+
export async function exchangeAuthorizationCode(code, verifier, redirectUri = REDIRECT_URI) {
|
|
54
|
+
const res = await fetch(TOKEN_URL, {
|
|
55
|
+
method: "POST",
|
|
56
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
57
|
+
body: new URLSearchParams({
|
|
58
|
+
grant_type: "authorization_code",
|
|
59
|
+
client_id: CLIENT_ID,
|
|
60
|
+
code,
|
|
61
|
+
code_verifier: verifier,
|
|
62
|
+
redirect_uri: redirectUri,
|
|
63
|
+
}),
|
|
64
|
+
});
|
|
65
|
+
if (!res.ok) {
|
|
66
|
+
const text = await res.text().catch(() => "");
|
|
67
|
+
console.error("[openai-codex-plugin] code->token failed:", res.status, text);
|
|
68
|
+
return { type: "failed" };
|
|
69
|
+
}
|
|
70
|
+
const json = (await res.json());
|
|
71
|
+
if (!json?.access_token ||
|
|
72
|
+
!json?.refresh_token ||
|
|
73
|
+
typeof json?.expires_in !== "number") {
|
|
74
|
+
console.error("[openai-codex-plugin] token response missing fields:", json);
|
|
75
|
+
return { type: "failed" };
|
|
76
|
+
}
|
|
77
|
+
return {
|
|
78
|
+
type: "success",
|
|
79
|
+
access: json.access_token,
|
|
80
|
+
refresh: json.refresh_token,
|
|
81
|
+
expires: Date.now() + json.expires_in * 1000,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Decode a JWT token to extract payload
|
|
86
|
+
* @param token - JWT token to decode
|
|
87
|
+
* @returns Decoded payload or null if invalid
|
|
88
|
+
*/
|
|
89
|
+
export function decodeJWT(token) {
|
|
90
|
+
try {
|
|
91
|
+
const parts = token.split(".");
|
|
92
|
+
if (parts.length !== 3)
|
|
93
|
+
return null;
|
|
94
|
+
const payload = parts[1];
|
|
95
|
+
const decoded = Buffer.from(payload, "base64").toString("utf-8");
|
|
96
|
+
return JSON.parse(decoded);
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Refresh access token using refresh token
|
|
104
|
+
* @param refreshToken - Refresh token
|
|
105
|
+
* @returns Token result
|
|
106
|
+
*/
|
|
107
|
+
export async function refreshAccessToken(refreshToken) {
|
|
108
|
+
try {
|
|
109
|
+
const response = await fetch(TOKEN_URL, {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
112
|
+
body: new URLSearchParams({
|
|
113
|
+
grant_type: "refresh_token",
|
|
114
|
+
refresh_token: refreshToken,
|
|
115
|
+
client_id: CLIENT_ID,
|
|
116
|
+
}),
|
|
117
|
+
});
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
const text = await response.text().catch(() => "");
|
|
120
|
+
console.error("[openai-codex-plugin] Token refresh failed:", response.status, text);
|
|
121
|
+
return { type: "failed" };
|
|
122
|
+
}
|
|
123
|
+
const json = (await response.json());
|
|
124
|
+
if (!json?.access_token ||
|
|
125
|
+
!json?.refresh_token ||
|
|
126
|
+
typeof json?.expires_in !== "number") {
|
|
127
|
+
console.error("[openai-codex-plugin] Token refresh response missing fields:", json);
|
|
128
|
+
return { type: "failed" };
|
|
129
|
+
}
|
|
130
|
+
return {
|
|
131
|
+
type: "success",
|
|
132
|
+
access: json.access_token,
|
|
133
|
+
refresh: json.refresh_token,
|
|
134
|
+
expires: Date.now() + json.expires_in * 1000,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
catch (error) {
|
|
138
|
+
const err = error;
|
|
139
|
+
console.error("[openai-codex-plugin] Token refresh error:", err);
|
|
140
|
+
return { type: "failed" };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Create OAuth authorization flow
|
|
145
|
+
* @returns Authorization flow details
|
|
146
|
+
*/
|
|
147
|
+
export async function createAuthorizationFlow() {
|
|
148
|
+
const pkce = (await generatePKCE());
|
|
149
|
+
const state = createState();
|
|
150
|
+
const url = new URL(AUTHORIZE_URL);
|
|
151
|
+
url.searchParams.set("response_type", "code");
|
|
152
|
+
url.searchParams.set("client_id", CLIENT_ID);
|
|
153
|
+
url.searchParams.set("redirect_uri", REDIRECT_URI);
|
|
154
|
+
url.searchParams.set("scope", SCOPE);
|
|
155
|
+
url.searchParams.set("code_challenge", pkce.challenge);
|
|
156
|
+
url.searchParams.set("code_challenge_method", "S256");
|
|
157
|
+
url.searchParams.set("state", state);
|
|
158
|
+
url.searchParams.set("id_token_add_organizations", "true");
|
|
159
|
+
url.searchParams.set("codex_cli_simplified_flow", "true");
|
|
160
|
+
url.searchParams.set("originator", "codex_cli_rs");
|
|
161
|
+
return { pkce, state, url: url.toString() };
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../lib/auth/auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser utilities for OAuth flow
|
|
3
|
+
* Handles platform-specific browser opening
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Gets the platform-specific command to open a URL in the default browser
|
|
7
|
+
* @returns Browser opener command for the current platform
|
|
8
|
+
*/
|
|
9
|
+
export declare function getBrowserOpener(): string;
|
|
10
|
+
/**
|
|
11
|
+
* Opens a URL in the default browser
|
|
12
|
+
* Silently fails if browser cannot be opened (user can copy URL manually)
|
|
13
|
+
* @param url - URL to open
|
|
14
|
+
* @returns True if a browser launch was attempted
|
|
15
|
+
*/
|
|
16
|
+
export declare function openBrowserUrl(url: string): boolean;
|
|
17
|
+
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../lib/auth/browser.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAKzC;AAkCD;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBnD"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser utilities for OAuth flow
|
|
3
|
+
* Handles platform-specific browser opening
|
|
4
|
+
*/
|
|
5
|
+
import { spawn } from "node:child_process";
|
|
6
|
+
import fs from "node:fs";
|
|
7
|
+
import path from "node:path";
|
|
8
|
+
import { PLATFORM_OPENERS } from "../constants.js";
|
|
9
|
+
/**
|
|
10
|
+
* Gets the platform-specific command to open a URL in the default browser
|
|
11
|
+
* @returns Browser opener command for the current platform
|
|
12
|
+
*/
|
|
13
|
+
export function getBrowserOpener() {
|
|
14
|
+
const platform = process.platform;
|
|
15
|
+
if (platform === "darwin")
|
|
16
|
+
return PLATFORM_OPENERS.darwin;
|
|
17
|
+
if (platform === "win32")
|
|
18
|
+
return PLATFORM_OPENERS.win32;
|
|
19
|
+
return PLATFORM_OPENERS.linux;
|
|
20
|
+
}
|
|
21
|
+
function commandExists(command) {
|
|
22
|
+
if (!command)
|
|
23
|
+
return false;
|
|
24
|
+
// "start" is a shell builtin on Windows; rely on shell execution
|
|
25
|
+
if (process.platform === "win32" && command.toLowerCase() === "start") {
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
const pathValue = process.env.PATH || "";
|
|
29
|
+
const entries = pathValue.split(path.delimiter).filter(Boolean);
|
|
30
|
+
if (entries.length === 0)
|
|
31
|
+
return false;
|
|
32
|
+
if (process.platform === "win32") {
|
|
33
|
+
const pathext = (process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM")
|
|
34
|
+
.split(";")
|
|
35
|
+
.filter(Boolean);
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
for (const ext of pathext) {
|
|
38
|
+
const candidate = path.join(entry, `${command}${ext}`);
|
|
39
|
+
if (fs.existsSync(candidate))
|
|
40
|
+
return true;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
for (const entry of entries) {
|
|
46
|
+
const candidate = path.join(entry, command);
|
|
47
|
+
if (fs.existsSync(candidate))
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Opens a URL in the default browser
|
|
54
|
+
* Silently fails if browser cannot be opened (user can copy URL manually)
|
|
55
|
+
* @param url - URL to open
|
|
56
|
+
* @returns True if a browser launch was attempted
|
|
57
|
+
*/
|
|
58
|
+
export function openBrowserUrl(url) {
|
|
59
|
+
try {
|
|
60
|
+
const opener = getBrowserOpener();
|
|
61
|
+
if (!commandExists(opener)) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
const child = spawn(opener, [url], {
|
|
65
|
+
stdio: "ignore",
|
|
66
|
+
shell: process.platform === "win32",
|
|
67
|
+
});
|
|
68
|
+
child.on("error", () => { });
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
catch (error) {
|
|
72
|
+
// Silently fail - user can manually open the URL from instructions
|
|
73
|
+
return false;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=browser.js.map
|