@juspay/neurolink 10.8.0 → 10.8.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/cli/commands/proxyAnalyze.js +6 -0
- package/dist/lib/proxy/proxyAnalysis.js +22 -4
- package/dist/lib/types/cli.d.ts +1 -0
- package/dist/lib/types/proxy.d.ts +2 -0
- package/dist/proxy/proxyAnalysis.js +22 -4
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/proxy.d.ts +2 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
## [10.8.1](https://github.com/juspay/neurolink/compare/v10.8.0...v10.8.1) (2026-07-30)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
- **(proxy):** snapshot live log analysis ([1c975bd](https://github.com/juspay/neurolink/commit/1c975bd9fcf53230e593ffafc485ec15ef26eb5e))
|
|
6
|
+
|
|
1
7
|
## [10.8.0](https://github.com/juspay/neurolink/compare/v10.7.1...v10.8.0) (2026-07-30)
|
|
2
8
|
|
|
3
9
|
### Features
|
|
@@ -10,6 +10,7 @@ function printAnalysis(report) {
|
|
|
10
10
|
logger.always(chalk.bold.cyan("NeuroLink Proxy Analysis"));
|
|
11
11
|
logger.always(chalk.gray("=".repeat(50)));
|
|
12
12
|
logger.always(` Since: ${chalk.cyan(report.since)}`);
|
|
13
|
+
logger.always(` Until: ${chalk.cyan(report.until)}`);
|
|
13
14
|
logger.always(` Logs: ${chalk.cyan(report.logsDir)}`);
|
|
14
15
|
logger.always(` Files: ${report.files.requests} request, ${report.files.attempts} attempt, ${report.files.lifecycle} lifecycle, ${report.files.debug} debug`);
|
|
15
16
|
logger.always("");
|
|
@@ -133,6 +134,10 @@ export const proxyAnalyzeCommand = {
|
|
|
133
134
|
type: "string",
|
|
134
135
|
default: "24h",
|
|
135
136
|
description: "ISO timestamp or lookback such as 6h, 1d, or 1w",
|
|
137
|
+
})
|
|
138
|
+
.option("until", {
|
|
139
|
+
type: "string",
|
|
140
|
+
description: "ISO timestamp or lookback such as 6h, 1d, or 1w; defaults to analysis start time",
|
|
136
141
|
})
|
|
137
142
|
.option("format", {
|
|
138
143
|
type: "string",
|
|
@@ -152,6 +157,7 @@ export const proxyAnalyzeCommand = {
|
|
|
152
157
|
const report = await analyzeProxyLogs({
|
|
153
158
|
logsDir: argv.logsDir,
|
|
154
159
|
since: argv.since,
|
|
160
|
+
until: argv.until,
|
|
155
161
|
});
|
|
156
162
|
if (argv.format === "json") {
|
|
157
163
|
logger.always(JSON.stringify(report, null, 2));
|
|
@@ -212,6 +212,19 @@ function parseSince(value, nowMs) {
|
|
|
212
212
|
}
|
|
213
213
|
return parsed;
|
|
214
214
|
}
|
|
215
|
+
function parseUntil(value, nowMs) {
|
|
216
|
+
let parsed;
|
|
217
|
+
try {
|
|
218
|
+
parsed = parseSince(value, nowMs);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
throw new Error(`Invalid --until value "${value}". Use an ISO timestamp or a duration such as 6h, 1d, or 1w.`);
|
|
222
|
+
}
|
|
223
|
+
if (parsed > nowMs) {
|
|
224
|
+
throw new Error(`Invalid --until value "${value}". It must not be later than the analysis start time.`);
|
|
225
|
+
}
|
|
226
|
+
return parsed;
|
|
227
|
+
}
|
|
215
228
|
async function readJsonLines(filePath, onRecord, onMalformed) {
|
|
216
229
|
let linesRead = 0;
|
|
217
230
|
const lines = createInterface({
|
|
@@ -412,6 +425,10 @@ async function discoverLogFiles(logsDir) {
|
|
|
412
425
|
export async function analyzeProxyLogs(options) {
|
|
413
426
|
const nowMs = options?.nowMs ?? Date.now();
|
|
414
427
|
const sinceMs = parseSince(options?.since ?? "24h", nowMs);
|
|
428
|
+
const untilMs = options?.until ? parseUntil(options.until, nowMs) : nowMs;
|
|
429
|
+
if (untilMs < sinceMs) {
|
|
430
|
+
throw new Error(`Invalid analysis window: --until must not be earlier than --since.`);
|
|
431
|
+
}
|
|
415
432
|
const logsDir = resolve(options?.logsDir ?? join(homedir(), ".neurolink", "logs"));
|
|
416
433
|
const { lifecycleFiles, requestFiles, attemptFiles, debugFiles } = await discoverLogFiles(logsDir);
|
|
417
434
|
const observedRanges = {
|
|
@@ -448,7 +465,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
448
465
|
for (const filePath of lifecycleFiles) {
|
|
449
466
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
450
467
|
const timestamp = observeTimestamp("lifecycle", record);
|
|
451
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
468
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
452
469
|
return;
|
|
453
470
|
}
|
|
454
471
|
const event = stringValue(record.event);
|
|
@@ -530,7 +547,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
530
547
|
for (const filePath of attemptFiles) {
|
|
531
548
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
532
549
|
const timestamp = observeTimestamp("attempts", record);
|
|
533
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
550
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
534
551
|
return;
|
|
535
552
|
}
|
|
536
553
|
const requestId = stringValue(record.requestId);
|
|
@@ -595,7 +612,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
595
612
|
for (const filePath of requestFiles) {
|
|
596
613
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
597
614
|
const timestamp = observeTimestamp("requests", record);
|
|
598
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
615
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
599
616
|
return;
|
|
600
617
|
}
|
|
601
618
|
const requestId = stringValue(record.requestId);
|
|
@@ -649,7 +666,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
649
666
|
for (const filePath of debugFiles) {
|
|
650
667
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
651
668
|
const timestamp = observeTimestamp("debug", record);
|
|
652
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
669
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
653
670
|
return;
|
|
654
671
|
}
|
|
655
672
|
if (record.type !== "body_capture") {
|
|
@@ -709,6 +726,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
709
726
|
return {
|
|
710
727
|
generatedAt: new Date(nowMs).toISOString(),
|
|
711
728
|
since: new Date(sinceMs).toISOString(),
|
|
729
|
+
until: new Date(untilMs).toISOString(),
|
|
712
730
|
logsDir,
|
|
713
731
|
files: {
|
|
714
732
|
lifecycle: lifecycleFiles.length,
|
package/dist/lib/types/cli.d.ts
CHANGED
|
@@ -1247,6 +1247,7 @@ export type ProxyAnalysisStreamName = "lifecycle" | "requests" | "attempts" | "d
|
|
|
1247
1247
|
export type ProxyAnalysisReport = {
|
|
1248
1248
|
generatedAt: string;
|
|
1249
1249
|
since: string;
|
|
1250
|
+
until: string;
|
|
1250
1251
|
logsDir: string;
|
|
1251
1252
|
files: {
|
|
1252
1253
|
lifecycle: number;
|
|
@@ -1352,6 +1353,7 @@ export type ProxyAnalysisReport = {
|
|
|
1352
1353
|
export type ProxyAnalysisOptions = {
|
|
1353
1354
|
logsDir?: string;
|
|
1354
1355
|
since?: string;
|
|
1356
|
+
until?: string;
|
|
1355
1357
|
nowMs?: number;
|
|
1356
1358
|
};
|
|
1357
1359
|
/** Attempt timing retained while joining offline proxy log records. */
|
|
@@ -212,6 +212,19 @@ function parseSince(value, nowMs) {
|
|
|
212
212
|
}
|
|
213
213
|
return parsed;
|
|
214
214
|
}
|
|
215
|
+
function parseUntil(value, nowMs) {
|
|
216
|
+
let parsed;
|
|
217
|
+
try {
|
|
218
|
+
parsed = parseSince(value, nowMs);
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
throw new Error(`Invalid --until value "${value}". Use an ISO timestamp or a duration such as 6h, 1d, or 1w.`);
|
|
222
|
+
}
|
|
223
|
+
if (parsed > nowMs) {
|
|
224
|
+
throw new Error(`Invalid --until value "${value}". It must not be later than the analysis start time.`);
|
|
225
|
+
}
|
|
226
|
+
return parsed;
|
|
227
|
+
}
|
|
215
228
|
async function readJsonLines(filePath, onRecord, onMalformed) {
|
|
216
229
|
let linesRead = 0;
|
|
217
230
|
const lines = createInterface({
|
|
@@ -412,6 +425,10 @@ async function discoverLogFiles(logsDir) {
|
|
|
412
425
|
export async function analyzeProxyLogs(options) {
|
|
413
426
|
const nowMs = options?.nowMs ?? Date.now();
|
|
414
427
|
const sinceMs = parseSince(options?.since ?? "24h", nowMs);
|
|
428
|
+
const untilMs = options?.until ? parseUntil(options.until, nowMs) : nowMs;
|
|
429
|
+
if (untilMs < sinceMs) {
|
|
430
|
+
throw new Error(`Invalid analysis window: --until must not be earlier than --since.`);
|
|
431
|
+
}
|
|
415
432
|
const logsDir = resolve(options?.logsDir ?? join(homedir(), ".neurolink", "logs"));
|
|
416
433
|
const { lifecycleFiles, requestFiles, attemptFiles, debugFiles } = await discoverLogFiles(logsDir);
|
|
417
434
|
const observedRanges = {
|
|
@@ -448,7 +465,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
448
465
|
for (const filePath of lifecycleFiles) {
|
|
449
466
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
450
467
|
const timestamp = observeTimestamp("lifecycle", record);
|
|
451
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
468
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
452
469
|
return;
|
|
453
470
|
}
|
|
454
471
|
const event = stringValue(record.event);
|
|
@@ -530,7 +547,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
530
547
|
for (const filePath of attemptFiles) {
|
|
531
548
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
532
549
|
const timestamp = observeTimestamp("attempts", record);
|
|
533
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
550
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
534
551
|
return;
|
|
535
552
|
}
|
|
536
553
|
const requestId = stringValue(record.requestId);
|
|
@@ -595,7 +612,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
595
612
|
for (const filePath of requestFiles) {
|
|
596
613
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
597
614
|
const timestamp = observeTimestamp("requests", record);
|
|
598
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
615
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
599
616
|
return;
|
|
600
617
|
}
|
|
601
618
|
const requestId = stringValue(record.requestId);
|
|
@@ -649,7 +666,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
649
666
|
for (const filePath of debugFiles) {
|
|
650
667
|
linesRead += await readJsonLines(filePath, (record) => {
|
|
651
668
|
const timestamp = observeTimestamp("debug", record);
|
|
652
|
-
if (timestamp === null || timestamp < sinceMs) {
|
|
669
|
+
if (timestamp === null || timestamp < sinceMs || timestamp > untilMs) {
|
|
653
670
|
return;
|
|
654
671
|
}
|
|
655
672
|
if (record.type !== "body_capture") {
|
|
@@ -709,6 +726,7 @@ export async function analyzeProxyLogs(options) {
|
|
|
709
726
|
return {
|
|
710
727
|
generatedAt: new Date(nowMs).toISOString(),
|
|
711
728
|
since: new Date(sinceMs).toISOString(),
|
|
729
|
+
until: new Date(untilMs).toISOString(),
|
|
712
730
|
logsDir,
|
|
713
731
|
files: {
|
|
714
732
|
lifecycle: lifecycleFiles.length,
|
package/dist/types/cli.d.ts
CHANGED
package/dist/types/proxy.d.ts
CHANGED
|
@@ -1247,6 +1247,7 @@ export type ProxyAnalysisStreamName = "lifecycle" | "requests" | "attempts" | "d
|
|
|
1247
1247
|
export type ProxyAnalysisReport = {
|
|
1248
1248
|
generatedAt: string;
|
|
1249
1249
|
since: string;
|
|
1250
|
+
until: string;
|
|
1250
1251
|
logsDir: string;
|
|
1251
1252
|
files: {
|
|
1252
1253
|
lifecycle: number;
|
|
@@ -1352,6 +1353,7 @@ export type ProxyAnalysisReport = {
|
|
|
1352
1353
|
export type ProxyAnalysisOptions = {
|
|
1353
1354
|
logsDir?: string;
|
|
1354
1355
|
since?: string;
|
|
1356
|
+
until?: string;
|
|
1355
1357
|
nowMs?: number;
|
|
1356
1358
|
};
|
|
1357
1359
|
/** Attempt timing retained while joining offline proxy log records. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.8.
|
|
3
|
+
"version": "10.8.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": {
|