@cortexkit/opencode-openai-auth 0.5.1 → 0.5.2
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 +1 -1
- package/dist/core/oauth.d.ts +1 -1
- package/dist/{index-j1364eag.js → index-qhvsskdz.js} +5 -5
- package/dist/index.js +63 -63
- package/dist/version.d.ts +1 -1
- package/dist/ws-pool.d.ts +1 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{F as q,J as B,K as V,r as Y,y as Z,z as $}from"./index-
|
|
2
|
+
import{F as q,J as B,K as V,r as Y,y as Z,z as $}from"./index-qhvsskdz.js";import"./index-vrdc90yd.js";import"./index-s5fbqqwx.js";import{Ga as X}from"./index-wpd7mg3p.js";import{execFileSync as E}from"node:child_process";function Q(C,H=process.platform,D=E){try{if(H==="win32"){D("cmd",["/c","start","",C],{stdio:"ignore",timeout:3000});return}D(H==="darwin"?"open":"xdg-open",[C],{stdio:"ignore",timeout:3000})}catch{}}function T(){console.log(`Usage:
|
|
3
3
|
npx @cortexkit/opencode-openai-auth login [--label <name>] [--headless]
|
|
4
4
|
npx @cortexkit/opencode-openai-auth list
|
|
5
5
|
npx @cortexkit/opencode-openai-auth remove <id>
|
package/dist/core/oauth.d.ts
CHANGED
|
@@ -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.5.
|
|
5
|
+
export declare const USER_AGENT = "cortexkit-opencode-openai-auth/0.5.2";
|
|
6
6
|
export declare const RESERVED_ACCOUNT_ID = "main";
|
|
7
7
|
export declare const RESERVED_ACCOUNT_ID_ERROR = "\"main\" is a reserved account id; choose a different label.";
|
|
8
8
|
export interface PkceCodes {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{ta as T}from"./index-vrdc90yd.js";import{za as s}from"./index-s5fbqqwx.js";import{Ga as
|
|
1
|
+
import{ta as T}from"./index-vrdc90yd.js";import{za as s}from"./index-s5fbqqwx.js";import{Ga as Y2}from"./index-wpd7mg3p.js";import{createHash as p0}from"node:crypto";var l0=86400000,d0=300000,g0=3600000,i0=60000,u0=900000,s0=300000;function t(B){return B instanceof Error?B.message:String(B)}function r0(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 e(B){let Z=t(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 Q0(B){return p0("sha256").update(B).digest("hex")}function N0(B){let Z=Q0(B.refreshToken),W=(B.previous?.tokenHash===Z?B.previous.retryCount??0:0)+1,z,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)z=X*1000;else if(r0(B.error))z=Math.min(g0,d0*2**Math.min(W-1,6));else z=l0;return{message:t(B.error),checkedAt:B.now,nextRetryAt:B.now+z,retryCount:W,tokenHash:Z}}function U(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===Q0(Z)}function d(B,Z){return`Codex OAuth refresh is backed off for ${Math.max(1,Math.ceil(((B.nextRetryAt??Z)-Z)/1000))}s after: ${B.message}`}function A(B){let $=(B.previous?.retryCount??0)+1,W,z=B.error?.retryAfter;if(typeof z==="number"&&z>0)W=z*1000;else if(e(B.error))W=Math.min(u0,i0*2**Math.min($-1,6));else W=s0;return{message:t(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 B0(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 n0}from"node:http";import{setTimeout as c0}from"node:timers/promises";var P0="0.5.2";var u="app_EMoamEEZ73f0CkXaXp7hrann",q="https://auth.openai.com",m=1455,a0=3000,F0=`cortexkit-opencode-openai-auth/${P0}`,O0="main",o0=`"${O0}" is a reserved account id; choose a different label.`;function b0(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function t0(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((W)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[W%66]).join(""),$=b0(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 L0(B){let Z=B.chatgpt_account_id;if(typeof Z==="string"&&Z.length>0)return Z;let $=B["https://api.openai.com/auth"];if($&&typeof $==="object"&&!Array.isArray($)&&typeof $.chatgpt_account_id==="string"&&$.chatgpt_account_id.length>0)return $.chatgpt_account_id;let W=B.organizations;if(Array.isArray(W)){let z=W[0];if(z&&typeof z==="object"&&!Array.isArray(z)&&typeof z.id==="string"&&z.id.length>0)return z.id}return}function i(B){if(B.id_token){let Z=V0(B.id_token),$=Z&&L0(Z);if($)return $}if(B.access_token){let Z=V0(B.access_token);return Z?L0(Z):void 0}return}function e0(B){return typeof B==="string"&&B.toLowerCase()===O0}function Z0(B){if(e0(B))throw Error(o0);return B}function B2(B,Z,$){let W=new URLSearchParams({response_type:"code",client_id:u,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`${q}/oauth/authorize?${W.toString()}`}async function Z2(B,Z,$){let W=await fetch(`${q}/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:u,code_verifier:$.verifier}).toString()});if(!W.ok)throw Error(`Token exchange failed: ${W.status}`);return await W.json()}function $2(B){return B.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}var W2=`<!doctype html>
|
|
2
2
|
<html>
|
|
3
3
|
<head>
|
|
4
4
|
<title>CortexKit OpenAI Auth - Authorization Successful</title>
|
|
@@ -81,9 +81,9 @@ import{ta as T}from"./index-vrdc90yd.js";import{za as s}from"./index-s5fbqqwx.js
|
|
|
81
81
|
<div class="container">
|
|
82
82
|
<h1>Authorization Failed</h1>
|
|
83
83
|
<p>An error occurred during authorization.</p>
|
|
84
|
-
<div class="error">${$
|
|
84
|
+
<div class="error">${$2(B)}</div>
|
|
85
85
|
</div>
|
|
86
86
|
</body>
|
|
87
|
-
</html>`,k,w,L=new Map;function M(){return L.size}function C(B){if(L.delete(B),M()===0)_()}async function z1(){let B=`http://localhost:${m}/auth/callback`;if(k)return{port:m,redirectUri:B};if(w)return w;w=(async()=>{let Z=n0(($,W)=>{let z=new URL($.url||"/",`http://127.0.0.1:${m}`);if(z.pathname==="/auth/callback"){let X=z.searchParams.get("code"),G=z.searchParams.get("state"),K=z.searchParams.get("error"),Y=z.searchParams.get("error_description");if(K){let j=Y||K;if(G){let Q=L.get(G);if(Q)Q.reject(Error(j)),C(G);else if(M()===0)_()}else if(M()===0)_();W.writeHead(200,{"Content-Type":"text/html"}),W.end(g(j));return}if(!G){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(g("Missing state parameter"));return}if(!X){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(g("Missing authorization code"));return}let J=L.get(G);if(!J){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(g("Unknown state — authorization may have expired"));return}C(G),Z1(X,B,J.pkce).then((j)=>J.resolve(j)).catch((j)=>J.reject(j)),W.writeHead(200,{"Content-Type":"text/html"}),W.end(W1);return}if(z.pathname==="/cancel"){let X=z.searchParams.get("state"),G=X?[X]:[...L.keys()];W.writeHead(200),W.end("Login cancelled");for(let K of G){let Y=L.get(K);if(!Y)continue;Y.reject(Error("Login cancelled")),C(K)}if(M()===0)_();return}W.writeHead(404),W.end("Not found")});return await new Promise(($,W)=>{Z.once("error",W),Z.listen(m,"127.0.0.1",()=>{Z.off("error",W),$()})}),k=Z,{port:m,redirectUri:B}})();try{return await w}finally{w=void 0}}function _(){if(k){let B=k;k=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function X1(B,Z,$=300000,W){return new Promise((z,X)=>{if(W?.aborted){C(Z),X(Error("Login cancelled"));return}let G=setTimeout(()=>{if(L.get(Z))C(Z),X(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),L.get(Z))C(Z),X(Error("Login cancelled"))};if(W)W.addEventListener("abort",K);L.set(Z,{pkce:B,state:Z,resolve:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);z(Y)},reject:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);X(Y)}})})}async function G1(){let B=await fetch(`${q}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":F0},body:JSON.stringify({client_id:u})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${q}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function K1(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),z=!Number.isNaN(W)&&W>0?W*1000:900000,X=Date.now();while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");if(Date.now()-X>z)throw Error("Device authorization expired");let G=await fetch(`${q}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":F0},body:JSON.stringify({device_auth_id:B.device_auth_id,user_code:B.user_code})});if(G.ok){let J=await G.json(),j=await fetch(`${q}/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:`${q}/deviceauth/callback`,client_id:u,code_verifier:J.code_verifier}).toString()});if(!j.ok)throw Error(`Token exchange failed: ${j.status}`);return await j.json()}if(G.status!==403&&G.status!==404)throw Error(`Device authorization failed: ${G.status}`);let K=z-(Date.now()-X);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+a0,K);try{await c0(Y,void 0,{signal:Z})}catch(J){if(J instanceof Error&&J.name==="AbortError")throw Error("Device authorization cancelled");throw J}}}function qB(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 CB(B={}){let{label:Z,headless:$=!1,signal:W}=B;if(Z0(Z),$){let{deviceData:J,url:j,instructions:Q}=await G1(),y=(async()=>{let V=await K1(J,W),F=Date.now(),H0=i(V);return{id:Z0(Z||H0||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:V.access_token,refresh:V.refresh_token,expires:F+(V.expires_in??3600)*1000,enabled:!0,addedAt:F,lastUsed:F,lastRefreshedAt:F,accountId:H0}})();return{url:j,instructions:Q,completion:y}}let{redirectUri:z}=await z1(),X=await t0(),G=b0(crypto.getRandomValues(new Uint8Array(32)).buffer),K=B1(z,X,G),Y=(async()=>{try{if(W?.aborted)throw Error("Login cancelled");let J=await X1(X,G,void 0,W),j=Date.now(),Q=i(J);return{id:Z0(Z||Q||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:J.access_token,refresh:J.refresh_token,expires:j+(J.expires_in??3600)*1000,enabled:!0,addedAt:j,lastUsed:j,lastRefreshedAt:j,accountId:Q}}finally{C(G)}})();return{url:K,instructions:"Complete authorization in your browser. This window will close automatically.",completion:Y}}function D0(B){if(B instanceof Error)return B.message;if(typeof B==="string")return B;try{return JSON.stringify(B)}catch{return String(B)}}var J1=s("quota"),$0="primary",W0="secondary",j1="app_EMoamEEZ73f0CkXaXp7hrann",H1="https://auth.openai.com";async function TB(B){let Z=await B.fetchImpl(`${H1}/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:j1}).toString()});if(!Z.ok){let W=B0(Z.headers.get("retry-after"));throw Object.assign(Error(`Token refresh failed: ${Z.status}`),{status:Z.status,retryAfter:W,isRefreshError:!0})}let $=await Z.json();if(!$||typeof $.access_token!=="string"||!$.access_token||typeof $.refresh_token!=="string"||!$.refresh_token||typeof $.expires_in!=="number")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});return{access:$.access_token,refresh:$.refresh_token,expires:B.now()+$.expires_in*1000,expiresIn:$.expires_in}}var Q1="https://chatgpt.com/backend-api/wham/usage";async function fB(B){let Z=B.logger??J1,$=B.accountKey??"unknown",W=Date.now();Z.debug("wham usage fetch started",{pid:process.pid,accountId:$});try{let z=await B.fetchImpl(Q1,{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(!z.ok){let K=B0(z.headers.get("retry-after"));throw Object.assign(Error(`wham usage check failed: ${z.status}`),{status:z.status,retryAfter:K})}let{normalizeWham:X}=await import("./quota-normalize-n02dfdx0.js"),G=X(await z.json());return Z.debug("wham usage fetch succeeded",{pid:process.pid,accountId:$,status:z.status,elapsedMs:Date.now()-W}),G}catch(z){throw Z.warn("wham usage fetch failed",{pid:process.pid,accountId:$,status:typeof z?.status==="number"?z.status:"error",elapsedMs:Date.now()-W,error:D0(z)}),z}}import{createHash as N1}from"node:crypto";var P1=globalThis.setTimeout,V1=5;function h(B){let Z=B?.quota?.checkIntervalMinutes??V1;return Math.max(1,Z)*60000}function L1(B){return B?.quota?.enabled!==!1}function r(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function hB(B,Z,$,W,z){if(z!==void 0&&Number.isFinite(z)&&z>$)return z;let X=Z===$0?B?.primary:Z===W0?B?.secondary:void 0,G=X?.resetsAt?Date.parse(X.resetsAt):NaN;if(Number.isFinite(G)&&G>$)return G;return $+W}function F1(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function U0(B,Z,$){if(!L1(Z))return $+h(Z);let W=F1(Z),z=[];for(let X of["primary","secondary"]){let G=B?.[X];if(!G)continue;if(G.remainingPercent>=W[X])continue;let K=G.resetsAt?Date.parse(G.resetsAt):Number.NaN;if(!Number.isFinite(K)||K<=$)return $+h(Z);z.push(K)}if(!z.length)return $+h(Z);return Math.min(...z)+60000}function O1(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function b1(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function P(B){return N1("sha256").update(B).digest("hex").slice(0,16)}class O{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!==P(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)!==P(Z))return this.fallbacks.delete(B),this.fallbackTokenFps.delete(B),null;return $}getAllFallbacks(){return this.fallbacks}setMain(B,Z,$,W=!1){if(!W&&!M0(Z.quota))return;if(this.mainTokenFp=P(B),$&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==$)this.clearRateLimited("main");if($)this.mainQuotaAccountId=$;if(this.main=Z,z0(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,z){if(!W&&!M0(Z.quota))return;let X=this.fallbacks.get(B)?.accountId;if(z&&X&&z!==X)this.clearRateLimited(B);let G=z??X;if(this.fallbacks.set(B,{...Z,accountId:G}),$)this.fallbackTokenFps.set(B,P($));else this.fallbackTokenFps.delete(B);if(z0(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=P(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 $=O.fallbackInflightKey(B,Z),W=this.inflightFallbacks.get($);if(W)return W;if(this.isFallbackBackedOff(B,Z)){let X=this.getFallback(B,Z);if(X)return X.quota;throw Error("Quota API rate-limited — try again later")}let z=this._fetchFallback(B,Z);return this.inflightFallbacks.set($,z),z}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=P(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=b1(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 $=O1(B);if(!$)return;let W=Z?P(Z):null;if(W&&$.tokenFingerprint&&$.tokenFingerprint!==W)return;let z={quota:$.quota,refreshAfter:U0($.quota,B,$.checkedAt),checkedAt:$.checkedAt};if(this.main&&this.main.checkedAt>=z.checkedAt&&(!W||!this.mainTokenFp||this.mainTokenFp===W))return;if(this.main=z,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=h(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 z=this.getFallback($.id,$.access);if(z&&z.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)!==P(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,P(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<O.API_CALL_GAP_MS)await new Promise((z)=>{let X=P1(z,O.API_CALL_GAP_MS-W);if(typeof X==="object"&&"unref"in X)X.unref()});return this.lastApiCallAt=this.now(),B()},$=this.apiGate.then(Z,Z);return this.apiGate=$.catch(()=>{}),$}async _fetchMain(B){let Z=P(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 T({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(),z=await this._fetchQuota(B),X=this.now();if(this.mainTokenFp=P(B),this.main={quota:z,refreshAfter:U0(z,this.storage,X),checkedAt:X},z0(z))this.clearRateLimited("main");return this.mainLastApiError=void 0,this.onMainQuotaFetched?.(z,X,this.mainTokenFp,W),z}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 T({name:O.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),z=this.now();return this.setFallback(B,{quota:W,refreshAfter:z+h(this.storage),checkedAt:z},Z,!0),this.fallbackApiErrors.delete(B),this.fallbackErrorTokenFps.delete(B),W}finally{await $.release()}}catch($){throw this._handleFallbackFetchError(B,Z,$),$}finally{this.inflightFallbacks.delete(O.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(O.isAuthError(B))return;this.mainLastApiError=A({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(O.isAuthError($))return;let W=P(Z),z=this.fallbackErrorTokenFps.get(B)===W?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,A({error:$,now:this.now(),previous:z})),this.fallbackErrorTokenFps.set(B,W)}}function M0(B){return Boolean(B.primary||B.secondary)}function z0(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 E1,randomUUID as S1}from"node:crypto";import{homedir as R1}from"node:os";import{dirname as y1,join as n}from"node:path";import{setTimeout as x1}from"node:timers/promises";import{randomUUID as D1}from"node:crypto";import{mkdir as U1,rename as M1,rm as _1,writeFile as q1}from"node:fs/promises";import{dirname as C1}from"node:path";async function f(B,Z){await U1(C1(B),{recursive:!0});let $=`${B}.${D1()}.tmp`;await q1($,`${JSON.stringify(Z,null,2)}
|
|
88
|
-
`,{encoding:"utf8",mode:384});try{await M1($,B)}catch(W){throw await _1($,{force:!0}).catch(()=>{}),W}}import{readFile as l1}from"node:fs/promises";var E=s("refresh"),_0=1e4,T1=50,x0="openai-auth.json",f1="openai-auth-state.json";function I1(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return n(process.env.XDG_CONFIG_HOME||n(R1(),".config"),"opencode")}function I(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||n(I1(),x0)}function o(B=I()){let Z=process.env.OPENCODE_OPENAI_AUTH_STATE_FILE?.trim();if(Z)return Z;return A1(B)}function A1(B){return B.endsWith(x0)?n(y1(B),f1):`${B}.state.json`}function b(B){return B.type==="oauth"}function m1(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 ZZ(B){return B.costZeroing?.enabled!==!1}class c extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var w1=[401,403,429],q0={primary:0,secondary:0},k1=!1,K0={primary:5,secondary:10};function H(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}function h1(B){return B instanceof c||H(B)&&B.name==="AccountRemovedDuringRefreshError"&&B.code==="ACCOUNT_REMOVED_DURING_REFRESH"}function C0(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():S1(),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 E0(B){if(!H(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 v1(B){if(!H(B))return;let Z={};for(let W of["primary","secondary"]){let z=B[W];if(!H(z))continue;let X=Number(z.usedPercent),G=Number(z.remainingPercent),K=Number(z.checkedAt);if(!Number.isFinite(X)||!Number.isFinite(G)||!Number.isFinite(K))continue;let Y=typeof z.windowMinutes==="number"?z.windowMinutes:Number.NaN;Z[W]={usedPercent:X,remainingPercent:G,checkedAt:K,resetsAt:typeof z.resetsAt==="string"?z.resetsAt:void 0,...Number.isFinite(Y)&&Y>0?{windowMinutes:Y}:{}}}let $=typeof B.resetCreditsAvailable==="number"?B.resetCreditsAvailable:Number.NaN;if(Number.isFinite($)&&$>=0)Z.resetCreditsAvailable=$;return Object.keys(Z).length?Z:void 0}function p1(B){if(!H(B))return null;if(B.type==="api"){let Z=typeof B.baseURL==="string"?B.baseURL.trim():"",$=typeof B.apiKey==="string"?B.apiKey.trim():"";if(!m1(Z))return null;let W=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...C0(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{...C0(B),type:"oauth",access:typeof B.access==="string"?B.access:void 0,refresh:B.refresh,expires:typeof B.expires==="number"?B.expires:void 0,lastRefreshedAt:typeof B.lastRefreshedAt==="number"?B.lastRefreshedAt:void 0,lastRefreshError:E0(B.lastRefreshError),lastQuotaRefreshError:E0(B.lastQuotaRefreshError),quota:v1(B.quota)}}function T0(B){if(!H(B)||!Array.isArray(B.accounts))return null;return{version:1,main:{type:"opencode",provider:"openai"},routing:H(B.routing)?B.routing:void 0,fallbackOn:Array.isArray(B.fallbackOn)?B.fallbackOn.filter((Z)=>Number.isInteger(Z)):void 0,refresh:H(B.refresh)?B.refresh:void 0,quota:H(B.quota)?B.quota:void 0,dump:H(B.dump)?B.dump:void 0,costZeroing:H(B.costZeroing)?B.costZeroing:void 0,killswitch:H(B.killswitch)?B.killswitch:void 0,logging:H(B.logging)?B.logging:void 0,cachekeep:H(B.cachekeep)?B.cachekeep:void 0,mainAccountId:typeof B.mainAccountId==="string"?B.mainAccountId:void 0,accounts:B.accounts.map(p1).filter((Z)=>Z!=null)}}async function R(B){try{return{exists:!0,value:JSON.parse(await l1(B,"utf8"))}}catch(Z){if(Z.code==="ENOENT")return{exists:!1,value:null};throw Z}}function D(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}async function d1(B){let Z;try{Z=(await R(B)).value}catch{return null}if(!H(Z)||!Array.isArray(Z.accounts))return null;let $=new Set;for(let W of Z.accounts)if(H(W)&&typeof W.id==="string")$.add(W.id);return $}function f0(B,Z){if(!H(B))return B;let $=H(Z)?Z:{},W=H($.main)?$.main:void 0,z=H($.accounts)?$.accounts:{},X=H(B.quota)?B.quota:{},G=H(B.refresh)?B.refresh:{},K=W??X,Y=W??G,j=Array.isArray(B.accounts)?B.accounts.map((Q)=>{if(!H(Q))return Q;let y=typeof Q.id==="string"&&H(z[Q.id])?z[Q.id]:{};return{...Q,...y}}):void 0;return I0({...B,refresh:D({...G,mainLastRefreshError:Y.lastRefreshError,mainRefreshLeaseId:Y.refreshLeaseId,mainRefreshLeaseUntil:Y.refreshLeaseUntil,mainRefreshLeaseTokenHash:Y.refreshLeaseTokenHash}),quota:D({...X,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:j})}async function g1(B=I()){let Z=await R(B);if(!Z.exists)return null;let $=await R(o(B));return T0(f0(Z.value,$.value))}function I0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function i1(B){return D({id:B.id,label:B.label,type:B.type,enabled:B.enabled,addedAt:B.addedAt,accountId:B.accountId,baseURL:B.type==="api"?B.baseURL:void 0,authHeader:B.type==="api"?B.authHeader:void 0})}function A0(B){if(B.type==="api")return D({apiKey:B.apiKey,lastUsed:B.lastUsed});return D({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 a(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function v(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function u1(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function s1(B,Z){if(!u1(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 r1(B,Z,$){let W=Z.lastRefreshedAt??0,z=$.lastRefreshedAt??0,X=Z.expires??0,G=$.expires??0,K=z>W?$:W>z?Z:G>X?$:X>G?Z:s1(Z,$);v(B,K,"access"),v(B,K,"refresh"),v(B,K,"expires"),v(B,K,"lastRefreshedAt"),v(B,K,"lastRefreshError")}function n1(B,Z){if(!H(B))return Z;let $=B,W=a($.quota),z=a(Z.quota),X=W>z,G=X?{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}:{...$,...Z};if(!X&&!("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 r1(G,$,Z),G}function m0(B){let Z=B.refresh?D({enabled:B.refresh.enabled,intervalMinutes:B.refresh.intervalMinutes,refreshBeforeExpiryMinutes:B.refresh.refreshBeforeExpiryMinutes}):void 0,$=B.quota?D({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 I0({version:1,main:B.main,routing:B.routing,fallbackOn:B.fallbackOn,refresh:Z,quota:$,dump:B.dump,costZeroing:B.costZeroing,killswitch:B.killswitch,logging:B.logging,cachekeep:B.cachekeep,mainAccountId:B.mainAccountId,accounts:B.accounts.map(i1)})}async function p(B){let Z=Date.now()+_0;while(Date.now()<=Z){let $=await T({name:"save",ttlMs:_0,path:B});if($)return $;let W=Z-Date.now();if(W<=0)break;await x1(Math.min(T1,W))}throw Error(`Timed out acquiring account store lock for ${B}; refusing to overwrite newer account data`)}function w0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,A0($)]));return{version:1,main:D({quota:B.quota?.mainQuota,quotaCheckedAt:B.quota?.mainQuotaCheckedAt,quotaToken:B.quota?.mainQuotaToken,lastQuotaApiError:B.quota?.mainLastQuotaApiError,lastRefreshError:B.refresh?.mainLastRefreshError,refreshLeaseId:B.refresh?.mainRefreshLeaseId,refreshLeaseUntil:B.refresh?.mainRefreshLeaseUntil,refreshLeaseTokenHash:B.refresh?.mainRefreshLeaseTokenHash}),accounts:Z}}async function WZ(B,Z=I()){let $=o(Z),W=await p(Z);try{let z=await p($);try{let X=await R(Z),G=await R($),K=(X.exists?T0(f0(X.value,G.value)):null)??c1(),Y=B(K)??K,j={...H(X.value)?X.value:{},...m0(Y)};return await f(Z,j),await f($,w0(Y)),Y}finally{await z.release()}}finally{await W.release()}}function c1(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function a1(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:a(B.main.quota),W=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:a(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 o1(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 Y0(B){if(Array.isArray(B))return B.map(Y0);if(!H(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,Y0($)]))}async function t1(B,Z=I(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let W=o(Z),z=await p(W);try{let X=(await R(W)).value,G=H(X)?{...X,version:1}:{version:1};if($.mainQuota)a1(G,B);if($.mainRefresh)o1(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await d1(Z);G.accounts={...H(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]=n1(G.accounts[J.id],A0(J))}if(K){for(let J of K)if(!B.accounts.some((j)=>j.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,Y0(G))}finally{await z.release()}}function e1(B){return B?.fallbackOn?.length?B.fallbackOn:w1}function zZ(B,Z){return e1(Z).includes(B)}function BB(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??q0.primary,secondary:Z.secondary??Z["1w"]??q0.secondary}}function J0(B){return B?.quota?.enabled!==!1}function l(B){return B?.quota?.failClosedOnUnknownQuota??k1}function k0(B,Z,$=Date.now()){if(!J0(Z))return!0;if(!B)return!l(Z);let W=BB(Z),z=l(Z);for(let X of["primary","secondary"]){let G=B[X];if(!G)continue;if(r(G,$)){if(z)return!1;continue}if(G.remainingPercent<W[X])return!1}return!0}function h0(B){return B?.killswitch?.enabled===!0}function S0(B){return{primary:B?.primary??B?.["5h"]??K0.primary,secondary:B?.secondary??B?.["1w"]??K0.secondary}}function v0(B,Z){if(!B?.killswitch)return K0;if(Z&&B.killswitch.accounts?.[Z])return S0(B.killswitch.accounts[Z]);return S0(B.killswitch.main)}function XZ(B,Z,$,W=Date.now()){if(!h0(Z))return!0;if(!B)return!l(Z);let z=v0(Z,$),X=l(Z);for(let G of["primary","secondary"]){let K=B[G];if(!K)continue;if(r(K,W)){if(X)return!1;continue}if(K.remainingPercent<z[G])return!1}return!0}function GZ(B,Z,$,W){if(!h0(W))return 300;let z=[],X=[{accountId:void 0,quota:B},...Z];for(let{accountId:K,quota:Y}of X){if(!Y)continue;let J=v0(W,K),j=[],Q=!1;for(let y of["primary","secondary"]){let V=Y[y];if(!V||r(V,$))continue;if(V.remainingPercent>=J[y])continue;let F=V.resetsAt?Date.parse(V.resetsAt):NaN;if(!Number.isFinite(F)||F<=$){Q=!0;break}j.push(F)}if(Q||j.length===0)continue;z.push(Math.max(...j))}if(z.length===0)return 300;let G=Math.min(...z);return Math.max(1,Math.ceil((G-$)/1000))}function ZB(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function KZ(B,Z=I()){let $=o(Z),W=await p(Z);try{let z=await p($);try{let X=await R(Z);if(X.exists&&H(X.value)){if(ZB(X.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let J=i({id_token:"",access_token:B.access,refresh_token:B.refresh});if(J)G.mainAccountId=J}let Y={...X.exists&&H(X.value)?X.value:{},...m0(G)};await f(Z,Y),await f($,w0(G))}finally{await z.release()}}finally{await W.release()}}function $B(B){return B?.refresh?.enabled!==!1}function WB(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function zB(B){return Math.floor(Math.random()*(B+1))}function S(B,Z,$){return!B.access||!B.expires||B.expires-$<=WB(Z)}function XB(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function GB(B,Z){return Boolean(B.mainAccountId&&Z.accountId&&Z.accountId===B.mainAccountId)}function N(B,Z){let $=B.accounts.findIndex((W)=>W.id===Z.id);if($!==-1)B.accounts[$]=Z}function X0(B){return B instanceof Error?B.message:String(B)}function j0(B,Z,$){B.lastRefreshError=N0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function G0(B,Z,$){if(B.lastQuotaRefreshError=A({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)j0(B,Z,$)}function KB(B){return`fallback-oauth-refresh-${E1("sha256").update(B).digest("base64url").slice(0,16)}`}function R0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function YB(B,Z){if(!B)return!1;return R0(B.primary,Z)||R0(B.secondary,Z)}function JB(B,Z,$){if(!B)return!1;let W=Z?.quota?.checkIntervalMinutes??5,z=Math.max(1,W)*60000,X=Math.max(B.primary?.checkedAt??0,B.secondary?.checkedAt??0);return $-X<z}function y0(B,Z,$){return!JB(B.quota,Z,$)}function jB(B,Z,$,W){return e($)&&k0(B.quota,Z,W)&&YB(B.quota,W)}function HB(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var QB=60000,NB=60000,PB=600000,VB=1e4,LB=100;var YZ=globalThis.setTimeout.bind(globalThis),JZ=globalThis.clearTimeout.bind(globalThis);class FB{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:$+HB(Z),checkedAt:$},B.access,!1,B.accountId)}async load(){return g1(this.configPath)}async save(B,Z){await t1(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(()=>{})},QB+zB(NB)),"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 z of Z.accounts){if(z.enabled===!1||!b(z))continue;if(GB(Z,z))continue;let X=!1,G=z;try{if(S(G,Z,this.now())){let K=G.lastRefreshError;if(K&&U(K,G.refresh,this.now()))throw X=!0,Error(d(K,this.now()));try{G=await this.refreshAccount(G,Z),W=!0}catch(Y){if(h1(Y))continue;X=!0;let J=Z.accounts.find((j)=>j.id===z.id&&b(j));if(J&&!U(J.lastRefreshError,J.refresh,this.now()))j0(J,Y,this.now()),N(Z,J),W=!0;throw Y}}if(this.seedFallbackQuota(G,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(G),Z))$.push(G)}catch(K){let Y=XB(G,this.now());if(X){if(!Y)continue}else if(!Y)continue;if(jB(G,Z,K,this.now()))E.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:X0(K)}),$.push(G);else if(!l(Z))$.push(G)}}if(W)await this.save(Z);return $}async markUsed(B){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)}accountPassesQuotaPolicy(B,Z){return k0(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||!$B(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!b($))continue;if(!S($,B,this.now()))continue;if(U($.lastRefreshError,$.refresh,this.now()))continue;try{E.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){E.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:X0(W)}),j0($,W,this.now()),N(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!J0(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!b($))continue;let W=$;try{if(S(W,B,this.now())){if(U(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):y0(W,B,this.now())))continue;await this.refreshAccountQuota(W,B),Z=!0}catch(z){G0($,z,this.now()),N(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!J0(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let W=B.force??!1,z=!1;for(let X of Z.accounts){if(X.enabled===!1||!b(X))continue;let G=X;try{if(S(G,Z,this.now())){let K=G.lastRefreshError;if(K&&U(K,G.refresh,this.now()))throw Error(d(K,this.now()));G=await this.refreshAccount(G,Z),z=!0}if(!W&&!y0(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,N(Z,G),z=!0;continue}await this.refreshAccountQuota(G,Z),z=!0}catch(K){G0(X,K,this.now()),N(Z,X),z=!0,$.push({accountId:X.id,message:X0(K)})}}if(z)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 N(Z,G),G}let z=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,z);let X=await z;return N(Z,X),X}async waitForConcurrentFallbackRefresh(B,Z,$,W){let z=Date.now()+VB;while(Date.now()<z){await new Promise((J)=>setTimeout(J,LB));let X=await this.load(),G=X?.accounts.find((J)=>J.id===B.id&&b(J));if(!G)continue;if((G.access!==$.access||G.refresh!==$.refresh||(G.expires??0)>($.expires??0)+60000)&&(W.force||!S(G,X,this.now())))return N(Z,G),E.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&&U(Y,G.refresh,this.now()))throw N(Z,G),Error(d(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let W=await this.load(),z=W?.accounts.find((K)=>K.id===B.id&&b(K));if(z&&!$.force&&!S(z,W,this.now()))return N(Z,z),z;let X=z??B,G=await T({name:KB(X.id),ttlMs:PB,path:this.configPath,now:this.now,renew:!0});if(!G){E.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:X.id});let K=await this.waitForConcurrentFallbackRefresh(B,Z,X,$);if(K)return K;throw Error("Fallback OAuth refresh is already in progress")}try{if(W=await this.load(),z=W?.accounts.find((j)=>j.id===B.id&&b(j)),z&&!$.force&&!S(z,W,this.now()))return N(Z,z),z;if(!z)throw new c(B.id);X=z;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});E.debug("fallback oauth refresh request start",{pid:process.pid,accountId:X.id,force:$.force===!0,expiresInMs:X.expires?X.expires-this.now():void 0});let Y=await K({refreshToken:X.refresh,fetchImpl:this.fetchImpl,now:this.now});if(X.access=Y.access,X.refresh=Y.refresh,X.expires=Y.expires,X.lastRefreshedAt=Y.expires-Y.expiresIn*1000,X.lastRefreshError=void 0,N(Z,X),await this.save(Z),!(await this.load())?.accounts.some((j)=>j.id===B.id))throw new c(B.id);return E.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:X.id,expiresInMs:X.expires?X.expires-this.now():void 0}),X}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")}),z=(X)=>this.quotaManager?this.quotaManager.refreshFallback($.id,X):W({accessToken:X,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let X=await z($.access);$.quota=X,$.lastQuotaRefreshError=void 0,N(Z,$),await this.save(Z)}catch(X){throw G0(B,X,this.now()),N(Z,B),X}}}
|
|
89
|
-
export{Q0 as h,N0 as i,U as j,d as k,F0 as l,b0 as m,t0 as n,V0 as o,L0 as p,i as q,Z0 as r,
|
|
87
|
+
</html>`,k,w,L=new Map;function M(){return L.size}function C(B){if(L.delete(B),M()===0)_()}async function z2(){let B=`http://localhost:${m}/auth/callback`;if(k)return{port:m,redirectUri:B};if(w)return w;w=(async()=>{let Z=n0(($,W)=>{let z=new URL($.url||"/",`http://127.0.0.1:${m}`);if(z.pathname==="/auth/callback"){let X=z.searchParams.get("code"),G=z.searchParams.get("state"),K=z.searchParams.get("error"),Y=z.searchParams.get("error_description");if(K){let j=Y||K;if(G){let Q=L.get(G);if(Q)Q.reject(Error(j)),C(G);else if(M()===0)_()}else if(M()===0)_();W.writeHead(200,{"Content-Type":"text/html"}),W.end(g(j));return}if(!G){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(g("Missing state parameter"));return}if(!X){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(g("Missing authorization code"));return}let J=L.get(G);if(!J){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(g("Unknown state — authorization may have expired"));return}C(G),Z2(X,B,J.pkce).then((j)=>J.resolve(j)).catch((j)=>J.reject(j)),W.writeHead(200,{"Content-Type":"text/html"}),W.end(W2);return}if(z.pathname==="/cancel"){let X=z.searchParams.get("state"),G=X?[X]:[...L.keys()];W.writeHead(200),W.end("Login cancelled");for(let K of G){let Y=L.get(K);if(!Y)continue;Y.reject(Error("Login cancelled")),C(K)}if(M()===0)_();return}W.writeHead(404),W.end("Not found")});return await new Promise(($,W)=>{Z.once("error",W),Z.listen(m,"127.0.0.1",()=>{Z.off("error",W),$()})}),k=Z,{port:m,redirectUri:B}})();try{return await w}finally{w=void 0}}function _(){if(k){let B=k;k=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function X2(B,Z,$=300000,W){return new Promise((z,X)=>{if(W?.aborted){C(Z),X(Error("Login cancelled"));return}let G=setTimeout(()=>{if(L.get(Z))C(Z),X(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),L.get(Z))C(Z),X(Error("Login cancelled"))};if(W)W.addEventListener("abort",K);L.set(Z,{pkce:B,state:Z,resolve:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);z(Y)},reject:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);X(Y)}})})}async function G2(){let B=await fetch(`${q}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":F0},body:JSON.stringify({client_id:u})});if(!B.ok)throw Error("Failed to initiate device authorization");let Z=await B.json();return{deviceData:Z,url:`${q}/codex/device`,instructions:`Enter code: ${Z.user_code}`}}async function K2(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),z=!Number.isNaN(W)&&W>0?W*1000:900000,X=Date.now();while(!0){if(Z?.aborted)throw Error("Device authorization cancelled");if(Date.now()-X>z)throw Error("Device authorization expired");let G=await fetch(`${q}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":F0},body:JSON.stringify({device_auth_id:B.device_auth_id,user_code:B.user_code})});if(G.ok){let J=await G.json(),j=await fetch(`${q}/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:`${q}/deviceauth/callback`,client_id:u,code_verifier:J.code_verifier}).toString()});if(!j.ok)throw Error(`Token exchange failed: ${j.status}`);return await j.json()}if(G.status!==403&&G.status!==404)throw Error(`Device authorization failed: ${G.status}`);let K=z-(Date.now()-X);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+a0,K);try{await c0(Y,void 0,{signal:Z})}catch(J){if(J instanceof Error&&J.name==="AbortError")throw Error("Device authorization cancelled");throw J}}}function qB(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 CB(B={}){let{label:Z,headless:$=!1,signal:W}=B;if(Z0(Z),$){let{deviceData:J,url:j,instructions:Q}=await G2(),y=(async()=>{let V=await K2(J,W),F=Date.now(),H0=i(V);return{id:Z0(Z||H0||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:V.access_token,refresh:V.refresh_token,expires:F+(V.expires_in??3600)*1000,enabled:!0,addedAt:F,lastUsed:F,lastRefreshedAt:F,accountId:H0}})();return{url:j,instructions:Q,completion:y}}let{redirectUri:z}=await z2(),X=await t0(),G=b0(crypto.getRandomValues(new Uint8Array(32)).buffer),K=B2(z,X,G),Y=(async()=>{try{if(W?.aborted)throw Error("Login cancelled");let J=await X2(X,G,void 0,W),j=Date.now(),Q=i(J);return{id:Z0(Z||Q||crypto.randomUUID()),label:Z||void 0,type:"oauth",access:J.access_token,refresh:J.refresh_token,expires:j+(J.expires_in??3600)*1000,enabled:!0,addedAt:j,lastUsed:j,lastRefreshedAt:j,accountId:Q}}finally{C(G)}})();return{url:K,instructions:"Complete authorization in your browser. This window will close automatically.",completion:Y}}function D0(B){if(B instanceof Error)return B.message;if(typeof B==="string")return B;try{return JSON.stringify(B)}catch{return String(B)}}var J2=s("quota"),$0="primary",W0="secondary",j2="app_EMoamEEZ73f0CkXaXp7hrann",H2="https://auth.openai.com";async function TB(B){let Z=await B.fetchImpl(`${H2}/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:j2}).toString()});if(!Z.ok){let W=B0(Z.headers.get("retry-after"));throw Object.assign(Error(`Token refresh failed: ${Z.status}`),{status:Z.status,retryAfter:W,isRefreshError:!0})}let $=await Z.json();if(!$||typeof $.access_token!=="string"||!$.access_token||typeof $.refresh_token!=="string"||!$.refresh_token||typeof $.expires_in!=="number")throw Object.assign(Error("Token refresh failed: malformed response"),{status:Z.status,isRefreshError:!0});return{access:$.access_token,refresh:$.refresh_token,expires:B.now()+$.expires_in*1000,expiresIn:$.expires_in}}var Q2="https://chatgpt.com/backend-api/wham/usage";async function fB(B){let Z=B.logger??J2,$=B.accountKey??"unknown",W=Date.now();Z.debug("wham usage fetch started",{pid:process.pid,accountId:$});try{let z=await B.fetchImpl(Q2,{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(!z.ok){let K=B0(z.headers.get("retry-after"));throw Object.assign(Error(`wham usage check failed: ${z.status}`),{status:z.status,retryAfter:K})}let{normalizeWham:X}=await import("./quota-normalize-n02dfdx0.js"),G=X(await z.json());return Z.debug("wham usage fetch succeeded",{pid:process.pid,accountId:$,status:z.status,elapsedMs:Date.now()-W}),G}catch(z){throw Z.warn("wham usage fetch failed",{pid:process.pid,accountId:$,status:typeof z?.status==="number"?z.status:"error",elapsedMs:Date.now()-W,error:D0(z)}),z}}import{createHash as N2}from"node:crypto";var P2=globalThis.setTimeout,V2=5;function h(B){let Z=B?.quota?.checkIntervalMinutes??V2;return Math.max(1,Z)*60000}function L2(B){return B?.quota?.enabled!==!1}function r(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function hB(B,Z,$,W,z){if(z!==void 0&&Number.isFinite(z)&&z>$)return z;let X=Z===$0?B?.primary:Z===W0?B?.secondary:void 0,G=X?.resetsAt?Date.parse(X.resetsAt):NaN;if(Number.isFinite(G)&&G>$)return G;return $+W}function F2(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function U0(B,Z,$){if(!L2(Z))return $+h(Z);let W=F2(Z),z=[];for(let X of["primary","secondary"]){let G=B?.[X];if(!G)continue;if(G.remainingPercent>=W[X])continue;let K=G.resetsAt?Date.parse(G.resetsAt):Number.NaN;if(!Number.isFinite(K)||K<=$)return $+h(Z);z.push(K)}if(!z.length)return $+h(Z);return Math.min(...z)+60000}function O2(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function b2(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function P(B){return N2("sha256").update(B).digest("hex").slice(0,16)}class O{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!==P(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)!==P(Z))return this.fallbacks.delete(B),this.fallbackTokenFps.delete(B),null;return $}getAllFallbacks(){return this.fallbacks}setMain(B,Z,$,W=!1){if(!W&&!M0(Z.quota))return;if(this.mainTokenFp=P(B),$&&this.mainQuotaAccountId&&this.mainQuotaAccountId!==$)this.clearRateLimited("main");if($)this.mainQuotaAccountId=$;if(this.main=Z,z0(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,z){if(!W&&!M0(Z.quota))return;let X=this.fallbacks.get(B)?.accountId;if(z&&X&&z!==X)this.clearRateLimited(B);let G=z??X;if(this.fallbacks.set(B,{...Z,accountId:G}),$)this.fallbackTokenFps.set(B,P($));else this.fallbackTokenFps.delete(B);if(z0(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=P(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 $=O.fallbackInflightKey(B,Z),W=this.inflightFallbacks.get($);if(W)return W;if(this.isFallbackBackedOff(B,Z)){let X=this.getFallback(B,Z);if(X)return X.quota;throw Error("Quota API rate-limited — try again later")}let z=this._fetchFallback(B,Z);return this.inflightFallbacks.set($,z),z}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=P(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=b2(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 $=O2(B);if(!$)return;let W=Z?P(Z):null;if(W&&$.tokenFingerprint&&$.tokenFingerprint!==W)return;let z={quota:$.quota,refreshAfter:U0($.quota,B,$.checkedAt),checkedAt:$.checkedAt};if(this.main&&this.main.checkedAt>=z.checkedAt&&(!W||!this.mainTokenFp||this.mainTokenFp===W))return;if(this.main=z,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=h(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 z=this.getFallback($.id,$.access);if(z&&z.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)!==P(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,P(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<O.API_CALL_GAP_MS)await new Promise((z)=>{let X=P2(z,O.API_CALL_GAP_MS-W);if(typeof X==="object"&&"unref"in X)X.unref()});return this.lastApiCallAt=this.now(),B()},$=this.apiGate.then(Z,Z);return this.apiGate=$.catch(()=>{}),$}async _fetchMain(B){let Z=P(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 T({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(),z=await this._fetchQuota(B),X=this.now();if(this.mainTokenFp=P(B),this.main={quota:z,refreshAfter:U0(z,this.storage,X),checkedAt:X},z0(z))this.clearRateLimited("main");return this.mainLastApiError=void 0,this.onMainQuotaFetched?.(z,X,this.mainTokenFp,W),z}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 T({name:O.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),z=this.now();return this.setFallback(B,{quota:W,refreshAfter:z+h(this.storage),checkedAt:z},Z,!0),this.fallbackApiErrors.delete(B),this.fallbackErrorTokenFps.delete(B),W}finally{await $.release()}}catch($){throw this._handleFallbackFetchError(B,Z,$),$}finally{this.inflightFallbacks.delete(O.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(O.isAuthError(B))return;this.mainLastApiError=A({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(O.isAuthError($))return;let W=P(Z),z=this.fallbackErrorTokenFps.get(B)===W?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,A({error:$,now:this.now(),previous:z})),this.fallbackErrorTokenFps.set(B,W)}}function M0(B){return Boolean(B.primary||B.secondary)}function z0(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 E2,randomUUID as S2}from"node:crypto";import{homedir as R2}from"node:os";import{dirname as y2,join as n}from"node:path";import{setTimeout as x2}from"node:timers/promises";import{randomUUID as D2}from"node:crypto";import{mkdir as U2,rename as M2,rm as _2,writeFile as q2}from"node:fs/promises";import{dirname as C2}from"node:path";async function f(B,Z){await U2(C2(B),{recursive:!0});let $=`${B}.${D2()}.tmp`;await q2($,`${JSON.stringify(Z,null,2)}
|
|
88
|
+
`,{encoding:"utf8",mode:384});try{await M2($,B)}catch(W){throw await _2($,{force:!0}).catch(()=>{}),W}}import{readFile as l2}from"node:fs/promises";var E=s("refresh"),_0=1e4,T2=50,x0="openai-auth.json",f2="openai-auth-state.json";function I2(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return n(process.env.XDG_CONFIG_HOME||n(R2(),".config"),"opencode")}function I(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||n(I2(),x0)}function o(B=I()){let Z=process.env.OPENCODE_OPENAI_AUTH_STATE_FILE?.trim();if(Z)return Z;return A2(B)}function A2(B){return B.endsWith(x0)?n(y2(B),f2):`${B}.state.json`}function b(B){return B.type==="oauth"}function m2(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 ZZ(B){return B.costZeroing?.enabled!==!1}class c extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var w2=[401,403,429],q0={primary:0,secondary:0},k2=!1,K0={primary:5,secondary:10};function H(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}function h2(B){return B instanceof c||H(B)&&B.name==="AccountRemovedDuringRefreshError"&&B.code==="ACCOUNT_REMOVED_DURING_REFRESH"}function C0(B){return{id:typeof B.id==="string"&&B.id.trim()?B.id.trim():S2(),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 E0(B){if(!H(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 v2(B){if(!H(B))return;let Z={};for(let W of["primary","secondary"]){let z=B[W];if(!H(z))continue;let X=Number(z.usedPercent),G=Number(z.remainingPercent),K=Number(z.checkedAt);if(!Number.isFinite(X)||!Number.isFinite(G)||!Number.isFinite(K))continue;let Y=typeof z.windowMinutes==="number"?z.windowMinutes:Number.NaN;Z[W]={usedPercent:X,remainingPercent:G,checkedAt:K,resetsAt:typeof z.resetsAt==="string"?z.resetsAt:void 0,...Number.isFinite(Y)&&Y>0?{windowMinutes:Y}:{}}}let $=typeof B.resetCreditsAvailable==="number"?B.resetCreditsAvailable:Number.NaN;if(Number.isFinite($)&&$>=0)Z.resetCreditsAvailable=$;return Object.keys(Z).length?Z:void 0}function p2(B){if(!H(B))return null;if(B.type==="api"){let Z=typeof B.baseURL==="string"?B.baseURL.trim():"",$=typeof B.apiKey==="string"?B.apiKey.trim():"";if(!m2(Z))return null;let W=B.authHeader==="x-api-key"?"x-api-key":"authorization-bearer";return{...C0(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{...C0(B),type:"oauth",access:typeof B.access==="string"?B.access:void 0,refresh:B.refresh,expires:typeof B.expires==="number"?B.expires:void 0,lastRefreshedAt:typeof B.lastRefreshedAt==="number"?B.lastRefreshedAt:void 0,lastRefreshError:E0(B.lastRefreshError),lastQuotaRefreshError:E0(B.lastQuotaRefreshError),quota:v2(B.quota)}}function T0(B){if(!H(B)||!Array.isArray(B.accounts))return null;return{version:1,main:{type:"opencode",provider:"openai"},routing:H(B.routing)?B.routing:void 0,fallbackOn:Array.isArray(B.fallbackOn)?B.fallbackOn.filter((Z)=>Number.isInteger(Z)):void 0,refresh:H(B.refresh)?B.refresh:void 0,quota:H(B.quota)?B.quota:void 0,dump:H(B.dump)?B.dump:void 0,costZeroing:H(B.costZeroing)?B.costZeroing:void 0,killswitch:H(B.killswitch)?B.killswitch:void 0,logging:H(B.logging)?B.logging:void 0,cachekeep:H(B.cachekeep)?B.cachekeep:void 0,mainAccountId:typeof B.mainAccountId==="string"?B.mainAccountId:void 0,accounts:B.accounts.map(p2).filter((Z)=>Z!=null)}}async function R(B){try{return{exists:!0,value:JSON.parse(await l2(B,"utf8"))}}catch(Z){if(Z.code==="ENOENT")return{exists:!1,value:null};throw Z}}function D(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}async function d2(B){let Z;try{Z=(await R(B)).value}catch{return null}if(!H(Z)||!Array.isArray(Z.accounts))return null;let $=new Set;for(let W of Z.accounts)if(H(W)&&typeof W.id==="string")$.add(W.id);return $}function f0(B,Z){if(!H(B))return B;let $=H(Z)?Z:{},W=H($.main)?$.main:void 0,z=H($.accounts)?$.accounts:{},X=H(B.quota)?B.quota:{},G=H(B.refresh)?B.refresh:{},K=W??X,Y=W??G,j=Array.isArray(B.accounts)?B.accounts.map((Q)=>{if(!H(Q))return Q;let y=typeof Q.id==="string"&&H(z[Q.id])?z[Q.id]:{};return{...Q,...y}}):void 0;return I0({...B,refresh:D({...G,mainLastRefreshError:Y.lastRefreshError,mainRefreshLeaseId:Y.refreshLeaseId,mainRefreshLeaseUntil:Y.refreshLeaseUntil,mainRefreshLeaseTokenHash:Y.refreshLeaseTokenHash}),quota:D({...X,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:j})}async function g2(B=I()){let Z=await R(B);if(!Z.exists)return null;let $=await R(o(B));return T0(f0(Z.value,$.value))}function I0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function i2(B){return D({id:B.id,label:B.label,type:B.type,enabled:B.enabled,addedAt:B.addedAt,accountId:B.accountId,baseURL:B.type==="api"?B.baseURL:void 0,authHeader:B.type==="api"?B.authHeader:void 0})}function A0(B){if(B.type==="api")return D({apiKey:B.apiKey,lastUsed:B.lastUsed});return D({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 a(B){return Math.max(B?.primary?.checkedAt??0,B?.secondary?.checkedAt??0)}function v(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function u2(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function s2(B,Z){if(!u2(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 r2(B,Z,$){let W=Z.lastRefreshedAt??0,z=$.lastRefreshedAt??0,X=Z.expires??0,G=$.expires??0,K=z>W?$:W>z?Z:G>X?$:X>G?Z:s2(Z,$);v(B,K,"access"),v(B,K,"refresh"),v(B,K,"expires"),v(B,K,"lastRefreshedAt"),v(B,K,"lastRefreshError")}function n2(B,Z){if(!H(B))return Z;let $=B,W=a($.quota),z=a(Z.quota),X=W>z,G=X?{...$,...Z,quota:$.quota,lastQuotaRefreshError:$.lastQuotaRefreshError}:{...$,...Z};if(!X&&!("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 r2(G,$,Z),G}function m0(B){let Z=B.refresh?D({enabled:B.refresh.enabled,intervalMinutes:B.refresh.intervalMinutes,refreshBeforeExpiryMinutes:B.refresh.refreshBeforeExpiryMinutes}):void 0,$=B.quota?D({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 I0({version:1,main:B.main,routing:B.routing,fallbackOn:B.fallbackOn,refresh:Z,quota:$,dump:B.dump,costZeroing:B.costZeroing,killswitch:B.killswitch,logging:B.logging,cachekeep:B.cachekeep,mainAccountId:B.mainAccountId,accounts:B.accounts.map(i2)})}async function p(B){let Z=Date.now()+_0;while(Date.now()<=Z){let $=await T({name:"save",ttlMs:_0,path:B});if($)return $;let W=Z-Date.now();if(W<=0)break;await x2(Math.min(T2,W))}throw Error(`Timed out acquiring account store lock for ${B}; refusing to overwrite newer account data`)}function w0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,A0($)]));return{version:1,main:D({quota:B.quota?.mainQuota,quotaCheckedAt:B.quota?.mainQuotaCheckedAt,quotaToken:B.quota?.mainQuotaToken,lastQuotaApiError:B.quota?.mainLastQuotaApiError,lastRefreshError:B.refresh?.mainLastRefreshError,refreshLeaseId:B.refresh?.mainRefreshLeaseId,refreshLeaseUntil:B.refresh?.mainRefreshLeaseUntil,refreshLeaseTokenHash:B.refresh?.mainRefreshLeaseTokenHash}),accounts:Z}}async function WZ(B,Z=I()){let $=o(Z),W=await p(Z);try{let z=await p($);try{let X=await R(Z),G=await R($),K=(X.exists?T0(f0(X.value,G.value)):null)??c2(),Y=B(K)??K,j={...H(X.value)?X.value:{},...m0(Y)};return await f(Z,j),await f($,w0(Y)),Y}finally{await z.release()}}finally{await W.release()}}function c2(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function a2(B,Z){B.main=B.main??{};let $=typeof B.main.quotaCheckedAt==="number"?B.main.quotaCheckedAt:a(B.main.quota),W=typeof Z.quota?.mainQuotaCheckedAt==="number"?Z.quota.mainQuotaCheckedAt:a(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 o2(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 Y0(B){if(Array.isArray(B))return B.map(Y0);if(!H(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,Y0($)]))}async function t2(B,Z=I(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let W=o(Z),z=await p(W);try{let X=(await R(W)).value,G=H(X)?{...X,version:1}:{version:1};if($.mainQuota)a2(G,B);if($.mainRefresh)o2(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await d2(Z);G.accounts={...H(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]=n2(G.accounts[J.id],A0(J))}if(K){for(let J of K)if(!B.accounts.some((j)=>j.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,Y0(G))}finally{await z.release()}}function e2(B){return B?.fallbackOn?.length?B.fallbackOn:w2}function zZ(B,Z){return e2(Z).includes(B)}function BB(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??q0.primary,secondary:Z.secondary??Z["1w"]??q0.secondary}}function J0(B){return B?.quota?.enabled!==!1}function l(B){return B?.quota?.failClosedOnUnknownQuota??k2}function k0(B,Z,$=Date.now()){if(!J0(Z))return!0;if(!B)return!l(Z);let W=BB(Z),z=l(Z);for(let X of["primary","secondary"]){let G=B[X];if(!G)continue;if(r(G,$)){if(z)return!1;continue}if(G.remainingPercent<W[X])return!1}return!0}function h0(B){return B?.killswitch?.enabled===!0}function S0(B){return{primary:B?.primary??B?.["5h"]??K0.primary,secondary:B?.secondary??B?.["1w"]??K0.secondary}}function v0(B,Z){if(!B?.killswitch)return K0;if(Z&&B.killswitch.accounts?.[Z])return S0(B.killswitch.accounts[Z]);return S0(B.killswitch.main)}function XZ(B,Z,$,W=Date.now()){if(!h0(Z))return!0;if(!B)return!l(Z);let z=v0(Z,$),X=l(Z);for(let G of["primary","secondary"]){let K=B[G];if(!K)continue;if(r(K,W)){if(X)return!1;continue}if(K.remainingPercent<z[G])return!1}return!0}function GZ(B,Z,$,W){if(!h0(W))return 300;let z=[],X=[{accountId:void 0,quota:B},...Z];for(let{accountId:K,quota:Y}of X){if(!Y)continue;let J=v0(W,K),j=[],Q=!1;for(let y of["primary","secondary"]){let V=Y[y];if(!V||r(V,$))continue;if(V.remainingPercent>=J[y])continue;let F=V.resetsAt?Date.parse(V.resetsAt):NaN;if(!Number.isFinite(F)||F<=$){Q=!0;break}j.push(F)}if(Q||j.length===0)continue;z.push(Math.max(...j))}if(z.length===0)return 300;let G=Math.min(...z);return Math.max(1,Math.ceil((G-$)/1000))}function ZB(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function KZ(B,Z=I()){let $=o(Z),W=await p(Z);try{let z=await p($);try{let X=await R(Z);if(X.exists&&H(X.value)){if(ZB(X.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let J=i({id_token:"",access_token:B.access,refresh_token:B.refresh});if(J)G.mainAccountId=J}let Y={...X.exists&&H(X.value)?X.value:{},...m0(G)};await f(Z,Y),await f($,w0(G))}finally{await z.release()}}finally{await W.release()}}function $B(B){return B?.refresh?.enabled!==!1}function WB(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function zB(B){return Math.floor(Math.random()*(B+1))}function S(B,Z,$){return!B.access||!B.expires||B.expires-$<=WB(Z)}function XB(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function GB(B,Z){return Boolean(B.mainAccountId&&Z.accountId&&Z.accountId===B.mainAccountId)}function N(B,Z){let $=B.accounts.findIndex((W)=>W.id===Z.id);if($!==-1)B.accounts[$]=Z}function X0(B){return B instanceof Error?B.message:String(B)}function j0(B,Z,$){B.lastRefreshError=N0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function G0(B,Z,$){if(B.lastQuotaRefreshError=A({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)j0(B,Z,$)}function KB(B){return`fallback-oauth-refresh-${E2("sha256").update(B).digest("base64url").slice(0,16)}`}function R0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function YB(B,Z){if(!B)return!1;return R0(B.primary,Z)||R0(B.secondary,Z)}function JB(B,Z,$){if(!B)return!1;let W=Z?.quota?.checkIntervalMinutes??5,z=Math.max(1,W)*60000,X=Math.max(B.primary?.checkedAt??0,B.secondary?.checkedAt??0);return $-X<z}function y0(B,Z,$){return!JB(B.quota,Z,$)}function jB(B,Z,$,W){return e($)&&k0(B.quota,Z,W)&&YB(B.quota,W)}function HB(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var QB=60000,NB=60000,PB=600000,VB=1e4,LB=100;var YZ=globalThis.setTimeout.bind(globalThis),JZ=globalThis.clearTimeout.bind(globalThis);class FB{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:$+HB(Z),checkedAt:$},B.access,!1,B.accountId)}async load(){return g2(this.configPath)}async save(B,Z){await t2(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(()=>{})},QB+zB(NB)),"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 z of Z.accounts){if(z.enabled===!1||!b(z))continue;if(GB(Z,z))continue;let X=!1,G=z;try{if(S(G,Z,this.now())){let K=G.lastRefreshError;if(K&&U(K,G.refresh,this.now()))throw X=!0,Error(d(K,this.now()));try{G=await this.refreshAccount(G,Z),W=!0}catch(Y){if(h2(Y))continue;X=!0;let J=Z.accounts.find((j)=>j.id===z.id&&b(j));if(J&&!U(J.lastRefreshError,J.refresh,this.now()))j0(J,Y,this.now()),N(Z,J),W=!0;throw Y}}if(this.seedFallbackQuota(G,Z),this.accountPassesQuotaPolicy(this.quotaPolicyAccount(G),Z))$.push(G)}catch(K){let Y=XB(G,this.now());if(X){if(!Y)continue}else if(!Y)continue;if(jB(G,Z,K,this.now()))E.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:X0(K)}),$.push(G);else if(!l(Z))$.push(G)}}if(W)await this.save(Z);return $}async markUsed(B){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)}accountPassesQuotaPolicy(B,Z){return k0(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||!$B(B))return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!b($))continue;if(!S($,B,this.now()))continue;if(U($.lastRefreshError,$.refresh,this.now()))continue;try{E.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){E.warn("fallback oauth background failed",{pid:process.pid,accountId:$.id,error:X0(W)}),j0($,W,this.now()),N(B,$),Z=!0}}if(Z)await this.save(B)}async refreshQuotaForDueAccounts(){let B=await this.load();if(!B||!J0(B))return;if(!this.options.fetchQuotaFn)return;let Z=!1;for(let $ of B.accounts){if($.enabled===!1||!b($))continue;let W=$;try{if(S(W,B,this.now())){if(U(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):y0(W,B,this.now())))continue;await this.refreshAccountQuota(W,B),Z=!0}catch(z){G0($,z,this.now()),N(B,$),Z=!0}}if(Z)await this.save(B),this.onFallbackStorageChanged?.()}async refreshQuotaForAllAccounts(B={}){let Z=await this.load(),$=[];if(!Z||!J0(Z))return{storage:Z,errors:$};if(!this.options.fetchQuotaFn)return{storage:Z,errors:$};let W=B.force??!1,z=!1;for(let X of Z.accounts){if(X.enabled===!1||!b(X))continue;let G=X;try{if(S(G,Z,this.now())){let K=G.lastRefreshError;if(K&&U(K,G.refresh,this.now()))throw Error(d(K,this.now()));G=await this.refreshAccount(G,Z),z=!0}if(!W&&!y0(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,N(Z,G),z=!0;continue}await this.refreshAccountQuota(G,Z),z=!0}catch(K){G0(X,K,this.now()),N(Z,X),z=!0,$.push({accountId:X.id,message:X0(K)})}}if(z)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 N(Z,G),G}let z=this.refreshAccountNow(B,Z,$).finally(()=>{this.refreshPromises.delete(B.id)});this.refreshPromises.set(B.id,z);let X=await z;return N(Z,X),X}async waitForConcurrentFallbackRefresh(B,Z,$,W){let z=Date.now()+VB;while(Date.now()<z){await new Promise((J)=>setTimeout(J,LB));let X=await this.load(),G=X?.accounts.find((J)=>J.id===B.id&&b(J));if(!G)continue;if((G.access!==$.access||G.refresh!==$.refresh||(G.expires??0)>($.expires??0)+60000)&&(W.force||!S(G,X,this.now())))return N(Z,G),E.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&&U(Y,G.refresh,this.now()))throw N(Z,G),Error(d(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let W=await this.load(),z=W?.accounts.find((K)=>K.id===B.id&&b(K));if(z&&!$.force&&!S(z,W,this.now()))return N(Z,z),z;let X=z??B,G=await T({name:KB(X.id),ttlMs:PB,path:this.configPath,now:this.now,renew:!0});if(!G){E.debug("fallback oauth refresh skipped file lock",{pid:process.pid,accountId:X.id});let K=await this.waitForConcurrentFallbackRefresh(B,Z,X,$);if(K)return K;throw Error("Fallback OAuth refresh is already in progress")}try{if(W=await this.load(),z=W?.accounts.find((j)=>j.id===B.id&&b(j)),z&&!$.force&&!S(z,W,this.now()))return N(Z,z),z;if(!z)throw new c(B.id);X=z;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});E.debug("fallback oauth refresh request start",{pid:process.pid,accountId:X.id,force:$.force===!0,expiresInMs:X.expires?X.expires-this.now():void 0});let Y=await K({refreshToken:X.refresh,fetchImpl:this.fetchImpl,now:this.now});if(X.access=Y.access,X.refresh=Y.refresh,X.expires=Y.expires,X.lastRefreshedAt=Y.expires-Y.expiresIn*1000,X.lastRefreshError=void 0,N(Z,X),await this.save(Z),!(await this.load())?.accounts.some((j)=>j.id===B.id))throw new c(B.id);return E.debug("fallback oauth refresh succeeded",{pid:process.pid,accountId:X.id,expiresInMs:X.expires?X.expires-this.now():void 0}),X}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")}),z=(X)=>this.quotaManager?this.quotaManager.refreshFallback($.id,X):W({accessToken:X,fetchImpl:this.fetchImpl,now:this.now});try{if(!$.access)throw Error(`Fallback account ${B.id} has no access token`);let X=await z($.access);$.quota=X,$.lastQuotaRefreshError=void 0,N(Z,$),await this.save(Z)}catch(X){throw G0(B,X,this.now()),N(Z,B),X}}}
|
|
89
|
+
export{Q0 as h,N0 as i,U as j,d as k,F0 as l,b0 as m,t0 as n,V0 as o,L0 as p,i as q,Z0 as r,B2 as s,C as t,z2 as u,X2 as v,G2 as w,K2 as x,qB as y,CB as z,D0 as A,TB as B,fB as C,hB as D,O as E,I as F,b as G,ZZ as H,K0 as I,g2 as J,WZ as K,zZ as L,h0 as M,v0 as N,XZ as O,GZ as P,KZ as Q,FB as R};
|