@cortexkit/opencode-openai-auth 0.6.2 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +7 -7
- package/dist/core/account-paths.d.ts +25 -0
- package/dist/core/accounts.d.ts +31 -5
- package/dist/core/oauth.d.ts +1 -1
- package/dist/core/refresh-file-lock.d.ts +1 -5
- package/dist/{index-e08r33g5.js → index-00rp531h.js} +2 -2
- package/dist/{index-dz9a4xwy.js → index-4agbg1ec.js} +1 -1
- package/dist/{index-nwy7ec7p.js → index-7tsnfb8g.js} +1 -1
- package/dist/{index-hxpv25e8.js → index-80gqxa1f.js} +1 -1
- package/dist/index-8f1200qx.js +6 -0
- package/dist/index-ng315c61.js +89 -0
- package/dist/{index-s2vhsb2v.js → index-x55z0b3y.js} +1 -1
- package/dist/{index-meg0ng0z.js → index-zbpt7v1a.js} +1 -1
- package/dist/index.js +91 -91
- package/dist/{quota-normalize-vf2pj6n7.js → quota-normalize-s27mex1w.js} +1 -1
- package/dist/rpc/port-file.js +1 -1
- package/dist/rpc/rpc-client.js +1 -1
- package/dist/rpc/rpc-dir.js +1 -1
- package/dist/sidebar-state.js +1 -1
- package/dist/{token-esc14v6e.js → token-tag90anp.js} +1 -1
- package/dist/token-util-by7nbdh3.js +1 -0
- package/dist/tui-preferences.js +1 -1
- package/dist/version.d.ts +1 -1
- package/package.json +2 -1
- package/src/core/account-paths.ts +103 -0
- package/src/core/refresh-file-lock.ts +217 -145
- package/src/tui-compiled/core/account-paths.ts +103 -0
- package/src/tui-compiled/core/refresh-file-lock.ts +217 -145
- package/dist/index-n00ybbbq.js +0 -6
- package/dist/index-srgn00yp.js +0 -89
- package/dist/token-util-qkpkvy5t.js +0 -1
package/dist/index-srgn00yp.js
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import{ua as T}from"./index-n00ybbbq.js";import{Aa as h}from"./index-hxpv25e8.js";import{Ha as j2}from"./index-s2vhsb2v.js";import{createHash as d0}from"node:crypto";var g0=86400000,i0=300000,u0=3600000,s0=60000,r0=900000,n0=300000;function e(B){return B instanceof Error?B.message:String(B)}function c0(B){let Z=B?.status;if(typeof Z==="number")return Z===429||Z>=500;if(!(B instanceof Error))return!1;return B.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 B0(B){let Z=e(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 N0(B){return d0("sha256").update(B).digest("hex")}function P0(B){let Z=N0(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(c0(B.error))X=Math.min(u0,i0*2**Math.min(W-1,6));else X=g0;return{message:e(B.error),checkedAt:B.now,nextRetryAt:B.now+X,retryCount:W,tokenHash:Z}}function U(B,Z,$){if(!B?.nextRetryAt||B.nextRetryAt<=$)return!1;if(!Z)return!0;return B.tokenHash===N0(Z)}function i(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 I(B){let $=(B.previous?.retryCount??0)+1,W,X=B.error?.retryAfter;if(typeof X==="number"&&X>0)W=X*1000;else if(B0(B.error))W=Math.min(r0,s0*2**Math.min($-1,6));else W=n0;return{message:e(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 Z0(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 o0}from"node:http";import{setTimeout as a0}from"node:timers/promises";var V0="0.6.2";var r="app_EMoamEEZ73f0CkXaXp7hrann",q="https://auth.openai.com",w=1455,t0=3000,O0=`cortexkit-opencode-openai-auth/${V0}`,b0="main",e0=`"${b0}" is a reserved account id; choose a different label.`;function D0(B){let Z=new Uint8Array(B),$=String.fromCharCode(...Z);return btoa($).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function B2(){let Z=Array.from(crypto.getRandomValues(new Uint8Array(43))).map((W)=>"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"[W%66]).join(""),$=D0(await crypto.subtle.digest("SHA-256",new TextEncoder().encode(Z)));return{verifier:Z,challenge:$}}function L0(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 F0(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 s(B){if(B.id_token){let Z=L0(B.id_token),$=Z&&F0(Z);if($)return $}if(B.access_token){let Z=L0(B.access_token);return Z?F0(Z):void 0}return}function Z2(B){return typeof B==="string"&&B.toLowerCase()===b0}function $0(B){if(Z2(B))throw Error(e0);return B}function $2(B,Z,$){let W=new URLSearchParams({response_type:"code",client_id:r,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 W2(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:r,code_verifier:$.verifier}).toString()});if(!W.ok)throw Error(`Token exchange failed: ${W.status}`);return await W.json()}function X2(B){return B.replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}var z2=`<!doctype html>
|
|
2
|
-
<html>
|
|
3
|
-
<head>
|
|
4
|
-
<title>CortexKit OpenAI Auth - Authorization Successful</title>
|
|
5
|
-
<style>
|
|
6
|
-
body {
|
|
7
|
-
font-family:
|
|
8
|
-
system-ui,
|
|
9
|
-
-apple-system,
|
|
10
|
-
sans-serif;
|
|
11
|
-
display: flex;
|
|
12
|
-
justify-content: center;
|
|
13
|
-
align-items: center;
|
|
14
|
-
height: 100vh;
|
|
15
|
-
margin: 0;
|
|
16
|
-
background: #131010;
|
|
17
|
-
color: #f1ecec;
|
|
18
|
-
}
|
|
19
|
-
.container {
|
|
20
|
-
text-align: center;
|
|
21
|
-
padding: 2rem;
|
|
22
|
-
}
|
|
23
|
-
h1 {
|
|
24
|
-
color: #f1ecec;
|
|
25
|
-
margin-bottom: 1rem;
|
|
26
|
-
}
|
|
27
|
-
p {
|
|
28
|
-
color: #b7b1b1;
|
|
29
|
-
}
|
|
30
|
-
</style>
|
|
31
|
-
</head>
|
|
32
|
-
<body>
|
|
33
|
-
<div class="container">
|
|
34
|
-
<h1>Authorization Successful</h1>
|
|
35
|
-
<p>You can close this window and return to OpenCode.</p>
|
|
36
|
-
</div>
|
|
37
|
-
<script>
|
|
38
|
-
setTimeout(() => window.close(), 2000)
|
|
39
|
-
</script>
|
|
40
|
-
</body>
|
|
41
|
-
</html>`,u=(B)=>`<!doctype html>
|
|
42
|
-
<html>
|
|
43
|
-
<head>
|
|
44
|
-
<title>CortexKit OpenAI Auth - Authorization Failed</title>
|
|
45
|
-
<style>
|
|
46
|
-
body {
|
|
47
|
-
font-family:
|
|
48
|
-
system-ui,
|
|
49
|
-
-apple-system,
|
|
50
|
-
sans-serif;
|
|
51
|
-
display: flex;
|
|
52
|
-
justify-content: center;
|
|
53
|
-
align-items: center;
|
|
54
|
-
height: 100vh;
|
|
55
|
-
margin: 0;
|
|
56
|
-
background: #131010;
|
|
57
|
-
color: #f1ecec;
|
|
58
|
-
}
|
|
59
|
-
.container {
|
|
60
|
-
text-align: center;
|
|
61
|
-
padding: 2rem;
|
|
62
|
-
}
|
|
63
|
-
h1 {
|
|
64
|
-
color: #fc533a;
|
|
65
|
-
margin-bottom: 1rem;
|
|
66
|
-
}
|
|
67
|
-
p {
|
|
68
|
-
color: #b7b1b1;
|
|
69
|
-
}
|
|
70
|
-
.error {
|
|
71
|
-
color: #ff917b;
|
|
72
|
-
font-family: monospace;
|
|
73
|
-
margin-top: 1rem;
|
|
74
|
-
padding: 1rem;
|
|
75
|
-
background: #3c140d;
|
|
76
|
-
border-radius: 0.5rem;
|
|
77
|
-
}
|
|
78
|
-
</style>
|
|
79
|
-
</head>
|
|
80
|
-
<body>
|
|
81
|
-
<div class="container">
|
|
82
|
-
<h1>Authorization Failed</h1>
|
|
83
|
-
<p>An error occurred during authorization.</p>
|
|
84
|
-
<div class="error">${X2(B)}</div>
|
|
85
|
-
</div>
|
|
86
|
-
</body>
|
|
87
|
-
</html>`,k,m,L=new Map;function M(){return L.size}function C(B){if(L.delete(B),M()===0)_()}async function G2(){let B=`http://localhost:${w}/auth/callback`;if(k)return{port:w,redirectUri:B};if(m)return m;m=(async()=>{let Z=o0(($,W)=>{let X=new URL($.url||"/",`http://127.0.0.1:${w}`);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 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(u(j));return}if(!G){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(u("Missing state parameter"));return}if(!z){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(u("Missing authorization code"));return}let J=L.get(G);if(!J){if(M()===0)_();W.writeHead(400,{"Content-Type":"text/html"}),W.end(u("Unknown state — authorization may have expired"));return}C(G),W2(z,B,J.pkce).then((j)=>J.resolve(j)).catch((j)=>J.reject(j)),W.writeHead(200,{"Content-Type":"text/html"}),W.end(z2);return}if(X.pathname==="/cancel"){let z=X.searchParams.get("state"),G=z?[z]:[...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(w,"127.0.0.1",()=>{Z.off("error",W),$()})}),k=Z,{port:w,redirectUri:B}})();try{return await m}finally{m=void 0}}function _(){if(k){let B=k;k=void 0,B.close(()=>{}),B.closeIdleConnections?.(),setTimeout(()=>{B.closeAllConnections?.()},25).unref?.()}}function K2(B,Z,$=300000,W){return new Promise((X,z)=>{if(W?.aborted){C(Z),z(Error("Login cancelled"));return}let G=setTimeout(()=>{if(L.get(Z))C(Z),z(Error("OAuth callback timeout — authorization took too long"))},$),K=()=>{if(clearTimeout(G),L.get(Z))C(Z),z(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);X(Y)},reject:(Y)=>{if(clearTimeout(G),W)W.removeEventListener("abort",K);z(Y)}})})}async function Y2(){let B=await fetch(`${q}/api/accounts/deviceauth/usercode`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":O0},body:JSON.stringify({client_id:r})});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 J2(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(`${q}/api/accounts/deviceauth/token`,{method:"POST",headers:{"Content-Type":"application/json","User-Agent":O0},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:r,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=X-(Date.now()-z);if(K<=0)throw Error("Device authorization expired");let Y=Math.min($+t0,K);try{await a0(Y,void 0,{signal:Z})}catch(J){if(J instanceof Error&&J.name==="AbortError")throw Error("Device authorization cancelled");throw J}}}function y6(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 x6(B={}){let{label:Z,headless:$=!1,signal:W}=B;if($0(Z),$){let{deviceData:J,url:j,instructions:Q}=await Y2(),y=(async()=>{let V=await J2(J,W),F=Date.now(),Q0=s(V);return{id:$0(Z||Q0||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:Q0}})();return{url:j,instructions:Q,completion:y}}let{redirectUri:X}=await G2(),z=await B2(),G=D0(crypto.getRandomValues(new Uint8Array(32)).buffer),K=$2(X,z,G),Y=(async()=>{try{if(W?.aborted)throw Error("Login cancelled");let J=await K2(z,G,void 0,W),j=Date.now(),Q=s(J);return{id:$0(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 U0(B){if(B instanceof Error)return B.message;if(typeof B==="string")return B;try{return JSON.stringify(B)}catch{return String(B)}}var H2=h("quota"),W0="primary",X0="secondary",Q2="app_EMoamEEZ73f0CkXaXp7hrann",N2="https://auth.openai.com";async function m6(B){let Z=await B.fetchImpl(`${N2}/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:Q2}).toString()});if(!Z.ok){let W=Z0(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 P2="https://chatgpt.com/backend-api/wham/usage";async function k6(B){let Z=B.logger??H2,$=B.accountKey??"unknown",W=Date.now();Z.debug("wham usage fetch started",{pid:process.pid,accountId:$});try{let X=await B.fetchImpl(P2,{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=Z0(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-vf2pj6n7.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:U0(X)}),X}}import{createHash as V2}from"node:crypto";var L2=globalThis.setTimeout,F2=5;function v(B){let Z=B?.quota?.checkIntervalMinutes??F2;return Math.max(1,Z)*60000}function O2(B){return B?.quota?.enabled!==!1}function n(B,Z){if(!B?.resetsAt)return!1;let $=Date.parse(B.resetsAt);return Number.isFinite($)&&$<=Z}function g6(B,Z,$,W,X){if(X!==void 0&&Number.isFinite(X)&&X>$)return X;let z=Z===W0?B?.primary:Z===X0?B?.secondary:void 0,G=z?.resetsAt?Date.parse(z.resetsAt):NaN;if(Number.isFinite(G)&&G>$)return G;return $+W}function b2(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??15,secondary:Z.secondary??Z["1w"]??10}}function M0(B,Z,$){if(!O2(Z))return $+v(Z);let W=b2(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 $+v(Z);X.push(K)}if(!X.length)return $+v(Z);return Math.min(...X)+60000}function D2(B){if(!B?.quota?.mainQuota||!B.quota.mainQuotaCheckedAt)return null;return{quota:B.quota.mainQuota,checkedAt:B.quota.mainQuotaCheckedAt,tokenFingerprint:B.quota.mainQuotaToken}}function U2(B){let Z=B?.quota?.refreshEveryNRequests;return typeof Z==="number"&&Number.isFinite(Z)&&Z>0?Math.floor(Z):0}function P(B){return V2("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&&!_0(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,X){if(!W&&!_0(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,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 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=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=U2(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 $=D2(B);if(!$)return;let W=Z?P(Z):null;if(W&&$.tokenFingerprint&&$.tokenFingerprint!==W)return;let X={quota:$.quota,refreshAfter:M0($.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=v(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)!==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((X)=>{let z=L2(X,O.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=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(),X=await this._fetchQuota(B),z=this.now();if(this.mainTokenFp=P(B),this.main={quota:X,refreshAfter:M0(X,this.storage,z),checkedAt:z},z0(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 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),X=this.now();return this.setFallback(B,{quota:W,refreshAfter:X+v(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(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=I({error:B,now:this.now(),previous:this.mainLastApiError}),this.onApiError?.(this.mainLastApiError)}_handleFallbackFetchError(B,Z,$){if(O.isAuthError($))return;let W=P(Z),X=this.fallbackErrorTokenFps.get(B)===W?this.fallbackApiErrors.get(B):void 0;this.fallbackApiErrors.set(B,I({error:$,now:this.now(),previous:X})),this.fallbackErrorTokenFps.set(B,W)}}function _0(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 R2,randomUUID as y2}from"node:crypto";import{homedir as x2}from"node:os";import{dirname as T2,join as c}from"node:path";import{setTimeout as f2}from"node:timers/promises";import{randomUUID as M2}from"node:crypto";import{mkdir as _2,rename as q2,rm as C2,writeFile as E2}from"node:fs/promises";import{dirname as S2}from"node:path";async function f(B,Z){await _2(S2(B),{recursive:!0});let $=`${B}.${M2()}.tmp`;await E2($,`${JSON.stringify(Z,null,2)}
|
|
88
|
-
`,{encoding:"utf8",mode:384});try{await q2($,B)}catch(W){throw await C2($,{force:!0}).catch(()=>{}),W}}import{readFile as r2}from"node:fs/promises";var E=h("refresh"),q0=h("accounts"),A2=1e4,I2=15000,G0=50,T0="openai-auth.json",w2="openai-auth-state.json";function m2(){if(process.env.OPENCODE_CONFIG_DIR?.trim())return process.env.OPENCODE_CONFIG_DIR.trim();return c(process.env.XDG_CONFIG_HOME||c(x2(),".config"),"opencode")}function A(){return process.env.OPENCODE_OPENAI_AUTH_FILE?.trim()||c(m2(),T0)}function t(B=A()){let Z=process.env.OPENCODE_OPENAI_AUTH_STATE_FILE?.trim();if(Z)return Z;return k2(B)}function k2(B){return B.endsWith(T0)?c(T2(B),w2):`${B}.state.json`}function b(B){return B.type==="oauth"}function h2(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 GB(B){return B.costZeroing?.enabled!==!1}class o extends Error{code="ACCOUNT_REMOVED_DURING_REFRESH";constructor(B){super(`Fallback account ${B} was removed before refresh`);this.name="AccountRemovedDuringRefreshError"}}var v2=[401,403,429],C0={primary:0,secondary:0},p2=!1,Y0={primary:5,secondary:10};function H(B){return B!=null&&typeof B==="object"&&!Array.isArray(B)}var l2=new Set(["__proto__","constructor","prototype"]);function d2(B){return B.length>0&&!l2.has(B)}function g2(B){return B instanceof o||H(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():y2(),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 S0(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 i2(B){if(!H(B))return;let Z={};for(let $ of["primary","secondary"]){let W=B[$];if(!H(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 u2(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(!h2(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:S0(B.lastRefreshError),lastQuotaRefreshError:S0(B.lastQuotaRefreshError),quota:i2(B.quota)}}function s2(B){if(!H(B))return;let Z=Object.create(null);for(let[$,W]of Object.entries(B)){if(!d2($)||!H(W))continue;let X={};if(H(W.inFlight))X.inFlight={...W.inFlight};if(H(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,...H(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}function f0(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,reset:s2(B.reset),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(u2).filter((Z)=>Z!=null)}}async function R(B){try{return{exists:!0,value:JSON.parse(await r2(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 n2(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 A0(B,Z){if(!H(B))return B;let $=H(Z)?Z:{},W=H($.main)?$.main:void 0,X=H($.accounts)?$.accounts:{},z=H(B.quota)?B.quota:{},G=H(B.refresh)?B.refresh:{},K=W??z,Y=W??G,j=Array.isArray(B.accounts)?B.accounts.map((Q)=>{if(!H(Q))return Q;let y=typeof Q.id==="string"&&H(X[Q.id])?X[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({...z,mainQuota:K.quota,mainQuotaCheckedAt:K.quotaCheckedAt,mainQuotaToken:K.quotaToken,mainLastQuotaApiError:K.lastQuotaApiError}),accounts:j})}async function c2(B=A()){let Z=await R(B);if(!Z.exists)return null;let $=await R(t(B));return f0(A0(Z.value,$.value))}function I0(B){return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0))}function o2(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 w0(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 p(B,Z,$){if($ in Z)B[$]=Z[$];else delete B[$]}function a2(B,Z){return B.access===Z.access&&B.refresh===Z.refresh&&B.expires===Z.expires&&B.lastRefreshedAt===Z.lastRefreshedAt}function t2(B,Z){if(!a2(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 e2(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:t2(Z,$);p(B,K,"access"),p(B,K,"refresh"),p(B,K,"expires"),p(B,K,"lastRefreshedAt"),p(B,K,"lastRefreshError")}function B6(B,Z){if(!H(B))return Z;let $=B,W=a($.quota),X=a(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 e2(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:$,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(o2)})}async function d(B){let Z=Date.now(),$=Z+I2,W=0;while(Date.now()<=$){W++;let G=await T({name:"save",ttlMs:A2,path:B});if(G)return G;let K=$-Date.now();if(K<=0)break;await f2(Math.min(G0+l0(G0),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 ${G0}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 k0(B){let Z=Object.fromEntries(B.accounts.map(($)=>[$.id,w0($)]));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 YB(B,Z=A()){let $=t(Z),W=await d(Z);try{let X=await d($);try{let z=await R(Z),G=await R($),K=(z.exists?f0(A0(z.value,G.value)):null)??Z6(),Y=B(K)??K,j={...H(z.value)?z.value:{},...m0(Y)};return await f(Z,j),await f($,k0(Y)),Y}finally{await X.release()}}finally{await W.release()}}function Z6(){return{version:1,main:{type:"opencode",provider:"openai"},accounts:[]}}function $6(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 W6(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 J0(B){if(Array.isArray(B))return B.map(J0);if(!H(B))return B;return Object.fromEntries(Object.entries(B).filter(([,Z])=>Z!==void 0).map(([Z,$])=>[Z,J0($)]))}async function X6(B,Z=A(),$={mainQuota:!0,mainRefresh:!0,accounts:!0}){let W=t(Z),X=await d(W);try{let z=(await R(W)).value,G=H(z)?{...z,version:1}:{version:1};if($.mainQuota)$6(G,B);if($.mainRefresh)W6(G,B);if($.accounts){let K=$.accounts===!0?null:new Set($.accounts),Y=await n2(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]=B6(G.accounts[J.id],w0(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,J0(G))}finally{await X.release()}}function z6(B){return B?.fallbackOn?.length?B.fallbackOn:v2}function JB(B,Z){return z6(Z).includes(B)}function G6(B){let Z=B?.quota?.minimumRemaining||{};return{primary:Z.primary??Z["5h"]??C0.primary,secondary:Z.secondary??Z["1w"]??C0.secondary}}function j0(B){return B?.quota?.enabled!==!1}function g(B){return B?.quota?.failClosedOnUnknownQuota??p2}function h0(B,Z,$=Date.now()){if(!j0(Z))return!0;if(!B)return!g(Z);let W=G6(Z),X=g(Z);for(let z of["primary","secondary"]){let G=B[z];if(!G)continue;if(n(G,$)){if(X)return!1;continue}if(G.remainingPercent<W[z])return!1}return!0}function v0(B){return B?.killswitch?.enabled===!0}function R0(B){return{primary:B?.primary??B?.["5h"]??Y0.primary,secondary:B?.secondary??B?.["1w"]??Y0.secondary}}function p0(B,Z){if(!B?.killswitch)return Y0;if(Z&&B.killswitch.accounts?.[Z])return R0(B.killswitch.accounts[Z]);return R0(B.killswitch.main)}function jB(B,Z,$,W=Date.now()){if(!v0(Z))return!0;if(!B)return!g(Z);let X=p0(Z,$),z=g(Z);for(let G of["primary","secondary"]){let K=B[G];if(!K)continue;if(n(K,W)){if(z)return!1;continue}if(K.remainingPercent<X[G])return!1}return!0}function HB(B,Z,$,W){if(!v0(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=p0(W,K),j=[],Q=!1;for(let y of["primary","secondary"]){let V=Y[y];if(!V||n(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;X.push(Math.max(...j))}if(X.length===0)return 300;let G=Math.min(...X);return Math.max(1,Math.ceil((G-$)/1000))}function K6(B){return typeof B.version==="number"&&Array.isArray(B.accounts)}async function QB(B,Z=A()){let $=t(Z),W=await d(Z);try{let X=await d($);try{let z=await R(Z);if(z.exists&&H(z.value)){if(K6(z.value))return}if(!B)return;let G={version:1,main:{type:"opencode",provider:"openai"},accounts:[]};if(B.access){let J=s({id_token:"",access_token:B.access,refresh_token:B.refresh});if(J)G.mainAccountId=J}let Y={...z.exists&&H(z.value)?z.value:{},...m0(G)};await f(Z,Y),await f($,k0(G))}finally{await X.release()}}finally{await W.release()}}function Y6(B){return B?.refresh?.enabled!==!1}function J6(B){return(B?.refresh?.refreshBeforeExpiryMinutes??240)*60000}function l0(B){return Math.floor(Math.random()*(B+1))}function S(B,Z,$){return!B.access||!B.expires||B.expires-$<=J6(Z)}function j6(B,Z){return Boolean(B.access&&typeof B.expires==="number"&&B.expires>Z)}function H6(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 l(B){return B instanceof Error?B.message:String(B)}function H0(B,Z,$){B.lastRefreshError=P0({error:Z,now:$,refreshToken:B.refresh,previous:B.lastRefreshError})}function K0(B,Z,$){if(B.lastQuotaRefreshError=I({error:Z,now:$,previous:B.lastQuotaRefreshError}),Z?.isRefreshError===!0)H0(B,Z,$)}function Q6(B){return`fallback-oauth-refresh-${R2("sha256").update(B).digest("base64url").slice(0,16)}`}function y0(B,Z){if(!B)return!1;if(!B.resetsAt)return!0;let $=Date.parse(B.resetsAt);return Number.isFinite($)?$>Z:!0}function N6(B,Z){if(!B)return!1;return y0(B.primary,Z)||y0(B.secondary,Z)}function P6(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 x0(B,Z,$){return!P6(B.quota,Z,$)}function V6(B,Z,$,W){return B0($)&&h0(B.quota,Z,W)&&N6(B.quota,W)}function L6(B){let Z=B?.quota?.checkIntervalMinutes??5;return Math.max(1,Z)*60000}var F6=60000,O6=60000,b6=600000,D6=1e4,U6=100;var NB=globalThis.setTimeout.bind(globalThis),PB=globalThis.clearTimeout.bind(globalThis);class M6{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??A(),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:$+L6(Z),checkedAt:$},B.access,!1,B.accountId)}async load(){return c2(this.configPath)}async save(B,Z){await X6(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(()=>{})},F6+l0(O6)),"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||!b(X))continue;if(H6(Z,X))continue;let z=!1,G=X;try{if(S(G,Z,this.now())){let K=G.lastRefreshError;if(K&&U(K,G.refresh,this.now()))throw z=!0,Error(i(K,this.now()));try{G=await this.refreshAccount(G,Z),W=!0}catch(Y){if(g2(Y))continue;z=!0;let J=Z.accounts.find((j)=>j.id===X.id&&b(j));if(J&&!U(J.lastRefreshError,J.refresh,this.now()))H0(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=j6(G,this.now());if(z){if(!Y)continue}else if(!Y)continue;if(V6(G,Z,K,this.now()))E.debug("fallback quota using cached quota after refresh error",{pid:process.pid,accountId:G.id,error:l(K)}),$.push(G);else if(!g(Z))$.push(G)}}if(W)try{await this.save(Z)}catch(X){q0.warn("fallback selection bookkeeping not persisted",{pid:process.pid,error:l(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){q0.warn("lastUsed stamp not persisted",{pid:process.pid,accountId:B.id,error:l(Z)})}}accountPassesQuotaPolicy(B,Z){return h0(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||!Y6(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:l(W)}),H0($,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):x0(W,B,this.now())))continue;await this.refreshAccountQuota(W,B),Z=!0}catch(X){K0($,X,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,X=!1;for(let z of Z.accounts){if(z.enabled===!1||!b(z))continue;let G=z;try{if(S(G,Z,this.now())){let K=G.lastRefreshError;if(K&&U(K,G.refresh,this.now()))throw Error(i(K,this.now()));G=await this.refreshAccount(G,Z),X=!0}if(!W&&!x0(G,Z,this.now())){if(G.lastQuotaRefreshError)G.lastQuotaRefreshError=void 0,N(Z,G),X=!0;continue}await this.refreshAccountQuota(G,Z),X=!0}catch(K){K0(z,K,this.now()),N(Z,z),X=!0,$.push({accountId:z.id,message:l(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 N(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 N(Z,z),z}async waitForConcurrentFallbackRefresh(B,Z,$,W){let X=Date.now()+D6;while(Date.now()<X){await new Promise((J)=>setTimeout(J,U6));let z=await this.load(),G=z?.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,z,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(i(Y,this.now()))}return null}async refreshAccountNow(B,Z,$){let W=await this.load(),X=W?.accounts.find((K)=>K.id===B.id&&b(K));if(X&&!$.force&&!S(X,W,this.now()))return N(Z,X),X;let z=X??B,G=await T({name:Q6(z.id),ttlMs:b6,path:this.configPath,now:this.now,renew:!0});if(!G){E.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((j)=>j.id===B.id&&b(j)),X&&!$.force&&!S(X,W,this.now()))return N(Z,X),X;if(!X)throw new o(B.id);z=X;let K=this.options.refreshFn??(async()=>{throw Error("No refreshFn injected into FallbackAccountManager")});E.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,N(Z,z),await this.save(Z),!(await this.load())?.accounts.some((j)=>j.id===B.id))throw new o(B.id);return E.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,N(Z,$),await this.save(Z)}catch(z){throw K0(B,z,this.now()),N(Z,B),z}}}
|
|
89
|
-
export{N0 as h,P0 as i,U as j,i as k,O0 as l,D0 as m,B2 as n,L0 as o,F0 as p,s as q,$0 as r,$2 as s,C as t,G2 as u,K2 as v,Y2 as w,J2 as x,y6 as y,x6 as z,U0 as A,m6 as B,k6 as C,g6 as D,O as E,A as F,b as G,GB as H,Y0 as I,d2 as J,c2 as K,YB as L,JB as M,v0 as N,p0 as O,jB as P,HB as Q,QB as R,M6 as S};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{b as a}from"./index-nwy7ec7p.js";import"./index-s2vhsb2v.js";export default a();
|