@juspay/neurolink 12.9.6 → 12.10.0
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 +3 -3
- package/dist/artifacts/artifactBanking.d.ts +6 -2
- package/dist/artifacts/artifactBanking.js +9 -14
- package/dist/artifacts/artifactReader.d.ts +69 -0
- package/dist/artifacts/artifactReader.js +157 -0
- package/dist/artifacts/artifactStore.d.ts +7 -3
- package/dist/artifacts/artifactStore.js +10 -21
- package/dist/artifacts/artifactStoreFactory.d.ts +39 -0
- package/dist/artifacts/artifactStoreFactory.js +101 -0
- package/dist/artifacts/redisArtifactStore.d.ts +84 -0
- package/dist/artifacts/redisArtifactStore.js +270 -0
- package/dist/browser/neurolink.min.js +367 -371
- package/dist/index.d.ts +3 -0
- package/dist/index.js +7 -0
- package/dist/memory/memoryRetrievalTools.js +104 -35
- package/dist/neurolink.d.ts +45 -1
- package/dist/neurolink.js +128 -18
- package/dist/types/artifact.d.ts +124 -3
- package/dist/types/config.d.ts +7 -0
- package/dist/utils/redis.d.ts +15 -0
- package/dist/utils/redis.js +64 -6
- package/package.json +5 -5
package/dist/types/config.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { MCPToolRegistry } from "../mcp/toolRegistry.js";
|
|
|
6
6
|
import type { TaskManagerConfig } from "./task.js";
|
|
7
7
|
import type { HITLConfig } from "../types/hitl.js";
|
|
8
8
|
import type { ConversationMemoryConfig } from "./conversation.js";
|
|
9
|
+
import type { ArtifactStorageConfig } from "./artifact.js";
|
|
9
10
|
import type { ObservabilityConfig } from "./observability.js";
|
|
10
11
|
import type { AuthProvider, AuthProviderType, AuthProviderConfig, Auth0Config, ClerkConfig, FirebaseConfig, SupabaseConfig, WorkOSConfig, BetterAuthConfig, JWTConfig, OAuth2Config, CognitoConfig, KeycloakConfig, AuthenticatedContext } from "./auth.js";
|
|
11
12
|
import type { NeurolinkCredentials } from "./providers.js";
|
|
@@ -61,6 +62,12 @@ export type NeurolinkConstructorConfig = {
|
|
|
61
62
|
modelAliasConfig?: ModelAliasConfig;
|
|
62
63
|
/** MCP enhancement modules configuration (cache, router, batcher, annotations, middleware) */
|
|
63
64
|
mcp?: MCPEnhancementsConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Artifact storage: where externalized MCP tool outputs and banked payloads
|
|
67
|
+
* live. The backend follows `STORAGE_TYPE` exactly like conversation memory
|
|
68
|
+
* unless chosen here. See {@link ArtifactStorageConfig}.
|
|
69
|
+
*/
|
|
70
|
+
artifacts?: ArtifactStorageConfig;
|
|
64
71
|
/** Authentication provider configuration */
|
|
65
72
|
auth?: NeuroLinkAuthConfig;
|
|
66
73
|
/** TaskManager configuration (scheduled and self-running tasks) */
|
package/dist/utils/redis.d.ts
CHANGED
|
@@ -3,6 +3,21 @@
|
|
|
3
3
|
* Helper functions for Redis storage operations
|
|
4
4
|
*/
|
|
5
5
|
import type { ChatMessage, RedisClient, RedisConversationObject, RedisStorageConfig } from "../types/index.js";
|
|
6
|
+
/**
|
|
7
|
+
* Redact the userinfo of every `scheme://user:pass@host` in `text`.
|
|
8
|
+
*
|
|
9
|
+
* Deliberately not a regex. `/:\/\/[^@]+@/` and its relatives backtrack
|
|
10
|
+
* quadratically on input with many `://` and no `@` (CodeQL
|
|
11
|
+
* js/polynomial-redos), and the URL here can come straight from a caller —
|
|
12
|
+
* `RedisStorageConfig.url` reaches this through `RedisArtifactStore` and the
|
|
13
|
+
* conversation memory manager. One forward pass, every character visited a
|
|
14
|
+
* bounded number of times.
|
|
15
|
+
*
|
|
16
|
+
* Redacts everything before the LAST `@` of the authority, so a password
|
|
17
|
+
* containing `@` is still hidden. A URL with only a user name is redacted
|
|
18
|
+
* too; the old regexes let that through.
|
|
19
|
+
*/
|
|
20
|
+
export declare function redactUrlCredentials(text: string): string;
|
|
6
21
|
/**
|
|
7
22
|
* Get a pooled Redis connection. Multiple callers with the same host:port:db
|
|
8
23
|
* share a single connection, reducing connection count.
|
package/dist/utils/redis.js
CHANGED
|
@@ -6,17 +6,75 @@ import { randomUUID } from "crypto";
|
|
|
6
6
|
import { createClient } from "redis";
|
|
7
7
|
import { logger } from "./logger.js";
|
|
8
8
|
const SESSION_ONLY_PREFIX = "session-only:";
|
|
9
|
+
/** Characters that end the authority (`user:pass@host:port`) of a URL in text. */
|
|
10
|
+
const AUTHORITY_TERMINATORS = new Set(["/", "?", "#", " ", "\t", "\n", "\r"]);
|
|
11
|
+
/**
|
|
12
|
+
* Redact the userinfo of every `scheme://user:pass@host` in `text`.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately not a regex. `/:\/\/[^@]+@/` and its relatives backtrack
|
|
15
|
+
* quadratically on input with many `://` and no `@` (CodeQL
|
|
16
|
+
* js/polynomial-redos), and the URL here can come straight from a caller —
|
|
17
|
+
* `RedisStorageConfig.url` reaches this through `RedisArtifactStore` and the
|
|
18
|
+
* conversation memory manager. One forward pass, every character visited a
|
|
19
|
+
* bounded number of times.
|
|
20
|
+
*
|
|
21
|
+
* Redacts everything before the LAST `@` of the authority, so a password
|
|
22
|
+
* containing `@` is still hidden. A URL with only a user name is redacted
|
|
23
|
+
* too; the old regexes let that through.
|
|
24
|
+
*/
|
|
25
|
+
export function redactUrlCredentials(text) {
|
|
26
|
+
let out = "";
|
|
27
|
+
let cursor = 0;
|
|
28
|
+
for (;;) {
|
|
29
|
+
const schemeEnd = text.indexOf("://", cursor);
|
|
30
|
+
if (schemeEnd === -1) {
|
|
31
|
+
return out + text.slice(cursor);
|
|
32
|
+
}
|
|
33
|
+
const authorityStart = schemeEnd + 3;
|
|
34
|
+
let authorityEnd = authorityStart;
|
|
35
|
+
let lastAt = -1;
|
|
36
|
+
while (authorityEnd < text.length) {
|
|
37
|
+
const ch = text[authorityEnd];
|
|
38
|
+
if (AUTHORITY_TERMINATORS.has(ch)) {
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
if (ch === "@") {
|
|
42
|
+
lastAt = authorityEnd;
|
|
43
|
+
}
|
|
44
|
+
authorityEnd += 1;
|
|
45
|
+
}
|
|
46
|
+
if (lastAt === -1) {
|
|
47
|
+
out += text.slice(cursor, authorityEnd);
|
|
48
|
+
cursor = authorityEnd;
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
out += `${text.slice(cursor, authorityStart)}[redacted]@`;
|
|
52
|
+
cursor = lastAt + 1;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
9
56
|
// Connection pool - keyed by host:port:db
|
|
10
57
|
const connectionPool = new Map();
|
|
11
58
|
const pendingConnections = new Map();
|
|
59
|
+
/**
|
|
60
|
+
* One pool key per distinct connection. Shared by acquire AND release: they
|
|
61
|
+
* used to compute it separately, and the release side never knew about the
|
|
62
|
+
* `url:` form, so a URL-configured client was acquired under one key and
|
|
63
|
+
* "released" under another that did not exist — its reference count never
|
|
64
|
+
* dropped and the connection outlived every owner. Credentials never appear
|
|
65
|
+
* in the key; it is logged.
|
|
66
|
+
*/
|
|
67
|
+
function poolKeyFor(config) {
|
|
68
|
+
return config.url
|
|
69
|
+
? `url:${redactUrlCredentials(config.url)}`
|
|
70
|
+
: `${config.host}:${config.port}:${config.db}:${config.password ? "auth" : "noauth"}`;
|
|
71
|
+
}
|
|
12
72
|
/**
|
|
13
73
|
* Get a pooled Redis connection. Multiple callers with the same host:port:db
|
|
14
74
|
* share a single connection, reducing connection count.
|
|
15
75
|
*/
|
|
16
76
|
export async function getPooledRedisClient(config) {
|
|
17
|
-
const key = config
|
|
18
|
-
? `url:${config.url.replace(/:\/\/[^:]+:[^@]+@/, "://[redacted]@")}`
|
|
19
|
-
: `${config.host}:${config.port}:${config.db}:${config.password ? "auth" : "noauth"}`;
|
|
77
|
+
const key = poolKeyFor(config);
|
|
20
78
|
const existing = connectionPool.get(key);
|
|
21
79
|
if (existing && existing.client.isOpen) {
|
|
22
80
|
existing.refCount++;
|
|
@@ -77,7 +135,7 @@ export async function getPooledRedisClient(config) {
|
|
|
77
135
|
* Release a pooled Redis connection. Only closes when refCount reaches 0.
|
|
78
136
|
*/
|
|
79
137
|
export async function releasePooledRedisClient(config) {
|
|
80
|
-
const key =
|
|
138
|
+
const key = poolKeyFor(config);
|
|
81
139
|
const entry = connectionPool.get(key);
|
|
82
140
|
if (!entry) {
|
|
83
141
|
return;
|
|
@@ -140,7 +198,7 @@ export async function createRedisClient(config) {
|
|
|
140
198
|
// Create client with secured options
|
|
141
199
|
const client = createClient(clientOptions);
|
|
142
200
|
client.on("error", (err) => {
|
|
143
|
-
const sanitizedMessage = err.message
|
|
201
|
+
const sanitizedMessage = redactUrlCredentials(err.message);
|
|
144
202
|
logger.error("Redis client error", { error: sanitizedMessage });
|
|
145
203
|
});
|
|
146
204
|
client.on("connect", () => {
|
|
@@ -420,7 +478,7 @@ export function getNormalizedConfig(config) {
|
|
|
420
478
|
: 0;
|
|
421
479
|
}
|
|
422
480
|
catch (e) {
|
|
423
|
-
const sanitizedUrl = url
|
|
481
|
+
const sanitizedUrl = redactUrlCredentials(url);
|
|
424
482
|
logger.warn("[redisUtils] Failed to parse Redis URL, falling back to component-based connection", {
|
|
425
483
|
url: sanitizedUrl,
|
|
426
484
|
error: e instanceof Error ? e.message : String(e),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.10.0",
|
|
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": {
|
|
@@ -456,7 +456,7 @@
|
|
|
456
456
|
"exceljs": "^4.4.0",
|
|
457
457
|
"express": "^5.1.0",
|
|
458
458
|
"express-rate-limit": "^8.2.1",
|
|
459
|
-
"fastify": "^5.
|
|
459
|
+
"fastify": "^5.12.1",
|
|
460
460
|
"ffmpeg-static": "^5.3.0",
|
|
461
461
|
"fluent-ffmpeg": "^2.1.3",
|
|
462
462
|
"koa": "^3.1.1",
|
|
@@ -605,7 +605,7 @@
|
|
|
605
605
|
"@opentelemetry/sdk-trace-node": "^2.6.0",
|
|
606
606
|
"jws@<4.0.1": ">=4.0.1",
|
|
607
607
|
"tar@<7.5.8": ">=7.5.8",
|
|
608
|
-
"qs@<6.
|
|
608
|
+
"qs@<6.16.0": ">=6.16.0",
|
|
609
609
|
"minimatch@>=10.0.0 <10.2.3": ">=10.2.3",
|
|
610
610
|
"minimatch@>=9.0.0 <9.0.7": ">=9.0.7",
|
|
611
611
|
"typedoc>minimatch": ">=10.2.3",
|
|
@@ -622,7 +622,7 @@
|
|
|
622
622
|
"ajv@>=8.0.0 <8.18.0": ">=8.18.0",
|
|
623
623
|
"@grpc/grpc-js@<1.14.4": ">=1.14.4",
|
|
624
624
|
"@protobufjs/utf8@<1.1.1": ">=1.1.1",
|
|
625
|
-
"fast-uri@<3.1.
|
|
625
|
+
"fast-uri@<3.1.6": ">=3.1.6 <4",
|
|
626
626
|
"ip-address@<10.1.1": ">=10.1.1",
|
|
627
627
|
"basic-ftp@<5.2.2": ">=5.2.2",
|
|
628
628
|
"fast-xml-builder@<1.1.7": ">=1.1.7",
|
|
@@ -632,7 +632,7 @@
|
|
|
632
632
|
"undici@>=8.0.0": ">=7.24.0 <8.0.0",
|
|
633
633
|
"pdfjs-dist": "5.4.624",
|
|
634
634
|
"markdown-it@<14.2.0": ">=14.2.0",
|
|
635
|
-
"@xmldom/xmldom@<0.9.
|
|
635
|
+
"@xmldom/xmldom@<0.9.12": ">=0.9.12",
|
|
636
636
|
"protobufjs@<7.6.5": ">=7.6.5",
|
|
637
637
|
"brace-expansion@>=5.0.0 <5.0.9": ">=5.0.9",
|
|
638
638
|
"@opentelemetry/core@>=2.0.0 <2.8.0": ">=2.8.0"
|