@cortexkit/opencode-openai-auth 0.1.1 → 0.1.3

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.
Files changed (64) hide show
  1. package/README.md +27 -0
  2. package/dist/cli.d.ts +2 -0
  3. package/dist/cli.js +14 -0
  4. package/dist/commands.d.ts +49 -0
  5. package/dist/core/accounts.d.ts +227 -0
  6. package/dist/core/atomic-write.d.ts +1 -0
  7. package/dist/core/backoff.d.ts +53 -0
  8. package/dist/core/cachekeep.d.ts +95 -0
  9. package/dist/core/oauth.d.ts +126 -0
  10. package/dist/core/provider.d.ts +59 -0
  11. package/dist/core/quota-manager.d.ts +136 -0
  12. package/dist/core/refresh-all-quota.d.ts +52 -0
  13. package/dist/core/refresh-file-lock.d.ts +15 -0
  14. package/dist/index-0s5tftne.js +3 -0
  15. package/dist/index-6qjg8qfw.js +2 -0
  16. package/dist/index-dz7tcrxb.js +2 -0
  17. package/dist/index-eks9xm6s.js +1 -0
  18. package/dist/index-hrg6bdgb.js +2 -0
  19. package/dist/index-jshhys8t.js +2 -0
  20. package/dist/index-mrh6k1zf.js +92 -0
  21. package/dist/index-sgfft5d3.js +2 -0
  22. package/dist/index.d.ts +3 -19
  23. package/dist/index.js +118 -124
  24. package/dist/logger.d.ts +11 -1
  25. package/dist/quota-normalize-qh5n0p7v.js +1 -0
  26. package/dist/quota-normalize.d.ts +33 -0
  27. package/dist/response-stream-error.d.ts +12 -1
  28. package/dist/rpc/notifications.d.ts +5 -0
  29. package/dist/rpc/port-file.d.ts +12 -0
  30. package/dist/rpc/port-file.js +1 -0
  31. package/dist/rpc/protocol.d.ts +20 -0
  32. package/dist/rpc/protocol.js +0 -0
  33. package/dist/rpc/rpc-client.d.ts +7 -0
  34. package/dist/rpc/rpc-client.js +1 -0
  35. package/dist/rpc/rpc-dir.d.ts +3 -0
  36. package/dist/rpc/rpc-dir.js +1 -0
  37. package/dist/rpc/rpc-server.d.ts +13 -0
  38. package/dist/sidebar-state.d.ts +83 -0
  39. package/dist/sidebar-state.js +1 -0
  40. package/dist/token-util-sqwtzxz0.js +1 -0
  41. package/dist/token-zzzp7w2y.js +1 -0
  42. package/dist/tui/command-dialogs.d.ts +14 -0
  43. package/dist/tui-preferences.d.ts +40 -0
  44. package/dist/tui-preferences.js +6 -0
  45. package/dist/tui.d.ts +9 -0
  46. package/dist/util/open-url.d.ts +6 -0
  47. package/dist/version.d.ts +1 -1
  48. package/dist/ws-pool.d.ts +8 -0
  49. package/dist/ws.d.ts +4 -0
  50. package/package.json +25 -4
  51. package/src/rpc/notifications.ts +54 -0
  52. package/src/rpc/port-file.ts +70 -0
  53. package/src/rpc/protocol.ts +31 -0
  54. package/src/rpc/rpc-client.ts +78 -0
  55. package/src/rpc/rpc-dir.ts +22 -0
  56. package/src/rpc/rpc-server.ts +129 -0
  57. package/src/sidebar-state.ts +312 -0
  58. package/src/tui/command-dialogs.tsx +742 -0
  59. package/src/tui-preferences.ts +328 -0
  60. package/src/tui.tsx +837 -0
  61. package/dist/index-6z8w05g9.js +0 -2
  62. package/dist/index-xqe8xm96.js +0 -2
  63. package/dist/token-util-fs3z8kkp.js +0 -1
  64. package/dist/token-yyjm093c.js +0 -1
