@juspay/neurolink
Version:
The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002
1,210 lines (1,209 loc) • 46.4 kB
JavaScript
/**
* Proxy usage statistics with restart- and handoff-safe persistence.
*
* Request handlers update memory synchronously. Small deltas are merged into a
* shared snapshot asynchronously, under a cross-process lock, so overlapping
* rolling workers cannot overwrite each other's counters.
*/
import { randomUUID } from "node:crypto";
import { mkdir, open, readFile, readdir, rename, rm, stat, } from "node:fs/promises";
import { basename, dirname, join } from "node:path";
import { normalizeAnthropicAccountKey } from "./accountSelection.js";
import { AsyncMutex } from "../utils/asyncMutex.js";
import { redactUrlsInText, sanitizeForLog } from "../utils/logSanitize.js";
import { writeJsonSnapshotAtomically } from "./snapshotPersistence.js";
const SNAPSHOT_SCHEMA_VERSION = 1;
const DEFAULT_FLUSH_INTERVAL_MS = 1_000;
const DEFAULT_LOCK_TIMEOUT_MS = 2_000;
const DEFAULT_STALE_LOCK_MS = 30_000;
const LOCK_RETRY_MS = 25;
const MAX_CORRUPT_SNAPSHOTS = 3;
const MAX_RECENT_TERMINAL_ERRORS = 20;
const MAX_TERMINAL_ERROR_FIELD_LENGTH = 128;
const MAX_TERMINAL_ERROR_MESSAGE_LENGTH = 500;
const TERMINAL_ERROR_ESCAPE = String.fromCharCode(27);
const TERMINAL_ERROR_BELL = String.fromCharCode(7);
const TERMINAL_ERROR_OSC_PATTERN = new RegExp(`${TERMINAL_ERROR_ESCAPE}\\][\\s\\S]*?(?:${TERMINAL_ERROR_BELL}|${TERMINAL_ERROR_ESCAPE}\\\\)`, "g");
const TERMINAL_ERROR_ANSI_PATTERN = new RegExp(`${TERMINAL_ERROR_ESCAPE}\\[[0-?]*[ -/]*[@-~]`, "g");
const TERMINAL_ERROR_CATEGORIES = [
"authentication",
"client_cancelled",
"fallback_exhausted",
"invalid_request",
"proxy_error",
"rate_limit",
"stream_error",
"unclassified",
"upstream_error",
"other",
];
class InvalidProxyStatsSnapshotError extends Error {
}
function emptyStats(startedAt) {
return {
startedAt,
totalAttempts: 0,
totalAttemptErrors: 0,
totalRequests: 0,
totalSuccess: 0,
totalErrors: 0,
totalRateLimits: 0,
totalTransientRateLimits: 0,
totalQuotaRateLimits: 0,
accounts: {},
};
}
function emptyTerminalErrorCounts() {
return Object.fromEntries(TERMINAL_ERROR_CATEGORIES.map((category) => [category, 0]));
}
function emptyTerminalErrorJournal(startedAt) {
return {
startedAt,
totalErrors: 0,
counts: emptyTerminalErrorCounts(),
recent: [],
};
}
/**
* Statistics must never use an email/label as their primary map key. One
* person can authenticate both provider pools with the same email, and a
* bare key silently merged their attempts, limits, and failures into one row.
*
* Keep non-account pseudo rows (passthrough, peer, internal) untouched. The
* display label remains separate so the CLI stays readable while persisted
* counters retain a collision-proof identity.
*/
function resolveStatsAccountIdentity(label, type) {
if (type === "codex-oauth") {
const key = label.startsWith("codex:") ? label : `codex:${label}`;
return {
key,
label: label.startsWith("codex:") ? label.slice("codex:".length) : label,
};
}
if (type === "oauth" || type === "api_key") {
const key = normalizeAnthropicAccountKey(label);
return {
key,
label: label.startsWith("anthropic:")
? label.slice("anthropic:".length)
: label,
};
}
return { key: label, label };
}
function cloneTerminalErrorSummary(summary) {
return { ...summary };
}
function cloneTerminalErrorJournal(journal) {
return {
...journal,
counts: { ...journal.counts },
recent: journal.recent.map(cloneTerminalErrorSummary),
};
}
function mergeTerminalErrorJournals(left, right) {
const counts = emptyTerminalErrorCounts();
for (const category of TERMINAL_ERROR_CATEGORIES) {
counts[category] = left.counts[category] + right.counts[category];
}
const byId = new Map();
for (const summary of [...left.recent, ...right.recent]) {
byId.set(summary.id, cloneTerminalErrorSummary(summary));
}
const recent = [...byId.values()]
.sort((a, b) => a.at - b.at || a.id.localeCompare(b.id))
.slice(-MAX_RECENT_TERMINAL_ERRORS);
return {
startedAt: Math.min(left.startedAt, right.startedAt),
totalErrors: left.totalErrors + right.totalErrors,
counts,
recent,
};
}
function terminalErrorsPathForStats(filePath) {
return join(dirname(filePath), "proxy-terminal-errors.json");
}
function clipTerminalErrorField(value) {
const clipped = value?.slice(0, MAX_TERMINAL_ERROR_FIELD_LENGTH);
return clipped ? clipped : undefined;
}
function stripTerminalErrorControlCharacters(value) {
const withoutAnsi = value
.replace(TERMINAL_ERROR_OSC_PATTERN, "")
.replace(TERMINAL_ERROR_ANSI_PATTERN, "");
return Array.from(withoutAnsi, (character) => {
const code = character.charCodeAt(0);
return code < 32 || (code >= 127 && code <= 159) ? " " : character;
}).join("");
}
function terminalErrorCategory(status, errorType) {
const normalized = errorType?.toLowerCase() ?? "";
if (status === 499 || normalized.includes("client_cancel")) {
return "client_cancelled";
}
if (normalized.includes("stream_telemetry")) {
return "proxy_error";
}
if (normalized.includes("stream")) {
return "stream_error";
}
if (status === 429 || normalized.includes("rate_limit")) {
return "rate_limit";
}
if (normalized.includes("auth") || normalized.includes("token_refresh")) {
return "authentication";
}
if (status === 404 ||
normalized.includes("invalid_request") ||
normalized.includes("not_found") ||
normalized.includes("construction_rejection")) {
return "invalid_request";
}
if (normalized.includes("fallback_exhausted")) {
return "fallback_exhausted";
}
if (normalized.includes("proxy") ||
normalized.includes("handler_error") ||
normalized.includes("runtime")) {
return "proxy_error";
}
if (normalized.includes("upstream") ||
normalized.includes("network") ||
normalized.includes("transient") ||
normalized.includes("generation") ||
normalized.includes("all_accounts") ||
normalized === "api_error" ||
status >= 500) {
return "upstream_error";
}
return normalized ? "other" : "unclassified";
}
function createTerminalErrorSummary(args) {
const { now, status, accountLabel, accountType, details } = args;
const accountIdentity = accountLabel && accountType
? resolveStatsAccountIdentity(accountLabel, accountType)
: undefined;
const errorType = clipTerminalErrorField(details?.errorType);
const message = details?.message
? stripTerminalErrorControlCharacters(sanitizeForLog(redactUrlsInText(details.message), MAX_TERMINAL_ERROR_MESSAGE_LENGTH + MAX_TERMINAL_ERROR_FIELD_LENGTH))
.replace(/\s+/g, " ")
.trim()
.slice(0, MAX_TERMINAL_ERROR_MESSAGE_LENGTH)
: undefined;
return {
id: randomUUID(),
at: now,
status,
category: terminalErrorCategory(status, errorType),
...(clipTerminalErrorField(details?.requestId)
? { requestId: clipTerminalErrorField(details?.requestId) }
: {}),
...(clipTerminalErrorField(accountLabel)
? { account: clipTerminalErrorField(accountLabel) }
: {}),
...(clipTerminalErrorField(details?.accountKey ?? accountIdentity?.key)
? {
accountKey: clipTerminalErrorField(details?.accountKey ?? accountIdentity?.key),
}
: {}),
...(clipTerminalErrorField(accountType)
? { accountType: clipTerminalErrorField(accountType) }
: {}),
...(errorType ? { errorType } : {}),
...(clipTerminalErrorField(details?.errorCode)
? { errorCode: clipTerminalErrorField(details?.errorCode) }
: {}),
...(clipTerminalErrorField(details?.terminalOutcome)
? {
terminalOutcome: clipTerminalErrorField(details?.terminalOutcome),
}
: {}),
...(message ? { message } : {}),
};
}
function cloneAccount(account) {
return { ...account };
}
function cloneStats(value) {
return {
...value,
accounts: Object.fromEntries(Object.entries(value.accounts).map(([label, account]) => [
label,
cloneAccount(account),
])),
};
}
function mergeAccountStats(left, right) {
if (!left) {
return cloneAccount(right);
}
const key = right.key ?? left.key;
return {
...(key ? { key } : {}),
label: right.label || left.label,
type: right.type || left.type,
attemptCount: left.attemptCount + right.attemptCount,
attemptErrorCount: left.attemptErrorCount + right.attemptErrorCount,
successCount: left.successCount + right.successCount,
errorCount: left.errorCount + right.errorCount,
rateLimitCount: left.rateLimitCount + right.rateLimitCount,
transientRateLimitCount: left.transientRateLimitCount + right.transientRateLimitCount,
quotaRateLimitCount: left.quotaRateLimitCount + right.quotaRateLimitCount,
lastAttemptAt: Math.max(left.lastAttemptAt, right.lastAttemptAt),
...(left.lastErrorAt || right.lastErrorAt
? {
lastErrorAt: Math.max(left.lastErrorAt ?? 0, right.lastErrorAt ?? 0),
}
: {}),
};
}
function mergeStats(left, right) {
const accounts = Object.fromEntries(Object.entries(left.accounts).map(([label, account]) => [
label,
cloneAccount(account),
]));
for (const [label, account] of Object.entries(right.accounts)) {
accounts[label] = mergeAccountStats(accounts[label], account);
}
return {
startedAt: Math.min(left.startedAt, right.startedAt),
totalAttempts: left.totalAttempts + right.totalAttempts,
totalAttemptErrors: left.totalAttemptErrors + right.totalAttemptErrors,
totalRequests: left.totalRequests + right.totalRequests,
totalSuccess: left.totalSuccess + right.totalSuccess,
totalErrors: left.totalErrors + right.totalErrors,
totalRateLimits: left.totalRateLimits + right.totalRateLimits,
totalTransientRateLimits: left.totalTransientRateLimits + right.totalTransientRateLimits,
totalQuotaRateLimits: left.totalQuotaRateLimits + right.totalQuotaRateLimits,
accounts,
};
}
function finiteNonNegativeInteger(value) {
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
}
function validAccountStats(value) {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value;
return ((candidate.key === undefined ||
(typeof candidate.key === "string" && candidate.key.length > 0)) &&
typeof candidate.label === "string" &&
typeof candidate.type === "string" &&
finiteNonNegativeInteger(candidate.attemptCount) &&
finiteNonNegativeInteger(candidate.attemptErrorCount) &&
finiteNonNegativeInteger(candidate.successCount) &&
finiteNonNegativeInteger(candidate.errorCount) &&
finiteNonNegativeInteger(candidate.rateLimitCount) &&
finiteNonNegativeInteger(candidate.transientRateLimitCount) &&
finiteNonNegativeInteger(candidate.quotaRateLimitCount) &&
finiteNonNegativeInteger(candidate.lastAttemptAt) &&
(candidate.lastErrorAt === undefined ||
finiteNonNegativeInteger(candidate.lastErrorAt)));
}
function validStats(value) {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value;
const counters = [
candidate.startedAt,
candidate.totalAttempts,
candidate.totalAttemptErrors,
candidate.totalRequests,
candidate.totalSuccess,
candidate.totalErrors,
candidate.totalRateLimits,
candidate.totalTransientRateLimits,
candidate.totalQuotaRateLimits,
];
if (!counters.every(finiteNonNegativeInteger) ||
!candidate.accounts ||
typeof candidate.accounts !== "object") {
return false;
}
return Object.entries(candidate.accounts).every(([key, account]) => validAccountStats(account) && key === (account.key ?? account.label));
}
function validOptionalString(value, maxLength) {
return (value === undefined ||
(typeof value === "string" && value.length <= maxLength));
}
function validTerminalErrorSummary(value) {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value;
return (typeof candidate.id === "string" &&
candidate.id.length > 0 &&
candidate.id.length <= MAX_TERMINAL_ERROR_FIELD_LENGTH &&
finiteNonNegativeInteger(candidate.at) &&
finiteNonNegativeInteger(candidate.status) &&
typeof candidate.category === "string" &&
TERMINAL_ERROR_CATEGORIES.includes(candidate.category) &&
validOptionalString(candidate.requestId, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.account, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.accountKey, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.accountType, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.errorType, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.errorCode, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.terminalOutcome, MAX_TERMINAL_ERROR_FIELD_LENGTH) &&
validOptionalString(candidate.message, MAX_TERMINAL_ERROR_MESSAGE_LENGTH));
}
function validTerminalErrorJournal(value) {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value;
if (!finiteNonNegativeInteger(candidate.startedAt) ||
!finiteNonNegativeInteger(candidate.totalErrors) ||
!candidate.counts ||
typeof candidate.counts !== "object" ||
!Array.isArray(candidate.recent) ||
candidate.recent.length > MAX_RECENT_TERMINAL_ERRORS ||
!candidate.recent.every(validTerminalErrorSummary)) {
return false;
}
const countEntries = Object.entries(candidate.counts);
return (countEntries.length === TERMINAL_ERROR_CATEGORIES.length &&
countEntries.every(([category, count]) => TERMINAL_ERROR_CATEGORIES.includes(category) && finiteNonNegativeInteger(count)) &&
countEntries.reduce((total, [, count]) => total + Number(count), 0) ===
candidate.totalErrors);
}
function validSnapshot(value) {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value;
return (candidate.schemaVersion === SNAPSHOT_SCHEMA_VERSION &&
finiteNonNegativeInteger(candidate.revision) &&
finiteNonNegativeInteger(candidate.updatedAt) &&
validStats(candidate.stats));
}
function validTerminalErrorSnapshot(value) {
if (!value || typeof value !== "object") {
return false;
}
const candidate = value;
return (candidate.schemaVersion === SNAPSHOT_SCHEMA_VERSION &&
finiteNonNegativeInteger(candidate.revision) &&
finiteNonNegativeInteger(candidate.updatedAt) &&
validTerminalErrorJournal(candidate.journal));
}
function isMissingFileError(error) {
return error?.code === "ENOENT";
}
function isCorruptSnapshotError(error) {
return (error instanceof SyntaxError ||
error instanceof InvalidProxyStatsSnapshotError);
}
function processIsRunning(pid) {
try {
process.kill(pid, 0);
return true;
}
catch (error) {
return error.code === "EPERM";
}
}
async function sleep(ms) {
await new Promise((resolve) => setTimeout(resolve, ms));
}
async function readLockOwner(lockPath) {
try {
const parsed = JSON.parse(await readFile(lockPath, "utf8"));
if (!parsed || typeof parsed !== "object") {
return null;
}
const candidate = parsed;
if (typeof candidate.token !== "string" ||
!finiteNonNegativeInteger(candidate.pid) ||
candidate.pid === 0 ||
!finiteNonNegativeInteger(candidate.acquiredAt)) {
return null;
}
return candidate;
}
catch {
return null;
}
}
async function removeAbandonedLock(lockPath, staleLockMs, now) {
const owner = await readLockOwner(lockPath);
try {
const lockStat = await stat(lockPath);
const oldEnough = now - lockStat.mtimeMs >= staleLockMs;
const ownerIsRunning = owner ? processIsRunning(owner.pid) : false;
if (owner && ownerIsRunning && !oldEnough) {
return false;
}
if ((owner && !ownerIsRunning) || oldEnough) {
await rm(lockPath, { force: true });
return true;
}
}
catch (error) {
return isMissingFileError(error);
}
return false;
}
async function acquireFileLock(lockPath, timeoutMs, staleLockMs, now) {
await mkdir(dirname(lockPath), { recursive: true, mode: 0o700 });
const deadline = Date.now() + timeoutMs;
while (true) {
const owner = {
token: randomUUID(),
pid: process.pid,
acquiredAt: now(),
};
let handle;
try {
handle = await open(lockPath, "wx", 0o600);
await handle.writeFile(JSON.stringify(owner));
const acquiredHandle = handle;
return async () => {
await acquiredHandle.close().catch(() => undefined);
const current = await readLockOwner(lockPath);
if (current?.token === owner.token) {
await rm(lockPath, { force: true }).catch(() => undefined);
}
};
}
catch (error) {
if (handle) {
await handle.close().catch(() => undefined);
await rm(lockPath, { force: true }).catch(() => undefined);
}
if (error.code !== "EEXIST") {
throw error;
}
}
if (await removeAbandonedLock(lockPath, staleLockMs, now())) {
continue;
}
if (Date.now() >= deadline) {
throw new Error(`Timed out acquiring proxy stats lock ${lockPath}`);
}
await sleep(LOCK_RETRY_MS);
}
}
export class ProxyUsageStatsStore {
now;
flushIntervalMs;
lockTimeoutMs;
staleLockMs;
filePath;
terminalErrorsFilePath;
stats;
pending;
terminalErrors;
pendingTerminalErrors;
pendingMutations = 0;
inFlightMutations = 0;
pendingTerminalErrorMutations = 0;
inFlightTerminalErrorMutations = 0;
revision = 0;
terminalErrorsRevision = 0;
flushTimer = null;
flushMutex = new AsyncMutex();
lastFlushedAt;
lastReconciledAt;
lastRecoveryAt;
lastError;
terminalErrorsLastFlushedAt;
terminalErrorsLastRecoveryAt;
terminalErrorsLastError;
snapshotVersion = 0;
constructor(options = {}) {
this.now = options.now ?? Date.now;
this.flushIntervalMs = options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;
this.lockTimeoutMs = options.lockTimeoutMs ?? DEFAULT_LOCK_TIMEOUT_MS;
this.staleLockMs = options.staleLockMs ?? DEFAULT_STALE_LOCK_MS;
this.filePath = options.filePath;
this.terminalErrorsFilePath =
options.terminalErrorsFilePath ??
(options.filePath
? terminalErrorsPathForStats(options.filePath)
: undefined);
const startedAt = this.now();
this.stats = emptyStats(startedAt);
this.pending = emptyStats(startedAt);
this.terminalErrors = emptyTerminalErrorJournal(startedAt);
this.pendingTerminalErrors = emptyTerminalErrorJournal(startedAt);
}
async initialize(filePath = this.filePath ?? "") {
this.cancelFlushTimer();
const configuredStatsPath = this.filePath;
const configuredTerminalErrorsPath = this.terminalErrorsFilePath;
this.filePath = filePath || undefined;
this.terminalErrorsFilePath =
this.filePath &&
configuredStatsPath === this.filePath &&
configuredTerminalErrorsPath
? configuredTerminalErrorsPath
: this.filePath
? terminalErrorsPathForStats(this.filePath)
: undefined;
const startedAt = this.now();
this.stats = emptyStats(startedAt);
this.pending = emptyStats(startedAt);
this.terminalErrors = emptyTerminalErrorJournal(startedAt);
this.pendingTerminalErrors = emptyTerminalErrorJournal(startedAt);
this.pendingMutations = 0;
this.inFlightMutations = 0;
this.pendingTerminalErrorMutations = 0;
this.inFlightTerminalErrorMutations = 0;
this.revision = 0;
this.terminalErrorsRevision = 0;
this.lastFlushedAt = undefined;
this.lastReconciledAt = undefined;
this.lastRecoveryAt = undefined;
this.lastError = undefined;
this.terminalErrorsLastFlushedAt = undefined;
this.terminalErrorsLastRecoveryAt = undefined;
this.terminalErrorsLastError = undefined;
this.snapshotVersion = 0;
if (!this.filePath) {
return;
}
try {
const snapshot = await this.readSnapshot();
if (snapshot) {
this.stats = cloneStats(snapshot.stats);
this.pending = emptyStats(this.now());
this.revision = snapshot.revision;
this.lastFlushedAt = snapshot.updatedAt;
}
this.lastReconciledAt = this.now();
}
catch (error) {
if (isCorruptSnapshotError(error)) {
try {
const recoveredSnapshot = await this.recoverCorruptSnapshot();
if (recoveredSnapshot) {
this.applySnapshot(recoveredSnapshot);
}
this.lastReconciledAt = this.now();
}
catch (recoveryError) {
this.lastError = this.describeError(recoveryError);
}
}
else {
this.lastError = this.describeError(error);
}
}
if (!this.terminalErrorsFilePath) {
return;
}
try {
const snapshot = await this.readTerminalErrorSnapshot();
if (snapshot) {
this.applyTerminalErrorSnapshot(snapshot);
}
}
catch (error) {
if (isCorruptSnapshotError(error)) {
try {
const recoveredSnapshot = await this.recoverCorruptTerminalErrorSnapshot();
if (recoveredSnapshot) {
this.applyTerminalErrorSnapshot(recoveredSnapshot);
}
}
catch (recoveryError) {
this.terminalErrorsLastError = this.describeError(recoveryError);
}
}
else {
this.terminalErrorsLastError = this.describeError(error);
}
}
}
recordAttempt(accountLabel, accountType) {
const attemptedAt = this.now();
this.applyAttempt(this.stats, accountLabel, accountType, attemptedAt);
this.applyAttempt(this.pending, accountLabel, accountType, attemptedAt);
this.markMutation();
}
recordFinalSuccess(accountLabel, accountType) {
this.applyFinalSuccess(this.stats, accountLabel, accountType);
this.applyFinalSuccess(this.pending, accountLabel, accountType);
this.markMutation();
}
recordAttemptError(accountLabel, accountType, status, rateLimitKind) {
const failedAt = this.now();
this.applyAttemptError(this.stats, accountLabel, accountType, status, rateLimitKind, failedAt);
this.applyAttemptError(this.pending, accountLabel, accountType, status, rateLimitKind, failedAt);
this.markMutation();
}
recordFinalError(status, accountLabel, accountType, details) {
const failedAt = this.now();
const summary = createTerminalErrorSummary({
now: failedAt,
status,
accountLabel,
accountType,
details,
});
this.applyFinalError(this.stats, accountLabel, accountType, failedAt);
this.applyFinalError(this.pending, accountLabel, accountType, failedAt);
this.applyTerminalError(this.terminalErrors, summary);
if (this.terminalErrorsFilePath) {
this.applyTerminalError(this.pendingTerminalErrors, summary);
this.pendingTerminalErrorMutations += 1;
}
this.markMutation();
}
getStats() {
return cloneStats(this.stats);
}
getAccountStats(label, type) {
const direct = this.stats.accounts[label];
if (direct) {
return cloneAccount(direct);
}
const identity = type
? resolveStatsAccountIdentity(label, type)
: undefined;
const account = identity
? this.stats.accounts[identity.key]
: (() => {
const matches = Object.values(this.stats.accounts).filter((candidate) => candidate.label === label);
return matches.length === 1 ? matches[0] : undefined;
})();
return account ? cloneAccount(account) : undefined;
}
getTerminalErrors() {
return cloneTerminalErrorJournal(this.terminalErrors);
}
getUsageSnapshot() {
const version = this.snapshotVersion;
return {
stats: this.getStats(),
statsVersion: version,
terminalErrors: this.getTerminalErrors(),
terminalErrorsVersion: version,
};
}
getPersistenceStatus() {
return {
enabled: !!this.filePath,
filePath: this.filePath ?? null,
revision: this.revision,
pendingMutations: this.pendingMutations,
inFlightMutations: this.inFlightMutations,
unpersistedMutations: this.pendingMutations + this.inFlightMutations,
lastFlushedAt: this.lastFlushedAt ?? null,
lastReconciledAt: this.lastReconciledAt ?? null,
lastRecoveryAt: this.lastRecoveryAt ?? null,
lastError: this.lastError ?? null,
terminalErrorsFilePath: this.terminalErrorsFilePath ?? null,
terminalErrorsRevision: this.terminalErrorsRevision,
terminalErrorsPending: this.pendingTerminalErrorMutations,
terminalErrorsInFlight: this.inFlightTerminalErrorMutations,
terminalErrorsUnpersisted: this.pendingTerminalErrorMutations +
this.inFlightTerminalErrorMutations,
terminalErrorsLastFlushedAt: this.terminalErrorsLastFlushedAt ?? null,
terminalErrorsLastRecoveryAt: this.terminalErrorsLastRecoveryAt ?? null,
terminalErrorsLastError: this.terminalErrorsLastError ?? null,
};
}
async flush() {
if (!this.filePath ||
(this.pendingMutations === 0 &&
this.inFlightMutations === 0 &&
this.pendingTerminalErrorMutations === 0 &&
this.inFlightTerminalErrorMutations === 0)) {
return;
}
this.cancelFlushTimer();
await this.flushMutex.runExclusive(async () => {
if (!this.filePath) {
return;
}
let statsDelta;
let terminalErrorDelta;
if (this.pendingMutations > 0) {
statsDelta = {
value: this.pending,
mutations: this.pendingMutations,
};
this.pending = emptyStats(this.now());
this.pendingMutations = 0;
this.inFlightMutations = statsDelta.mutations;
}
if (this.terminalErrorsFilePath &&
this.pendingTerminalErrorMutations > 0) {
terminalErrorDelta = {
value: this.pendingTerminalErrors,
mutations: this.pendingTerminalErrorMutations,
};
this.pendingTerminalErrors = emptyTerminalErrorJournal(this.now());
this.pendingTerminalErrorMutations = 0;
this.inFlightTerminalErrorMutations = terminalErrorDelta.mutations;
}
const countersPersisted = statsDelta
? await this.persistStatsDelta(statsDelta.value, statsDelta.mutations)
: true;
if (terminalErrorDelta) {
if (countersPersisted) {
await this.persistTerminalErrorDelta(terminalErrorDelta.value, terminalErrorDelta.mutations);
}
else {
this.pendingTerminalErrors = mergeTerminalErrorJournals(terminalErrorDelta.value, this.pendingTerminalErrors);
this.pendingTerminalErrorMutations += terminalErrorDelta.mutations;
this.inFlightTerminalErrorMutations = 0;
}
}
if (this.pendingMutations > 0 || this.pendingTerminalErrorMutations > 0) {
this.scheduleFlush();
}
});
}
async persistStatsDelta(delta, deltaMutations) {
if (!this.filePath) {
return false;
}
let releaseLock;
try {
releaseLock = await acquireFileLock(`${this.filePath}.lock`, this.lockTimeoutMs, this.staleLockMs, this.now);
let existing;
try {
existing = await this.readSnapshot();
}
catch (error) {
if (!isCorruptSnapshotError(error)) {
throw error;
}
await this.quarantineCorruptSnapshot();
existing = null;
}
const persisted = existing?.stats ?? emptyStats(delta.startedAt);
const merged = mergeStats(persisted, delta);
const revision = (existing?.revision ?? 0) + 1;
const updatedAt = this.now();
await writeJsonSnapshotAtomically(this.filePath, {
schemaVersion: SNAPSHOT_SCHEMA_VERSION,
revision,
updatedAt,
stats: merged,
}, 0o600);
this.revision = revision;
this.lastFlushedAt = updatedAt;
this.lastReconciledAt = updatedAt;
this.lastError = undefined;
this.stats = mergeStats(merged, this.pending);
this.inFlightMutations = 0;
return true;
}
catch (error) {
this.pending = mergeStats(delta, this.pending);
this.pendingMutations += deltaMutations;
this.inFlightMutations = 0;
this.lastError = this.describeError(error);
return false;
}
finally {
await releaseLock?.();
}
}
async persistTerminalErrorDelta(delta, deltaMutations) {
if (!this.terminalErrorsFilePath) {
return;
}
let releaseLock;
try {
releaseLock = await acquireFileLock(`${this.terminalErrorsFilePath}.lock`, this.lockTimeoutMs, this.staleLockMs, this.now);
let existing;
try {
existing = await this.readTerminalErrorSnapshot();
}
catch (error) {
if (!isCorruptSnapshotError(error)) {
throw error;
}
await this.quarantineCorruptTerminalErrorSnapshot();
existing = null;
}
const persisted = existing?.journal ?? emptyTerminalErrorJournal(delta.startedAt);
const merged = mergeTerminalErrorJournals(persisted, delta);
const revision = (existing?.revision ?? 0) + 1;
const updatedAt = this.now();
await writeJsonSnapshotAtomically(this.terminalErrorsFilePath, {
schemaVersion: SNAPSHOT_SCHEMA_VERSION,
revision,
updatedAt,
journal: merged,
}, 0o600);
this.terminalErrorsRevision = revision;
this.terminalErrorsLastFlushedAt = updatedAt;
this.terminalErrorsLastError = undefined;
this.terminalErrors = mergeTerminalErrorJournals(merged, this.pendingTerminalErrors);
this.inFlightTerminalErrorMutations = 0;
}
catch (error) {
this.pendingTerminalErrors = mergeTerminalErrorJournals(delta, this.pendingTerminalErrors);
this.pendingTerminalErrorMutations += deltaMutations;
this.inFlightTerminalErrorMutations = 0;
this.terminalErrorsLastError = this.describeError(error);
}
finally {
await releaseLock?.();
}
}
async reconcileUsageSnapshot() {
if (!this.filePath) {
return this.getUsageSnapshot();
}
return this.flushMutex.runExclusive(async () => {
try {
const snapshot = await this.readSnapshot();
if (snapshot) {
this.stats = mergeStats(snapshot.stats, this.pending);
this.revision = snapshot.revision;
this.lastFlushedAt = snapshot.updatedAt;
}
this.lastReconciledAt = this.now();
this.lastError = undefined;
}
catch (error) {
this.lastError = this.describeError(error);
}
if (this.terminalErrorsFilePath) {
try {
const snapshot = await this.readTerminalErrorSnapshot();
if (snapshot) {
this.terminalErrors = mergeTerminalErrorJournals(snapshot.journal, this.pendingTerminalErrors);
this.terminalErrorsRevision = snapshot.revision;
this.terminalErrorsLastFlushedAt = snapshot.updatedAt;
}
this.terminalErrorsLastError = undefined;
}
catch (error) {
this.terminalErrorsLastError = this.describeError(error);
}
}
this.snapshotVersion += 1;
return this.getUsageSnapshot();
});
}
async reconcile() {
return (await this.reconcileUsageSnapshot()).stats;
}
resetMemory() {
this.cancelFlushTimer();
const startedAt = this.now();
this.stats = emptyStats(startedAt);
this.pending = emptyStats(startedAt);
this.terminalErrors = emptyTerminalErrorJournal(startedAt);
this.pendingTerminalErrors = emptyTerminalErrorJournal(startedAt);
this.pendingMutations = 0;
this.inFlightMutations = 0;
this.pendingTerminalErrorMutations = 0;
this.inFlightTerminalErrorMutations = 0;
this.revision = 0;
this.terminalErrorsRevision = 0;
this.lastFlushedAt = undefined;
this.lastReconciledAt = undefined;
this.lastRecoveryAt = undefined;
this.lastError = undefined;
this.terminalErrorsLastFlushedAt = undefined;
this.terminalErrorsLastRecoveryAt = undefined;
this.terminalErrorsLastError = undefined;
this.snapshotVersion = 0;
}
async resetForTests() {
await this.flushMutex.runExclusive(async () => {
this.resetMemory();
this.filePath = undefined;
this.terminalErrorsFilePath = undefined;
});
}
markMutation() {
this.pendingMutations += 1;
this.snapshotVersion += 1;
this.scheduleFlush();
}
applyAttempt(target, accountLabel, accountType, attemptedAt) {
target.totalAttempts += 1;
const account = this.ensureAccount(target, accountLabel, accountType);
account.attemptCount += 1;
account.lastAttemptAt = attemptedAt;
}
applyFinalSuccess(target, accountLabel, accountType) {
target.totalRequests += 1;
target.totalSuccess += 1;
if (accountLabel && accountType) {
this.ensureAccount(target, accountLabel, accountType).successCount += 1;
}
}
applyAttemptError(target, accountLabel, accountType, status, rateLimitKind, failedAt) {
const account = this.ensureAccount(target, accountLabel, accountType);
target.totalAttemptErrors += 1;
account.attemptErrorCount += 1;
account.lastErrorAt = failedAt;
if (status !== 429) {
return;
}
target.totalRateLimits += 1;
account.rateLimitCount += 1;
if (rateLimitKind === "transient") {
target.totalTransientRateLimits += 1;
account.transientRateLimitCount += 1;
}
else if (rateLimitKind === "quota") {
target.totalQuotaRateLimits += 1;
account.quotaRateLimitCount += 1;
}
}
applyFinalError(target, accountLabel, accountType, failedAt) {
target.totalRequests += 1;
target.totalErrors += 1;
if (accountLabel && accountType) {
const account = this.ensureAccount(target, accountLabel, accountType);
account.errorCount += 1;
account.lastErrorAt = failedAt;
}
}
applyTerminalError(target, summary) {
target.totalErrors += 1;
target.counts[summary.category] += 1;
target.recent.push(cloneTerminalErrorSummary(summary));
if (target.recent.length > MAX_RECENT_TERMINAL_ERRORS) {
target.recent.splice(0, target.recent.length - MAX_RECENT_TERMINAL_ERRORS);
}
}
ensureAccount(target, label, type) {
const identity = resolveStatsAccountIdentity(label, type);
if (!target.accounts[identity.key]) {
target.accounts[identity.key] = {
key: identity.key,
label: identity.label,
type,
attemptCount: 0,
attemptErrorCount: 0,
successCount: 0,
errorCount: 0,
rateLimitCount: 0,
transientRateLimitCount: 0,
quotaRateLimitCount: 0,
lastAttemptAt: 0,
};
}
return target.accounts[identity.key];
}
scheduleFlush() {
if (!this.filePath || this.flushTimer) {
return;
}
this.flushTimer = setTimeout(() => {
this.flushTimer = null;
void this.flush().catch((error) => {
this.lastError = this.describeError(error);
this.scheduleFlush();
});
}, this.flushIntervalMs);
this.flushTimer.unref?.();
}
cancelFlushTimer() {
if (this.flushTimer) {
clearTimeout(this.flushTimer);
this.flushTimer = null;
}
}
async readSnapshot() {
if (!this.filePath) {
return null;
}
let raw;
try {
raw = await readFile(this.filePath, "utf8");
}
catch (error) {
if (isMissingFileError(error)) {
return null;
}
throw error;
}
const parsed = JSON.parse(raw);
if (!validSnapshot(parsed)) {
throw new InvalidProxyStatsSnapshotError(`Invalid proxy stats snapshot ${this.filePath}`);
}
return parsed;
}
async readTerminalErrorSnapshot() {
if (!this.terminalErrorsFilePath) {
return null;
}
let raw;
try {
raw = await readFile(this.terminalErrorsFilePath, "utf8");
}
catch (error) {
if (isMissingFileError(error)) {
return null;
}
throw error;
}
const parsed = JSON.parse(raw);
if (!validTerminalErrorSnapshot(parsed)) {
throw new InvalidProxyStatsSnapshotError(`Invalid proxy terminal-error snapshot ${this.terminalErrorsFilePath}`);
}
return parsed;
}
applySnapshot(snapshot) {
this.stats = cloneStats(snapshot.stats);
this.pending = emptyStats(this.now());
this.revision = snapshot.revision;
this.lastFlushedAt = snapshot.updatedAt;
}
applyTerminalErrorSnapshot(snapshot) {
this.terminalErrors = cloneTerminalErrorJournal(snapshot.journal);
this.pendingTerminalErrors = emptyTerminalErrorJournal(this.now());
this.terminalErrorsRevision = snapshot.revision;
this.terminalErrorsLastFlushedAt = snapshot.updatedAt;
}
async recoverCorruptSnapshot() {
if (!this.filePath) {
return null;
}
const releaseLock = await acquireFileLock(`${this.filePath}.lock`, this.lockTimeoutMs, this.staleLockMs, this.now);
try {
try {
return await this.readSnapshot();
}
catch (error) {
if (!isCorruptSnapshotError(error)) {
throw error;
}
await this.quarantineCorruptSnapshot();
return null;
}
}
finally {
await releaseLock();
}
}
async recoverCorruptTerminalErrorSnapshot() {
if (!this.terminalErrorsFilePath) {
return null;
}
const releaseLock = await acquireFileLock(`${this.terminalErrorsFilePath}.lock`, this.lockTimeoutMs, this.staleLockMs, this.now);
try {
try {
return await this.readTerminalErrorSnapshot();
}
catch (error) {
if (!isCorruptSnapshotError(error)) {
throw error;
}
await this.quarantineCorruptTerminalErrorSnapshot();
return null;
}
}
finally {
await releaseLock();
}
}
async quarantineCorruptSnapshot() {
if (!this.filePath) {
return;
}
const recoveredAt = this.now();
const quarantinePath = `${this.filePath}.corrupt.${recoveredAt}.${randomUUID()}`;
try {
await rename(this.filePath, quarantinePath);
}
catch (error) {
if (!isMissingFileError(error)) {
throw error;
}
return;
}
this.lastRecoveryAt = recoveredAt;
this.lastError = undefined;
await this.pruneCorruptSnapshots(this.filePath);
}
async quarantineCorruptTerminalErrorSnapshot() {
if (!this.terminalErrorsFilePath) {
return;
}
const recoveredAt = this.now();
const quarantinePath = `${this.terminalErrorsFilePath}.corrupt.${recoveredAt}.${randomUUID()}`;
try {
await rename(this.terminalErrorsFilePath, quarantinePath);
}
catch (error) {
if (!isMissingFileError(error)) {
throw error;
}
return;
}
this.terminalErrorsLastRecoveryAt = recoveredAt;
this.terminalErrorsLastError = undefined;
await this.pruneCorruptSnapshots(this.terminalErrorsFilePath);
}
async pruneCorruptSnapshots(filePath) {
const directory = dirname(filePath);
const prefix = `${basename(filePath)}.corrupt.`;
const quarantined = (await readdir(directory))
.filter((entry) => entry.startsWith(prefix))
.sort()
.reverse();
await Promise.all(quarantined
.slice(MAX_CORRUPT_SNAPSHOTS)
.map((entry) => rm(join(directory, entry), { force: true })));
}
describeError(error) {
return (error instanceof Error ? error.message : String(error)).slice(0, 1_000);
}
}
const defaultStore = new ProxyUsageStatsStore();
export async function initUsageStats(filePath) {
await defaultStore.initialize(filePath);
}
export function recordAttempt(accountLabel, accountType) {
defaultStore.recordAttempt(accountLabel, accountType);
}
export function recordFinalSuccess(accountLabel, accountType) {
defaultStore.recordFinalSuccess(accountLabel, accountType);
}
export function recordAttemptError(accountLabel, accountType, status, rateLimitKind) {
defaultStore.recordAttemptError(accountLabel, accountType, status, rateLimitKind);
}
export function recordFinalError(status, accountLabel, accountType, details) {
defaultStore.recordFinalError(status, accountLabel, accountType, details);
}
export function getStats() {
return defaultStore.getStats();
}
/** Return the process-local coherent snapshot without filesystem reconciliation. */
export function getUsageSnapshot() {
return defaultStore.getUsageSnapshot();
}
export async function getReconciledStats() {
return defaultStore.reconcile();
}
export async function getReconciledUsageSnapshot() {
return defaultStore.reconcileUsageSnapshot();
}
export function getAccountStats(label, type) {
return defaultStore.getAccountStats(label, type);
}
export function getTerminalErrors() {
return defaultStore.getTerminalErrors();
}
export function getUsageStatsPersistenceStatus() {
return defaultStore.getPersistenceStatus();
}
export async function flushUsageStats() {
await defaultStore.flush();
}
/** Reset process-local counters while intentionally preserving durable state. */
export function resetStats() {
defaultStore.resetMemory();
}
/** Disconnect persistence and clear singleton state between isolated tests. */
export async function resetUsageStatsForTests() {
await defaultStore.resetForTests();
}