@cortexkit/opencode-openai-auth 0.7.2 → 0.8.0
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/README.md +9 -5
- package/dist/{index-9jpc8yct.js → index-02h7g5f9.js} +1 -1
- package/dist/index-2xppkvkx.js +2 -0
- package/dist/index-3w4vmckx.js +2 -0
- package/dist/{index-zxqb5ydj.js → index-507jh8bv.js} +1 -1
- package/dist/{index-zg1x8sty.js → index-944gsj1s.js} +1 -1
- package/dist/index-nshbgkz1.js +198 -0
- package/dist/{index-87145jkw.js → index-xyg86jgt.js} +1 -1
- package/dist/index.d.ts +381 -35
- package/dist/index.js +66 -161
- package/dist/protocol-Cv9ZmU0p.d.ts +24 -0
- package/dist/quota-normalize-wap0rne8.js +1 -0
- package/dist/rpc/port-file.d.ts +11 -9
- package/dist/rpc/port-file.js +1 -1
- package/dist/rpc/protocol.d.ts +2 -21
- package/dist/rpc/rpc-client.d.ts +6 -4
- package/dist/rpc/rpc-client.js +1 -1
- package/dist/rpc/rpc-dir.d.ts +7 -5
- package/dist/rpc/rpc-dir.js +1 -1
- package/dist/sidebar-state.d.ts +84 -83
- package/dist/sidebar-state.js +1 -1
- package/dist/{token-bvp0y166.js → token-jdvpwk60.js} +1 -1
- package/dist/token-util-zzm7paz9.js +1 -0
- package/dist/tui-preferences.d.ts +27 -26
- package/dist/tui-preferences.js +1 -1
- package/dist/tui.d.ts +18 -17
- package/package.json +7 -14
- package/src/tui/entry.mjs +2 -2
- package/src/tui-compiled/{core/account-paths.ts → raw/core-account-paths.ts} +29 -18
- package/src/tui-compiled/raw/logger.ts +53 -0
- package/src/tui-compiled/{rpc/port-file.ts → raw/rpc-port-file.ts} +1 -1
- package/src/tui-compiled/raw/rpc-protocol.ts +12 -0
- package/src/{rpc/rpc-client.ts → tui-compiled/raw/rpc-rpc-client.ts} +2 -2
- package/src/{sidebar-state.ts → tui-compiled/raw/sidebar-state.ts} +2 -2
- package/src/{tui/command-dialogs.tsx → tui-compiled/raw/tui-command-dialogs.tsx} +5 -5
- package/src/{tui.tsx → tui-compiled/raw/tui.tsx} +11 -10
- package/src/{core/account-paths.ts → tui-compiled/runtime/core-account-paths.ts} +29 -18
- package/src/tui-compiled/runtime/logger.ts +53 -0
- package/src/{rpc/port-file.ts → tui-compiled/runtime/rpc-port-file.ts} +1 -1
- package/src/tui-compiled/runtime/rpc-protocol.ts +12 -0
- package/src/tui-compiled/{rpc/rpc-client.ts → runtime/rpc-rpc-client.ts} +2 -2
- package/src/tui-compiled/{sidebar-state.ts → runtime/sidebar-state.ts} +2 -2
- package/src/tui-compiled/{tui/command-dialogs.tsx → runtime/tui-command-dialogs.tsx} +3 -4
- package/src/tui-compiled/{tui.tsx → runtime/tui.tsx} +10 -10
- package/src/tui-compiled/shared/internal.ts +6 -0
- package/src/{logger.ts → tui-compiled/shared/logger.ts} +82 -21
- package/src/tui-compiled/shared/paths.ts +33 -0
- package/src/{core → tui-compiled/shared}/refresh-file-lock.ts +7 -4
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -15
- package/dist/codex-http.d.ts +0 -3
- package/dist/commands.d.ts +0 -88
- package/dist/config.d.ts +0 -47
- package/dist/core/account-paths.d.ts +0 -25
- package/dist/core/accounts.d.ts +0 -330
- package/dist/core/atomic-write.d.ts +0 -1
- package/dist/core/background-quota-refresh.d.ts +0 -46
- package/dist/core/backoff.d.ts +0 -53
- package/dist/core/cachekeep.d.ts +0 -118
- package/dist/core/oauth.d.ts +0 -138
- package/dist/core/provider.d.ts +0 -70
- package/dist/core/quota-manager.d.ts +0 -192
- package/dist/core/refresh-all-quota.d.ts +0 -86
- package/dist/core/refresh-file-lock.d.ts +0 -12
- package/dist/core/reset-credits.d.ts +0 -116
- package/dist/core/sticky-routing.d.ts +0 -43
- package/dist/dump.d.ts +0 -20
- package/dist/hosted-web-search.d.ts +0 -5
- package/dist/index-8f1200qx.js +0 -6
- package/dist/index-cfjed1st.js +0 -89
- package/dist/index-nrvjr97q.js +0 -3
- package/dist/index-qaggaze1.js +0 -2
- package/dist/index-sdcpzbnk.js +0 -2
- package/dist/logger.d.ts +0 -22
- package/dist/model-costs.d.ts +0 -29
- package/dist/prompt-context.d.ts +0 -19
- package/dist/quota-normalize-dvwtmy7f.js +0 -1
- package/dist/quota-normalize.d.ts +0 -43
- package/dist/raw-ws-bun.d.ts +0 -40
- package/dist/raw-ws-node.d.ts +0 -37
- package/dist/raw-ws-upgrade.d.ts +0 -2
- package/dist/raw-ws.d.ts +0 -3
- package/dist/response-stream-error.d.ts +0 -12
- package/dist/rpc/notifications.d.ts +0 -5
- package/dist/rpc/rpc-server.d.ts +0 -17
- package/dist/token-util-jcj7k7pa.js +0 -1
- package/dist/tui/command-dialogs.d.ts +0 -21
- package/dist/util/error.d.ts +0 -1
- package/dist/util/open-url.d.ts +0 -6
- package/dist/util/proxy-env.d.ts +0 -4
- package/dist/util/record.d.ts +0 -1
- package/dist/util/stable-json.d.ts +0 -1
- package/dist/util/uuid-v7.d.ts +0 -1
- package/dist/version.d.ts +0 -1
- package/dist/ws-pool.d.ts +0 -57
- package/dist/ws.d.ts +0 -71
- package/src/rpc/notifications.ts +0 -54
- package/src/rpc/protocol.ts +0 -33
- package/src/rpc/rpc-server.ts +0 -172
- package/src/tui-compiled/core/refresh-file-lock.ts +0 -381
- package/src/tui-compiled/logger.ts +0 -196
- package/src/tui-compiled/rpc/protocol.ts +0 -33
- package/src/util/error.ts +0 -9
- package/src/util/open-url.ts +0 -30
- package/src/util/proxy-env.ts +0 -42
- package/src/util/record.ts +0 -3
- package/src/util/stable-json.ts +0 -15
- package/src/util/uuid-v7.ts +0 -18
- /package/src/{rpc/rpc-dir.ts → tui-compiled/raw/rpc-rpc-dir.ts} +0 -0
- /package/src/tui-compiled/{tui-preferences.ts → raw/tui-preferences.ts} +0 -0
- /package/src/tui-compiled/{rpc/rpc-dir.ts → runtime/rpc-rpc-dir.ts} +0 -0
- /package/src/{tui-preferences.ts → tui-compiled/runtime/tui-preferences.ts} +0 -0
- /package/src/tui-compiled/{util → shared/util}/error.ts +0 -0
- /package/src/tui-compiled/{util → shared/util}/open-url.ts +0 -0
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure path values shared by every host.
|
|
3
|
+
*
|
|
4
|
+
* Nothing here reads an environment variable or knows where a host keeps its
|
|
5
|
+
* configuration. A host resolves its own two file paths and hands them to the
|
|
6
|
+
* store as an `AccountPaths`; the only thing that must not drift between hosts
|
|
7
|
+
* is the file name itself, which is why the constants live here rather than in
|
|
8
|
+
* each host's own resolver.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { basename, dirname, join } from 'node:path'
|
|
12
|
+
|
|
13
|
+
export const ACCOUNT_FILE_NAME = 'openai-auth.json'
|
|
14
|
+
export const ACCOUNT_STATE_FILE_NAME = 'openai-auth-state.json'
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* The config file and the runtime-state file a store operation reads and writes.
|
|
18
|
+
*
|
|
19
|
+
* Both are required. A store function never derives one from the other, because
|
|
20
|
+
* a host may point its state file somewhere the derivation would not reach and
|
|
21
|
+
* a silently derived path would lock one file while writing another.
|
|
22
|
+
*/
|
|
23
|
+
export interface AccountPaths {
|
|
24
|
+
configPath: string
|
|
25
|
+
statePath: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Derive the state-file path from the config path without reading env vars. */
|
|
29
|
+
export function deriveStatePath(configPath: string): string {
|
|
30
|
+
return basename(configPath) === ACCOUNT_FILE_NAME
|
|
31
|
+
? join(dirname(configPath), ACCOUNT_STATE_FILE_NAME)
|
|
32
|
+
: `${configPath}.state.json`
|
|
33
|
+
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto'
|
|
2
2
|
import { mkdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises'
|
|
3
3
|
import { dirname, join } from 'node:path'
|
|
4
|
-
import { getAccountStoragePath } from './account-paths'
|
|
5
4
|
|
|
6
5
|
const setRefreshLockRenewalTimeout = globalThis.setTimeout.bind(globalThis)
|
|
7
6
|
const clearRefreshLockRenewalTimeout = globalThis.clearTimeout.bind(globalThis)
|
|
@@ -18,7 +17,12 @@ export function isLostMarkerRaceError(error: unknown): boolean {
|
|
|
18
17
|
export async function acquireRefreshFileLock(options: {
|
|
19
18
|
name: string
|
|
20
19
|
ttlMs: number
|
|
21
|
-
|
|
20
|
+
/**
|
|
21
|
+
* File the lock is named after. Required: the lock and the write it guards
|
|
22
|
+
* must target the same file, and a default resolved in here could only ever
|
|
23
|
+
* be one host's path.
|
|
24
|
+
*/
|
|
25
|
+
path: string
|
|
22
26
|
now?: () => number
|
|
23
27
|
renew?: boolean
|
|
24
28
|
renewIntervalMs?: number
|
|
@@ -37,8 +41,7 @@ export async function acquireRefreshFileLock(options: {
|
|
|
37
41
|
| 'release-owner-confirmed',
|
|
38
42
|
) => void | Promise<void>
|
|
39
43
|
}): Promise<{ release: () => Promise<void> } | null> {
|
|
40
|
-
const
|
|
41
|
-
const lockPath = `${accountPath}.${options.name}.lock`
|
|
44
|
+
const lockPath = `${options.path}.${options.name}.lock`
|
|
42
45
|
const legacyOwnerPath = join(lockPath, 'owner.json')
|
|
43
46
|
const ownerId = randomUUID()
|
|
44
47
|
const now = options.now ?? Date.now
|
package/dist/cli.d.ts
DELETED
package/dist/cli.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import{J as C,K as E,L as X,r as $,y as q,z as B}from"./index-cfjed1st.js";import{ua as Y}from"./index-8f1200qx.js";import"./index-nrvjr97q.js";import{Ka as Z}from"./index-zxqb5ydj.js";import{execFileSync as U}from"node:child_process";function V(z,K=process.platform,H=U){try{if(K==="win32"){H("cmd",["/c","start","",z],{stdio:"ignore",timeout:3000});return}H(K==="darwin"?"open":"xdg-open",[z],{stdio:"ignore",timeout:3000})}catch{}}function W(){console.log(`Usage:
|
|
3
|
-
npx @cortexkit/opencode-openai-auth login [--label <name>] [--headless]
|
|
4
|
-
npx @cortexkit/opencode-openai-auth list
|
|
5
|
-
npx @cortexkit/opencode-openai-auth remove <id>
|
|
6
|
-
|
|
7
|
-
Fallback accounts are stored in:
|
|
8
|
-
${Y()}`)}function P(z){let K=[],H={};for(let N=0;N<z.length;N++){let j=z[N];if(!j)continue;if(j.startsWith("--")){let J=j.slice(2),D=z[N+1];if(D&&!D.startsWith("--"))H[J]=D,N++;else H[J]=!0}else K.push(j)}return{positional:K,flags:H}}async function R(){let{positional:z,flags:K}=P(process.argv.slice(2)),[H,...N]=z;if(!H||H==="help")W(),process.exit(0);switch(H){case"login":{let j=typeof K.label==="string"?K.label:void 0,J=Boolean(K.headless);try{$(j)}catch(G){console.error(`
|
|
9
|
-
Error: ${G instanceof Error?G.message:String(G)}`),process.exit(1)}let{url:D,instructions:M,completion:T}=await B({label:j,headless:J});if(console.log(`
|
|
10
|
-
Open this URL in your browser and complete sign-in:
|
|
11
|
-
`),console.log(`${D}
|
|
12
|
-
`),M)console.log(`${M}
|
|
13
|
-
`);V(D);let O=await T,Q=!1;if(await X((G)=>{if(O.accountId&&G.mainAccountId&&O.accountId===G.mainAccountId)return Q=!0,G;return q(G.accounts,O),G}),Q)console.error(`
|
|
14
|
-
Error: that account is already your main (same ChatGPT account).`),console.error("A self-fallback would retry on the account that just returned 429."),process.exit(1);if(console.log(`
|
|
15
|
-
✓ Added account ${O.id}`),O.label)console.log(` Label: ${O.label}`);break}case"list":{let j=await E();if(!j||j.accounts.length===0)console.log("No fallback accounts configured.");else for(let J of j.accounts){let D=J.label,M=[` ${J.id}`];if(D)M.push(`(${D})`);M.push(J.enabled!==!1?"[enabled]":"[disabled]"),console.log(M.join(" "))}break}case"remove":{let j=N[0];if(!j)console.error("Error: remove requires an account ID."),W(),process.exit(1);let J=Y(),D=await C(J),M=D?D.has(j):!1,T=!1;if(await X((Q)=>{let G=Q.accounts.findIndex((L)=>L.id===j);if(G===-1)return Q;return Q.accounts.splice(G,1),T=!0,Q},J,{allowDrop:[j]}),!(T||M))console.error(`No account with id "${j}".`),process.exit(1);console.log(`Removed account ${j}.`);break}default:console.error(`Unknown command: ${H}`),W(),process.exit(1)}}if(Z.main==Z.module)R().catch((z)=>{console.error(z instanceof Error?z.message:String(z)),process.exit(1)});export{V as openBrowserForLogin};
|
package/dist/codex-http.d.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
export declare function hasWebSocketResponsesLiteMetadata(body: BodyInit | null | undefined): boolean;
|
|
2
|
-
export declare function sanitizeHttpFallbackBody(body: BodyInit | null | undefined): string | ArrayBuffer | ArrayBufferView<ArrayBuffer> | Blob | FormData | ReadableStream<any> | URLSearchParams | null | undefined;
|
|
3
|
-
export declare function sanitizeHttpFallbackInit(init: RequestInit | undefined): RequestInit | undefined;
|
package/dist/commands.d.ts
DELETED
|
@@ -1,88 +0,0 @@
|
|
|
1
|
-
import { type loadAccounts as defaultLoadAccounts } from './core/accounts';
|
|
2
|
-
import type { CacheKeepManager, CacheKeepWindow } from './core/cachekeep';
|
|
3
|
-
import type { QuotaManager } from './core/quota-manager';
|
|
4
|
-
import type { RefreshAllQuotaResult } from './core/refresh-all-quota';
|
|
5
|
-
import { type RunResetCreditResult } from './core/reset-credits';
|
|
6
|
-
import type { ApplyRequest, ApplyResult, CommandModalName, OpenDialogPayload } from './rpc/protocol';
|
|
7
|
-
export declare const OPENAI_QUOTA_COMMAND_NAME = "openai-quota";
|
|
8
|
-
export declare const OPENAI_ACCOUNT_COMMAND_NAME = "openai-account";
|
|
9
|
-
export declare const OPENAI_ROUTING_COMMAND_NAME = "openai-routing";
|
|
10
|
-
export declare const OPENAI_KILLSWITCH_COMMAND_NAME = "openai-killswitch";
|
|
11
|
-
export declare const OPENAI_DUMP_COMMAND_NAME = "openai-dump";
|
|
12
|
-
export declare const OPENAI_LOGGING_COMMAND_NAME = "openai-logging";
|
|
13
|
-
export declare const OPENAI_CACHEKEEP_COMMAND_NAME = "openai-cachekeep";
|
|
14
|
-
export declare const OPENAI_RESET_COMMAND_NAME = "openai-reset";
|
|
15
|
-
export declare const MODAL_COMMANDS: CommandModalName[];
|
|
16
|
-
export interface CommandContext {
|
|
17
|
-
accountStoragePath: string;
|
|
18
|
-
quotaManager: QuotaManager;
|
|
19
|
-
loadAccounts: typeof defaultLoadAccounts;
|
|
20
|
-
client: {
|
|
21
|
-
auth: {
|
|
22
|
-
set: (input: {
|
|
23
|
-
path: {
|
|
24
|
-
id: string;
|
|
25
|
-
};
|
|
26
|
-
body: {
|
|
27
|
-
type: string;
|
|
28
|
-
access?: string;
|
|
29
|
-
refresh: string;
|
|
30
|
-
expires?: number;
|
|
31
|
-
};
|
|
32
|
-
}) => Promise<unknown>;
|
|
33
|
-
};
|
|
34
|
-
};
|
|
35
|
-
/** Session ID for pushNotification delivery. */
|
|
36
|
-
sessionId?: string;
|
|
37
|
-
/** If set, pushNotification is wired up and can deliver feedback to the user. */
|
|
38
|
-
notify?: (payload: OpenDialogPayload) => void;
|
|
39
|
-
/** Refresh the sidebar-state file so the TUI modal shows current data. */
|
|
40
|
-
refreshSidebar?: () => Promise<void>;
|
|
41
|
-
/** Actively poll wham/usage for all accounts (main + fallbacks). */
|
|
42
|
-
refreshAllQuota?: () => Promise<RefreshAllQuotaResult[]>;
|
|
43
|
-
/** Prompt-cache cachekeep manager. Set when the command is wired. */
|
|
44
|
-
cacheKeepManager?: CacheKeepManager | null;
|
|
45
|
-
/** Updates the live loader's persisted-enabled cachekeep gate. */
|
|
46
|
-
setCacheKeepEnabled?: (enabled: boolean) => void;
|
|
47
|
-
/** Updates the live loader's persisted-subagent cachekeep gate. */
|
|
48
|
-
setCacheKeepSubagents?: (enabled: boolean) => void;
|
|
49
|
-
/** Updates the live loader's main-agent idle-cap bypass gate. */
|
|
50
|
-
setCacheKeepSustain?: (enabled: boolean) => void;
|
|
51
|
-
/** Updates the live loader's clock-hour warm window. undefined = no window. */
|
|
52
|
-
setCacheKeepWindow?: (window: CacheKeepWindow | undefined) => void;
|
|
53
|
-
/** Clears only the sticky account assignment for one OpenCode session. */
|
|
54
|
-
clearStickyRouting?: (sessionId: string) => Promise<boolean>;
|
|
55
|
-
/** Resolves the current session's usable sticky account, if one exists. */
|
|
56
|
-
getStickyRouting?: (sessionId: string) => Promise<string | undefined>;
|
|
57
|
-
resolveResetTarget?: (accountKey: string) => Promise<ResetTargetIdentity>;
|
|
58
|
-
fetchImpl?: typeof fetch;
|
|
59
|
-
now?: () => number;
|
|
60
|
-
randomUUID?: () => string;
|
|
61
|
-
refreshResetTargetQuota?: (accountKey: string) => Promise<RefreshAllQuotaResult>;
|
|
62
|
-
}
|
|
63
|
-
export interface ResetTargetIdentity {
|
|
64
|
-
accountKey: string;
|
|
65
|
-
label: string;
|
|
66
|
-
accessToken: string;
|
|
67
|
-
chatgptAccountId?: string;
|
|
68
|
-
}
|
|
69
|
-
type ResetCommandContext = CommandContext & Required<Pick<CommandContext, 'resolveResetTarget' | 'fetchImpl' | 'now' | 'randomUUID' | 'refreshResetTargetQuota'>>;
|
|
70
|
-
export declare function renderResetCoordinatorResult(result: RunResetCreditResult, ctx: ResetCommandContext, boundChatgptAccountId?: string): Promise<OpenDialogPayload>;
|
|
71
|
-
/**
|
|
72
|
-
* Strip credential-shaped fields from a dialog payload's knobs.
|
|
73
|
-
*
|
|
74
|
-
* Knobs are returned across the loopback RPC and JSON-serialized to the TUI, so
|
|
75
|
-
* a knob is a published surface. Individual commands project their own knobs
|
|
76
|
-
* deliberately (see accountKnob), but this is the boundary backstop: a future
|
|
77
|
-
* command that returns a stored object directly cannot leak credentials even if
|
|
78
|
-
* the projection is forgotten, because nothing credential-shaped survives here.
|
|
79
|
-
*
|
|
80
|
-
* Scrub rather than throw. A rejected dialog is a visible outage for a live
|
|
81
|
-
* command, while a scrubbed one keeps working with the leak removed; the warning
|
|
82
|
-
* is what gets the projection fixed. Recurses into nested objects and arrays,
|
|
83
|
-
* since the account list arrives as an array of records.
|
|
84
|
-
*/
|
|
85
|
-
export declare function scrubKnobs(value: unknown, path: string, found: string[]): unknown;
|
|
86
|
-
export declare function buildDialogPayload(command: CommandModalName, args: string, ctx: CommandContext): Promise<OpenDialogPayload>;
|
|
87
|
-
export declare function applyCommand(request: ApplyRequest, ctx: CommandContext): Promise<ApplyResult>;
|
|
88
|
-
export {};
|
package/dist/config.d.ts
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
export declare const DEFAULT_CODEX_API_ENDPOINT = "https://chatgpt.com/backend-api/codex/responses";
|
|
2
|
-
/** Shape of ~/.config/opencode/openai-auth.json (all fields optional). */
|
|
3
|
-
export interface OpenAIAuthConfig {
|
|
4
|
-
/** Inject the native web_search tool to keep the Codex prompt cache stable. Default true. */
|
|
5
|
-
webSearch?: boolean;
|
|
6
|
-
/** Use the WebSocket transport for /responses instead of plain HTTP. Default false. */
|
|
7
|
-
webSockets?: boolean;
|
|
8
|
-
/** Use the hand-rolled raw TCP/TLS WebSocket client (incremental streaming). Default false. */
|
|
9
|
-
rawWebSocket?: boolean;
|
|
10
|
-
/** Use Codex's Responses Lite request shape. Default false. */
|
|
11
|
-
responsesLite?: boolean;
|
|
12
|
-
/** Dump final Codex request bodies for cache debugging. Default false. */
|
|
13
|
-
dump?: boolean | {
|
|
14
|
-
enabled?: boolean;
|
|
15
|
-
};
|
|
16
|
-
/** Directory for request dumps. Defaults to the OS temp directory. */
|
|
17
|
-
dumpDir?: string;
|
|
18
|
-
/** Codex-compatible Responses endpoint. Defaults to ChatGPT's Codex backend. */
|
|
19
|
-
codexApiEndpoint?: string;
|
|
20
|
-
}
|
|
21
|
-
export interface ResolvedSettings {
|
|
22
|
-
webSearch: boolean;
|
|
23
|
-
webSockets: boolean;
|
|
24
|
-
rawWebSocket: boolean;
|
|
25
|
-
responsesLite: boolean;
|
|
26
|
-
dump: boolean;
|
|
27
|
-
dumpDir: string;
|
|
28
|
-
codexApiEndpoint: string;
|
|
29
|
-
}
|
|
30
|
-
export declare function getConfigDir(): string;
|
|
31
|
-
export declare function getConfigPath(): string;
|
|
32
|
-
/**
|
|
33
|
-
* Resolved settings, memoized per process.
|
|
34
|
-
*
|
|
35
|
-
* Env and the config file are read once because neither changes under a running
|
|
36
|
-
* process — except through a command that writes the config itself. Those
|
|
37
|
-
* commands must call `refreshSettings()`, or the process keeps serving the
|
|
38
|
-
* values it read at startup while the file on disk says otherwise.
|
|
39
|
-
*/
|
|
40
|
-
export declare function getSettings(): ResolvedSettings;
|
|
41
|
-
/**
|
|
42
|
-
* Drop the memoized settings after a command writes the config file, so the
|
|
43
|
-
* running process picks the change up without a restart.
|
|
44
|
-
*/
|
|
45
|
-
export declare function refreshSettings(): ResolvedSettings;
|
|
46
|
-
/** Test-only: drop the memoized settings so a later getSettings() re-reads env + config. */
|
|
47
|
-
export declare function resetSettingsForTest(): void;
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Where the account store lives.
|
|
3
|
-
*
|
|
4
|
-
* This is the ONLY definition. It used to be duplicated verbatim in both
|
|
5
|
-
* `accounts.ts` and `refresh-file-lock.ts`, because `accounts.ts` imports the
|
|
6
|
-
* lock and the reverse import would have been a cycle. Two copies of a path
|
|
7
|
-
* resolver is a bad trade for that: the lock and the write must agree on the
|
|
8
|
-
* exact file, and if the copies ever drifted, a writer would take a lock on one
|
|
9
|
-
* path while writing another — mutual exclusion silently lost on a file holding
|
|
10
|
-
* credentials. Nothing would fail a test, since each copy works on its own.
|
|
11
|
-
*
|
|
12
|
-
* This module imports nothing from either side, so both can depend on it.
|
|
13
|
-
*/
|
|
14
|
-
export declare const ACCOUNT_FILE_NAME = "openai-auth.json";
|
|
15
|
-
export declare const ACCOUNT_STATE_FILE_NAME = "openai-auth-state.json";
|
|
16
|
-
export declare function getAccountStoragePath(): string;
|
|
17
|
-
/** Derive the state-file path from the config path without reading env vars. */
|
|
18
|
-
export declare function deriveStatePath(configPath: string): string;
|
|
19
|
-
/**
|
|
20
|
-
* Detect path aliases without requiring either file to exist. This is defense
|
|
21
|
-
* in depth: hardlinks and bind mounts can still make distinct paths share a
|
|
22
|
-
* file, because neither is distinguishable through pathname identity.
|
|
23
|
-
*/
|
|
24
|
-
export declare function accountPathsCollide(configPath: string, statePath: string, platform?: NodeJS.Platform): boolean;
|
|
25
|
-
export declare function getAccountStatePath(configPath?: string): string;
|
package/dist/core/accounts.d.ts
DELETED
|
@@ -1,330 +0,0 @@
|
|
|
1
|
-
import { ACCOUNT_FILE_NAME, ACCOUNT_STATE_FILE_NAME, deriveStatePath, getAccountStatePath, getAccountStoragePath } from './account-paths';
|
|
2
|
-
import type { ProviderQuotaFn, ProviderRefreshFn, QuotaWindowName } from './provider.ts';
|
|
3
|
-
import { PRIMARY, SECONDARY } from './provider.ts';
|
|
4
|
-
export { ACCOUNT_FILE_NAME, ACCOUNT_STATE_FILE_NAME, deriveStatePath, getAccountStatePath, getAccountStoragePath, };
|
|
5
|
-
export type { QuotaWindowName };
|
|
6
|
-
export { PRIMARY, SECONDARY };
|
|
7
|
-
export type AccountQuotaWindow = {
|
|
8
|
-
usedPercent: number;
|
|
9
|
-
remainingPercent: number;
|
|
10
|
-
resetsAt?: string;
|
|
11
|
-
checkedAt: number;
|
|
12
|
-
windowMinutes?: number;
|
|
13
|
-
};
|
|
14
|
-
export interface OAuthQuotaSnapshot {
|
|
15
|
-
primary?: AccountQuotaWindow;
|
|
16
|
-
secondary?: AccountQuotaWindow;
|
|
17
|
-
resetCreditsAvailable?: number;
|
|
18
|
-
resetCreditsApplicable?: number;
|
|
19
|
-
}
|
|
20
|
-
export type AccountBase = {
|
|
21
|
-
id: string;
|
|
22
|
-
label?: string;
|
|
23
|
-
enabled?: boolean;
|
|
24
|
-
addedAt?: number;
|
|
25
|
-
lastUsed?: number;
|
|
26
|
-
/** Stable ChatGPT account identifier extracted from the OAuth token claims. */
|
|
27
|
-
accountId?: string;
|
|
28
|
-
};
|
|
29
|
-
export type AccountOperationError = {
|
|
30
|
-
message: string;
|
|
31
|
-
checkedAt: number;
|
|
32
|
-
nextRetryAt?: number;
|
|
33
|
-
retryCount?: number;
|
|
34
|
-
tokenHash?: string;
|
|
35
|
-
};
|
|
36
|
-
export type OAuthAccount = AccountBase & {
|
|
37
|
-
type: 'oauth';
|
|
38
|
-
access?: string;
|
|
39
|
-
refresh: string;
|
|
40
|
-
expires?: number;
|
|
41
|
-
lastRefreshedAt?: number;
|
|
42
|
-
lastRefreshError?: AccountOperationError;
|
|
43
|
-
lastQuotaRefreshError?: AccountOperationError;
|
|
44
|
-
quota?: OAuthQuotaSnapshot;
|
|
45
|
-
};
|
|
46
|
-
export type ApiKeyAccount = AccountBase & {
|
|
47
|
-
type: 'api';
|
|
48
|
-
apiKey?: string;
|
|
49
|
-
baseURL: string;
|
|
50
|
-
authHeader?: 'authorization-bearer' | 'x-api-key';
|
|
51
|
-
};
|
|
52
|
-
export type FallbackAccount = OAuthAccount | ApiKeyAccount;
|
|
53
|
-
export declare function isOAuthAccount(account: FallbackAccount): account is OAuthAccount;
|
|
54
|
-
export declare function isApiKeyAccount(account: FallbackAccount): account is ApiKeyAccount;
|
|
55
|
-
export declare function isValidApiBaseURL(value: string | undefined): boolean;
|
|
56
|
-
export type RoutingMode = 'main-first' | 'fallback-first' | 'sticky-balanced';
|
|
57
|
-
export type KillswitchThresholds = Partial<Record<QuotaWindowName | '5h' | '1w', number>>;
|
|
58
|
-
export type KillswitchConfig = {
|
|
59
|
-
enabled?: boolean;
|
|
60
|
-
main?: KillswitchThresholds;
|
|
61
|
-
accounts?: Record<string, KillswitchThresholds>;
|
|
62
|
-
};
|
|
63
|
-
export interface ResetInFlight {
|
|
64
|
-
redeemRequestId: string;
|
|
65
|
-
creditId: string;
|
|
66
|
-
startedAt: number;
|
|
67
|
-
}
|
|
68
|
-
export interface ResetLastOutcome {
|
|
69
|
-
code: string;
|
|
70
|
-
at: number;
|
|
71
|
-
previousOutcome?: {
|
|
72
|
-
code: string;
|
|
73
|
-
at: number;
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
export interface ResetAccountState {
|
|
77
|
-
inFlight?: ResetInFlight | Record<string, unknown>;
|
|
78
|
-
lastOutcome?: ResetLastOutcome;
|
|
79
|
-
cooldownUntil?: number;
|
|
80
|
-
}
|
|
81
|
-
export type ResetStateByAccount = Record<string, ResetAccountState>;
|
|
82
|
-
export type AccountStorage = {
|
|
83
|
-
version: 1;
|
|
84
|
-
main?: {
|
|
85
|
-
type: 'opencode';
|
|
86
|
-
provider: 'openai';
|
|
87
|
-
};
|
|
88
|
-
routing?: {
|
|
89
|
-
mode?: RoutingMode;
|
|
90
|
-
};
|
|
91
|
-
fallbackOn?: number[];
|
|
92
|
-
refresh?: {
|
|
93
|
-
enabled?: boolean;
|
|
94
|
-
intervalMinutes?: number;
|
|
95
|
-
refreshBeforeExpiryMinutes?: number;
|
|
96
|
-
mainLastRefreshError?: AccountOperationError;
|
|
97
|
-
mainRefreshLeaseId?: string;
|
|
98
|
-
mainRefreshLeaseUntil?: number;
|
|
99
|
-
mainRefreshLeaseTokenHash?: string;
|
|
100
|
-
};
|
|
101
|
-
quota?: {
|
|
102
|
-
enabled?: boolean;
|
|
103
|
-
checkIntervalMinutes?: number;
|
|
104
|
-
refreshEveryNRequests?: number;
|
|
105
|
-
minimumRemaining?: Partial<Record<QuotaWindowName | '5h' | '1w', number>>;
|
|
106
|
-
failClosedOnUnknownQuota?: boolean;
|
|
107
|
-
showToasts?: boolean;
|
|
108
|
-
mainQuota?: OAuthQuotaSnapshot;
|
|
109
|
-
mainQuotaCheckedAt?: number;
|
|
110
|
-
mainQuotaToken?: string;
|
|
111
|
-
mainLastQuotaApiError?: AccountOperationError;
|
|
112
|
-
};
|
|
113
|
-
reset?: ResetStateByAccount;
|
|
114
|
-
dump?: {
|
|
115
|
-
enabled?: boolean;
|
|
116
|
-
};
|
|
117
|
-
costZeroing?: {
|
|
118
|
-
enabled?: boolean;
|
|
119
|
-
};
|
|
120
|
-
killswitch?: KillswitchConfig;
|
|
121
|
-
logging?: {
|
|
122
|
-
level?: string;
|
|
123
|
-
};
|
|
124
|
-
cachekeep?: {
|
|
125
|
-
enabled?: boolean;
|
|
126
|
-
subagents?: boolean;
|
|
127
|
-
sustain?: boolean;
|
|
128
|
-
/** Clock-hour window start (0-23, inclusive) — keeps cachekeep idle warming
|
|
129
|
-
* inside `[startHour, endHour)` local hours. Omit to warm unconditionally. */
|
|
130
|
-
startHour?: number;
|
|
131
|
-
/** Clock-hour window end (0-23, exclusive) — must differ from startHour
|
|
132
|
-
* to be honored; an unset or equal hour falls back to "always warm". */
|
|
133
|
-
endHour?: number;
|
|
134
|
-
};
|
|
135
|
-
/** Stable ChatGPT account identifier of the main account (extracted from OAuth token). */
|
|
136
|
-
mainAccountId?: string;
|
|
137
|
-
accounts: FallbackAccount[];
|
|
138
|
-
};
|
|
139
|
-
export declare function isCostZeroingEnabled(storage: Pick<AccountStorage, 'costZeroing'>): boolean;
|
|
140
|
-
export type AccountRuntimeEntry = Partial<Pick<OAuthAccount, 'access' | 'refresh' | 'expires' | 'lastUsed' | 'lastRefreshedAt' | 'lastRefreshError' | 'lastQuotaRefreshError' | 'quota'> & Pick<ApiKeyAccount, 'apiKey' | 'lastUsed'>>;
|
|
141
|
-
export type AccountRuntimeState = {
|
|
142
|
-
version: 1;
|
|
143
|
-
main?: {
|
|
144
|
-
quota?: OAuthQuotaSnapshot;
|
|
145
|
-
quotaCheckedAt?: number;
|
|
146
|
-
quotaToken?: string;
|
|
147
|
-
lastQuotaApiError?: AccountOperationError;
|
|
148
|
-
lastRefreshError?: AccountOperationError;
|
|
149
|
-
refreshLeaseId?: string;
|
|
150
|
-
refreshLeaseUntil?: number;
|
|
151
|
-
refreshLeaseTokenHash?: string;
|
|
152
|
-
};
|
|
153
|
-
accounts?: Record<string, AccountRuntimeEntry>;
|
|
154
|
-
};
|
|
155
|
-
export type AccountStateSaveScope = {
|
|
156
|
-
mainQuota?: boolean;
|
|
157
|
-
mainRefresh?: boolean;
|
|
158
|
-
accounts?: true | string[];
|
|
159
|
-
};
|
|
160
|
-
export type AccountManagerOptions = {
|
|
161
|
-
now?: () => number;
|
|
162
|
-
fetchImpl?: typeof fetch;
|
|
163
|
-
configPath?: string;
|
|
164
|
-
onFallbackStorageChanged?: () => void;
|
|
165
|
-
/** Provider token-refresh function (constructor-injected). */
|
|
166
|
-
refreshFn?: ProviderRefreshFn;
|
|
167
|
-
/** Provider quota-fetch function (constructor-injected, OPTIONAL wham/usage supplement). */
|
|
168
|
-
fetchQuotaFn?: ProviderQuotaFn;
|
|
169
|
-
/** QuotaManager instance for unified cache (constructor-injected). */
|
|
170
|
-
quotaManager?: import('./quota-manager.ts').QuotaManager;
|
|
171
|
-
};
|
|
172
|
-
export type AccountRefreshError = {
|
|
173
|
-
accountId: string;
|
|
174
|
-
message: string;
|
|
175
|
-
};
|
|
176
|
-
export declare class AccountRemovedDuringRefreshError extends Error {
|
|
177
|
-
readonly code = "ACCOUNT_REMOVED_DURING_REFRESH";
|
|
178
|
-
constructor(accountId: string);
|
|
179
|
-
}
|
|
180
|
-
export declare const DEFAULT_KILLSWITCH_THRESHOLDS: {
|
|
181
|
-
primary: number;
|
|
182
|
-
secondary: number;
|
|
183
|
-
};
|
|
184
|
-
export declare function isSafeResetAccountKey(accountKey: string): boolean;
|
|
185
|
-
/**
|
|
186
|
-
* The set of account ids present in the CONFIG file (the authoritative account
|
|
187
|
-
* roster). Returns null when the config is absent or unreadable/malformed, so
|
|
188
|
-
* callers can fall back to non-pruning behavior rather than risk wiping live
|
|
189
|
-
* state. The config never holds secrets (see accountConfig), so reading it here
|
|
190
|
-
* is safe. Reads are lock-free but the file is written atomically, so a
|
|
191
|
-
* concurrent write is seen as either the complete old or complete new file.
|
|
192
|
-
*
|
|
193
|
-
* Trims and skips blank ids per the rule in collectConfigRosterIds above.
|
|
194
|
-
*/
|
|
195
|
-
export declare function readConfigRosterIds(path: string): Promise<Set<string> | null>;
|
|
196
|
-
export declare function loadAccounts(path?: string): Promise<AccountStorage | null>;
|
|
197
|
-
export declare function saveAccounts(storage: AccountStorage, path?: string): Promise<void>;
|
|
198
|
-
/**
|
|
199
|
-
* Read-modify-write the account store atomically under the save lock.
|
|
200
|
-
*
|
|
201
|
-
* Unlike saveAccounts (which UNION-merges the incoming accounts with the latest
|
|
202
|
-
* on-disk set so concurrent ADDS from another process are never lost), this
|
|
203
|
-
* reads the freshest state under the lock and writes the mutator's result
|
|
204
|
-
* AUTHORITATIVELY — no union. That is required for structural edits (remove,
|
|
205
|
-
* reorder): a union cannot express a deletion (the removed id reappears from
|
|
206
|
-
* `latest`) or a reordering (the union is seeded latest-first). Because the
|
|
207
|
-
* mutator runs against freshly-read state under the lock, an add committed by a
|
|
208
|
-
* concurrent process is still visible to it and preserved.
|
|
209
|
-
*
|
|
210
|
-
* The mutator may edit `current` in place and return it, or return a new
|
|
211
|
-
* storage object. Returning undefined means "no change" and still rewrites the
|
|
212
|
-
* freshly-read state (a harmless idempotent write).
|
|
213
|
-
*
|
|
214
|
-
* Load-time drop preservation: if normalizeAccount (called inside
|
|
215
|
-
* normalizeStorage) rejects an account whose id IS in the raw config roster,
|
|
216
|
-
* the previous behavior would erase that id silently on the next write. This
|
|
217
|
-
* function now carries the dropped raw entry through to the written config
|
|
218
|
-
* verbatim, so the on-disk state always matches the operator's intent (an
|
|
219
|
-
* account they added, even if temporarily un-loadable, stays in their list
|
|
220
|
-
* until they deliberately remove it).
|
|
221
|
-
*
|
|
222
|
-
* Removal seam: when the caller knows they are removing an id (e.g. the CLI
|
|
223
|
-
* `remove` command) and that id may be load-dropped — in which case the
|
|
224
|
-
* mutator cannot find it in `current.accounts` to splice it — the caller can
|
|
225
|
-
* pass `options.allowDrop: [id]`. Ids in `allowDrop` are NOT preserved; the
|
|
226
|
-
* mutator's splice still no-ops on a dropped id, but the absence of
|
|
227
|
-
* preservation completes the removal end-to-end.
|
|
228
|
-
*/
|
|
229
|
-
export declare function mutateAccounts(mutate: (current: AccountStorage) => AccountStorage | undefined, path?: string, options?: {
|
|
230
|
-
allowDrop?: readonly string[];
|
|
231
|
-
}): Promise<AccountStorage>;
|
|
232
|
-
export declare function saveAccountState(storage: AccountStorage, path?: string, scope?: AccountStateSaveScope): Promise<void>;
|
|
233
|
-
export declare function shouldFallbackStatus(status: number, storage: AccountStorage | null): boolean;
|
|
234
|
-
export declare function quotaSnapshotPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null, now?: number): boolean;
|
|
235
|
-
export declare function isKillswitchEnabled(storage: AccountStorage | null): boolean;
|
|
236
|
-
export declare function getKillswitchThresholdsForAccount(storage: AccountStorage | null, accountId?: string): {
|
|
237
|
-
primary: number;
|
|
238
|
-
secondary: number;
|
|
239
|
-
};
|
|
240
|
-
export declare function killswitchPassesPolicy(quota: OAuthQuotaSnapshot | undefined, storage: AccountStorage | null, accountId?: string, now?: number): boolean;
|
|
241
|
-
export declare function killswitchRetryAfterSeconds(mainQuota: OAuthQuotaSnapshot | undefined, fallbackAccounts: Array<{
|
|
242
|
-
accountId: string;
|
|
243
|
-
quota?: OAuthQuotaSnapshot;
|
|
244
|
-
}>, now: number, storage: AccountStorage | null): number;
|
|
245
|
-
/**
|
|
246
|
-
* Migrate an existing single-slot token into the multi-account store.
|
|
247
|
-
*
|
|
248
|
-
* Reads the existing token via the caller-provided `getAuth` (the ONLY
|
|
249
|
-
* read path — there is no `client.auth.get`). If a token exists and the
|
|
250
|
-
* config file is NOT yet an account store (content discriminator), seeds
|
|
251
|
-
* it as the primary OAuth account.
|
|
252
|
-
*
|
|
253
|
-
* Idempotent: a second run is a no-op because the content discriminator
|
|
254
|
-
* will already match.
|
|
255
|
-
*
|
|
256
|
-
* Tolerates expired/revoked tokens (migrates them; refresh handles validity).
|
|
257
|
-
*
|
|
258
|
-
* Guards against first-run races with the same save-lock order used by
|
|
259
|
-
* structural account mutations.
|
|
260
|
-
*/
|
|
261
|
-
export declare function migrateIfNeeded(existingToken: {
|
|
262
|
-
type: 'oauth';
|
|
263
|
-
access: string;
|
|
264
|
-
refresh: string;
|
|
265
|
-
expires: number;
|
|
266
|
-
} | undefined, path?: string): Promise<void>;
|
|
267
|
-
export declare function getQuotaCheckIntervalMs(storage: AccountStorage | null): number;
|
|
268
|
-
export declare function getRefreshIntervalMs(storage: AccountStorage | null): number;
|
|
269
|
-
export declare class FallbackAccountManager {
|
|
270
|
-
private readonly now;
|
|
271
|
-
private readonly fetchImpl;
|
|
272
|
-
private readonly configPath;
|
|
273
|
-
private readonly refreshPromises;
|
|
274
|
-
private refreshTimer;
|
|
275
|
-
private quotaTimer;
|
|
276
|
-
readonly quotaManager: import('./quota-manager.ts').QuotaManager | null;
|
|
277
|
-
private readonly onFallbackStorageChanged;
|
|
278
|
-
private readonly options;
|
|
279
|
-
constructor(options?: AccountManagerOptions);
|
|
280
|
-
/**
|
|
281
|
-
* Seed QuotaManager from persisted account.quota if no cache entry exists
|
|
282
|
-
* yet. Prevents unnecessary API calls when the on-disk snapshot is fresh.
|
|
283
|
-
*/
|
|
284
|
-
private seedFallbackQuota;
|
|
285
|
-
load(): Promise<AccountStorage | null>;
|
|
286
|
-
save(storage: AccountStorage, accountIds?: string[]): Promise<void>;
|
|
287
|
-
startBackgroundRefresh(): void;
|
|
288
|
-
stopBackgroundRefresh(): void;
|
|
289
|
-
getUsableFallbackAccounts(existingStorage?: AccountStorage | null): Promise<OAuthAccount[]>;
|
|
290
|
-
/**
|
|
291
|
-
* Stamp `lastUsed` on a served account.
|
|
292
|
-
*
|
|
293
|
-
* This runs on the request path after a response is already in hand, and
|
|
294
|
-
* `lastUsed` is telemetry: nothing reads it to make a routing, quota, or
|
|
295
|
-
* killswitch decision. The WHOLE operation is therefore best-effort, read
|
|
296
|
-
* included — loadAccounts deliberately rethrows anything that is not ENOENT so
|
|
297
|
-
* corruption surfaces to callers that must act on it, and a store lock shared
|
|
298
|
-
* by every session in the host process can legitimately time out under a burst
|
|
299
|
-
* of concurrent turns. Neither may reach this caller: it would discard a
|
|
300
|
-
* successful, already-billed provider response to record a timestamp. Losing
|
|
301
|
-
* the stamp costs nothing a later turn cannot redo.
|
|
302
|
-
*
|
|
303
|
-
* Contrast refreshAccount, whose save persists rotated tokens and MUST
|
|
304
|
-
* propagate: dropping it silently would strand a refresh and invalidate the
|
|
305
|
-
* account's credentials.
|
|
306
|
-
*/
|
|
307
|
-
markUsed(account: FallbackAccount): Promise<void>;
|
|
308
|
-
accountPassesQuotaPolicy(account: OAuthAccount, storage: AccountStorage | null): boolean;
|
|
309
|
-
/**
|
|
310
|
-
* Return the account with its quota overlaid from the unified QuotaManager
|
|
311
|
-
* cache (token-bound) when available, so quota-policy decisions use the same
|
|
312
|
-
* source of truth as the staleness check. Falls back to the stored
|
|
313
|
-
* account.quota when no manager is wired or the cache has no entry.
|
|
314
|
-
*/
|
|
315
|
-
private quotaPolicyAccount;
|
|
316
|
-
refreshDueAccounts(): Promise<void>;
|
|
317
|
-
refreshQuotaForDueAccounts(): Promise<void>;
|
|
318
|
-
refreshQuotaForAllAccounts(options?: {
|
|
319
|
-
force?: boolean;
|
|
320
|
-
}): Promise<{
|
|
321
|
-
storage: AccountStorage | null;
|
|
322
|
-
errors: AccountRefreshError[];
|
|
323
|
-
}>;
|
|
324
|
-
refreshAccount(account: OAuthAccount, storage: AccountStorage, options?: {
|
|
325
|
-
force?: boolean;
|
|
326
|
-
}): Promise<OAuthAccount>;
|
|
327
|
-
private waitForConcurrentFallbackRefresh;
|
|
328
|
-
private refreshAccountNow;
|
|
329
|
-
refreshAccountQuota(account: OAuthAccount, storage: AccountStorage): Promise<void>;
|
|
330
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function writeJsonAtomic(path: string, value: unknown): Promise<void>;
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
import { type RefreshAllQuotaDeps, type RefreshAllQuotaResult } from './refresh-all-quota';
|
|
2
|
-
export declare const BACKGROUND_QUOTA_REFRESH_INTERVAL_MS: number;
|
|
3
|
-
export declare const BACKGROUND_QUOTA_REFRESH_JITTER_MS = 30000;
|
|
4
|
-
export declare const BACKGROUND_QUOTA_FRESHNESS_MS: number;
|
|
5
|
-
export declare const BACKGROUND_QUOTA_REFRESH_LOCK_NAME = "bg-quota-refresh";
|
|
6
|
-
export declare const BACKGROUND_QUOTA_REFRESH_LOCK_TTL_MS = 120000;
|
|
7
|
-
type TimerHandle = ReturnType<typeof setInterval>;
|
|
8
|
-
interface BackgroundQuotaRefreshOptions {
|
|
9
|
-
setIntervalFn?: (callback: () => void, intervalMs: number) => TimerHandle;
|
|
10
|
-
clearIntervalFn?: (timer: TimerHandle) => void;
|
|
11
|
-
random?: () => number;
|
|
12
|
-
onError?: (error: unknown) => void;
|
|
13
|
-
}
|
|
14
|
-
type RefreshAllQuotaFn = (deps: RefreshAllQuotaDeps) => Promise<RefreshAllQuotaResult[]>;
|
|
15
|
-
type BackgroundLockHandle = {
|
|
16
|
-
release: () => Promise<void>;
|
|
17
|
-
};
|
|
18
|
-
export type BackgroundLockAcquirer = () => Promise<BackgroundLockHandle | null>;
|
|
19
|
-
/**
|
|
20
|
-
* Acquire the cross-process lock that serializes the background refresh.
|
|
21
|
-
* `renew` re-arms the TTL on an interval until release(), so a serial pass that
|
|
22
|
-
* outlasts the TTL (a fleet of accounts each costing a token refresh plus a
|
|
23
|
-
* wham fetch) never lets the lock expire mid-run — an expiry would let a second
|
|
24
|
-
* process start a concurrent refresh. Overrides exist so tests can drive the
|
|
25
|
-
* renewal with a mock clock and a fast interval.
|
|
26
|
-
*/
|
|
27
|
-
export declare function acquireBackgroundRefreshLock(configPath: string, overrides?: {
|
|
28
|
-
now?: () => number;
|
|
29
|
-
renewIntervalMs?: number;
|
|
30
|
-
}): Promise<BackgroundLockHandle | null>;
|
|
31
|
-
export declare function refreshQuotaInBackground(deps: RefreshAllQuotaDeps, refreshFn?: RefreshAllQuotaFn, acquireLock?: BackgroundLockAcquirer): Promise<RefreshAllQuotaResult[]>;
|
|
32
|
-
export declare class BackgroundQuotaRefresh {
|
|
33
|
-
private readonly setIntervalFn;
|
|
34
|
-
private readonly clearIntervalFn;
|
|
35
|
-
private readonly random;
|
|
36
|
-
private onError;
|
|
37
|
-
private run;
|
|
38
|
-
private timer;
|
|
39
|
-
private tickPromise;
|
|
40
|
-
private stopped;
|
|
41
|
-
constructor(options?: BackgroundQuotaRefreshOptions);
|
|
42
|
-
start(run: () => Promise<void>, onError?: ((error: unknown) => void) | undefined): void;
|
|
43
|
-
stop(): void;
|
|
44
|
-
isStopped(): boolean;
|
|
45
|
-
}
|
|
46
|
-
export {};
|