@cortexkit/opencode-openai-auth 0.6.3 → 0.6.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{J as C,K as E,L as X,r as $,y as q,z as B}from"./index-ng315c61.js";import{ua as Y}from"./index-8f1200qx.js";import"./index-80gqxa1f.js";import{Ja as Z}from"./index-x55z0b3y.js";import{execFileSync as U}from"node:child_process";function V(z,K=process.platform,H=U){try{if(K==="win32"){H("cmd",["/c","start","",z],{stdio:"ignore",timeout:3000});return}H(K==="darwin"?"open":"xdg-open",[z],{stdio:"ignore",timeout:3000})}catch{}}function W(){console.log(`Usage:
2
+ import{J as C,K as E,L as X,r as $,y as q,z as B}from"./index-z6mxjaar.js";import{ua as Y}from"./index-8f1200qx.js";import"./index-80gqxa1f.js";import{Ja as Z}from"./index-x55z0b3y.js";import{execFileSync as U}from"node:child_process";function V(z,K=process.platform,H=U){try{if(K==="win32"){H("cmd",["/c","start","",z],{stdio:"ignore",timeout:3000});return}H(K==="darwin"?"open":"xdg-open",[z],{stdio:"ignore",timeout:3000})}catch{}}function W(){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.6.3";
5
+ export declare const USER_AGENT = "cortexkit-opencode-openai-auth/0.6.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 {
package/dist/dump.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export declare const DUMP_SESSION_HEADER = "x-cortexkit-openai-auth-dump-session";
2
2
  type DumpHeaders = ConstructorParameters<typeof Headers>[0];
3
3
  type DumpTransport = 'http' | 'websocket';
4
- type DumpPhase = 'http' | 'prewarm' | 'main';
4
+ declare const DUMP_PHASES: readonly ['http', 'prewarm', 'main'];
5
+ type DumpPhase = (typeof DUMP_PHASES)[number];
5
6
  export declare function dumpCodexRequest(input: {
6
7
  sessionID?: string | null;
7
8
  transport: DumpTransport;
@@ -1,4 +1,4 @@
1
- import{ua as I,va as u,wa as A}from"./index-8f1200qx.js";import{Ca as v}from"./index-80gqxa1f.js";import{Ja as Q3}from"./index-x55z0b3y.js";import{createHash as i0}from"node:crypto";var u0=86400000,s0=300000,r0=3600000,n0=60000,c0=900000,o0=300000;function $0(B){return B instanceof Error?B.message:String(B)}function a0(B){let Z=B?.status;if(typeof Z==="number")return Z===429||Z>=500;if(!(B instanceof Error))return!1;return B.name==="AbortError"||B.name==="TimeoutError"||B.message.includes("fetch failed")||"code"in B&&(B.code==="ECONNRESET"||B.code==="ECONNREFUSED"||B.code==="ETIMEDOUT"||B.code==="UND_ERR_CONNECT_TIMEOUT")}function W0(B){let Z=$0(B),$=B?.status;if(typeof $==="number")return $===429||$>=500;if(!(B instanceof Error))return!1;let W=B.code;return B.name==="AbortError"||B.name==="TimeoutError"||Z.includes("fetch failed")||W==="ECONNRESET"||W==="ECONNREFUSED"||W==="ETIMEDOUT"||W==="UND_ERR_CONNECT_TIMEOUT"}function L0(B){return i0("sha256").update(B).digest("hex")}function F0(B){let Z=L0(B.refreshToken),W=(B.previous?.tokenHash===Z?B.previous.retryCount??0:0)+1,X,z=B.error?.retryAfter;if(typeof z==="number"&&z>0)X=z*1000;else if(a0(B.error))X=Math.min(r0,s0*2**Math.min(W-1,6));else X=u0;return{message:$0(B.error),checkedAt:B.now,nextRetryAt:B.now+X,retryCount:W,tokenHash:Z}}function _(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===L0(Z)}function r(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 m(B){let $=(B.previous?.retryCount??0)+1,W,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)W=X*1000;else if(W0(B.error))W=Math.min(c0,n0*2**Math.min($-1,6));else W=o0;return{message:$0(B.error),checkedAt:B.now,nextRetryAt:B.now+W,retryCount:$}}function x(B,Z){if(!B?.nextRetryAt||B.nextRetryAt<=Z)return!1;return!0}function X0(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 W=Math.ceil(($-Date.now())/1000);return W>0?W:void 0}return}import{createServer as t0}from"node:http";import{setTimeout as e0}from"node:timers/promises";var O0="0.6.3";var o="app_EMoamEEZ73f0CkXaXp7hrann",S="https://auth.openai.com",k=1455,B3=3000,D0=`cortexkit-opencode-openai-auth/${O0}`,U0="main",Z3=`"${U0}" is a reserved account id; choose a different label.`;function M0(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function $3(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((W)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[W%66]).join(""),$=M0(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(Z)));return{verifier:Z,challenge:$}}function V0(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 b0(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 W=B.organizations;if(Array.isArray(W)){let X=W[0];if(X&&typeof X==="object"&&!Array.isArray(X)&&typeof X.id==="string"&&X.id.length>0)return X.id}return}function c(B){if(B.id_token){let Z=V0(B.id_token),$=Z&&b0(Z);if($)return $}if(B.access_token){let Z=V0(B.access_token);return Z?b0(Z):void 0}return}function W3(B){return typeof B==="string"&&B.toLowerCase()===U0}function G0(B){if(W3(B))throw Error(Z3);return B}function X3(B,Z,$){let W=new URLSearchParams({response_type:"code",client_id:o,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`${S}/oauth/authorize?${W.toString()}`}async function G3(B,Z,$){let W=await fetch(`${S}/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:o,code_verifier:$.verifier}).toString()});if(!W.ok)throw Error(`Token exchange failed: ${W.status}`);return await W.json()}function z3(B){return B.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}var K3=`<!doctype html>
1
+ import{ua as I,va as u,wa as A}from"./index-8f1200qx.js";import{Ca as v}from"./index-80gqxa1f.js";import{Ja as Q4}from"./index-x55z0b3y.js";import{createHash as i0}from"node:crypto";var u0=86400000,s0=300000,r0=3600000,n0=60000,c0=900000,o0=300000;function $0(B){return B instanceof Error?B.message:String(B)}function a0(B){let Z=B?.status;if(typeof Z==="number")return Z===429||Z>=500;if(!(B instanceof Error))return!1;return B.name==="AbortError"||B.name==="TimeoutError"||B.message.includes("fetch failed")||"code"in B&&(B.code==="ECONNRESET"||B.code==="ECONNREFUSED"||B.code==="ETIMEDOUT"||B.code==="UND_ERR_CONNECT_TIMEOUT")}function W0(B){let Z=$0(B),$=B?.status;if(typeof $==="number")return $===429||$>=500;if(!(B instanceof Error))return!1;let W=B.code;return B.name==="AbortError"||B.name==="TimeoutError"||Z.includes("fetch failed")||W==="ECONNRESET"||W==="ECONNREFUSED"||W==="ETIMEDOUT"||W==="UND_ERR_CONNECT_TIMEOUT"}function L0(B){return i0("sha256").update(B).digest("hex")}function F0(B){let Z=L0(B.refreshToken),W=(B.previous?.tokenHash===Z?B.previous.retryCount??0:0)+1,X,z=B.error?.retryAfter;if(typeof z==="number"&&z>0)X=z*1000;else if(a0(B.error))X=Math.min(r0,s0*2**Math.min(W-1,6));else X=u0;return{message:$0(B.error),checkedAt:B.now,nextRetryAt:B.now+X,retryCount:W,tokenHash:Z}}function _(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===L0(Z)}function r(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 m(B){let $=(B.previous?.retryCount??0)+1,W,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)W=X*1000;else if(W0(B.error))W=Math.min(c0,n0*2**Math.min($-1,6));else W=o0;return{message:$0(B.error),checkedAt:B.now,nextRetryAt:B.now+W,retryCount:$}}function x(B,Z){if(!B?.nextRetryAt||B.nextRetryAt<=Z)return!1;return!0}function X0(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 W=Math.ceil(($-Date.now())/1000);return W>0?W:void 0}return}import{createServer as t0}from"node:http";import{setTimeout as e0}from"node:timers/promises";var O0="0.6.4";var o="app_EMoamEEZ73f0CkXaXp7hrann",S="https://auth.openai.com",k=1455,B4=3000,D0=`cortexkit-opencode-openai-auth/${O0}`,U0="main",Z4=`"${U0}" is a reserved account id; choose a different label.`;function M0(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function $4(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((W)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[W%66]).join(""),$=M0(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(Z)));return{verifier:Z,challenge:$}}function V0(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 b0(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 W=B.organizations;if(Array.isArray(W)){let X=W[0];if(X&&typeof X==="object"&&!Array.isArray(X)&&typeof X.id==="string"&&X.id.length>0)return X.id}return}function c(B){if(B.id_token){let Z=V0(B.id_token),$=Z&&b0(Z);if($)return $}if(B.access_token){let Z=V0(B.access_token);return Z?b0(Z):void 0}return}function W4(B){return typeof B==="string"&&B.toLowerCase()===U0}function G0(B){if(W4(B))throw Error(Z4);return B}function X4(B,Z,$){let W=new URLSearchParams({response_type:"code",client_id:o,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`${S}/oauth/authorize?${W.toString()}`}async function G4(B,Z,$){let W=await fetch(`${S}/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:o,code_verifier:$.verifier}).toString()});if(!W.ok)throw Error(`Token exchange failed: ${W.status}`);return await W.json()}function z4(B){return B.replaceAll("&","&amp;").replaceAll("<","&lt;").replaceAll(">","&gt;").replaceAll('"',"&quot;").replaceAll("'","&#39;")}var K4=`<!doctype html>
2
2
  <html>
3
3
  <head>
4
4
  <title>CortexKit OpenAI Auth - Authorization Successful</title>
@@ -81,9 +81,9 @@ import{ua as I,va as u,wa as A}from"./index-8f1200qx.js";import{Ca as v}from"./i
81
81
  <div class="container">
82
82
  <h1>Authorization Failed</h1>
83
83
  <p>An error occurred during authorization.</p>
84
- <div class="error">${z3(B)}</div>
84
+ <div class="error">${z4(B)}</div>
85
85
  </div>
86
86
  </body>
87
- </html>`,w,h,V=new Map;function q(){return V.size}function E(B){if(V.delete(B),q()===0)C()}async function Y3(){let B=`http://localhost:${k}/auth/callback`;if(w)return{port:k,redirectUri:B};if(h)return h;h=(async()=>{let Z=t0(($,W)=>{let X=new URL($.url||"/",`http://127.0.0.1:${k}`);if(X.pathname==="/auth/callback"){let z=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 Q=V.get(G);if(Q)Q.reject(Error(H)),E(G);else if(q()===0)C()}else if(q()===0)C();W.writeHead(200,{"Content-Type":"text/html"}),W.end(n(H));return}if(!G){if(q()===0)C();W.writeHead(400,{"Content-Type":"text/html"}),W.end(n("Missing state parameter"));return}if(!z){if(q()===0)C();W.writeHead(400,{"Content-Type":"text/html"}),W.end(n("Missing authorization code"));return}let j=V.get(G);if(!j){if(q()===0)C();W.writeHead(400,{"Content-Type":"text/html"}),W.end(n("Unknown state — authorization may have expired"));return}E(G),G3(z,B,j.pkce).then((H)=>j.resolve(H)).catch((H)=>j.reject(H)),W.writeHead(200,{"Content-Type":"text/html"}),W.end(K3);return}if(X.pathname==="/cancel"){let z=X.searchParams.get("state"),G=z?[z]:[...V.keys()];W.writeHead(200),W.end("Login cancelled");for(let K of G){let Y=V.get(K);if(!Y)continue;Y.reject(Error("Login cancelled")),E(K)}if(q()===0)C();return}W.writeHead(404),W.end("Not found")});return await new Promise(($,W)=>{Z.once("error",W),Z.listen(k,"127.0.0.1",()=>{Z.off("error",W),$()})}),w=Z,{port:k,redirectUri:B}})();try{return await h}finally{h=void 0}}function C(){if(w){let B=w;w=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function j3(B,Z,$=300000,W){return new Promise((X,z)=>{if(W?.aborted){E(Z),z(Error("Login cancelled"));return}let G=setTimeout(()=>{if(V.get(Z))E(Z),z(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),V.get(Z))E(Z),z(Error("Login cancelled"))};if(W)W.addEventListener("abort",K);V.set(Z,{pkce:B,state:Z,resolve:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);X(Y)},reject:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);z(Y)}})})}async function J3(){let B=await fetch(`${S}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":D0},body:JSON.stringify({client_id:o})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${S}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function H3(B,Z){let $=Math.max(parseInt(B.interval,10)||5,1)*1000,W=typeof B.expires_in==="number"?B.expires_in:parseInt(B.expires_in||"",10),X=!Number.isNaN(W)&&W>0?W*1000:900000,z=Date.now();while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");if(Date.now()-z>X)throw Error("Device authorization expired");let G=await fetch(`${S}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":D0},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(`${S}/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:`${S}/deviceauth/callback`,client_id:o,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()-z);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+B3,K);try{await e0(Y,void 0,{signal:Z})}catch(j){if(j instanceof Error&&j.name==="AbortError")throw Error("Device authorization cancelled");throw j}}}function x6(B,Z){let $=-1;if(Z.accountId)$=B.findIndex((W)=>W.accountId&&W.accountId===Z.accountId);if($<0)$=B.findIndex((W)=>W.id===Z.id);if($<0&&Z.label&&!Z.accountId)$=B.findIndex((W)=>W.label===Z.label);if($>=0)return B[$]={...B[$],...Z,addedAt:B[$]?.addedAt??Z.addedAt},$;return B.push(Z),B.length-1}async function A6(B={}){let{label:Z,headless:$=!1,signal:W}=B;if(G0(Z),$){let{deviceData:j,url:H,instructions:Q}=await J3(),b=(async()=>{let N=await H3(j,W),F=Date.now(),s=c(N);return{id:G0(Z||s||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:N.access_token,refresh:N.refresh_token,expires:F+(N.expires_in??3600)*1000,enabled:!0,addedAt:F,lastUsed:F,lastRefreshedAt:F,accountId:s}})();return{url:H,instructions:Q,completion:b}}let{redirectUri:X}=await Y3(),z=await $3(),G=M0(crypto.getRandomValues(new Uint8Array(32)).buffer),K=X3(X,z,G),Y=(async()=>{try{if(W?.aborted)throw Error("Login cancelled");let j=await j3(z,G,void 0,W),H=Date.now(),Q=c(j);return{id:G0(Z||Q||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:Q}}finally{E(G)}})();return{url:K,instructions:"Complete authorization in your browser. This window will close automatically.",completion:Y}}function _0(B){if(B instanceof Error)return B.message;if(typeof B==="string")return B;try{return JSON.stringify(B)}catch{return String(B)}}var N3=v("quota"),z0="primary",K0="secondary",P3="app_EMoamEEZ73f0CkXaXp7hrann",L3="https://auth.openai.com";async function w6(B){let Z=await B.fetchImpl(`${L3}/oauth/token`,{method:"POST",signal:AbortSignal.timeout(15000),headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:B.refreshToken,client_id:P3}).toString()});if(!Z.ok){let X=X0(Z.headers.get("retry-after"));throw Object.assign(Error(`Token refresh failed: ${Z.status}`),{status:Z.status,retryAfter:X,isRefreshError:!0})}let $=await Z.json();if(!$||typeof $.access_token!=="string"||!$.access_token||typeof $.expires_in!=="number")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});if($.refresh_token!==void 0&&typeof $.refresh_token!=="string")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});let W=typeof $.refresh_token==="string"&&$.refresh_token?$.refresh_token:B.refreshToken;return{access:$.access_token,refresh:W,expires:B.now()+$.expires_in*1000,expiresIn:$.expires_in}}var F3="https://chatgpt.com/backend-api/wham/usage";async function v6(B){let Z=B.logger??N3,$=B.accountKey??"unknown",W=Date.now();Z.debug("wham usage fetch started",{pid:process.pid,accountId:$});try{let X=await B.fetchImpl(F3,{signal:AbortSignal.timeout(15000),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(!X.ok){let K=X0(X.headers.get("retry-after"));throw Object.assign(Error(`wham usage check failed: ${X.status}`),{status:X.status,retryAfter:K})}let{normalizeWham:z}=await import("./quota-normalize-s27mex1w.js"),G=z(await X.json());return Z.debug("wham usage fetch succeeded",{pid:process.pid,accountId:$,status:X.status,elapsedMs:Date.now()-W}),G}catch(X){throw Z.warn("wham usage fetch failed",{pid:process.pid,accountId:$,status:typeof X?.status==="number"?X.status:"error",elapsedMs:Date.now()-W,error:_0(X)}),X}}import{createHash as O3}from"node:crypto";var V3=globalThis.setTimeout,b3=5;function p(B){let Z=B?.quota?.checkIntervalMinutes??b3;return Math.max(1,Z)*60000}function D3(B){return B?.quota?.enabled!==!1}function a(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function u6(B,Z,$,W,X){if(X!==void 0&&Number.isFinite(X)&&X>$)return X;let z=Z===z0?B?.primary:Z===K0?B?.secondary:void 0,G=z?.resetsAt?Date.parse(z.resetsAt):NaN;if(Number.isFinite(G)&&G>$)return G;return $+W}function U3(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function q0(B,Z,$){if(!D3(Z))return $+p(Z);let W=U3(Z),X=[];for(let z of["primary","secondary"]){let G=B?.[z];if(!G)continue;if(G.remainingPercent>=W[z])continue;let K=G.resetsAt?Date.parse(G.resetsAt):Number.NaN;if(!Number.isFinite(K)||K<=$)return $+p(Z);X.push(K)}if(!X.length)return $+p(Z);return Math.min(...X)+60000}function M3(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function _3(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function L(B){return O3("sha256").update(B).digest("hex").slice(0,16)}class D{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!==L(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)!==L(Z))return this.fallbacks.delete(B),this.fallbackTokenFps.delete(B),null;return $}getAllFallbacks(){return this.fallbacks}setMain(B,Z,$,W=!1){if(!W&&!C0(Z.quota))return;if(this.mainTokenFp=L(B),$&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==$)this.clearRateLimited("main");if($)this.mainQuotaAccountId=$;if(this.main=Z,Y0(Z.quota))this.clearRateLimited("main")}peekMainForPolicy(B){if(B&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==B)return null;return this.main}peekFallbackForPolicy(B,Z){let $=this.fallbacks.get(B)??null;if(Z&&$?.accountId&&$.accountId!==Z)return null;return $}setFallback(B,Z,$,W=!1,X){if(!W&&!C0(Z.quota))return;let z=this.fallbacks.get(B)?.accountId;if(X&&z&&X!==z)this.clearRateLimited(B);let G=X??z;if(this.fallbacks.set(B,{...Z,accountId:G}),$)this.fallbackTokenFps.set(B,L($));else this.fallbackTokenFps.delete(B);if(Y0(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=L(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 $=D.fallbackInflightKey(B,Z),W=this.inflightFallbacks.get($);if(W)return W;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 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 W=this.getFallback($.id,$.access);if(W&&Z<W.refreshAfter)continue;try{await this.refreshFallback($.id,$.access)}catch{}}}refreshMainInBackground(B){let Z=L(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=_3(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 $=M3(B);if(!$)return;let W=Z?L(Z):null;if(W&&$.tokenFingerprint&&$.tokenFingerprint!==W)return;let X={quota:$.quota,refreshAfter:q0($.quota,B,$.checkedAt),checkedAt:$.checkedAt};if(this.main&&this.main.checkedAt>=X.checkedAt&&(!W||!this.mainTokenFp||this.mainTokenFp===W))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&&x(Z,this.now())?Z:void 0}seedFallbacksFromAccounts(B){let Z=p(this.storage);for(let $ of B){if($.enabled===!1)continue;if(!$.quota)continue;let W=Math.max($.quota.primary?.checkedAt??0,$.quota.secondary?.checkedAt??0);if(W<=0)continue;let X=this.getFallback($.id,$.access);if(X&&X.checkedAt>=W)continue;this.setFallback($.id,{quota:$.quota,refreshAfter:W+Z,checkedAt:W},$.access,!1,$.accountId)}}isBackedOff(){return x(this.mainLastApiError,this.now())}isFallbackBackedOff(B,Z){if(Z){if(this.fallbackErrorTokenFps.get(B)!==L(Z))return!1}return x(this.fallbackApiErrors.get(B),this.now())}getLastApiError(){return this.mainLastApiError}static API_CALL_GAP_MS=1000;static fallbackInflightKey(B,Z){return JSON.stringify([B,L(Z)])}static quotaLockName(B){return`opencode-fallback-quota-refresh-${B.replace(/[^a-zA-Z0-9._-]+/g,"-")||"account"}`}_enqueueApiFetch(B){let Z=async()=>{let W=this.now()-this.lastApiCallAt;if(W<D.API_CALL_GAP_MS)await new Promise((X)=>{let z=V3(X,D.API_CALL_GAP_MS-W);if(typeof z==="object"&&"unref"in z)z.unref()});return this.lastApiCallAt=this.now(),B()},$=this.apiGate.then(Z,Z);return this.apiGate=$.catch(()=>{}),$}async _fetchMain(B){let Z=L(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 A({name:"opencode-main-quota-refresh",ttlMs:30000});if(!$){let W=this.main;if(W&&this.now()<W.refreshAfter)return W.quota;throw Error("Quota refresh is already in progress")}try{let W=this.now(),X=await this._fetchQuota(B),z=this.now();if(this.mainTokenFp=L(B),this.main={quota:X,refreshAfter:q0(X,this.storage,z),checkedAt:z},Y0(X))this.clearRateLimited("main");return this.mainLastApiError=void 0,this.onMainQuotaFetched?.(X,z,this.mainTokenFp,W),X}catch(W){throw this._handleMainFetchError(W),W}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 W=this.getFallback(B,Z);if(W)return W.quota;throw Error("Quota API rate-limited — try again later")}let $=await A({name:D.quotaLockName(B),ttlMs:30000});if(!$){let W=this.getFallback(B,Z);if(W&&this.now()<W.refreshAfter)return W.quota;throw Error("Quota refresh is already in progress")}try{let W=await this._fetchQuota(Z),X=this.now();return this.setFallback(B,{quota:W,refreshAfter:X+p(this.storage),checkedAt:X},Z,!0),this.fallbackApiErrors.delete(B),this.fallbackErrorTokenFps.delete(B),W}finally{await $.release()}}catch($){throw this._handleFallbackFetchError(B,Z,$),$}finally{this.inflightFallbacks.delete(D.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(D.isAuthError(B))return;this.mainLastApiError=m({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(D.isAuthError($))return;let W=L(Z),X=this.fallbackErrorTokenFps.get(B)===W?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,m({error:$,now:this.now(),previous:X})),this.fallbackErrorTokenFps.set(B,W)}}function C0(B){return Boolean(B.primary||B.secondary)}function Y0(B){let{primary:Z,secondary:$}=B;if(!Z&&!$)return!1;if(Z&&Z.usedPercent>=100)return!1;if($&&$.usedPercent>=100)return!1;return!0}import{createHash as T3,randomUUID as x3}from"node:crypto";import{setTimeout as A3}from"node:timers/promises";import{randomUUID as q3}from"node:crypto";import{mkdir as C3,rename as S3,rm as E3,writeFile as R3}from"node:fs/promises";import{dirname as y3}from"node:path";async function f(B,Z){await C3(y3(B),{recursive:!0});let $=`${B}.${q3()}.tmp`;await R3($,`${JSON.stringify(Z,null,2)}
88
- `,{encoding:"utf8",mode:384});try{await S3($,B)}catch(W){throw await E3($,{force:!0}).catch(()=>{}),W}}import{readFile as i3}from"node:fs/promises";var R=v("refresh"),t=v("accounts"),f3=1e4,I3=15000,j0=50;function U(B){return B.type==="oauth"}function m3(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 JB(B){return B.costZeroing?.enabled!==!1}class e extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var k3=[401,403,429],S0={primary:0,secondary:0},h3=!1,H0={primary:5,secondary:10};function J(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}var w3=new Set(["__proto__","constructor","prototype"]);function v3(B){return B.length>0&&!w3.has(B)}function p3(B){return B instanceof e||J(B)&&B.name==="AccountRemovedDuringRefreshError"&&B.code==="ACCOUNT_REMOVED_DURING_REFRESH"}function E0(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():x3(),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 R0(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),W=Number(B.retryCount);return{message:B.message,checkedAt:Z,nextRetryAt:Number.isFinite($)?$:void 0,retryCount:Number.isFinite(W)?W:void 0,tokenHash:typeof B.tokenHash==="string"?B.tokenHash:void 0}}function l3(B){if(!J(B))return;let Z={};for(let $ of["primary","secondary"]){let W=B[$];if(!J(W))continue;let X=Number(W.usedPercent),z=Number(W.remainingPercent),G=Number(W.checkedAt);if(!Number.isFinite(X)||!Number.isFinite(z)||!Number.isFinite(G))continue;let K=typeof W.windowMinutes==="number"?W.windowMinutes:Number.NaN;Z[$]={usedPercent:X,remainingPercent:z,checkedAt:G,resetsAt:typeof W.resetsAt==="string"?W.resetsAt:void 0,...Number.isFinite(K)&&K>0?{windowMinutes:K}:{}}}for(let $ of["resetCreditsAvailable","resetCreditsApplicable"]){let W=typeof B[$]==="number"?B[$]:Number.NaN;if(Number.isFinite(W)&&W>=0)Z[$]=W}return Object.keys(Z).length?Z:void 0}function g3(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(!m3(Z))return null;let W=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...E0(B),type:"api",apiKey:$||void 0,baseURL:Z,authHeader:W}}if(B.type!=="oauth")return null;if(typeof B.refresh!=="string"||!B.refresh.trim())return null;return{...E0(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:R0(B.lastRefreshError),lastQuotaRefreshError:R0(B.lastQuotaRefreshError),quota:l3(B.quota)}}function d3(B){if(!J(B))return;let Z=Object.create(null);for(let[$,W]of Object.entries(B)){if(!v3($)||!J(W))continue;let X={};if(J(W.inFlight))X.inFlight={...W.inFlight};if(J(W.lastOutcome)&&typeof W.lastOutcome.code==="string"&&W.lastOutcome.code.length>0&&typeof W.lastOutcome.at==="number"&&Number.isFinite(W.lastOutcome.at))X.lastOutcome={code:W.lastOutcome.code,at:W.lastOutcome.at,...J(W.lastOutcome.previousOutcome)&&typeof W.lastOutcome.previousOutcome.code==="string"&&W.lastOutcome.previousOutcome.code.length>0&&typeof W.lastOutcome.previousOutcome.at==="number"&&Number.isFinite(W.lastOutcome.previousOutcome.at)?{previousOutcome:{code:W.lastOutcome.previousOutcome.code,at:W.lastOutcome.previousOutcome.at}}:{}};if(typeof W.cooldownUntil==="number"&&Number.isFinite(W.cooldownUntil))X.cooldownUntil=W.cooldownUntil;if(Object.keys(X).length>0)Z[$]=X}return Object.keys(Z).length>0?Z:void 0}var y0=new Set;function f0(B){if(B.length===0)return;let Z=JSON.stringify([...B].sort());if(y0.has(Z))return;y0.add(Z),t.warn("account load-dropped, preserved on disk",{droppedIds:B})}function I0(B){if(!J(B)||!Array.isArray(B.accounts))return null;let Z=B.accounts,$=Z.map(g3).filter((W)=>W!=null);if($.length<Z.length){let W=new Set;for(let G of Z)if(J(G)&&typeof G.id==="string"&&G.id.trim())W.add(G.id.trim());let X=new Set($.map((G)=>G.id)),z=[];for(let G of W)if(!X.has(G))z.push(G);f0(z)}return{version:1,main:{type:"opencode",provider:"openai"},routing:J(B.routing)?B.routing:void 0,fallbackOn:Array.isArray(B.fallbackOn)?B.fallbackOn.filter((W)=>Number.isInteger(W)):void 0,refresh:J(B.refresh)?B.refresh:void 0,quota:J(B.quota)?B.quota:void 0,reset:d3(B.reset),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:$}}async function T(B){try{return{exists:!0,value:JSON.parse(await i3(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 u3(B){let Z;try{Z=(await T(B)).value}catch{return null}if(!J(Z)||!Array.isArray(Z.accounts))return null;let $=new Set;for(let W of Z.accounts){if(!J(W))continue;if(typeof W.id!=="string")continue;let X=W.id.trim();if(!X)continue;$.add(X)}return $}function m0(B,Z){if(!J(B))return B;let $=J(Z)?Z:{},W=J($.main)?$.main:void 0,X=J($.accounts)?$.accounts:{},z=J(B.quota)?B.quota:{},G=J(B.refresh)?B.refresh:{},K=W??z,Y=W??G,H=Array.isArray(B.accounts)?B.accounts.map((Q)=>{if(!J(Q))return Q;let b=typeof Q.id==="string"&&J(X[Q.id])?X[Q.id]:{};return{...Q,...b}}):void 0;return k0({...B,refresh:M({...G,mainLastRefreshError:Y.lastRefreshError,mainRefreshLeaseId:Y.refreshLeaseId,mainRefreshLeaseUntil:Y.refreshLeaseUntil,mainRefreshLeaseTokenHash:Y.refreshLeaseTokenHash}),quota:M({...z,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:H})}async function s3(B=I()){let Z=await T(B);if(!Z.exists)return null;let $=await T(u(B));return I0(m0(Z.value,$.value))}function k0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function r3(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 h0(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 B0(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function l(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function n3(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function c3(B,Z){if(!n3(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 o3(B,Z,$){let W=Z.lastRefreshedAt??0,X=$.lastRefreshedAt??0,z=Z.expires??0,G=$.expires??0,K=X>W?$:W>X?Z:G>z?$:z>G?Z:c3(Z,$);l(B,K,"access"),l(B,K,"refresh"),l(B,K,"expires"),l(B,K,"lastRefreshedAt"),l(B,K,"lastRefreshError")}function a3(B,Z){if(!J(B))return Z;let $=B,W=B0($.quota),X=B0(Z.quota),z=W>X,G=z?{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}:{...$,...Z};if(!z&&!("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 o3(G,$,Z),G}function w0(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 k0({version:1,main:B.main,routing:B.routing,fallbackOn:B.fallbackOn,refresh:Z,quota:$,reset:B.reset,dump:B.dump,costZeroing:B.costZeroing,killswitch:B.killswitch,logging:B.logging,cachekeep:B.cachekeep,mainAccountId:B.mainAccountId,accounts:B.accounts.map(r3)})}async function d(B){let Z=Date.now(),$=Z+I3,W=0;while(Date.now()<=$){W++;let G=await A({name:"save",ttlMs:f3,path:B});if(G)return G;let K=$-Date.now();if(K<=0)break;await A3(Math.min(j0+d0(j0),K))}let X=Date.now()-Z,z=Math.round(X/Math.max(1,W));throw Error(`Timed out after ${X}ms waiting for the account store lock on ${B} (${W} attempts, ~${z}ms apart; retry interval is ${j0}ms). A gap near the retry interval means lock contention; a much larger one means this process's event loop was saturated and the wait expired without getting scheduled.`)}function v0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,h0($)]));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}}function t3(B){if(!J(B)||!Array.isArray(B.accounts))return null;let Z=new Set;for(let $ of B.accounts){if(!J($))continue;if(typeof $.id!=="string")continue;let W=$.id.trim();if(!W)continue;Z.add(W)}return Z}function e3(B,Z,$,W){if(!J(B)||!Array.isArray(B.accounts))return{preservedRawEntries:[],preservedIds:[]};let X=[],z=[];for(let G of Z){if($.has(G))continue;if(W.has(G))continue;let K=B.accounts.find((Y)=>J(Y)&&typeof Y.id==="string"&&Y.id.trim()===G);if(!K)continue;X.push(K),z.push(G)}return{preservedRawEntries:X,preservedIds:z}}function B6(B){if(!Array.isArray(B))return[];let Z=[];for(let $ of B){if(!J($))continue;if(typeof $.id!=="string")continue;Z.push($.id)}return Z}function Z6(B,Z,$){let W=t3(B);if(W===null)return[];let{preservedRawEntries:X,preservedIds:z}=e3(B,W,Z,$);return f0(z),X}async function QB(B,Z=I(),$={}){let W=u(Z),X=await d(Z);try{let z=await d(W);try{let G=await T(Z),K=await T(W),Y=(G.exists?I0(m0(G.value,K.value)):null)??$6(),j=new Set(Y.accounts.map((O)=>O.id)),H=B(Y)??Y,Q=new Set($.allowDrop??[]),b=Z6(G.value,j,Q),N=w0(H),F=new Set((Array.isArray(N.accounts)?N.accounts:[]).map((O)=>J(O)&&typeof O.id==="string"?O.id.trim():"").filter(Boolean)),s=b.filter((O)=>{if(!J(O))return!1;if(typeof O.id!=="string")return!1;return!F.has(O.id.trim())}),Z0={...J(G.value)?G.value:{},...N,accounts:[...Array.isArray(N.accounts)?N.accounts:[],...s]};return await f(Z,Z0),await f(W,v0(H)),t.debug("account config written",{accountCount:Z0.accounts.length,accountIds:B6(Z0.accounts)}),H}finally{await z.release()}}finally{await X.release()}}function $6(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function W6(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:B0(B.main.quota),W=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:B0(Z.quota?.mainQuota);if($>W)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 X6(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 Q0(B){if(Array.isArray(B))return B.map(Q0);if(!J(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,Q0($)]))}async function G6(B,Z=I(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let W=u(Z),X=await d(W);try{let z=(await T(W)).value,G=J(z)?{...z,version:1}:{version:1};if($.mainQuota)W6(G,B);if($.mainRefresh)X6(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await u3(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]=a3(G.accounts[j.id],h0(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 f(W,Q0(G))}finally{await X.release()}}function z6(B){return B?.fallbackOn?.length?B.fallbackOn:k3}function NB(B,Z){return z6(Z).includes(B)}function K6(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??S0.primary,secondary:Z.secondary??Z["1w"]??S0.secondary}}function N0(B){return B?.quota?.enabled!==!1}function i(B){return B?.quota?.failClosedOnUnknownQuota??h3}function p0(B,Z,$=Date.now()){if(!N0(Z))return!0;if(!B)return!i(Z);let W=K6(Z),X=i(Z);for(let z of["primary","secondary"]){let G=B[z];if(!G)continue;if(a(G,$)){if(X)return!1;continue}if(G.remainingPercent<W[z])return!1}return!0}function l0(B){return B?.killswitch?.enabled===!0}function T0(B){return{primary:B?.primary??B?.["5h"]??H0.primary,secondary:B?.secondary??B?.["1w"]??H0.secondary}}function g0(B,Z){if(!B?.killswitch)return H0;if(Z&&B.killswitch.accounts?.[Z])return T0(B.killswitch.accounts[Z]);return T0(B.killswitch.main)}function PB(B,Z,$,W=Date.now()){if(!l0(Z))return!0;if(!B)return!i(Z);let X=g0(Z,$),z=i(Z);for(let G of["primary","secondary"]){let K=B[G];if(!K)continue;if(a(K,W)){if(z)return!1;continue}if(K.remainingPercent<X[G])return!1}return!0}function LB(B,Z,$,W){if(!l0(W))return 300;let X=[],z=[{accountId:void 0,quota:B},...Z];for(let{accountId:K,quota:Y}of z){if(!Y)continue;let j=g0(W,K),H=[],Q=!1;for(let b of["primary","secondary"]){let N=Y[b];if(!N||a(N,$))continue;if(N.remainingPercent>=j[b])continue;let F=N.resetsAt?Date.parse(N.resetsAt):NaN;if(!Number.isFinite(F)||F<=$){Q=!0;break}H.push(F)}if(Q||H.length===0)continue;X.push(Math.max(...H))}if(X.length===0)return 300;let G=Math.min(...X);return Math.max(1,Math.ceil((G-$)/1000))}function Y6(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function FB(B,Z=I()){let $=u(Z),W=await d(Z);try{let X=await d($);try{let z=await T(Z);if(z.exists&&J(z.value)){if(Y6(z.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let j=c({id_token:"",access_token:B.access,refresh_token:B.refresh});if(j)G.mainAccountId=j}let Y={...z.exists&&J(z.value)?z.value:{},...w0(G)};await f(Z,Y),await f($,v0(G))}finally{await X.release()}}finally{await W.release()}}function j6(B){return B?.refresh?.enabled!==!1}function J6(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function d0(B){return Math.floor(Math.random()*(B+1))}function y(B,Z,$){return!B.access||!B.expires||B.expires-$<=J6(Z)}function H6(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function Q6(B,Z){return Boolean(B.mainAccountId&&Z.accountId&&Z.accountId===B.mainAccountId)}function P(B,Z){let $=B.accounts.findIndex((W)=>W.id===Z.id);if($!==-1)B.accounts[$]=Z}function g(B){return B instanceof Error?B.message:String(B)}function P0(B,Z,$){B.lastRefreshError=F0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function J0(B,Z,$){if(B.lastQuotaRefreshError=m({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)P0(B,Z,$)}function N6(B){return`fallback-oauth-refresh-${T3("sha256").update(B).digest("base64url").slice(0,16)}`}function x0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function P6(B,Z){if(!B)return!1;return x0(B.primary,Z)||x0(B.secondary,Z)}function L6(B,Z,$){if(!B)return!1;let W=Z?.quota?.checkIntervalMinutes??5,X=Math.max(1,W)*60000,z=Math.max(B.primary?.checkedAt??0,B.secondary?.checkedAt??0);return $-z<X}function A0(B,Z,$){return!L6(B.quota,Z,$)}function F6(B,Z,$,W){return W0($)&&p0(B.quota,Z,W)&&P6(B.quota,W)}function O6(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var V6=60000,b6=60000,D6=600000,U6=1e4,M6=100;var OB=globalThis.setTimeout.bind(globalThis),VB=globalThis.clearTimeout.bind(globalThis);class _6{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??I(),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.primary?.checkedAt??0,B.quota.secondary?.checkedAt??0);if($<=0)return;let W=this.quotaManager.getFallback(B.id,B.access);if(W&&W.checkedAt>=$)return;this.quotaManager.setFallback(B.id,{quota:B.quota,refreshAfter:$+O6(Z),checkedAt:$},B.access,!1,B.accountId)}async load(){return s3(this.configPath)}async save(B,Z){await G6(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(()=>{})},V6+d0(b6)),"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 $=[],W=!1;for(let X of Z.accounts){if(X.enabled===!1||!U(X))continue;if(Q6(Z,X))continue;let z=!1,G=X;try{if(y(G,Z,this.now())){let K=G.lastRefreshError;if(K&&_(K,G.refresh,this.now()))throw z=!0,Error(r(K,this.now()));try{G=await this.refreshAccount(G,Z),W=!0}catch(Y){if(p3(Y))continue;z=!0;let j=Z.accounts.find((H)=>H.id===X.id&&U(H));if(j&&!_(j.lastRefreshError,j.refresh,this.now()))P0(j,Y,this.now()),P(Z,j),W=!0;throw Y}}if(this.seedFallbackQuota(G,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(G),Z))$.push(G)}catch(K){let Y=H6(G,this.now());if(z){if(!Y)continue}else if(!Y)continue;if(F6(G,Z,K,this.now()))R.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:g(K)}),$.push(G);else if(!i(Z))$.push(G)}}if(W)try{await this.save(Z)}catch(X){t.warn("fallback selection bookkeeping not persisted",{pid:process.pid,error:g(X)})}return $}async markUsed(B){try{let Z=await this.load();if(!Z)return;let $=Z.accounts.find((W)=>W.id===B.id);if(!$)return;$.lastUsed=this.now(),await this.save(Z,[$.id])}catch(Z){t.warn("lastUsed stamp not persisted",{pid:process.pid,accountId:B.id,error:g(Z)})}}accountPassesQuotaPolicy(B,Z){return p0(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||!j6(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;if(!y($,B,this.now()))continue;if(_($.lastRefreshError,$.refresh,this.now()))continue;try{R.debug("fallback oauth background due",{pid:process.pid,accountId:$.id,expiresInMs:$.expires?$.expires-this.now():void 0}),await this.refreshAccount($,B),Z=!0}catch(W){R.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:g(W)}),P0($,W,this.now()),P(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!N0(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;let W=$;try{if(y(W,B,this.now())){if(_(W.lastRefreshError,W.refresh,this.now()))continue;W=await this.refreshAccount(W,B),Z=!0}if(x(W.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota(W,B),!(this.quotaManager?this.quotaManager.isFallbackStale(W.id,W.access):A0(W,B,this.now())))continue;await this.refreshAccountQuota(W,B),Z=!0}catch(X){J0($,X,this.now()),P(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!N0(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let W=B.force??!1,X=!1;for(let z of Z.accounts){if(z.enabled===!1||!U(z))continue;let G=z;try{if(y(G,Z,this.now())){let K=G.lastRefreshError;if(K&&_(K,G.refresh,this.now()))throw Error(r(K,this.now()));G=await this.refreshAccount(G,Z),X=!0}if(!W&&!A0(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,P(Z,G),X=!0;continue}await this.refreshAccountQuota(G,Z),X=!0}catch(K){J0(z,K,this.now()),P(Z,z),X=!0,$.push({accountId:z.id,message:g(K)})}}if(X)await this.save(Z);return{storage:Z,errors:$}}async refreshAccount(B,Z,$={}){let W=this.refreshPromises.get(B.id);if(W){let G=await W;return P(Z,G),G}let X=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,X);let z=await X;return P(Z,z),z}async waitForConcurrentFallbackRefresh(B,Z,$,W){let X=Date.now()+U6;while(Date.now()<X){await new Promise((j)=>setTimeout(j,M6));let z=await this.load(),G=z?.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)&&(W.force||!y(G,z,this.now())))return P(Z,G),R.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&&_(Y,G.refresh,this.now()))throw P(Z,G),Error(r(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let W=await this.load(),X=W?.accounts.find((K)=>K.id===B.id&&U(K));if(X&&!$.force&&!y(X,W,this.now()))return P(Z,X),X;let z=X??B,G=await A({name:N6(z.id),ttlMs:D6,path:this.configPath,now:this.now,renew:!0});if(!G){R.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:z.id});let K=await this.waitForConcurrentFallbackRefresh(B,Z,z,$);if(K)return K;throw Error("Fallback OAuth refresh is already in progress")}try{if(W=await this.load(),X=W?.accounts.find((H)=>H.id===B.id&&U(H)),X&&!$.force&&!y(X,W,this.now()))return P(Z,X),X;if(!X)throw new e(B.id);z=X;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});R.debug("fallback oauth refresh request start",{pid:process.pid,accountId:z.id,force:$.force===!0,expiresInMs:z.expires?z.expires-this.now():void 0});let Y=await K({refreshToken:z.refresh,fetchImpl:this.fetchImpl,now:this.now});if(z.access=Y.access,z.refresh=Y.refresh,z.expires=Y.expires,z.lastRefreshedAt=Y.expires-Y.expiresIn*1000,z.lastRefreshError=void 0,P(Z,z),await this.save(Z),!(await this.load())?.accounts.some((H)=>H.id===B.id))throw new e(B.id);return R.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:z.id,expiresInMs:z.expires?z.expires-this.now():void 0}),z}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 W=this.options.fetchQuotaFn??(async()=>{throw Error("No fetchQuotaFn injected — wham/usage supplement is disabled")}),X=(z)=>this.quotaManager?this.quotaManager.refreshFallback($.id,z):W({accessToken:z,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let z=await X($.access);$.quota=z,$.lastQuotaRefreshError=void 0,P(Z,$),await this.save(Z)}catch(z){throw J0(B,z,this.now()),P(Z,B),z}}}
89
- export{L0 as h,F0 as i,_ as j,r as k,D0 as l,M0 as m,$3 as n,V0 as o,b0 as p,c as q,G0 as r,X3 as s,E as t,Y3 as u,j3 as v,J3 as w,H3 as x,x6 as y,A6 as z,_0 as A,w6 as B,v6 as C,u6 as D,D as E,U as F,JB as G,H0 as H,v3 as I,u3 as J,s3 as K,QB as L,NB as M,l0 as N,g0 as O,PB as P,LB as Q,FB as R,_6 as S};
87
+ </html>`,w,h,V=new Map;function q(){return V.size}function E(B){if(V.delete(B),q()===0)C()}async function Y4(){let B=`http://localhost:${k}/auth/callback`;if(w)return{port:k,redirectUri:B};if(h)return h;h=(async()=>{let Z=t0(($,W)=>{let X=new URL($.url||"/",`http://127.0.0.1:${k}`);if(X.pathname==="/auth/callback"){let z=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 Q=V.get(G);if(Q)Q.reject(Error(H)),E(G);else if(q()===0)C()}else if(q()===0)C();W.writeHead(200,{"Content-Type":"text/html"}),W.end(n(H));return}if(!G){if(q()===0)C();W.writeHead(400,{"Content-Type":"text/html"}),W.end(n("Missing state parameter"));return}if(!z){if(q()===0)C();W.writeHead(400,{"Content-Type":"text/html"}),W.end(n("Missing authorization code"));return}let j=V.get(G);if(!j){if(q()===0)C();W.writeHead(400,{"Content-Type":"text/html"}),W.end(n("Unknown state — authorization may have expired"));return}E(G),G4(z,B,j.pkce).then((H)=>j.resolve(H)).catch((H)=>j.reject(H)),W.writeHead(200,{"Content-Type":"text/html"}),W.end(K4);return}if(X.pathname==="/cancel"){let z=X.searchParams.get("state"),G=z?[z]:[...V.keys()];W.writeHead(200),W.end("Login cancelled");for(let K of G){let Y=V.get(K);if(!Y)continue;Y.reject(Error("Login cancelled")),E(K)}if(q()===0)C();return}W.writeHead(404),W.end("Not found")});return await new Promise(($,W)=>{Z.once("error",W),Z.listen(k,"127.0.0.1",()=>{Z.off("error",W),$()})}),w=Z,{port:k,redirectUri:B}})();try{return await h}finally{h=void 0}}function C(){if(w){let B=w;w=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function j4(B,Z,$=300000,W){return new Promise((X,z)=>{if(W?.aborted){E(Z),z(Error("Login cancelled"));return}let G=setTimeout(()=>{if(V.get(Z))E(Z),z(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),V.get(Z))E(Z),z(Error("Login cancelled"))};if(W)W.addEventListener("abort",K);V.set(Z,{pkce:B,state:Z,resolve:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);X(Y)},reject:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);z(Y)}})})}async function J4(){let B=await fetch(`${S}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":D0},body:JSON.stringify({client_id:o})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${S}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function H4(B,Z){let $=Math.max(parseInt(B.interval,10)||5,1)*1000,W=typeof B.expires_in==="number"?B.expires_in:parseInt(B.expires_in||"",10),X=!Number.isNaN(W)&&W>0?W*1000:900000,z=Date.now();while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");if(Date.now()-z>X)throw Error("Device authorization expired");let G=await fetch(`${S}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":D0},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(`${S}/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:`${S}/deviceauth/callback`,client_id:o,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()-z);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+B4,K);try{await e0(Y,void 0,{signal:Z})}catch(j){if(j instanceof Error&&j.name==="AbortError")throw Error("Device authorization cancelled");throw j}}}function x6(B,Z){let $=-1;if(Z.accountId)$=B.findIndex((W)=>W.accountId&&W.accountId===Z.accountId);if($<0)$=B.findIndex((W)=>W.id===Z.id);if($<0&&Z.label&&!Z.accountId)$=B.findIndex((W)=>W.label===Z.label);if($>=0)return B[$]={...B[$],...Z,addedAt:B[$]?.addedAt??Z.addedAt},$;return B.push(Z),B.length-1}async function A6(B={}){let{label:Z,headless:$=!1,signal:W}=B;if(G0(Z),$){let{deviceData:j,url:H,instructions:Q}=await J4(),b=(async()=>{let N=await H4(j,W),F=Date.now(),s=c(N);return{id:G0(Z||s||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:N.access_token,refresh:N.refresh_token,expires:F+(N.expires_in??3600)*1000,enabled:!0,addedAt:F,lastUsed:F,lastRefreshedAt:F,accountId:s}})();return{url:H,instructions:Q,completion:b}}let{redirectUri:X}=await Y4(),z=await $4(),G=M0(crypto.getRandomValues(new Uint8Array(32)).buffer),K=X4(X,z,G),Y=(async()=>{try{if(W?.aborted)throw Error("Login cancelled");let j=await j4(z,G,void 0,W),H=Date.now(),Q=c(j);return{id:G0(Z||Q||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:Q}}finally{E(G)}})();return{url:K,instructions:"Complete authorization in your browser. This window will close automatically.",completion:Y}}function _0(B){if(B instanceof Error)return B.message;if(typeof B==="string")return B;try{return JSON.stringify(B)}catch{return String(B)}}var N4=v("quota"),z0="primary",K0="secondary",P4="app_EMoamEEZ73f0CkXaXp7hrann",L4="https://auth.openai.com";async function w6(B){let Z=await B.fetchImpl(`${L4}/oauth/token`,{method:"POST",signal:AbortSignal.timeout(15000),headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"refresh_token",refresh_token:B.refreshToken,client_id:P4}).toString()});if(!Z.ok){let X=X0(Z.headers.get("retry-after"));throw Object.assign(Error(`Token refresh failed: ${Z.status}`),{status:Z.status,retryAfter:X,isRefreshError:!0})}let $=await Z.json();if(!$||typeof $.access_token!=="string"||!$.access_token||typeof $.expires_in!=="number")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});if($.refresh_token!==void 0&&typeof $.refresh_token!=="string")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});let W=typeof $.refresh_token==="string"&&$.refresh_token?$.refresh_token:B.refreshToken;return{access:$.access_token,refresh:W,expires:B.now()+$.expires_in*1000,expiresIn:$.expires_in}}var F4="https://chatgpt.com/backend-api/wham/usage";async function v6(B){let Z=B.logger??N4,$=B.accountKey??"unknown",W=Date.now();Z.debug("wham usage fetch started",{pid:process.pid,accountId:$});try{let X=await B.fetchImpl(F4,{signal:AbortSignal.timeout(15000),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(!X.ok){let K=X0(X.headers.get("retry-after"));throw Object.assign(Error(`wham usage check failed: ${X.status}`),{status:X.status,retryAfter:K})}let{normalizeWham:z}=await import("./quota-normalize-s27mex1w.js"),G=z(await X.json());return Z.debug("wham usage fetch succeeded",{pid:process.pid,accountId:$,status:X.status,elapsedMs:Date.now()-W}),G}catch(X){throw Z.warn("wham usage fetch failed",{pid:process.pid,accountId:$,status:typeof X?.status==="number"?X.status:"error",elapsedMs:Date.now()-W,error:_0(X)}),X}}import{createHash as O4}from"node:crypto";var V4=globalThis.setTimeout,b4=5;function p(B){let Z=B?.quota?.checkIntervalMinutes??b4;return Math.max(1,Z)*60000}function D4(B){return B?.quota?.enabled!==!1}function a(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function u6(B,Z,$,W,X){if(X!==void 0&&Number.isFinite(X)&&X>$)return X;let z=Z===z0?B?.primary:Z===K0?B?.secondary:void 0,G=z?.resetsAt?Date.parse(z.resetsAt):NaN;if(Number.isFinite(G)&&G>$)return G;return $+W}function U4(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function q0(B,Z,$){if(!D4(Z))return $+p(Z);let W=U4(Z),X=[];for(let z of["primary","secondary"]){let G=B?.[z];if(!G)continue;if(G.remainingPercent>=W[z])continue;let K=G.resetsAt?Date.parse(G.resetsAt):Number.NaN;if(!Number.isFinite(K)||K<=$)return $+p(Z);X.push(K)}if(!X.length)return $+p(Z);return Math.min(...X)+60000}function M4(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function _4(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function L(B){return O4("sha256").update(B).digest("hex").slice(0,16)}class D{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!==L(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)!==L(Z))return this.fallbacks.delete(B),this.fallbackTokenFps.delete(B),null;return $}getAllFallbacks(){return this.fallbacks}setMain(B,Z,$,W=!1){if(!W&&!C0(Z.quota))return;if(this.mainTokenFp=L(B),$&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==$)this.clearRateLimited("main");if($)this.mainQuotaAccountId=$;if(this.main=Z,Y0(Z.quota))this.clearRateLimited("main")}peekMainForPolicy(B){if(B&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==B)return null;return this.main}peekFallbackForPolicy(B,Z){let $=this.fallbacks.get(B)??null;if(Z&&$?.accountId&&$.accountId!==Z)return null;return $}setFallback(B,Z,$,W=!1,X){if(!W&&!C0(Z.quota))return;let z=this.fallbacks.get(B)?.accountId;if(X&&z&&X!==z)this.clearRateLimited(B);let G=X??z;if(this.fallbacks.set(B,{...Z,accountId:G}),$)this.fallbackTokenFps.set(B,L($));else this.fallbackTokenFps.delete(B);if(Y0(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=L(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 $=D.fallbackInflightKey(B,Z),W=this.inflightFallbacks.get($);if(W)return W;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 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 W=this.getFallback($.id,$.access);if(W&&Z<W.refreshAfter)continue;try{await this.refreshFallback($.id,$.access)}catch{}}}refreshMainInBackground(B){let Z=L(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=_4(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 $=M4(B);if(!$)return;let W=Z?L(Z):null;if(W&&$.tokenFingerprint&&$.tokenFingerprint!==W)return;let X={quota:$.quota,refreshAfter:q0($.quota,B,$.checkedAt),checkedAt:$.checkedAt};if(this.main&&this.main.checkedAt>=X.checkedAt&&(!W||!this.mainTokenFp||this.mainTokenFp===W))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&&x(Z,this.now())?Z:void 0}seedFallbacksFromAccounts(B){let Z=p(this.storage);for(let $ of B){if($.enabled===!1)continue;if(!$.quota)continue;let W=Math.max($.quota.primary?.checkedAt??0,$.quota.secondary?.checkedAt??0);if(W<=0)continue;let X=this.getFallback($.id,$.access);if(X&&X.checkedAt>=W)continue;this.setFallback($.id,{quota:$.quota,refreshAfter:W+Z,checkedAt:W},$.access,!1,$.accountId)}}isBackedOff(){return x(this.mainLastApiError,this.now())}isFallbackBackedOff(B,Z){if(Z){if(this.fallbackErrorTokenFps.get(B)!==L(Z))return!1}return x(this.fallbackApiErrors.get(B),this.now())}getLastApiError(){return this.mainLastApiError}static API_CALL_GAP_MS=1000;static fallbackInflightKey(B,Z){return JSON.stringify([B,L(Z)])}static quotaLockName(B){return`opencode-fallback-quota-refresh-${B.replace(/[^a-zA-Z0-9._-]+/g,"-")||"account"}`}_enqueueApiFetch(B){let Z=async()=>{let W=this.now()-this.lastApiCallAt;if(W<D.API_CALL_GAP_MS)await new Promise((X)=>{let z=V4(X,D.API_CALL_GAP_MS-W);if(typeof z==="object"&&"unref"in z)z.unref()});return this.lastApiCallAt=this.now(),B()},$=this.apiGate.then(Z,Z);return this.apiGate=$.catch(()=>{}),$}async _fetchMain(B){let Z=L(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 A({name:"opencode-main-quota-refresh",ttlMs:30000});if(!$){let W=this.main;if(W&&this.now()<W.refreshAfter)return W.quota;throw Error("Quota refresh is already in progress")}try{let W=this.now(),X=await this._fetchQuota(B),z=this.now();if(this.mainTokenFp=L(B),this.main={quota:X,refreshAfter:q0(X,this.storage,z),checkedAt:z},Y0(X))this.clearRateLimited("main");return this.mainLastApiError=void 0,this.onMainQuotaFetched?.(X,z,this.mainTokenFp,W),X}catch(W){throw this._handleMainFetchError(W),W}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 W=this.getFallback(B,Z);if(W)return W.quota;throw Error("Quota API rate-limited — try again later")}let $=await A({name:D.quotaLockName(B),ttlMs:30000});if(!$){let W=this.getFallback(B,Z);if(W&&this.now()<W.refreshAfter)return W.quota;throw Error("Quota refresh is already in progress")}try{let W=await this._fetchQuota(Z),X=this.now();return this.setFallback(B,{quota:W,refreshAfter:X+p(this.storage),checkedAt:X},Z,!0),this.fallbackApiErrors.delete(B),this.fallbackErrorTokenFps.delete(B),W}finally{await $.release()}}catch($){throw this._handleFallbackFetchError(B,Z,$),$}finally{this.inflightFallbacks.delete(D.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(D.isAuthError(B))return;this.mainLastApiError=m({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(D.isAuthError($))return;let W=L(Z),X=this.fallbackErrorTokenFps.get(B)===W?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,m({error:$,now:this.now(),previous:X})),this.fallbackErrorTokenFps.set(B,W)}}function C0(B){return Boolean(B.primary||B.secondary)}function Y0(B){let{primary:Z,secondary:$}=B;if(!Z&&!$)return!1;if(Z&&Z.usedPercent>=100)return!1;if($&&$.usedPercent>=100)return!1;return!0}import{createHash as T4,randomUUID as x4}from"node:crypto";import{setTimeout as A4}from"node:timers/promises";import{randomUUID as q4}from"node:crypto";import{mkdir as C4,rename as S4,rm as E4,writeFile as R4}from"node:fs/promises";import{dirname as y4}from"node:path";async function f(B,Z){await C4(y4(B),{recursive:!0});let $=`${B}.${q4()}.tmp`;await R4($,`${JSON.stringify(Z,null,2)}
88
+ `,{encoding:"utf8",mode:384});try{await S4($,B)}catch(W){throw await E4($,{force:!0}).catch(()=>{}),W}}import{readFile as i4}from"node:fs/promises";var R=v("refresh"),t=v("accounts"),f4=1e4,I4=15000,j0=50;function U(B){return B.type==="oauth"}function m4(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 JB(B){return B.costZeroing?.enabled!==!1}class e extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var k4=[401,403,429],S0={primary:0,secondary:0},h4=!1,H0={primary:5,secondary:10};function J(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}var w4=new Set(["__proto__","constructor","prototype"]);function v4(B){return B.length>0&&!w4.has(B)}function p4(B){return B instanceof e||J(B)&&B.name==="AccountRemovedDuringRefreshError"&&B.code==="ACCOUNT_REMOVED_DURING_REFRESH"}function E0(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():x4(),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 R0(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),W=Number(B.retryCount);return{message:B.message,checkedAt:Z,nextRetryAt:Number.isFinite($)?$:void 0,retryCount:Number.isFinite(W)?W:void 0,tokenHash:typeof B.tokenHash==="string"?B.tokenHash:void 0}}function l4(B){if(!J(B))return;let Z={};for(let $ of["primary","secondary"]){let W=B[$];if(!J(W))continue;let X=Number(W.usedPercent),z=Number(W.remainingPercent),G=Number(W.checkedAt);if(!Number.isFinite(X)||!Number.isFinite(z)||!Number.isFinite(G))continue;let K=typeof W.windowMinutes==="number"?W.windowMinutes:Number.NaN;Z[$]={usedPercent:X,remainingPercent:z,checkedAt:G,resetsAt:typeof W.resetsAt==="string"?W.resetsAt:void 0,...Number.isFinite(K)&&K>0?{windowMinutes:K}:{}}}for(let $ of["resetCreditsAvailable","resetCreditsApplicable"]){let W=typeof B[$]==="number"?B[$]:Number.NaN;if(Number.isFinite(W)&&W>=0)Z[$]=W}return Object.keys(Z).length?Z:void 0}function g4(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(!m4(Z))return null;let W=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...E0(B),type:"api",apiKey:$||void 0,baseURL:Z,authHeader:W}}if(B.type!=="oauth")return null;if(typeof B.refresh!=="string"||!B.refresh.trim())return null;return{...E0(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:R0(B.lastRefreshError),lastQuotaRefreshError:R0(B.lastQuotaRefreshError),quota:l4(B.quota)}}function d4(B){if(!J(B))return;let Z=Object.create(null);for(let[$,W]of Object.entries(B)){if(!v4($)||!J(W))continue;let X={};if(J(W.inFlight))X.inFlight={...W.inFlight};if(J(W.lastOutcome)&&typeof W.lastOutcome.code==="string"&&W.lastOutcome.code.length>0&&typeof W.lastOutcome.at==="number"&&Number.isFinite(W.lastOutcome.at))X.lastOutcome={code:W.lastOutcome.code,at:W.lastOutcome.at,...J(W.lastOutcome.previousOutcome)&&typeof W.lastOutcome.previousOutcome.code==="string"&&W.lastOutcome.previousOutcome.code.length>0&&typeof W.lastOutcome.previousOutcome.at==="number"&&Number.isFinite(W.lastOutcome.previousOutcome.at)?{previousOutcome:{code:W.lastOutcome.previousOutcome.code,at:W.lastOutcome.previousOutcome.at}}:{}};if(typeof W.cooldownUntil==="number"&&Number.isFinite(W.cooldownUntil))X.cooldownUntil=W.cooldownUntil;if(Object.keys(X).length>0)Z[$]=X}return Object.keys(Z).length>0?Z:void 0}var y0=new Set;function f0(B){if(B.length===0)return;let Z=JSON.stringify([...B].sort());if(y0.has(Z))return;y0.add(Z),t.warn("account load-dropped, preserved on disk",{droppedIds:B})}function I0(B){if(!J(B)||!Array.isArray(B.accounts))return null;let Z=B.accounts,$=Z.map(g4).filter((W)=>W!=null);if($.length<Z.length){let W=new Set;for(let G of Z)if(J(G)&&typeof G.id==="string"&&G.id.trim())W.add(G.id.trim());let X=new Set($.map((G)=>G.id)),z=[];for(let G of W)if(!X.has(G))z.push(G);f0(z)}return{version:1,main:{type:"opencode",provider:"openai"},routing:J(B.routing)?B.routing:void 0,fallbackOn:Array.isArray(B.fallbackOn)?B.fallbackOn.filter((W)=>Number.isInteger(W)):void 0,refresh:J(B.refresh)?B.refresh:void 0,quota:J(B.quota)?B.quota:void 0,reset:d4(B.reset),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:$}}async function T(B){try{return{exists:!0,value:JSON.parse(await i4(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 u4(B){let Z;try{Z=(await T(B)).value}catch{return null}if(!J(Z)||!Array.isArray(Z.accounts))return null;let $=new Set;for(let W of Z.accounts){if(!J(W))continue;if(typeof W.id!=="string")continue;let X=W.id.trim();if(!X)continue;$.add(X)}return $}function m0(B,Z){if(!J(B))return B;let $=J(Z)?Z:{},W=J($.main)?$.main:void 0,X=J($.accounts)?$.accounts:{},z=J(B.quota)?B.quota:{},G=J(B.refresh)?B.refresh:{},K=W??z,Y=W??G,H=Array.isArray(B.accounts)?B.accounts.map((Q)=>{if(!J(Q))return Q;let b=typeof Q.id==="string"&&J(X[Q.id])?X[Q.id]:{};return{...Q,...b}}):void 0;return k0({...B,refresh:M({...G,mainLastRefreshError:Y.lastRefreshError,mainRefreshLeaseId:Y.refreshLeaseId,mainRefreshLeaseUntil:Y.refreshLeaseUntil,mainRefreshLeaseTokenHash:Y.refreshLeaseTokenHash}),quota:M({...z,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:H})}async function s4(B=I()){let Z=await T(B);if(!Z.exists)return null;let $=await T(u(B));return I0(m0(Z.value,$.value))}function k0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function r4(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 h0(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 B0(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function l(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function n4(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function c4(B,Z){if(!n4(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 o4(B,Z,$){let W=Z.lastRefreshedAt??0,X=$.lastRefreshedAt??0,z=Z.expires??0,G=$.expires??0,K=X>W?$:W>X?Z:G>z?$:z>G?Z:c4(Z,$);l(B,K,"access"),l(B,K,"refresh"),l(B,K,"expires"),l(B,K,"lastRefreshedAt"),l(B,K,"lastRefreshError")}function a4(B,Z){if(!J(B))return Z;let $=B,W=B0($.quota),X=B0(Z.quota),z=W>X,G=z?{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}:{...$,...Z};if(!z&&!("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 o4(G,$,Z),G}function w0(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 k0({version:1,main:B.main,routing:B.routing,fallbackOn:B.fallbackOn,refresh:Z,quota:$,reset:B.reset,dump:B.dump,costZeroing:B.costZeroing,killswitch:B.killswitch,logging:B.logging,cachekeep:B.cachekeep,mainAccountId:B.mainAccountId,accounts:B.accounts.map(r4)})}async function d(B){let Z=Date.now(),$=Z+I4,W=0;while(Date.now()<=$){W++;let G=await A({name:"save",ttlMs:f4,path:B});if(G)return G;let K=$-Date.now();if(K<=0)break;await A4(Math.min(j0+d0(j0),K))}let X=Date.now()-Z,z=Math.round(X/Math.max(1,W));throw Error(`Timed out after ${X}ms waiting for the account store lock on ${B} (${W} attempts, ~${z}ms apart; retry interval is ${j0}ms). A gap near the retry interval means lock contention; a much larger one means this process's event loop was saturated and the wait expired without getting scheduled.`)}function v0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,h0($)]));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}}function t4(B){if(!J(B)||!Array.isArray(B.accounts))return null;let Z=new Set;for(let $ of B.accounts){if(!J($))continue;if(typeof $.id!=="string")continue;let W=$.id.trim();if(!W)continue;Z.add(W)}return Z}function e4(B,Z,$,W){if(!J(B)||!Array.isArray(B.accounts))return{preservedRawEntries:[],preservedIds:[]};let X=[],z=[];for(let G of Z){if($.has(G))continue;if(W.has(G))continue;let K=B.accounts.find((Y)=>J(Y)&&typeof Y.id==="string"&&Y.id.trim()===G);if(!K)continue;X.push(K),z.push(G)}return{preservedRawEntries:X,preservedIds:z}}function B6(B){if(!Array.isArray(B))return[];let Z=[];for(let $ of B){if(!J($))continue;if(typeof $.id!=="string")continue;Z.push($.id)}return Z}function Z6(B,Z,$){let W=t4(B);if(W===null)return[];let{preservedRawEntries:X,preservedIds:z}=e4(B,W,Z,$);return f0(z),X}async function QB(B,Z=I(),$={}){let W=u(Z),X=await d(Z);try{let z=await d(W);try{let G=await T(Z),K=await T(W),Y=(G.exists?I0(m0(G.value,K.value)):null)??$6(),j=new Set(Y.accounts.map((O)=>O.id)),H=B(Y)??Y,Q=new Set($.allowDrop??[]),b=Z6(G.value,j,Q),N=w0(H),F=new Set((Array.isArray(N.accounts)?N.accounts:[]).map((O)=>J(O)&&typeof O.id==="string"?O.id.trim():"").filter(Boolean)),s=b.filter((O)=>{if(!J(O))return!1;if(typeof O.id!=="string")return!1;return!F.has(O.id.trim())}),Z0={...J(G.value)?G.value:{},...N,accounts:[...Array.isArray(N.accounts)?N.accounts:[],...s]};return await f(Z,Z0),await f(W,v0(H)),t.debug("account config written",{accountCount:Z0.accounts.length,accountIds:B6(Z0.accounts)}),H}finally{await z.release()}}finally{await X.release()}}function $6(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function W6(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:B0(B.main.quota),W=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:B0(Z.quota?.mainQuota);if($>W)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 X6(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 Q0(B){if(Array.isArray(B))return B.map(Q0);if(!J(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,Q0($)]))}async function G6(B,Z=I(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let W=u(Z),X=await d(W);try{let z=(await T(W)).value,G=J(z)?{...z,version:1}:{version:1};if($.mainQuota)W6(G,B);if($.mainRefresh)X6(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await u4(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]=a4(G.accounts[j.id],h0(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 f(W,Q0(G))}finally{await X.release()}}function z6(B){return B?.fallbackOn?.length?B.fallbackOn:k4}function NB(B,Z){return z6(Z).includes(B)}function K6(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??S0.primary,secondary:Z.secondary??Z["1w"]??S0.secondary}}function N0(B){return B?.quota?.enabled!==!1}function i(B){return B?.quota?.failClosedOnUnknownQuota??h4}function p0(B,Z,$=Date.now()){if(!N0(Z))return!0;if(!B)return!i(Z);let W=K6(Z),X=i(Z);for(let z of["primary","secondary"]){let G=B[z];if(!G)continue;if(a(G,$)){if(X)return!1;continue}if(G.remainingPercent<W[z])return!1}return!0}function l0(B){return B?.killswitch?.enabled===!0}function T0(B){return{primary:B?.primary??B?.["5h"]??H0.primary,secondary:B?.secondary??B?.["1w"]??H0.secondary}}function g0(B,Z){if(!B?.killswitch)return H0;if(Z&&B.killswitch.accounts?.[Z])return T0(B.killswitch.accounts[Z]);return T0(B.killswitch.main)}function PB(B,Z,$,W=Date.now()){if(!l0(Z))return!0;if(!B)return!i(Z);let X=g0(Z,$),z=i(Z);for(let G of["primary","secondary"]){let K=B[G];if(!K)continue;if(a(K,W)){if(z)return!1;continue}if(K.remainingPercent<X[G])return!1}return!0}function LB(B,Z,$,W){if(!l0(W))return 300;let X=[],z=[{accountId:void 0,quota:B},...Z];for(let{accountId:K,quota:Y}of z){if(!Y)continue;let j=g0(W,K),H=[],Q=!1;for(let b of["primary","secondary"]){let N=Y[b];if(!N||a(N,$))continue;if(N.remainingPercent>=j[b])continue;let F=N.resetsAt?Date.parse(N.resetsAt):NaN;if(!Number.isFinite(F)||F<=$){Q=!0;break}H.push(F)}if(Q||H.length===0)continue;X.push(Math.max(...H))}if(X.length===0)return 300;let G=Math.min(...X);return Math.max(1,Math.ceil((G-$)/1000))}function Y6(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function FB(B,Z=I()){let $=u(Z),W=await d(Z);try{let X=await d($);try{let z=await T(Z);if(z.exists&&J(z.value)){if(Y6(z.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let j=c({id_token:"",access_token:B.access,refresh_token:B.refresh});if(j)G.mainAccountId=j}let Y={...z.exists&&J(z.value)?z.value:{},...w0(G)};await f(Z,Y),await f($,v0(G))}finally{await X.release()}}finally{await W.release()}}function j6(B){return B?.refresh?.enabled!==!1}function J6(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function d0(B){return Math.floor(Math.random()*(B+1))}function y(B,Z,$){return!B.access||!B.expires||B.expires-$<=J6(Z)}function H6(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function Q6(B,Z){return Boolean(B.mainAccountId&&Z.accountId&&Z.accountId===B.mainAccountId)}function P(B,Z){let $=B.accounts.findIndex((W)=>W.id===Z.id);if($!==-1)B.accounts[$]=Z}function g(B){return B instanceof Error?B.message:String(B)}function P0(B,Z,$){B.lastRefreshError=F0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function J0(B,Z,$){if(B.lastQuotaRefreshError=m({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)P0(B,Z,$)}function N6(B){return`fallback-oauth-refresh-${T4("sha256").update(B).digest("base64url").slice(0,16)}`}function x0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function P6(B,Z){if(!B)return!1;return x0(B.primary,Z)||x0(B.secondary,Z)}function L6(B,Z,$){if(!B)return!1;let W=Z?.quota?.checkIntervalMinutes??5,X=Math.max(1,W)*60000,z=Math.max(B.primary?.checkedAt??0,B.secondary?.checkedAt??0);return $-z<X}function A0(B,Z,$){return!L6(B.quota,Z,$)}function F6(B,Z,$,W){return W0($)&&p0(B.quota,Z,W)&&P6(B.quota,W)}function O6(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var V6=60000,b6=60000,D6=600000,U6=1e4,M6=100;var OB=globalThis.setTimeout.bind(globalThis),VB=globalThis.clearTimeout.bind(globalThis);class _6{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??I(),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.primary?.checkedAt??0,B.quota.secondary?.checkedAt??0);if($<=0)return;let W=this.quotaManager.getFallback(B.id,B.access);if(W&&W.checkedAt>=$)return;this.quotaManager.setFallback(B.id,{quota:B.quota,refreshAfter:$+O6(Z),checkedAt:$},B.access,!1,B.accountId)}async load(){return s4(this.configPath)}async save(B,Z){await G6(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(()=>{})},V6+d0(b6)),"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 $=[],W=!1;for(let X of Z.accounts){if(X.enabled===!1||!U(X))continue;if(Q6(Z,X))continue;let z=!1,G=X;try{if(y(G,Z,this.now())){let K=G.lastRefreshError;if(K&&_(K,G.refresh,this.now()))throw z=!0,Error(r(K,this.now()));try{G=await this.refreshAccount(G,Z),W=!0}catch(Y){if(p4(Y))continue;z=!0;let j=Z.accounts.find((H)=>H.id===X.id&&U(H));if(j&&!_(j.lastRefreshError,j.refresh,this.now()))P0(j,Y,this.now()),P(Z,j),W=!0;throw Y}}if(this.seedFallbackQuota(G,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(G),Z))$.push(G)}catch(K){let Y=H6(G,this.now());if(z){if(!Y)continue}else if(!Y)continue;if(F6(G,Z,K,this.now()))R.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:g(K)}),$.push(G);else if(!i(Z))$.push(G)}}if(W)try{await this.save(Z)}catch(X){t.warn("fallback selection bookkeeping not persisted",{pid:process.pid,error:g(X)})}return $}async markUsed(B){try{let Z=await this.load();if(!Z)return;let $=Z.accounts.find((W)=>W.id===B.id);if(!$)return;$.lastUsed=this.now(),await this.save(Z,[$.id])}catch(Z){t.warn("lastUsed stamp not persisted",{pid:process.pid,accountId:B.id,error:g(Z)})}}accountPassesQuotaPolicy(B,Z){return p0(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||!j6(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;if(!y($,B,this.now()))continue;if(_($.lastRefreshError,$.refresh,this.now()))continue;try{R.debug("fallback oauth background due",{pid:process.pid,accountId:$.id,expiresInMs:$.expires?$.expires-this.now():void 0}),await this.refreshAccount($,B),Z=!0}catch(W){R.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:g(W)}),P0($,W,this.now()),P(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!N0(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!U($))continue;let W=$;try{if(y(W,B,this.now())){if(_(W.lastRefreshError,W.refresh,this.now()))continue;W=await this.refreshAccount(W,B),Z=!0}if(x(W.lastQuotaRefreshError,this.now()))continue;if(this.seedFallbackQuota(W,B),!(this.quotaManager?this.quotaManager.isFallbackStale(W.id,W.access):A0(W,B,this.now())))continue;await this.refreshAccountQuota(W,B),Z=!0}catch(X){J0($,X,this.now()),P(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!N0(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let W=B.force??!1,X=!1;for(let z of Z.accounts){if(z.enabled===!1||!U(z))continue;let G=z;try{if(y(G,Z,this.now())){let K=G.lastRefreshError;if(K&&_(K,G.refresh,this.now()))throw Error(r(K,this.now()));G=await this.refreshAccount(G,Z),X=!0}if(!W&&!A0(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,P(Z,G),X=!0;continue}await this.refreshAccountQuota(G,Z),X=!0}catch(K){J0(z,K,this.now()),P(Z,z),X=!0,$.push({accountId:z.id,message:g(K)})}}if(X)await this.save(Z);return{storage:Z,errors:$}}async refreshAccount(B,Z,$={}){let W=this.refreshPromises.get(B.id);if(W){let G=await W;return P(Z,G),G}let X=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,X);let z=await X;return P(Z,z),z}async waitForConcurrentFallbackRefresh(B,Z,$,W){let X=Date.now()+U6;while(Date.now()<X){await new Promise((j)=>setTimeout(j,M6));let z=await this.load(),G=z?.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)&&(W.force||!y(G,z,this.now())))return P(Z,G),R.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&&_(Y,G.refresh,this.now()))throw P(Z,G),Error(r(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let W=await this.load(),X=W?.accounts.find((K)=>K.id===B.id&&U(K));if(X&&!$.force&&!y(X,W,this.now()))return P(Z,X),X;let z=X??B,G=await A({name:N6(z.id),ttlMs:D6,path:this.configPath,now:this.now,renew:!0});if(!G){R.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:z.id});let K=await this.waitForConcurrentFallbackRefresh(B,Z,z,$);if(K)return K;throw Error("Fallback OAuth refresh is already in progress")}try{if(W=await this.load(),X=W?.accounts.find((H)=>H.id===B.id&&U(H)),X&&!$.force&&!y(X,W,this.now()))return P(Z,X),X;if(!X)throw new e(B.id);z=X;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});R.debug("fallback oauth refresh request start",{pid:process.pid,accountId:z.id,force:$.force===!0,expiresInMs:z.expires?z.expires-this.now():void 0});let Y=await K({refreshToken:z.refresh,fetchImpl:this.fetchImpl,now:this.now});if(z.access=Y.access,z.refresh=Y.refresh,z.expires=Y.expires,z.lastRefreshedAt=Y.expires-Y.expiresIn*1000,z.lastRefreshError=void 0,P(Z,z),await this.save(Z),!(await this.load())?.accounts.some((H)=>H.id===B.id))throw new e(B.id);return R.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:z.id,expiresInMs:z.expires?z.expires-this.now():void 0}),z}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 W=this.options.fetchQuotaFn??(async()=>{throw Error("No fetchQuotaFn injected — wham/usage supplement is disabled")}),X=(z)=>this.quotaManager?this.quotaManager.refreshFallback($.id,z):W({accessToken:z,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let z=await X($.access);$.quota=z,$.lastQuotaRefreshError=void 0,P(Z,$),await this.save(Z)}catch(z){throw J0(B,z,this.now()),P(Z,B),z}}}
89
+ export{L0 as h,F0 as i,_ as j,r as k,D0 as l,M0 as m,$4 as n,V0 as o,b0 as p,c as q,G0 as r,X4 as s,E as t,Y4 as u,j4 as v,J4 as w,H4 as x,x6 as y,A6 as z,_0 as A,w6 as B,v6 as C,u6 as D,D as E,U as F,JB as G,H0 as H,v4 as I,u4 as J,s4 as K,QB as L,NB as M,l0 as N,g0 as O,PB as P,LB as Q,FB as R,_6 as S};