@juspay/neurolink 9.87.2 → 9.87.4

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.
@@ -11,8 +11,9 @@
11
11
  */
12
12
  import { buildTranslationOptions } from "../../proxy/proxyTranslationEngine.js";
13
13
  import type { ModelRouter } from "../../proxy/modelRouter.js";
14
+ import { ProxyTracer } from "../../proxy/proxyTracer.js";
14
15
  import { isPermanentRefreshFailure } from "../../proxy/tokenRefresh.js";
15
- import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, ParsedClaudeError, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, StreamTerminalOutcome } from "../../types/index.js";
16
+ import type { AccountAllowlist, AccountCooldownPlan, AccountQuota, AnthropicAttemptLogger, AnthropicAuthRetryResult, AnthropicLoopState, AnthropicSuccessResult, AnthropicUpstreamFetchResult, ClaudeFinalRequestLogger, ClaudeLoggedErrorBuilder, ClaudeRequest, ParsedClaudeError, ProxyBodyCaptureLogger, ProxyPassthroughAccount, RouteGroup, RuntimeAccountState, ServerContext, StreamTerminalOutcome } from "../../types/index.js";
16
17
  /** Resolve the configured primary's stable key to its current index in the
17
18
  * request's enabledAccounts list. Returns 0 (insertion-order fallback) when
18
19
  * no key is configured or the key cannot be matched (account disabled/
@@ -24,6 +25,9 @@ declare function resolveHomeIndex(enabledAccounts: ProxyPassthroughAccount[]): n
24
25
  * account once its rate limit window expires. Called at the start of each
25
26
  * request. Home is resolved fresh per call via resolveHomeIndex. */
26
27
  declare function maybeResetPrimaryToHome(enabledAccounts: ProxyPassthroughAccount[]): void;
28
+ declare function claimTransientRateLimitRetry(accountKey: string, coolingUntil: number, now?: number): number | undefined;
29
+ declare function claimTransientCooldownAdmission(accountKey: string, coolingUntil: number, now?: number): number | undefined;
30
+ declare function waitForTransientAccountAvailability(orderedAccounts: ProxyPassthroughAccount[]): Promise<ProxyPassthroughAccount[]>;
27
31
  /** Convert an Anthropic unified-window reset (Unix epoch SECONDS, per the
28
32
  * `anthropic-ratelimit-unified-*-reset` headers) into epoch-ms. Tolerates a
29
33
  * value already expressed in ms (some intermediaries normalise it). Returns
@@ -58,17 +62,24 @@ declare function planCooldownFor429(quota: AccountQuota | null, retryAfterMs: nu
58
62
  declare function seedRuntimeQuotasFromDisk(accounts: ProxyPassthroughAccount[]): Promise<void>;
59
63
  /**
60
64
  * Order accounts to MAXIMIZE quota utilization (fill-first, smart order):
61
- * spend the account whose window refreshes SOONEST first, so its about-to-reset
65
+ * spend the window that expires SOONEST first, so its about-to-reset
62
66
  * allowance isn't wasted, then move to accounts with longer-dated resets.
63
67
  *
64
68
  * Priority among usable accounts:
65
69
  * 1. no quota data yet — probe first: one request reveals its windows and
66
70
  * self-corrects the ordering. (Ranking unknowns last would starve them
67
71
  * forever: never picked → never observed → never comparable.)
68
- * 2. soonest WEEKLY (7d) reset — the scarce, use-it-or-lose-it ceiling
69
- * 3. soonest SESSION (5h) reset
70
- * 4. highest weekly utilization finish off the one closest to done
71
- * 5. configured primary account, then insertion order
72
+ * 2. session headroom before session-saturated (>= soft limit or
73
+ * "throttled") saturated accounts then follow the same bucketed
74
+ * session ordering below: soonest back in service first, weekly
75
+ * deciding same-bucket ties.
76
+ * 3. soonest SESSION (5h) reset — the capacity expiring soonest; compared
77
+ * in tolerance buckets so near-simultaneous resets count as equal.
78
+ * 4. soonest WEEKLY (7d) reset — decides between same-bucket sessions.
79
+ * 5. highest weekly utilization — finish off the one closest to done
80
+ * 6. configured primary account, then insertion order
81
+ * An account with NO ticking session window (fresh, not yet started) has
82
+ * nothing expiring and sorts after ticking windows in step 3.
72
83
  * Cooling/rejected accounts sort last, soonest-back-to-service first, as
73
84
  * last resort.
74
85
  */
@@ -77,11 +88,150 @@ declare function trackUpstreamReadableStream(source: ReadableStream<Uint8Array>)
77
88
  stream: ReadableStream<Uint8Array>;
78
89
  outcome: Promise<StreamTerminalOutcome>;
