@juspay/neurolink 10.6.5 → 10.7.1

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.
@@ -42,6 +42,17 @@ function printAnalysis(report) {
42
42
  logger.always(chalk.yellow(" Rate limits: unavailable"));
43
43
  }
44
44
  logger.always("");
45
+ logger.always(chalk.bold(" Account Routing"));
46
+ if (report.coverage.routingDecisions) {
47
+ logger.always(` Decisions: ${report.routing.totalRecords} (${report.routing.records.length} retained), modes: ${JSON.stringify(report.routing.modes)}`);
48
+ logger.always(` Selection reasons: ${JSON.stringify(report.routing.selectionReasons)}`);
49
+ logger.always(` Initial accounts: ${JSON.stringify(report.routing.initialAccounts)}`);
50
+ logger.always(` Final account changed after retry: ${report.routing.finalAccountChanges}, outside candidate set: ${report.routing.finalOutsideCandidateSet}`);
51
+ }
52
+ else {
53
+ logger.always(chalk.yellow(" Routing decisions: unavailable (legacy or no logs)"));
54
+ }
55
+ logger.always("");
45
56
  logger.always(chalk.bold(" Latency (ms)"));
46
57
  const latencyHeader = `${"METRIC".padEnd(22)} ${"COUNT".padStart(7)} ${"P50".padStart(9)} ${"P95".padStart(9)} ${"P99".padStart(9)} ${"MAX".padStart(9)}`;
47
58
  logger.always(` ${chalk.gray(latencyHeader)}`);
