@juspay/neurolink 12.9.0 → 12.9.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.
|
@@ -26,7 +26,7 @@ import { ProxyRuntimeConfigStore } from "../../proxy/runtimeConfig.js";
|
|
|
26
26
|
import { startProxyLogCleanupScheduler } from "../../proxy/logCleanupScheduler.js";
|
|
27
27
|
import { anthropicAccountKeysEqual, createAccountAllowlist, isAccountAllowed, LEGACY_ANTHROPIC_ACCOUNT_KEY, normalizeAnthropicAccountKey, shouldLoadFallbackCredential, } from "../../proxy/accountSelection.js";
|
|
28
28
|
import { resolveProxyStatusAccountIdentity } from "../../proxy/codexAccountUsage.js";
|
|
29
|
-
import { beginProxyRequest, getProxyActivitySnapshot, trackProxyResponse, } from "../../proxy/proxyActivity.js";
|
|
29
|
+
import { beginProxyRequest, getProxyActivitySnapshot, takeProxyResponseObservers, trackProxyResponse, } from "../../proxy/proxyActivity.js";
|
|
30
30
|
import { flushProxyLifecycleEvents, getProxyLifecycleLoggerSnapshot, hashProxyLifecycleSessionId, logProxyLifecycleEvent, } from "../../proxy/proxyLifecycle.js";
|
|
31
31
|
import { describeInstallFailure, getGlobalInstallArgs, isTransientInstallFailure, resolveGlobalInstaller, validateInstalledVersion, } from "../../proxy/globalInstaller.js";
|
|
32
32
|
import { startUpdaterWorkerSupervisor } from "../../proxy/updaterSupervisor.js";
|
|
@@ -1120,6 +1120,27 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1120
1120
|
responseStatus,
|
|
1121
1121
|
elapsedMs: performance.now() - startedMonotonicMs,
|
|
1122
1122
|
});
|
|
1123
|
+
const routeResponseObservers = takeProxyResponseObservers(metadata);
|
|
1124
|
+
const notifyRouteFirstChunk = (details) => {
|
|
1125
|
+
for (const observer of routeResponseObservers) {
|
|
1126
|
+
try {
|
|
1127
|
+
observer.onFirstChunk?.(details);
|
|
1128
|
+
}
|
|
1129
|
+
catch {
|
|
1130
|
+
// Route-level accounting must never interfere with the relay.
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
};
|
|
1134
|
+
const notifyRouteTerminal = (details) => {
|
|
1135
|
+
for (const observer of routeResponseObservers) {
|
|
1136
|
+
try {
|
|
1137
|
+
observer.onTerminal?.(details);
|
|
1138
|
+
}
|
|
1139
|
+
catch {
|
|
1140
|
+
// Route-level accounting must never interfere with the relay.
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
};
|
|
1123
1144
|
c.res = trackProxyResponse(c.res, finish, {
|
|
1124
1145
|
onFirstChunk: ({ observedBodyBytes, responseChunks }) => {
|
|
1125
1146
|
logProxyLifecycleEvent({
|
|
@@ -1137,6 +1158,10 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1137
1158
|
responseChunks,
|
|
1138
1159
|
elapsedMs: performance.now() - startedMonotonicMs,
|
|
1139
1160
|
});
|
|
1161
|
+
notifyRouteFirstChunk({
|
|
1162
|
+
observedBodyBytes,
|
|
1163
|
+
responseChunks,
|
|
1164
|
+
});
|
|
1140
1165
|
},
|
|
1141
1166
|
onTerminal: ({ outcome, observedBodyBytes, responseChunks }) => {
|
|
1142
1167
|
logProxyLifecycleEvent({
|
|
@@ -1157,6 +1182,11 @@ function registerProxyRequestTracking(app, requestMetadata, readiness) {
|
|
|
1157
1182
|
errorType: metadata.terminalErrorType,
|
|
1158
1183
|
errorCode: metadata.terminalErrorCode,
|
|
1159
1184
|
});
|
|
1185
|
+
notifyRouteTerminal({
|
|
1186
|
+
outcome,
|
|
1187
|
+
observedBodyBytes,
|
|
1188
|
+
responseChunks,
|
|
1189
|
+
});
|
|
1160
1190
|
},
|
|
1161
1191
|
});
|
|
1162
1192
|
}
|
|
@@ -1484,7 +1514,10 @@ export async function createProxyStartApp(params) {
|
|
|
1484
1514
|
neurolink: params.neurolink,
|
|
1485
1515
|
toolRegistry: params.neurolink.getToolRegistry(),
|
|
1486
1516
|
timestamp: Date.now(),
|
|
1487
|
-
metadata
|
|
1517
|
+
// Keep route terminal observers on the runtime request metadata so the
|
|
1518
|
+
// outer response tracker can notify them without adding a second body
|
|
1519
|
+
// wrapper to streaming routes.
|
|
1520
|
+
metadata: (metadata ?? {}),
|
|
1488
1521
|
// Route handlers publish limit/quota headers here. Only the streaming
|
|
1489
1522
|
// paths build their own Response (and set headers directly); every
|
|
1490
1523
|
// JSON and error path returns a plain object, so without this the
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { ProxyActivitySnapshot, ProxyResponseTrackingObserver } from "../types/index.js";
|
|
2
|
+
export declare function registerProxyResponseObserver(metadata: object, observer: ProxyResponseTrackingObserver): void;
|
|
3
|
+
export declare function takeProxyResponseObservers(metadata: object): ProxyResponseTrackingObserver[];
|
|
2
4
|
/** Track one client-facing proxy request until its response body settles. */
|
|
3
5
|
export declare function beginProxyRequest(): () => void;
|
|
4
6
|
export declare function getProxyActivitySnapshot(): ProxyActivitySnapshot;
|
|
@@ -3,6 +3,24 @@ import { logger } from "../utils/logger.js";
|
|
|
3
3
|
const PROXY_RESPONSE_CANCEL_TIMEOUT_MS = 1_000;
|
|
4
4
|
let activeRequests = 0;
|
|
5
5
|
let lastActivityAtMs = null;
|
|
6
|
+
// Route handlers can attach terminal observers to their request context without
|
|
7
|
+
// wrapping the response body a second time. The HTTP runtime drains every
|
|
8
|
+
// response through one tracker, which fans these observers out at the point
|
|
9
|
+
// where bytes actually leave the proxy.
|
|
10
|
+
const responseObserversByMetadata = new WeakMap();
|
|
11
|
+
export function registerProxyResponseObserver(metadata, observer) {
|
|
12
|
+
const existing = responseObserversByMetadata.get(metadata);
|
|
13
|
+
if (existing) {
|
|
14
|
+
existing.push(observer);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
responseObserversByMetadata.set(metadata, [observer]);
|
|
18
|
+
}
|
|
19
|
+
export function takeProxyResponseObservers(metadata) {
|
|
20
|
+
const observers = responseObserversByMetadata.get(metadata) ?? [];
|
|
21
|
+
responseObserversByMetadata.delete(metadata);
|
|
22
|
+
return observers;
|
|
23
|
+
}
|
|
6
24
|
function touchActivity() {
|
|
7
25
|
lastActivityAtMs = Date.now();
|
|
8
26
|
}
|
|
@@ -24,7 +24,7 @@ import { loadAccountQuotas, saveAccountQuota, } from "../../proxy/accountQuota.j
|
|
|
24
24
|
import { createCodexUsageTap } from "../../proxy/codexUsage.js";
|
|
25
25
|
import { CODEX_ACCOUNT_PREFIX, parseCodexRateLimitHeaders, } from "../../proxy/codexAccountUsage.js";
|
|
26
26
|
import { buildClientAttribution } from "../../proxy/clientAttribution.js";
|
|
27
|
-
import {
|
|
27
|
+
import { registerProxyResponseObserver } from "../../proxy/proxyActivity.js";
|
|
28
28
|
import { logRequest, logRequestAttempt } from "../../proxy/requestLogger.js";
|
|
29
29
|
import { parseRetryAfterMs } from "../../proxy/routingPolicy.js";
|
|
30
30
|
import { recordAttempt, recordAttemptError, recordFinalError, recordFinalSuccess, } from "../../proxy/usageStats.js";
|
|
@@ -459,7 +459,7 @@ export async function handleCodexResponsesRequest(ctx) {
|
|
|
459
459
|
status: upstream.status,
|
|
460
460
|
headers,
|
|
461
461
|
});
|
|
462
|
-
|
|
462
|
+
registerProxyResponseObserver(ctx.metadata, {
|
|
463
463
|
onTerminal: ({ outcome }) => {
|
|
464
464
|
void usageSeen
|
|
465
465
|
.then((usage) => {
|
|
@@ -491,6 +491,7 @@ export async function handleCodexResponsesRequest(ctx) {
|
|
|
491
491
|
.catch(() => undefined);
|
|
492
492
|
},
|
|
493
493
|
});
|
|
494
|
+
return relay;
|
|
494
495
|
}
|
|
495
496
|
const errText = await upstream.text().catch(() => "");
|
|
496
497
|
// 401/403 → try a forced token refresh once, then rotate.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "12.9.
|
|
3
|
+
"version": "12.9.1",
|
|
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": {
|