79
90
  };
91
+ declare function executeClaudeFallbackTranslation(args: {
92
+ ctx: ServerContext;
93
+ body: ClaudeRequest;
94
+ tracer?: ProxyTracer;
95
+ requestStartTime: number;
96
+ logProxyBody: ProxyBodyCaptureLogger;
97
+ logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
98
+ inputTokens?: number;
99
+ outputTokens?: number;
100
+ cacheCreationTokens?: number;
101
+ cacheReadTokens?: number;
102
+ }) => void;
103
+ options: Parameters<ServerContext["neurolink"]["stream"]>[0];
104
+ providerLabel: string;
105
+ }): Promise<unknown>;
106
+ declare function executeClaudeFallbackWithRetry(args: Parameters<typeof executeClaudeFallbackTranslation>[0]): Promise<unknown>;
107
+ declare function buildClaudeAnthropicFailureResponse(args: {
108
+ tracer?: ProxyTracer;
109
+ requestStartTime: number;
110
+ authFailureMessage: string | null;
111
+ authCooldownMessage: string | null;
112
+ invalidRequestFailure: {
113
+ status: number;
114
+ body: string;
115
+ contentType?: string;
116
+ } | null;
117
+ sawNetworkError: boolean;
118
+ sawTransientFailure: boolean;
119
+ sawRateLimit: boolean;
120
+ lastError: unknown;
121
+ fallbackFailureMessage?: string;
122
+ orderedAccounts: ProxyPassthroughAccount[];
123
+ buildLoggedClaudeError: ClaudeLoggedErrorBuilder;
124
+ logProxyBody: ProxyBodyCaptureLogger;
125
+ logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
126
+ inputTokens?: number;
127
+ outputTokens?: number;
128
+ cacheCreationTokens?: number;
129
+ cacheReadTokens?: number;
130
+ }) => void;
131
+ }): unknown;
132
+ declare function handleAnthropicStreamingSuccessResponse(args: {
133
+ ctx: ServerContext;
134
+ body: ClaudeRequest;
135
+ account: ProxyPassthroughAccount;
136
+ accountState: RuntimeAccountState;
137
+ response: Response;
138
+ responseHeaders: Record<string, string>;
139
+ tracer?: ProxyTracer;
140
+ requestStartTime: number;
141
+ fetchStartMs: number;
142
+ attemptNumber: number;
143
+ finalBodyStr: string;
144
+ upstreamSpan?: import("@opentelemetry/api").Span;
145
+ logProxyBody: ProxyBodyCaptureLogger;
146
+ logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
147
+ inputTokens?: number;
148
+ outputTokens?: number;
149
+ cacheCreationTokens?: number;
150
+ cacheReadTokens?: number;
151
+ }) => void;
152
+ }): Promise<AnthropicSuccessResult>;
80
153
  declare function getStreamFailureDetails(outcome: StreamTerminalOutcome): {
81
154
  status: number;
82
155
  errorType: string;
83
156
  message: string;
84
157
  } | undefined;