@@ -68,6 +79,7 @@ function printAnalysis(report) {
68
79
  logger.always("");
69
80
  logger.always(chalk.bold(" Data Quality"));
70
81
  logger.always(` ${report.dataQuality.linesRead} lines scanned, ${report.dataQuality.malformedLines} malformed, ${report.dataQuality.unsupportedLifecycleLines} unsupported lifecycle, ${report.dataQuality.lifecycleSequenceGaps} sequence gaps, ${report.dataQuality.lifecycleSequenceDuplicates} duplicates`);
82
+ logger.always(` Routing decisions: ${report.dataQuality.routingDecisions.valid} valid, ${report.dataQuality.routingDecisions.invalid} invalid, ${report.dataQuality.routingDecisions.absent} absent`);
71
83
  for (const [stream, range] of Object.entries(report.dataQuality.streams)) {
72
84
  if (range.observedFrom) {
73
85
  logger.always(` ${stream}: ${range.observedFrom} to ${range.observedTo}${range.startsAtOrBeforeRequestedWindow ? "" : chalk.yellow(" (starts after requested window)")}`);
@@ -2,15 +2,10 @@ import { readFile } from "node:fs/promises";
2
2
  import { homedir } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { AsyncMutex } from "../utils/asyncMutex.js";
5
+ import { ACCOUNT_COOLING_REASONS } from "./routingEvidence.js";
5
6
  import { writeJsonSnapshotAtomically } from "./snapshotPersistence.js";
6
7
  const COOLDOWN_FILE = "account-cooldowns.json";
7
- const VALID_REASONS = new Set([
8
- "weekly",
9
- "session",
10
- "unified",
11
- "transient",
12
- "auth",
13
- ]);
8
+ const VALID_REASONS = new Set(ACCOUNT_COOLING_REASONS);
14
9
  let customCooldownFilePath = null;
15
10
  let cacheLoaded = false;
16
11
  let cacheLoadPromise = null;
@@ -3,6 +3,7 @@ import { lstat, readdir, realpath, stat } from "node:fs/promises";
3
3
  import { homedir } from "node:os";
4
4
  import { createInterface } from "node:readline";
5
5
  import { isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import { ACCOUNT_COOLING_REASONS, PROXY_ACCOUNT_TYPES, PROXY_ACCOUNT_ROUTING_MODES, PROXY_ACCOUNT_ROUTING_REASONS, PROXY_ACCOUNT_ROUTING_STRATEGIES, } from "./routingEvidence.js";
6
7
  const LIFECYCLE_FILE_PATTERN = /^proxy-lifecycle-\d{4}-\d{2}-\d{2}\.jsonl$/;
7
8
  const REQUEST_FILE_PATTERN = /^proxy-\d{4}-\d{2}-\d{2}\.jsonl$/;
8
9
  const ATTEMPT_FILE_PATTERN = /^proxy-attempts-\d{4}-\d{2}-\d{2}\.jsonl$/;
@@ -14,6 +15,13 @@ const LIFECYCLE_EVENTS = new Set([
14
15
  "response_first_chunk",
15
16
  "request_terminal",
16
17
  ]);
18
+ const ROUTING_STRATEGIES = new Set(PROXY_ACCOUNT_ROUTING_STRATEGIES);
19
+ const ROUTING_MODES = new Set(PROXY_ACCOUNT_ROUTING_MODES);
20
+ const ROUTING_REASONS = new Set(PROXY_ACCOUNT_ROUTING_REASONS);
21
+ const ROUTING_ACCOUNT_TYPES = new Set(PROXY_ACCOUNT_TYPES);
22
+ const COOLING_REASONS = new Set(ACCOUNT_COOLING_REASONS);
23
+ const MAX_RETAINED_ROUTING_RECORDS = 200;
24
+ const MAX_ROUTING_RECORDS_BEFORE_COMPACTION = MAX_RETAINED_ROUTING_RECORDS * 2;
17
25
  function isContainedPath(root, candidate) {
18
26
  const candidateRelative = relative(root, candidate);
19
27
  return (candidateRelative.length > 0 &&
@@ -45,6 +53,130 @@ function finiteNumber(value) {
45
53
  function stringValue(value) {
46
54
  return typeof value === "string" && value.length > 0 ? value : null;
47
55
  }
56
+ function isNullableString(value) {
57
+ return value === null || (typeof value === "string" && value.length > 0);
58
+ }
59
+ function isNullableFiniteNumber(value) {
60
+ return value === null || finiteNumber(value) !== null;
61
+ }
62
+ function routingCandidateValue(value) {
63
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
64
+ return null;
65
+ }
66
+ const candidate = value;
67
+ const requiredBooleanFields = [
68
+ "configuredPrimary",
69
+ "usable",
70
+ "saturated",
71
+ "quotaObserved",
72
+ "coolingActive",
73
+ ];
74
+ const requiredNullableNumberFields = [
75
+ "quotaLastUpdated",
76
+ "quotaAgeMs",
77
+ "coolingUntil",
78
+ "sessionUsed",
79
+ "sessionResetAt",
80
+ "sessionResetBucket",
81
+ "weeklyUsed",
82
+ "weeklyResetAt",
83
+ ];
84
+ const requiredNullableStringFields = [
85
+ "unifiedStatus",
86
+ "overageStatus",
87
+ "sessionStatus",
88
+ "weeklyStatus",
89
+ ];
90
+ if (!stringValue(candidate.account) ||
91
+ typeof candidate.accountType !== "string" ||
92
+ !ROUTING_ACCOUNT_TYPES.has(candidate.accountType) ||
93
+ !Number.isInteger(candidate.sourceIndex) ||
94
+ candidate.sourceIndex < 0 ||
95
+ !Number.isInteger(candidate.rank) ||
96
+ candidate.rank < 0 ||
97
+ requiredBooleanFields.some((field) => typeof candidate[field] !== "boolean") ||
98
+ requiredNullableNumberFields.some((field) => !isNullableFiniteNumber(candidate[field])) ||
99
+ requiredNullableStringFields.some((field) => !isNullableString(candidate[field])) ||
100
+ !(candidate.coolingReason === null ||
101
+ (typeof candidate.coolingReason === "string" &&
102
+ COOLING_REASONS.has(candidate.coolingReason)))) {
103
+ return null;
104
+ }
105
+ return {
106
+ account: candidate.account,
107
+ accountType: candidate.accountType,
108
+ sourceIndex: candidate.sourceIndex,
109
+ rank: candidate.rank,
110
+ configuredPrimary: candidate.configuredPrimary,
111
+ usable: candidate.usable,
112
+ saturated: candidate.saturated,
113
+ quotaObserved: candidate.quotaObserved,
114
+ quotaLastUpdated: candidate.quotaLastUpdated,
115
+ quotaAgeMs: candidate.quotaAgeMs,
116
+ coolingActive: candidate.coolingActive,
117
+ coolingReason: candidate.coolingReason,
118
+ coolingUntil: candidate.coolingUntil,
119
+ unifiedStatus: candidate.unifiedStatus,
120
+ overageStatus: candidate.overageStatus,
121
+ sessionStatus: candidate.sessionStatus,
122
+ sessionUsed: candidate.sessionUsed,
123
+ sessionResetAt: candidate.sessionResetAt,
124
+ sessionResetBucket: candidate.sessionResetBucket,
125
+ weeklyStatus: candidate.weeklyStatus,
126
+ weeklyUsed: candidate.weeklyUsed,
127
+ weeklyResetAt: candidate.weeklyResetAt,
128
+ };
129
+ }
130
+ function routingDecisionValue(value) {
131
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
132
+ return null;
133
+ }
134
+ const decision = value;
135
+ const candidates = Array.isArray(decision.candidates)
136
+ ? decision.candidates.map(routingCandidateValue)
137
+ : [];
138
+ if (decision.schemaVersion !== 1 ||
139
+ !stringValue(decision.evaluatedAt) ||
140
+ !Number.isFinite(Date.parse(String(decision.evaluatedAt))) ||
141
+ typeof decision.strategy !== "string" ||
142
+ !ROUTING_STRATEGIES.has(decision.strategy) ||
143
+ typeof decision.mode !== "string" ||
144
+ !ROUTING_MODES.has(decision.mode) ||
145
+ typeof decision.selectionReason !== "string" ||
146
+ !ROUTING_REASONS.has(decision.selectionReason) ||
147
+ typeof decision.quotaRoutingEnabled !== "boolean" ||
148
+ typeof decision.quotaInputsUsed !== "boolean" ||
149
+ finiteNumber(decision.sessionSoftLimit) === null ||
150
+ decision.sessionSoftLimit <= 0 ||
151
+ decision.sessionSoftLimit > 1 ||
152
+ !Number.isInteger(decision.sessionResetToleranceMs) ||
153
+ decision.sessionResetToleranceMs <= 0 ||
154
+ !isNullableString(decision.configuredPrimaryAccount) ||
155
+ typeof decision.configuredPrimaryMatched !== "boolean" ||
156
+ !Number.isInteger(decision.rotationOffset) ||
157
+ decision.rotationOffset < 0 ||
158
+ !stringValue(decision.initialAccount) ||
159
+ candidates.length === 0 ||
160
+ candidates.some((candidate) => candidate === null)) {
161
+ return null;
162
+ }
163
+ return {
164
+ schemaVersion: 1,
165
+ evaluatedAt: decision.evaluatedAt,
166
+ strategy: decision.strategy,
167
+ mode: decision.mode,
168
+ selectionReason: decision.selectionReason,
169
+ quotaRoutingEnabled: decision.quotaRoutingEnabled,
170
+ quotaInputsUsed: decision.quotaInputsUsed,
171
+ sessionSoftLimit: decision.sessionSoftLimit,
172
+ sessionResetToleranceMs: decision.sessionResetToleranceMs,
173
+ configuredPrimaryAccount: decision.configuredPrimaryAccount,
174
+ configuredPrimaryMatched: decision.configuredPrimaryMatched,
175
+ rotationOffset: decision.rotationOffset,
176
+ initialAccount: decision.initialAccount,
177
+ candidates: candidates,
178
+ };
179
+ }
48
180
  function percentile(sorted, fraction) {
49
181
  if (sorted.length === 0) {
50
182
  return null;
@@ -204,6 +336,63 @@ function summarizeFinalRequests(finalRequests, terminalStreamErrors, attemptsByR
204
336
  singleAttemptDelta,
205
337
  };
206
338
  }
339
+ function summarizeRouting(finalRequests) {
340
+ const modes = {};
341
+ const selectionReasons = {};
342
+ const initialAccounts = {};
343
+ const retainedRecords = [];
344
+ let totalRecords = 0;
345
+ let finalAccountChanges = 0;
346
+ let finalOutsideCandidateSet = 0;
347
+ for (const [requestId, request] of finalRequests) {
348
+ const decision = request.routingDecision;
349
+ if (!decision) {
350
+ continue;
351
+ }
352
+ increment(modes, decision.mode);
353
+ increment(selectionReasons, decision.selectionReason);
354
+ increment(initialAccounts, decision.initialAccount);
355
+ const finalCandidate = decision.candidates.some((candidate) => candidate.account === request.account &&
356
+ candidate.accountType === request.accountType);
357
+ if (!finalCandidate) {
358
+ finalOutsideCandidateSet += 1;
359
+ }
360
+ else if (decision.initialAccount !== request.account) {
361
+ finalAccountChanges += 1;
362
+ }
363
+ totalRecords += 1;
364
+ retainedRecords.push({
365
+ record: {
366
+ requestId,
367
+ timestamp: request.timestamp,
368
+ responseStatus: request.status,
369
+ finalAccount: request.account,
370
+ finalAccountType: request.accountType,
371
+ decision,
372
+ },
373
+ timestampMs: Date.parse(request.timestamp),
374
+ sequence: totalRecords,
375
+ });
376
+ if (retainedRecords.length > MAX_ROUTING_RECORDS_BEFORE_COMPACTION) {
377
+ retainedRecords.sort((left, right) => left.timestampMs - right.timestampMs ||
378
+ left.sequence - right.sequence);
379
+ retainedRecords.splice(0, retainedRecords.length - MAX_RETAINED_ROUTING_RECORDS);
380
+ }
381
+ }
382
+ retainedRecords.sort((left, right) => left.timestampMs - right.timestampMs || left.sequence - right.sequence);
383
+ const records = retainedRecords
384
+ .slice(-MAX_RETAINED_ROUTING_RECORDS)
385
+ .map(({ record }) => record);
386
+ return {
387
+ modes,
388
+ selectionReasons,
389
+ initialAccounts,
390
+ finalAccountChanges,
391
+ finalOutsideCandidateSet,
392
+ totalRecords,
393
+ records,
394
+ };
395
+ }
207
396
  async function discoverLogFiles(logsDir) {
208
397
  const entries = await readdir(logsDir, { withFileTypes: true }).catch((error) => {
209
398
  throw new Error(`Unable to read proxy logs at ${logsDir}: ${error.message}`);
@@ -400,6 +589,9 @@ export async function analyzeProxyLogs(options) {
400
589
  }
401
590
  const finalRequests = new Map();
402
591
  const terminalStreamErrors = new Set();
592
+ let validRoutingDecisions = 0;
593
+ let invalidRoutingDecisions = 0;
594
+ let absentRoutingDecisions = 0;
403
595
  for (const filePath of requestFiles) {
404
596
  linesRead += await readJsonLines(filePath, (record) => {
405
597
  const timestamp = observeTimestamp("requests", record);
@@ -418,7 +610,21 @@ export async function analyzeProxyLogs(options) {
418
610
  if (status === null || !stringValue(record.method)) {
419
611
  return;
420
612
  }
613
+ const hasRoutingDecision = Object.prototype.hasOwnProperty.call(record, "routingDecision");
614
+ const routingDecision = hasRoutingDecision
615
+ ? routingDecisionValue(record.routingDecision)
616
+ : null;
617
+ if (routingDecision) {
618
+ validRoutingDecisions += 1;
619
+ }
620
+ else if (hasRoutingDecision) {
621
+ invalidRoutingDecisions += 1;
622
+ }
623
+ else {
624
+ absentRoutingDecisions += 1;
625
+ }
421
626
  finalRequests.set(requestId, {
627
+ timestamp: new Date(timestamp).toISOString(),
422
628
  status,
423
629
  durationMs: finiteNumber(record.responseTimeMs),
424
630
  account: stringValue(record.account) ?? "unknown",
@@ -428,6 +634,7 @@ export async function analyzeProxyLogs(options) {
428
634
  cacheCreationTokens: finiteNumber(record.cacheCreationTokens),
429
635
  errorType: stringValue(record.errorType),
430
636
  errorCode: stringValue(record.errorCode),
637
+ routingDecision,
431
638
  });
432
639
  }, () => {
433
640
  malformedLines += 1;
@@ -498,6 +705,7 @@ export async function analyzeProxyLogs(options) {
498
705
  }
499
706
  const artifactsReferenced = artifactsPresent + artifactsMissing;
500
707
  const finalSummary = summarizeFinalRequests(finalRequests, terminalStreamErrors, attemptsByRequest, accounts);
708
+ const routingSummary = summarizeRouting(finalRequests);
501
709
  return {
502
710
  generatedAt: new Date(nowMs).toISOString(),
503
711
  since: new Date(sinceMs).toISOString(),
@@ -514,6 +722,7 @@ export async function analyzeProxyLogs(options) {
514
722
  attempts: totalAttempts > 0,
515
723
  attemptLatency: attemptLatency.length > 0,
516
724
  cacheUsage: finalSummary.cache.requestsWithUsage > 0,
725
+ routingDecisions: routingSummary.totalRecords > 0,
517
726
  },
518
727
  dataQuality: {
519
728
  linesRead,
@@ -538,6 +747,11 @@ export async function analyzeProxyLogs(options) {
538
747
  writeFailures,
539
748
  truncatedCaptures,
540
749
  },
750
+ routingDecisions: {
751
+ valid: validRoutingDecisions,
752
+ invalid: invalidRoutingDecisions,
753
+ absent: absentRoutingDecisions,
754
+ },
541
755
  },
542
756
  lifecycle: {
543
757
  accepted: accepted.size,
@@ -572,6 +786,7 @@ export async function analyzeProxyLogs(options) {
572
786
  singleAttemptDelta: summarizeLatency(finalSummary.singleAttemptDelta),
573
787
  },
574
788
  cache: finalSummary.cache,
789
+ routing: routingSummary,
575
790
  accounts: [...accounts.values()].sort((left, right) => right.attempts - left.attempts),
576
791
  };
577
792
  }
@@ -236,6 +236,17 @@ function emitOtlpLogRecord(entry) {
236
236
  // Account info
237
237
  "account.name": entry.account,
238
238
  "account.type": entry.accountType,
239
+ // Compact routing summary. Full candidate evidence stays in JSONL.
240
+ ...(entry.routingDecision && {
241
+ "routing.mode": entry.routingDecision.mode,
242
+ "routing.strategy": entry.routingDecision.strategy,
243
+ "routing.selection_reason": entry.routingDecision.selectionReason,
244
+ "routing.initial_account": entry.routingDecision.initialAccount,
245
+ "routing.candidate_count": entry.routingDecision.candidates.length,
246
+ "routing.final_account_changed": entry.routingDecision.initialAccount !== entry.account &&
247
+ entry.routingDecision.candidates.some((candidate) => candidate.account === entry.account &&
248
+ candidate.accountType === entry.accountType),
249
+ }),
239
250
  // Token usage (when available)
240
251
  ...(entry.inputTokens !== undefined && {
241
252
  "ai.input_tokens": entry.inputTokens,
@@ -0,0 +1,6 @@
1
+ /** Schema-v1 routing evidence values shared by emitters and offline readers. */
2
+ export declare const PROXY_ACCOUNT_ROUTING_STRATEGIES: readonly ["round-robin", "fill-first"];
3
+ export declare const PROXY_ACCOUNT_ROUTING_MODES: readonly ["quota", "primary", "round_robin", "single_account"];
4
+ export declare const PROXY_ACCOUNT_ROUTING_REASONS: readonly ["single_account", "round_robin", "configured_primary", "insertion_order", "availability", "cooldown_recovery", "quota_probe", "session_headroom", "session_reset", "weekly_reset", "weekly_utilization"];
5
+ export declare const PROXY_ACCOUNT_TYPES: readonly ["oauth", "api_key"];
6
+ export declare const ACCOUNT_COOLING_REASONS: readonly ["weekly", "session", "unified", "transient", "auth"];
@@ -0,0 +1,33 @@
1
+ /** Schema-v1 routing evidence values shared by emitters and offline readers. */
2
+ export const PROXY_ACCOUNT_ROUTING_STRATEGIES = [
3
+ "round-robin",
4
+ "fill-first",
5
+ ];
6
+ export const PROXY_ACCOUNT_ROUTING_MODES = [
7
+ "quota",
8
+ "primary",
9
+ "round_robin",
10
+ "single_account",
11
+ ];
12
+ export const PROXY_ACCOUNT_ROUTING_REASONS = [
13
+ "single_account",
14
+ "round_robin",
15
+ "configured_primary",
16
+ "insertion_order",
17
+ "availability",
18
+ "cooldown_recovery",
19
+ "quota_probe",
20
+ "session_headroom",
21
+ "session_reset",
22
+ "weekly_reset",
23
+ "weekly_utilization",
24
+ ];
25
+ export const PROXY_ACCOUNT_TYPES = ["oauth", "api_key"];
26
+ export const ACCOUNT_COOLING_REASONS = [
27
+ "weekly",
28
+ "session",
29
+ "unified",
30
+ "transient",
31
+ "auth",
32
+ ];
33
+ //# sourceMappingURL=routingEvidence.js.map
@@ -12,7 +12,7 @@
12
12
  import { buildTranslationOptions } from "../../proxy/proxyTranslationEngine.js";
13
13
  import { ProxyTracer } from "../../proxy/proxyTracer.js";
14
14
  import { isPermanentRefreshFailure } from "../../proxy/tokenRefresh.js";
15
- import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
15
+ import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ClaudeProxyRouteRuntimeOptions, ModelRouterInterface, ParsedClaudeError, ProxyAccountRoutingDecision, ProxyAccountSortMetrics, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
16
16
  /** Resolve the configured primary's stable key to its current index in the
17
17
  * request's enabledAccounts list. Returns 0 (insertion-order fallback) when
18
18
  * no key is configured or the key cannot be matched (account disabled/
@@ -85,6 +85,19 @@ declare function seedRuntimeQuotasFromDisk(accounts: ProxyPassthroughAccount[]):
85
85
  * last resort.
86
86
  */
87
87
  declare function orderAccountsByQuota(accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number): ProxyPassthroughAccount[];
88
+ declare function buildRoutingDecision(args: {
89
+ accounts: ProxyPassthroughAccount[];
90
+ orderedAccounts: ProxyPassthroughAccount[];
91
+ metricsByKey: ReadonlyMap<string, ProxyAccountSortMetrics>;
92
+ evaluatedAt: number;
93
+ strategy: "round-robin" | "fill-first";
94
+ primaryKey: string | undefined;
95
+ quotaRoutingEnabled: boolean;
96
+ quotaOrdered: boolean;
97
+ sessionSoftLimit: number;
98
+ sessionResetToleranceMs: number;
99
+ rotationOffset: number;
100
+ }): ProxyAccountRoutingDecision | undefined;
88
101
  declare function trackUpstreamReadableStream(source: ReadableStream<Uint8Array>): {
89
102
  stream: ReadableStream<Uint8Array>;
90
103
  outcome: Promise<StreamTerminalOutcome>;
@@ -279,6 +292,8 @@ export declare const __testHooks: {
279
292
  getStreamFailureDetails: typeof getStreamFailureDetails;
280
293
  trackUpstreamReadableStream: typeof trackUpstreamReadableStream;
281
294
  orderAccountsByQuota: typeof orderAccountsByQuota;
295
+ buildQuotaRoutingDecision: (accounts: ProxyPassthroughAccount[], now: number, primaryKey: string | undefined, sessionSoftLimit?: number, sessionResetToleranceMs?: number) => ProxyAccountRoutingDecision | undefined;
296
+ buildRoutingDecision: typeof buildRoutingDecision;
282
297
  resetEpochToMs: typeof resetEpochToMs;
283
298
  seedRuntimeQuotasFromDisk: typeof seedRuntimeQuotasFromDisk;
284
299
  reconcileEligibleAccountRuntimeState: typeof reconcileEligibleAccountRuntimeState;