@cortexkit/opencode-openai-auth 0.3.3 → 0.3.4

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/dist/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import{F as q,J as B,K as V,q as Y,x as Z,y as $}from"./index-phrx93zy.js";import"./index-qdh7pt5a.js";import{ka as X}from"./index-e7m7qbne.js";import{execFileSync as E}from"node:child_process";function Q(C,H=process.platform,D=E){try{if(H==="win32"){D("cmd",["/c","start","",C],{stdio:"ignore",timeout:3000});return}D(H==="darwin"?"open":"xdg-open",[C],{stdio:"ignore",timeout:3000})}catch{}}function T(){console.log(`Usage:
2
+ import{F as q,J as B,K as V,q as Y,x as Z,y as $}from"./index-y8d01tgn.js";import"./index-qdh7pt5a.js";import{ka as X}from"./index-e7m7qbne.js";import{execFileSync as E}from"node:child_process";function Q(C,H=process.platform,D=E){try{if(H==="win32"){D("cmd",["/c","start","",C],{stdio:"ignore",timeout:3000});return}D(H==="darwin"?"open":"xdg-open",[C],{stdio:"ignore",timeout:3000})}catch{}}function T(){console.log(`Usage:
3
3
  npx @cortexkit/opencode-openai-auth login [--label <name>] [--headless]
4
4
  npx @cortexkit/opencode-openai-auth list
5
5
  npx @cortexkit/opencode-openai-auth remove <id>
@@ -2,7 +2,7 @@ export declare const CLIENT_ID = "app_EMoamEEZ73f0CkXaXp7hrann";
2
2
  export declare const ISSUER = "https://auth.openai.com";
3
3
  export declare const OAUTH_PORT = 1455;
4
4
  export declare const OAUTH_POLLING_SAFETY_MARGIN_MS = 3000;
5
- export declare const USER_AGENT = "cortexkit-opencode-openai-auth/0.3.3";
5
+ export declare const USER_AGENT = "cortexkit-opencode-openai-auth/0.3.4";
6
6
  export declare const RESERVED_ACCOUNT_ID = "main";
7
7
  export declare const RESERVED_ACCOUNT_ID_ERROR = "\"main\" is a reserved account id; choose a different label.";
8
8
  export interface PkceCodes {
@@ -1,4 +1,4 @@
1
- import{ca as g3}from"./index-qdh7pt5a.js";import{ka as U0}from"./index-e7m7qbne.js";import{createHash as e3}from"node:crypto";var B0=86400000,Z0=300000,$0=3600000,z0=60000,W0=900000,X0=300000;function W3(B){return B instanceof Error?B.message:String(B)}function G0(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 X3(B){let Z=W3(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 C3(B){return e3("sha256").update(B).digest("hex")}function S3(B){let Z=C3(B.refreshToken),z=(B.previous?.tokenHash===Z?B.previous.retryCount??0:0)+1,X,W=B.error?.retryAfter;if(typeof W==="number"&&W>0)X=W*1000;else if(G0(B.error))X=Math.min($0,Z0*2**Math.min(z-1,6));else X=B0;return{message:W3(B.error),checkedAt:B.now,nextRetryAt:B.now+X,retryCount:z,tokenHash:Z}}function q(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===C3(Z)}function a(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 l(B){let $=(B.previous?.retryCount??0)+1,z,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)z=X*1000;else if(X3(B.error))z=Math.min(W0,z0*2**Math.min($-1,6));else z=X0;return{message:W3(B.error),checkedAt:B.now,nextRetryAt:B.now+z,retryCount:$}}function I(B,Z){if(!B?.nextRetryAt||B.nextRetryAt<=Z)return!1;return!0}function G3(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 K0}from"node:http";import{setTimeout as Y0}from"node:timers/promises";var R3="0.3.3";var e="app_EMoamEEZ73f0CkXaXp7hrann",R="https://auth.openai.com",d=1455,J0=3000,x3=`cortexkit-opencode-openai-auth/${R3}`,A3="main",H0=`"${A3}" is a reserved account id; choose a different label.`;function I3(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function j0(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((z)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[z%66]).join(""),$=I3(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(Z)));return{verifier:Z,challenge:$}}function E3(B){if(B.length>16384)return;let Z=B.split(".");if(Z.length!==3)return;let $=Z[1];if(!$||$.length>8192)return;try{return JSON.parse(Buffer.from($,"base64url").toString())}catch{return}}function y3(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 X=z[0];if(X&&typeof X==="object"&&!Array.isArray(X)&&typeof X.id==="string"&&X.id.length>0)return X.id}return}function t(B){if(B.id_token){let Z=E3(B.id_token),$=Z&&y3(Z);if($)return $}if(B.access_token){let Z=E3(B.access_token);return Z?y3(Z):void 0}return}function Q0(B){return typeof B==="string"&&B.toLowerCase()===A3}function K3(B){if(Q0(B))throw Error(H0);return B}function V0(B,Z,$){let z=new URLSearchParams({response_type:"code",client_id:e,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`${R}/oauth/authorize?${z.toString()}`}async function N0(B,Z,$){let z=await fetch(`${R}/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:e,code_verifier:$.verifier}).toString()});if(!z.ok)throw Error(`Token exchange failed: ${z.status}`);return await z.json()}function L0(B){return B.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}var b0=`<!doctype html>
1
+ import{ca as g0}from"./index-qdh7pt5a.js";import{ka as U3}from"./index-e7m7qbne.js";import{createHash as e0}from"node:crypto";var B3=86400000,Z3=300000,$3=3600000,z3=60000,W3=900000,X3=300000;function W0(B){return B instanceof Error?B.message:String(B)}function G3(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 X0(B){let Z=W0(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 C0(B){return e0("sha256").update(B).digest("hex")}function S0(B){let Z=C0(B.refreshToken),z=(B.previous?.tokenHash===Z?B.previous.retryCount??0:0)+1,X,W=B.error?.retryAfter;if(typeof W==="number"&&W>0)X=W*1000;else if(G3(B.error))X=Math.min($3,Z3*2**Math.min(z-1,6));else X=B3;return{message:W0(B.error),checkedAt:B.now,nextRetryAt:B.now+X,retryCount:z,tokenHash:Z}}function q(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===C0(Z)}function a(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 l(B){let $=(B.previous?.retryCount??0)+1,z,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)z=X*1000;else if(X0(B.error))z=Math.min(W3,z3*2**Math.min($-1,6));else z=X3;return{message:W0(B.error),checkedAt:B.now,nextRetryAt:B.now+z,retryCount:$}}function I(B,Z){if(!B?.nextRetryAt||B.nextRetryAt<=Z)return!1;return!0}function G0(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 K3}from"node:http";import{setTimeout as Y3}from"node:timers/promises";var R0="0.3.4";var e="app_EMoamEEZ73f0CkXaXp7hrann",R="https://auth.openai.com",d=1455,J3=3000,x0=`cortexkit-opencode-openai-auth/${R0}`,A0="main",H3=`"${A0}" is a reserved account id; choose a different label.`;function I0(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function j3(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((z)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[z%66]).join(""),$=I0(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(Z)));return{verifier:Z,challenge:$}}function E0(B){if(B.length>16384)return;let Z=B.split(".");if(Z.length!==3)return;let $=Z[1];if(!$||$.length>8192)return;try{return JSON.parse(Buffer.from($,"base64url").toString())}catch{return}}function y0(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 X=z[0];if(X&&typeof X==="object"&&!Array.isArray(X)&&typeof X.id==="string"&&X.id.length>0)return X.id}return}function t(B){if(B.id_token){let Z=E0(B.id_token),$=Z&&y0(Z);if($)return $}if(B.access_token){let Z=E0(B.access_token);return Z?y0(Z):void 0}return}function Q3(B){return typeof B==="string"&&B.toLowerCase()===A0}function K0(B){if(Q3(B))throw Error(H3);return B}function V3(B,Z,$){let z=new URLSearchParams({response_type:"code",client_id:e,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`${R}/oauth/authorize?${z.toString()}`}async function N3(B,Z,$){let z=await fetch(`${R}/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:e,code_verifier:$.verifier}).toString()});if(!z.ok)throw Error(`Token exchange failed: ${z.status}`);return await z.json()}function L3(B){return B.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}var b3=`<!doctype html>
2
2
  <html>
3
3
  <head>
4
4
  <title>CortexKit OpenAI Auth - Authorization Successful</title>
@@ -81,12 +81,12 @@ import{ca as g3}from"./index-qdh7pt5a.js";import{ka as U0}from"./index-e7m7qbne.
81
81
  <div class="container">
82
82
  <h1>Authorization Failed</h1>
83
83
  <p>An error occurred during authorization.</p>
84
- <div class="error">${L0(B)}</div>
84
+ <div class="error">${L3(B)}</div>
85
85
  </div>
86
86
  </body>
87
- </html>`,i,g,O=new Map;function C(){return O.size}function E(B){if(O.delete(B),C()===0)S()}async function F0(){let B=`http://localhost:${d}/auth/callback`;if(i)return{port:d,redirectUri:B};if(g)return g;g=(async()=>{let Z=K0(($,z)=>{let X=new URL($.url||"/",`http://127.0.0.1:${d}`);if(X.pathname==="/auth/callback"){let W=X.searchParams.get("code"),G=X.searchParams.get("state"),K=X.searchParams.get("error"),Y=X.searchParams.get("error_description");if(K){let H=Y||K;if(G){let V=O.get(G);if(V)V.reject(Error(H)),E(G);else if(C()===0)S()}else if(C()===0)S();z.writeHead(200,{"Content-Type":"text/html"}),z.end(o(H));return}if(!G){if(C()===0)S();z.writeHead(400,{"Content-Type":"text/html"}),z.end(o("Missing state parameter"));return}if(!W){if(C()===0)S();z.writeHead(400,{"Content-Type":"text/html"}),z.end(o("Missing authorization code"));return}let J=O.get(G);if(!J){if(C()===0)S();z.writeHead(400,{"Content-Type":"text/html"}),z.end(o("Unknown state — authorization may have expired"));return}E(G),N0(W,B,J.pkce).then((H)=>J.resolve(H)).catch((H)=>J.reject(H)),z.writeHead(200,{"Content-Type":"text/html"}),z.end(b0);return}if(X.pathname==="/cancel"){let W=X.searchParams.get("state"),G=W?[W]:[...O.keys()];z.writeHead(200),z.end("Login cancelled");for(let K of G){let Y=O.get(K);if(!Y)continue;Y.reject(Error("Login cancelled")),E(K)}if(C()===0)S();return}z.writeHead(404),z.end("Not found")});return await new Promise(($,z)=>{Z.once("error",z),Z.listen(d,"127.0.0.1",()=>{Z.off("error",z),$()})}),i=Z,{port:d,redirectUri:B}})();try{return await g}finally{g=void 0}}function S(){if(i){let B=i;i=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function D0(B,Z,$=300000,z){return new Promise((X,W)=>{if(z?.aborted){E(Z),W(Error("Login cancelled"));return}let G=setTimeout(()=>{if(O.get(Z))E(Z),W(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),O.get(Z))E(Z),W(Error("Login cancelled"))};if(z)z.addEventListener("abort",K);O.set(Z,{pkce:B,state:Z,resolve:(Y)=>{if(clearTimeout(G),z)z.removeEventListener("abort",K);X(Y)},reject:(Y)=>{if(clearTimeout(G),z)z.removeEventListener("abort",K);W(Y)}})})}async function O0(){let B=await fetch(`${R}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":x3},body:JSON.stringify({client_id:e})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${R}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function P0(B,Z){let $=Math.max(parseInt(B.interval,10)||5,1)*1000,z=typeof B.expires_in==="number"?B.expires_in:parseInt(B.expires_in||"",10),X=!Number.isNaN(z)&&z>0?z*1000:900000,W=Date.now();while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");if(Date.now()-W>X)throw Error("Device authorization expired");let G=await fetch(`${R}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":x3},body:JSON.stringify({device_auth_id:B.device_auth_id,user_code:B.user_code})});if(G.ok){let J=await G.json(),H=await fetch(`${R}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:J.authorization_code,redirect_uri:`${R}/deviceauth/callback`,client_id:e,code_verifier:J.code_verifier}).toString()});if(!H.ok)throw Error(`Token exchange failed: ${H.status}`);return await H.json()}if(G.status!==403&&G.status!==404)throw Error(`Device authorization failed: ${G.status}`);let K=X-(Date.now()-W);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+J0,K);try{await Y0(Y,void 0,{signal:Z})}catch(J){if(J instanceof Error&&J.name==="AbortError")throw Error("Device authorization cancelled");throw J}}}function aB(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 oB(B={}){let{label:Z,headless:$=!1,signal:z}=B;if(K3(Z),$){let{deviceData:J,url:H,instructions:V}=await O0(),F=(async()=>{let Q=await P0(J,z),N=Date.now(),_=t(Q);return{id:K3(Z||_||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:Q.access_token,refresh:Q.refresh_token,expires:N+(Q.expires_in??3600)*1000,enabled:!0,addedAt:N,lastUsed:N,lastRefreshedAt:N,accountId:_}})();return{url:H,instructions:V,completion:F}}let{redirectUri:X}=await F0(),W=await j0(),G=I3(crypto.getRandomValues(new Uint8Array(32)).buffer),K=V0(X,W,G),Y=(async()=>{try{if(z?.aborted)throw Error("Login cancelled");let J=await D0(W,G,void 0,z),H=Date.now(),V=t(J);return{id:K3(Z||V||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:J.access_token,refresh:J.refresh_token,expires:H+(J.expires_in??3600)*1000,enabled:!0,addedAt:H,lastUsed:H,lastRefreshedAt:H,accountId:V}}finally{E(G)}})();return{url:K,instructions:"Complete authorization in your browser. This window will close automatically.",completion:Y}}var T="primary",f="secondary",M0="app_EMoamEEZ73f0CkXaXp7hrann",_0="https://auth.openai.com";async function BZ(B){let Z=await B.fetchImpl(`${_0}/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:M0}).toString()});if(!Z.ok){let z=G3(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();if(!$||typeof $.access_token!=="string"||!$.access_token||typeof $.refresh_token!=="string"||!$.refresh_token||typeof $.expires_in!=="number")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});return{access:$.access_token,refresh:$.refresh_token,expires:B.now()+$.expires_in*1000,expiresIn:$.expires_in}}var q0="https://chatgpt.com/backend-api/wham/usage";async function ZZ(B){let Z=await B.fetchImpl(q0,{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=G3(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-dfdpwwm3.js");return $(await Z.json())}import{randomUUID as Y3}from"node:crypto";import{mkdir as C0,readFile as J3,rename as S0,rm as u,stat as T3,writeFile as H3}from"node:fs/promises";import{homedir as R0}from"node:os";import{dirname as KZ,join as s}from"node:path";var E0=globalThis.setTimeout.bind(globalThis),y0=globalThis.clearTimeout.bind(globalThis),x0="openai-auth.json";function A0(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return s(process.env.XDG_CONFIG_HOME||s(R0(),".config"),"opencode")}function I0(B){let Z=B?.code;return Z==="ENOENT"||Z==="EINVAL"||Z==="ENOTDIR"}function T0(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||s(A0(),x0)}async function m(B){let $=`${B.path??T0()}.${B.name}.lock`,z=s($,"owner.json"),X=Y3(),W=B.now??Date.now,G=null,K=!1;async function Y(){try{return JSON.parse(await J3($,"utf8"))}catch(Q){if(Q.code!=="EISDIR")throw Q;return JSON.parse(await J3(z,"utf8"))}}async function J(){await H3($,`${JSON.stringify({ownerId:X,expiresAt:W()+B.ttlMs})}
88
- `,{encoding:"utf8",mode:384})}async function H(){try{return await H3($,`${JSON.stringify({ownerId:X,expiresAt:W()+B.ttlMs})}
89
- `,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(Q){let N=Q.code;if(N==="EEXIST"||N==="EISDIR")return!1;throw Q}}function V(){if(!B.renew||K)return;let Q=B.renewIntervalMs??Math.max(1000,Math.floor(B.ttlMs/3));if(G=E0(()=>{(async()=>{try{let N=await Y(),_=W();if(K||N?.ownerId!==X||Number(N?.expiresAt)<=_)return;await J(),V()}catch{}})()},Q),"unref"in G)G.unref()}let F=await H();if(!F){let Q=`${$}.evicting`,N=s(Q,"owner.json"),_=Y3(),lB=5000,dB=8;async function c(){await new Promise((D)=>setTimeout(D,Math.floor(Math.random()*4)))}async function P3(){try{let D=await Y();return Number(D?.expiresAt)>W()}catch{try{return(await T3($)).mtimeMs+B.ttlMs>W()}catch{return!1}}}async function v(){try{return JSON.parse(await J3(N,"utf8"))?.ownerId===_}catch{return!1}}async function t3(){await C0(Q);try{await H3(N,`${JSON.stringify({ownerId:_,createdAt:W()})}
90
- `,{encoding:"utf8",mode:384,flag:"wx"})}catch(D){if(I0(D))return!1;throw await U3(),D}return await B.onStep?.("eviction-marker-acquired"),!0}async function U3(){if(await v())await u(Q,{recursive:!0,force:!0}).catch(()=>{})}for(let D=0;D<8;D++){if(F=await H(),F)break;if(await P3())return null;try{if(!await t3()){await c();continue}}catch(M3){if(M3.code!=="EEXIST")throw M3;let _3;try{_3=await T3(Q)}catch(p){if(p.code==="ENOENT"){await c();continue}throw p}if(_3.mtimeMs+5000>W())return null;await B.onStep?.("stale-marker-stat");let q3=`${Q}.${Y3()}`;try{await S0(Q,q3)}catch(p){if(p.code==="ENOENT"){await c();continue}throw p}await B.onStep?.("stale-marker-claimed"),await u(q3,{recursive:!0,force:!0}).catch(()=>{}),await c();continue}try{if(await P3())return null;if(!await v())return null;if(await B.onStep?.("stale-lock-confirmed"),!await v())return null;if(await u($,{recursive:!0,force:!0}).catch(()=>{}),!await v())return null;if(F=await H(),!F)return null;if(!await v())return await u($,{recursive:!0,force:!0}).catch(()=>{}),F=!1,null;break}finally{await U3()}}}if(!F)return null;return V(),{release:async()=>{if(K=!0,G)y0(G),G=null;try{if((await Y())?.ownerId!==X)return}catch{return}await u($,{recursive:!0,force:!0}).catch(()=>{})}}}import{createHash as f0}from"node:crypto";var m0=globalThis.setTimeout,w0=5;function w(B){let Z=B?.quota?.checkIntervalMinutes??w0;return Math.max(1,Z)*60000}function k0(B){return B?.quota?.enabled!==!1}function Q3(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function VZ(B,Z,$,z){let X=Z===T?B?.primary:Z===f?B?.secondary:void 0,W=X?.resetsAt?Date.parse(X.resetsAt):NaN;if(Number.isFinite(W)&&W>$)return W;return $+z}function h0(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function f3(B,Z,$){if(!k0(Z))return $+w(Z);let z=h0(Z),X=[];for(let W of["primary","secondary"]){let G=B?.[W];if(!G)return $+w(Z);if(G.remainingPercent>=z[W])continue;let K=G.resetsAt?Date.parse(G.resetsAt):Number.NaN;if(!Number.isFinite(K)||K<=$)return $+w(Z);X.push(K)}if(!X.length)return $+w(Z);return Math.min(...X)+60000}function v0(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function p0(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function b(B){return f0("sha256").update(B).digest("hex").slice(0,16)}class P{main=null;mainTokenFp=null;mainQuotaAccountId=null;fallbacks=new Map;fallbackTokenFps=new Map;inflightMain=null;inflightMainFp=null;inflightFallbacks=new Map;mainLastApiError=void 0;fallbackApiErrors=new Map;fallbackErrorTokenFps=new Map;rateLimitedUntilMap=new Map;apiGate=Promise.resolve();lastApiCallAt=0;storage;fetchImpl;now;fetchQuotaFn;onMainQuotaFetched;onApiError;constructor(B){this.storage=B.storage,this.fetchImpl=B.fetchImpl??fetch,this.now=B.now??Date.now,this.fetchQuotaFn=B.fetchQuotaFn,this.onMainQuotaFetched=B.onMainQuotaFetched,this.onApiError=B.onApiError,this.seedMainFromStorage(B.storage),this.seedMainBackoffFromStorage(B.storage)}getMain(B){if(B&&this.main&&this.mainTokenFp&&this.mainTokenFp!==b(B))this.main=null,this.mainTokenFp=null;return this.main}getFallback(B,Z){let $=this.fallbacks.get(B)??null;if(!Z||!$)return $;if(this.fallbackTokenFps.get(B)!==b(Z))return this.fallbacks.delete(B),this.fallbackTokenFps.delete(B),null;return $}getAllFallbacks(){return this.fallbacks}setMain(B,Z,$){if(!m3(Z.quota))return;if(this.mainTokenFp=b(B),$&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==$)this.clearRateLimited("main");if($)this.mainQuotaAccountId=$;if(this.main=Z,j3(Z.quota))this.clearRateLimited("main")}peekMainForPolicy(B){if(B&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==B)return null;return this.main}peekFallbackForPolicy(B){return this.fallbacks.get(B)??null}setFallback(B,Z,$){if(!m3(Z.quota))return;if(this.fallbacks.set(B,Z),$)this.fallbackTokenFps.set(B,b($));else this.fallbackTokenFps.delete(B);if(j3(Z.quota))this.clearRateLimited(B)}markRateLimited(B,Z){let $=this.rateLimitedUntilMap.get(B);if($!==void 0&&$>Z)return;this.rateLimitedUntilMap.set(B,Z)}isRateLimited(B){let Z=this.rateLimitedUntilMap.get(B);return Z!==void 0&&this.now()<Z}rateLimitedUntil(B){return this.rateLimitedUntilMap.get(B)}clearRateLimited(B){this.rateLimitedUntilMap.delete(B)}async refreshMain(B){let Z=b(B);if(this.mainTokenFp&&this.mainTokenFp!==Z)this.main=null,this.mainTokenFp=null;if(this.inflightMain&&this.inflightMainFp===Z)return this.inflightMain;if(this.isBackedOff()){if(this.main)return this.main.quota;throw Error("Quota API rate-limited — try again later")}return this.inflightMainFp=Z,this.inflightMain=this._fetchMain(B),this.inflightMain}async refreshFallback(B,Z){let $=P.fallbackInflightKey(B,Z),z=this.inflightFallbacks.get($);if(z)return z;if(this.isFallbackBackedOff(B,Z)){let W=this.getFallback(B,Z);if(W)return W.quota;throw Error("Quota API rate-limited — try again later")}let X=this._fetchFallback(B,Z);return this.inflightFallbacks.set($,X),X}async refreshAllFallbacks(B){let Z=this.now();for(let $ of B){if($.enabled===!1)continue;if(!$.access)continue;let z=this.getFallback($.id,$.access);if(z&&Z<z.refreshAfter)continue;try{await this.refreshFallback($.id,$.access)}catch{}}}refreshMainInBackground(B){let Z=b(B);if(this.inflightMain&&this.inflightMainFp===Z)return;if(this.isBackedOff())return;this.refreshMain(B).catch(()=>{})}isMainStale(){if(!this.main)return!0;return this.now()>=this.main.refreshAfter}isFallbackStale(B,Z){let $=this.getFallback(B,Z);if(!$)return!0;return this.now()>=$.refreshAfter}shouldRefreshOnRequestCount(B){let Z=p0(this.storage);if(Z<=0)return!1;return B>0&&B%Z===0}needsRefresh(B){return this.isMainStale()||this.shouldRefreshOnRequestCount(B)}updateStorage(B){this.storage=B,this.seedMainFromStorage(B),this.seedMainBackoffFromStorage(B)}seedMainFromStorage(B,Z){let $=v0(B);if(!$)return;let z=Z?b(Z):null;if(z&&$.tokenFingerprint&&$.tokenFingerprint!==z)return;let X={quota:$.quota,refreshAfter:f3($.quota,B,$.checkedAt),checkedAt:$.checkedAt};if(this.main&&this.main.checkedAt>=X.checkedAt&&(!z||!this.mainTokenFp||this.mainTokenFp===z))return;if(this.main=X,this.mainTokenFp=$.tokenFingerprint??null,B?.mainAccountId){if(this.mainQuotaAccountId&&this.mainQuotaAccountId!==B.mainAccountId)this.clearRateLimited("main");this.mainQuotaAccountId=B.mainAccountId}}seedMainBackoffFromStorage(B){let Z=B?.quota?.mainLastQuotaApiError;this.mainLastApiError=Z&&I(Z,this.now())?Z:void 0}seedFallbacksFromAccounts(B){let Z=w(this.storage);for(let $ of B){if($.enabled===!1)continue;if(!$.quota)continue;let z=Math.max($.quota.primary?.checkedAt??0,$.quota.secondary?.checkedAt??0);if(z<=0)continue;let X=this.getFallback($.id,$.access);if(X&&X.checkedAt>=z)continue;this.setFallback($.id,{quota:$.quota,refreshAfter:z+Z,checkedAt:z},$.access)}}isBackedOff(){return I(this.mainLastApiError,this.now())}isFallbackBackedOff(B,Z){if(Z){if(this.fallbackErrorTokenFps.get(B)!==b(Z))return!1}return I(this.fallbackApiErrors.get(B),this.now())}getLastApiError(){return this.mainLastApiError}static API_CALL_GAP_MS=1000;static fallbackInflightKey(B,Z){return JSON.stringify([B,b(Z)])}static quotaLockName(B){return`opencode-fallback-quota-refresh-${B.replace(/[^a-zA-Z0-9._-]+/g,"-")||"account"}`}_enqueueApiFetch(B){let Z=async()=>{let z=this.now()-this.lastApiCallAt;if(z<P.API_CALL_GAP_MS)await new Promise((X)=>{let W=m0(X,P.API_CALL_GAP_MS-z);if(typeof W==="object"&&"unref"in W)W.unref()});return this.lastApiCallAt=this.now(),B()},$=this.apiGate.then(Z,Z);return this.apiGate=$.catch(()=>{}),$}async _fetchMain(B){let Z=b(B);return this._enqueueApiFetch(async()=>{try{if(this.isBackedOff()){if(this.main)return this.main.quota;throw Error("Quota API rate-limited — try again later")}let $=await m({name:"opencode-main-quota-refresh",ttlMs:30000});if(!$){let z=this.main;if(z&&this.now()<z.refreshAfter)return z.quota;throw Error("Quota refresh is already in progress")}try{let z=this.now(),X=await this._fetchQuota(B),W=this.now();if(this.mainTokenFp=b(B),this.main={quota:X,refreshAfter:f3(X,this.storage,W),checkedAt:W},j3(X))this.clearRateLimited("main");return this.mainLastApiError=void 0,this.onMainQuotaFetched?.(X,W,this.mainTokenFp,z),X}catch(z){throw this._handleMainFetchError(z),z}finally{await $.release()}}finally{if(this.inflightMainFp===Z)this.inflightMain=null,this.inflightMainFp=null}})}async _fetchFallback(B,Z){return this._enqueueApiFetch(async()=>{try{if(this.isFallbackBackedOff(B,Z)){let z=this.getFallback(B,Z);if(z)return z.quota;throw Error("Quota API rate-limited — try again later")}let $=await m({name:P.quotaLockName(B),ttlMs:30000});if(!$){let z=this.getFallback(B,Z);if(z&&this.now()<z.refreshAfter)return z.quota;throw Error("Quota refresh is already in progress")}try{let z=await this._fetchQuota(Z),X=this.now();return this.setFallback(B,{quota:z,refreshAfter:X+w(this.storage),checkedAt:X},Z),this.fallbackApiErrors.delete(B),this.fallbackErrorTokenFps.delete(B),z}finally{await $.release()}}catch($){throw this._handleFallbackFetchError(B,Z,$),$}finally{this.inflightFallbacks.delete(P.fallbackInflightKey(B,Z))}})}async _fetchQuota(B){if(!this.fetchQuotaFn)throw Error("Quota fetch not available — no fetchQuotaFn injected (push-only mode)");return this.fetchQuotaFn({accessToken:B,fetchImpl:this.fetchImpl,now:this.now})}static isAuthError(B){return B?.status===401}_handleMainFetchError(B){if(P.isAuthError(B))return;this.mainLastApiError=l({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(P.isAuthError($))return;let z=b(Z),X=this.fallbackErrorTokenFps.get(B)===z?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,l({error:$,now:this.now(),previous:X})),this.fallbackErrorTokenFps.set(B,z)}}function m3(B){for(let Z of Object.keys(B))return!0;return!1}function j3(B){let{primary:Z,secondary:$}=B;if(!Z||!$)return!1;return Z.usedPercent<100&&$.usedPercent<100}import{createHash as r0,randomUUID as n0}from"node:crypto";import{homedir as c0}from"node:os";import{dirname as a0,join as B3}from"node:path";import{setTimeout as o0}from"node:timers/promises";import{randomUUID as l0}from"node:crypto";import{mkdir as d0,rename as g0,rm as i0,writeFile as u0}from"node:fs/promises";import{dirname as s0}from"node:path";async function k(B,Z){await d0(s0(B),{recursive:!0});let $=`${B}.${l0()}.tmp`;await u0($,`${JSON.stringify(Z,null,2)}
91
- `,{encoding:"utf8",mode:384});try{await g0($,B)}catch(z){throw await i0($,{force:!0}).catch(()=>{}),z}}import{readFile as YB}from"node:fs/promises";var y=g3("refresh"),w3=1e4,t0=50,i3="openai-auth.json",e0="openai-auth-state.json";function BB(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return B3(process.env.XDG_CONFIG_HOME||B3(c0(),".config"),"opencode")}function h(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||B3(BB(),i3)}function z3(B=h()){let Z=process.env.OPENCODE_OPENAI_AUTH_STATE_FILE?.trim();if(Z)return Z;return ZB(B)}function ZB(B){return B.endsWith(i3)?B3(a0(B),e0):`${B}.state.json`}function U(B){return B.type==="oauth"}function $B(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 xZ(B){return B.costZeroing?.enabled!==!1}class Z3 extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var zB=[401,403,429],k3={primary:0,secondary:0},WB=!1,L3={primary:5,secondary:10};function j(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}function XB(B){return B instanceof Z3||j(B)&&B.name==="AccountRemovedDuringRefreshError"&&B.code==="ACCOUNT_REMOVED_DURING_REFRESH"}function h3(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():n0(),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 v3(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 GB(B){if(!j(B))return;let Z={};for(let $ of["primary","secondary"]){let z=B[$];if(!j(z))continue;let X=Number(z.usedPercent),W=Number(z.remainingPercent),G=Number(z.checkedAt);if(!Number.isFinite(X)||!Number.isFinite(W)||!Number.isFinite(G))continue;Z[$]={usedPercent:X,remainingPercent:W,checkedAt:G,resetsAt:typeof z.resetsAt==="string"?z.resetsAt:void 0}}return Object.keys(Z).length?Z:void 0}function KB(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(!$B(Z))return null;let z=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...h3(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{...h3(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:v3(B.lastRefreshError),lastQuotaRefreshError:v3(B.lastQuotaRefreshError),quota:GB(B.quota)}}function u3(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(KB).filter((Z)=>Z!=null)}}async function A(B){try{return{exists:!0,value:JSON.parse(await YB(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))}async function JB(B){let Z;try{Z=(await A(B)).value}catch{return null}if(!j(Z)||!Array.isArray(Z.accounts))return null;let $=new Set;for(let z of Z.accounts)if(j(z)&&typeof z.id==="string")$.add(z.id);return $}function s3(B,Z){if(!j(B))return B;let $=j(Z)?Z:{},z=j($.main)?$.main:void 0,X=j($.accounts)?$.accounts:{},W=j(B.quota)?B.quota:{},G=j(B.refresh)?B.refresh:{},K=z??W,Y=z??G,H=Array.isArray(B.accounts)?B.accounts.map((V)=>{if(!j(V))return V;let F=typeof V.id==="string"&&j(X[V.id])?X[V.id]:{};return{...V,...F}}):void 0;return r3({...B,refresh:M({...G,mainLastRefreshError:Y.lastRefreshError,mainRefreshLeaseId:Y.refreshLeaseId,mainRefreshLeaseUntil:Y.refreshLeaseUntil,mainRefreshLeaseTokenHash:Y.refreshLeaseTokenHash}),quota:M({...W,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:H})}async function HB(B=h()){let Z=await A(B);if(!Z.exists)return null;let $=await A(z3(B));return u3(s3(Z.value,$.value))}function r3(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function jB(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 n3(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 $3(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function r(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function QB(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function VB(B,Z){if(!QB(B,Z))return Z;if(!("lastRefreshError"in Z))return B;if(!("lastRefreshError"in B))return Z;return(Z.lastRefreshError?.checkedAt??0)>(B.lastRefreshError?.checkedAt??0)?Z:B}function NB(B,Z,$){let z=Z.lastRefreshedAt??0,X=$.lastRefreshedAt??0,W=Z.expires??0,G=$.expires??0,K=X>z?$:z>X?Z:G>W?$:W>G?Z:VB(Z,$);r(B,K,"access"),r(B,K,"refresh"),r(B,K,"expires"),r(B,K,"lastRefreshedAt"),r(B,K,"lastRefreshError")}function LB(B,Z){if(!j(B))return Z;let $=B,z=$3($.quota),X=$3(Z.quota),W=z>X,G=W?{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}:{...$,...Z};if(!W&&!("lastQuotaRefreshError"in Z))delete G.lastQuotaRefreshError;if(!("lastRefreshError"in Z))delete G.lastRefreshError;if(typeof $.lastUsed==="number"&&(typeof Z.lastUsed!=="number"||$.lastUsed>Z.lastUsed))G.lastUsed=$.lastUsed;return NB(G,$,Z),G}function c3(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 r3({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(jB)})}async function n(B){let Z=Date.now()+w3;while(Date.now()<=Z){let $=await m({name:"save",ttlMs:w3,path:B});if($)return $;let z=Z-Date.now();if(z<=0)break;await o0(Math.min(t0,z))}throw Error(`Timed out acquiring account store lock for ${B}; refusing to overwrite newer account data`)}function a3(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,n3($)]));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 IZ(B,Z=h()){let $=z3(Z),z=await n(Z);try{let X=await n($);try{let W=await A(Z),G=await A($),K=(W.exists?u3(s3(W.value,G.value)):null)??bB(),Y=B(K)??K,H={...j(W.value)?W.value:{},...c3(Y)};return await k(Z,H),await k($,a3(Y)),Y}finally{await X.release()}}finally{await z.release()}}function bB(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function FB(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:$3(B.main.quota),z=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:$3(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 DB(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 b3(B){if(Array.isArray(B))return B.map(b3);if(!j(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,b3($)]))}async function OB(B,Z=h(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let z=z3(Z),X=await n(z);try{let W=(await A(z)).value,G=j(W)?{...W,version:1}:{version:1};if($.mainQuota)FB(G,B);if($.mainRefresh)DB(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await JB(Z);G.accounts={...j(G.accounts)?G.accounts:{}};for(let J of B.accounts){if(K&&!K.has(J.id))continue;if(Y&&!Y.has(J.id))continue;G.accounts[J.id]=LB(G.accounts[J.id],n3(J))}if(K){for(let J of K)if(!B.accounts.some((H)=>H.id===J))delete G.accounts[J]}if(Y){for(let J of Object.keys(G.accounts))if(!Y.has(J))delete G.accounts[J]}}await k(z,b3(G))}finally{await X.release()}}function PB(B){return B?.fallbackOn?.length?B.fallbackOn:zB}function TZ(B,Z){return PB(Z).includes(B)}function UB(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??k3.primary,secondary:Z.secondary??Z["1w"]??k3.secondary}}function F3(B){return B?.quota?.enabled!==!1}function O3(B){return B?.quota?.failClosedOnUnknownQuota??WB}function o3(B,Z,$=Date.now()){if(!F3(Z))return!0;let z=UB(Z);for(let X of["primary","secondary"]){let W=B?.[X];if(!W||Q3(W,$))return!O3(Z);if(W.remainingPercent<z[X])return!1}return!0}function MB(B){return B?.killswitch?.enabled===!0}function p3(B){return{primary:B?.primary??B?.["5h"]??L3.primary,secondary:B?.secondary??B?.["1w"]??L3.secondary}}function _B(B,Z){if(!B?.killswitch)return L3;if(Z&&B.killswitch.accounts?.[Z])return p3(B.killswitch.accounts[Z]);return p3(B.killswitch.main)}function fZ(B,Z,$,z=Date.now()){if(!MB(Z))return!0;let X=_B(Z,$),W=!1;for(let G of["primary","secondary"]){let K=B?.[G];if(!K||Q3(K,z)){W=!0;continue}if(K.remainingPercent<X[G])return!1}if(W)return!O3(Z);return!0}function mZ(B,Z,$){let z=[],X=[B,...Z.map((G)=>G.quota)];for(let G of X)for(let K of["primary","secondary"]){let Y=G?.[K]?.resetsAt;if(!Y)continue;let J=Date.parse(Y);if(Number.isFinite(J)&&J>$)z.push(J)}if(z.length===0)return 300;let W=Math.min(...z);return Math.max(1,Math.ceil((W-$)/1000))}function qB(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function wZ(B,Z=h()){let $=z3(Z),z=await n(Z);try{let X=await n($);try{let W=await A(Z);if(W.exists&&j(W.value)){if(qB(W.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let J=t({id_token:"",access_token:B.access,refresh_token:B.refresh});if(J)G.mainAccountId=J}let Y={...W.exists&&j(W.value)?W.value:{},...c3(G)};await k(Z,Y),await k($,a3(G))}finally{await X.release()}}finally{await z.release()}}function CB(B){return B?.refresh?.enabled!==!1}function SB(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function RB(B){return Math.floor(Math.random()*(B+1))}function x(B,Z,$){return!B.access||!B.expires||B.expires-$<=SB(Z)}function EB(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function yB(B,Z){return Boolean(B.mainAccountId&&Z.accountId&&Z.accountId===B.mainAccountId)}function L(B,Z){let $=B.accounts.findIndex((z)=>z.id===Z.id);if($!==-1)B.accounts[$]=Z}function V3(B){return B instanceof Error?B.message:String(B)}function D3(B,Z,$){B.lastRefreshError=S3({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function N3(B,Z,$){if(B.lastQuotaRefreshError=l({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)D3(B,Z,$)}function xB(B){return`fallback-oauth-refresh-${r0("sha256").update(B).digest("base64url").slice(0,16)}`}function l3(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function AB(B,Z){if(!B)return!1;return l3(B[T],Z)||l3(B[f],Z)}function IB(B,Z,$){if(!B)return!1;let z=Z?.quota?.checkIntervalMinutes??5,X=Math.max(1,z)*60000,W=Math.max(B[T]?.checkedAt??0,B[f]?.checkedAt??0);return $-W<X}function d3(B,Z,$){return!IB(B.quota,Z,$)}function TB(B,Z,$,z){return X3($)&&o3(B.quota,Z,z)&&AB(B.quota,z)}function fB(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var mB=60000,wB=60000,kB=600000,hB=1e4,vB=100;var kZ=globalThis.setTimeout.bind(globalThis),hZ=globalThis.clearTimeout.bind(globalThis);class pB{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??h(),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[T]?.checkedAt??0,B.quota[f]?.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:$+fB(Z),checkedAt:$},B.access)}async load(){return HB(this.configPath)}async save(B,Z){await OB(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(()=>{})},mB+RB(wB)),"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 X of Z.accounts){if(X.enabled===!1||!U(X))continue;if(yB(Z,X))continue;let W=!1,G=X;try{if(x(G,Z,this.now())){let K=G.lastRefreshError;if(K&&q(K,G.refresh,this.now()))throw W=!0,Error(a(K,this.now()));try{G=await this.refreshAccount(G,Z),z=!0}catch(Y){if(XB(Y))continue;W=!0;let J=Z.accounts.find((H)=>H.id===X.id&&U(H));if(J&&!q(J.lastRefreshError,J.refresh,this.now()))D3(J,Y,this.now()),L(Z,J),z=!0;throw Y}}if(this.seedFallbackQuota(G,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(G),Z))$.push(G)}catch(K){let Y=EB(G,this.now());if(W){if(!Y)continue}else if(!Y)continue;if(TB(G,Z,K,this.now()))y.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:V3(K)}),$.push(G);else if(!O3(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 o3(B.quota,Z,this.now())}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||!CB(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;if(!x($,B,this.now()))continue;if(q($.lastRefreshError,$.refresh,this.now()))continue;try{y.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){y.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:V3(z)}),D3($,z,this.now()),L(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!F3(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;let z=$;try{if(x(z,B,this.now())){if(q(z.lastRefreshError,z.refresh,this.now()))continue;z=await this.refreshAccount(z,B),Z=!0}if(I(z.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota(z,B),!(this.quotaManager?this.quotaManager.isFallbackStale(z.id,z.access):d3(z,B,this.now())))continue;await this.refreshAccountQuota(z,B),Z=!0}catch(X){N3($,X,this.now()),L(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!F3(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let z=B.force??!1,X=!1;for(let W of Z.accounts){if(W.enabled===!1||!U(W))continue;let G=W;try{if(x(G,Z,this.now())){let K=G.lastRefreshError;if(K&&q(K,G.refresh,this.now()))throw Error(a(K,this.now()));G=await this.refreshAccount(G,Z),X=!0}if(!z&&!d3(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,L(Z,G),X=!0;continue}await this.refreshAccountQuota(G,Z),X=!0}catch(K){N3(W,K,this.now()),L(Z,W),X=!0,$.push({accountId:W.id,message:V3(K)})}}if(X)await this.save(Z);return{storage:Z,errors:$}}async refreshAccount(B,Z,$={}){let z=this.refreshPromises.get(B.id);if(z){let G=await z;return L(Z,G),G}let X=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,X);let W=await X;return L(Z,W),W}async waitForConcurrentFallbackRefresh(B,Z,$,z){let X=Date.now()+hB;while(Date.now()<X){await new Promise((J)=>setTimeout(J,vB));let W=await this.load(),G=W?.accounts.find((J)=>J.id===B.id&&U(J));if(!G)continue;if((G.access!==$.access||G.refresh!==$.refresh||(G.expires??0)>($.expires??0)+60000)&&(z.force||!x(G,W,this.now())))return L(Z,G),y.debug("fallback oauth joined concurrent refresh",{pid:process.pid,accountId:G.id,expiresInMs:G.expires?G.expires-this.now():void 0}),G;let Y=G.lastRefreshError;if(Y&&q(Y,G.refresh,this.now()))throw L(Z,G),Error(a(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let z=await this.load(),X=z?.accounts.find((K)=>K.id===B.id&&U(K));if(X&&!$.force&&!x(X,z,this.now()))return L(Z,X),X;let W=X??B,G=await m({name:xB(W.id),ttlMs:kB,path:this.configPath,now:this.now,renew:!0});if(!G){y.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:W.id});let K=await this.waitForConcurrentFallbackRefresh(B,Z,W,$);if(K)return K;throw Error("Fallback OAuth refresh is already in progress")}try{if(z=await this.load(),X=z?.accounts.find((H)=>H.id===B.id&&U(H)),X&&!$.force&&!x(X,z,this.now()))return L(Z,X),X;if(!X)throw new Z3(B.id);W=X;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});y.debug("fallback oauth refresh request start",{pid:process.pid,accountId:W.id,force:$.force===!0,expiresInMs:W.expires?W.expires-this.now():void 0});let Y=await K({refreshToken:W.refresh,fetchImpl:this.fetchImpl,now:this.now});if(W.access=Y.access,W.refresh=Y.refresh,W.expires=Y.expires,W.lastRefreshedAt=Y.expires-Y.expiresIn*1000,W.lastRefreshError=void 0,L(Z,W),await this.save(Z),!(await this.load())?.accounts.some((H)=>H.id===B.id))throw new Z3(B.id);return y.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:W.id,expiresInMs:W.expires?W.expires-this.now():void 0}),W}finally{await G.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")}),X=(W)=>this.quotaManager?this.quotaManager.refreshFallback($.id,W):z({accessToken:W,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let W=await X($.access);$.quota=W,$.lastQuotaRefreshError=void 0,L(Z,$),await this.save(Z)}catch(W){throw N3(B,W,this.now()),L(Z,B),W}}}
92
- export{C3 as g,S3 as h,q as i,a as j,x3 as k,I3 as l,j0 as m,E3 as n,y3 as o,t as p,K3 as q,V0 as r,E as s,F0 as t,D0 as u,O0 as v,P0 as w,aB as x,oB as y,BZ as z,ZZ as A,m as B,Q3 as C,VZ as D,P as E,h as F,U as G,xZ as H,L3 as I,HB as J,IZ as K,TZ as L,MB as M,fZ as N,mZ as O,wZ as P,pB as Q};
87
+ </html>`,i,g,O=new Map;function C(){return O.size}function E(B){if(O.delete(B),C()===0)S()}async function F3(){let B=`http://localhost:${d}/auth/callback`;if(i)return{port:d,redirectUri:B};if(g)return g;g=(async()=>{let Z=K3(($,z)=>{let X=new URL($.url||"/",`http://127.0.0.1:${d}`);if(X.pathname==="/auth/callback"){let W=X.searchParams.get("code"),G=X.searchParams.get("state"),K=X.searchParams.get("error"),Y=X.searchParams.get("error_description");if(K){let H=Y||K;if(G){let V=O.get(G);if(V)V.reject(Error(H)),E(G);else if(C()===0)S()}else if(C()===0)S();z.writeHead(200,{"Content-Type":"text/html"}),z.end(o(H));return}if(!G){if(C()===0)S();z.writeHead(400,{"Content-Type":"text/html"}),z.end(o("Missing state parameter"));return}if(!W){if(C()===0)S();z.writeHead(400,{"Content-Type":"text/html"}),z.end(o("Missing authorization code"));return}let J=O.get(G);if(!J){if(C()===0)S();z.writeHead(400,{"Content-Type":"text/html"}),z.end(o("Unknown state — authorization may have expired"));return}E(G),N3(W,B,J.pkce).then((H)=>J.resolve(H)).catch((H)=>J.reject(H)),z.writeHead(200,{"Content-Type":"text/html"}),z.end(b3);return}if(X.pathname==="/cancel"){let W=X.searchParams.get("state"),G=W?[W]:[...O.keys()];z.writeHead(200),z.end("Login cancelled");for(let K of G){let Y=O.get(K);if(!Y)continue;Y.reject(Error("Login cancelled")),E(K)}if(C()===0)S();return}z.writeHead(404),z.end("Not found")});return await new Promise(($,z)=>{Z.once("error",z),Z.listen(d,"127.0.0.1",()=>{Z.off("error",z),$()})}),i=Z,{port:d,redirectUri:B}})();try{return await g}finally{g=void 0}}function S(){if(i){let B=i;i=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function D3(B,Z,$=300000,z){return new Promise((X,W)=>{if(z?.aborted){E(Z),W(Error("Login cancelled"));return}let G=setTimeout(()=>{if(O.get(Z))E(Z),W(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),O.get(Z))E(Z),W(Error("Login cancelled"))};if(z)z.addEventListener("abort",K);O.set(Z,{pkce:B,state:Z,resolve:(Y)=>{if(clearTimeout(G),z)z.removeEventListener("abort",K);X(Y)},reject:(Y)=>{if(clearTimeout(G),z)z.removeEventListener("abort",K);W(Y)}})})}async function O3(){let B=await fetch(`${R}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":x0},body:JSON.stringify({client_id:e})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${R}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function P3(B,Z){let $=Math.max(parseInt(B.interval,10)||5,1)*1000,z=typeof B.expires_in==="number"?B.expires_in:parseInt(B.expires_in||"",10),X=!Number.isNaN(z)&&z>0?z*1000:900000,W=Date.now();while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");if(Date.now()-W>X)throw Error("Device authorization expired");let G=await fetch(`${R}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":x0},body:JSON.stringify({device_auth_id:B.device_auth_id,user_code:B.user_code})});if(G.ok){let J=await G.json(),H=await fetch(`${R}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",code:J.authorization_code,redirect_uri:`${R}/deviceauth/callback`,client_id:e,code_verifier:J.code_verifier}).toString()});if(!H.ok)throw Error(`Token exchange failed: ${H.status}`);return await H.json()}if(G.status!==403&&G.status!==404)throw Error(`Device authorization failed: ${G.status}`);let K=X-(Date.now()-W);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+J3,K);try{await Y3(Y,void 0,{signal:Z})}catch(J){if(J instanceof Error&&J.name==="AbortError")throw Error("Device authorization cancelled");throw J}}}function a4(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 o4(B={}){let{label:Z,headless:$=!1,signal:z}=B;if(K0(Z),$){let{deviceData:J,url:H,instructions:V}=await O3(),F=(async()=>{let Q=await P3(J,z),N=Date.now(),_=t(Q);return{id:K0(Z||_||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:Q.access_token,refresh:Q.refresh_token,expires:N+(Q.expires_in??3600)*1000,enabled:!0,addedAt:N,lastUsed:N,lastRefreshedAt:N,accountId:_}})();return{url:H,instructions:V,completion:F}}let{redirectUri:X}=await F3(),W=await j3(),G=I0(crypto.getRandomValues(new Uint8Array(32)).buffer),K=V3(X,W,G),Y=(async()=>{try{if(z?.aborted)throw Error("Login cancelled");let J=await D3(W,G,void 0,z),H=Date.now(),V=t(J);return{id:K0(Z||V||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:J.access_token,refresh:J.refresh_token,expires:H+(J.expires_in??3600)*1000,enabled:!0,addedAt:H,lastUsed:H,lastRefreshedAt:H,accountId:V}}finally{E(G)}})();return{url:K,instructions:"Complete authorization in your browser. This window will close automatically.",completion:Y}}var T="primary",f="secondary",M3="app_EMoamEEZ73f0CkXaXp7hrann",_3="https://auth.openai.com";async function BB(B){let Z=await B.fetchImpl(`${_3}/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:M3}).toString()});if(!Z.ok){let z=G0(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();if(!$||typeof $.access_token!=="string"||!$.access_token||typeof $.refresh_token!=="string"||!$.refresh_token||typeof $.expires_in!=="number")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});return{access:$.access_token,refresh:$.refresh_token,expires:B.now()+$.expires_in*1000,expiresIn:$.expires_in}}var q3="https://chatgpt.com/backend-api/wham/usage";async function ZB(B){let Z=await B.fetchImpl(q3,{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=G0(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-dfdpwwm3.js");return $(await Z.json())}import{randomUUID as Y0}from"node:crypto";import{mkdir as C3,readFile as J0,rename as S3,rm as u,stat as T0,writeFile as H0}from"node:fs/promises";import{homedir as R3}from"node:os";import{dirname as KB,join as s}from"node:path";var E3=globalThis.setTimeout.bind(globalThis),y3=globalThis.clearTimeout.bind(globalThis),x3="openai-auth.json";function A3(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return s(process.env.XDG_CONFIG_HOME||s(R3(),".config"),"opencode")}function I3(B){let Z=B?.code;return Z==="ENOENT"||Z==="EINVAL"||Z==="ENOTDIR"}function T3(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||s(A3(),x3)}async function m(B){let $=`${B.path??T3()}.${B.name}.lock`,z=s($,"owner.json"),X=Y0(),W=B.now??Date.now,G=null,K=!1;async function Y(){try{return JSON.parse(await J0($,"utf8"))}catch(Q){if(Q.code!=="EISDIR")throw Q;return JSON.parse(await J0(z,"utf8"))}}async function J(){await H0($,`${JSON.stringify({ownerId:X,expiresAt:W()+B.ttlMs})}
88
+ `,{encoding:"utf8",mode:384})}async function H(){try{return await H0($,`${JSON.stringify({ownerId:X,expiresAt:W()+B.ttlMs})}
89
+ `,{encoding:"utf8",mode:384,flag:"wx"}),!0}catch(Q){let N=Q.code;if(N==="EEXIST"||N==="EISDIR")return!1;throw Q}}function V(){if(!B.renew||K)return;let Q=B.renewIntervalMs??Math.max(1000,Math.floor(B.ttlMs/3));if(G=E3(()=>{(async()=>{try{let N=await Y(),_=W();if(K||N?.ownerId!==X||Number(N?.expiresAt)<=_)return;await J(),V()}catch{}})()},Q),"unref"in G)G.unref()}let F=await H();if(!F){let Q=`${$}.evicting`,N=s(Q,"owner.json"),_=Y0(),l4=5000,d4=8;async function c(){await new Promise((D)=>setTimeout(D,Math.floor(Math.random()*4)))}async function P0(){try{let D=await Y();return Number(D?.expiresAt)>W()}catch{try{return(await T0($)).mtimeMs+B.ttlMs>W()}catch{return!1}}}async function v(){try{return JSON.parse(await J0(N,"utf8"))?.ownerId===_}catch{return!1}}async function t0(){await C3(Q);try{await H0(N,`${JSON.stringify({ownerId:_,createdAt:W()})}
90
+ `,{encoding:"utf8",mode:384,flag:"wx"})}catch(D){if(I3(D))return!1;throw await U0(),D}return await B.onStep?.("eviction-marker-acquired"),!0}async function U0(){if(await v())await u(Q,{recursive:!0,force:!0}).catch(()=>{})}for(let D=0;D<8;D++){if(F=await H(),F)break;if(await P0())return null;try{if(!await t0()){await c();continue}}catch(M0){if(M0.code!=="EEXIST")throw M0;let _0;try{_0=await T0(Q)}catch(p){if(p.code==="ENOENT"){await c();continue}throw p}if(_0.mtimeMs+5000>W())return null;await B.onStep?.("stale-marker-stat");let q0=`${Q}.${Y0()}`;try{await S3(Q,q0)}catch(p){if(p.code==="ENOENT"){await c();continue}throw p}await B.onStep?.("stale-marker-claimed"),await u(q0,{recursive:!0,force:!0}).catch(()=>{}),await c();continue}try{if(await P0())return null;if(!await v())return null;if(await B.onStep?.("stale-lock-confirmed"),!await v())return null;if(await u($,{recursive:!0,force:!0}).catch(()=>{}),!await v())return null;if(F=await H(),!F)return null;if(!await v())return await u($,{recursive:!0,force:!0}).catch(()=>{}),F=!1,null;break}finally{await U0()}}}if(!F)return null;return V(),{release:async()=>{if(K=!0,G)y3(G),G=null;try{if((await Y())?.ownerId!==X)return}catch{return}await u($,{recursive:!0,force:!0}).catch(()=>{})}}}import{createHash as f3}from"node:crypto";var m3=globalThis.setTimeout,w3=5;function w(B){let Z=B?.quota?.checkIntervalMinutes??w3;return Math.max(1,Z)*60000}function k3(B){return B?.quota?.enabled!==!1}function Q0(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function VB(B,Z,$,z){let X=Z===T?B?.primary:Z===f?B?.secondary:void 0,W=X?.resetsAt?Date.parse(X.resetsAt):NaN;if(Number.isFinite(W)&&W>$)return W;return $+z}function h3(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function f0(B,Z,$){if(!k3(Z))return $+w(Z);let z=h3(Z),X=[];for(let W of["primary","secondary"]){let G=B?.[W];if(!G)return $+w(Z);if(G.remainingPercent>=z[W])continue;let K=G.resetsAt?Date.parse(G.resetsAt):Number.NaN;if(!Number.isFinite(K)||K<=$)return $+w(Z);X.push(K)}if(!X.length)return $+w(Z);return Math.min(...X)+60000}function v3(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function p3(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function b(B){return f3("sha256").update(B).digest("hex").slice(0,16)}class P{main=null;mainTokenFp=null;mainQuotaAccountId=null;fallbacks=new Map;fallbackTokenFps=new Map;inflightMain=null;inflightMainFp=null;inflightFallbacks=new Map;mainLastApiError=void 0;fallbackApiErrors=new Map;fallbackErrorTokenFps=new Map;rateLimitedUntilMap=new Map;apiGate=Promise.resolve();lastApiCallAt=0;storage;fetchImpl;now;fetchQuotaFn;onMainQuotaFetched;onApiError;constructor(B){this.storage=B.storage,this.fetchImpl=B.fetchImpl??fetch,this.now=B.now??Date.now,this.fetchQuotaFn=B.fetchQuotaFn,this.onMainQuotaFetched=B.onMainQuotaFetched,this.onApiError=B.onApiError,this.seedMainFromStorage(B.storage),this.seedMainBackoffFromStorage(B.storage)}getMain(B){if(B&&this.main&&this.mainTokenFp&&this.mainTokenFp!==b(B))this.main=null,this.mainTokenFp=null;return this.main}getFallback(B,Z){let $=this.fallbacks.get(B)??null;if(!Z||!$)return $;if(this.fallbackTokenFps.get(B)!==b(Z))return this.fallbacks.delete(B),this.fallbackTokenFps.delete(B),null;return $}getAllFallbacks(){return this.fallbacks}setMain(B,Z,$){if(!m0(Z.quota))return;if(this.mainTokenFp=b(B),$&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==$)this.clearRateLimited("main");if($)this.mainQuotaAccountId=$;if(this.main=Z,j0(Z.quota))this.clearRateLimited("main")}peekMainForPolicy(B){if(B&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==B)return null;return this.main}peekFallbackForPolicy(B){return this.fallbacks.get(B)??null}setFallback(B,Z,$){if(!m0(Z.quota))return;if(this.fallbacks.set(B,Z),$)this.fallbackTokenFps.set(B,b($));else this.fallbackTokenFps.delete(B);if(j0(Z.quota))this.clearRateLimited(B)}markRateLimited(B,Z){let $=this.rateLimitedUntilMap.get(B);if($!==void 0&&$>Z)return;this.rateLimitedUntilMap.set(B,Z)}isRateLimited(B){let Z=this.rateLimitedUntilMap.get(B);return Z!==void 0&&this.now()<Z}rateLimitedUntil(B){return this.rateLimitedUntilMap.get(B)}clearRateLimited(B){this.rateLimitedUntilMap.delete(B)}async refreshMain(B){let Z=b(B);if(this.mainTokenFp&&this.mainTokenFp!==Z)this.main=null,this.mainTokenFp=null;if(this.inflightMain&&this.inflightMainFp===Z)return this.inflightMain;if(this.isBackedOff()){if(this.main)return this.main.quota;throw Error("Quota API rate-limited — try again later")}return this.inflightMainFp=Z,this.inflightMain=this._fetchMain(B),this.inflightMain}async refreshFallback(B,Z){let $=P.fallbackInflightKey(B,Z),z=this.inflightFallbacks.get($);if(z)return z;if(this.isFallbackBackedOff(B,Z)){let W=this.getFallback(B,Z);if(W)return W.quota;throw Error("Quota API rate-limited — try again later")}let X=this._fetchFallback(B,Z);return this.inflightFallbacks.set($,X),X}async refreshAllFallbacks(B){let Z=this.now();for(let $ of B){if($.enabled===!1)continue;if(!$.access)continue;let z=this.getFallback($.id,$.access);if(z&&Z<z.refreshAfter)continue;try{await this.refreshFallback($.id,$.access)}catch{}}}refreshMainInBackground(B){let Z=b(B);if(this.inflightMain&&this.inflightMainFp===Z)return;if(this.isBackedOff())return;this.refreshMain(B).catch(()=>{})}isMainStale(){if(!this.main)return!0;return this.now()>=this.main.refreshAfter}isFallbackStale(B,Z){let $=this.getFallback(B,Z);if(!$)return!0;return this.now()>=$.refreshAfter}shouldRefreshOnRequestCount(B){let Z=p3(this.storage);if(Z<=0)return!1;return B>0&&B%Z===0}needsRefresh(B){return this.isMainStale()||this.shouldRefreshOnRequestCount(B)}updateStorage(B){this.storage=B,this.seedMainFromStorage(B),this.seedMainBackoffFromStorage(B)}seedMainFromStorage(B,Z){let $=v3(B);if(!$)return;let z=Z?b(Z):null;if(z&&$.tokenFingerprint&&$.tokenFingerprint!==z)return;let X={quota:$.quota,refreshAfter:f0($.quota,B,$.checkedAt),checkedAt:$.checkedAt};if(this.main&&this.main.checkedAt>=X.checkedAt&&(!z||!this.mainTokenFp||this.mainTokenFp===z))return;if(this.main=X,this.mainTokenFp=$.tokenFingerprint??null,B?.mainAccountId){if(this.mainQuotaAccountId&&this.mainQuotaAccountId!==B.mainAccountId)this.clearRateLimited("main");this.mainQuotaAccountId=B.mainAccountId}}seedMainBackoffFromStorage(B){let Z=B?.quota?.mainLastQuotaApiError;this.mainLastApiError=Z&&I(Z,this.now())?Z:void 0}seedFallbacksFromAccounts(B){let Z=w(this.storage);for(let $ of B){if($.enabled===!1)continue;if(!$.quota)continue;let z=Math.max($.quota.primary?.checkedAt??0,$.quota.secondary?.checkedAt??0);if(z<=0)continue;let X=this.getFallback($.id,$.access);if(X&&X.checkedAt>=z)continue;this.setFallback($.id,{quota:$.quota,refreshAfter:z+Z,checkedAt:z},$.access)}}isBackedOff(){return I(this.mainLastApiError,this.now())}isFallbackBackedOff(B,Z){if(Z){if(this.fallbackErrorTokenFps.get(B)!==b(Z))return!1}return I(this.fallbackApiErrors.get(B),this.now())}getLastApiError(){return this.mainLastApiError}static API_CALL_GAP_MS=1000;static fallbackInflightKey(B,Z){return JSON.stringify([B,b(Z)])}static quotaLockName(B){return`opencode-fallback-quota-refresh-${B.replace(/[^a-zA-Z0-9._-]+/g,"-")||"account"}`}_enqueueApiFetch(B){let Z=async()=>{let z=this.now()-this.lastApiCallAt;if(z<P.API_CALL_GAP_MS)await new Promise((X)=>{let W=m3(X,P.API_CALL_GAP_MS-z);if(typeof W==="object"&&"unref"in W)W.unref()});return this.lastApiCallAt=this.now(),B()},$=this.apiGate.then(Z,Z);return this.apiGate=$.catch(()=>{}),$}async _fetchMain(B){let Z=b(B);return this._enqueueApiFetch(async()=>{try{if(this.isBackedOff()){if(this.main)return this.main.quota;throw Error("Quota API rate-limited — try again later")}let $=await m({name:"opencode-main-quota-refresh",ttlMs:30000});if(!$){let z=this.main;if(z&&this.now()<z.refreshAfter)return z.quota;throw Error("Quota refresh is already in progress")}try{let z=this.now(),X=await this._fetchQuota(B),W=this.now();if(this.mainTokenFp=b(B),this.main={quota:X,refreshAfter:f0(X,this.storage,W),checkedAt:W},j0(X))this.clearRateLimited("main");return this.mainLastApiError=void 0,this.onMainQuotaFetched?.(X,W,this.mainTokenFp,z),X}catch(z){throw this._handleMainFetchError(z),z}finally{await $.release()}}finally{if(this.inflightMainFp===Z)this.inflightMain=null,this.inflightMainFp=null}})}async _fetchFallback(B,Z){return this._enqueueApiFetch(async()=>{try{if(this.isFallbackBackedOff(B,Z)){let z=this.getFallback(B,Z);if(z)return z.quota;throw Error("Quota API rate-limited — try again later")}let $=await m({name:P.quotaLockName(B),ttlMs:30000});if(!$){let z=this.getFallback(B,Z);if(z&&this.now()<z.refreshAfter)return z.quota;throw Error("Quota refresh is already in progress")}try{let z=await this._fetchQuota(Z),X=this.now();return this.setFallback(B,{quota:z,refreshAfter:X+w(this.storage),checkedAt:X},Z),this.fallbackApiErrors.delete(B),this.fallbackErrorTokenFps.delete(B),z}finally{await $.release()}}catch($){throw this._handleFallbackFetchError(B,Z,$),$}finally{this.inflightFallbacks.delete(P.fallbackInflightKey(B,Z))}})}async _fetchQuota(B){if(!this.fetchQuotaFn)throw Error("Quota fetch not available — no fetchQuotaFn injected (push-only mode)");return this.fetchQuotaFn({accessToken:B,fetchImpl:this.fetchImpl,now:this.now})}static isAuthError(B){return B?.status===401}_handleMainFetchError(B){if(P.isAuthError(B))return;this.mainLastApiError=l({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(P.isAuthError($))return;let z=b(Z),X=this.fallbackErrorTokenFps.get(B)===z?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,l({error:$,now:this.now(),previous:X})),this.fallbackErrorTokenFps.set(B,z)}}function m0(B){for(let Z of Object.keys(B))return!0;return!1}function j0(B){let{primary:Z,secondary:$}=B;if(!Z||!$)return!1;return Z.usedPercent<100&&$.usedPercent<100}import{createHash as r3,randomUUID as n3}from"node:crypto";import{homedir as c3}from"node:os";import{dirname as a3,join as B0}from"node:path";import{setTimeout as o3}from"node:timers/promises";import{randomUUID as l3}from"node:crypto";import{mkdir as d3,rename as g3,rm as i3,writeFile as u3}from"node:fs/promises";import{dirname as s3}from"node:path";async function k(B,Z){await d3(s3(B),{recursive:!0});let $=`${B}.${l3()}.tmp`;await u3($,`${JSON.stringify(Z,null,2)}
91
+ `,{encoding:"utf8",mode:384});try{await g3($,B)}catch(z){throw await i3($,{force:!0}).catch(()=>{}),z}}import{readFile as Y4}from"node:fs/promises";var y=g0("refresh"),w0=1e4,t3=50,i0="openai-auth.json",e3="openai-auth-state.json";function B4(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return B0(process.env.XDG_CONFIG_HOME||B0(c3(),".config"),"opencode")}function h(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||B0(B4(),i0)}function z0(B=h()){let Z=process.env.OPENCODE_OPENAI_AUTH_STATE_FILE?.trim();if(Z)return Z;return Z4(B)}function Z4(B){return B.endsWith(i0)?B0(a3(B),e3):`${B}.state.json`}function U(B){return B.type==="oauth"}function $4(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 xB(B){return B.costZeroing?.enabled!==!1}class Z0 extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var z4=[401,403,429],k0={primary:0,secondary:0},W4=!1,L0={primary:5,secondary:10};function j(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}function X4(B){return B instanceof Z0||j(B)&&B.name==="AccountRemovedDuringRefreshError"&&B.code==="ACCOUNT_REMOVED_DURING_REFRESH"}function h0(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():n3(),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 v0(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 G4(B){if(!j(B))return;let Z={};for(let $ of["primary","secondary"]){let z=B[$];if(!j(z))continue;let X=Number(z.usedPercent),W=Number(z.remainingPercent),G=Number(z.checkedAt);if(!Number.isFinite(X)||!Number.isFinite(W)||!Number.isFinite(G))continue;Z[$]={usedPercent:X,remainingPercent:W,checkedAt:G,resetsAt:typeof z.resetsAt==="string"?z.resetsAt:void 0}}return Object.keys(Z).length?Z:void 0}function K4(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(!$4(Z))return null;let z=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...h0(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{...h0(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:v0(B.lastRefreshError),lastQuotaRefreshError:v0(B.lastQuotaRefreshError),quota:G4(B.quota)}}function u0(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(K4).filter((Z)=>Z!=null)}}async function A(B){try{return{exists:!0,value:JSON.parse(await Y4(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))}async function J4(B){let Z;try{Z=(await A(B)).value}catch{return null}if(!j(Z)||!Array.isArray(Z.accounts))return null;let $=new Set;for(let z of Z.accounts)if(j(z)&&typeof z.id==="string")$.add(z.id);return $}function s0(B,Z){if(!j(B))return B;let $=j(Z)?Z:{},z=j($.main)?$.main:void 0,X=j($.accounts)?$.accounts:{},W=j(B.quota)?B.quota:{},G=j(B.refresh)?B.refresh:{},K=z??W,Y=z??G,H=Array.isArray(B.accounts)?B.accounts.map((V)=>{if(!j(V))return V;let F=typeof V.id==="string"&&j(X[V.id])?X[V.id]:{};return{...V,...F}}):void 0;return r0({...B,refresh:M({...G,mainLastRefreshError:Y.lastRefreshError,mainRefreshLeaseId:Y.refreshLeaseId,mainRefreshLeaseUntil:Y.refreshLeaseUntil,mainRefreshLeaseTokenHash:Y.refreshLeaseTokenHash}),quota:M({...W,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:H})}async function H4(B=h()){let Z=await A(B);if(!Z.exists)return null;let $=await A(z0(B));return u0(s0(Z.value,$.value))}function r0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function j4(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 n0(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 $0(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function r(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function Q4(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function V4(B,Z){if(!Q4(B,Z))return Z;if(!("lastRefreshError"in Z))return B;if(!("lastRefreshError"in B))return Z;return(Z.lastRefreshError?.checkedAt??0)>(B.lastRefreshError?.checkedAt??0)?Z:B}function N4(B,Z,$){let z=Z.lastRefreshedAt??0,X=$.lastRefreshedAt??0,W=Z.expires??0,G=$.expires??0,K=X>z?$:z>X?Z:G>W?$:W>G?Z:V4(Z,$);r(B,K,"access"),r(B,K,"refresh"),r(B,K,"expires"),r(B,K,"lastRefreshedAt"),r(B,K,"lastRefreshError")}function L4(B,Z){if(!j(B))return Z;let $=B,z=$0($.quota),X=$0(Z.quota),W=z>X,G=W?{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}:{...$,...Z};if(!W&&!("lastQuotaRefreshError"in Z))delete G.lastQuotaRefreshError;if(!("lastRefreshError"in Z))delete G.lastRefreshError;if(typeof $.lastUsed==="number"&&(typeof Z.lastUsed!=="number"||$.lastUsed>Z.lastUsed))G.lastUsed=$.lastUsed;return N4(G,$,Z),G}function c0(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 r0({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(j4)})}async function n(B){let Z=Date.now()+w0;while(Date.now()<=Z){let $=await m({name:"save",ttlMs:w0,path:B});if($)return $;let z=Z-Date.now();if(z<=0)break;await o3(Math.min(t3,z))}throw Error(`Timed out acquiring account store lock for ${B}; refusing to overwrite newer account data`)}function a0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,n0($)]));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 IB(B,Z=h()){let $=z0(Z),z=await n(Z);try{let X=await n($);try{let W=await A(Z),G=await A($),K=(W.exists?u0(s0(W.value,G.value)):null)??b4(),Y=B(K)??K,H={...j(W.value)?W.value:{},...c0(Y)};return await k(Z,H),await k($,a0(Y)),Y}finally{await X.release()}}finally{await z.release()}}function b4(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function F4(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:$0(B.main.quota),z=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:$0(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 D4(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 b0(B){if(Array.isArray(B))return B.map(b0);if(!j(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,b0($)]))}async function O4(B,Z=h(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let z=z0(Z),X=await n(z);try{let W=(await A(z)).value,G=j(W)?{...W,version:1}:{version:1};if($.mainQuota)F4(G,B);if($.mainRefresh)D4(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await J4(Z);G.accounts={...j(G.accounts)?G.accounts:{}};for(let J of B.accounts){if(K&&!K.has(J.id))continue;if(Y&&!Y.has(J.id))continue;G.accounts[J.id]=L4(G.accounts[J.id],n0(J))}if(K){for(let J of K)if(!B.accounts.some((H)=>H.id===J))delete G.accounts[J]}if(Y){for(let J of Object.keys(G.accounts))if(!Y.has(J))delete G.accounts[J]}}await k(z,b0(G))}finally{await X.release()}}function P4(B){return B?.fallbackOn?.length?B.fallbackOn:z4}function TB(B,Z){return P4(Z).includes(B)}function U4(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??k0.primary,secondary:Z.secondary??Z["1w"]??k0.secondary}}function F0(B){return B?.quota?.enabled!==!1}function O0(B){return B?.quota?.failClosedOnUnknownQuota??W4}function o0(B,Z,$=Date.now()){if(!F0(Z))return!0;let z=U4(Z);for(let X of["primary","secondary"]){let W=B?.[X];if(!W||Q0(W,$))return!O0(Z);if(W.remainingPercent<z[X])return!1}return!0}function M4(B){return B?.killswitch?.enabled===!0}function p0(B){return{primary:B?.primary??B?.["5h"]??L0.primary,secondary:B?.secondary??B?.["1w"]??L0.secondary}}function _4(B,Z){if(!B?.killswitch)return L0;if(Z&&B.killswitch.accounts?.[Z])return p0(B.killswitch.accounts[Z]);return p0(B.killswitch.main)}function fB(B,Z,$,z=Date.now()){if(!M4(Z))return!0;let X=_4(Z,$),W=!1;for(let G of["primary","secondary"]){let K=B?.[G];if(!K||Q0(K,z)){W=!0;continue}if(K.remainingPercent<X[G])return!1}if(W)return!O0(Z);return!0}function mB(B,Z,$){let z=[],X=[B,...Z.map((G)=>G.quota)];for(let G of X)for(let K of["primary","secondary"]){let Y=G?.[K]?.resetsAt;if(!Y)continue;let J=Date.parse(Y);if(Number.isFinite(J)&&J>$)z.push(J)}if(z.length===0)return 300;let W=Math.min(...z);return Math.max(1,Math.ceil((W-$)/1000))}function q4(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function wB(B,Z=h()){let $=z0(Z),z=await n(Z);try{let X=await n($);try{let W=await A(Z);if(W.exists&&j(W.value)){if(q4(W.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let J=t({id_token:"",access_token:B.access,refresh_token:B.refresh});if(J)G.mainAccountId=J}let Y={...W.exists&&j(W.value)?W.value:{},...c0(G)};await k(Z,Y),await k($,a0(G))}finally{await X.release()}}finally{await z.release()}}function C4(B){return B?.refresh?.enabled!==!1}function S4(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function R4(B){return Math.floor(Math.random()*(B+1))}function x(B,Z,$){return!B.access||!B.expires||B.expires-$<=S4(Z)}function E4(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function y4(B,Z){return Boolean(B.mainAccountId&&Z.accountId&&Z.accountId===B.mainAccountId)}function L(B,Z){let $=B.accounts.findIndex((z)=>z.id===Z.id);if($!==-1)B.accounts[$]=Z}function V0(B){return B instanceof Error?B.message:String(B)}function D0(B,Z,$){B.lastRefreshError=S0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function N0(B,Z,$){if(B.lastQuotaRefreshError=l({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)D0(B,Z,$)}function x4(B){return`fallback-oauth-refresh-${r3("sha256").update(B).digest("base64url").slice(0,16)}`}function l0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function A4(B,Z){if(!B)return!1;return l0(B[T],Z)||l0(B[f],Z)}function I4(B,Z,$){if(!B)return!1;let z=Z?.quota?.checkIntervalMinutes??5,X=Math.max(1,z)*60000,W=Math.max(B[T]?.checkedAt??0,B[f]?.checkedAt??0);return $-W<X}function d0(B,Z,$){return!I4(B.quota,Z,$)}function T4(B,Z,$,z){return X0($)&&o0(B.quota,Z,z)&&A4(B.quota,z)}function f4(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var m4=60000,w4=60000,k4=600000,h4=1e4,v4=100;var kB=globalThis.setTimeout.bind(globalThis),hB=globalThis.clearTimeout.bind(globalThis);class p4{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??h(),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[T]?.checkedAt??0,B.quota[f]?.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:$+f4(Z),checkedAt:$},B.access)}async load(){return H4(this.configPath)}async save(B,Z){await O4(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(()=>{})},m4+R4(w4)),"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 X of Z.accounts){if(X.enabled===!1||!U(X))continue;if(y4(Z,X))continue;let W=!1,G=X;try{if(x(G,Z,this.now())){let K=G.lastRefreshError;if(K&&q(K,G.refresh,this.now()))throw W=!0,Error(a(K,this.now()));try{G=await this.refreshAccount(G,Z),z=!0}catch(Y){if(X4(Y))continue;W=!0;let J=Z.accounts.find((H)=>H.id===X.id&&U(H));if(J&&!q(J.lastRefreshError,J.refresh,this.now()))D0(J,Y,this.now()),L(Z,J),z=!0;throw Y}}if(this.seedFallbackQuota(G,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(G),Z))$.push(G)}catch(K){let Y=E4(G,this.now());if(W){if(!Y)continue}else if(!Y)continue;if(T4(G,Z,K,this.now()))y.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:V0(K)}),$.push(G);else if(!O0(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 o0(B.quota,Z,this.now())}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||!C4(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;if(!x($,B,this.now()))continue;if(q($.lastRefreshError,$.refresh,this.now()))continue;try{y.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){y.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:V0(z)}),D0($,z,this.now()),L(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!F0(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;let z=$;try{if(x(z,B,this.now())){if(q(z.lastRefreshError,z.refresh,this.now()))continue;z=await this.refreshAccount(z,B),Z=!0}if(I(z.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota(z,B),!(this.quotaManager?this.quotaManager.isFallbackStale(z.id,z.access):d0(z,B,this.now())))continue;await this.refreshAccountQuota(z,B),Z=!0}catch(X){N0($,X,this.now()),L(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!F0(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let z=B.force??!1,X=!1;for(let W of Z.accounts){if(W.enabled===!1||!U(W))continue;let G=W;try{if(x(G,Z,this.now())){let K=G.lastRefreshError;if(K&&q(K,G.refresh,this.now()))throw Error(a(K,this.now()));G=await this.refreshAccount(G,Z),X=!0}if(!z&&!d0(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,L(Z,G),X=!0;continue}await this.refreshAccountQuota(G,Z),X=!0}catch(K){N0(W,K,this.now()),L(Z,W),X=!0,$.push({accountId:W.id,message:V0(K)})}}if(X)await this.save(Z);return{storage:Z,errors:$}}async refreshAccount(B,Z,$={}){let z=this.refreshPromises.get(B.id);if(z){let G=await z;return L(Z,G),G}let X=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,X);let W=await X;return L(Z,W),W}async waitForConcurrentFallbackRefresh(B,Z,$,z){let X=Date.now()+h4;while(Date.now()<X){await new Promise((J)=>setTimeout(J,v4));let W=await this.load(),G=W?.accounts.find((J)=>J.id===B.id&&U(J));if(!G)continue;if((G.access!==$.access||G.refresh!==$.refresh||(G.expires??0)>($.expires??0)+60000)&&(z.force||!x(G,W,this.now())))return L(Z,G),y.debug("fallback oauth joined concurrent refresh",{pid:process.pid,accountId:G.id,expiresInMs:G.expires?G.expires-this.now():void 0}),G;let Y=G.lastRefreshError;if(Y&&q(Y,G.refresh,this.now()))throw L(Z,G),Error(a(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let z=await this.load(),X=z?.accounts.find((K)=>K.id===B.id&&U(K));if(X&&!$.force&&!x(X,z,this.now()))return L(Z,X),X;let W=X??B,G=await m({name:x4(W.id),ttlMs:k4,path:this.configPath,now:this.now,renew:!0});if(!G){y.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:W.id});let K=await this.waitForConcurrentFallbackRefresh(B,Z,W,$);if(K)return K;throw Error("Fallback OAuth refresh is already in progress")}try{if(z=await this.load(),X=z?.accounts.find((H)=>H.id===B.id&&U(H)),X&&!$.force&&!x(X,z,this.now()))return L(Z,X),X;if(!X)throw new Z0(B.id);W=X;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});y.debug("fallback oauth refresh request start",{pid:process.pid,accountId:W.id,force:$.force===!0,expiresInMs:W.expires?W.expires-this.now():void 0});let Y=await K({refreshToken:W.refresh,fetchImpl:this.fetchImpl,now:this.now});if(W.access=Y.access,W.refresh=Y.refresh,W.expires=Y.expires,W.lastRefreshedAt=Y.expires-Y.expiresIn*1000,W.lastRefreshError=void 0,L(Z,W),await this.save(Z),!(await this.load())?.accounts.some((H)=>H.id===B.id))throw new Z0(B.id);return y.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:W.id,expiresInMs:W.expires?W.expires-this.now():void 0}),W}finally{await G.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")}),X=(W)=>this.quotaManager?this.quotaManager.refreshFallback($.id,W):z({accessToken:W,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let W=await X($.access);$.quota=W,$.lastQuotaRefreshError=void 0,L(Z,$),await this.save(Z)}catch(W){throw N0(B,W,this.now()),L(Z,B),W}}}
92
+ export{C0 as g,S0 as h,q as i,a as j,x0 as k,I0 as l,j3 as m,E0 as n,y0 as o,t as p,K0 as q,V3 as r,E as s,F3 as t,D3 as u,O3 as v,P3 as w,a4 as x,o4 as y,BB as z,ZB as A,m as B,Q0 as C,VB as D,P as E,h as F,U as G,xB as H,L0 as I,H4 as J,IB as K,TB as L,M4 as M,fB as N,mB as O,wB as P,p4 as Q};
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import{d as F4,e as lW}from"./index-d9hq0tmc.js";import{A as tY,B as FG,C as aY,D as EG,E as PG,G as q4,H as AG,I as x6,J as n$,K as H$,L as Gz,M as sY,N as eY,O as IG,P as bG,Q as MG,g as WG,h as GG,i as QG,j as vG,k as wG,l as _G,m as HG,n as Qz,o as vz,p as Wz,r as LG,s as DG,t as BG,u as qG,v as VG,w as KG,x as ON,y as WN,z as C1}from"./index-phrx93zy.js";import{R as RG,V as ZG}from"./index-mrg2fms9.js";import{aa as h1,ba as KN,ca as A$}from"./index-qdh7pt5a.js";import{da as fN}from"./index-k5zwf3j1.js";import{ga as SG}from"./index-1xmasv0x.js";import{ja as z6}from"./index-e7m7qbne.js";import{mkdirSync as lH,readFileSync as nH,renameSync as dH,statSync as pH,writeFileSync as rH}from"node:fs";import rY from"node:os";import{join as oH}from"node:path";import{readFileSync as gG}from"node:fs";import{homedir as xG,tmpdir as fG}from"node:os";import{join as x1}from"node:path";var hG="https://chatgpt.com/backend-api/codex/responses",yG="openai-auth.json",q6={noWebSearch:"CORTEXKIT_OPENAI_AUTH_NO_WEB_SEARCH",webSockets:"CORTEXKIT_OPENAI_AUTH_WEBSOCKETS",rawWebSocket:"CORTEXKIT_OPENAI_AUTH_RAW_WS",dump:"CORTEXKIT_OPENAI_AUTH_DUMP",dumpDir:"OPENCODE_OPENAI_AUTH_DUMP_DIR",codexApiEndpoint:"CORTEXKIT_OPENAI_AUTH_CODEX_ENDPOINT",configFile:"OPENCODE_OPENAI_AUTH_FILE",stateFile:"OPENCODE_OPENAI_AUTH_STATE_FILE",configDir:"OPENCODE_CONFIG_DIR"};function f1(){let $=process.env[q6.configDir]?.trim();if($)return $;return x1(process.env.XDG_CONFIG_HOME||x1(xG(),".config"),"opencode")}function B$(){return process.env[q6.configFile]?.trim()||x1(f1(),yG)}function mG(){try{let $=JSON.parse(gG(B$(),"utf8"));return $!=null&&typeof $==="object"&&!Array.isArray($)?$:{}}catch{return{}}}function YN($){let U=process.env[$];if(U===void 0)return;let J=U.trim().toLowerCase();if(J==="1"||J==="true"||J==="yes"||J==="on")return!0;if(J===""||J==="0"||J==="false"||J==="no"||J==="off")return!1;return}function Lz($,U,J){let X=YN($);if(X!==void 0)return X;if(typeof U==="boolean")return U;return J}function cG(){let $=mG(),U=YN(q6.noWebSearch),J=U!==void 0?!U:typeof $.webSearch==="boolean"?$.webSearch:!0,X;if($.dump!==void 0&&$.dump!==null){if(typeof $.dump==="object")X=$.dump.enabled;else if(typeof $.dump==="boolean")X=$.dump}return{webSearch:J,webSockets:Lz(q6.webSockets,$.webSockets,!1),rawWebSocket:Lz(q6.rawWebSocket,$.rawWebSocket,!1),dump:Lz(q6.dump,X,!1),dumpDir:process.env[q6.dumpDir]?.trim()||(typeof $.dumpDir==="string"&&$.dumpDir.trim()?$.dumpDir.trim():x1(fG(),"opencode-openai-auth-dumps")),codexApiEndpoint:process.env[q6.codexApiEndpoint]?.trim()||(typeof $.codexApiEndpoint==="string"&&$.codexApiEndpoint.trim()?$.codexApiEndpoint.trim():hG)}}var Dz;function Z$(){if(!Dz)Dz=cG();return Dz}var Bz="openai-quota",qz="openai-account",Vz="openai-routing",Kz="openai-killswitch",Fz="openai-dump",Ez="openai-logging",Pz="openai-cachekeep",GN=["openai-quota","openai-account","openai-routing","openai-killswitch","openai-dump","openai-logging","openai-cachekeep"],D$=A$("commands");function NN($){return $==="fallback-first"?"Try usable fallback accounts before the main account.":"Try the main account first. Use fallback accounts only when required."}async function uG($){let U=await $.refreshAllQuota?.(),J=$.quotaManager.getMain(),X=["## OpenAI Quota",""];if(J?.quota){let Y=J.quota;X.push("### Main account");for(let N of["primary","secondary"]){let O=Y[N];if(O){let W=Math.round(O.usedPercent),v="█".repeat(Math.max(0,Math.min(Math.round(W/10),10)))+"░".repeat(Math.max(0,10-Math.min(Math.round(W/10),10)));X.push(`- ${N}: ${v} ${W}% used (${Math.round(O.remainingPercent)}% remaining)`)}}}else X.push("No main quota snapshot available. Send a request first.");let j=[...$.quotaManager.getAllFallbacks().entries()].filter(([,Y])=>Y);if(j.length>0){X.push(""),X.push("### Fallback accounts");for(let[Y,N]of j){if(!N?.quota)continue;X.push(`**${Y}**`);for(let O of["primary","secondary"]){let W=N.quota[O];if(W){let v=Math.round(W.usedPercent);X.push(` - ${O}: ${v}% used (${Math.round(W.remainingPercent)}% remaining)`)}}}}if(U?.length){let Y=U.filter((N)=>!N.ok);if(Y.length>0){X.push("");for(let N of Y)X.push(`⚠ ${N.account}: could not fetch (${N.error??"unknown error"})`)}}return{command:"openai-quota",text:X.join(`
1
+ import{d as F4,e as lW}from"./index-d9hq0tmc.js";import{A as tY,B as FG,C as aY,D as EG,E as PG,G as q4,H as AG,I as x6,J as n$,K as H$,L as Gz,M as sY,N as eY,O as IG,P as bG,Q as MG,g as WG,h as GG,i as QG,j as vG,k as wG,l as _G,m as HG,n as Qz,o as vz,p as Wz,r as LG,s as DG,t as BG,u as qG,v as VG,w as KG,x as ON,y as WN,z as C1}from"./index-y8d01tgn.js";import{R as RG,V as ZG}from"./index-mrg2fms9.js";import{aa as h1,ba as KN,ca as A$}from"./index-qdh7pt5a.js";import{da as fN}from"./index-k5zwf3j1.js";import{ga as SG}from"./index-1xmasv0x.js";import{ja as z6}from"./index-e7m7qbne.js";import{mkdirSync as lH,readFileSync as nH,renameSync as dH,statSync as pH,writeFileSync as rH}from"node:fs";import rY from"node:os";import{join as oH}from"node:path";import{readFileSync as gG}from"node:fs";import{homedir as xG,tmpdir as fG}from"node:os";import{join as x1}from"node:path";var hG="https://chatgpt.com/backend-api/codex/responses",yG="openai-auth.json",q6={noWebSearch:"CORTEXKIT_OPENAI_AUTH_NO_WEB_SEARCH",webSockets:"CORTEXKIT_OPENAI_AUTH_WEBSOCKETS",rawWebSocket:"CORTEXKIT_OPENAI_AUTH_RAW_WS",dump:"CORTEXKIT_OPENAI_AUTH_DUMP",dumpDir:"OPENCODE_OPENAI_AUTH_DUMP_DIR",codexApiEndpoint:"CORTEXKIT_OPENAI_AUTH_CODEX_ENDPOINT",configFile:"OPENCODE_OPENAI_AUTH_FILE",stateFile:"OPENCODE_OPENAI_AUTH_STATE_FILE",configDir:"OPENCODE_CONFIG_DIR"};function f1(){let $=process.env[q6.configDir]?.trim();if($)return $;return x1(process.env.XDG_CONFIG_HOME||x1(xG(),".config"),"opencode")}function B$(){return process.env[q6.configFile]?.trim()||x1(f1(),yG)}function mG(){try{let $=JSON.parse(gG(B$(),"utf8"));return $!=null&&typeof $==="object"&&!Array.isArray($)?$:{}}catch{return{}}}function YN($){let U=process.env[$];if(U===void 0)return;let J=U.trim().toLowerCase();if(J==="1"||J==="true"||J==="yes"||J==="on")return!0;if(J===""||J==="0"||J==="false"||J==="no"||J==="off")return!1;return}function Lz($,U,J){let X=YN($);if(X!==void 0)return X;if(typeof U==="boolean")return U;return J}function cG(){let $=mG(),U=YN(q6.noWebSearch),J=U!==void 0?!U:typeof $.webSearch==="boolean"?$.webSearch:!0,X;if($.dump!==void 0&&$.dump!==null){if(typeof $.dump==="object")X=$.dump.enabled;else if(typeof $.dump==="boolean")X=$.dump}return{webSearch:J,webSockets:Lz(q6.webSockets,$.webSockets,!1),rawWebSocket:Lz(q6.rawWebSocket,$.rawWebSocket,!1),dump:Lz(q6.dump,X,!1),dumpDir:process.env[q6.dumpDir]?.trim()||(typeof $.dumpDir==="string"&&$.dumpDir.trim()?$.dumpDir.trim():x1(fG(),"opencode-openai-auth-dumps")),codexApiEndpoint:process.env[q6.codexApiEndpoint]?.trim()||(typeof $.codexApiEndpoint==="string"&&$.codexApiEndpoint.trim()?$.codexApiEndpoint.trim():hG)}}var Dz;function Z$(){if(!Dz)Dz=cG();return Dz}var Bz="openai-quota",qz="openai-account",Vz="openai-routing",Kz="openai-killswitch",Fz="openai-dump",Ez="openai-logging",Pz="openai-cachekeep",GN=["openai-quota","openai-account","openai-routing","openai-killswitch","openai-dump","openai-logging","openai-cachekeep"],D$=A$("commands");function NN($){return $==="fallback-first"?"Try usable fallback accounts before the main account.":"Try the main account first. Use fallback accounts only when required."}async function uG($){let U=await $.refreshAllQuota?.(),J=$.quotaManager.getMain(),X=["## OpenAI Quota",""];if(J?.quota){let Y=J.quota;X.push("### Main account");for(let N of["primary","secondary"]){let O=Y[N];if(O){let W=Math.round(O.usedPercent),v="█".repeat(Math.max(0,Math.min(Math.round(W/10),10)))+"░".repeat(Math.max(0,10-Math.min(Math.round(W/10),10)));X.push(`- ${N}: ${v} ${W}% used (${Math.round(O.remainingPercent)}% remaining)`)}}}else X.push("No main quota snapshot available. Send a request first.");let j=[...$.quotaManager.getAllFallbacks().entries()].filter(([,Y])=>Y);if(j.length>0){X.push(""),X.push("### Fallback accounts");for(let[Y,N]of j){if(!N?.quota)continue;X.push(`**${Y}**`);for(let O of["primary","secondary"]){let W=N.quota[O];if(W){let v=Math.round(W.usedPercent);X.push(` - ${O}: ${v}% used (${Math.round(W.remainingPercent)}% remaining)`)}}}}if(U?.length){let Y=U.filter((N)=>!N.ok);if(Y.length>0){X.push("");for(let N of Y)X.push(`⚠ ${N.account}: could not fetch (${N.error??"unknown error"})`)}}return{command:"openai-quota",text:X.join(`
2
2
  `),knobs:{}}}async function iG($,U){let J=$.trim().split(/\s+/).filter(Boolean),X=await U.loadAccounts(U.accountStoragePath)??{version:1,accounts:[]},z=X.accounts??[];if(J.length===0){let j=["## OpenAI Accounts",""];if(z.length===0)j.push("No accounts configured. Use `/login openai` to add your main account, or `/openai-account add` to add a fallback account.");else{let Y=X.routing?.mode??"main-first";j.push(`Routing: \`${Y}\` (set with \`/openai-routing\`).`),j.push("");for(let N of z){let O=N.type??"oauth";j.push(`- \`${N.id}\` (${O})`)}}return j.push(""),j.push("Commands: `/openai-account add [label]` | `/openai-account remove <id>`"),{command:"openai-account",text:j.join(`
3
3
  `),knobs:{accounts:z}}}if(J[0]==="remove"&&J[1]){let j=J[1],Y=!1,N=await H$((O)=>{let W=O.accounts.findIndex((v)=>v.id===j);if(W===-1)return O;return Y=!0,O.accounts.splice(W,1),O},U.accountStoragePath);if(!Y)return{command:"openai-account",text:`## Account Not Found
4
4
 
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const PackageVersion = "0.3.3";
1
+ export declare const PackageVersion = "0.3.4";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cortexkit/opencode-openai-auth",
3
- "version": "0.3.3",
3
+ "version": "0.3.4",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -20,7 +20,7 @@
20
20
  },
21
21
  "./tui": {
22
22
  "types": "./dist/tui.d.ts",
23
- "import": "./src/tui.tsx"
23
+ "import": "./src/tui/entry.mjs"
24
24
  },
25
25
  "./tui-prefs": {
26
26
  "types": "./dist/tui-preferences.d.ts",
@@ -37,7 +37,8 @@
37
37
  "files": [
38
38
  "dist",
39
39
  "src/tui.tsx",
40
- "src/tui/command-dialogs.tsx",
40
+ "src/tui",
41
+ "src/tui-compiled",
41
42
  "src/sidebar-state.ts",
42
43
  "src/tui-preferences.ts",
43
44
  "src/logger.ts",
@@ -47,7 +48,8 @@
47
48
  "LICENSE"
48
49
  ],
49
50
  "scripts": {
50
- "build": "rm -rf dist && bun build src/index.ts src/cli.ts src/sidebar-state.ts src/tui-preferences.ts src/rpc/rpc-client.ts src/rpc/port-file.ts src/rpc/protocol.ts src/rpc/rpc-dir.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --minify && tsc -p tsconfig.build.json --emitDeclarationOnly",
51
+ "build": "rm -rf dist && bun build src/index.ts src/cli.ts src/sidebar-state.ts src/tui-preferences.ts src/rpc/rpc-client.ts src/rpc/port-file.ts src/rpc/protocol.ts src/rpc/rpc-dir.ts --outdir dist --target node --format esm --splitting --external @opencode-ai/plugin --minify && tsc -p tsconfig.build.json --emitDeclarationOnly && bun run build:tui",
52
+ "build:tui": "bun scripts/build-tui.ts",
51
53
  "build:dev": "rm -rf dist && tsc -p tsconfig.build.json",
52
54
  "test": "bun test src/tests",
53
55
  "typecheck": "tsc",
@@ -0,0 +1,37 @@
1
+ // Prefer the host OpenTUI runtime registry when it exists. OpenTUI 0.4.x
2
+ // registers these virtual modules process-wide, allowing the precompiled TUI to
3
+ // share the host's single Solid/OpenTUI runtime when loaded from node_modules.
4
+ const runtimeProbe = `opentui:runtime-module:${encodeURIComponent('@opentui/solid')}`
5
+
6
+ function isMissingRuntimeRegistry(error) {
7
+ const message = error instanceof Error ? error.message : String(error)
8
+ return (
9
+ /Cannot find|Could not resolve|Module not found|Unable to resolve/.test(
10
+ message,
11
+ ) && message.includes('opentui:runtime-module:')
12
+ )
13
+ }
14
+
15
+ let mod
16
+ try {
17
+ await import(runtimeProbe)
18
+ } catch (error) {
19
+ if (!isMissingRuntimeRegistry(error)) {
20
+ console.error('OpenAI Auth TUI runtime registry probe failed', error)
21
+ throw error
22
+ }
23
+ // Older hosts and bare Bun do not provide the virtual registry. Their source
24
+ // loader still applies the Solid transform, so retain the raw TSX fallback.
25
+ mod = await import('../tui.tsx')
26
+ }
27
+
28
+ if (!mod) {
29
+ try {
30
+ mod = await import('../tui-compiled/tui.tsx')
31
+ } catch (error) {
32
+ console.error('OpenAI Auth compiled TUI failed to load', error)
33
+ throw error
34
+ }
35
+ }
36
+
37
+ export default mod.default
@@ -0,0 +1,161 @@
1
+ import {
2
+ appendFileSync,
3
+ chmodSync,
4
+ existsSync,
5
+ renameSync,
6
+ statSync,
7
+ } from 'node:fs'
8
+ import { tmpdir } from 'node:os'
9
+ import { join } from 'node:path'
10
+
11
+ type Level = 'error' | 'warn' | 'info' | 'debug' | 'trace'
12
+ const ORDER: Record<Level, number> = {
13
+ error: 0,
14
+ warn: 1,
15
+ info: 2,
16
+ debug: 3,
17
+ trace: 4,
18
+ }
19
+ const isTestEnv = process.env.NODE_ENV === 'test'
20
+ const MAX_BYTES = 5 * 1024 * 1024
21
+
22
+ function logFile(): string {
23
+ return (
24
+ process.env.OPENCODE_OPENAI_AUTH_LOG_FILE ??
25
+ join(tmpdir(), 'opencode-openai-auth.log')
26
+ )
27
+ }
28
+ let runtimeLevel: Level | undefined
29
+ export function setLogLevel(l: Level | undefined) {
30
+ if (l === undefined || l in ORDER) runtimeLevel = l
31
+ }
32
+ function configuredLevel(): Level {
33
+ if (runtimeLevel) return runtimeLevel
34
+ const env = process.env.OPENCODE_OPENAI_AUTH_LOG_LEVEL as Level | undefined
35
+ if (env && env in ORDER) return env
36
+ return 'info'
37
+ }
38
+
39
+ const SECRET_KEY_EXACT =
40
+ /^(authorization|x-api-key|cookie|set-cookie|refresh|access|token)$/i
41
+ function isSecretKey(key: string): boolean {
42
+ if (SECRET_KEY_EXACT.test(key)) return true
43
+ const k = key.toLowerCase().replace(/[-_]/g, '')
44
+ // Only the unambiguous ChatGPT stable id (chatgpt-account-id / chatgptAccountId)
45
+ // is sensitive. A bare `accountId` field is overloaded — most diagnostic logs put
46
+ // the INTERNAL account id/key ('main' or a fallback id) there, which is safe and
47
+ // needed for debugging — so it is intentionally NOT redacted by name. The genuine
48
+ // ChatGPT id is kept out of logs at the source instead.
49
+ if (k === 'chatgptaccountid') return true
50
+ if (k.includes('apikey')) return true
51
+ if (k.endsWith('secret') || k.endsWith('password')) return true
52
+ if (k.endsWith('token') && !k.endsWith('tokens')) return true
53
+ return false
54
+ }
55
+ const TOKEN_VALUE = /\b(Bearer\s+[\w.-]+|sk-[\w-]+|eyJ[\w.-]+)\b/g
56
+ export function redact(value: unknown): unknown {
57
+ return redactInner(value, new WeakSet<object>())
58
+ }
59
+ function redactInner(value: unknown, seen: WeakSet<object>): unknown {
60
+ if (typeof value === 'string')
61
+ return value.replace(TOKEN_VALUE, '***REDACTED***')
62
+ if (Array.isArray(value)) {
63
+ if (seen.has(value)) return '[Circular]'
64
+ seen.add(value)
65
+ const arr = value.map((v) => redactInner(v, seen))
66
+ seen.delete(value)
67
+ return arr
68
+ }
69
+ if (value && typeof value === 'object') {
70
+ if (seen.has(value)) return '[Circular]'
71
+ seen.add(value)
72
+ const out: Record<string, unknown> = {}
73
+ for (const [k, v] of Object.entries(value))
74
+ out[k] = isSecretKey(k) ? '***REDACTED***' : redactInner(v, seen)
75
+ seen.delete(value)
76
+ return out
77
+ }
78
+ return value
79
+ }
80
+
81
+ let buffer: string[] = []
82
+ let timer: ReturnType<typeof setTimeout> | undefined
83
+ const ROTATE_KEEP = 3
84
+ function chmodPrivate(path: string) {
85
+ try {
86
+ chmodSync(path, 0o600)
87
+ } catch {
88
+ /* never throw */
89
+ }
90
+ }
91
+ function rotateIfNeeded() {
92
+ try {
93
+ const f = logFile()
94
+ if (!(existsSync(f) && statSync(f).size > MAX_BYTES)) return
95
+ for (let i = ROTATE_KEEP - 1; i >= 1; i--) {
96
+ if (existsSync(`${f}.${i}`)) {
97
+ const rotated = `${f}.${i + 1}`
98
+ renameSync(`${f}.${i}`, rotated)
99
+ chmodPrivate(rotated)
100
+ }
101
+ }
102
+ const rotated = `${f}.1`
103
+ renameSync(f, rotated)
104
+ chmodPrivate(rotated)
105
+ } catch {
106
+ /* never throw */
107
+ }
108
+ }
109
+ function flush() {
110
+ if (!buffer.length) return
111
+ const text = buffer.join('')
112
+ buffer = []
113
+ try {
114
+ rotateIfNeeded()
115
+ const file = logFile()
116
+ if (existsSync(file)) chmodPrivate(file)
117
+ appendFileSync(file, text, { encoding: 'utf8', mode: 0o600 })
118
+ } catch {
119
+ /* never throw */
120
+ }
121
+ }
122
+ function schedule() {
123
+ if (!timer)
124
+ timer = setTimeout(() => {
125
+ timer = undefined
126
+ flush()
127
+ }, 500)
128
+ }
129
+ if (!isTestEnv) process.on('exit', flush)
130
+
131
+ function safeSerialize(data: unknown): string {
132
+ try {
133
+ return ` ${JSON.stringify(redact(data))}`
134
+ } catch {
135
+ return ' [unserializable]'
136
+ }
137
+ }
138
+
139
+ function emit(channel: string, level: Level, message: string, data?: unknown) {
140
+ if (ORDER[level] > ORDER[configuredLevel()]) return
141
+ const line =
142
+ `[${new Date().toISOString()}] ${level.toUpperCase()} [${channel}] ${message}` +
143
+ (data === undefined ? '' : safeSerialize(data)) +
144
+ '\n'
145
+ buffer.push(line)
146
+ if (buffer.length >= 50) flush()
147
+ else schedule()
148
+ }
149
+
150
+ export function createLogger(channel: string) {
151
+ return {
152
+ error: (m: string, d?: unknown) => emit(channel, 'error', m, d),
153
+ warn: (m: string, d?: unknown) => emit(channel, 'warn', m, d),
154
+ info: (m: string, d?: unknown) => emit(channel, 'info', m, d),
155
+ debug: (m: string, d?: unknown) => emit(channel, 'debug', m, d),
156
+ trace: (m: string, d?: unknown) => emit(channel, 'trace', m, d),
157
+ }
158
+ }
159
+ export async function flushForTest() {
160
+ flush()
161
+ }
@@ -0,0 +1,70 @@
1
+ import {
2
+ mkdir,
3
+ readdir,
4
+ readFile,
5
+ rename,
6
+ unlink,
7
+ writeFile,
8
+ } from 'node:fs/promises'
9
+ import { join } from 'node:path'
10
+
11
+ export interface PortFileEntry {
12
+ port: number
13
+ token: string
14
+ pid: number
15
+ startedAt: number
16
+ }
17
+
18
+ function pidAlive(pid: number): boolean {
19
+ try {
20
+ process.kill(pid, 0)
21
+ return true
22
+ } catch (error) {
23
+ return (error as NodeJS.ErrnoException).code === 'EPERM'
24
+ }
25
+ }
26
+
27
+ export async function writePortFile(
28
+ dir: string,
29
+ entry: { port: number; token: string; pid: number },
30
+ ): Promise<string> {
31
+ await mkdir(dir, { recursive: true })
32
+ const full: PortFileEntry = { ...entry, startedAt: Date.now() }
33
+ const target = join(dir, `port-${entry.pid}.json`)
34
+ const tmp = `${target}.${process.pid}.tmp`
35
+ await writeFile(tmp, JSON.stringify(full), { encoding: 'utf8', mode: 0o600 })
36
+ await rename(tmp, target)
37
+ return target
38
+ }
39
+
40
+ export async function discoverPortFile(
41
+ dir: string,
42
+ expectedPid?: number,
43
+ ): Promise<PortFileEntry | null> {
44
+ let names: string[]
45
+ try {
46
+ names = await readdir(dir)
47
+ } catch {
48
+ return null
49
+ }
50
+ const live: PortFileEntry[] = []
51
+ for (const name of names) {
52
+ if (!name.startsWith('port-') || !name.endsWith('.json')) continue
53
+ try {
54
+ const parsed = JSON.parse(
55
+ await readFile(join(dir, name), 'utf8'),
56
+ ) as PortFileEntry
57
+ if (Number.isFinite(parsed.port)) {
58
+ if (pidAlive(parsed.pid)) live.push(parsed)
59
+ else unlink(join(dir, name)).catch(() => {})
60
+ }
61
+ } catch {}
62
+ }
63
+ if (live.length === 0) return null
64
+ const candidates =
65
+ expectedPid !== undefined && expectedPid >= 1
66
+ ? live.filter((entry) => entry.pid === expectedPid)
67
+ : []
68
+ const entries = candidates.length > 0 ? candidates : live
69
+ return entries.sort((a, b) => b.startedAt - a.startedAt)[0] ?? null
70
+ }