@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 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,
@@ -795,6 +795,7 @@ export type ProxyStatusArgs = {
795
795
  export type ProxyAnalyzeArgs = {
796
796
  logsDir?: string;
797
797
  since?: string;
798
+ until?: string;
798
799
  format?: "text" | "json";
799
800
  quiet?: boolean;
800
801
  };
@@ -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,
@@ -795,6 +795,7 @@ export type ProxyStatusArgs = {
795
795
  export type ProxyAnalyzeArgs = {
796
796
  logsDir?: string;
797
797
  since?: string;
798
+ until?: string;
798
799
  format?: "text" | "json";
799
800
  quiet?: boolean;
800
801
  };
@@ -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.0",
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": {