From 9dbab133dbdcf179a65552101e479e38e4b02a6d Mon Sep 17 00:00:00 2001 From: Vanilagy <1696106+Vanilagy@users.noreply.github.com> Date: Wed, 17 Dec 2025 17:57:26 +0100 Subject: [PATCH] Add input type validation --- src/cursors.ts | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/src/cursors.ts b/src/cursors.ts index be34826..2c390be 100644 --- a/src/cursors.ts +++ b/src/cursors.ts @@ -223,6 +223,8 @@ export class PacketCursor { } seekTo(timestamp: number): MaybePromise { + validateTimestamp(timestamp); + return this.callSerializer.call(() => { const result = this.reader.readAt(timestamp, this.options); @@ -240,6 +242,8 @@ export class PacketCursor { } seekToKey(timestamp: number): MaybePromise { + validateTimestamp(timestamp); + return this.callSerializer.call(() => { const result = this.reader.readKeyAt(timestamp, this.options); @@ -307,6 +311,10 @@ export class PacketCursor { async iterate( callback: (packet: EncodedPacket, stop: () => void) => MaybePromise, ) { + if (typeof callback !== 'function') { + throw new TypeError('callback must be a function.'); + } + let stopped = false; const stop = () => stopped = true; @@ -371,6 +379,20 @@ type SampleCursorOptions = { transform?: SampleTransformer; }; +const validateSampleCursorOptions = ( + options: SampleCursorOptions, +) => { + if (!options || typeof options !== 'object') { + throw new TypeError('options must an object.'); + } + if (options.autoClose !== undefined && typeof options.autoClose !== 'boolean') { + throw new TypeError('options.autoClose, when provided, must be a boolean.'); + } + if (options.transform !== undefined && typeof options.transform !== 'function') { + throw new TypeError('options.transform, when provided, must be a function.'); + } +}; + export abstract class SampleCursor< Sample extends VideoSample | AudioSample, TransformedSample = Sample, @@ -420,12 +442,10 @@ export abstract class SampleCursor< abstract initDecoder(): Promise>; - constructor( + protected constructor( reader: PacketReader, options: SampleCursorOptions, ) { - // todo options validation - this.packetReader = reader; this.packetCursor = new PacketCursor(reader); this.options = options; @@ -678,6 +698,7 @@ export abstract class SampleCursor< } seekTo(timestamp: number): MaybePromise { + validateTimestamp(timestamp); this._ensureWillBeOpen(); try { @@ -697,6 +718,7 @@ export abstract class SampleCursor< } seekToKey(timestamp: number): MaybePromise { + validateTimestamp(timestamp); this._ensureWillBeOpen(); try { @@ -789,6 +811,10 @@ export abstract class SampleCursor< async iterate( callback: (sample: TransformedSample, stop: () => void) => MaybePromise, ) { + if (typeof callback !== 'function') { + throw new TypeError('callback must be a function.'); + } + this._ensureWillBeOpen(); let stopped = false; @@ -1069,6 +1095,7 @@ export class VideoSampleCursor extends SampleCu if (!(reader instanceof PacketReader) || !(reader.track instanceof InputVideoTrack)) { throw new TypeError('reader must be a PacketReader for an InputVideoTrack.'); } + validateSampleCursorOptions(options); super(reader, options); } @@ -1116,6 +1143,7 @@ export class AudioSampleCursor extends SampleCu if (!(reader instanceof PacketReader) || !(reader.track instanceof InputAudioTrack)) { throw new TypeError('reader must be a PacketReader for an InputAudioTrack.'); } + validateSampleCursorOptions(options); super(reader, options); }