// Exercise the production StreamClient against native hardware video, while // deliberately stalling only this auxiliary local consumer. Adds no UDP peer. // Bitmap decoding is stubbed here; actual JPEG decoding is checked separately. import {readFileSync,writeFileSync} from 'node:fs'; import assert from 'node:assert/strict'; import ts from 'typescript'; const [logPath,outPath]=process.argv.slice(2); if(!logPath||!outPath)throw new Error('Use '); const log=readFileSync(logPath,'utf8'); const url=[...log.matchAll(/ws:\/\/127\.0\.0\.1:\d+\/\?token=[A-Za-z0-9_-]+/g)].at(-1)?.[0]; if(!url)throw new Error('No local video URL in the private debug log'); const source=readFileSync(new URL('../src/lib/stream.ts',import.meta.url),'utf8'); const compiled=ts.transpileModule(source,{compilerOptions:{module:ts.ModuleKind.CommonJS,target:ts.ScriptTarget.ES2022}}).outputText; const exports={};new Function('require','exports',compiled)(()=>({FRAME_HEADER_LEN:16}),exports); globalThis.window={setTimeout,clearTimeout}; globalThis.createImageBitmap=async()=>({close(){}}); const rx=new exports.StreamClient({onMessage(){},onConnection(){}}); const delay=ms=>new Promise(resolve=>setTimeout(resolve,ms)); try { rx.connect(url); const deadline=performance.now()+10_000; while(rx.counters.frames<10&&performance.now()=10,'Real native JPEG video did not arrive'); const camera=[...rx.frames.keys()][0]; const before=rx.latest(camera)?.frameId; const staleBefore=rx.counters.staleFrames; const blockedAt=performance.now(); while(performance.now()-blockedAt<350) { /* synthetic consumer stall */ } await delay(700); const latest=rx.latest(camera); assert.ok(rx.counters.staleFrames>staleBefore,'Stale native-timestamped frames were not rejected'); assert.ok(latest&&latest.frameId!==before,'The consumer did not recover to new video'); assert.ok(performance.now()-latest.receivedAt<150,'Recovered image is still stale locally'); const result={passed:true,stall_ms:350,stale_frames_rejected:rx.counters.staleFrames-staleBefore, frame_before:before,frame_after:latest.frameId,frames_received:rx.counters.frames, additional_udp_subscribers:0,jpeg_decoder_stubbed:true, scope:'Production StreamClient over real native WebSocket; tests queued-frame age and recovery, not physical display latency'}; writeFileSync(outPath,JSON.stringify(result,null,2)+'\n'); console.log(JSON.stringify(result)); } finally {rx.close();}