@@ -0,0 +1,136 @@
1
+ /**
2
+ * Unified quota cache and API gateway.
3
+ *
4
+ * Single source of truth for main + fallback quota state. All consumers
5
+ * share one QuotaManager instance so they see the same in-memory cache.
6
+ * Handles deduplication, rate-limiting (429 backoff), and staleness.
7
+ *
8
+ * Adapted from anthropic-auth — provider-specific quota fetch injected via
9
+ * fetchQuotaFn instead of hard-importing fetchOAuthQuotaSnapshot.
10
+ */
11
+ import type { AccountOperationError, AccountStorage, OAuthAccount, OAuthQuotaSnapshot } from './accounts.ts';
12
+ import type { ProviderQuotaFn } from './provider.ts';
13
+ export type { ProviderQuotaFn };
14
+ /**
15
+ * Stable, non-reversible fingerprint of an access token. Used to detect a
16
+ * main-account switch so a different account's persisted/cached quota is never
17
+ * reused. Not a secret — a truncated SHA-256, safe to persist alongside quota.
18
+ */
19
+ export declare function tokenFingerprint(token: string): string;
20
+ export type QuotaEntry = {
21
+ quota: OAuthQuotaSnapshot;
22
+ refreshAfter: number;
23
+ checkedAt: number;
24
+ };
25
+ export type QuotaManagerOptions = {
26
+ storage: AccountStorage | null;
27
+ fetchImpl?: typeof fetch;
28
+ now?: () => number;
29
+ /** Injected quota-fetch function — replaces the hard-imported Anthropic fetchOAuthQuotaSnapshot */
30
+ fetchQuotaFn?: ProviderQuotaFn;
31
+ onMainQuotaFetched?: (quota: OAuthQuotaSnapshot, checkedAt: number, fingerprint: string, fetchStartedAt: number) => void;
32
+ onApiError?: (error: AccountOperationError) => void;
33
+ };
34
+ export declare class QuotaManager {
35
+ private main;
36
+ private mainTokenFp;
37
+ private fallbacks;
38
+ private fallbackTokenFps;
39
+ private inflightMain;
40
+ private inflightMainFp;
41
+ private inflightFallbacks;
42
+ private mainLastApiError;
43
+ private fallbackApiErrors;
44
+ private fallbackErrorTokenFps;
45
+ private apiGate;
46
+ private lastApiCallAt;
47
+ private storage;
48
+ private readonly fetchImpl;
49
+ private readonly now;
50
+ private readonly fetchQuotaFn;
51
+ private readonly onMainQuotaFetched;
52
+ private readonly onApiError;
53
+ constructor(opts: QuotaManagerOptions);
54
+ /**
55
+ * Cached main quota entry. Pass the live access token to enforce token
56
+ * binding: if the cached entry was produced by a different token (main
57
+ * account switched), it is dropped and null is returned so the caller
58
+ * refetches for the current account. Called without a token (e.g. for
59
+ * display) it returns whatever is cached.
60
+ */
61
+ getMain(accessToken?: string): QuotaEntry | null;
62
+ /**
63
+ * Cached fallback quota entry. Pass the live access token to enforce token
64
+ * binding: if the entry was produced by a different token (account re-login),
65
+ * it is dropped and null is returned so the caller refetches.
66
+ */
67
+ getFallback(accountId: string, accessToken?: string): QuotaEntry | null;
68
+ getAllFallbacks(): Map<string, QuotaEntry>;
69
+ setMain(accessToken: string, entry: QuotaEntry): void;
70
+ setFallback(accountId: string, entry: QuotaEntry, accessToken?: string): void;
71
+ refreshMain(accessToken: string): Promise<OAuthQuotaSnapshot>;
72
+ refreshFallback(accountId: string, accessToken: string): Promise<OAuthQuotaSnapshot>;
73
+ refreshAllFallbacks(accounts: OAuthAccount[]): Promise<void>;
74
+ /**
75
+ * Fire-and-forget refresh. Does not await, swallows errors.
76
+ */
77
+ refreshMainInBackground(accessToken: string): void;
78
+ isMainStale(): boolean;
79
+ isFallbackStale(accountId: string, accessToken?: string): boolean;
80
+ shouldRefreshOnRequestCount(requestCount: number): boolean;
81
+ /**
82
+ * Combined check: should a refresh happen right now?
83
+ * True if main is stale by time OR triggered by request count.
84
+ */
85
+ needsRefresh(requestCount: number): boolean;
86
+ updateStorage(storage: AccountStorage | null): void;
87
+ /**
88
+ * Seed/update the main quota cache from persisted state. This is deliberately
89
+ * callable after every disk load so another plugin process's fresh quota write
90
+ * can stop this process from showing "checking…" or making a redundant quota
91
+ * API call.
92
+ */
93
+ seedMainFromStorage(storage: AccountStorage | null, accessToken?: string): void;
94
+ private seedMainBackoffFromStorage;
95
+ /**
96
+ * Seed fallback cache entries from persisted account.quota data.
97
+ * Updates older in-memory entries so a fresh quota write from another plugin
98
+ * process prevents redundant checks and stale sidebar writes.
99
+ */
100
+ seedFallbacksFromAccounts(accounts: OAuthAccount[]): void;
101
+ /**
102
+ * Whether the MAIN quota API is currently in backoff. Scoped to the main
103
+ * account — a fallback account's 429 never reports here.
104
+ */
105
+ isBackedOff(): boolean;
106
+ /**
107
+ * Whether a specific fallback account's quota API is in backoff.
108
+ */
109
+ isFallbackBackedOff(accountId: string, accessToken?: string): boolean;
110
+ getLastApiError(): AccountOperationError | undefined;
111
+ /** Minimum gap between consecutive quota API calls (ms). */
112
+ private static readonly API_CALL_GAP_MS;
113
+ private static fallbackInflightKey;
114
+ private static quotaLockName;
115
+ /**
116
+ * Serialize API calls through a shared gate so only one
117
+ * quota API request runs at a time, with a minimum gap
118
+ * between calls. Prevents concurrent and rapid-fire calls
119
+ * from triggering rate limits.
120
+ */
121
+ private _enqueueApiFetch;
122
+ private _fetchMain;
123
+ private _fetchFallback;
124
+ /** Route through injected fetchQuotaFn, or throw if unset. */
125
+ private _fetchQuota;
126
+ private static isAuthError;
127
+ /** Main quota failure: arms main-only backoff and persists via onApiError. */
128
+ private _handleMainFetchError;
129
+ /**
130
+ * Fallback quota failure: arms backoff for THIS account only. Never touches
131
+ * main backoff state and never calls onApiError (which persists the main
132
+ * quota error) — the per-account error is recorded by the caller via the
133
+ * account's lastQuotaRefreshError.
134
+ */
135
+ private _handleFallbackFetchError;
136
+ }
@@ -0,0 +1,52 @@
1
+ import type { FallbackAccountManager, isOAuthAccount, loadAccounts } from './accounts';
2
+ import type { whamUsageFn } from './provider';
3
+ import type { QuotaManager } from './quota-manager';
4
+ export interface RefreshAllQuotaDeps {
5
+ getAuth: () => Promise<{
6
+ type: string;
7
+ access?: string;
8
+ refresh?: string;
9
+ expires?: number;
10
+ }>;
11
+ codexRefreshFn: (input: {
12
+ refreshToken: string;
13
+ fetchImpl: typeof fetch;
14
+ now: () => number;
15
+ }) => Promise<{
16
+ access: string;
17
+ refresh: string;
18
+ expires: number;
19
+ }>;
20
+ fallbackManager: FallbackAccountManager;
21
+ quotaManager: QuotaManager;
22
+ loadAccounts: typeof loadAccounts;
23
+ writeSidebarState: (qm: QuotaManager, store: Awaited<ReturnType<typeof loadAccounts>>) => Promise<void>;
24
+ client: {
25
+ auth: {
26
+ set: (input: {
27
+ path: {
28
+ id: string;
29
+ };
30
+ body: {
31
+ type: string;
32
+ access?: string;
33
+ refresh: string;
34
+ expires?: number;
35
+ };
36
+ }) => Promise<unknown>;
37
+ };
38
+ };
39
+ fetchImpl: typeof fetch;
40
+ now: () => number;
41
+ configPath: string;
42
+ storageMainAccountId: string | undefined;
43
+ isOAuthAccountFn: typeof isOAuthAccount;
44
+ whamFn?: typeof whamUsageFn;
45
+ respectBackoff?: boolean;
46
+ }
47
+ export interface RefreshAllQuotaResult {
48
+ account: string;
49
+ ok: boolean;
50
+ error?: string;
51
+ }
52
+ export declare function refreshAllQuota(deps: RefreshAllQuotaDeps): Promise<RefreshAllQuotaResult[]>;
@@ -0,0 +1,15 @@
1
+ export declare const ACCOUNT_FILE_NAME = "openai-auth.json";
2
+ export declare const ACCOUNT_STATE_FILE_NAME = "openai-auth-state.json";
3
+ export declare function getAccountStoragePath(): string;
4
+ export declare function getAccountStatePath(configPath?: string): string;
5
+ export declare function acquireRefreshFileLock(options: {
6
+ name: string;
7
+ ttlMs: number;
8
+ path?: string;
9
+ now?: () => number;
10
+ renew?: boolean;
11
+ renewIntervalMs?: number;
12
+ onStep?: (step: 'stale-marker-stat' | 'stale-marker-claimed' | 'stale-lock-confirmed' | 'eviction-marker-acquired') => void | Promise<void>;
13
+ }): Promise<{
14
+ release: () => Promise<void>;
15
+ } | null>;
@@ -0,0 +1,3 @@
1
+ import{appendFileSync as k,existsSync as g,renameSync as p,statSync as w}from"node:fs";import{tmpdir as y}from"node:os";import{join as L}from"node:path";var s={error:0,warn:1,info:2,debug:3,trace:4},l=!1,m=5242880;function E(){return process.env.OPENCODE_OPENAI_AUTH_LOG_FILE??L(y(),"opencode-openai-auth.log")}var f;function x(n){if(n===void 0||n in s)f=n}function O(){if(f)return f;let n=process.env.OPENCODE_OPENAI_AUTH_LOG_LEVEL;if(n&&n in s)return n;return"info"}var T=/^(authorization|x-api-key|cookie|set-cookie|refresh|access|token)$/i;function _(n){if(T.test(n))return!0;let e=n.toLowerCase().replace(/[-_]/g,"");if(e.includes("apikey"))return!0;if(e.endsWith("secret")||e.endsWith("password"))return!0;if(e.endsWith("token")&&!e.endsWith("tokens"))return!0;return!1}var b=/\b(Bearer\s+[\w.-]+|sk-[\w-]+|eyJ[\w.-]+)\b/g;function h(n){return d(n,new WeakSet)}function d(n,e){if(typeof n==="string")return n.replace(b,"***REDACTED***");if(Array.isArray(n)){if(e.has(n))return"[Circular]";e.add(n);let t=n.map((r)=>d(r,e));return e.delete(n),t}if(n&&typeof n==="object"){if(e.has(n))return"[Circular]";e.add(n);let t={};for(let[r,u]of Object.entries(n))t[r]=_(r)?"***REDACTED***":d(u,e);return e.delete(n),t}return n}var o=[],c,S=3;function $(){try{let n=E();if(!(g(n)&&w(n).size>m))return;for(let e=S-1;e>=1;e--)if(g(`${n}.${e}`))p(`${n}.${e}`,`${n}.${e+1}`);p(n,`${n}.1`)}catch{}}function a(){if(!o.length)return;let n=o.join("");o=[];try{$(),k(E(),n)}catch{}}function A(){if(!c)c=setTimeout(()=>{c=void 0,a()},500)}if(!l)process.on("exit",a);function C(n){try{return` ${JSON.stringify(h(n))}`}catch{return" [unserializable]"}}function i(n,e,t,r){if(s[e]>s[O()])return;let u=`[${new Date().toISOString()}] ${e.toUpperCase()} [${n}] ${t}`+(r===void 0?"":C(r))+`
2
+ `;if(o.push(u),o.length>=50)a();else A()}function j(n){return{error:(e,t)=>i(n,"error",e,t),warn:(e,t)=>i(n,"warn",e,t),info:(e,t)=>i(n,"info",e,t),debug:(e,t)=>i(n,"debug",e,t),trace:(e,t)=>i(n,"trace",e,t)}}
3
+ export{x as X,j as Y};
@@ -0,0 +1,2 @@
1
+ import{ca as Y,ea as K}from"./index-hrg6bdgb.js";var V=Y((rz,O)=>{var{defineProperty:J,getOwnPropertyDescriptor:r,getOwnPropertyNames:t}=Object,e=Object.prototype.hasOwnProperty,o=(z,B)=>{for(var F in B)J(z,F,{get:B[F],enumerable:!0})},zz=(z,B,F,H)=>{if(B&&typeof B==="object"||typeof B==="function"){for(let G of t(B))if(!e.call(z,G)&&G!==F)J(z,G,{get:()=>B[G],enumerable:!(H=r(B,G))||H.enumerable})}return z},Bz=(z)=>zz(J({},"__esModule",{value:!0}),z),M={};o(M,{VercelOidcTokenError:()=>j});O.exports=Bz(M);class j extends Error{constructor(z,B){super(z);this.name="VercelOidcTokenError",this.cause=B}toString(){if(this.cause)return`${this.name}: ${this.message}: ${this.cause}`;return`${this.name}: ${this.message}`}}});var C=Y((tz,x)=>{var{create:Fz,defineProperty:v,getOwnPropertyDescriptor:Gz,getOwnPropertyNames:Hz,getPrototypeOf:Kz}=Object,Qz=Object.prototype.hasOwnProperty,Wz=(z,B)=>{for(var F in B)v(z,F,{get:B[F],enumerable:!0})},S=(z,B,F,H)=>{if(B&&typeof B==="object"||typeof B==="function"){for(let G of Hz(B))if(!Qz.call(z,G)&&G!==F)v(z,G,{get:()=>B[G],enumerable:!(H=Gz(B,G))||H.enumerable})}return z},N=(z,B,F)=>(F=z!=null?Fz(Kz(z)):{},S(B||!z||!z.__esModule?v(F,"default",{value:z,enumerable:!0}):F,z)),Xz=(z)=>S(v({},"__esModule",{value:!0}),z),E={};Wz(E,{findRootDir:()=>$z,getUserDataDir:()=>qz});x.exports=Xz(E);var Z=N(K("path")),Yz=N(K("fs")),A=N(K("os")),Zz=V();function $z(){try{let z=process.cwd();while(z!==Z.default.dirname(z)){let B=Z.default.join(z,".vercel");if(Yz.default.existsSync(B))return z;z=Z.default.dirname(z)}}catch(z){throw new Zz.VercelOidcTokenError("Token refresh only supported in node server environments")}return null}function qz(){if(process.env.XDG_DATA_HOME)return process.env.XDG_DATA_HOME;switch(A.default.platform()){case"darwin":return Z.default.join(A.default.homedir(),"Library/Application Support");case"linux":return Z.default.join(A.default.homedir(),".local/share");case"win32":if(process.env.LOCALAPPDATA)return process.env.LOCALAPPDATA;return null;default:return null}}});var c=Y((ez,g)=>{var{create:vz,defineProperty:b,getOwnPropertyDescriptor:bz,getOwnPropertyNames:Uz,getPrototypeOf:Lz}=Object,Jz=Object.prototype.hasOwnProperty,Vz=(z,B)=>{for(var F in B)b(z,F,{get:B[F],enumerable:!0})},y=(z,B,F,H)=>{if(B&&typeof B==="object"||typeof B==="function"){for(let G of Uz(B))if(!Jz.call(z,G)&&G!==F)b(z,G,{get:()=>B[G],enumerable:!(H=bz(B,G))||H.enumerable})}return z},u=(z,B,F)=>(F=z!=null?vz(Lz(z)):{},y(B||!z||!z.__esModule?b(F,"default",{value:z,enumerable:!0}):F,z)),Az=(z)=>y(b({},"__esModule",{value:!0}),z),P={};Vz(P,{isValidAccessToken:()=>wz,readAuthConfig:()=>Rz,writeAuthConfig:()=>Iz});g.exports=Az(P);var $=u(K("fs")),l=u(K("path")),Nz=k();function h(){let z=(0,Nz.getVercelDataDir)();if(!z)throw Error(`Unable to find Vercel CLI data directory. Your platform: ${process.platform}. Supported: darwin, linux, win32.`);return l.join(z,"auth.json")}function Rz(){try{let z=h();if(!$.existsSync(z))return null;let B=$.readFileSync(z,"utf8");if(!B)return null;return JSON.parse(B)}catch(z){return null}}function Iz(z){let B=h(),F=l.dirname(B);if(!$.existsSync(F))$.mkdirSync(F,{mode:504,recursive:!0});$.writeFileSync(B,JSON.stringify(z,null,2),{mode:384})}function wz(z){if(!z.token)return!1;if(typeof z.expiresAt!=="number")return!0;let B=Math.floor(Date.now()/1000);return z.expiresAt>=B}});var p=Y((oz,d)=>{var{defineProperty:w,getOwnPropertyDescriptor:Dz,getOwnPropertyNames:Tz}=Object,Mz=Object.prototype.hasOwnProperty,jz=(z,B)=>{for(var F in B)w(z,F,{get:B[F],enumerable:!0})},Oz=(z,B,F,H)=>{if(B&&typeof B==="object"||typeof B==="function"){for(let G of Tz(B))if(!Mz.call(z,G)&&G!==F)w(z,G,{get:()=>B[G],enumerable:!(H=Dz(B,G))||H.enumerable})}return z},Sz=(z)=>Oz(w({},"__esModule",{value:!0}),z),i={};jz(i,{processTokenResponse:()=>uz,refreshTokenRequest:()=>yz});d.exports=Sz(i);var R=K("os"),Ez="https://vercel.com",xz="cl_HYyOPBNtFMfHhaUn9L4QPfTZz6TP47bp",f=`@vercel/oidc node-${process.version} ${(0,R.platform)()} (${(0,R.arch)()}) ${(0,R.hostname)()}`,I=null;async function Cz(){if(I)return I;let z=`${Ez}/.well-known/openid-configuration`,B=await fetch(z,{headers:{"user-agent":f}});if(!B.ok)throw Error("Failed to discover OAuth endpoints");let F=await B.json();if(!F||typeof F.token_endpoint!=="string")throw Error("Invalid OAuth discovery response");let H=F.token_endpoint;return I=H,H}async function yz(z){let B=await Cz();return await fetch(B,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded","user-agent":f},body:new URLSearchParams({client_id:xz,grant_type:"refresh_token",...z})})}async function uz(z){let B=await z.json();if(!z.ok){let F=typeof B==="object"&&B&&"error"in B?String(B.error):"Token refresh failed";return[Error(F)]}if(typeof B!=="object"||B===null)return[Error("Invalid token response")];if(typeof B.access_token!=="string")return[Error("Missing access_token in response")];if(B.token_type!=="Bearer")return[Error("Invalid token_type in response")];if(typeof B.expires_in!=="number")return[Error("Missing expires_in in response")];return[null,B]}});var k=Y((zB,n)=>{var{create:Pz,defineProperty:U,getOwnPropertyDescriptor:lz,getOwnPropertyNames:hz,getPrototypeOf:gz}=Object,cz=Object.prototype.hasOwnProperty,kz=(z,B)=>{for(var F in B)U(z,F,{get:B[F],enumerable:!0})},a=(z,B,F,H)=>{if(B&&typeof B==="object"||typeof B==="function"){for(let G of hz(B))if(!cz.call(z,G)&&G!==F)U(z,G,{get:()=>B[G],enumerable:!(H=lz(B,G))||H.enumerable})}return z},_=(z,B,F)=>(F=z!=null?Pz(gz(z)):{},a(B||!z||!z.__esModule?U(F,"default",{value:z,enumerable:!0}):F,z)),iz=(z)=>a(U({},"__esModule",{value:!0}),z),m={};kz(m,{assertVercelOidcTokenResponse:()=>D,findProjectInfo:()=>sz,getTokenPayload:()=>mz,getVercelCliToken:()=>dz,getVercelDataDir:()=>fz,getVercelOidcToken:()=>pz,isExpired:()=>nz,loadToken:()=>_z,saveToken:()=>az});n.exports=iz(m);var q=_(K("path")),Q=_(K("fs")),X=V(),L=C(),W=c(),s=p();function fz(){let B=(0,L.getUserDataDir)();if(!B)return null;return q.join(B,"com.vercel.cli")}async function dz(){let z=(0,W.readAuthConfig)();if(!z)return null;if((0,W.isValidAccessToken)(z))return z.token||null;if(!z.refreshToken)return(0,W.writeAuthConfig)({}),null;try{let B=await(0,s.refreshTokenRequest)({refresh_token:z.refreshToken}),[F,H]=await(0,s.processTokenResponse)(B);if(F||!H)return(0,W.writeAuthConfig)({}),null;let G={token:H.access_token,expiresAt:Math.floor(Date.now()/1000)+H.expires_in};if(H.refresh_token)G.refreshToken=H.refresh_token;return(0,W.writeAuthConfig)(G),G.token??null}catch(B){return(0,W.writeAuthConfig)({}),null}}async function pz(z,B,F){let H=`https://api.vercel.com/v1/projects/${B}/token?source=vercel-oidc-refresh${F?`&teamId=${F}`:""}`,G=await fetch(H,{method:"POST",headers:{Authorization:`Bearer ${z}`}});if(!G.ok)throw new X.VercelOidcTokenError(`Failed to refresh OIDC token: ${G.statusText}`);let T=await G.json();return D(T),T}function D(z){if(!z||typeof z!=="object")throw TypeError("Vercel OIDC token is malformed. Expected an object. Please run `vc env pull` and try again");if(!("token"in z)||typeof z.token!=="string")throw TypeError("Vercel OIDC token is malformed. Expected a string-valued token property. Please run `vc env pull` and try again")}function sz(){let z=(0,L.findRootDir)();if(!z)throw new X.VercelOidcTokenError("Unable to find project root directory. Have you linked your project with `vc link?`");let B=q.join(z,".vercel","project.json");if(!Q.existsSync(B))throw new X.VercelOidcTokenError("project.json not found, have you linked your project with `vc link?`");let F=JSON.parse(Q.readFileSync(B,"utf8"));if(typeof F.projectId!=="string"&&typeof F.orgId!=="string")throw TypeError("Expected a string-valued projectId property. Try running `vc link` to re-link your project.");return{projectId:F.projectId,teamId:F.orgId}}function az(z,B){let F=(0,L.getUserDataDir)();if(!F)throw new X.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");let H=q.join(F,"com.vercel.token",`${B}.json`),G=JSON.stringify(z);Q.mkdirSync(q.dirname(H),{mode:504,recursive:!0}),Q.writeFileSync(H,G),Q.chmodSync(H,432);return}function _z(z){let B=(0,L.getUserDataDir)();if(!B)throw new X.VercelOidcTokenError("Unable to find user data directory. Please reach out to Vercel support.");let F=q.join(B,"com.vercel.token",`${z}.json`);if(!Q.existsSync(F))return null;let H=JSON.parse(Q.readFileSync(F,"utf8"));return D(H),H}function mz(z){let B=z.split(".");if(B.length!==3)throw new X.VercelOidcTokenError("Invalid token. Please run `vc env pull` and try again");let F=B[1].replace(/-/g,"+").replace(/_/g,"/"),H=F.padEnd(F.length+(4-F.length%4)%4,"=");return JSON.parse(Buffer.from(H,"base64").toString("utf8"))}function nz(z){return z.exp*1000<Date.now()}});
2
+ export{V as a,k as b};
@@ -0,0 +1,2 @@
1
+ import{mkdir as u,readdir as l,readFile as c,rename as p,unlink as m,writeFile as d}from"node:fs/promises";import{join as a}from"node:path";function f(t){try{return process.kill(t,0),!0}catch(r){return r.code==="EPERM"}}async function b(t,r){await u(t,{recursive:!0});let s={...r,startedAt:Date.now()},e=a(t,`port-${r.pid}.json`),i=`${e}.${process.pid}.tmp`;return await d(i,JSON.stringify(s),{encoding:"utf8",mode:384}),await p(i,e),e}async function h(t,r){let s;try{s=await l(t)}catch{return null}let e=[];for(let n of s){if(!n.startsWith("port-")||!n.endsWith(".json"))continue;try{let o=JSON.parse(await c(a(t,n),"utf8"));if(Number.isFinite(o.port))if(f(o.pid))e.push(o);else m(a(t,n)).catch(()=>{})}catch{}}if(e.length===0)return null;let i=r!==void 0&&r>=1?e.filter((n)=>n.pid===r):[];return(i.length>0?i:e).sort((n,o)=>o.startedAt-n.startedAt)[0]??null}
2
+ export{b as Z,h as _};
@@ -0,0 +1 @@
1
+ import{createHash as z}from"node:crypto";import{homedir as A,tmpdir as K}from"node:os";import{join as q,resolve as B}from"node:path";var F="OPENCODE_OPENAI_AUTH_RPC_DIR";function M(f){let k=process.env[F]?.trim();if(k)return B(f,k);let w=z("sha256").update(f).digest("hex").slice(0,16),x=process.env.XDG_STATE_HOME||q(A(),".local","state");return q(x,"cortexkit","openai-auth","rpc",w)}export{K as $,M as aa};
@@ -0,0 +1,2 @@
1
+ import{createRequire as s}from"node:module";var j=Object.create;var{getPrototypeOf:k,defineProperty:f,getOwnPropertyNames:l}=Object;var m=Object.prototype.hasOwnProperty;function n(a){return this[a]}var o,p,t=(a,b,c)=>{var g=a!=null&&typeof a==="object";if(g){var h=b?o??=new WeakMap:p??=new WeakMap,i=h.get(a);if(i)return i}c=a!=null?j(k(a)):{};let d=b||!a||!a.__esModule?f(c,"default",{value:a,enumerable:!0}):c;for(let e of l(a))if(!m.call(d,e))f(d,e,{get:n.bind(a,e),enumerable:!0});if(g)h.set(a,d);return d};var u=(a,b)=>()=>(b||a((b={exports:{}}).exports,b),b.exports);var q=(a)=>a;function r(a,b){this[a]=q.bind(null,b)}var v=(a,b)=>{for(var c in b)f(a,c,{get:b[c],enumerable:!0,configurable:!0,set:r.bind(b,c)})};var x=s(import.meta.url);
2
+ export{t as ba,u as ca,v as da,x as ea};
@@ -0,0 +1,2 @@
1
+ import{Y as v}from"./index-0s5tftne.js";import{mkdir as h,readFile as O,writeFile as N}from"node:fs/promises";import{tmpdir as C}from"node:os";import{dirname as g,join as R}from"node:path";var k=v("sidebar"),L="OPENCODE_OPENAI_AUTH_SIDEBAR_STATE_FILE",D=R(C(),"opencode-openai-auth"),f=R(D,"sidebar-state.json");function W(){return process.env[L]||f}var B={main:{quota:null,killed:!1},fallbacks:[],activeId:void 0,route:"main",lastUpdated:0};function F(K){if(K===null||typeof K!=="object"||Array.isArray(K))return B;let x=K,J=x.main,Q;if(J!==null&&typeof J==="object"&&!Array.isArray(J)){let H=J;Q={quota:"quota"in H?H.quota:null,killed:typeof H.killed==="boolean"?H.killed:!1,...typeof H.quotaBackedOff==="boolean"?{quotaBackedOff:H.quotaBackedOff}:{},...typeof H.quotaBackoffUntil==="number"?{quotaBackoffUntil:H.quotaBackoffUntil}:{},...typeof H.refreshBackedOff==="boolean"?{refreshBackedOff:H.refreshBackedOff}:{},...typeof H.refreshBackoffUntil==="number"?{refreshBackoffUntil:H.refreshBackoffUntil}:{}}}else Q={quota:null,killed:!1};let Y=x.fallbacks,X=Array.isArray(Y)?Y.filter((H)=>H!==null&&typeof H==="object"&&!Array.isArray(H)&&typeof H.id==="string").map((H)=>({id:H.id,label:typeof H.label==="string"?H.label:void 0,quota:"quota"in H?H.quota:null,killed:typeof H.killed==="boolean"?H.killed:!1,enabled:typeof H.enabled==="boolean"?H.enabled:!0})):[],Z=typeof x.activeId==="string"?x.activeId:void 0,V=typeof x.route==="string"?x.route:B.route,$=typeof x.lastUpdated==="number"?x.lastUpdated:0,j=typeof x.planType==="string"?x.planType:void 0,z=typeof x.credits==="number"?x.credits:void 0;return{main:Q,fallbacks:X,activeId:Z,route:V,lastUpdated:$,...j!==void 0?{planType:j}:{},...z!==void 0?{credits:z}:{}}}async function p(){try{let K=await O(W(),"utf8");return F(JSON.parse(K))}catch{return B}}var G=Promise.resolve();function u(K,x=W()){return G=G.then(()=>I(K,x)).catch(()=>{}),G}async function I(K,x){try{await h(g(x),{recursive:!0}),await N(x,JSON.stringify(K),"utf8")}catch(J){k.warn("sidebar write failed",{pid:process.pid,error:J instanceof Error?J.message:String(J)})}}function T(){return G}function E(K){let x=K.activeId;if(x&&x!=="main"){let J=K.fallbacks.find((Q)=>Q.enabled&&Q.id===x);if(J)return{id:J.id,name:J.label??J.id,quota:J.quota,killed:J.killed}}return{id:"main",name:"main",quota:K.main.quota,killed:K.main.killed}}function A(K){let x=K?.primary?.usedPercent??null,J=K?.secondary?.usedPercent??null;if(x==null&&J==null)return{primaryUsedPercent:x,secondaryUsedPercent:J,text:null};return{primaryUsedPercent:x,secondaryUsedPercent:J,text:`5h: ${x==null?"—":`${Math.round(x)}%`} 7d: ${J==null?"—":`${Math.round(J)}%`}`}}var m=18000000,c=604800000,M=300000,U=0.01,b=1;function w(K,x,J){if(!K.resetsAt)return null;let Q=new Date(K.resetsAt).getTime();if(!Number.isFinite(Q))return null;let Y=Q-x,X=J-Y;if(X<M)return null;if(X<x*U)return null;if(X>=x)return null;let Z=K.usedPercent,V=Math.min(Math.max(X/x*100,0),100),$=Z-V,j=Math.abs($)<b?"on-pace":$>0?"deficit":"reserve",z=null;if(Z>0){let H=X*100/Z,q=Y+H;if(q<Q)z=new Date(q).toISOString()}return{pacePercent:V,deltaPercent:$,state:j,runsOutAt:z}}
2
+ export{W as M,B as N,F as O,p as P,u as Q,T as R,E as S,A as T,m as U,c as V,w as W};
@@ -0,0 +1,92 @@
1
+ import{Y as y0}from"./index-0s5tftne.js";import{ea as K1}from"./index-hrg6bdgb.js";import{createHash as v0}from"node:crypto";var d0=86400000,l0=300000,g0=3600000,i0=60000,u0=900000,s0=300000;function r(B){return B instanceof Error?B.message:String(B)}function c0(B){let Z=B?.status;if(typeof Z==="number")return Z===429||Z>=500;if(!(B instanceof Error))return!1;return B.message.includes("fetch failed")||"code"in B&&(B.code==="ECONNRESET"||B.code==="ECONNREFUSED"||B.code==="ETIMEDOUT"||B.code==="UND_ERR_CONNECT_TIMEOUT")}function a(B){let Z=r(B),$=B?.status;if(typeof $==="number")return $===429||$>=500;if(!(B instanceof Error))return!1;let z=B.code;return Z.includes("fetch failed")||z==="ECONNRESET"||z==="ECONNREFUSED"||z==="ETIMEDOUT"||z==="UND_ERR_CONNECT_TIMEOUT"}function N0(B){return v0("sha256").update(B).digest("hex")}function V0(B){let Z=N0(B.refreshToken),z=(B.previous?.tokenHash===Z?B.previous.retryCount??0:0)+1,G,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)G=X*1000;else if(c0(B.error))G=Math.min(g0,l0*2**Math.min(z-1,6));else G=d0;return{message:r(B.error),checkedAt:B.now,nextRetryAt:B.now+G,retryCount:z,tokenHash:Z}}function I(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===N0(Z)}function d(B,Z){return`Codex OAuth refresh is backed off for ${Math.max(1,Math.ceil(((B.nextRetryAt??Z)-Z)/1000))}s after: ${B.message}`}function H0(B){let $=(B.previous?.retryCount??0)+1,z=a(B.error)?Math.min(u0,i0*2**Math.min($-1,6)):s0;return{message:r(B.error),checkedAt:B.now,nextRetryAt:B.now+z,retryCount:$}}function b0(B,Z){if(!B?.nextRetryAt||B.nextRetryAt<=Z)return!1;return!0}function o(B){if(!B)return;let Z=Number(B);if(Number.isFinite(Z)&&Z>0)return Math.ceil(Z);let $=Date.parse(B);if(Number.isFinite($)){let z=Math.ceil(($-Date.now())/1000);return z>0?z:void 0}return}import{createServer as n0}from"node:http";import{setTimeout as r0}from"node:timers/promises";var F0="0.1.3";var l="app_EMoamEEZ73f0CkXaXp7hrann",_="https://auth.openai.com",k=1455,a0=3000,M0=`cortexkit-opencode-openai-auth/${F0}`;function q0(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function o0(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((z)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[z%66]).join(""),$=q0(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(Z)));return{verifier:Z,challenge:$}}function D0(B){let Z=B.split(".");if(Z.length!==3)return;let $=Z[1];if(!$)return;try{return JSON.parse(Buffer.from($,"base64url").toString())}catch{return}}function L0(B){let Z=B.chatgpt_account_id;if(typeof Z==="string"&&Z.length>0)return Z;let $=B["https://api.openai.com/auth"];if($&&typeof $==="object"&&!Array.isArray($)&&typeof $.chatgpt_account_id==="string"&&$.chatgpt_account_id.length>0)return $.chatgpt_account_id;let z=B.organizations;if(Array.isArray(z)){let G=z[0];if(G&&typeof G==="object"&&!Array.isArray(G)&&typeof G.id==="string"&&G.id.length>0)return G.id}return}function R(B){if(B.id_token){let Z=D0(B.id_token),$=Z&&L0(Z);if($)return $}if(B.access_token){let Z=D0(B.access_token);return Z?L0(Z):void 0}return}function t0(B,Z,$){let z=new URLSearchParams({response_type:"code",client_id:l,redirect_uri:B,scope:"openid profile email offline_access",code_challenge:Z.challenge,code_challenge_method:"S256",id_token_add_organizations:"true",codex_cli_simplified_flow:"true",state:$,originator:"opencode"});return`${_}/oauth/authorize?${z.toString()}`}async function e0(B,Z,$){let z=await fetch(`${_}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:B,redirect_uri:Z,client_id:l,code_verifier:$.verifier}).toString()});if(!z.ok)throw Error(`Token exchange failed: ${z.status}`);return await z.json()}function B1(B){return B.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}var Z1=`<!doctype html>
2
+ <html>
3
+ <head>
4
+ <title>CortexKit OpenAI Auth - Authorization Successful</title>
5
+ <style>
6
+ body {
7
+ font-family:
8
+ system-ui,
9
+ -apple-system,
10
+ sans-serif;
11
+ display: flex;
12
+ justify-content: center;
13
+ align-items: center;
14
+ height: 100vh;
15
+ margin: 0;
16
+ background: #131010;
17
+ color: #f1ecec;
18
+ }
19
+ .container {
20
+ text-align: center;
21
+ padding: 2rem;
22
+ }
23
+ h1 {
24
+ color: #f1ecec;
25
+ margin-bottom: 1rem;
26
+ }
27
+ p {
28
+ color: #b7b1b1;
29
+ }
30
+ </style>
31
+ </head>
32
+ <body>
33
+ <div class="container">
34
+ <h1>Authorization Successful</h1>
35
+ <p>You can close this window and return to OpenCode.</p>
36
+ </div>
37
+ <script>
38
+ setTimeout(() => window.close(), 2000)
39
+ </script>
40
+ </body>
41
+ </html>`,t=(B)=>`<!doctype html>
42
+ <html>
43
+ <head>
44
+ <title>CortexKit OpenAI Auth - Authorization Failed</title>
45
+ <style>
46
+ body {
47
+ font-family:
48
+ system-ui,
49
+ -apple-system,
50
+ sans-serif;
51
+ display: flex;
52
+ justify-content: center;
53
+ align-items: center;
54
+ height: 100vh;
55
+ margin: 0;
56
+ background: #131010;
57
+ color: #f1ecec;
58
+ }
59
+ .container {
60
+ text-align: center;
61
+ padding: 2rem;
62
+ }
63
+ h1 {
64
+ color: #fc533a;
65
+ margin-bottom: 1rem;
66
+ }
67
+ p {
68
+ color: #b7b1b1;
69
+ }
70
+ .error {
71
+ color: #ff917b;
72
+ font-family: monospace;
73
+ margin-top: 1rem;
74
+ padding: 1rem;
75
+ background: #3c140d;
76
+ border-radius: 0.5rem;
77
+ }
78
+ </style>
79
+ </head>
80
+ <body>
81
+ <div class="container">
82
+ <h1>Authorization Failed</h1>
83
+ <p>An error occurred during authorization.</p>
84
+ <div class="error">${B1(B)}</div>
85
+ </div>
86
+ </body>
87
+ </html>`,f,m,L=new Map;function q(){return L.size}function y(B){if(L.delete(B),q()===0)O()}async function $1(){let B=`http://localhost:${k}/auth/callback`;if(f)return{port:k,redirectUri:B};if(m)return m;m=(async()=>{let Z=n0(($,z)=>{let G=new URL($.url||"/",`http://localhost:${k}`);if(G.pathname==="/auth/callback"){let X=G.searchParams.get("code"),K=G.searchParams.get("state"),J=G.searchParams.get("error"),W=G.searchParams.get("error_description");if(J){let Q=W||J;if(K){let V=L.get(K);if(V)V.reject(Error(Q)),y(K);else if(q()===0)O()}else if(q()===0)O();z.writeHead(200,{"Content-Type":"text/html"}),z.end(t(Q));return}if(!X||!K){let Q=!X?"Missing authorization code":"Missing state parameter";if(K){let V=L.get(K);if(V)V.reject(Error(Q)),y(K);else if(q()===0)O()}else if(q()===0)O();z.writeHead(400,{"Content-Type":"text/html"}),z.end(t(Q));return}let Y=L.get(K);if(!Y){if(q()===0)O();z.writeHead(400,{"Content-Type":"text/html"}),z.end(t("Unknown state — authorization may have expired"));return}y(K),e0(X,B,Y.pkce).then((Q)=>Y.resolve(Q)).catch((Q)=>Y.reject(Q)),z.writeHead(200,{"Content-Type":"text/html"}),z.end(Z1);return}if(G.pathname==="/cancel"){let X=G.searchParams.get("state"),K=X?[X]:[...L.keys()];z.writeHead(200),z.end("Login cancelled");for(let J of K){let W=L.get(J);if(!W)continue;W.reject(Error("Login cancelled")),y(J)}if(q()===0)O();return}z.writeHead(404),z.end("Not found")});return await new Promise(($,z)=>{Z.once("error",z),Z.listen(k,"127.0.0.1",()=>{Z.off("error",z),$()})}),f=Z,{port:k,redirectUri:B}})();try{return await m}finally{m=void 0}}function O(){if(f){let B=f;f=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function z1(B,Z,$=300000){return new Promise((z,G)=>{let X=setTimeout(()=>{if(L.get(Z))y(Z),G(Error("OAuth callback timeout — authorization took too long"))},$);L.set(Z,{pkce:B,state:Z,resolve:(K)=>{clearTimeout(X),z(K)},reject:(K)=>{clearTimeout(X),G(K)}})})}async function X1(){let B=await fetch(`${_}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":M0},body:JSON.stringify({client_id:l})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${_}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function G1(B,Z){let $=Math.max(parseInt(B.interval,10)||5,1)*1000;while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");let z=await fetch(`${_}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":M0},body:JSON.stringify({device_auth_id:B.device_auth_id,user_code:B.user_code})});if(z.ok){let G=await z.json(),X=await fetch(`${_}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:G.authorization_code,redirect_uri:`${_}/deviceauth/callback`,client_id:l,code_verifier:G.code_verifier}).toString()});if(!X.ok)throw Error(`Token exchange failed: ${X.status}`);return await X.json()}if(z.status!==403&&z.status!==404)throw Error(`Device authorization failed: ${z.status}`);await r0($+a0)}}function L3(B,Z){let $=-1;if(Z.accountId)$=B.findIndex((z)=>z.accountId&&z.accountId===Z.accountId);if($<0)$=B.findIndex((z)=>z.id===Z.id);if($<0&&Z.label&&!Z.accountId)$=B.findIndex((z)=>z.label===Z.label);if($>=0)return B[$]={...B[$],...Z,addedAt:B[$]?.addedAt??Z.addedAt},$;return B.push(Z),B.length-1}async function M3(B={}){let{label:Z,headless:$=!1,signal:z}=B;if($){let{deviceData:Y,url:Q,instructions:V}=await X1(),F=(async()=>{let N=await G1(Y,z),H=Date.now();return{id:Z||R(N)||crypto.randomUUID(),label:Z||void 0,type:"oauth",access:N.access_token,refresh:N.refresh_token,expires:H+(N.expires_in??3600)*1000,enabled:!0,addedAt:H,lastUsed:H,accountId:R(N)}})();return{url:Q,instructions:V,completion:F}}let{redirectUri:G}=await $1(),X=await o0(),K=q0(crypto.getRandomValues(new Uint8Array(32)).buffer),J=t0(G,X,K),W=(async()=>{try{if(z?.aborted)throw Error("Login cancelled");let Y=await z1(X,K),Q=Date.now();return{id:Z||R(Y)||crypto.randomUUID(),label:Z||void 0,type:"oauth",access:Y.access_token,refresh:Y.refresh_token,expires:Q+(Y.expires_in??3600)*1000,enabled:!0,addedAt:Q,lastUsed:Q,accountId:R(Y)}}finally{y(K)}})();return{url:J,instructions:"Complete authorization in your browser. This window will close automatically.",completion:W}}var g="primary",i="secondary",J1="app_EMoamEEZ73f0CkXaXp7hrann",W1="https://auth.openai.com";async function _3(B){let Z=await B.fetchImpl(`${W1}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:B.refreshToken,client_id:J1}).toString()});if(!Z.ok){let z=o(Z.headers.get("retry-after"));throw Object.assign(Error(`Token refresh failed: ${Z.status}`),{status:Z.status,retryAfter:z,isRefreshError:!0})}let $=await Z.json();return{access:$.access_token,refresh:$.refresh_token,expires:$.expires_in?B.now()+$.expires_in*1000:0,expiresIn:$.expires_in??3600}}var Y1="https://chatgpt.com/backend-api/wham/usage";async function U3(B){let Z=await B.fetchImpl(Y1,{headers:{authorization:`Bearer ${B.accessToken}`,"chatgpt-account-id":B.accountId??"","oai-client-platform":"web","oai-client-version":"0","x-openai-target-path":"/backend-api/wham/usage"}});if(!Z.ok){let z=o(Z.headers.get("retry-after"));throw Object.assign(Error(`wham usage check failed: ${Z.status}`),{status:Z.status,retryAfter:z})}let{normalizeWham:$}=await import("./quota-normalize-qh5n0p7v.js");return $(await Z.json())}import{randomUUID as e}from"node:crypto";import{mkdir as j1,readFile as B0,rename as Q1,rm as w,stat as O0,writeFile as Z0}from"node:fs/promises";import{homedir as N1}from"node:os";import{dirname as T3,join as h}from"node:path";var V1=globalThis.setTimeout.bind(globalThis),H1=globalThis.clearTimeout.bind(globalThis),b1="openai-auth.json";function F1(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return h(process.env.XDG_CONFIG_HOME||h(N1(),".config"),"opencode")}function D1(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||h(F1(),b1)}async function u(B){let $=`${B.path??D1()}.${B.name}.lock`,z=h($,"owner.json"),G=e(),X=B.now??Date.now,K=null,J=!1;async function W(){try{return JSON.parse(await B0($,"utf8"))}catch(N){if(N.code!=="EISDIR")throw N;return JSON.parse(await B0(z,"utf8"))}}async function Y(){await Z0($,`${JSON.stringify({ownerId:G,expiresAt:X()+B.ttlMs})}
88
+ `,{encoding:"utf8",mode:384})}async function Q(){try{return await Z0($,`${JSON.stringify({ownerId:G,expiresAt:X()+B.ttlMs})}
89
+ `,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(N){let H=N.code;if(H==="EEXIST"||H==="EISDIR")return!1;throw N}}function V(){if(!B.renew||J)return;let N=B.renewIntervalMs??Math.max(1000,Math.floor(B.ttlMs/3));if(K=V1(()=>{(async()=>{try{let H=await W(),p=X();if(J||H?.ownerId!==G||Number(H?.expiresAt)<=p)return;await Y(),V()}catch{}})()},N),"unref"in K)K.unref()}let F=await Q();if(!F){let N=`${$}.evicting`,H=h(N,"owner.json"),p=e(),Y3=5000,j3=8;async function v(){await new Promise((D)=>setTimeout(D,Math.floor(Math.random()*4)))}async function J0(){try{let D=await W();return Number(D?.expiresAt)>X()}catch{try{return(await O0($)).mtimeMs+B.ttlMs>X()}catch{return!1}}}async function x(){try{return JSON.parse(await B0(H,"utf8"))?.ownerId===p}catch{return!1}}async function p0(){await j1(N);try{await Z0(H,`${JSON.stringify({ownerId:p,createdAt:X()})}
90
+ `,{encoding:"utf8",mode:384,flag:"wx"})}catch(D){if(D.code==="ENOENT")return!1;throw await W0(),D}return await B.onStep?.("eviction-marker-acquired"),!0}async function W0(){if(await x())await w(N,{recursive:!0,force:!0}).catch(()=>{})}for(let D=0;D<8;D++){if(F=await Q(),F)break;if(await J0())return null;try{if(!await p0()){await v();continue}}catch(Y0){if(Y0.code!=="EEXIST")throw Y0;let j0;try{j0=await O0(N)}catch(A){if(A.code==="ENOENT"){await v();continue}throw A}if(j0.mtimeMs+5000>X())return null;await B.onStep?.("stale-marker-stat");let Q0=`${N}.${e()}`;try{await Q1(N,Q0)}catch(A){if(A.code==="ENOENT"){await v();continue}throw A}await B.onStep?.("stale-marker-claimed"),await w(Q0,{recursive:!0,force:!0}).catch(()=>{}),await v();continue}try{if(await J0())return null;if(!await x())return null;if(await B.onStep?.("stale-lock-confirmed"),!await x())return null;if(await w($,{recursive:!0,force:!0}).catch(()=>{}),!await x())return null;if(F=await Q(),!F)return null;if(!await x())return await w($,{recursive:!0,force:!0}).catch(()=>{}),F=!1,null;break}finally{await W0()}}}if(!F)return null;return V(),{release:async()=>{if(J=!0,K)H1(K),K=null;try{if((await W())?.ownerId!==G)return}catch{return}await w($,{recursive:!0,force:!0}).catch(()=>{})}}}import{createHash as C1,randomUUID as P1}from"node:crypto";import{homedir as I1}from"node:os";import{dirname as R1,join as s}from"node:path";import{setTimeout as y1}from"node:timers/promises";import{randomUUID as L1}from"node:crypto";import{mkdir as M1,rename as q1,rm as O1,writeFile as _1}from"node:fs/promises";import{dirname as U1}from"node:path";async function T(B,Z){await M1(U1(B),{recursive:!0});let $=`${B}.${L1()}.tmp`;await _1($,`${JSON.stringify(Z,null,2)}
91
+ `,{encoding:"utf8",mode:384});try{await q1($,B)}catch(z){throw await O1($,{force:!0}).catch(()=>{}),z}}import{readFile as h1}from"node:fs/promises";var U=y0("refresh"),_0=1e4,T1=50,T0="openai-auth.json",E1="openai-auth-state.json";function S1(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return s(process.env.XDG_CONFIG_HOME||s(I1(),".config"),"opencode")}function S(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||s(S1(),T0)}function n(B=S()){let Z=process.env.OPENCODE_OPENAI_AUTH_STATE_FILE?.trim();if(Z)return Z;return x1(B)}function x1(B){return B.endsWith(T0)?s(R1(B),E1):`${B}.state.json`}function C(B){return B.type==="oauth"}function A1(B){let Z=B?.trim();if(!Z)return!1;try{let $=new URL(Z);return($.protocol==="http:"||$.protocol==="https:")&&!$.username&&!$.password}catch{return!1}}function u3(B){return B.costZeroing?.enabled!==!1}var k1=[401,403,429],U0={primary:0,secondary:0},m1=!1,s3={primary:5,secondary:10};function j(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}function C0(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():P1(),label:typeof B.label==="string"?B.label:void 0,enabled:typeof B.enabled==="boolean"?B.enabled:void 0,addedAt:typeof B.addedAt==="number"?B.addedAt:void 0,lastUsed:typeof B.lastUsed==="number"?B.lastUsed:void 0,accountId:typeof B.accountId==="string"?B.accountId:void 0}}function P0(B){if(!j(B))return;if(typeof B.message!=="string")return;let Z=Number(B.checkedAt);if(!Number.isFinite(Z))return;let $=Number(B.nextRetryAt),z=Number(B.retryCount);return{message:B.message,checkedAt:Z,nextRetryAt:Number.isFinite($)?$:void 0,retryCount:Number.isFinite(z)?z:void 0,tokenHash:typeof B.tokenHash==="string"?B.tokenHash:void 0}}function f1(B){if(!j(B))return;let Z={};for(let $ of["primary","secondary"]){let z=B[$];if(!j(z))continue;let G=Number(z.usedPercent),X=Number(z.remainingPercent),K=Number(z.checkedAt);if(!Number.isFinite(G)||!Number.isFinite(X)||!Number.isFinite(K))continue;Z[$]={usedPercent:G,remainingPercent:X,checkedAt:K,resetsAt:typeof z.resetsAt==="string"?z.resetsAt:void 0}}return Object.keys(Z).length?Z:void 0}function w1(B){if(!j(B))return null;if(B.type==="api"){let Z=typeof B.baseURL==="string"?B.baseURL.trim():"",$=typeof B.apiKey==="string"?B.apiKey.trim():"";if(!A1(Z))return null;let z=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...C0(B),type:"api",apiKey:$||void 0,baseURL:Z,authHeader:z}}if(B.type!=="oauth")return null;if(typeof B.refresh!=="string"||!B.refresh.trim())return null;return{...C0(B),type:"oauth",access:typeof B.access==="string"?B.access:void 0,refresh:B.refresh,expires:typeof B.expires==="number"?B.expires:void 0,lastRefreshedAt:typeof B.lastRefreshedAt==="number"?B.lastRefreshedAt:void 0,lastRefreshError:P0(B.lastRefreshError),lastQuotaRefreshError:P0(B.lastQuotaRefreshError),quota:f1(B.quota)}}function E0(B){if(!j(B)||!Array.isArray(B.accounts))return null;return{version:1,main:{type:"opencode",provider:"openai"},routing:j(B.routing)?B.routing:void 0,fallbackOn:Array.isArray(B.fallbackOn)?B.fallbackOn.filter((Z)=>Number.isInteger(Z)):void 0,refresh:j(B.refresh)?B.refresh:void 0,quota:j(B.quota)?B.quota:void 0,dump:j(B.dump)?B.dump:void 0,costZeroing:j(B.costZeroing)?B.costZeroing:void 0,killswitch:j(B.killswitch)?B.killswitch:void 0,logging:j(B.logging)?B.logging:void 0,cachekeep:j(B.cachekeep)?B.cachekeep:void 0,mainAccountId:typeof B.mainAccountId==="string"?B.mainAccountId:void 0,accounts:B.accounts.map(w1).filter((Z)=>Z!=null)}}async function E(B){try{return{exists:!0,value:JSON.parse(await h1(B,"utf8"))}}catch(Z){if(Z.code==="ENOENT")return{exists:!1,value:null};throw Z}}function M(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function S0(B,Z){if(!j(B))return B;let $=j(Z)?Z:{},z=j($.main)?$.main:void 0,G=j($.accounts)?$.accounts:{},X=j(B.quota)?B.quota:{},K=j(B.refresh)?B.refresh:{},J=z??X,W=z??K,Q=Array.isArray(B.accounts)?B.accounts.map((V)=>{if(!j(V))return V;let F=typeof V.id==="string"&&j(G[V.id])?G[V.id]:{};return{...V,...F}}):void 0;return x0({...B,refresh:M({...K,mainLastRefreshError:W.lastRefreshError,mainRefreshLeaseId:W.refreshLeaseId,mainRefreshLeaseUntil:W.refreshLeaseUntil,mainRefreshLeaseTokenHash:W.refreshLeaseTokenHash}),quota:M({...X,mainQuota:J.quota,mainQuotaCheckedAt:J.quotaCheckedAt,mainQuotaToken:J.quotaToken,mainLastQuotaApiError:J.lastQuotaApiError}),accounts:Q})}async function p1(B=S()){let Z=await E(B);if(!Z.exists)return null;let $=await E(n(B));return E0(S0(Z.value,$.value))}function x0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function v1(B){return M({id:B.id,label:B.label,type:B.type,enabled:B.enabled,addedAt:B.addedAt,accountId:B.accountId,baseURL:B.type==="api"?B.baseURL:void 0,authHeader:B.type==="api"?B.authHeader:void 0})}function A0(B){if(B.type==="api")return M({apiKey:B.apiKey,lastUsed:B.lastUsed});return M({access:B.access,refresh:B.refresh,expires:B.expires,lastUsed:B.lastUsed,lastRefreshedAt:B.lastRefreshedAt,lastRefreshError:B.lastRefreshError,lastQuotaRefreshError:B.lastQuotaRefreshError,quota:B.quota})}function c(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function d1(B,Z){if(!j(B))return Z;let $=B,z=c($.quota),G=c(Z.quota);if(z>G){let K=Boolean($.access&&Z.access&&$.access!==Z.access),J=$.lastRefreshedAt??0,W=Z.lastRefreshedAt??0;if(K&&W<=J){let Y={...$};if(typeof Z.lastUsed==="number"&&(typeof $.lastUsed!=="number"||Z.lastUsed>$.lastUsed))Y.lastUsed=Z.lastUsed;return Y}return{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}}let X={...$,...Z};if(!("lastQuotaRefreshError"in Z))delete X.lastQuotaRefreshError;if(!("lastRefreshError"in Z))delete X.lastRefreshError;return X}function k0(B){let Z=B.refresh?M({enabled:B.refresh.enabled,intervalMinutes:B.refresh.intervalMinutes,refreshBeforeExpiryMinutes:B.refresh.refreshBeforeExpiryMinutes}):void 0,$=B.quota?M({enabled:B.quota.enabled,checkIntervalMinutes:B.quota.checkIntervalMinutes,refreshEveryNRequests:B.quota.refreshEveryNRequests,minimumRemaining:B.quota.minimumRemaining,failClosedOnUnknownQuota:B.quota.failClosedOnUnknownQuota,showToasts:B.quota.showToasts}):void 0;return x0({version:1,main:B.main,routing:B.routing,fallbackOn:B.fallbackOn,refresh:Z,quota:$,dump:B.dump,costZeroing:B.costZeroing,killswitch:B.killswitch,logging:B.logging,cachekeep:B.cachekeep,mainAccountId:B.mainAccountId,accounts:B.accounts.map(v1)})}function l1(B,Z){if(!B)return Z;let $=new Map;for(let z of B.accounts)$.set(z.id,z);for(let z of Z.accounts)$.set(z.id,z);return{...B,...Z,accounts:[...$.values()]}}async function X0(B){let Z=Date.now()+_0;while(Date.now()<=Z){let $=await u({name:"save",ttlMs:_0,path:B});if($)return $;let z=Z-Date.now();if(z<=0)break;await y1(Math.min(T1,z))}throw Error(`Timed out acquiring account store lock for ${B}; refusing to overwrite newer account data`)}function m0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,A0($)]));return{version:1,main:M({quota:B.quota?.mainQuota,quotaCheckedAt:B.quota?.mainQuotaCheckedAt,quotaToken:B.quota?.mainQuotaToken,lastQuotaApiError:B.quota?.mainLastQuotaApiError,lastRefreshError:B.refresh?.mainLastRefreshError,refreshLeaseId:B.refresh?.mainRefreshLeaseId,refreshLeaseUntil:B.refresh?.mainRefreshLeaseUntil,refreshLeaseTokenHash:B.refresh?.mainRefreshLeaseTokenHash}),accounts:Z}}async function n3(B,Z=S()){let $=n(Z),z=await X0(Z);try{let G=await X0($);try{let X=await E(Z),K=await E($),J=X.exists?E0(S0(X.value,K.value)):null,W=l1(J,B),Q={...j(X.value)?X.value:{},...k0(W)};await T(Z,Q),await T($,m0(W))}finally{await G.release()}}finally{await z.release()}}function g1(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:c(B.main.quota),z=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:c(Z.quota?.mainQuota);if($>z)return;B.main.quota=Z.quota?.mainQuota,B.main.quotaCheckedAt=Z.quota?.mainQuotaCheckedAt,B.main.quotaToken=Z.quota?.mainQuotaToken,B.main.lastQuotaApiError=Z.quota?.mainLastQuotaApiError}function i1(B,Z){B.main=B.main??{},B.main.lastRefreshError=Z.refresh?.mainLastRefreshError,B.main.refreshLeaseId=Z.refresh?.mainRefreshLeaseId,B.main.refreshLeaseUntil=Z.refresh?.mainRefreshLeaseUntil,B.main.refreshLeaseTokenHash=Z.refresh?.mainRefreshLeaseTokenHash}function G0(B){if(Array.isArray(B))return B.map(G0);if(!j(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,G0($)]))}async function u1(B,Z=S(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let z=n(Z),G=await X0(z);try{let X=(await E(z)).value,K=j(X)?{...X,version:1}:{version:1};if($.mainQuota)g1(K,B);if($.mainRefresh)i1(K,B);if($.accounts){let J=$.accounts===!0?null:new Set($.accounts);K.accounts={...j(K.accounts)?K.accounts:{}};for(let W of B.accounts){if(J&&!J.has(W.id))continue;K.accounts[W.id]=d1(K.accounts[W.id],A0(W))}if(J){for(let W of J)if(!B.accounts.some((Y)=>Y.id===W))delete K.accounts[W]}}await T(z,G0(K))}finally{await G.release()}}function s1(B){return B?.fallbackOn?.length?B.fallbackOn:k1}function r3(B,Z){return s1(Z).includes(B)}function c1(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??U0.primary,secondary:Z.secondary??Z["1w"]??U0.secondary}}function K0(B){return B?.quota?.enabled!==!1}function f0(B){return B?.quota?.failClosedOnUnknownQuota??m1}function w0(B,Z){if(!K0(Z))return!0;let $=c1(Z);for(let z of["primary","secondary"]){let G=B?.[z];if(!G)return!f0(Z);if(G.remainingPercent<$[z])return!1}return!0}function n1(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function a3(B,Z=S()){let $=await u({name:"migrate",ttlMs:30000,path:Z});if(!$)return;try{let z=await E(Z);if(z.exists&&j(z.value)){if(n1(z.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let J=R({id_token:"",access_token:B.access,refresh_token:B.refresh});if(J)G.mainAccountId=J}let K={...z.exists&&j(z.value)?z.value:{},...k0(G)};await T(Z,K),await T(n(Z),m0(G))}finally{await $.release()}}function r1(B){return B?.refresh?.enabled!==!1}function a1(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function o1(B){return Math.floor(Math.random()*(B+1))}function P(B,Z,$){return!B.access||!B.expires||B.expires-$<=a1(Z)}function b(B,Z){let $=B.accounts.findIndex((z)=>z.id===Z.id);if($!==-1)B.accounts[$]=Z}function $0(B){return B instanceof Error?B.message:String(B)}function h0(B,Z,$){B.lastRefreshError=V0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function z0(B,Z,$){if(B.lastQuotaRefreshError=H0({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)h0(B,Z,$)}function t1(B){return`fallback-oauth-refresh-${C1("sha256").update(B).digest("base64url").slice(0,16)}`}function I0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function e1(B,Z){if(!B)return!1;return I0(B[g],Z)||I0(B[i],Z)}function B3(B,Z,$){if(!B)return!1;let z=Z?.quota?.checkIntervalMinutes??5,G=Math.max(1,z)*60000,X=Math.max(B[g]?.checkedAt??0,B[i]?.checkedAt??0);return $-X<G}function R0(B,Z,$){return!B3(B.quota,Z,$)}function Z3(B,Z,$,z){return a($)&&w0(B.quota,Z)&&e1(B.quota,z)}function $3(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var z3=60000,X3=60000,G3=600000,K3=1e4,J3=100;var o3=globalThis.setTimeout.bind(globalThis),t3=globalThis.clearTimeout.bind(globalThis);class W3{now;fetchImpl;configPath;refreshPromises=new Map;refreshTimer=null;quotaTimer=null;quotaManager;onFallbackStorageChanged;options;constructor(B={}){this.options=B,this.now=B.now??Date.now,this.fetchImpl=B.fetchImpl??fetch,this.configPath=B.configPath??S(),this.quotaManager=B.quotaManager??null,this.onFallbackStorageChanged=B.onFallbackStorageChanged}seedFallbackQuota(B,Z){if(!this.quotaManager)return;if(!B.quota)return;let $=Math.max(B.quota[g]?.checkedAt??0,B.quota[i]?.checkedAt??0);if($<=0)return;let z=this.quotaManager.getFallback(B.id,B.access);if(z&&z.checkedAt>=$)return;this.quotaManager.setFallback(B.id,{quota:B.quota,refreshAfter:$+$3(Z),checkedAt:$},B.access)}async load(){return p1(this.configPath)}async save(B,Z){await u1(B,this.configPath,{accounts:Z??!0})}startBackgroundRefresh(){let B=async()=>{if(await this.refreshDueAccounts(),this.options.fetchQuotaFn)await this.refreshQuotaForDueAccounts()};if(B().catch(()=>{}),!this.refreshTimer){if(this.refreshTimer=setInterval(()=>{B().catch(()=>{})},z3+o1(X3)),"unref"in this.refreshTimer)this.refreshTimer.unref()}}stopBackgroundRefresh(){if(this.refreshTimer)clearInterval(this.refreshTimer);if(this.quotaTimer)clearInterval(this.quotaTimer);this.refreshTimer=null,this.quotaTimer=null}async getUsableFallbackAccounts(B){let Z=B!==void 0?B:await this.load();if(!Z)return[];let $=[],z=!1;for(let G of Z.accounts){if(G.enabled===!1||!C(G))continue;try{let X=G;if(P(X,Z,this.now())){let K=X.lastRefreshError;if(K&&I(K,X.refresh,this.now()))throw Error(d(K,this.now()));X=await this.refreshAccount(X,Z),z=!0}if(this.seedFallbackQuota(X,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(X),Z))$.push(X)}catch(X){if(Z3(G,Z,X,this.now()))U.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:$0(X)}),$.push(G);else if(!f0(Z))$.push(G)}}if(z)await this.save(Z);return $}async markUsed(B){let Z=await this.load();if(!Z)return;let $=Z.accounts.find((z)=>z.id===B.id);if(!$)return;$.lastUsed=this.now(),await this.save(Z)}accountPassesQuotaPolicy(B,Z){return w0(B.quota,Z)}quotaPolicyAccount(B){if(!this.quotaManager)return B;let Z=this.quotaManager.getFallback(B.id,B.access)?.quota;return Z?{...B,quota:Z}:B}async refreshDueAccounts(){let B=await this.load();if(!B||!r1(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!C($))continue;if(!P($,B,this.now()))continue;if(I($.lastRefreshError,$.refresh,this.now()))continue;try{U.debug("fallback oauth background due",{pid:process.pid,accountId:$.id,expiresInMs:$.expires?$.expires-this.now():void 0}),await this.refreshAccount($,B),Z=!0}catch(z){U.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:$0(z)}),h0($,z,this.now()),b(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!K0(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!C($))continue;let z=$;try{if(P(z,B,this.now())){if(I(z.lastRefreshError,z.refresh,this.now()))continue;z=await this.refreshAccount(z,B),Z=!0}if(b0(z.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota(z,B),!(this.quotaManager?this.quotaManager.isFallbackStale(z.id,z.access):R0(z,B,this.now())))continue;await this.refreshAccountQuota(z,B),Z=!0}catch(G){z0($,G,this.now()),b(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!K0(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let z=B.force??!1,G=!1;for(let X of Z.accounts){if(X.enabled===!1||!C(X))continue;let K=X;try{if(P(K,Z,this.now())){let J=K.lastRefreshError;if(J&&I(J,K.refresh,this.now()))throw Error(d(J,this.now()));K=await this.refreshAccount(K,Z),G=!0}if(!z&&!R0(K,Z,this.now())){if(K.lastQuotaRefreshError)K.lastQuotaRefreshError=void 0,b(Z,K),G=!0;continue}await this.refreshAccountQuota(K,Z),G=!0}catch(J){z0(X,J,this.now()),b(Z,X),G=!0,$.push({accountId:X.id,message:$0(J)})}}if(G)await this.save(Z);return{storage:Z,errors:$}}async refreshAccount(B,Z,$={}){let z=this.refreshPromises.get(B.id);if(z){let K=await z;return b(Z,K),K}let G=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,G);let X=await G;return b(Z,X),X}async waitForConcurrentFallbackRefresh(B,Z,$,z){let G=Date.now()+K3;while(Date.now()<G){await new Promise((Y)=>setTimeout(Y,J3));let X=await this.load(),K=X?.accounts.find((Y)=>Y.id===B.id&&C(Y));if(!K)continue;if((K.access!==$.access||K.refresh!==$.refresh||(K.expires??0)>($.expires??0)+60000)&&(z.force||!P(K,X,this.now())))return b(Z,K),U.debug("fallback oauth joined concurrent refresh",{pid:process.pid,accountId:K.id,expiresInMs:K.expires?K.expires-this.now():void 0}),K;let W=K.lastRefreshError;if(W&&I(W,K.refresh,this.now()))throw b(Z,K),Error(d(W,this.now()))}return null}async refreshAccountNow(B,Z,$){let z=await this.load(),G=z?.accounts.find((J)=>J.id===B.id&&C(J));if(G&&!$.force&&!P(G,z,this.now()))return b(Z,G),G;let X=G??B,K=await u({name:t1(X.id),ttlMs:G3,path:this.configPath,now:this.now,renew:!0});if(!K){U.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:X.id});let J=await this.waitForConcurrentFallbackRefresh(B,Z,X,$);if(J)return J;throw Error("Fallback OAuth refresh is already in progress")}try{if(z=await this.load(),G=z?.accounts.find((Y)=>Y.id===B.id&&C(Y)),G&&!$.force&&!P(G,z,this.now()))return b(Z,G),G;X=G??X;let J=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});U.debug("fallback oauth refresh request start",{pid:process.pid,accountId:X.id,force:$.force===!0,expiresInMs:X.expires?X.expires-this.now():void 0});let W=await J({refreshToken:X.refresh,fetchImpl:this.fetchImpl,now:this.now});return X.access=W.access,X.refresh=W.refresh,X.expires=W.expires,X.lastRefreshedAt=W.expires-W.expiresIn*1000,X.lastRefreshError=void 0,b(Z,X),await this.save(Z),U.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:X.id,expiresInMs:X.expires?X.expires-this.now():void 0}),X}finally{await K.release()}}async refreshAccountQuota(B,Z){let $=B;if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);if(!this.options.fetchQuotaFn)throw Error("No fetchQuotaFn injected — wham/usage supplement is disabled");let z=this.options.fetchQuotaFn??(async()=>{throw Error("No fetchQuotaFn injected — wham/usage supplement is disabled")}),G=(X)=>this.quotaManager?this.quotaManager.refreshFallback($.id,X):z({accessToken:X,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let X=await G($.access);$.quota=X,$.lastQuotaRefreshError=void 0,b(Z,$),await this.save(Z)}catch(X){throw z0(B,X,this.now()),b(Z,B),X}}}
92
+ export{N0 as g,V0 as h,I as i,d as j,H0 as k,b0 as l,M0 as m,q0 as n,o0 as o,D0 as p,L0 as q,R as r,t0 as s,y as t,$1 as u,z1 as v,X1 as w,G1 as x,L3 as y,M3 as z,_3 as A,U3 as B,u as C,S as D,C as E,u3 as F,s3 as G,p1 as H,n3 as I,r3 as J,a3 as K,W3 as L};
@@ -0,0 +1,2 @@
1
+ function A(b){if(b==null||b==="")return;let g=typeof b==="number"?b:Number(b);if(Number.isFinite(g)){let z=g<100000000000?g*1000:g,B=new Date(z);return Number.isNaN(B.getTime())?void 0:B.toISOString()}let q=new Date(b);return Number.isNaN(q.getTime())?void 0:q.toISOString()}function C(b,g){let q=b.get(g);if(q===null)return;let z=Number(q);if(!Number.isFinite(z))return;return{usedPercent:z,remainingPercent:100-z,resetsAt:A(b.get(`${g.slice(0,-13)}-reset-at`)??void 0),checkedAt:Date.now()}}function G(b){let g={},q=C(b,"x-codex-primary-used-percent");if(q)g.primary=q;let z=C(b,"x-codex-secondary-used-percent");if(z)g.secondary=z;return g}function D(b){if(!b)return;if(!Number.isFinite(b.used_percent))return;return{usedPercent:b.used_percent,remainingPercent:100-b.used_percent,resetsAt:A(b.reset_at),checkedAt:Date.now()}}function J(b){let g={},q=D(b.rate_limits?.primary);if(q)g.primary=q;let z=D(b.rate_limits?.secondary);if(z)g.secondary=z;return g}function E(b){if(!b)return;if(!Number.isFinite(b.used_percent))return;return{usedPercent:b.used_percent,remainingPercent:100-b.used_percent,resetsAt:A(b.reset_at),checkedAt:Date.now()}}function K(b){let g={},q=E(b.rate_limit?.primary_window);if(q)g.primary=q;let z=E(b.rate_limit?.secondary_window);if(z)g.secondary=z;return g}
2
+ export{A as c,G as d,J as e,K as f};
package/dist/index.d.ts CHANGED
@@ -1,28 +1,12 @@
1
1
  import type { Hooks, Plugin, PluginInput } from '@opencode-ai/plugin';
2
- export interface IdTokenClaims {
3
- chatgpt_account_id?: string;
4
- organizations?: Array<{
5
- id: string;
6
- }>;
7
- email?: string;
8
- 'https://api.openai.com/auth'?: {
9
- chatgpt_account_id?: string;
10
- };
11
- }
12
- export declare function parseJwtClaims(token: string): IdTokenClaims | undefined;
13
- export declare function extractAccountIdFromClaims(claims: IdTokenClaims): string | undefined;
14
- export declare function extractAccountId(tokens: TokenResponse): string | undefined;
15
- interface TokenResponse {
16
- id_token: string;
17
- access_token: string;
18
- refresh_token: string;
19
- expires_in?: number;
20
- }
2
+ import { type FallbackAccount, type OAuthAccount } from './core/accounts';
3
+ export { extractAccountIdFromClaims, type IdTokenClaims, parseJwtClaims, } from './core/oauth';
21
4
  interface CodexAuthPluginOptions {
22
5
  issuer?: string;
23
6
  codexApiEndpoint?: string;
24
7
  experimentalWebSockets?: boolean;
25
8
  }
9
+ export declare function findCachekeepFallbackAccount(accounts: FallbackAccount[], accountId: string): OAuthAccount | undefined;
26
10
  export declare function CodexAuthPlugin(input: PluginInput, options?: CodexAuthPluginOptions): Promise<Hooks>;
27
11
  export declare const OpenAIAuthPlugin: Plugin;
28
12
  declare const _default: {