158
+ declare function handleAnthropicAuthRetry(args: {
159
+ ctx: ServerContext;
160
+ body: ClaudeRequest;
161
+ account: ProxyPassthroughAccount;
162
+ accountState: RuntimeAccountState;
163
+ headers: Record<string, string>;
164
+ buildUpstreamBody: (token: string) => {
165
+ bodyStr: string;
166
+ sessionId?: string;
167
+ };
168
+ enabledAccounts: ProxyPassthroughAccount[];
169
+ orderedAccounts: ProxyPassthroughAccount[];
170
+ response: Response;
171
+ tracer?: ProxyTracer;
172
+ requestStartTime: number;
173
+ fetchStartMs: number;
174
+ attemptNumber: number;
175
+ finalBodyStr: string;
176
+ upstreamSpan?: import("@opentelemetry/api").Span;
177
+ logAttempt: (status: number, errorType?: string, errorMessage?: string, extra?: {
178
+ inputTokens?: number;
179
+ outputTokens?: number;
180
+ cacheCreationTokens?: number;
181
+ cacheReadTokens?: number;
182
+ }) => void;
183
+ logProxyBody: ProxyBodyCaptureLogger;
184
+ logFinalRequest: (status: number, accountLabel: string, accountType: string, errorType?: string, errorMessage?: string, extra?: {
185
+ inputTokens?: number;
186
+ outputTokens?: number;
187
+ cacheCreationTokens?: number;
188
+ cacheReadTokens?: number;
189
+ }) => void;
190
+ lastError: unknown;
191
+ authFailureMessage: string | null;
192
+ sawRateLimit: boolean;
193
+ sawTransientFailure: boolean;
194
+ sawNetworkError: boolean;
195
+ }): Promise<AnthropicAuthRetryResult>;
196
+ declare function finalizeAnthropicTerminalFetchError(args: {
197
+ terminalError: NonNullable<AnthropicUpstreamFetchResult["terminalError"]>;
198
+ account: ProxyPassthroughAccount;
199
+ tracer?: ProxyTracer;
200
+ requestStartTime: number;
201
+ attemptNumber: number;
202
+ logProxyBody: ProxyBodyCaptureLogger;
203
+ logFinalRequest: ClaudeFinalRequestLogger;
204
+ }): Response | unknown;
205
+ /**
206
+ * Detect Anthropic's anti-abuse / request-construction 429.
207
+ *
208
+ * The subscription/OAuth path rejects requests it does not recognise as genuine
209
+ * Claude Code traffic with a 429 `rate_limit_error` whose message is literally
210
+ * "Error" and which carries NONE of the real rate-limit headers (no retry-after,
211
+ * no anthropic-ratelimit-*). This is NOT a capacity limit — retrying or rotating
212
+ * accounts cannot fix it and only burns quota, so the caller must fail fast and
213
+ * return a non-retryable request error instead of "all accounts rate-limited".
214
+ */
215
+ declare function isAntiAbuseConstruction429(headers: Record<string, string>, body: string): boolean;
216
+ declare function fetchAnthropicAccountResponse(args: {
217
+ url: string;
218
+ headers: Record<string, string>;
219
+ finalBodyStr: string;
220
+ account: ProxyPassthroughAccount;
221
+ accountState: RuntimeAccountState;
222
+ enabledAccounts: ProxyPassthroughAccount[];
223
+ orderedAccounts: ProxyPassthroughAccount[];
224
+ tracer?: ProxyTracer;
225
+ logAttempt: AnthropicAttemptLogger;
226
+ logProxyBody: ProxyBodyCaptureLogger;
227
+ fetchStartMs: number;
228
+ attemptNumber: number;
229
+ currentLastError: unknown;
230
+ currentSawRateLimit: boolean;
231
+ currentSawNetworkError: boolean;
232
+ upstreamSpan?: import("@opentelemetry/api").Span;
233
+ }): Promise<AnthropicUpstreamFetchResult>;
234
+ declare function shouldAttemptClaudeFallback(loopState: AnthropicLoopState): boolean;
85
235
  /**
86
236
  * Create Claude-compatible proxy routes.
87
237
  *
@@ -94,6 +244,7 @@ declare function getStreamFailureDetails(outcome: StreamTerminalOutcome): {
94
244
  */
95
245
  export declare function createClaudeProxyRoutes(modelRouter?: ModelRouter, basePath?: string, accountStrategy?: "round-robin" | "fill-first", passthroughMode?: boolean, primaryAccountKey?: string, accountAllowlist?: AccountAllowlist): RouteGroup;
96
246
  export declare function getTransientSameAccountRetryDelayMs(retryNumber: number): number;
247
+ declare function describeTransportError(error: unknown): string;
97
248
  /**
98
249
  * Parse a Claude error payload when available.
99
250
  */
@@ -132,5 +283,21 @@ export declare const __testHooks: {
132
283
  getPrimaryAccountIndex: () => number;
133
284
  setAccountRuntimeState: (key: string, state: Partial<RuntimeAccountState>) => void;
134
285
  resetAllRuntimeState: () => void;
286
+ polyfillOAuthBody: (bodyStr: string, isClaudeClientRequest: boolean) => {
287
+ bodyStr: string;
288
+ sessionId?: string;
289
+ };
290
+ isAntiAbuseConstruction429: typeof isAntiAbuseConstruction429;
291
+ fetchAnthropicAccountResponse: typeof fetchAnthropicAccountResponse;
292
+ finalizeAnthropicTerminalFetchError: typeof finalizeAnthropicTerminalFetchError;
293
+ handleAnthropicAuthRetry: typeof handleAnthropicAuthRetry;
294
+ handleAnthropicStreamingSuccessResponse: typeof handleAnthropicStreamingSuccessResponse;
295
+ claimTransientRateLimitRetry: typeof claimTransientRateLimitRetry;
296
+ claimTransientCooldownAdmission: typeof claimTransientCooldownAdmission;
297
+ waitForTransientAccountAvailability: typeof waitForTransientAccountAvailability;
298
+ describeTransportError: typeof describeTransportError;
299
+ shouldAttemptClaudeFallback: typeof shouldAttemptClaudeFallback;
300
+ executeClaudeFallbackWithRetry: typeof executeClaudeFallbackWithRetry;
301
+ buildClaudeAnthropicFailureResponse: typeof buildClaudeAnthropicFailureResponse;
135
302
  };
136
303
  export {};