@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.
@@ -146,12 +146,53 @@ async function handleOpenAIToAnthropicBridge(args) {
146
146
  });
147
147
  return buildOpenAIErrorResponse(502, "Anthropic loopback returned empty stream body");
148
148
  }
149
- // Streaming success: log now since the response body is consumed by the
150
- // client. Token counts are not visible at this layer (the inner /v1/messages
151
- // handler accounts them), so we omit them here.
152
- await writeLifecycle(200);
153
- const transformed = upstream.body.pipeThrough(createClaudeToOpenAIStreamTransform(body.model));
154
- return new Response(transformed, {
149
+ let terminalStreamError;
150
+ const transformed = upstream.body.pipeThrough(createClaudeToOpenAIStreamTransform(body.model, {
151
+ onError: (message) => {
152
+ terminalStreamError = sanitizeForLog(message);
153
+ },
154
+ }));
155
+ const reader = transformed.getReader();
156
+ let lifecycleWritten = false;
157
+ const finishLifecycle = async (status, errorType, errorMessage) => {
158
+ if (lifecycleWritten) {
159
+ return;
160
+ }
161
+ lifecycleWritten = true;
162
+ await writeLifecycle(status, { errorType, errorMessage });
163
+ };
164
+ const trackedStream = new ReadableStream({
165
+ async pull(controller) {
166
+ try {
167
+ const { value, done } = await reader.read();
168
+ if (done) {
169
+ if (terminalStreamError) {
170
+ await finishLifecycle(502, "loopback_stream_error", terminalStreamError);
171
+ }
172
+ else {
173
+ await finishLifecycle(200);
174
+ }
175
+ controller.close();
176
+ return;
177
+ }
178
+ controller.enqueue(value);
179
+ }
180
+ catch (error) {
181
+ const message = sanitizeForLog(error instanceof Error ? error.message : String(error));
182
+ await finishLifecycle(502, "loopback_stream_error", message);
183
+ controller.error(error);
184
+ }
185
+ },
186
+ async cancel(reason) {
187
+ try {
188
+ await reader.cancel(reason);
189
+ }
190
+ finally {
191
+ await finishLifecycle(499, "client_cancelled", "Client cancelled the OpenAI-compatible stream");
192
+ }
193
+ },
194
+ });
195
+ return new Response(trackedStream, {
155
196
  status: 200,
156
197
  headers: {
157
198
  "content-type": "text/event-stream",
@@ -800,6 +800,8 @@ export type ProxyGuardArgs = {
800
800
  failureThreshold?: number;
801
801
  pollIntervalMs?: number;
802
802
  quiet?: boolean;
803
+ /** Run update checks only; never mutate client settings. */
804
+ updaterOnly?: boolean;
803
805
  };
804
806
  /** Arguments accepted by `neurolink proxy telemetry <subcommand>` */
805
807
  export type ProxyTelemetryArgs = {
@@ -829,6 +831,8 @@ export type ProxyState = {
829
831
  accountAllowlist?: string[];
830
832
  /** Optional fail-open guard PID that reverts Claude settings if proxy dies */
831
833
  guardPid?: number;
834
+ /** Dedicated updater PID for launchd-managed proxy installations. */
835
+ updaterPid?: number;
832
836
  /** How the proxy was launched — "launchd" if installed as service, "manual" otherwise */
833
837
  managedBy?: "launchd" | "manual";
834
838
  /** Whether the proxy is running in transparent passthrough mode */
@@ -518,6 +518,7 @@ export type AnthropicLoopState = {
518
518
  } | null;
519
519
  authFailureMessage: string | null;
520
520
  authCooldownMessage: string | null;
521
+ fallbackFailureMessage?: string;
521
522
  attemptNumber: number;
522
523
  };
523
524
  export type AnthropicUpstreamBody = {
@@ -586,6 +587,10 @@ export type AccountCooldownPlan = {
586
587
  * burst), a small number of jittered same-account retries is allowed first. */
587
588
  rotateImmediately: boolean;
588
589
  };
590
+ export type TransientRateLimitRetryBudget = {
591
+ coolingUntil: number;
592
+ retriesClaimed: number;
593
+ };
589
594
  export type AnthropicUpstreamFetchResult = {
590
595
  continueLoop: boolean;
591
596
  retrySameAccount?: boolean;
@@ -595,6 +600,15 @@ export type AnthropicUpstreamFetchResult = {
595
600
  cooldownPlan?: AccountCooldownPlan;
596
601
  /** Quota snapshot parsed from the response headers (429 or success), if present. */
597
602
  quota?: AccountQuota;
603
+ /** A terminal upstream rejection already captured and classified by the
604
+ * fetch layer. The route must finalize it directly instead of feeding it
605
+ * through the generic non-OK handler a second time. */
606
+ terminalError?: {
607
+ status: number;
608
+ body: string;
609
+ headers: Record<string, string>;
610
+ errorType: "construction_rejection";
611
+ };
598
612
  response?: Response;
599
613
  lastError: unknown;
600
614
  sawRateLimit: boolean;
@@ -897,6 +911,26 @@ export type QuietStatus = {
897
911
  lastActivityAt: Date | null;
898
912
  silenceDurationMs: number;
899
913
  };
914
+ /** In-process proxy request activity used to protect streaming restarts. */
915
+ export type ProxyActivitySnapshot = {
916
+ activeRequests: number;
917
+ lastActivityAt: Date | null;
918
+ };
919
+ /** Activity payload exposed by the running proxy status endpoint. */
920
+ export type ProxyRuntimeActivity = {
921
+ activeRequests: number;
922
+ lastActivityAt: string | null;
923
+ };
924
+ /** Request metadata retained by the HTTP adapter for terminal error logging. */
925
+ export type RuntimeRequestMetadata = {
926
+ requestId: string;
927
+ method: string;
928
+ path: string;
929
+ startedAt: number;
930
+ model: string;
931
+ stream: boolean;
932
+ toolCount: number;
933
+ };
900
934
  /** Accumulated upstream body capture from a raw stream. */
901
935
  export type RawStreamCapture = {
902
936
  totalBytes: number;
@@ -1060,6 +1094,34 @@ export type UpdateState = {
1060
1094
  lastUpdateAt: string | null;
1061
1095
  lastUpdateVersion: string | null;
1062
1096
  };
1097
+ /** Supported global package managers for proxy self-updates. */
1098
+ export type GlobalInstallerKind = "npm" | "pnpm";
1099
+ /** Result of probing one global package-manager executable. */
1100
+ export type GlobalInstallerProbe = {
1101
+ kind: GlobalInstallerKind;
1102
+ bin: string;
1103
+ version?: string;
1104
+ globalRoot?: string;
1105
+ globalBinDir?: string;
1106
+ working: boolean;
1107
+ installable: boolean;
1108
+ matchesCurrentInstall: boolean;
1109
+ reason?: string;
1110
+ };
1111
+ /** Selected package manager plus all candidates considered. */
1112
+ export type GlobalInstallerResolution = {
1113
+ installer?: GlobalInstallerProbe;
1114
+ tried: GlobalInstallerProbe[];
1115
+ };
1116
+ /** Injectable command runner used by global-installer tests. */
1117
+ export type GlobalInstallerExecFile = typeof import("node:child_process").execFileSync;
1118
+ /** Overrides used while resolving the global package manager. */
1119
+ export type ResolveGlobalInstallerOptions = {
1120
+ entryScript?: string;
1121
+ env?: NodeJS.ProcessEnv;
1122
+ homeDir?: string;
1123
+ execFileSync?: GlobalInstallerExecFile;
1124
+ };
1063
1125
  /** Shape of the dynamically-imported js-yaml module. `dump` is optional —
1064
1126
  * read-only consumers (proxy config loader) only need `load`; writers
1065
1127
  * (CLI primary-account commands) check `dump` before calling. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "9.87.2",
3
+ "version": "9.87.4",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (58+ servers), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {