@juspay/neurolink 10.5.0 → 10.5.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.
- package/CHANGELOG.md +6 -0
- package/dist/browser/neurolink.min.js +280 -280
- package/dist/lib/server/routes/claudeProxyRoutes.d.ts +11 -0
- package/dist/lib/server/routes/claudeProxyRoutes.js +55 -0
- package/dist/server/routes/claudeProxyRoutes.d.ts +11 -0
- package/dist/server/routes/claudeProxyRoutes.js +55 -0
- package/package.json +1 -1
|
@@ -249,6 +249,17 @@ export declare function parseClaudeErrorBody(errBody: string): ParsedClaudeError
|
|
|
249
249
|
* Detect malformed request errors that should not trigger account/provider failover.
|
|
250
250
|
*/
|
|
251
251
|
export declare function isInvalidRequestError(status: number, errBody: string): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* A subscription-specific beta rejection. Anthropic returns
|
|
254
|
+
* `400 invalid_request_error` with a message like
|
|
255
|
+
* "The long context beta is not yet available for this subscription." when an
|
|
256
|
+
* account's plan tier does not grant an optional beta the proxy injected (see
|
|
257
|
+
* CLAUDE_CODE_OAUTH_BETAS in anthropicOAuth.ts). Unlike a genuinely malformed
|
|
258
|
+
* request, the SAME request can succeed on a different account whose tier
|
|
259
|
+
* grants the beta — so this must be treated as retryable on the next account
|
|
260
|
+
* rather than a terminal client-facing 400.
|
|
261
|
+
*/
|
|
262
|
+
export declare function isSubscriptionBetaRejection(status: number, errBody: string): boolean;
|
|
252
263
|
/**
|
|
253
264
|
* Backward-compatible alias — delegates to the shared translation engine.
|
|
254
265
|
*/
|
|
@@ -3131,6 +3131,38 @@ async function handleAnthropicNonOkResponse(args) {
|
|
|
3131
3131
|
durationMs: Date.now() - fetchStartMs,
|
|
3132
3132
|
});
|
|
3133
3133
|
if (isInvalidRequestError(response.status, errBody)) {
|
|
3134
|
+
if (isSubscriptionBetaRejection(response.status, errBody)) {
|
|
3135
|
+
// Subscription-specific beta rejection (an account whose plan tier lacks
|
|
3136
|
+
// an optional beta the proxy injected). The SAME request can succeed on
|
|
3137
|
+
// another account whose tier grants the beta — or on a fallback provider —
|
|
3138
|
+
// so advance to the next account instead of failing the client here.
|
|
3139
|
+
//
|
|
3140
|
+
// Deliberately do NOT store this in `currentInvalidRequestFailure`: that
|
|
3141
|
+
// field is a deterministic "malformed request" signal that both
|
|
3142
|
+
// suppresses provider fallback (shouldAttemptClaudeFallback) and outranks
|
|
3143
|
+
// transient/rate-limit failures in the final response. A beta rejection is
|
|
3144
|
+
// neither terminal nor higher-priority — a later account's real 429/5xx
|
|
3145
|
+
// must still take precedence, and fallback must stay eligible. The reason
|
|
3146
|
+
// is carried in `lastError`, so if every account rejects the beta the
|
|
3147
|
+
// exhaustion response still explains why.
|
|
3148
|
+
logger.always(`[proxy] ← ${response.status} account=${account.label} beta unavailable for subscription; advancing to next account`);
|
|
3149
|
+
logAttempt(response.status, "invalid_request_error", summarizeErrorMessage(errBody));
|
|
3150
|
+
tracer?.setError("invalid_request_error", summarizeErrorMessage(errBody));
|
|
3151
|
+
tracer?.recordRetry(account.label, "beta_unavailable");
|
|
3152
|
+
// A tier's lack of a beta is stable, not transient — advance the
|
|
3153
|
+
// fill-first primary pointer (like the auth/rate-limit rotation paths) so
|
|
3154
|
+
// this account stops being retried first on every future request.
|
|
3155
|
+
advancePrimaryIfCurrent(account.key, enabledAccounts.length, orderedAccounts[0]?.key);
|
|
3156
|
+
currentLastError = summarizeErrorMessage(errBody);
|
|
3157
|
+
return {
|
|
3158
|
+
continueLoop: true,
|
|
3159
|
+
lastError: currentLastError,
|
|
3160
|
+
authFailureMessage: currentAuthFailureMessage,
|
|
3161
|
+
sawTransientFailure: currentSawTransientFailure,
|
|
3162
|
+
invalidRequestFailure: currentInvalidRequestFailure,
|
|
3163
|
+
upstreamSpan: undefined,
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3134
3166
|
logger.always(`[proxy] ← ${response.status} upstream invalid_request_error`);
|
|
3135
3167
|
logAttempt(response.status, "invalid_request_error", summarizeErrorMessage(errBody));
|
|
3136
3168
|
tracer?.setError("invalid_request_error", summarizeErrorMessage(errBody));
|
|
@@ -4613,6 +4645,29 @@ export function isInvalidRequestError(status, errBody) {
|
|
|
4613
4645
|
return (parsed.errorType === "invalid_request_error" ||
|
|
4614
4646
|
errBody.includes("invalid_request_error"));
|
|
4615
4647
|
}
|
|
4648
|
+
/**
|
|
4649
|
+
* A subscription-specific beta rejection. Anthropic returns
|
|
4650
|
+
* `400 invalid_request_error` with a message like
|
|
4651
|
+
* "The long context beta is not yet available for this subscription." when an
|
|
4652
|
+
* account's plan tier does not grant an optional beta the proxy injected (see
|
|
4653
|
+
* CLAUDE_CODE_OAUTH_BETAS in anthropicOAuth.ts). Unlike a genuinely malformed
|
|
4654
|
+
* request, the SAME request can succeed on a different account whose tier
|
|
4655
|
+
* grants the beta — so this must be treated as retryable on the next account
|
|
4656
|
+
* rather than a terminal client-facing 400.
|
|
4657
|
+
*/
|
|
4658
|
+
export function isSubscriptionBetaRejection(status, errBody) {
|
|
4659
|
+
if (status !== 400) {
|
|
4660
|
+
return false;
|
|
4661
|
+
}
|
|
4662
|
+
const parsed = parseClaudeErrorBody(errBody);
|
|
4663
|
+
if (parsed.errorType !== "invalid_request_error") {
|
|
4664
|
+
return false;
|
|
4665
|
+
}
|
|
4666
|
+
const message = (parsed.message ?? "").toLowerCase();
|
|
4667
|
+
return (message.includes("beta") &&
|
|
4668
|
+
message.includes("subscription") &&
|
|
4669
|
+
message.includes("available"));
|
|
4670
|
+
}
|
|
4616
4671
|
function normalizeClaudeRequestForAnthropic(body) {
|
|
4617
4672
|
return {
|
|
4618
4673
|
...body,
|
|
@@ -249,6 +249,17 @@ export declare function parseClaudeErrorBody(errBody: string): ParsedClaudeError
|
|
|
249
249
|
* Detect malformed request errors that should not trigger account/provider failover.
|
|
250
250
|
*/
|
|
251
251
|
export declare function isInvalidRequestError(status: number, errBody: string): boolean;
|
|
252
|
+
/**
|
|
253
|
+
* A subscription-specific beta rejection. Anthropic returns
|
|
254
|
+
* `400 invalid_request_error` with a message like
|
|
255
|
+
* "The long context beta is not yet available for this subscription." when an
|
|
256
|
+
* account's plan tier does not grant an optional beta the proxy injected (see
|
|
257
|
+
* CLAUDE_CODE_OAUTH_BETAS in anthropicOAuth.ts). Unlike a genuinely malformed
|
|
258
|
+
* request, the SAME request can succeed on a different account whose tier
|
|
259
|
+
* grants the beta — so this must be treated as retryable on the next account
|
|
260
|
+
* rather than a terminal client-facing 400.
|
|
261
|
+
*/
|
|
262
|
+
export declare function isSubscriptionBetaRejection(status: number, errBody: string): boolean;
|
|
252
263
|
/**
|
|
253
264
|
* Backward-compatible alias — delegates to the shared translation engine.
|
|
254
265
|
*/
|
|
@@ -3131,6 +3131,38 @@ async function handleAnthropicNonOkResponse(args) {
|
|
|
3131
3131
|
durationMs: Date.now() - fetchStartMs,
|
|
3132
3132
|
});
|
|
3133
3133
|
if (isInvalidRequestError(response.status, errBody)) {
|
|
3134
|
+
if (isSubscriptionBetaRejection(response.status, errBody)) {
|
|
3135
|
+
// Subscription-specific beta rejection (an account whose plan tier lacks
|
|
3136
|
+
// an optional beta the proxy injected). The SAME request can succeed on
|
|
3137
|
+
// another account whose tier grants the beta — or on a fallback provider —
|
|
3138
|
+
// so advance to the next account instead of failing the client here.
|
|
3139
|
+
//
|
|
3140
|
+
// Deliberately do NOT store this in `currentInvalidRequestFailure`: that
|
|
3141
|
+
// field is a deterministic "malformed request" signal that both
|
|
3142
|
+
// suppresses provider fallback (shouldAttemptClaudeFallback) and outranks
|
|
3143
|
+
// transient/rate-limit failures in the final response. A beta rejection is
|
|
3144
|
+
// neither terminal nor higher-priority — a later account's real 429/5xx
|
|
3145
|
+
// must still take precedence, and fallback must stay eligible. The reason
|
|
3146
|
+
// is carried in `lastError`, so if every account rejects the beta the
|
|
3147
|
+
// exhaustion response still explains why.
|
|
3148
|
+
logger.always(`[proxy] ← ${response.status} account=${account.label} beta unavailable for subscription; advancing to next account`);
|
|
3149
|
+
logAttempt(response.status, "invalid_request_error", summarizeErrorMessage(errBody));
|
|
3150
|
+
tracer?.setError("invalid_request_error", summarizeErrorMessage(errBody));
|
|
3151
|
+
tracer?.recordRetry(account.label, "beta_unavailable");
|
|
3152
|
+
// A tier's lack of a beta is stable, not transient — advance the
|
|
3153
|
+
// fill-first primary pointer (like the auth/rate-limit rotation paths) so
|
|
3154
|
+
// this account stops being retried first on every future request.
|
|
3155
|
+
advancePrimaryIfCurrent(account.key, enabledAccounts.length, orderedAccounts[0]?.key);
|
|
3156
|
+
currentLastError = summarizeErrorMessage(errBody);
|
|
3157
|
+
return {
|
|
3158
|
+
continueLoop: true,
|
|
3159
|
+
lastError: currentLastError,
|
|
3160
|
+
authFailureMessage: currentAuthFailureMessage,
|
|
3161
|
+
sawTransientFailure: currentSawTransientFailure,
|
|
3162
|
+
invalidRequestFailure: currentInvalidRequestFailure,
|
|
3163
|
+
upstreamSpan: undefined,
|
|
3164
|
+
};
|
|
3165
|
+
}
|
|
3134
3166
|
logger.always(`[proxy] ← ${response.status} upstream invalid_request_error`);
|
|
3135
3167
|
logAttempt(response.status, "invalid_request_error", summarizeErrorMessage(errBody));
|
|
3136
3168
|
tracer?.setError("invalid_request_error", summarizeErrorMessage(errBody));
|
|
@@ -4613,6 +4645,29 @@ export function isInvalidRequestError(status, errBody) {
|
|
|
4613
4645
|
return (parsed.errorType === "invalid_request_error" ||
|
|
4614
4646
|
errBody.includes("invalid_request_error"));
|
|
4615
4647
|
}
|
|
4648
|
+
/**
|
|
4649
|
+
* A subscription-specific beta rejection. Anthropic returns
|
|
4650
|
+
* `400 invalid_request_error` with a message like
|
|
4651
|
+
* "The long context beta is not yet available for this subscription." when an
|
|
4652
|
+
* account's plan tier does not grant an optional beta the proxy injected (see
|
|
4653
|
+
* CLAUDE_CODE_OAUTH_BETAS in anthropicOAuth.ts). Unlike a genuinely malformed
|
|
4654
|
+
* request, the SAME request can succeed on a different account whose tier
|
|
4655
|
+
* grants the beta — so this must be treated as retryable on the next account
|
|
4656
|
+
* rather than a terminal client-facing 400.
|
|
4657
|
+
*/
|
|
4658
|
+
export function isSubscriptionBetaRejection(status, errBody) {
|
|
4659
|
+
if (status !== 400) {
|
|
4660
|
+
return false;
|
|
4661
|
+
}
|
|
4662
|
+
const parsed = parseClaudeErrorBody(errBody);
|
|
4663
|
+
if (parsed.errorType !== "invalid_request_error") {
|
|
4664
|
+
return false;
|
|
4665
|
+
}
|
|
4666
|
+
const message = (parsed.message ?? "").toLowerCase();
|
|
4667
|
+
return (message.includes("beta") &&
|
|
4668
|
+
message.includes("subscription") &&
|
|
4669
|
+
message.includes("available"));
|
|
4670
|
+
}
|
|
4616
4671
|
function normalizeClaudeRequestForAnthropic(body) {
|
|
4617
4672
|
return {
|
|
4618
4673
|
...body,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.5.
|
|
3
|
+
"version": "10.5.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": {
|