@juspay/neurolink 13.8.18 → 13.8.20

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.
@@ -67,7 +67,7 @@ const ConfigSchema = z.object({
67
67
  anthropic: z
68
68
  .object({
69
69
  apiKey: z.string().optional(),
70
- model: z.string().default("claude-3-5-sonnet-20241022"),
70
+ model: z.string().default("claude-sonnet-4-6"),
71
71
  })
72
72
  .optional(),
73
73
  azure: z
@@ -41,7 +41,7 @@ export async function handleAnthropicSetup(argv) {
41
41
  logger.always(` Model: ${process.env.ANTHROPIC_MODEL}`);
42
42
  }
43
43
  else {
44
- logger.always(" Model: claude-3-5-sonnet-20241022 (default)");
44
+ logger.always(" Model: claude-sonnet-4-6 (default)");
45
45
  }
46
46
  }
47
47
  else {
@@ -61,7 +61,7 @@ export async function handleAnthropicSetup(argv) {
61
61
  logger.always(` Model: ${process.env.ANTHROPIC_MODEL}`);
62
62
  }
63
63
  else {
64
- logger.always(" Model: claude-3-5-sonnet-20241022 (default)");
64
+ logger.always(" Model: claude-sonnet-4-6 (default)");
65
65
  }
66
66
  if (options.interactive) {
67
67
  const { reconfigure } = await inquirer.prompt([
@@ -237,7 +237,7 @@ function displayCurrentStatus(hasApiKey, hasModel) {
237
237
  logger.always(chalk.green(`✔ ANTHROPIC_MODEL found: ${process.env.ANTHROPIC_MODEL}`));
238
238
  }
239
239
  else {
240
- logger.always(chalk.yellow("⚠ ANTHROPIC_MODEL not set (will use claude-3-5-sonnet-20241022 default)"));
240
+ logger.always(chalk.yellow("⚠ ANTHROPIC_MODEL not set (will use claude-sonnet-4-6 default)"));
241
241
  }
242
242
  }
243
243
  /**
@@ -725,6 +725,8 @@ export const parseSSEStream = async (body, onTextDelta, onReasoningDelta) => {
725
725
  };
726
726
  const decoder = new TextDecoder();
727
727
  let parseErr;
728
+ // Key of the tool call the previous delta wrote to (for unindexed deltas).
729
+ let lastToolCallKey;
728
730
  const handleEvent = (msg) => {
729
731
  const data = msg.data;
730
732
  if (!data || data === "[DONE]") {
@@ -768,14 +770,21 @@ export const parseSSEStream = async (body, onTextDelta, onReasoningDelta) => {
768
770
  }
769
771
  if (delta?.tool_calls) {
770
772
  for (const tc of delta.tool_calls) {
771
- let state = result.toolCalls.get(tc.index);
773
+ // Gemini's OpenAI-compatible endpoint omits `index`: an unindexed
774
+ // delta with an id or name starts a call, otherwise it continues one.
775
+ const index = tc.index ??
776
+ (tc.id || tc.function?.name || lastToolCallKey === undefined
777
+ ? Math.max(-1, ...result.toolCalls.keys()) + 1
778
+ : lastToolCallKey);
779
+ lastToolCallKey = index;
780
+ let state = result.toolCalls.get(index);
772
781
  if (!state) {
773
782
  state = {
774
- id: tc.id ?? `call_${tc.index}_${Date.now()}`,
783
+ id: tc.id ?? `call_${index}_${Date.now()}`,
775
784
  name: tc.function?.name ?? "",
776
785
  argsBuffered: "",
777
786
  };
778
- result.toolCalls.set(tc.index, state);
787
+ result.toolCalls.set(index, state);
779
788
  }
780
789
  else if (tc.id) {
781
790
  state.id = tc.id;
@@ -28,6 +28,7 @@
28
28
  import { homedir } from "node:os";
29
29
  import { join } from "node:path";
30
30
  import { calculateCost, hasPricing } from "../utils/pricing.js";
31
+ import { proxyTokenUsage } from "./proxyTokenUsage.js";
31
32
  /** Same pattern proxyAnalysis.ts uses, deliberately duplicated as a constant. */
32
33
  const REQUEST_FILE_PATTERN = /^proxy-\d{4}-\d{2}-\d{2}\.jsonl$/;
33
34
  /**
@@ -163,6 +164,7 @@ async function advanceCursor(fileName, cursor) {
163
164
  model: typeof record.model === "string" ? record.model : "",
164
165
  provider: typeof record.provider === "string" ? record.provider : undefined,
165
166
  inputTokens: finiteNumber(record.inputTokens),
167
+ inputIncludesCachedTokens: record.inputIncludesCachedTokens === true,
166
168
  outputTokens: finiteNumber(record.outputTokens),
167
169
  cacheReadTokens: finiteNumber(record.cacheReadTokens),
168
170
  cacheCreationTokens: finiteNumber(record.cacheCreationTokens),
@@ -196,6 +198,9 @@ async function advanceCursor(fileName, cursor) {
196
198
  ...previous,
197
199
  ...next,
198
200
  inputTokens: Math.max(previous.inputTokens, next.inputTokens),
201
+ inputIncludesCachedTokens: next.inputTokens > previous.inputTokens
202
+ ? next.inputIncludesCachedTokens
203
+ : previous.inputIncludesCachedTokens,
199
204
  outputTokens: Math.max(previous.outputTokens, next.outputTokens),
200
205
  cacheReadTokens: Math.max(previous.cacheReadTokens, next.cacheReadTokens),
201
206
  cacheCreationTokens: Math.max(previous.cacheCreationTokens, next.cacheCreationTokens),
@@ -335,14 +340,7 @@ export async function readAccountUsage(date = currentUsageDate()) {
335
340
  const provider = resolveProvider(entry);
336
341
  if (entry.model && entry.model !== "-") {
337
342
  if (hasPricing(provider, entry.model)) {
338
- const cost = calculateCost(provider, entry.model, {
339
- input: entry.inputTokens,
340
- output: entry.outputTokens,
341
- total: entry.inputTokens + entry.outputTokens,
342
- cacheReadTokens: entry.cacheReadTokens,
343
- cacheCreationTokens: entry.cacheCreationTokens,
344
- cacheCreation1hTokens: entry.cacheCreation1hTokens,
345
- });
343
+ const cost = calculateCost(provider, entry.model, proxyTokenUsage(entry));
346
344
  row.costUsd += cost;
347
345
  client.costUsd += cost;
348
346
  }
@@ -18,7 +18,7 @@
18
18
  * its own usage line, so getting them wrong is visible to the user rather than
19
19
  * merely wrong in a log.
20
20
  */
21
- import type { ParsedGeminiRequest, StreamSerializerAdapter } from "../types/index.js";
21
+ import type { ParsedGeminiRequest, StreamSerializerAdapter, TokenUsage } from "../types/index.js";
22
22
  /**
23
23
  * Parse a `generateContent` body into the shape the translation engine takes.
24
24
  *
@@ -46,11 +46,7 @@ export declare function parseGeminiRequest(model: string, body: Record<string, u
46
46
  * cannot drift.
47
47
  */
48
48
  export declare function renderGeminiToolUse(name: string, input: unknown): string;
49
- export declare function buildGeminiResponse(text: string, finishReason: string, usage: {
50
- input: number;
51
- output: number;
52
- total: number;
53
- }, modelVersion: string, toolCalls?: ReadonlyArray<{
49
+ export declare function buildGeminiResponse(text: string, finishReason: string, usage: TokenUsage, modelVersion: string, toolCalls?: ReadonlyArray<{
54
50
  toolName: string;
55
51
  args: Record<string, unknown>;
56
52
  }>): Record<string, unknown>;
@@ -81,11 +77,7 @@ export declare class GeminiStreamSerializer {
81
77
  * that is never coming; rendering it as text keeps the turn terminating.
82
78
  */
83
79
  pushToolUse(_id: string, name: string, input: unknown): string[];
84
- finish(finishReason: string, usage: {
85
- input: number;
86
- output: number;
87
- total: number;
88
- }): string[];
80
+ finish(finishReason: string, usage: TokenUsage): string[];
89
81
  /**
90
82
  * Errors ride the stream as a Google error object.
91
83
  *
@@ -206,10 +206,19 @@ function toGeminiFinishReason(reason) {
206
206
  }
207
207
  }
208
208
  function usageMetadata(usage) {
209
+ const promptTokens = usage.input +
210
+ (usage.cacheReadTokens ?? 0) +
211
+ (usage.cacheCreationTokens ?? 0);
209
212
  return {
210
- promptTokenCount: usage.input,
213
+ promptTokenCount: promptTokens,
211
214
  candidatesTokenCount: usage.output,
212
- totalTokenCount: usage.total || usage.input + usage.output,
215
+ totalTokenCount: usage.total || promptTokens + usage.output,
216
+ ...(usage.cacheReadTokens !== undefined && {
217
+ cachedContentTokenCount: usage.cacheReadTokens,
218
+ }),
219
+ ...(usage.reasoning !== undefined && {
220
+ thoughtsTokenCount: usage.reasoning,
221
+ }),
213
222
  };
214
223
  }
215
224
  /** Build a complete `generateContent` response body. */
@@ -8,7 +8,7 @@
8
8
  *
9
9
  * Reference: https://platform.openai.com/docs/api-reference/chat/create
10
10
  */
11
- import type { ClaudeRequest, ClaudeResponse, InternalResult, OpenAICompletionRequest, OpenAICompletionResponse, OpenAIErrorResponse, ParsedOpenAIRequest, StreamLifecycleState } from "../types/index.js";
11
+ import type { ClaudeRequest, ClaudeResponse, InternalResult, OpenAICompletionRequest, OpenAICompletionResponse, OpenAIErrorResponse, ParsedOpenAIRequest, StreamLifecycleState, TokenUsage } from "../types/index.js";
12
12
  /** Generate a unique chat completion ID in the OpenAI format. */
13
13
  export declare function generateChatCompletionId(): string;
14
14
  /** Generate an OpenAI-format tool call ID (`call_` + random chars). */
@@ -25,9 +25,7 @@ export declare function generateOpenAIToolCallId(): string;
25
25
  * - top_p, temperature, max_tokens pass-through
26
26
  */
27
27
  export declare function parseOpenAIRequest(body: OpenAICompletionRequest): ParsedOpenAIRequest;
28
- /**
29
- * Serialize a NeuroLink GenerateResult into an OpenAI Chat Completions response.
30
- */
28
+ /** Serialize a NeuroLink GenerateResult into an OpenAI Chat Completions response. */
31
29
  export declare function serializeOpenAIResponse(result: InternalResult, requestModel: string): OpenAICompletionResponse;
32
30
  /**
33
31
  * Build an OpenAI-compatible error envelope.
@@ -97,11 +95,7 @@ export declare class OpenAIStreamSerializer {
97
95
  /**
98
96
  * Finalize the stream: emit finish_reason chunk, then `data: [DONE]`.
99
97
  */
100
- finish(finishReason?: string, usage?: {
101
- input: number;
102
- output: number;
103
- total: number;
104
- }): Generator<string>;
98
+ finish(finishReason?: string, usage?: TokenUsage): Generator<string>;
105
99
  /**
106
100
  * Emit an error event. Transitions to terminal ERROR state.
107
101
  */
@@ -205,9 +205,25 @@ function mapFinishReason(finishReason) {
205
205
  return finishReason ? "stop" : null;
206
206
  }
207
207
  }
208
- /**
209
- * Serialize a NeuroLink GenerateResult into an OpenAI Chat Completions response.
210
- */
208
+ /** Add cache to the prompt total; reasoning is already part of completion. */
209
+ function toOpenAIUsage(usage) {
210
+ const promptTokens = (usage?.input ?? 0) +
211
+ (usage?.cacheReadTokens ?? 0) +
212
+ (usage?.cacheCreationTokens ?? 0);
213
+ const completionTokens = usage?.output ?? 0;
214
+ return {
215
+ prompt_tokens: promptTokens,
216
+ completion_tokens: completionTokens,
217
+ total_tokens: usage?.total ?? promptTokens + completionTokens,
218
+ ...(usage?.cacheReadTokens !== undefined && {
219
+ prompt_tokens_details: { cached_tokens: usage.cacheReadTokens },
220
+ }),
221
+ ...(usage?.reasoning !== undefined && {
222
+ completion_tokens_details: { reasoning_tokens: usage.reasoning },
223
+ }),
224
+ };
225
+ }
226
+ /** Serialize a NeuroLink GenerateResult into an OpenAI Chat Completions response. */
211
227
  export function serializeOpenAIResponse(result, requestModel) {
212
228
  const inferredFinishReason = result.toolCalls &&
213
229
  result.toolCalls.length > 0 &&
@@ -244,11 +260,7 @@ export function serializeOpenAIResponse(result, requestModel) {
244
260
  finish_reason: mapFinishReason(inferredFinishReason),
245
261
  },
246
262
  ],
247
- usage: {
248
- prompt_tokens: result.usage?.input ?? 0,
249
- completion_tokens: result.usage?.output ?? 0,
250
- total_tokens: result.usage?.total ?? 0,
251
- },
263
+ usage: toOpenAIUsage(result.usage),
252
264
  };
253
265
  }
254
266
  // ---------------------------------------------------------------------------
@@ -450,13 +462,7 @@ export class OpenAIStreamSerializer {
450
462
  return;
451
463
  }
452
464
  const mappedReason = mapFinishReason(finishReason) ?? "stop";
453
- const usagePayload = usage
454
- ? {
455
- prompt_tokens: usage.input,
456
- completion_tokens: usage.output,
457
- total_tokens: usage.total,
458
- }
459
- : undefined;
465
+ const usagePayload = usage ? toOpenAIUsage(usage) : undefined;
460
466
  yield formatOpenAISSE(this.makeChunk({}, mappedReason, usagePayload));
461
467
  yield "data: [DONE]\n\n";
462
468
  this.state = "done";
@@ -12,7 +12,7 @@
12
12
  * JSON handlers that accept a format discriminator.
13
13
  */
14
14
  import type { ProxyTracer } from "./proxyTracer.js";
15
- import type { ParsedClaudeRequest, ParsedGeminiRequest, ParsedOpenAIRequest, ProxyFormat, ProxyTranslationAttempt, ServerContext } from "../types/index.js";
15
+ import type { ParsedClaudeRequest, ParsedGeminiRequest, ParsedOpenAIRequest, ProxyFormat, ProxyTranslationAttempt, ServerContext, TokenUsage } from "../types/index.js";
16
16
  /**
17
17
  * Extract text content from a stream chunk (handles various chunk formats).
18
18
  */
@@ -29,11 +29,7 @@ export declare function hasTranslatedOutput(collectedText: string, toolCalls: un
29
29
  * - AI SDK v4: promptTokens / completionTokens
30
30
  * - NeuroLink internal: input / output
31
31
  */
32
- export declare function extractUsageFromStreamResult(usage: unknown): {
33
- input: number;
34
- output: number;
35
- total: number;
36
- };
32
+ export declare function extractUsageFromStreamResult(usage: unknown): TokenUsage;
37
33
  /**
38
34
  * Detect which proxy format a request is using based on path and headers.
39
35
  */
@@ -77,17 +77,25 @@ export function hasTranslatedOutput(collectedText, toolCalls) {
77
77
  * - NeuroLink internal: input / output
78
78
  */
79
79
  export function extractUsageFromStreamResult(usage) {
80
- if (!usage || typeof usage !== "object") {
81
- return { input: 0, output: 0, total: 0 };
82
- }
83
- const u = usage;
84
- const input = (typeof u.inputTokens === "number" ? u.inputTokens : 0) ||
85
- (typeof u.promptTokens === "number" ? u.promptTokens : 0) ||
86
- (typeof u.input === "number" ? u.input : 0);
87
- const output = (typeof u.outputTokens === "number" ? u.outputTokens : 0) ||
88
- (typeof u.completionTokens === "number" ? u.completionTokens : 0) ||
89
- (typeof u.output === "number" ? u.output : 0);
90
- return { input, output, total: input + output };
80
+ const observed = readTranslationUsage(usage);
81
+ const cacheReadTokens = observed.cacheReadTokens ?? 0;
82
+ const cacheCreationTokens = observed.cacheCreationTokens ?? 0;
83
+ const input = observed.inputIncludesCachedTokens
84
+ ? Math.max(0, (observed.inputTokens ?? 0) - cacheReadTokens - cacheCreationTokens)
85
+ : (observed.inputTokens ?? 0);
86
+ const output = observed.outputTokens ?? 0;
87
+ return {
88
+ input,
89
+ output,
90
+ total: input + cacheReadTokens + cacheCreationTokens + output,
91
+ ...(observed.cacheReadTokens !== undefined ? { cacheReadTokens } : {}),
92
+ ...(observed.cacheCreationTokens !== undefined
93
+ ? { cacheCreationTokens }
94
+ : {}),
95
+ ...(observed.reasoningTokens !== undefined
96
+ ? { reasoning: observed.reasoningTokens }
97
+ : {}),
98
+ };
91
99
  }
92
100
  // ---------------------------------------------------------------------------
93
101
  // Format detection
@@ -250,11 +258,11 @@ function defaultFinishReason(format) {
250
258
  return format === "claude" ? "end_turn" : "stop";
251
259
  }
252
260
  /** Preserve unknown usage as absent; zero is only reported when observed. */
253
- function translationUsage(result) {
254
- const raw = result?.usage;
255
- if (!raw) {
261
+ function readTranslationUsage(usage) {
262
+ if (!usage || typeof usage !== "object") {
256
263
  return {};
257
264
  }
265
+ const raw = usage;
258
266
  const number = (...values) => values.find((value) => typeof value === "number" && Number.isFinite(value) && value >= 0);
259
267
  const details = raw.outputTokenDetails;
260
268
  const inputs = raw.inputTokenDetails;
@@ -275,6 +283,9 @@ function translationUsage(result) {
275
283
  reasoningTokens: number(raw.reasoningTokens, raw.reasoning, details?.reasoningTokens),
276
284
  };
277
285
  }
286
+ function translationUsage(result) {
287
+ return readTranslationUsage(result?.usage);
288
+ }
278
289
  /** Shared request owner, independent of a consumer asking for another chunk. */
279
290
  function createTranslationRequest(args) {
280
291
  const { ctx, requestModel, parsed, tracer, requestStartTime, stream } = args;
@@ -14,6 +14,8 @@ export declare function buildProxyTranslationPlan(primary: {
14
14
  }, fallbackChain: FallbackEntry[], requestedModel: string, _parsed?: ParsedClaudeRequest, allowAutoFallback?: boolean): ProxyTranslationPlan;
15
15
  /**
16
16
  * Parse the retry-after header from an upstream 429 response.
17
- * Returns milliseconds to wait, or 0 if no valid header present.
17
+ *
18
+ * @param retryAfterHeader - The raw Retry-After header string or null
19
+ * @returns Milliseconds to wait (minimum 1000ms if valid), or 0 if no valid header present
18
20
  */
19
21
  export declare function parseRetryAfterMs(retryAfterHeader: string | null): number;
@@ -1,3 +1,4 @@
1
+ import { parseRetryAfterHeaderValue } from "../utils/retryAfter.js";
1
2
  export function inferClaudeProxyModelTier(modelName) {
2
3
  const normalized = modelName.toLowerCase();
3
4
  if (normalized.includes("opus")) {
@@ -59,19 +60,17 @@ export function buildProxyTranslationPlan(primary, fallbackChain, requestedModel
59
60
  // ---------------------------------------------------------------------------
60
61
  /**
61
62
  * Parse the retry-after header from an upstream 429 response.
62
- * Returns milliseconds to wait, or 0 if no valid header present.
63
+ *
64
+ * @param retryAfterHeader - The raw Retry-After header string or null
65
+ * @returns Milliseconds to wait (minimum 1000ms if valid), or 0 if no valid header present
63
66
  */
64
67
  export function parseRetryAfterMs(retryAfterHeader) {
65
68
  if (!retryAfterHeader) {
66
69
  return 0;
67
70
  }
68
- const seconds = parseInt(retryAfterHeader, 10);
69
- if (!Number.isNaN(seconds)) {
70
- return Math.max(1, seconds) * 1000;
71
- }
72
- const date = new Date(retryAfterHeader);
73
- if (!Number.isNaN(date.getTime())) {
74
- return Math.max(1000, date.getTime() - Date.now());
71
+ const delay = parseRetryAfterHeaderValue(retryAfterHeader);
72
+ if (delay !== undefined) {
73
+ return Math.max(1000, delay);
75
74
  }
76
75
  return 0;
77
76
  }
@@ -129,7 +129,7 @@ export type OpenAICompatStreamDelta = {
129
129
  role?: OpenAICompatChatRole;
130
130
  content?: string | null;
131
131
  tool_calls?: Array<{
132
- index: number;
132
+ index?: number;
133
133
  id?: string;
134
134
  type?: "function";
135
135
  function?: {
@@ -1,5 +1,6 @@
1
1
  import type { ProxyTokenBudgetLease, ProxyTokenBudgetSnapshot } from "./proxyBudget.js";
2
2
  import type { CodexRuntimeAccount } from "./codex.js";
3
+ import type { TokenUsage } from "./analytics.js";
3
4
  import type { JsonObject, JsonValue } from "./common.js";
4
5
  import type { ProxyContextEvidence, ProxyPreparedContext } from "./proxyContext.js";
5
6
  /**
@@ -258,14 +259,7 @@ export type InternalResult = {
258
259
  finishReason?: string;
259
260
  /** Thinking/reasoning text from provider (Anthropic thinking blocks, Gemini thought parts) */
260
261
  reasoning?: string;
261
- usage?: {
262
- input: number;
263
- output: number;
264
- total: number;
265
- cacheCreationTokens?: number;
266
- cacheReadTokens?: number;
267
- reasoning?: number;
268
- };
262
+ usage?: TokenUsage;
269
263
  toolCalls?: Array<{
270
264
  toolCallId: string;
271
265
  toolName: string;
@@ -3524,11 +3518,7 @@ export type StreamSerializerAdapter = {
3524
3518
  start(): Iterable<string>;
3525
3519
  pushDelta(text: string): Iterable<string>;
3526
3520
  pushToolUse(id: string, name: string, input: unknown): Iterable<string>;
3527
- finish(finishReason: string, usage: {
3528
- input: number;
3529
- output: number;
3530
- total: number;
3531
- }): Iterable<string>;
3521
+ finish(finishReason: string, usage: TokenUsage): Iterable<string>;
3532
3522
  emitError(message: string): Iterable<string>;
3533
3523
  };
3534
3524
  /** OpenAI content part in a user message. */
@@ -3615,6 +3605,12 @@ export type OpenAIUsage = {
3615
3605
  prompt_tokens: number;
3616
3606
  completion_tokens: number;
3617
3607
  total_tokens: number;
3608
+ prompt_tokens_details?: {
3609
+ cached_tokens: number;
3610
+ };
3611
+ completion_tokens_details?: {
3612
+ reasoning_tokens: number;
3613
+ };
3618
3614
  };
3619
3615
  /** OpenAI non-streaming response. */
3620
3616
  export type OpenAICompletionResponse = {
@@ -268,6 +268,8 @@ export type ProxyLedgerEntry = {
268
268
  model: string;
269
269
  provider?: string;
270
270
  inputTokens: number;
271
+ /** Native Codex input includes cache reads and writes. */
272
+ inputIncludesCachedTokens: boolean;
271
273
  outputTokens: number;
272
274
  cacheReadTokens: number;
273
275
  cacheCreationTokens: number;
@@ -22,7 +22,7 @@ export function getProviderSetupMessage(provider, missingVars) {
22
22
  envVars: [
23
23
  'ANTHROPIC_API_KEY="sk-ant-api03-your-anthropic-key"',
24
24
  "# Optional:",
25
- `ANTHROPIC_MODEL="${AnthropicModels.CLAUDE_3_5_SONNET}"`,
25
+ `ANTHROPIC_MODEL="${AnthropicModels.CLAUDE_SONNET_4_6}"`,
26
26
  ],
27
27
  },
28
28
  "google-ai": {
@@ -1,3 +1,35 @@
1
+ /**
2
+ * Parses a duration string (e.g., "6m0s", "30s", "1h30m", "500ms") into milliseconds.
3
+ *
4
+ * @param raw - The raw duration string
5
+ * @returns Duration in milliseconds, or undefined if invalid
6
+ */
7
+ export declare function parseDurationMs(raw: string): number | undefined;
8
+ /**
9
+ * Parses a single Retry-After header value into milliseconds.
10
+ *
11
+ * Checks in strict order:
12
+ * 1. Strict numeric seconds (e.g. "5", "120", "1.5") without truncation of dates or durations
13
+ * 2. HTTP-date or RFC 3339 / ISO 8601 date (e.g. "2026-10-18T12:00:00Z" or "Sun, 18 Oct 2026 12:00:00 GMT")
14
+ * 3. Duration string (e.g. "6m0s", "30s", "1h30m", "500ms")
15
+ *
16
+ * @param value - The header value string
17
+ * @returns Milliseconds to wait, or undefined if not parseable
18
+ */
19
+ export declare function parseRetryAfterHeaderValue(value: string | null | undefined): number | undefined;
20
+ /**
21
+ * Parses X-RateLimit-Reset header value into milliseconds until reset.
22
+ *
23
+ * Handles:
24
+ * - Delta seconds when value < 1e9 (e.g. "30", "60")
25
+ * - Epoch seconds when 1e9 <= value <= 1e12
26
+ * - Epoch milliseconds when value > 1e12
27
+ * - Fallback to date or duration strings
28
+ *
29
+ * @param value - The X-RateLimit-Reset header value
30
+ * @returns Milliseconds until reset, or undefined if not parseable
31
+ */
32
+ export declare function parseRateLimitResetValue(value: string | null | undefined): number | undefined;
1
33
  /**
2
34
  * Parse standard and commonly used rate-limit response headers.
3
35
  *