@juspay/neurolink 11.29.1 → 11.29.2

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.
@@ -2176,11 +2176,16 @@ export class BaseProvider {
2176
2176
  // shared timeout helper so standard video gen honors the caller's
2177
2177
  // timeout the same way director mode does (see above ~Line 2062).
2178
2178
  const videoTimeout = options.timeout ?? 600_000; // 10 min default
2179
+ // Thread the caller's cancellation signal into the handler chain —
2180
+ // output.video.abortSignal (video-scoped) wins over the request-level
2181
+ // options.abortSignal, matching the general per-field precedence.
2182
+ const videoAbortSignal = options.output?.video?.abortSignal ?? options.abortSignal;
2179
2183
  const videoResult = await this.executeWithTimeout(() => VideoProcessor.generate(requestedProvider, {
2180
2184
  ...(options.output?.video ?? {}),
2181
2185
  image: imageBuffer,
2182
2186
  prompt,
2183
2187
  region: options.region,
2188
+ abortSignal: videoAbortSignal,
2184
2189
  }), { timeout: videoTimeout, operationType: "generate" });
2185
2190
  // Prefer the handler's own model id (more accurate — it knows the exact
2186
2191
  // checkpoint that ran). Fall back to the request-time value, and finally
@@ -34,6 +34,11 @@ export type VideoGenerateOptions = VideoOutputOptions & {
34
34
  * `generateTransition` method on `VideoHandler`.
35
35
  */
36
36
  export type VideoTransitionOptions = {
37
+ /**
38
+ * Per-call cancellation signal forwarded to provider requests and polling
39
+ * loops — same contract as `VideoOutputOptions.abortSignal`.
40
+ */
41
+ abortSignal?: AbortSignal;
37
42
  aspectRatio?: "9:16" | "16:9" | "1:1" | string;
38
43
  resolution?: "720p" | "1080p";
39
44
  audio?: boolean;
@@ -84,6 +84,16 @@ export class VideoProcessor {
84
84
  }
85
85
  : optionsOrImage;
86
86
  const { image, prompt, region, ...videoOptions } = bag;
87
+ // A fired timeout must also cancel the handler's own request/polling
88
+ // loop — otherwise the caller sees the rejection while a ghost
89
+ // generation keeps polling (and possibly billing) for the rest of the
90
+ // render. Chain the internal controller onto any caller-supplied
91
+ // signal so both cancellation sources reach the handler.
92
+ const timeoutAbort = new AbortController();
93
+ const abortSignal = videoOptions.abortSignal
94
+ ? AbortSignal.any([videoOptions.abortSignal, timeoutAbort.signal])
95
+ : timeoutAbort.signal;
96
+ const handlerOptions = { ...videoOptions, abortSignal };
87
97
  const span = SpanSerializer.createSpan(SpanType.MEDIA_GENERATION, "video.generate", this.buildSpanAttributes(provider, videoOptions));
88
98
  try {
89
99
  const handler = this.getHandler(provider);
@@ -111,13 +121,17 @@ export class VideoProcessor {
111
121
  // Bounded per repo guideline (async provider calls wrap withTimeout):
112
122
  // video generation is legitimately slow, so the deadline is generous —
113
123
  // but a wedged handler must error, never hang the caller forever.
114
- const result = await withTimeout(handler.generate(image, prompt, videoOptions, region), VIDEO_GENERATION_TIMEOUT_MS, `Video generation via "${provider}" timed out after ${VIDEO_GENERATION_TIMEOUT_MS}ms`);
124
+ const result = await withTimeout(handler.generate(image, prompt, handlerOptions, region), VIDEO_GENERATION_TIMEOUT_MS, `Video generation via "${provider}" timed out after ${VIDEO_GENERATION_TIMEOUT_MS}ms`);
115
125
  const ended = SpanSerializer.endSpan(span, SpanStatus.OK);
116
126
  getMetricsAggregator().recordSpan(ended);
117
127
  logger.info(`[VideoProcessor] Generated ${result.data.length} bytes (${provider})`);
118
128
  return result;
119
129
  }
120
130
  catch (err) {
131
+ // Cancel the ghost: on timeout the handler promise is still pending;
132
+ // aborting here stops its polling loop. On handler-originated errors
133
+ // the promise has already settled, so the abort is a no-op.
134
+ timeoutAbort.abort();
121
135
  const ended = SpanSerializer.endSpan(span, SpanStatus.ERROR, err instanceof Error ? err.message : String(err));
122
136
  getMetricsAggregator().recordSpan(ended);
123
137
  if (err instanceof VideoError) {
@@ -174,11 +188,22 @@ export class VideoProcessor {
174
188
  context: { provider },
175
189
  });
176
190
  }
191
+ // Same ghost-cancellation contract as generate(): a fired timeout
192
+ // aborts the handler's polling loop, chained onto any caller signal.
193
+ const timeoutAbort = new AbortController();
194
+ const abortSignal = options?.abortSignal
195
+ ? AbortSignal.any([options.abortSignal, timeoutAbort.signal])
196
+ : timeoutAbort.signal;
197
+ const handlerOptions = {
198
+ ...(options ?? {}),
199
+ abortSignal,
200
+ };
177
201
  try {
178
202
  // Same bound as generate(): a wedged transition must error, not hang.
179
- return await withTimeout(handler.generateTransition(firstFrame, lastFrame, prompt, options, region), VIDEO_GENERATION_TIMEOUT_MS, `Video transition via "${provider}" timed out after ${VIDEO_GENERATION_TIMEOUT_MS}ms`);
203
+ return await withTimeout(handler.generateTransition(firstFrame, lastFrame, prompt, handlerOptions, region), VIDEO_GENERATION_TIMEOUT_MS, `Video transition via "${provider}" timed out after ${VIDEO_GENERATION_TIMEOUT_MS}ms`);
180
204
  }
181
205
  catch (err) {
206
+ timeoutAbort.abort();
182
207
  if (err instanceof VideoError) {
183
208
  throw err;
184
209
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "11.29.1",
3
+ "version": "11.29.2",
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": {
@@ -114,6 +114,7 @@
114
114
  "test:skills": "pnpm exec tsx test/continuous-test-suite-skills.ts",
115
115
  "test:servers": "pnpm exec tsx test/continuous-test-suite-servers.ts",
116
116
  "test:tool-reliability": "pnpm exec tsx test/continuous-test-suite-tool-reliability.ts",
117
+ "test:video-abort": "pnpm exec tsx test/continuous-test-suite-video-abort.ts",
117
118
  "test:tts": "pnpm exec tsx test/continuous-test-suite-tts.ts",
118
119
  "test:tts:unit": "pnpm exec tsx test/continuous-test-suite-tts-unit.ts",
119
120
  "test:stt:unit": "pnpm exec tsx test/continuous-test-suite-stt-unit.ts",