@juspay/neurolink 10.12.4 → 10.12.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/browser/neurolink.min.js +420 -420
- package/dist/cli/commands/proxy.js +13 -17
- package/dist/cli/commands/proxyAnalyze.js +8 -3
- package/dist/lib/processors/archive/ArchiveProcessor.js +13 -67
- package/dist/lib/processors/archive/zipEntryReader.d.ts +51 -0
- package/dist/lib/processors/archive/zipEntryReader.js +81 -0
- package/dist/lib/processors/document/OpenDocumentProcessor.js +13 -1
- package/dist/lib/processors/document/PptxProcessor.js +58 -12
- package/dist/lib/proxy/logCleanupScheduler.d.ts +12 -0
- package/dist/lib/proxy/logCleanupScheduler.js +74 -0
- package/dist/lib/proxy/logCleanupWorkerEntry.d.ts +1 -0
- package/dist/lib/proxy/logCleanupWorkerEntry.js +15 -0
- package/dist/lib/proxy/proxyAnalysis.js +6 -0
- package/dist/lib/proxy/requestLogger.d.ts +6 -0
- package/dist/lib/proxy/requestLogger.js +57 -47
- package/dist/lib/proxy/rollingWorkerSupervisor.d.ts +2 -0
- package/dist/lib/proxy/rollingWorkerSupervisor.js +40 -2
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +2 -0
- package/dist/lib/server/routes/claudeProxyRoutes.js +33 -2
- package/dist/lib/types/processor.d.ts +15 -0
- package/dist/lib/types/proxy.d.ts +32 -1
- package/dist/processors/archive/ArchiveProcessor.js +13 -67
- package/dist/processors/archive/zipEntryReader.d.ts +51 -0
- package/dist/processors/archive/zipEntryReader.js +80 -0
- package/dist/processors/document/OpenDocumentProcessor.js +13 -1
- package/dist/processors/document/PptxProcessor.js +58 -12
- package/dist/proxy/logCleanupScheduler.d.ts +12 -0
- package/dist/proxy/logCleanupScheduler.js +73 -0
- package/dist/proxy/logCleanupWorkerEntry.d.ts +1 -0
- package/dist/proxy/logCleanupWorkerEntry.js +14 -0
- package/dist/proxy/proxyAnalysis.js +6 -0
- package/dist/proxy/requestLogger.d.ts +6 -0
- package/dist/proxy/requestLogger.js +57 -47
- package/dist/proxy/rollingWorkerSupervisor.d.ts +2 -0
- package/dist/proxy/rollingWorkerSupervisor.js +40 -2
- package/dist/server/routes/claudeProxyRoutes.d.ts +2 -0
- package/dist/server/routes/claudeProxyRoutes.js +33 -2
- package/dist/types/processor.d.ts +15 -0
- package/dist/types/proxy.d.ts +32 -1
- package/package.json +5 -3
|
@@ -63,6 +63,7 @@ let lastKnownAccountCount = 0;
|
|
|
63
63
|
const MAX_AUTH_RETRIES = 5;
|
|
64
64
|
const MAX_TRANSIENT_SAME_ACCOUNT_RETRIES = 2;
|
|
65
65
|
const TRANSIENT_SAME_ACCOUNT_RETRY_DELAYS_MS = [250, 1_000];
|
|
66
|
+
const OVERLOAD_ACCOUNT_ROTATION_DELAYS_MS = [250, 500, 1_000, 2_000];
|
|
66
67
|
const MAX_FALLBACK_NETWORK_RETRIES = 1;
|
|
67
68
|
const FALLBACK_STREAM_IDLE_TIMEOUT_MS = 2 * 60 * 1000;
|
|
68
69
|
/** Maximum upstream 429 attempts per account before rotating — for a TRANSIENT
|
|
@@ -2883,7 +2884,13 @@ async function handleAnthropicStreamingSuccessResponse(args) {
|
|
|
2883
2884
|
});
|
|
2884
2885
|
return {
|
|
2885
2886
|
retryNextAccount: true,
|
|
2886
|
-
failure: {
|
|
2887
|
+
failure: {
|
|
2888
|
+
message: preflight.message,
|
|
2889
|
+
rateLimit: isRateLimit,
|
|
2890
|
+
...(preflight.errorType === "overloaded_error"
|
|
2891
|
+
? { retryDelayMs: getOverloadRotationDelayMs(attemptNumber) }
|
|
2892
|
+
: {}),
|
|
2893
|
+
},
|
|
2887
2894
|
};
|
|
2888
2895
|
}
|
|
2889
2896
|
logAttempt(response.status, undefined, undefined, {
|
|
@@ -3484,6 +3491,9 @@ async function handleAnthropicAuthRetry(args) {
|
|
|
3484
3491
|
const failure = successResult.failure;
|
|
3485
3492
|
return {
|
|
3486
3493
|
continueLoop: true,
|
|
3494
|
+
...(failure?.retryDelayMs
|
|
3495
|
+
? { retryDelayMs: failure.retryDelayMs }
|
|
3496
|
+
: {}),
|
|
3487
3497
|
lastError: failure?.message ?? currentLastError,
|
|
3488
3498
|
authFailureMessage: currentAuthFailureMessage,
|
|
3489
3499
|
sawRateLimit: currentSawRateLimit || Boolean(failure?.rateLimit),
|
|
@@ -3941,6 +3951,9 @@ async function handleAnthropicNonOkResponse(args) {
|
|
|
3941
3951
|
return {
|
|
3942
3952
|
continueLoop: true,
|
|
3943
3953
|
retrySameAccount: !upstreamOverload,
|
|
3954
|
+
...(upstreamOverload
|
|
3955
|
+
? { retryDelayMs: getOverloadRotationDelayMs(attemptNumber) }
|
|
3956
|
+
: {}),
|
|
3944
3957
|
lastError: currentLastError,
|
|
3945
3958
|
authFailureMessage: currentAuthFailureMessage,
|
|
3946
3959
|
sawTransientFailure: currentSawTransientFailure,
|
|
@@ -4553,7 +4566,8 @@ async function handleAnthropicRoutedClaudeRequest(args) {
|
|
|
4553
4566
|
effectiveAccounts.every((account) => !isAccountAdmissionAvailable(account.key, accountAdmissionCapacity))) {
|
|
4554
4567
|
queuedAccountAdmission = await acquireFirstAvailableAccountAdmission(effectiveAccounts.map((account) => account.key), accountAdmissionCapacity, ctx.abortSignal);
|
|
4555
4568
|
}
|
|
4556
|
-
accountLoop: for (const account of effectiveAccounts) {
|
|
4569
|
+
accountLoop: for (const [accountIndex, account,] of effectiveAccounts.entries()) {
|
|
4570
|
+
const hasNextAccount = accountIndex < effectiveAccounts.length - 1;
|
|
4557
4571
|
const accountState = getOrCreateRuntimeState(account.key);
|
|
4558
4572
|
let transientSameAccountRetries = 0;
|
|
4559
4573
|
let rateLimitSameAccountRetries = 0;
|
|
@@ -4763,6 +4777,10 @@ async function handleAnthropicRoutedClaudeRequest(args) {
|
|
|
4763
4777
|
return authRetryResult.response;
|
|
4764
4778
|
}
|
|
4765
4779
|
if (authRetryResult.continueLoop) {
|
|
4780
|
+
if (hasNextAccount && authRetryResult.retryDelayMs) {
|
|
4781
|
+
logger.always(`[proxy] pacing cross-account SSE overload rotation for ${authRetryResult.retryDelayMs}ms after auth refresh`);
|
|
4782
|
+
await sleep(authRetryResult.retryDelayMs);
|
|
4783
|
+
}
|
|
4766
4784
|
continue accountLoop;
|
|
4767
4785
|
}
|
|
4768
4786
|
}
|
|
@@ -4804,6 +4822,10 @@ async function handleAnthropicRoutedClaudeRequest(args) {
|
|
|
4804
4822
|
if (nonOkResult.retrySameAccount) {
|
|
4805
4823
|
logger.always(`[proxy] exhausted transient same-account retries for account=${account.label}; rotating`);
|
|
4806
4824
|
}
|
|
4825
|
+
if (hasNextAccount && nonOkResult.retryDelayMs) {
|
|
4826
|
+
logger.always(`[proxy] pacing cross-account overload rotation for ${nonOkResult.retryDelayMs}ms`);
|
|
4827
|
+
await sleep(nonOkResult.retryDelayMs);
|
|
4828
|
+
}
|
|
4807
4829
|
continue accountLoop;
|
|
4808
4830
|
}
|
|
4809
4831
|
break accountLoop;
|
|
@@ -4845,6 +4867,10 @@ async function handleAnthropicRoutedClaudeRequest(args) {
|
|
|
4845
4867
|
loopState.lastError = successResult.failure.message;
|
|
4846
4868
|
loopState.sawRateLimit ||= successResult.failure.rateLimit;
|
|
4847
4869
|
loopState.sawTransientFailure ||= !successResult.failure.rateLimit;
|
|
4870
|
+
if (hasNextAccount && successResult.failure.retryDelayMs) {
|
|
4871
|
+
logger.always(`[proxy] pacing cross-account SSE overload rotation for ${successResult.failure.retryDelayMs}ms`);
|
|
4872
|
+
await sleep(successResult.failure.retryDelayMs);
|
|
4873
|
+
}
|
|
4848
4874
|
}
|
|
4849
4875
|
continue accountLoop;
|
|
4850
4876
|
}
|
|
@@ -5315,6 +5341,10 @@ export function getTransientSameAccountRetryDelayMs(retryNumber) {
|
|
|
5315
5341
|
const index = Math.min(Math.max(retryNumber - 1, 0), TRANSIENT_SAME_ACCOUNT_RETRY_DELAYS_MS.length - 1);
|
|
5316
5342
|
return TRANSIENT_SAME_ACCOUNT_RETRY_DELAYS_MS[index] ?? 0;
|
|
5317
5343
|
}
|
|
5344
|
+
export function getOverloadRotationDelayMs(attemptNumber) {
|
|
5345
|
+
const index = Math.min(Math.max(attemptNumber - 1, 0), OVERLOAD_ACCOUNT_ROTATION_DELAYS_MS.length - 1);
|
|
5346
|
+
return jitteredDelay(OVERLOAD_ACCOUNT_ROTATION_DELAYS_MS[index] ?? 250);
|
|
5347
|
+
}
|
|
5318
5348
|
async function sleep(ms) {
|
|
5319
5349
|
await new Promise((resolve) => setTimeout(resolve, ms));
|
|
5320
5350
|
}
|
|
@@ -5586,6 +5616,7 @@ export const __testHooks = {
|
|
|
5586
5616
|
describeTransportError,
|
|
5587
5617
|
redactProviderErrorMessage,
|
|
5588
5618
|
isUpstreamOverload,
|
|
5619
|
+
getOverloadRotationDelayMs,
|
|
5589
5620
|
shouldAttemptClaudeFallback,
|
|
5590
5621
|
executeClaudeFallbackWithRetry,
|
|
5591
5622
|
buildClaudeAnthropicFailureResponse,
|
|
@@ -774,6 +774,21 @@ export type ArchiveDecompressionResult = {
|
|
|
774
774
|
* perfectly well-formed, and telling the user it is damaged would send them to
|
|
775
775
|
* re-create a file that was never broken.
|
|
776
776
|
*/
|
|
777
|
+
/**
|
|
778
|
+
* The slice of an adm-zip entry the bounded reader depends on.
|
|
779
|
+
*
|
|
780
|
+
* Structural rather than adm-zip's own `IZipEntry` so the reader states what it
|
|
781
|
+
* actually needs — the compressed bytes and the header fields it refuses to
|
|
782
|
+
* trust — instead of importing a library type it would then have to satisfy in
|
|
783
|
+
* full when building a test double.
|
|
784
|
+
*/
|
|
785
|
+
export type BoundedZipEntry = {
|
|
786
|
+
getCompressedData: () => Buffer;
|
|
787
|
+
header: {
|
|
788
|
+
method: number;
|
|
789
|
+
crc: number;
|
|
790
|
+
};
|
|
791
|
+
};
|
|
777
792
|
export type ArchiveEntryReadResult = {
|
|
778
793
|
readonly status: "ok";
|
|
779
794
|
readonly buffer: Buffer;
|
package/dist/types/proxy.d.ts
CHANGED
|
@@ -646,6 +646,7 @@ export type AnthropicSuccessResult = {
|
|
|
646
646
|
failure?: {
|
|
647
647
|
message: string;
|
|
648
648
|
rateLimit: boolean;
|
|
649
|
+
retryDelayMs?: number;
|
|
649
650
|
};
|
|
650
651
|
} | {
|
|
651
652
|
response: Response | unknown;
|
|
@@ -702,6 +703,8 @@ export type AnthropicAuthRetryResult = {
|
|
|
702
703
|
response?: Response | unknown;
|
|
703
704
|
holdsAccountAdmission?: boolean;
|
|
704
705
|
continueLoop: boolean;
|
|
706
|
+
/** Failure-path pacing before rotating after provider-wide overload. */
|
|
707
|
+
retryDelayMs?: number;
|
|
705
708
|
lastError: unknown;
|
|
706
709
|
authFailureMessage: string | null;
|
|
707
710
|
sawRateLimit: boolean;
|
|
@@ -713,6 +716,8 @@ export type AnthropicNonOkResult = {
|
|
|
713
716
|
response?: Response | unknown;
|
|
714
717
|
continueLoop: boolean;
|
|
715
718
|
retrySameAccount?: boolean;
|
|
719
|
+
/** Failure-path pacing before rotating after provider-wide overload. */
|
|
720
|
+
retryDelayMs?: number;
|
|
716
721
|
lastError: unknown;
|
|
717
722
|
authFailureMessage: string | null;
|
|
718
723
|
sawTransientFailure: boolean;
|
|
@@ -1457,6 +1462,9 @@ export type ProxyAnalysisReport = {
|
|
|
1457
1462
|
attemptLatency: boolean;
|
|
1458
1463
|
cacheUsage: boolean;
|
|
1459
1464
|
routingDecisions: boolean;
|
|
1465
|
+
/** True only when every stream needed for cross-stream request/attempt
|
|
1466
|
+
* reconciliation begins at or before the requested analysis window. */
|
|
1467
|
+
comparableRequestAttempts: boolean;
|
|
1460
1468
|
};
|
|
1461
1469
|
dataQuality: {
|
|
1462
1470
|
linesRead: number;
|
|
@@ -1468,6 +1476,8 @@ export type ProxyAnalysisReport = {
|
|
|
1468
1476
|
observedFrom: string | null;
|
|
1469
1477
|
observedTo: string | null;
|
|
1470
1478
|
startsAtOrBeforeRequestedWindow: boolean;
|
|
1479
|
+
/** Whether this stream can support claims covering the full window. */
|
|
1480
|
+
completeWindow: boolean;
|
|
1471
1481
|
}>;
|
|
1472
1482
|
bodyArtifacts: {
|
|
1473
1483
|
capturesIndexed: number;
|
|
@@ -2073,6 +2083,14 @@ export type RollingWorkerFailureDetails = {
|
|
|
2073
2083
|
workerExitSignal?: string | null;
|
|
2074
2084
|
supervisorAction?: "none" | "sigkill_after_transfer_failure";
|
|
2075
2085
|
};
|
|
2086
|
+
export type RollingWorkerSupervisorEvent = {
|
|
2087
|
+
at: string;
|
|
2088
|
+
type: "activated" | "failure" | "failed_transfer" | "rejected_socket";
|
|
2089
|
+
generation: number | null;
|
|
2090
|
+
version: string | null;
|
|
2091
|
+
phase?: "startup" | "activation" | "runtime" | "transfer";
|
|
2092
|
+
reason?: string;
|
|
2093
|
+
};
|
|
2076
2094
|
export type RollingWorkerSupervisorSnapshot = {
|
|
2077
2095
|
generation: number;
|
|
2078
2096
|
active: {
|
|
@@ -2093,6 +2111,8 @@ export type RollingWorkerSupervisorSnapshot = {
|
|
|
2093
2111
|
queuedSockets: number;
|
|
2094
2112
|
rejectedSockets: number;
|
|
2095
2113
|
failedTransfers: number;
|
|
2114
|
+
/** Bounded generation-scoped evidence for attributing lifetime counters. */
|
|
2115
|
+
recentEvents: RollingWorkerSupervisorEvent[];
|
|
2096
2116
|
lastFailure: ({
|
|
2097
2117
|
at: string;
|
|
2098
2118
|
generation: number;
|
|
@@ -2305,7 +2325,18 @@ export type ProxyNeurolinkRuntime = {
|
|
|
2305
2325
|
neurolink: {
|
|
2306
2326
|
getToolRegistry(): MCPToolRegistry;
|
|
2307
2327
|
};
|
|
2308
|
-
|
|
2328
|
+
logsDir: string;
|
|
2329
|
+
};
|
|
2330
|
+
/** Data passed to the isolated proxy log-retention worker. */
|
|
2331
|
+
export type ProxyLogCleanupWorkerData = {
|
|
2332
|
+
logsDir: string;
|
|
2333
|
+
maxAgeDays: number;
|
|
2334
|
+
maxSizeMb: number;
|
|
2335
|
+
};
|
|
2336
|
+
/** Lifecycle handle for non-blocking proxy log retention. */
|
|
2337
|
+
export type ProxyLogCleanupScheduler = {
|
|
2338
|
+
trigger: () => boolean;
|
|
2339
|
+
stop: () => Promise<void>;
|
|
2309
2340
|
};
|
|
2310
2341
|
/** Hono app + readiness state created by the proxy start command. */
|
|
2311
2342
|
export type ProxyStartApp = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.12.
|
|
3
|
+
"version": "10.12.6",
|
|
4
4
|
"packageManager": "pnpm@10.15.1",
|
|
5
5
|
"description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
|
|
6
6
|
"author": {
|
|
@@ -163,7 +163,7 @@
|
|
|
163
163
|
"test:system-messages": "npx tsx test/continuous-test-suite-system-messages.ts",
|
|
164
164
|
"test:test-stubs": "npx tsx test/continuous-test-suite-test-stubs.ts",
|
|
165
165
|
"test:tool-routing-semantic": "npx tsx test/continuous-test-suite-tool-routing-semantic.ts",
|
|
166
|
-
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:file-detector-extension && pnpm run test:file-detector-magic-bytes && pnpm run test:mcp:infra && pnpm run test:mcp:bash && pnpm run test:mcp:limits && pnpm run test:mcp:spans && pnpm run test:autoresearch:redis && pnpm run test:tool-routing && pnpm run test:tool-routing-cli && pnpm run test:tool-dedup && pnpm run test:model-pool && pnpm run test:litellm-context && pnpm run test:dedup-execute-map && pnpm run test:step-budget-guard && pnpm run test:agent-plumbing && pnpm run test:tool-execution-recorder && pnpm run test:proxy-terminal-errors && pnpm run test:proxy-usage-refresh && pnpm run test:system-messages && pnpm run test:tool-routing-semantic && pnpm run test:anthropic-tools-policy && pnpm run test:anthropic-structured && pnpm run test:sagemaker-tools && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop && pnpm run test:model-capabilities && pnpm run test:agent-runtime:vitest && pnpm run test:agent-delegation && pnpm run test:retry-after:vitest && pnpm run test:sampling-params && pnpm run test:structured-recovery && pnpm run test:prompt-redaction && pnpm run test:mcp-result-cache && pnpm run test:test-stubs && pnpm run test:model-not-found-retryable && pnpm run test:websearch-grounding && pnpm run test:archive:security",
|
|
166
|
+
"test:unit": "pnpm run test:envguard && pnpm run test:bugfixes && pnpm run test:file-detector-extension && pnpm run test:file-detector-magic-bytes && pnpm run test:mcp:infra && pnpm run test:mcp:bash && pnpm run test:mcp:limits && pnpm run test:mcp:spans && pnpm run test:autoresearch:redis && pnpm run test:tool-routing && pnpm run test:tool-routing-cli && pnpm run test:tool-dedup && pnpm run test:model-pool && pnpm run test:litellm-context && pnpm run test:dedup-execute-map && pnpm run test:step-budget-guard && pnpm run test:agent-plumbing && pnpm run test:tool-execution-recorder && pnpm run test:proxy-terminal-errors && pnpm run test:proxy-usage-refresh && pnpm run test:system-messages && pnpm run test:tool-routing-semantic && pnpm run test:anthropic-tools-policy && pnpm run test:anthropic-structured && pnpm run test:sagemaker-tools && pnpm run test:anthropic-multimodal && pnpm run test:excel-interop && pnpm run test:model-capabilities && pnpm run test:agent-runtime:vitest && pnpm run test:agent-delegation && pnpm run test:retry-after:vitest && pnpm run test:sampling-params && pnpm run test:structured-recovery && pnpm run test:prompt-redaction && pnpm run test:mcp-result-cache && pnpm run test:test-stubs && pnpm run test:model-not-found-retryable && pnpm run test:websearch-grounding && pnpm run test:archive:security && pnpm run test:office:security && pnpm run test:proxy:vitest",
|
|
167
167
|
"// CI tier — live providers, runs only when API keys are present (test:credentials and test:dynamic make real provider calls when keys are set, so they live here, not in test:unit)": "",
|
|
168
168
|
"test:live": "pnpm run test:providers && pnpm run test:mcp:http && pnpm run test:mcp:sdk && pnpm run test:mcp:cli && pnpm run test:observability && pnpm run test:context && pnpm run test:memory && pnpm run test:tool-reliability && pnpm run test:evaluation && pnpm run test:autoresearch && pnpm run test:credentials && pnpm run test:dynamic",
|
|
169
169
|
"// CI tier — product output (image/video/TTS/PPT) — costs $$ per run": "",
|
|
@@ -234,6 +234,7 @@
|
|
|
234
234
|
"test:proxy-terminal-errors": "npx tsx test/continuous-test-suite-proxy-terminal-errors.ts",
|
|
235
235
|
"test:proxy-limit-headers": "npx tsx test/continuous-test-suite-proxy-limit-headers.ts",
|
|
236
236
|
"test:proxy-usage-refresh": "npx tsx test/continuous-test-suite-proxy-usage-refresh.ts",
|
|
237
|
+
"test:proxy:vitest": "pnpm exec vitest run test/proxyAnalysis.test.ts test/proxyConfigHotReload.test.ts test/proxyObservabilityFoundation.test.ts test/proxyReliabilityHardening.test.ts test/proxyReplay.test.ts test/proxyRollingWorkerHandoff.test.ts test/proxyTestIsolation.test.ts test/proxyUpdaterFallback.test.ts test/proxyUsageStatsPersistence.test.ts",
|
|
237
238
|
"test:anthropic-limit-capture": "npx tsx test/continuous-test-suite-anthropic-limit-capture.ts",
|
|
238
239
|
"test:audio": "npx tsx test/continuous-test-suite-audio.ts",
|
|
239
240
|
"test:file-formats": "npx tsx test/continuous-test-suite-file-formats.ts",
|
|
@@ -246,7 +247,8 @@
|
|
|
246
247
|
"test:structured-recovery": "npx tsx test/continuous-test-suite-structured-recovery.ts",
|
|
247
248
|
"test:prompt-redaction": "npx tsx test/continuous-test-suite-prompt-redaction.ts",
|
|
248
249
|
"test:mcp-result-cache": "npx tsx test/continuous-test-suite-mcp-result-cache.ts",
|
|
249
|
-
"test:archive:security": "npx tsx test/continuous-test-suite-archive-security.ts"
|
|
250
|
+
"test:archive:security": "npx tsx test/continuous-test-suite-archive-security.ts",
|
|
251
|
+
"test:office:security": "npx tsx test/continuous-test-suite-office-security.ts"
|
|
250
252
|
},
|
|
251
253
|
"files": [
|
|
252
254
|
"dist",
|