@juspay/neurolink 10.8.7 → 10.8.8
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 +372 -372
- package/dist/lib/processors/media/AudioProcessor.d.ts +5 -6
- package/dist/lib/processors/media/AudioProcessor.js +8 -18
- package/dist/lib/processors/media/VideoProcessor.d.ts +5 -0
- package/dist/lib/processors/media/VideoProcessor.js +8 -18
- package/dist/lib/utils/mediaDuration.d.ts +23 -0
- package/dist/lib/utils/mediaDuration.js +45 -0
- package/dist/processors/media/AudioProcessor.d.ts +5 -6
- package/dist/processors/media/AudioProcessor.js +8 -18
- package/dist/processors/media/VideoProcessor.d.ts +5 -0
- package/dist/processors/media/VideoProcessor.js +8 -18
- package/dist/utils/mediaDuration.d.ts +23 -0
- package/dist/utils/mediaDuration.js +44 -0
- package/package.json +1 -1
|
@@ -179,13 +179,12 @@ export declare class AudioProcessor extends BaseFileProcessor<ProcessedAudio> {
|
|
|
179
179
|
/**
|
|
180
180
|
* Format a duration in seconds to a human-readable string.
|
|
181
181
|
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
182
|
+
* Delegates to the shared formatter so audio and video describe the same
|
|
183
|
+
* file the same way — this used to render "0:02" where VideoProcessor
|
|
184
|
+
* rendered "2s".
|
|
184
185
|
*
|
|
185
|
-
* @
|
|
186
|
-
*
|
|
187
|
-
* formatDuration(3750) // "1:02:30"
|
|
188
|
-
* formatDuration(0) // "0:00"
|
|
186
|
+
* @param seconds - Duration in seconds
|
|
187
|
+
* @returns Formatted string: "45s", "3m 45s", "1h 2m 30s"
|
|
189
188
|
*/
|
|
190
189
|
private formatDuration;
|
|
191
190
|
/**
|
|
@@ -40,6 +40,7 @@ import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
|
40
40
|
import { SIZE_LIMITS_MB } from "../config/index.js";
|
|
41
41
|
import { FileErrorCode } from "../errors/index.js";
|
|
42
42
|
import { withTimeout } from "../../utils/timeout.js";
|
|
43
|
+
import { formatMediaDuration } from "../../utils/mediaDuration.js";
|
|
43
44
|
let _musicMetadata = null;
|
|
44
45
|
async function loadMusicMetadata() {
|
|
45
46
|
if (_musicMetadata) {
|
|
@@ -397,7 +398,7 @@ export class AudioProcessor extends BaseFileProcessor {
|
|
|
397
398
|
textContent: "",
|
|
398
399
|
metadata: {
|
|
399
400
|
duration: 0,
|
|
400
|
-
durationFormatted:
|
|
401
|
+
durationFormatted: formatMediaDuration(0),
|
|
401
402
|
codec: "unknown",
|
|
402
403
|
lossless: false,
|
|
403
404
|
fileSize: buffer.length,
|
|
@@ -608,26 +609,15 @@ export class AudioProcessor extends BaseFileProcessor {
|
|
|
608
609
|
/**
|
|
609
610
|
* Format a duration in seconds to a human-readable string.
|
|
610
611
|
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
612
|
+
* Delegates to the shared formatter so audio and video describe the same
|
|
613
|
+
* file the same way — this used to render "0:02" where VideoProcessor
|
|
614
|
+
* rendered "2s".
|
|
613
615
|
*
|
|
614
|
-
* @
|
|
615
|
-
*
|
|
616
|
-
* formatDuration(3750) // "1:02:30"
|
|
617
|
-
* formatDuration(0) // "0:00"
|
|
616
|
+
* @param seconds - Duration in seconds
|
|
617
|
+
* @returns Formatted string: "45s", "3m 45s", "1h 2m 30s"
|
|
618
618
|
*/
|
|
619
619
|
formatDuration(seconds) {
|
|
620
|
-
|
|
621
|
-
return "0:00";
|
|
622
|
-
}
|
|
623
|
-
const totalSeconds = Math.round(seconds);
|
|
624
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
625
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
626
|
-
const secs = totalSeconds % 60;
|
|
627
|
-
if (hours > 0) {
|
|
628
|
-
return `${hours}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
|
|
629
|
-
}
|
|
630
|
-
return `${minutes}:${String(secs).padStart(2, "0")}`;
|
|
620
|
+
return formatMediaDuration(seconds);
|
|
631
621
|
}
|
|
632
622
|
/**
|
|
633
623
|
* Format bitrate to a human-readable string.
|
|
@@ -205,6 +205,11 @@ export declare class VideoProcessor extends BaseFileProcessor<ProcessedVideo> {
|
|
|
205
205
|
/**
|
|
206
206
|
* Format a duration in seconds to a human-readable string.
|
|
207
207
|
*
|
|
208
|
+
* Delegates to the shared formatter so audio and video agree — see
|
|
209
|
+
* `formatMediaDuration`. Rounding replaces the previous truncation, so a
|
|
210
|
+
* 2.6s clip now reads "3s" rather than "2s" and matches what the audio
|
|
211
|
+
* side reports for the same stream.
|
|
212
|
+
*
|
|
208
213
|
* @param seconds - Duration in seconds
|
|
209
214
|
* @returns Formatted string (e.g., "1h 23m 45s")
|
|
210
215
|
*/
|
|
@@ -50,6 +50,7 @@ import { join } from "path";
|
|
|
50
50
|
import { Readable } from "stream";
|
|
51
51
|
import { pipeline } from "stream/promises";
|
|
52
52
|
import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
53
|
+
import { formatMediaDuration } from "../../utils/mediaDuration.js";
|
|
53
54
|
import { SIZE_LIMITS_MB } from "../config/index.js";
|
|
54
55
|
import { FileErrorCode } from "../errors/index.js";
|
|
55
56
|
import { tracers, ATTR, withSpan } from "../../telemetry/index.js";
|
|
@@ -270,7 +271,7 @@ export class VideoProcessor extends BaseFileProcessor {
|
|
|
270
271
|
keyframes: [],
|
|
271
272
|
metadata: {
|
|
272
273
|
duration: 0,
|
|
273
|
-
durationFormatted:
|
|
274
|
+
durationFormatted: formatMediaDuration(0),
|
|
274
275
|
width: 0,
|
|
275
276
|
height: 0,
|
|
276
277
|
codec: "unknown",
|
|
@@ -908,27 +909,16 @@ export class VideoProcessor extends BaseFileProcessor {
|
|
|
908
909
|
/**
|
|
909
910
|
* Format a duration in seconds to a human-readable string.
|
|
910
911
|
*
|
|
912
|
+
* Delegates to the shared formatter so audio and video agree — see
|
|
913
|
+
* `formatMediaDuration`. Rounding replaces the previous truncation, so a
|
|
914
|
+
* 2.6s clip now reads "3s" rather than "2s" and matches what the audio
|
|
915
|
+
* side reports for the same stream.
|
|
916
|
+
*
|
|
911
917
|
* @param seconds - Duration in seconds
|
|
912
918
|
* @returns Formatted string (e.g., "1h 23m 45s")
|
|
913
919
|
*/
|
|
914
920
|
formatDuration(seconds) {
|
|
915
|
-
|
|
916
|
-
return "0s";
|
|
917
|
-
}
|
|
918
|
-
const hours = Math.floor(seconds / 3600);
|
|
919
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
920
|
-
const secs = Math.floor(seconds % 60);
|
|
921
|
-
const parts = [];
|
|
922
|
-
if (hours > 0) {
|
|
923
|
-
parts.push(`${hours}h`);
|
|
924
|
-
}
|
|
925
|
-
if (minutes > 0) {
|
|
926
|
-
parts.push(`${minutes}m`);
|
|
927
|
-
}
|
|
928
|
-
if (secs > 0 || parts.length === 0) {
|
|
929
|
-
parts.push(`${secs}s`);
|
|
930
|
-
}
|
|
931
|
-
return parts.join(" ");
|
|
921
|
+
return formatMediaDuration(seconds);
|
|
932
922
|
}
|
|
933
923
|
/**
|
|
934
924
|
* Get a file extension from FileInfo, falling back to ".mp4".
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared duration formatting for the media processors.
|
|
3
|
+
*
|
|
4
|
+
* AudioProcessor and VideoProcessor each carried their own private
|
|
5
|
+
* `formatDuration`, and they disagreed: the same two-second file rendered as
|
|
6
|
+
* "0:02" from audio and "2s" from video, and a zero duration as "0:00" versus
|
|
7
|
+
* "0s". Both strings land in the `textContent` handed to the model, often in
|
|
8
|
+
* the same request when a video's muxed audio is described alongside it, so
|
|
9
|
+
* the mismatch reads as two different facts about one file.
|
|
10
|
+
*
|
|
11
|
+
* The explicit-unit form wins over the "m:ss" clock form because these strings
|
|
12
|
+
* are consumed by a language model, not rendered in a player scrubber: "1m 30s"
|
|
13
|
+
* has exactly one reading, while "1:30" is ambiguous between 1m30s and 1h30m
|
|
14
|
+
* and has to be disambiguated from context that may not be present.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Format a duration in seconds as explicit units — "45s", "1m 30s", "1h 2m 3s".
|
|
18
|
+
*
|
|
19
|
+
* Non-finite, negative and zero durations all render as "0s": callers reach
|
|
20
|
+
* this with a probe failure or a stream that reports no duration, and a
|
|
21
|
+
* fabricated number would be worse than an obvious zero.
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatMediaDuration(seconds: number): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared duration formatting for the media processors.
|
|
3
|
+
*
|
|
4
|
+
* AudioProcessor and VideoProcessor each carried their own private
|
|
5
|
+
* `formatDuration`, and they disagreed: the same two-second file rendered as
|
|
6
|
+
* "0:02" from audio and "2s" from video, and a zero duration as "0:00" versus
|
|
7
|
+
* "0s". Both strings land in the `textContent` handed to the model, often in
|
|
8
|
+
* the same request when a video's muxed audio is described alongside it, so
|
|
9
|
+
* the mismatch reads as two different facts about one file.
|
|
10
|
+
*
|
|
11
|
+
* The explicit-unit form wins over the "m:ss" clock form because these strings
|
|
12
|
+
* are consumed by a language model, not rendered in a player scrubber: "1m 30s"
|
|
13
|
+
* has exactly one reading, while "1:30" is ambiguous between 1m30s and 1h30m
|
|
14
|
+
* and has to be disambiguated from context that may not be present.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Format a duration in seconds as explicit units — "45s", "1m 30s", "1h 2m 3s".
|
|
18
|
+
*
|
|
19
|
+
* Non-finite, negative and zero durations all render as "0s": callers reach
|
|
20
|
+
* this with a probe failure or a stream that reports no duration, and a
|
|
21
|
+
* fabricated number would be worse than an obvious zero.
|
|
22
|
+
*/
|
|
23
|
+
export function formatMediaDuration(seconds) {
|
|
24
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
25
|
+
return "0s";
|
|
26
|
+
}
|
|
27
|
+
const total = Math.round(seconds);
|
|
28
|
+
const hours = Math.floor(total / 3600);
|
|
29
|
+
const minutes = Math.floor((total % 3600) / 60);
|
|
30
|
+
const secs = total % 60;
|
|
31
|
+
const parts = [];
|
|
32
|
+
if (hours > 0) {
|
|
33
|
+
parts.push(`${hours}h`);
|
|
34
|
+
}
|
|
35
|
+
if (minutes > 0) {
|
|
36
|
+
parts.push(`${minutes}m`);
|
|
37
|
+
}
|
|
38
|
+
// Keep the seconds term when it is the only one, so sub-minute durations
|
|
39
|
+
// never render as an empty string.
|
|
40
|
+
if (secs > 0 || parts.length === 0) {
|
|
41
|
+
parts.push(`${secs}s`);
|
|
42
|
+
}
|
|
43
|
+
return parts.join(" ");
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=mediaDuration.js.map
|
|
@@ -179,13 +179,12 @@ export declare class AudioProcessor extends BaseFileProcessor<ProcessedAudio> {
|
|
|
179
179
|
/**
|
|
180
180
|
* Format a duration in seconds to a human-readable string.
|
|
181
181
|
*
|
|
182
|
-
*
|
|
183
|
-
*
|
|
182
|
+
* Delegates to the shared formatter so audio and video describe the same
|
|
183
|
+
* file the same way — this used to render "0:02" where VideoProcessor
|
|
184
|
+
* rendered "2s".
|
|
184
185
|
*
|
|
185
|
-
* @
|
|
186
|
-
*
|
|
187
|
-
* formatDuration(3750) // "1:02:30"
|
|
188
|
-
* formatDuration(0) // "0:00"
|
|
186
|
+
* @param seconds - Duration in seconds
|
|
187
|
+
* @returns Formatted string: "45s", "3m 45s", "1h 2m 30s"
|
|
189
188
|
*/
|
|
190
189
|
private formatDuration;
|
|
191
190
|
/**
|
|
@@ -40,6 +40,7 @@ import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
|
40
40
|
import { SIZE_LIMITS_MB } from "../config/index.js";
|
|
41
41
|
import { FileErrorCode } from "../errors/index.js";
|
|
42
42
|
import { withTimeout } from "../../utils/timeout.js";
|
|
43
|
+
import { formatMediaDuration } from "../../utils/mediaDuration.js";
|
|
43
44
|
let _musicMetadata = null;
|
|
44
45
|
async function loadMusicMetadata() {
|
|
45
46
|
if (_musicMetadata) {
|
|
@@ -397,7 +398,7 @@ export class AudioProcessor extends BaseFileProcessor {
|
|
|
397
398
|
textContent: "",
|
|
398
399
|
metadata: {
|
|
399
400
|
duration: 0,
|
|
400
|
-
durationFormatted:
|
|
401
|
+
durationFormatted: formatMediaDuration(0),
|
|
401
402
|
codec: "unknown",
|
|
402
403
|
lossless: false,
|
|
403
404
|
fileSize: buffer.length,
|
|
@@ -608,26 +609,15 @@ export class AudioProcessor extends BaseFileProcessor {
|
|
|
608
609
|
/**
|
|
609
610
|
* Format a duration in seconds to a human-readable string.
|
|
610
611
|
*
|
|
611
|
-
*
|
|
612
|
-
*
|
|
612
|
+
* Delegates to the shared formatter so audio and video describe the same
|
|
613
|
+
* file the same way — this used to render "0:02" where VideoProcessor
|
|
614
|
+
* rendered "2s".
|
|
613
615
|
*
|
|
614
|
-
* @
|
|
615
|
-
*
|
|
616
|
-
* formatDuration(3750) // "1:02:30"
|
|
617
|
-
* formatDuration(0) // "0:00"
|
|
616
|
+
* @param seconds - Duration in seconds
|
|
617
|
+
* @returns Formatted string: "45s", "3m 45s", "1h 2m 30s"
|
|
618
618
|
*/
|
|
619
619
|
formatDuration(seconds) {
|
|
620
|
-
|
|
621
|
-
return "0:00";
|
|
622
|
-
}
|
|
623
|
-
const totalSeconds = Math.round(seconds);
|
|
624
|
-
const hours = Math.floor(totalSeconds / 3600);
|
|
625
|
-
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
626
|
-
const secs = totalSeconds % 60;
|
|
627
|
-
if (hours > 0) {
|
|
628
|
-
return `${hours}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
|
|
629
|
-
}
|
|
630
|
-
return `${minutes}:${String(secs).padStart(2, "0")}`;
|
|
620
|
+
return formatMediaDuration(seconds);
|
|
631
621
|
}
|
|
632
622
|
/**
|
|
633
623
|
* Format bitrate to a human-readable string.
|
|
@@ -205,6 +205,11 @@ export declare class VideoProcessor extends BaseFileProcessor<ProcessedVideo> {
|
|
|
205
205
|
/**
|
|
206
206
|
* Format a duration in seconds to a human-readable string.
|
|
207
207
|
*
|
|
208
|
+
* Delegates to the shared formatter so audio and video agree — see
|
|
209
|
+
* `formatMediaDuration`. Rounding replaces the previous truncation, so a
|
|
210
|
+
* 2.6s clip now reads "3s" rather than "2s" and matches what the audio
|
|
211
|
+
* side reports for the same stream.
|
|
212
|
+
*
|
|
208
213
|
* @param seconds - Duration in seconds
|
|
209
214
|
* @returns Formatted string (e.g., "1h 23m 45s")
|
|
210
215
|
*/
|
|
@@ -50,6 +50,7 @@ import { join } from "path";
|
|
|
50
50
|
import { Readable } from "stream";
|
|
51
51
|
import { pipeline } from "stream/promises";
|
|
52
52
|
import { BaseFileProcessor } from "../base/BaseFileProcessor.js";
|
|
53
|
+
import { formatMediaDuration } from "../../utils/mediaDuration.js";
|
|
53
54
|
import { SIZE_LIMITS_MB } from "../config/index.js";
|
|
54
55
|
import { FileErrorCode } from "../errors/index.js";
|
|
55
56
|
import { tracers, ATTR, withSpan } from "../../telemetry/index.js";
|
|
@@ -270,7 +271,7 @@ export class VideoProcessor extends BaseFileProcessor {
|
|
|
270
271
|
keyframes: [],
|
|
271
272
|
metadata: {
|
|
272
273
|
duration: 0,
|
|
273
|
-
durationFormatted:
|
|
274
|
+
durationFormatted: formatMediaDuration(0),
|
|
274
275
|
width: 0,
|
|
275
276
|
height: 0,
|
|
276
277
|
codec: "unknown",
|
|
@@ -908,27 +909,16 @@ export class VideoProcessor extends BaseFileProcessor {
|
|
|
908
909
|
/**
|
|
909
910
|
* Format a duration in seconds to a human-readable string.
|
|
910
911
|
*
|
|
912
|
+
* Delegates to the shared formatter so audio and video agree — see
|
|
913
|
+
* `formatMediaDuration`. Rounding replaces the previous truncation, so a
|
|
914
|
+
* 2.6s clip now reads "3s" rather than "2s" and matches what the audio
|
|
915
|
+
* side reports for the same stream.
|
|
916
|
+
*
|
|
911
917
|
* @param seconds - Duration in seconds
|
|
912
918
|
* @returns Formatted string (e.g., "1h 23m 45s")
|
|
913
919
|
*/
|
|
914
920
|
formatDuration(seconds) {
|
|
915
|
-
|
|
916
|
-
return "0s";
|
|
917
|
-
}
|
|
918
|
-
const hours = Math.floor(seconds / 3600);
|
|
919
|
-
const minutes = Math.floor((seconds % 3600) / 60);
|
|
920
|
-
const secs = Math.floor(seconds % 60);
|
|
921
|
-
const parts = [];
|
|
922
|
-
if (hours > 0) {
|
|
923
|
-
parts.push(`${hours}h`);
|
|
924
|
-
}
|
|
925
|
-
if (minutes > 0) {
|
|
926
|
-
parts.push(`${minutes}m`);
|
|
927
|
-
}
|
|
928
|
-
if (secs > 0 || parts.length === 0) {
|
|
929
|
-
parts.push(`${secs}s`);
|
|
930
|
-
}
|
|
931
|
-
return parts.join(" ");
|
|
921
|
+
return formatMediaDuration(seconds);
|
|
932
922
|
}
|
|
933
923
|
/**
|
|
934
924
|
* Get a file extension from FileInfo, falling back to ".mp4".
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared duration formatting for the media processors.
|
|
3
|
+
*
|
|
4
|
+
* AudioProcessor and VideoProcessor each carried their own private
|
|
5
|
+
* `formatDuration`, and they disagreed: the same two-second file rendered as
|
|
6
|
+
* "0:02" from audio and "2s" from video, and a zero duration as "0:00" versus
|
|
7
|
+
* "0s". Both strings land in the `textContent` handed to the model, often in
|
|
8
|
+
* the same request when a video's muxed audio is described alongside it, so
|
|
9
|
+
* the mismatch reads as two different facts about one file.
|
|
10
|
+
*
|
|
11
|
+
* The explicit-unit form wins over the "m:ss" clock form because these strings
|
|
12
|
+
* are consumed by a language model, not rendered in a player scrubber: "1m 30s"
|
|
13
|
+
* has exactly one reading, while "1:30" is ambiguous between 1m30s and 1h30m
|
|
14
|
+
* and has to be disambiguated from context that may not be present.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Format a duration in seconds as explicit units — "45s", "1m 30s", "1h 2m 3s".
|
|
18
|
+
*
|
|
19
|
+
* Non-finite, negative and zero durations all render as "0s": callers reach
|
|
20
|
+
* this with a probe failure or a stream that reports no duration, and a
|
|
21
|
+
* fabricated number would be worse than an obvious zero.
|
|
22
|
+
*/
|
|
23
|
+
export declare function formatMediaDuration(seconds: number): string;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared duration formatting for the media processors.
|
|
3
|
+
*
|
|
4
|
+
* AudioProcessor and VideoProcessor each carried their own private
|
|
5
|
+
* `formatDuration`, and they disagreed: the same two-second file rendered as
|
|
6
|
+
* "0:02" from audio and "2s" from video, and a zero duration as "0:00" versus
|
|
7
|
+
* "0s". Both strings land in the `textContent` handed to the model, often in
|
|
8
|
+
* the same request when a video's muxed audio is described alongside it, so
|
|
9
|
+
* the mismatch reads as two different facts about one file.
|
|
10
|
+
*
|
|
11
|
+
* The explicit-unit form wins over the "m:ss" clock form because these strings
|
|
12
|
+
* are consumed by a language model, not rendered in a player scrubber: "1m 30s"
|
|
13
|
+
* has exactly one reading, while "1:30" is ambiguous between 1m30s and 1h30m
|
|
14
|
+
* and has to be disambiguated from context that may not be present.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Format a duration in seconds as explicit units — "45s", "1m 30s", "1h 2m 3s".
|
|
18
|
+
*
|
|
19
|
+
* Non-finite, negative and zero durations all render as "0s": callers reach
|
|
20
|
+
* this with a probe failure or a stream that reports no duration, and a
|
|
21
|
+
* fabricated number would be worse than an obvious zero.
|
|
22
|
+
*/
|
|
23
|
+
export function formatMediaDuration(seconds) {
|
|
24
|
+
if (!Number.isFinite(seconds) || seconds <= 0) {
|
|
25
|
+
return "0s";
|
|
26
|
+
}
|
|
27
|
+
const total = Math.round(seconds);
|
|
28
|
+
const hours = Math.floor(total / 3600);
|
|
29
|
+
const minutes = Math.floor((total % 3600) / 60);
|
|
30
|
+
const secs = total % 60;
|
|
31
|
+
const parts = [];
|
|
32
|
+
if (hours > 0) {
|
|
33
|
+
parts.push(`${hours}h`);
|
|
34
|
+
}
|
|
35
|
+
if (minutes > 0) {
|
|
36
|
+
parts.push(`${minutes}m`);
|
|
37
|
+
}
|
|
38
|
+
// Keep the seconds term when it is the only one, so sub-minute durations
|
|
39
|
+
// never render as an empty string.
|
|
40
|
+
if (secs > 0 || parts.length === 0) {
|
|
41
|
+
parts.push(`${secs}s`);
|
|
42
|
+
}
|
|
43
|
+
return parts.join(" ");
|
|
44
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@juspay/neurolink",
|
|
3
|
-
"version": "10.8.
|
|
3
|
+
"version": "10.8.8",
|
|
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": {
|