@juspay/neurolink 12.41.0 → 12.41.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.
package/CHANGELOG.md CHANGED
@@ -1,8 +1,8 @@
1
- ## [12.41.0](https://github.com/juspay/neurolink/compare/v12.40.3...v12.41.0) (2026-09-30)
1
+ ## [12.41.2](https://github.com/juspay/neurolink/compare/v12.41.1...v12.41.2) (2026-09-30)
2
2
 
3
- ### Features
3
+ ### Bug Fixes
4
4
 
5
- - **(codex-proxy):** fall back from exhausted Codex to Claude, off by default ([7748849](https://github.com/juspay/neurolink/commit/774884969605087f57ff0b1bed16db93f6346380))
5
+ - **(deps):** raise the @grpc/grpc-js floor to 1.14.5 for GHSA-m9gg-hp2v-232j ([7f5aff0](https://github.com/juspay/neurolink/commit/7f5aff026c5c71d7c11460eacec7fc95b8b7e027))
6
6
 
7
7
  ## [11.2.3](https://github.com/juspay/neurolink/compare/v11.2.2...v11.2.3) (2026-08-19)
8
8
 
@@ -817,7 +817,7 @@ Options:
817
817
  2. Contact support to add ${n} PDF configuration`)}const s=t.length/(1024*1024);if(s>o.maxSizeMB)throw new Error(`PDF size ${s.toFixed(2)}MB exceeds ${o.maxSizeMB}MB limit for ${n}`);const i=Vo.extractBasicMetadata(t),a=await Vo.getAccuratePageCount(t);if(a!==null&&(i.estimatedPages=a),i.estimatedPages&&i.estimatedPages>o.maxPages){if(r?.enforceLimits!==!1)throw pe.pdfPageLimitExceeded(i.estimatedPages,o.maxPages,n);m.warn(`[PDF] \u26A0\uFE0F LIMIT BYPASS: Processing ${i.estimatedPages}-page PDF despite ${o.maxPages}-page limit for ${n}. This may cause API rejection, token errors, or unexpected costs. Consider splitting the PDF or using a different provider.`)}return n==="bedrock"&&r?.bedrockApiMode==="converse"&&m.info("[PDF] Using Bedrock Converse API. Visual PDF analysis requires citations enabled. Text-only mode: ~1,000 tokens/3 pages. Visual mode: ~7,000 tokens/3 pages."),m.info("[PDF] \u2705 Validated PDF file",{provider:n,size:`${s.toFixed(2)}MB`,version:i.version,estimatedPages:i.estimatedPages,apiType:o.apiType,supportsNative:o.supportsNative}),{type:"pdf",content:t,mimeType:"application/pdf",metadata:{confidence:100,size:t.length,...i,provider:n,apiType:o.apiType,requiresCitations:o.requiresCitations}}}static supportsNativePDF(t){const r=t.toLowerCase();return Cf[r]?.supportsNative??!1}static getProviderConfig(t){return Cf[t]||null}static async resolvePageCount(t){const r=await Vo.getAccuratePageCount(t);return r!==null?r:Vo.extractBasicMetadata(t).estimatedPages}static isValidPDF(t){return t.length<5?!1:t.subarray(0,5).equals(Vo.PDF_SIGNATURE)}static extractBasicMetadata(t){const r=Math.min(1e4,t.length),n=t.toString("utf-8",0,r),o=n.match(/%PDF-(\d\.\d)/),s=o?o[1]:"unknown",i=n.match(/\/Type\s*\/Page[^s]/g),a=i?i.length:null;return{version:s,estimatedPages:a,filename:void 0}}static async getAccuratePageCount(t){try{const{PDFParse:r}=await Promise.resolve().then(()=>(xf(),nm)),n=new r({data:new Uint8Array(t)});let o;try{const i=(await Promise.race([n.getInfo(),new Promise((a,c)=>{o=setTimeout(()=>c(new Error("page-count timeout")),Gs.PAGE_COUNT_TIMEOUT_MS),o.unref?.()})])).total;return typeof i=="number"&&i>0?i:null}finally{o!==void 0&&clearTimeout(o);try{await n.destroy?.()}catch{}}}catch(r){return m.debug(`[PDF] Accurate page count unavailable; using regex estimate: ${r instanceof Error?r.message:String(r)}`),null}}static pdfjsAssetDirs;static resolvePdfjsAssetDirs(){if(Vo.pdfjsAssetDirs===void 0)try{const t=Tu(import.meta.url).resolve("pdf-parse"),r=nr.dirname(Tu(t).resolve("pdfjs-dist/package.json"));Vo.pdfjsAssetDirs={standardFontDataUrl:nr.join(r,"standard_fonts")+nr.sep,cMapUrl:nr.join(r,"cmaps")+nr.sep}}catch(t){m.debug(`[PDF\u2192Image] pdfjs font/CMap directories unavailable: ${t instanceof Error?t.message:String(t)}`),Vo.pdfjsAssetDirs=null}return Vo.pdfjsAssetDirs??void 0}static async openForRendering(t,r,n){const{PDFParse:o}=await Promise.resolve().then(()=>(xf(),nm)),s=new o({data:new Uint8Array(t),isEvalSupported:!1,cMapPacked:!0,...Vo.resolvePdfjsAssetDirs(),...n?{password:n}:{}});try{const{total:i}=await s.getInfo();return{length:i,getPage:async a=>{const l=(await s.getScreenshot({partial:[a],scale:r,imageBuffer:!0,imageDataUrl:!1})).pages[0];if(!l||l.data.length===0)throw new Error(`page ${a} rendered no image data`);return Buffer.from(l.data)},destroy:async()=>{await s.destroy().catch(()=>{})}}}catch(i){throw await s.destroy().catch(()=>{}),i}}static estimateTokens(t,r="visual"){return Math.ceil(r==="text-only"?t/3*1e3:t/3*7e3)}static largestPagePixels(t,r){const n=t.toString("latin1"),o=/\/MediaBox\s*\[\s*(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s+(-?[\d.]+)\s*\]/g;let s=0,i;for(;(i=o.exec(n))!==null;){const a=Math.abs(parseFloat(i[3])-parseFloat(i[1])),c=Math.abs(parseFloat(i[4])-parseFloat(i[2]));if(Number.isFinite(a)&&Number.isFinite(c)){const l=a*c*r*r,u=Number.isFinite(l)?Math.min(l,Number.MAX_SAFE_INTEGER):Number.MAX_SAFE_INTEGER;u>s&&(s=u)}}return s}static async convertToImages(t,r){const n=Date.now(),{scale:o=Gs.DEFAULT_SCALE,maxPages:s=Gs.DEFAULT_MAX_PAGES,format:i="png",maxCanvasPixels:a=Gs.DEFAULT_MAX_CANVAS_PIXELS,password:c,onProgress:l}=r||{},u=[],d=[],p=[],h=Vo.validateImageConversionInput(t,{format:i,scale:o,maxCanvasPixels:a,maxPages:s});m.debug("[PDF\u2192Image] \u2705 PDF validation passed",{bufferSize:t.length,sizeMB:h.toFixed(2),maxPages:s});const f=Math.max(1,Vo.extractBasicMetadata(t).estimatedPages??1),g=Vo.estimateConversionMemoryUsage(t.length,f,o);m.info("[PDF\u2192Image] Estimated memory usage before conversion",{scale:o,estimatedPages:f,estimatedMemoryMB:g,sizeMB:Number(h.toFixed(2))});let y;try{m.debug("[PDF\u2192Image] Starting PDF to image conversion",{bufferSize:t.length,scale:o,maxPages:s||"all"});let v=o;const T=Vo.largestPagePixels(t,o);if(T>a){const k=Math.sqrt(a/T);v=Math.max(Gs.MIN_EFFECTIVE_SCALE,o*k);const x=v/o,C=T*4/(1024*1024),I=T*x*x*4/(1024*1024),R=`Downscaled render (scale ${o} \u2192 ${v.toFixed(3)}): the largest page would allocate ~${C.toFixed(0)}MB, above the maxCanvasPixels ceiling; reduced to ~${I.toFixed(0)}MB per page.`;m.warn(`[PDF\u2192Image] \u26A0\uFE0F ${R}`),d.push(R)}y=await Vo.openForRendering(t,v,c);const b=y.length;for(let k=1;k<=b;k++){if(s!==void 0&&k-1>=s){d.push(`Stopped at page ${k-1} (maxPages limit: ${s})`);break}try{const x=await y.getPage(k),C=x.toString("base64");u.push(C),m.debug(`[PDF\u2192Image] Converted page ${k}`,{imageSizeBytes:x.length,base64Length:C.length}),l&&await l({pagesConverted:u.length,totalPages:b,elapsedMs:Date.now()-n})}catch(x){const C=x instanceof Error?x.message:String(x);m.warn(`[PDF\u2192Image] \u26A0\uFE0F page ${k} failed to render: ${C}`),p.push({page:k,error:C})}}if(u.length===0)throw p.length>0?new Error(`All ${p.length} page(s) failed to render. First error: ${p[0].error}`):new Error("PDF has 0 pages. Cannot convert empty PDF to images.");const S=Date.now()-n;return m.info("[PDF\u2192Image] \u2705 PDF conversion completed",{pageCount:u.length,failedPages:p.length,conversionTimeMs:S,totalImageBytes:u.reduce((k,x)=>k+x.length,0)}),{images:u,pageCount:u.length,conversionTimeMs:S,warnings:d.length>0?d:void 0,errors:p.length>0?p:void 0}}catch(v){const T=Date.now()-n,b=v instanceof Error?v.message:String(v);m.error("[PDF\u2192Image] \u274C PDF conversion failed",{error:b,conversionTimeMs:T});const S=v;throw S?.name==="PasswordException"||/password/i.test(b)?S.code===2||/incorrect|invalid/i.test(b)?pe.pdfIncorrectPassword():pe.pdfPasswordRequired():new Error(`PDF to image conversion failed: ${b}`,{cause:v})}finally{await y?.destroy()}}static validateImageConversionInput(t,r){if(r.format!=="png")throw new Error(`Invalid format: "${r.format}". Only "png" format is currently supported.`);if(!Number.isFinite(r.scale)||r.scale<Gs.MIN_SCALE||r.scale>Gs.MAX_SCALE)throw new Error(`Invalid scale: ${r.scale}. Scale must be a finite number between ${Gs.MIN_SCALE} and ${Gs.MAX_SCALE}.`);if(!Number.isFinite(r.maxCanvasPixels)||r.maxCanvasPixels<=0)throw new Error(`Invalid maxCanvasPixels: ${r.maxCanvasPixels}. Must be a finite number greater than 0.`);if(r.maxPages!==void 0&&(!Number.isInteger(r.maxPages)||r.maxPages<1))throw new Error(`Invalid maxPages: ${r.maxPages}. Must be a whole number of at least 1.`);if(!t||t.length<5)throw new Error("Invalid PDF: Buffer is too small or empty. A valid PDF must be at least 5 bytes (PDF header).");if(!Vo.isValidPDF(t))throw new Error("Invalid PDF: File must start with %PDF- header. The provided buffer does not appear to be a valid PDF file.");const n=t.length/(1024*1024);if(n>Gs.MAX_SIZE_MB)throw new Error(`PDF too large for image conversion: ${n.toFixed(2)}MB exceeds ${Gs.MAX_SIZE_MB}MB limit. Consider splitting the PDF or using a provider with native PDF support.`);return n}static async*convertToImagesStream(t,r){const n=Date.now(),{scale:o=Gs.DEFAULT_SCALE,maxPages:s=Gs.DEFAULT_MAX_PAGES,format:i="png",maxCanvasPixels:a=Gs.DEFAULT_MAX_CANVAS_PIXELS,password:c,onProgress:l}=r||{};Vo.validateImageConversionInput(t,{format:i,scale:o,maxCanvasPixels:a,maxPages:s});let u=o;const d=Vo.largestPagePixels(t,o);d>a&&(u=o*Math.sqrt(a/d));let p;try{p=await Vo.openForRendering(t,u,c)}catch(g){const y=g instanceof Error?g.message:String(g),v=g;throw v?.name==="PasswordException"||/password/i.test(y)?v.code===2||/incorrect|invalid/i.test(y)?pe.pdfIncorrectPassword():pe.pdfPasswordRequired():new Error(`PDF to image conversion failed: ${y}`,{cause:g})}const h=p.length;let f=0;try{for(let g=1;g<=h&&!(s!==void 0&&g-1>=s);g++)try{const y=await p.getPage(g),v=y.toString("base64");f++,l&&await l({pagesConverted:f,totalPages:h,elapsedMs:Date.now()-n}),yield{pageIndex:g,image:v,imageSizeBytes:y.length}}catch(y){const v=y instanceof Error?y.message:String(y);m.warn(`[PDF\u2192Image] \u26A0\uFE0F page ${g} failed to render (stream): ${v}`),yield{pageIndex:g,image:"",imageSizeBytes:0,error:v}}}finally{await p.destroy()}}static async convertFromPath(t,r){const o=await(await Promise.resolve().then(()=>(Yo(),hf))).readFile(t);return Vo.convertToImages(o,r)}static async isImageConversionAvailable(){try{return await Promise.resolve().then(()=>(xf(),nm)),!0}catch{return!1}}static estimateConversionMemoryUsage(t,r,n=Gs.DEFAULT_SCALE){const o=t/1048576*2,s=r*2*n;return Math.ceil(o+s)}static getImageFallbackProviders(){return Object.entries(Cf).filter(([t,r])=>!r.supportsNative).map(([t])=>t)}static getNativePDFProviders(){return Object.entries(Cf).filter(([t,r])=>r.supportsNative).map(([t])=>t)}},Xct=Af}});function RS(e){if(!Number.isFinite(e)||e<=0)return"0s";const t=Math.round(e),r=Math.floor(t/3600),n=Math.floor(t%3600/60),o=t%60,s=[];return r>0&&s.push(`${r}h`),n>0&&s.push(`${n}m`),(o>0||s.length===0)&&s.push(`${o}s`),s.join(" ")}function Qct(e){const t=Number.isFinite(e)&&e>0?e:0,r=`${t.toFixed(2)}s`;return t>=60?`${r} (${RS(t)})`:r}var $W=_({"src/lib/utils/mediaDuration.ts"(){"use strict"}}),UW={};Z(UW,{Agent:()=>llt,AsyncLocalStorage:()=>_lt,Buffer:()=>wdt,Channel:()=>cdt,DatabaseSync:()=>vdt,Duplex:()=>klt,EventEmitter:()=>Elt,Http2ServerRequest:()=>Sdt,Http2ServerResponse:()=>kdt,Interface:()=>ydt,MIMEType:()=>Mdt,PassThrough:()=>xlt,PerformanceObserver:()=>sdt,Readable:()=>zW,ReadableStream:()=>Clt,Resolver:()=>ndt,STATUS_CODES:()=>xut,TextDecoder:()=>jW,TextEncoder:()=>PS,Transform:()=>Slt,URL:()=>jut,URLSearchParams:()=>Vut,Worker:()=>pdt,Writable:()=>GW,access:()=>iut,appendFile:()=>$lt,appendFileSync:()=>ilt,arch:()=>Eut,arrayBuffer:()=>xdt,availableParallelism:()=>Nlt,basename:()=>flt,builtinModules:()=>But,callbackify:()=>Zut,channel:()=>adt,chmod:()=>Dlt,chmodSync:()=>Olt,clearInterval:()=>Rdt,clearTimeout:()=>Adt,closeSync:()=>Glt,connect:()=>Cut,constants:()=>Tdt,copyFileSync:()=>Blt,cpSync:()=>alt,cpus:()=>vut,createConnection:()=>Aut,createGunzip:()=>Nut,createGzip:()=>Lut,createHash:()=>BW,createHmac:()=>rlt,createInterface:()=>gdt,createReadStream:()=>Qlt,createRequire:()=>Uut,createServer:()=>clt,createWriteStream:()=>Zlt,debug:()=>Yut,debuglog:()=>qW,default:()=>elt,deflateSync:()=>Rut,deprecate:()=>Xut,deserialize:()=>ddt,dirname:()=>hlt,exec:()=>put,execFile:()=>hut,execFileSync:()=>fut,execSync:()=>mut,existsSync:()=>Rlt,extname:()=>glt,fileURLToPath:()=>Hut,finished:()=>Ilt,format:()=>qut,freemem:()=>wut,fstatSync:()=>qlt,get:()=>kut,gunzip:()=>Dut,gunzipSync:()=>Mut,gzip:()=>Out,gzipSync:()=>Put,hasSubscribers:()=>ldt,homedir:()=>Si,hostname:()=>yut,inflateSync:()=>Iut,inherits:()=>Kut,inspect:()=>MS,isAbsolute:()=>vlt,isBuiltin:()=>zut,isDeepStrictEqual:()=>Qut,isIP:()=>_dt,isIPv4:()=>Edt,isIPv6:()=>bdt,isMainThread:()=>mdt,join:()=>plt,loadavg:()=>Llt,lookup:()=>rdt,lstatSync:()=>Hlt,mkdir:()=>rut,mkdirSync:()=>jlt,monitorEventLoopDelay:()=>idt,normalize:()=>blt,ok:()=>Fut,open:()=>lut,openSync:()=>zlt,parentPort:()=>hdt,parse:()=>Gut,pathToFileURL:()=>Wut,performance:()=>odt,pipeline:()=>Alt,platform:()=>gut,posix:()=>Tlt,promises:()=>tlt,promisify:()=>Jut,randomBytes:()=>nlt,randomUUID:()=>olt,readFile:()=>eut,readFileSync:()=>Mlt,readdir:()=>out,readdirSync:()=>Wlt,realpath:()=>uut,realpathSync:()=>Ult,relative:()=>ylt,release:()=>_ut,rename:()=>aut,renameSync:()=>Jlt,request:()=>Sut,resolve:()=>mlt,rm:()=>cut,rmSync:()=>Xlt,rmdirSync:()=>Ylt,sep:()=>wlt,serialize:()=>udt,setImmediate:()=>Flt,setInterval:()=>Idt,setTimeout:()=>Cdt,spawn:()=>dut,stat:()=>nut,statSync:()=>Vlt,strict:()=>$ut,tmpdir:()=>fP,toUSVString:()=>edt,totalmem:()=>Tut,type:()=>but,types:()=>tdt,unlink:()=>sut,unlinkSync:()=>Klt,validateHeaderName:()=>ult,validateHeaderValue:()=>dlt,webcrypto:()=>slt,workerData:()=>fdt,writeFile:()=>tut,writeFileSync:()=>Plt});var io,Tn,elt,tlt,BW,rlt,nlt,olt,slt,ilt,alt,clt,llt,ult,dlt,plt,mlt,hlt,flt,glt,ylt,vlt,wlt,Tlt,blt,Elt,_lt,zW,GW,Slt,klt,xlt,Clt,Alt,Ilt,Rlt,Mlt,Plt,Olt,Dlt,Nlt,Llt,Flt,$lt,Ult,Blt,zlt,Glt,qlt,jlt,Vlt,Hlt,Wlt,Klt,Jlt,Ylt,Xlt,Zlt,Qlt,eut,tut,rut,nut,out,sut,iut,aut,cut,lut,uut,dut,put,mut,hut,fut,gut,Si,fP,yut,vut,wut,Tut,but,Eut,_ut,Sut,kut,xut,Cut,Aut,Iut,Rut,Mut,Put,Out,Dut,Nut,Lut,Fut,$ut,Uut,But,zut,Gut,qut,jut,Vut,Hut,Wut,Kut,Jut,qW,Yut,MS,Xut,Zut,Qut,edt,tdt,jW,PS,rdt,ndt,odt,sdt,idt,adt,cdt,ldt,udt,ddt,pdt,mdt,hdt,fdt,gdt,ydt,vdt,wdt,Tdt,bdt,Edt,_dt,Sdt,kdt,xdt,VW,Cdt,Adt,Idt,Rdt,Mdt,ki=_({"node-stub:os"(){io=()=>{},Tn=async()=>{},elt={},tlt={readFile:Tn,writeFile:Tn,mkdir:Tn,stat:Tn,readdir:Tn,unlink:Tn,access:Tn,rm:Tn,rename:Tn},BW=e=>{const t=[];return{update(r){return t.push(typeof r=="string"?new PS().encode(r):r),this},digest(r){let n=0;for(const s of t)for(let i=0;i<s.length;i++)n=(n<<5)-n+s[i]|0;const o=(n>>>0).toString(16).padStart(8,"0");return r==="hex"?o:r==="base64"?btoa(o):o}}},rlt=(e,t)=>BW(e),nlt=e=>new Uint8Array(e||32),olt=()=>globalThis.crypto?.randomUUID?.()||Math.random().toString(36),slt=globalThis.crypto,ilt=()=>{throw new Error("[NeuroLink:browser] fs.appendFileSync is not supported in browser runtime \u2014 use server-side execution")},alt=()=>{throw new Error("[NeuroLink:browser] fs.cpSync is not supported in browser runtime \u2014 use server-side execution")},clt=()=>({listen:io,close:io,on:io}),llt=class{constructor(){throw new Error("[NeuroLink:browser] Node HTTP agents require a server runtime")}},ult=io,dlt=io,plt=(...e)=>e.join("/"),mlt=(...e)=>e.join("/"),hlt=e=>e||"",flt=e=>e?.split?.("/")?.pop?.()||"",glt=e=>{const t=e?.match?.(/\.[^.]+$/);return t?t[0]:""},ylt=(e,t)=>t||"",vlt=()=>!1,wlt="/",Tlt={normalize:e=>e,join:(...e)=>e.join("/"),resolve:(...e)=>e.join("/"),sep:"/"},blt=e=>e,Elt=class{constructor(){this._ev=new Map}_list(t){let r=this._ev.get(t);return r||(r=[],this._ev.set(t,r)),r}on(t,r){return this._list(t).push(r),this}addListener(t,r){return this.on(t,r)}prependListener(t,r){return this._list(t).unshift(r),this}once(t,r){const n=(...o)=>{this.off(t,n),r(...o)};return n.listener=r,this.on(t,n)}prependOnceListener(t,r){const n=(...o)=>{this.off(t,n),r(...o)};return n.listener=r,this.prependListener(t,n)}off(t,r){const n=this._ev.get(t);if(n){const o=n.findIndex(s=>s===r||s.listener===r);o>=0&&n.splice(o,1)}return this}removeListener(t,r){return this.off(t,r)}removeAllListeners(t){return t===void 0?this._ev.clear():this._ev.delete(t),this}emit(t,...r){const n=this._ev.get(t);if(!n||n.length===0){if(t==="error")throw r[0]instanceof Error?r[0]:new Error("Unhandled error.");return!1}for(const o of[...n])o.apply(this,r);return!0}listenerCount(t){return(this._ev.get(t)||[]).length}listeners(t){return[...this._ev.get(t)||[]]}rawListeners(t){return this.listeners(t)}eventNames(){return[...this._ev.keys()]}setMaxListeners(){return this}getMaxListeners(){return 10}},_lt=class{getStore(){}run(e,t,...r){return t(...r)}enterWith(){}disable(){}},zW=class{pipe(){return this}on(){return this}read(){return null}push(){}destroy(){}},GW=class{write(){return!0}end(){}on(){return this}destroy(){}},Slt=class{push(){}on(){return this}},klt=class{on(){return this}},xlt=class{pipe(){return this}on(){return this}},Clt=globalThis.ReadableStream||class{},Alt=io,Ilt=io,Rlt=()=>!1,Mlt=()=>"",Plt=io,Olt=io,Dlt=Tn,Nlt=()=>1,Llt=()=>[0,0,0],Flt=Tn,$lt=Tn,Ult=e=>e,Blt=io,zlt=()=>0,Glt=io,qlt=()=>({}),jlt=io,Vlt=()=>({}),Hlt=()=>({isSymbolicLink:()=>!1}),Wlt=()=>[],Klt=io,Jlt=io,Ylt=io,Xlt=io,Zlt=()=>new GW,Qlt=()=>new zW,eut=Tn,tut=Tn,rut=Tn,nut=Tn,out=Tn,sut=Tn,iut=Tn,aut=Tn,cut=Tn,lut=async()=>({stat:Tn,readFile:Tn,close:Tn,read:Tn,write:Tn}),uut=async e=>e,dut=()=>({on:io,stdout:{on:io},stderr:{on:io},kill:io}),put=(e,t)=>t?.(null,"",""),mut=()=>"",hut=(e,t,r)=>{typeof t=="function"?t(null,"",""):r?.(null,"","")},fut=()=>"",gut="browser",Si=()=>"/",fP=()=>"/tmp",yut=()=>"browser",vut=()=>[{}],wut=()=>0,Tut=()=>0,but=()=>"Browser",Eut=()=>"wasm",_ut=()=>"0",Sut=()=>({}),kut=()=>({}),xut={100:"Continue",101:"Switching Protocols",200:"OK",201:"Created",202:"Accepted",204:"No Content",206:"Partial Content",301:"Moved Permanently",302:"Found",304:"Not Modified",307:"Temporary Redirect",308:"Permanent Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Payload Too Large",414:"URI Too Long",415:"Unsupported Media Type",416:"Range Not Satisfiable",417:"Expectation Failed",422:"Unprocessable Entity",425:"Too Early",426:"Upgrade Required",428:"Precondition Required",429:"Too Many Requests",431:"Request Header Fields Too Large",451:"Unavailable For Legal Reasons",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported"},Cut=()=>({}),Aut=()=>({}),Iut=()=>new Uint8Array,Rut=()=>new Uint8Array,Mut=()=>new Uint8Array,Put=()=>new Uint8Array,Out=(e,t)=>t?.(null,e),Dut=(e,t)=>t?.(null,e),Nut=()=>({}),Lut=()=>({}),Fut=io,$ut={},Uut=()=>()=>({}),But=[],zut=()=>!1,Gut=e=>({pathname:e||"",hostname:"",protocol:"",search:"",hash:""}),qut=()=>"",jut=globalThis.URL,Vut=globalThis.URLSearchParams,Hut=e=>typeof e=="string"?e.replace("file://",""):e,Wut=e=>new globalThis.URL("file://"+e),Kut=(e,t)=>{t&&(e.super_=t,Object.setPrototypeOf(e.prototype,t.prototype))},Jut=e=>(...t)=>new Promise((r,n)=>e(...t,(o,s)=>o?n(o):r(s))),qW=e=>{const t=(...r)=>{};return t.enabled=!1,t},Yut=qW,MS=e=>{try{return JSON.stringify(e,null,2)}catch{return String(e)}},MS.custom=Symbol.for("nodejs.util.inspect.custom"),MS.colors={},MS.styles={},Xut=e=>e,Zut=e=>(...t)=>{const r=t.pop();e(...t).then(n=>r(null,n)).catch(r)},Qut=(e,t)=>JSON.stringify(e)===JSON.stringify(t),edt=e=>String(e),tdt={isPromise:e=>e instanceof Promise,isDate:e=>e instanceof Date,isRegExp:e=>e instanceof RegExp,isNativeError:e=>e instanceof Error,isArrayBuffer:e=>e instanceof ArrayBuffer,isTypedArray:e=>ArrayBuffer.isView(e),isUint8Array:e=>e instanceof Uint8Array,isProxy:()=>!1},jW=globalThis.TextDecoder,PS=globalThis.TextEncoder,rdt=(e,t)=>t?.(null,"127.0.0.1",4),ndt=class{},odt=globalThis.performance||{now:()=>Date.now()},sdt=class{observe(){}disconnect(){}},idt=()=>({enable:io,disable:io,percentile:()=>0}),adt=()=>({}),cdt=class{},ldt=()=>!1,udt=()=>new Uint8Array,ddt=io,pdt=class{},mdt=!0,hdt=null,fdt=null,gdt=()=>({}),ydt=class{},vdt=class{},wdt=globalThis.Buffer||class extends Uint8Array{static from(t,r){if(typeof t=="string"){const n=(r||"utf8").toLowerCase();if(n==="base64"){const o=atob(t),s=new Uint8Array(o.length);for(let i=0;i<o.length;i++)s[i]=o.charCodeAt(i);return s}if(n==="hex"){const o=new Uint8Array(t.length/2);for(let s=0;s<t.length;s+=2)o[s/2]=parseInt(t.substr(s,2),16);return o}return new PS().encode(t)}return new Uint8Array(t)}static alloc(t){return new Uint8Array(t)}static isBuffer(t){return t instanceof Uint8Array}static concat(t){const r=t.reduce((s,i)=>s+i.length,0),n=new Uint8Array(r);let o=0;for(const s of t)n.set(s,o),o+=s.length;return n}static byteLength(t,r){return r==="base64"?Math.ceil(t.length*3/4):new PS().encode(t).length}toString(t){const r=(t||"utf8").toLowerCase();if(r==="hex")return Array.from(new Uint8Array(this.buffer,this.byteOffset,this.byteLength)).map(n=>n.toString(16).padStart(2,"0")).join("");if(r==="base64"){let n="";for(let o=0;o<this.length;o++)n+=String.fromCharCode(this[o]);return btoa(n)}return new jW().decode(this)}},Tdt={F_OK:0,R_OK:4,W_OK:2,X_OK:1},bdt=()=>!1,Edt=()=>!1,_dt=()=>0,Sdt=class{},kdt=class{},xdt=async()=>new ArrayBuffer(0),VW=e=>({[Symbol.toPrimitive](){return e},ref(){return this},unref(){return this},hasRef(){return!1},refresh(){return this},close(){}}),Cdt=(...e)=>VW(globalThis.setTimeout(...e)),Adt=globalThis.clearTimeout,Idt=(...e)=>VW(globalThis.setInterval(...e)),Rdt=globalThis.clearInterval,Mdt=class{constructor(e){this.type=e}toString(){return this.type}}}}),Pdt,d$r,p$r,Odt,m$r,h$r,gP,Ddt,HW,f$r,g$r,y$r,v$r,w$r=_({"node-stub:stream/promises"(){Pdt=()=>{},d$r=globalThis.crypto,p$r=globalThis.ReadableStream||class{},Odt=Pdt,m$r=globalThis.URL,h$r=globalThis.URLSearchParams,gP=e=>{try{return JSON.stringify(e,null,2)}catch{return String(e)}},gP.custom=Symbol.for("nodejs.util.inspect.custom"),gP.colors={},gP.styles={},Ddt=globalThis.TextDecoder,HW=globalThis.TextEncoder,f$r=globalThis.performance||{now:()=>Date.now()},g$r=globalThis.Buffer||class extends Uint8Array{static from(t,r){if(typeof t=="string"){const n=(r||"utf8").toLowerCase();if(n==="base64"){const o=atob(t),s=new Uint8Array(o.length);for(let i=0;i<o.length;i++)s[i]=o.charCodeAt(i);return s}if(n==="hex"){const o=new Uint8Array(t.length/2);for(let s=0;s<t.length;s+=2)o[s/2]=parseInt(t.substr(s,2),16);return o}return new HW().encode(t)}return new Uint8Array(t)}static alloc(t){return new Uint8Array(t)}static isBuffer(t){return t instanceof Uint8Array}static concat(t){const r=t.reduce((s,i)=>s+i.length,0),n=new Uint8Array(r);let o=0;for(const s of t)n.set(s,o),o+=s.length;return n}static byteLength(t,r){return r==="base64"?Math.ceil(t.length*3/4):new HW().encode(t).length}toString(t){const r=(t||"utf8").toLowerCase();if(r==="hex")return Array.from(new Uint8Array(this.buffer,this.byteOffset,this.byteLength)).map(n=>n.toString(16).padStart(2,"0")).join("");if(r==="base64"){let n="";for(let o=0;o<this.length;o++)n+=String.fromCharCode(this[o]);return btoa(n)}return new Ddt().decode(this)}},y$r=globalThis.clearTimeout,v$r=globalThis.clearInterval}}),yP={};Z(yP,{Agent:()=>jdt,AsyncLocalStorage:()=>opt,Buffer:()=>tht,Channel:()=>jmt,DatabaseSync:()=>eht,Duplex:()=>ipt,EventEmitter:()=>npt,Http2ServerRequest:()=>iht,Http2ServerResponse:()=>aht,Interface:()=>Qmt,MIMEType:()=>mht,PassThrough:()=>apt,PerformanceObserver:()=>zmt,Readable:()=>KW,ReadableStream:()=>cpt,Resolver:()=>Umt,STATUS_CODES:()=>lmt,TextDecoder:()=>ZW,TextEncoder:()=>DS,Transform:()=>spt,URL:()=>Cmt,URLSearchParams:()=>Amt,Worker:()=>Kmt,Writable:()=>JW,access:()=>zpt,appendFile:()=>wpt,appendFileSync:()=>zdt,arch:()=>smt,arrayBuffer:()=>cht,availableParallelism:()=>gpt,basename:()=>Ydt,builtinModules:()=>_mt,callbackify:()=>Dmt,channel:()=>qmt,chmod:()=>fpt,chmodSync:()=>hpt,clearInterval:()=>pht,clearTimeout:()=>uht,closeSync:()=>_pt,connect:()=>umt,constants:()=>rht,copyFileSync:()=>bpt,cpSync:()=>Gdt,cpus:()=>tmt,createConnection:()=>dmt,createGunzip:()=>vmt,createGzip:()=>wmt,createHash:()=>WW,createHmac:()=>Fdt,createInterface:()=>Zmt,createReadStream:()=>Dpt,createRequire:()=>Emt,createServer:()=>qdt,createWriteStream:()=>Opt,debug:()=>Pmt,debuglog:()=>XW,default:()=>Ndt,deflateSync:()=>mmt,deprecate:()=>Omt,deserialize:()=>Wmt,dirname:()=>Jdt,exec:()=>Wpt,execFile:()=>Jpt,execFileSync:()=>Ypt,execSync:()=>Kpt,existsSync:()=>dpt,extname:()=>Xdt,fileURLToPath:()=>Imt,finished:()=>upt,format:()=>xmt,freemem:()=>rmt,fstatSync:()=>Spt,get:()=>cmt,gunzip:()=>ymt,gunzipSync:()=>hmt,gzip:()=>gmt,gzipSync:()=>fmt,hasSubscribers:()=>Vmt,homedir:()=>Zpt,hostname:()=>emt,inflateSync:()=>pmt,inherits:()=>Mmt,inspect:()=>OS,isAbsolute:()=>Qdt,isBuiltin:()=>Smt,isDeepStrictEqual:()=>Nmt,isIP:()=>sht,isIPv4:()=>oht,isIPv6:()=>nht,isMainThread:()=>Jmt,join:()=>Wdt,loadavg:()=>ypt,lookup:()=>$mt,lstatSync:()=>Cpt,mkdir:()=>Fpt,mkdirSync:()=>kpt,monitorEventLoopDelay:()=>Gmt,normalize:()=>rpt,ok:()=>Tmt,open:()=>jpt,openSync:()=>Ept,parentPort:()=>Ymt,parse:()=>kmt,pathToFileURL:()=>Rmt,performance:()=>Bmt,pipeline:()=>lpt,platform:()=>Xpt,posix:()=>tpt,promises:()=>Ldt,promisify:()=>YW,randomBytes:()=>$dt,randomUUID:()=>Udt,readFile:()=>Npt,readFileSync:()=>ppt,readdir:()=>Upt,readdirSync:()=>Apt,realpath:()=>Vpt,realpathSync:()=>Tpt,relative:()=>Zdt,release:()=>imt,rename:()=>Gpt,renameSync:()=>Rpt,request:()=>amt,resolve:()=>Kdt,rm:()=>qpt,rmSync:()=>Ppt,rmdirSync:()=>Mpt,sep:()=>ept,serialize:()=>Hmt,setImmediate:()=>vpt,setInterval:()=>dht,setTimeout:()=>lht,spawn:()=>Hpt,stat:()=>$pt,statSync:()=>xpt,strict:()=>bmt,tmpdir:()=>Qpt,toUSVString:()=>Lmt,totalmem:()=>nmt,type:()=>omt,types:()=>Fmt,unlink:()=>Bpt,unlinkSync:()=>Ipt,validateHeaderName:()=>Vdt,validateHeaderValue:()=>Hdt,webcrypto:()=>Bdt,workerData:()=>Xmt,writeFile:()=>Lpt,writeFileSync:()=>mpt});var ao,bn,Ndt,Ldt,WW,Fdt,$dt,Udt,Bdt,zdt,Gdt,qdt,jdt,Vdt,Hdt,Wdt,Kdt,Jdt,Ydt,Xdt,Zdt,Qdt,ept,tpt,rpt,npt,opt,KW,JW,spt,ipt,apt,cpt,lpt,upt,dpt,ppt,mpt,hpt,fpt,gpt,ypt,vpt,wpt,Tpt,bpt,Ept,_pt,Spt,kpt,xpt,Cpt,Apt,Ipt,Rpt,Mpt,Ppt,Opt,Dpt,Npt,Lpt,Fpt,$pt,Upt,Bpt,zpt,Gpt,qpt,jpt,Vpt,Hpt,Wpt,Kpt,Jpt,Ypt,Xpt,Zpt,Qpt,emt,tmt,rmt,nmt,omt,smt,imt,amt,cmt,lmt,umt,dmt,pmt,mmt,hmt,fmt,gmt,ymt,vmt,wmt,Tmt,bmt,Emt,_mt,Smt,kmt,xmt,Cmt,Amt,Imt,Rmt,Mmt,YW,XW,Pmt,OS,Omt,Dmt,Nmt,Lmt,Fmt,ZW,DS,$mt,Umt,Bmt,zmt,Gmt,qmt,jmt,Vmt,Hmt,Wmt,Kmt,Jmt,Ymt,Xmt,Zmt,Qmt,eht,tht,rht,nht,oht,sht,iht,aht,cht,QW,lht,uht,dht,pht,mht,vP=_({"node-stub:util"(){ao=()=>{},bn=async()=>{},Ndt={},Ldt={readFile:bn,writeFile:bn,mkdir:bn,stat:bn,readdir:bn,unlink:bn,access:bn,rm:bn,rename:bn},WW=e=>{const t=[];return{update(r){return t.push(typeof r=="string"?new DS().encode(r):r),this},digest(r){let n=0;for(const s of t)for(let i=0;i<s.length;i++)n=(n<<5)-n+s[i]|0;const o=(n>>>0).toString(16).padStart(8,"0");return r==="hex"?o:r==="base64"?btoa(o):o}}},Fdt=(e,t)=>WW(e),$dt=e=>new Uint8Array(e||32),Udt=()=>globalThis.crypto?.randomUUID?.()||Math.random().toString(36),Bdt=globalThis.crypto,zdt=()=>{throw new Error("[NeuroLink:browser] fs.appendFileSync is not supported in browser runtime \u2014 use server-side execution")},Gdt=()=>{throw new Error("[NeuroLink:browser] fs.cpSync is not supported in browser runtime \u2014 use server-side execution")},qdt=()=>({listen:ao,close:ao,on:ao}),jdt=class{constructor(){throw new Error("[NeuroLink:browser] Node HTTP agents require a server runtime")}},Vdt=ao,Hdt=ao,Wdt=(...e)=>e.join("/"),Kdt=(...e)=>e.join("/"),Jdt=e=>e||"",Ydt=e=>e?.split?.("/")?.pop?.()||"",Xdt=e=>{const t=e?.match?.(/\.[^.]+$/);return t?t[0]:""},Zdt=(e,t)=>t||"",Qdt=()=>!1,ept="/",tpt={normalize:e=>e,join:(...e)=>e.join("/"),resolve:(...e)=>e.join("/"),sep:"/"},rpt=e=>e,npt=class{constructor(){this._ev=new Map}_list(t){let r=this._ev.get(t);return r||(r=[],this._ev.set(t,r)),r}on(t,r){return this._list(t).push(r),this}addListener(t,r){return this.on(t,r)}prependListener(t,r){return this._list(t).unshift(r),this}once(t,r){const n=(...o)=>{this.off(t,n),r(...o)};return n.listener=r,this.on(t,n)}prependOnceListener(t,r){const n=(...o)=>{this.off(t,n),r(...o)};return n.listener=r,this.prependListener(t,n)}off(t,r){const n=this._ev.get(t);if(n){const o=n.findIndex(s=>s===r||s.listener===r);o>=0&&n.splice(o,1)}return this}removeListener(t,r){return this.off(t,r)}removeAllListeners(t){return t===void 0?this._ev.clear():this._ev.delete(t),this}emit(t,...r){const n=this._ev.get(t);if(!n||n.length===0){if(t==="error")throw r[0]instanceof Error?r[0]:new Error("Unhandled error.");return!1}for(const o of[...n])o.apply(this,r);return!0}listenerCount(t){return(this._ev.get(t)||[]).length}listeners(t){return[...this._ev.get(t)||[]]}rawListeners(t){return this.listeners(t)}eventNames(){return[...this._ev.keys()]}setMaxListeners(){return this}getMaxListeners(){return 10}},opt=class{getStore(){}run(e,t,...r){return t(...r)}enterWith(){}disable(){}},KW=class{pipe(){return this}on(){return this}read(){return null}push(){}destroy(){}},JW=class{write(){return!0}end(){}on(){return this}destroy(){}},spt=class{push(){}on(){return this}},ipt=class{on(){return this}},apt=class{pipe(){return this}on(){return this}},cpt=globalThis.ReadableStream||class{},lpt=ao,upt=ao,dpt=()=>!1,ppt=()=>"",mpt=ao,hpt=ao,fpt=bn,gpt=()=>1,ypt=()=>[0,0,0],vpt=bn,wpt=bn,Tpt=e=>e,bpt=ao,Ept=()=>0,_pt=ao,Spt=()=>({}),kpt=ao,xpt=()=>({}),Cpt=()=>({isSymbolicLink:()=>!1}),Apt=()=>[],Ipt=ao,Rpt=ao,Mpt=ao,Ppt=ao,Opt=()=>new JW,Dpt=()=>new KW,Npt=bn,Lpt=bn,Fpt=bn,$pt=bn,Upt=bn,Bpt=bn,zpt=bn,Gpt=bn,qpt=bn,jpt=async()=>({stat:bn,readFile:bn,close:bn,read:bn,write:bn}),Vpt=async e=>e,Hpt=()=>({on:ao,stdout:{on:ao},stderr:{on:ao},kill:ao}),Wpt=(e,t)=>t?.(null,"",""),Kpt=()=>"",Jpt=(e,t,r)=>{typeof t=="function"?t(null,"",""):r?.(null,"","")},Ypt=()=>"",Xpt="browser",Zpt=()=>"/",Qpt=()=>"/tmp",emt=()=>"browser",tmt=()=>[{}],rmt=()=>0,nmt=()=>0,omt=()=>"Browser",smt=()=>"wasm",imt=()=>"0",amt=()=>({}),cmt=()=>({}),lmt={100:"Continue",101:"Switching Protocols",200:"OK",201:"Created",202:"Accepted",204:"No Content",206:"Partial Content",301:"Moved Permanently",302:"Found",304:"Not Modified",307:"Temporary Redirect",308:"Permanent Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Payload Too Large",414:"URI Too Long",415:"Unsupported Media Type",416:"Range Not Satisfiable",417:"Expectation Failed",422:"Unprocessable Entity",425:"Too Early",426:"Upgrade Required",428:"Precondition Required",429:"Too Many Requests",431:"Request Header Fields Too Large",451:"Unavailable For Legal Reasons",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported"},umt=()=>({}),dmt=()=>({}),pmt=()=>new Uint8Array,mmt=()=>new Uint8Array,hmt=()=>new Uint8Array,fmt=()=>new Uint8Array,gmt=(e,t)=>t?.(null,e),ymt=(e,t)=>t?.(null,e),vmt=()=>({}),wmt=()=>({}),Tmt=ao,bmt={},Emt=()=>()=>({}),_mt=[],Smt=()=>!1,kmt=e=>({pathname:e||"",hostname:"",protocol:"",search:"",hash:""}),xmt=()=>"",Cmt=globalThis.URL,Amt=globalThis.URLSearchParams,Imt=e=>typeof e=="string"?e.replace("file://",""):e,Rmt=e=>new globalThis.URL("file://"+e),Mmt=(e,t)=>{t&&(e.super_=t,Object.setPrototypeOf(e.prototype,t.prototype))},YW=e=>(...t)=>new Promise((r,n)=>e(...t,(o,s)=>o?n(o):r(s))),XW=e=>{const t=(...r)=>{};return t.enabled=!1,t},Pmt=XW,OS=e=>{try{return JSON.stringify(e,null,2)}catch{return String(e)}},OS.custom=Symbol.for("nodejs.util.inspect.custom"),OS.colors={},OS.styles={},Omt=e=>e,Dmt=e=>(...t)=>{const r=t.pop();e(...t).then(n=>r(null,n)).catch(r)},Nmt=(e,t)=>JSON.stringify(e)===JSON.stringify(t),Lmt=e=>String(e),Fmt={isPromise:e=>e instanceof Promise,isDate:e=>e instanceof Date,isRegExp:e=>e instanceof RegExp,isNativeError:e=>e instanceof Error,isArrayBuffer:e=>e instanceof ArrayBuffer,isTypedArray:e=>ArrayBuffer.isView(e),isUint8Array:e=>e instanceof Uint8Array,isProxy:()=>!1},ZW=globalThis.TextDecoder,DS=globalThis.TextEncoder,$mt=(e,t)=>t?.(null,"127.0.0.1",4),Umt=class{},Bmt=globalThis.performance||{now:()=>Date.now()},zmt=class{observe(){}disconnect(){}},Gmt=()=>({enable:ao,disable:ao,percentile:()=>0}),qmt=()=>({}),jmt=class{},Vmt=()=>!1,Hmt=()=>new Uint8Array,Wmt=ao,Kmt=class{},Jmt=!0,Ymt=null,Xmt=null,Zmt=()=>({}),Qmt=class{},eht=class{},tht=globalThis.Buffer||class extends Uint8Array{static from(t,r){if(typeof t=="string"){const n=(r||"utf8").toLowerCase();if(n==="base64"){const o=atob(t),s=new Uint8Array(o.length);for(let i=0;i<o.length;i++)s[i]=o.charCodeAt(i);return s}if(n==="hex"){const o=new Uint8Array(t.length/2);for(let s=0;s<t.length;s+=2)o[s/2]=parseInt(t.substr(s,2),16);return o}return new DS().encode(t)}return new Uint8Array(t)}static alloc(t){return new Uint8Array(t)}static isBuffer(t){return t instanceof Uint8Array}static concat(t){const r=t.reduce((s,i)=>s+i.length,0),n=new Uint8Array(r);let o=0;for(const s of t)n.set(s,o),o+=s.length;return n}static byteLength(t,r){return r==="base64"?Math.ceil(t.length*3/4):new DS().encode(t).length}toString(t){const r=(t||"utf8").toLowerCase();if(r==="hex")return Array.from(new Uint8Array(this.buffer,this.byteOffset,this.byteLength)).map(n=>n.toString(16).padStart(2,"0")).join("");if(r==="base64"){let n="";for(let o=0;o<this.length;o++)n+=String.fromCharCode(this[o]);return btoa(n)}return new ZW().decode(this)}},rht={F_OK:0,R_OK:4,W_OK:2,X_OK:1},nht=()=>!1,oht=()=>!1,sht=()=>0,iht=class{},aht=class{},cht=async()=>new ArrayBuffer(0),QW=e=>({[Symbol.toPrimitive](){return e},ref(){return this},unref(){return this},hasRef(){return!1},refresh(){return this},close(){}}),lht=(...e)=>QW(globalThis.setTimeout(...e)),uht=globalThis.clearTimeout,dht=(...e)=>QW(globalThis.setInterval(...e)),pht=globalThis.clearInterval,mht=class{constructor(e){this.type=e}toString(){return this.type}}}}),_u=_({"src/lib/processors/config/index.ts"(){"use strict";LW(),Bat(),mit()}});function T$r(e,t,r){const n=Zwe[e],o={code:e,message:n.message,userMessage:n.userMessage,suggestedAction:n.suggestedAction,retryable:n.retryable};t&&Object.keys(t).length>0&&(o.details=t);const s=r?.message||t?.technicalDetails;return s&&(o.technicalDetails=s),r&&(o.originalError=r),o}function hht(e){if(!e)return null;if(e instanceof Error){const t=[/HTTP\s*(\d{3})/i,/status[:\s]+(\d{3})/i,/statusCode[:\s]+(\d{3})/i,/\b(\d{3})\s+(?:Not Found|Unauthorized|Forbidden|Internal Server Error|Bad Gateway|Service Unavailable|Gateway Timeout)/i];for(const r of t){const n=e.message.match(r);if(n?.[1])return parseInt(n[1],10)}}if(typeof e=="object"&&e!==null){const t=e;if(typeof t.status=="number")return t.status;if(typeof t.statusCode=="number")return t.statusCode;if(typeof t.response=="object"&&t.response!==null){const r=t.response;if(typeof r.status=="number")return r.status}}return null}function b$r(e){if(E$r(e))return e.retryable??!1;if(e instanceof Error){if(cr(e))return!1;if(["TimeoutError","FetchError"].includes(e.name))return!0;const n=e.message.toLowerCase();if(/http\s*5\d{2}/i.test(e.message)||/http\s*429/i.test(e.message)||n.includes("rate limit")||/http\s*408/i.test(e.message)||["econnreset","etimedout","econnrefused","enotfound","enetunreach","ehostunreach","epipe","socket hang up","network error","connection refused","connection reset","dns lookup failed"].some(s=>n.includes(s))||n.includes("temporary")||n.includes("try again"))return!0}const t=hht(e);return t!==null&&(t>=500&&t<600||t===408||t===429)}function E$r(e){if(typeof e!="object"||e===null)return!1;const t=e;return typeof t.code=="string"&&typeof t.message=="string"&&typeof t.userMessage=="string"&&typeof t.retryable=="boolean"}var _$r=_({"src/lib/processors/errors/errorHelpers.ts"(){"use strict";et(),Qwe()}}),S$r=_({"src/lib/processors/errors/index.ts"(){"use strict";_$r()}});function wP(e,t){const r=new Error(`Download exceeds the maximum size of ${e} MB for ${t}`);return r.code=eK,r}function k$r(e){return e?.code===eK}function x$r(e){const t=new Error(e);return t.code=tK,t}function fht(e){return e?.code===tK}function C$r(e){return e?.code==="ERR_BUFFER_TOO_LARGE"}var ght,eK,tK,Id,om=_({"src/lib/processors/base/BaseFileProcessor.ts"(){"use strict";vP(),Qh(),et(),Fr(),mr(),S$r(),dt(),ght=YW(Y7),eK="DOWNLOAD_TOO_LARGE",tK="CONTENT_TOO_LARGE",Id=class{config;constructor(e){this.config=e}getConfig(){return this.config}async processFile(e,t){return pt({name:"neurolink.file.process",tracer:Be.file,attributes:{"file.processor":this.constructor.name,"file.type":this.config.fileTypeName,"file.mimetype":e.mimetype??"unknown","file.name":e.name??"unknown"}},async r=>{try{const n=this.validateFileWithResult(e);if(!n.success)return{success:!1,error:n.error};let o;if(e.buffer)o=e.buffer;else if(e.url){const i=await this.downloadFileWithRetry(e,t);if(!i.success)return{success:!1,error:i.error};if(!i.data)return{success:!1,error:this.createError("DOWNLOAD_FAILED",{reason:"Download succeeded but returned no data"})};if(o=i.data,!this.validateFileSize(o.length))return{success:!1,error:this.createError("FILE_TOO_LARGE",{sizeMB:(o.length/(1024*1024)).toFixed(2),maxMB:this.config.maxSizeMB,type:this.config.fileTypeName})}}else return{success:!1,error:this.createError("DOWNLOAD_FAILED",{reason:"No buffer or URL provided for file"})};const s=await this.validateDownloadedFileWithResult(o,e);return s.success?await this.buildProcessedResultWithResult(o,e):{success:!1,error:s.error}}catch(n){return{success:!1,error:this.createError("UNKNOWN_ERROR",{error:n instanceof Error?n.message:String(n)},n instanceof Error?n:void 0)}}})}async processFiles(e,t,r){const n=[],o=[],s=[],i=[],a=[];for(const c of e){const l=await t(c);if(!l){s.push({fileId:c,filename:"unknown",mimetype:"unknown",size:0,error:this.createError("FILE_NOT_FOUND")});continue}const u=await this.processFile(l,r);u.success&&u.data?(n.push(u.data),o.push({fileId:l.id,filename:l.name||"unknown",mimetype:l.mimetype,size:l.size,processorType:this.config.fileTypeName})):u.error&&(u.error.code==="UNSUPPORTED_TYPE"?i.push({fileId:l.id,filename:l.name||"unknown",mimetype:l.mimetype,size:l.size,reason:u.error.message}):s.push({fileId:l.id,filename:l.name||"unknown",mimetype:l.mimetype,size:l.size,error:u.error}))}return{totalFiles:e.length,processedFiles:o,failedFiles:s,skippedFiles:i,warnings:a,results:n}}isFileSupported(e,t){return this.isSupportedMimeType(e)||this.isSupportedExtension(t)}async validateDownloadedFile(e,t){return null}async validateDownloadedFileWithResult(e,t){const r=await this.validateDownloadedFile(e,t);return r?{success:!1,error:this.createError("INVALID_FORMAT",{reason:r})}:{success:!0,data:void 0}}async buildProcessedResultWithResult(e,t){try{return{success:!0,data:await this.buildProcessedResult(e,t)}}catch(r){return fht(r)?{success:!1,error:this.createError("FILE_TOO_LARGE",{maxMB:this.config.maxSizeMB,type:this.config.fileTypeName,reason:r instanceof Error?r.message:void 0})}:{success:!1,error:this.createError("PROCESSING_FAILED",{fileType:this.config.fileTypeName},r instanceof Error?r:void 0)}}}getFilename(e){return e.name||this.config.defaultFilename}async downloadFile(e,t,r){const n=new AbortController,o=r??this.config.timeoutMs,s=setTimeout(()=>{n.abort()},o);try{const i={...t},a=await fetch(e,{headers:i,signal:n.signal});if(!a.ok)throw new Error(`HTTP ${a.status}: ${a.statusText}`);const c=a.headers.get("Content-Type");if(c&&c.includes("text/html"))throw new Error(`Received HTML response instead of file content (Content-Type: ${c}). This usually means the download URL returned an error page.`);const l=this.config.maxSizeMB*1024*1024;let u=await this.readBodyWithinLimit(a,l);const d=a.headers.get("Content-Encoding"),p=u.length>=2&&u[0]===31&&u[1]===139;if(d?.toLowerCase().includes("gzip")&&p)try{u=Buffer.from(await ght(u,{maxOutputLength:l}))}catch(h){throw C$r(h)?wP(this.config.maxSizeMB,this.config.fileTypeName):new Error(`Failed to decompress gzip response: ${h instanceof Error?h.message:String(h)}`,{cause:h})}return u}finally{clearTimeout(s),n.abort()}}async readBodyWithinLimit(e,t){const r=Number(e.headers.get("Content-Length"));if(Number.isFinite(r)&&r>t)throw await e.body?.cancel(),wP(this.config.maxSizeMB,this.config.fileTypeName);if(!e.body){const i=Buffer.from(await e.arrayBuffer());if(i.length>t)throw wP(this.config.maxSizeMB,this.config.fileTypeName);return i}const n=e.body.getReader(),o=[];let s=0;for(;;){const{done:i,value:a}=await n.read();if(i)break;if(a){if(s+=a.byteLength,s>t)throw await n.cancel(),wP(this.config.maxSizeMB,this.config.fileTypeName);o.push(Buffer.from(a))}}return Buffer.concat(o,s)}async downloadFileWithRetry(e,t){const r=e.url;if(!r)return{success:!1,error:this.createError("DOWNLOAD_FAILED",{reason:"No URL provided for download"})};const n=t?.retryConfig??dG;let o;for(let s=0;s<=n.maxRetries;s++)try{return{success:!0,data:await this.downloadFile(r,t?.authHeaders,t?.timeout)}}catch(i){if(o=i instanceof Error?i:new Error(String(i)),s<n.maxRetries&&(n.retryOn?n.retryOn(o):b$r(o))){const c=Math.min(n.baseDelayMs*2**s,n.maxDelayMs);await this.sleep(c);continue}break}return{success:!1,error:this.classifyDownloadError(o)}}validateFileWithResult(e){if(!this.isFileSupported(e.mimetype,e.name||""))return{success:!1,error:this.createError("UNSUPPORTED_TYPE",{format:e.mimetype||e.name?.split(".").pop()||"unknown",supportedFormats:this.config.supportedMimeTypes.length>0?this.config.supportedMimeTypes.join(", "):this.config.supportedExtensions.join(", "),type:this.config.fileTypeName})};if(!this.validateFileSize(e.size)){const t=this.formatSizeMB(e.size);return{success:!1,error:this.createError("FILE_TOO_LARGE",{sizeMB:t,maxMB:this.config.maxSizeMB,type:this.config.fileTypeName})}}return{success:!0,data:void 0}}validateFileSize(e){const t=this.config.maxSizeMB*1024*1024;return e<=t}isSupportedMimeType(e){return e?this.config.supportedMimeTypes.includes(e.toLowerCase()):!1}isSupportedExtension(e){if(!e)return!1;const t=e.toLowerCase();return this.config.supportedExtensions.some(r=>t.endsWith(r))}formatSizeMB(e){return(e/(1024*1024)).toFixed(2)}createError(e,t,r){return T$r(e,t,r)}classifyDownloadError(e){if(k$r(e))return this.createError("FILE_TOO_LARGE",{maxMB:this.config.maxSizeMB,type:this.config.fileTypeName},e);if(cr(e))return this.createError("DOWNLOAD_TIMEOUT",{timeoutMs:this.config.timeoutMs},e);if(e.message.includes("HTTP")){const t=hht(e);return t===404?this.createError("FILE_NOT_FOUND",{},e):t===401||t===403?this.createError("DOWNLOAD_AUTH_FAILED",{httpStatus:t},e):t===429?this.createError("RATE_LIMITED",{},e):this.createError("NETWORK_ERROR",{httpStatus:t},e)}return e.message.includes("decompress")?this.createError("DECOMPRESSION_FAILED",{},e):this.createError("DOWNLOAD_FAILED",{},e)}sleep(e){return new Promise(t=>setTimeout(t,e))}}}}),TP={};Z(TP,{VideoProcessor:()=>oK,assertFluentFfmpegShape:()=>yht,isVideoFile:()=>I$r,processVideo:()=>R$r,videoProcessor:()=>EP});function yht(e){const t=e;if(typeof e!="function"||typeof t.ffprobe!="function"||typeof t.setFfmpegPath!="function")throw new Error(`The installed "fluent-ffmpeg" package does not export a callable with ffprobe and setFfmpegPath statics (got ${typeof e}). Reinstall a compatible version:
818
818
  pnpm add fluent-ffmpeg`)}async function bP(){const t=(await Ka("fluent-ffmpeg","Video processing")).default;return yht(t),t}async function A$r(){return NS||(NS=await Ka("mediabunny","Video processing"),NS)}async function vht(){try{return(await Ka("sharp","Video keyframe resizing")).default}catch(e){throw rK||(rK=!0,m.warn("[VideoProcessor] sharp is required to resize extracted keyframes but failed to load; keyframe extraction will return no frames",{error:e instanceof Error?e.message:String(e)})),e}}async function wht(){if(!nK){nK=!0;try{const t=(await Promise.resolve().then(()=>(ant(),qH))).default;typeof t=="string"&&js(t)&&(await bP()).setFfmpegPath(t)}catch{}}}function I$r(e,t){return EP.isFileSupported(e,t)}async function R$r(e,t){return EP.processFile(e,t)}var NS,rK,nK,Nn,Tht,bht,Eht,_ht,oK,EP,sK=_({"src/lib/processors/media/VideoProcessor.ts"(){"use strict";Nt(),an(),ki(),hr(),Bh(),w$r(),om(),$W(),_u(),wf(),ja(),z(),Eu(),et(),TS(),NS=null,rK=!1,nK=!1,Nn={MAX_FRAMES:100,FRAME_INTERVALS:[{maxDuration:10,intervalSec:1},{maxDuration:30,intervalSec:2},{maxDuration:120,intervalSec:3},{maxDuration:600,intervalSec:6},{maxDuration:1800,intervalSec:20},{maxDuration:1/0,intervalSec:60}],FRAME_MAX_DIMENSION:768,FRAME_JPEG_QUALITY:80,FFMPEG_TIMEOUT_MS:12e4,FFPROBE_TIMEOUT_MS:1e4,AUDIO_EXTRACT_TIMEOUT_MS:18e4,TRANSCRIPTION_TIMEOUT_MS:12e4,WHISPER_MAX_SIZE_MB:25},Tht=AQe("video"),bht=kd("video"),Eht=xc.VIDEO_MAX_MB,_ht=12e4,oK=class Gwr extends Id{constructor(){super({maxSizeMB:Eht,timeoutMs:_ht,supportedMimeTypes:[...Tht],supportedExtensions:[...bht],fileTypeName:"video",defaultFilename:"video.mp4"})}buildProcessedResult(t,r){return{buffer:t,mimetype:r.mimetype||"video/mp4",size:r.size,filename:this.getFilename(r),textContent:"",keyframes:[],keyframeTimestampsSec:[],hasTranscript:!1,metadata:{duration:0,durationFormatted:RS(0),width:0,height:0,codec:"unknown",fps:0,bitrate:0,subtitleTracks:0,fileSize:r.size},hasKeyframes:!1,frameCount:0}}async processFile(t,r){const n=this.getFilename(t),o=t.size||t.buffer?.length||0;return pt({name:"neurolink.file.video.process",tracer:Be.file,attributes:{[Ae.FILE_NAME]:n,[Ae.FILE_MIMETYPE]:t.mimetype||"video/mp4",[Ae.FILE_SIZE_BYTES]:o}},async s=>{m.info(`[NEUROLINK] Video processing started: ${n} (${(o/(1024*1024)).toFixed(2)} MB, ${t.mimetype||"video/mp4"})`),await wht();const i=At(fP(),`neurolink-video-${Qe()}`);let a=!1;try{const c=this.validateFileWithResult(t);if(!c.success){const T=c.error?.message||"Validation failed";return s.setAttribute(Ae.FILE_SUCCESS,!1),s.setAttribute(Ae.FILE_ERROR,T),m.warn(`[NEUROLINK] Video skipped/failed: ${n} \u2014 reason: ${T}`),{success:!1,error:c.error}}let l;if(t.buffer)l=t.buffer;else if(t.url){const T=await this.downloadFileWithRetry(t,r);if(!T.success){const b=T.error?.message||"Download failed";return s.setAttribute(Ae.FILE_SUCCESS,!1),s.setAttribute(Ae.FILE_ERROR,b),m.warn(`[NEUROLINK] Video skipped/failed: ${n} \u2014 reason: ${b}`),{success:!1,error:T.error}}if(!T.data){const b="Download succeeded but returned no data";return s.setAttribute(Ae.FILE_SUCCESS,!1),s.setAttribute(Ae.FILE_ERROR,b),m.warn(`[NEUROLINK] Video skipped/failed: ${n} \u2014 reason: ${b}`),{success:!1,error:this.createError("DOWNLOAD_FAILED",{reason:b})}}if(l=T.data,!this.validateFileSize(l.length)){const b=`File too large: ${(l.length/1048576).toFixed(2)} MB (max: ${this.config.maxSizeMB} MB)`;return s.setAttribute(Ae.FILE_SUCCESS,!1),s.setAttribute(Ae.FILE_ERROR,b),m.warn(`[NEUROLINK] Video skipped/failed: ${n} \u2014 reason: ${b}`),{success:!1,error:this.createError("FILE_TOO_LARGE",{sizeMB:(l.length/(1024*1024)).toFixed(2),maxMB:this.config.maxSizeMB,type:this.config.fileTypeName})}}}else{const T="No buffer or URL provided for file";return s.setAttribute(Ae.FILE_SUCCESS,!1),s.setAttribute(Ae.FILE_ERROR,T),m.warn(`[NEUROLINK] Video skipped/failed: ${n} \u2014 reason: ${T}`),{success:!1,error:this.createError("DOWNLOAD_FAILED",{reason:T})}}await qs.mkdir(i,{recursive:!0}),a=!0;const u=this.getExtensionFromFileInfo(t),d=At(i,`input${u}`);await this.writeBufferToFile(l,d);let p;const h=await this.probeVideoWithMediabunny(d);if(h.success&&h.data)p={...h.data,fileSize:l.length};else{const T=await this.probeVideo(d);T.success&&T.data&&(p=this.buildMetadata(T.data,l.length))}if(!p){const T=await this.probeVideoWithFfmpeg(d);T.success&&T.data?p={...T.data,fileSize:l.length}:m.warn(`[NEUROLINK] No metadata could be read for ${n} (mediabunny, ffprobe and ffmpeg all failed), so no keyframes will be extracted: ${T.error}`)}p||(p={duration:0,durationFormatted:"unknown",width:0,height:0,codec:"unknown",fps:0,bitrate:0,subtitleTracks:0,fileSize:l.length}),s.setAttribute(Ae.VIDEO_DURATION_SEC,p.duration),s.setAttribute(Ae.VIDEO_WIDTH,p.width),s.setAttribute(Ae.VIDEO_HEIGHT,p.height),s.setAttribute(Ae.VIDEO_CODEC,p.codec),s.setAttribute(Ae.VIDEO_HAS_SUBTITLES,p.subtitleTracks>0);let f=[];try{f=await this.extractKeyframes(d,i,p.duration,r)}catch{m.warn(`[NEUROLINK] Video keyframe extraction failed for ${n}, continuing without keyframes`)}s.setAttribute(Ae.VIDEO_KEYFRAMES_EXTRACTED,f.length),m.shouldLog("debug")&&f.length>0&&m.debug(`[NEUROLINK] Video keyframe timestamps: ${f.map(T=>T.timestampSec.toFixed(3)).join(",")}`);let g;if(p.subtitleTracks>0)try{g=await this.extractSubtitles(d,i)}catch{}const y=await this.extractAndTranscribeAudio(d,i,p,n,r),v=this.buildTextContent(p,f.map(T=>T.timestampSec),g,this.getFilename(t),y.transcript);return s.setAttribute(Ae.VIDEO_TEXT_CONTENT_LENGTH,v.length),s.setAttribute(Ae.FILE_OUTPUT_LENGTH,v.length),s.setAttribute(Ae.FILE_SUCCESS,!0),m.info(`[NEUROLINK] Video processed: ${n} \u2192 ${v.length} bytes text + ${f.length} keyframes (${p.durationFormatted}, ${p.width}x${p.height}, ${p.codec})`),{success:!0,data:{buffer:l,mimetype:t.mimetype||"video/mp4",size:t.size,filename:this.getFilename(t),textContent:v,keyframes:f.map(T=>T.buffer),keyframeTimestampsSec:f.map(T=>T.timestampSec),metadata:p,subtitleText:g,transcript:y.transcript,hasTranscript:!!y.transcript,...y.skippedReason?{transcriptionSkippedReason:y.skippedReason}:{},hasKeyframes:f.length>0,frameCount:f.length}}}catch(c){const l=c instanceof Error?c.message:String(c);return s.setAttribute(Ae.FILE_SUCCESS,!1),s.setAttribute(Ae.FILE_ERROR,l),m.error(`[NEUROLINK] Video processing failed: ${n} \u2014 ${l}`),{success:!1,error:this.createError("PROCESSING_FAILED",{fileType:"video",error:l},c instanceof Error?c:void 0)}}finally{a&&await qs.rm(i,{recursive:!0,force:!0}).catch(()=>{})}})}async probeVideo(t){const r=await bP();return new Promise(n=>{const o=setTimeout(()=>{n({success:!1,error:`ffprobe timed out after ${Nn.FFPROBE_TIMEOUT_MS}ms`})},Nn.FFPROBE_TIMEOUT_MS);r.ffprobe(t,(s,i)=>{clearTimeout(o),n(s?{success:!1,error:`ffprobe failed: ${s.message}`}:{success:!0,data:i})})})}async probeVideoWithMediabunny(t){const r=await A$r();let n;try{n=new r.Input({source:new r.FilePathSource(t),formats:[...r.ALL_FORMATS]});const o=await n.computeDuration(),s=await n.getPrimaryVideoTrack(),i=await n.getPrimaryAudioTrack(),c=(await n.getTracks()).filter(u=>!u.isVideoTrack()&&!u.isAudioTrack());let l=0;if(s)try{const u=await s.computePacketStats(120);l=Math.round(u.averagePacketRate*100)/100}catch{}return{success:!0,data:{duration:o??0,durationFormatted:this.formatDuration(o??0),width:s?.displayWidth??0,height:s?.displayHeight??0,codec:s?.codec??"unknown",fps:l,bitrate:0,audioCodec:i?.codec??void 0,audioChannels:i?.numberOfChannels,audioSampleRate:i?.sampleRate,subtitleTracks:c.length,fileSize:0}}}catch(o){return{success:!1,error:`mediabunny failed: ${o instanceof Error?o.message:String(o)}`}}finally{n?.dispose()}}async probeVideoWithFfmpeg(t){let r;try{const{stderr:o}=await bf(["-hide_banner","-i",t,"-t","0","-f","null","-"],{timeoutMs:Nn.FFPROBE_TIMEOUT_MS});r=o}catch(o){const s=o.stderr;if(typeof s!="string")return{success:!1,error:`ffmpeg probe failed: ${o instanceof Error?o.message:String(o)}`};r=s}const n=this.parseFfmpegInputReport(r);return n?{success:!0,data:n}:{success:!1,error:"ffmpeg reported no duration"}}parseFfmpegInputReport(t){const r=t.split(/\r?\n/),n=r.findIndex(y=>y.startsWith("Output #")),o=n===-1?r:r.slice(0,n),s=o.join(`
819
819
  `),i=/Duration:\s*(\d+):(\d{2}):(\d{2}(?:\.\d+)?)/.exec(s);if(!i)return;const a=Number(i[1])*3600+Number(i[2])*60+Number(i[3]);if(!(a>0))return;const c=o.flatMap(y=>{const v=/^\s*Stream #\d+:\d+(?:\[[^\]]*\])?(?:\([^)]*\))?:\s*(Video|Audio|Subtitle):\s*(.*)$/.exec(y);return v?[{kind:v[1],details:v[2]}]:[]}),l=c.find(y=>y.kind==="Video"&&!y.details.includes("attached pic")),u=c.find(y=>y.kind==="Audio"),d=l?/(?:^|[\s,])(\d{2,5})x(\d{2,5})(?=[\s,[]|$)/.exec(l.details):null,p=l?/,\s*(\d+(?:\.\d+)?)\s*(?:fps|tbr)/.exec(l.details):null,h=/bitrate:\s*(\d+)\s*kb\/s/.exec(s),f=u?/(\d+)\s*Hz/.exec(u.details):null,g=u?/Hz,\s*([^,]+)/.exec(u.details):null;return{duration:a,durationFormatted:this.formatDuration(a),width:d?Number(d[1]):0,height:d?Number(d[2]):0,codec:l?/^([^\s,(]+)/.exec(l.details)?.[1]??"unknown":"unknown",fps:p?Number(p[1]):0,bitrate:h?Number(h[1])*1e3:0,audioCodec:u?/^([^\s,(]+)/.exec(u.details)?.[1]:void 0,audioChannels:g?this.channelCountFromLayout(g[1]):void 0,audioSampleRate:f?Number(f[1]):void 0,subtitleTracks:c.filter(y=>y.kind==="Subtitle").length,fileSize:0}}channelCountFromLayout(t){const r=new Map([["mono",1],["stereo",2],["quad",4]]),n=t.trim(),o=r.get(n);if(o!==void 0)return o;const s=/^(\d+) channels?/.exec(n);if(s)return Number(s[1]);const i=/^(\d+)\.(\d)/.exec(n);return i?Number(i[1])+Number(i[2]):void 0}buildMetadata(t,r){const n=t.streams.find(c=>c.codec_type==="video"),o=t.streams.find(c=>c.codec_type==="audio"),s=t.streams.filter(c=>c.codec_type==="subtitle"),i=t.format?.duration?parseFloat(String(t.format.duration)):0;let a=0;if(n?.r_frame_rate){const c=String(n.r_frame_rate).split("/");if(c.length===2){const l=parseFloat(c[0]),u=parseFloat(c[1]);u>0&&(a=Math.round(l/u*100)/100)}else a=parseFloat(c[0])||0}return{duration:i,durationFormatted:this.formatDuration(i),width:n?.width??0,height:n?.height??0,codec:n?.codec_name??"unknown",fps:a,bitrate:t.format?.bit_rate?parseInt(String(t.format.bit_rate),10):0,audioCodec:o?.codec_name,audioChannels:o?.channels,audioSampleRate:o?.sample_rate?parseInt(String(o.sample_rate),10):void 0,subtitleTracks:s.length,fileSize:r}}static resolveFrameQuality(t){return typeof t!="number"||!Number.isFinite(t)?Nn.FRAME_JPEG_QUALITY:Math.min(100,Math.max(1,Math.round(t)))}async extractAndTranscribeAudio(t,r,n,o,s){if(!s?.transcribeAudio)return{};const i=g=>(m.warn(`[VideoProcessor] No transcript for ${o}: ${g}. The model will receive the keyframes and metadata only.`),{skippedReason:g});if(!n.audioCodec)return i("the video has no audio track");const a=process.env.OPENAI_API_KEY;if(!a)return i("OPENAI_API_KEY is not set, and Whisper is the only transcription backend wired up");const c=At(r,"audio.mp3");try{await bf(["-y","-v","error","-i",t,"-vn","-ac","1","-ar","16000","-c:a","libmp3lame","-q:a","4",c],{timeoutMs:Nn.AUDIO_EXTRACT_TIMEOUT_MS})}catch(g){const y=g instanceof Error?g.message.split(`
820
- `)[0]:String(g);return i(`the audio track could not be extracted \u2014 ${y}`)}let l;try{l=await qs.readFile(c)}catch{return i("ffmpeg reported success but wrote no audio file")}if(l.length===0)return i("the extracted audio track was empty");const u=l.length/(1024*1024);if(u>Nn.WHISPER_MAX_SIZE_MB)return i(`the extracted audio is ${u.toFixed(1)}MB, over Whisper's ${Nn.WHISPER_MAX_SIZE_MB}MB limit \u2014 split the recording`);const d=(process.env.OPENAI_BASE_URL??"https://api.openai.com/v1").replace(/\/+$/,""),p=new FormData;p.append("file",new Blob([new Uint8Array(l)],{type:"audio/mpeg"}),"audio.mp3"),p.append("model","whisper-1"),p.append("response_format","verbose_json");const h=new AbortController,f=setTimeout(()=>h.abort(),Nn.TRANSCRIPTION_TIMEOUT_MS);try{const g=await ze(fetch(`${d}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${a}`},body:p,signal:h.signal}),Nn.TRANSCRIPTION_TIMEOUT_MS);if(!g.ok){const T=await g.text().catch(()=>"");return i(`the transcription request failed \u2014 HTTP ${g.status}${T?`: ${T.slice(0,200)}`:""}`)}const y=await g.json(),v=typeof y=="object"&&y!==null&&typeof y.text=="string"?y.text.trim():"";return v.length===0?i("Whisper returned an empty transcript for this audio"):(m.debug(`[VideoProcessor] Transcribed ${o} via openai-whisper (${v.length} chars)`),{transcript:v})}catch(g){const y=g instanceof Error?g.message:String(g);return i(`the transcription request failed \u2014 ${y}`)}finally{clearTimeout(f)}}async extractKeyframes(t,r,n,o){if(n<=0)return[];const s=o?.frames,i=typeof s=="number"&&Number.isFinite(s)&&s>0,a=i?Math.min(Math.floor(s),Nn.MAX_FRAMES):Nn.MAX_FRAMES,c=i?Math.max(n/a,Number.EPSILON):this.getFrameInterval(n),l=[];for(let h=0;h<n&&l.length<a;h+=c)l.push(h);l.length===0&&l.push(0);const u=At(r,"frames");await qs.mkdir(u,{recursive:!0});const d=await this.runFfmpegFrameExtraction(t,u,l,c),p=[];for(let h=0;h<l.length;h++){const f=At(u,`frame_${String(h+1).padStart(4,"0")}.jpg`);try{await qs.access(f);const g=await qs.readFile(f),v=(await vht())(g).resize(Nn.FRAME_MAX_DIMENSION,Nn.FRAME_MAX_DIMENSION,{fit:"inside",withoutEnlargement:!0}),T=Gwr.resolveFrameQuality(o?.quality),b=await(o?.format==="png"?v.png({quality:T}):v.jpeg({quality:T})).toBuffer(),S=d[h]??l[h];p.push({buffer:b,timestampSec:S})}catch{}}return p}async runFfmpegFrameExtraction(t,r,n,o){const s=await bP();return new Promise((i,a)=>{const c=`isnan(prev_selected_t)+gte(t-prev_selected_t,${o}-0.001)`,l=/pts_time:\s*(-?\d+(?:\.\d+)?)/,u=[],d=setTimeout(()=>{a(new Error(`ffmpeg frame extraction timed out after ${Nn.FFMPEG_TIMEOUT_MS}ms`))},Nn.FFMPEG_TIMEOUT_MS);s(t).outputOptions(["-vf",`select='${c}',showinfo,scale='min(${Nn.FRAME_MAX_DIMENSION}\\,iw):-2'`,"-vsync","vfr","-q:v","3","-frames:v",String(n.length)]).output(At(r,"frame_%04d.jpg")).on("stderr",p=>{const h=l.exec(p);h&&u.push(Number.parseFloat(h[1]))}).on("end",()=>{clearTimeout(d),i(u)}).on("error",p=>{clearTimeout(d),a(p)}).run()})}getFrameInterval(t){let r=180;for(const o of Nn.FRAME_INTERVALS)if(t<=o.maxDuration){r=o.intervalSec;break}return Math.floor(t/r)>Nn.MAX_FRAMES&&(r=Math.ceil(t/Nn.MAX_FRAMES)),r}async extractSubtitles(t,r){const n=At(r,"subtitles.srt"),o=await bP();await new Promise((s,i)=>{const a=setTimeout(()=>{i(new Error(`ffmpeg subtitle extraction timed out after ${Nn.FFMPEG_TIMEOUT_MS}ms`))},Nn.FFMPEG_TIMEOUT_MS);o(t).outputOptions(["-map","0:s:0","-c:s","srt"]).output(n).on("end",()=>{clearTimeout(a),s()}).on("error",c=>{clearTimeout(a),i(c)}).run()});try{const s=await qs.readFile(n,"utf-8");return this.parseSrtToPlainText(s)}catch{return}}parseSrtToPlainText(t){return t.trim()?t.split(`
820
+ `)[0]:String(g);return i(`the audio track could not be extracted \u2014 ${y}`)}let l;try{l=await qs.readFile(c)}catch{return i("ffmpeg reported success but wrote no audio file")}if(l.length===0)return i("the extracted audio track was empty");const u=l.length/(1024*1024);if(u>Nn.WHISPER_MAX_SIZE_MB)return i(`the extracted audio is ${u.toFixed(1)}MB, over Whisper's ${Nn.WHISPER_MAX_SIZE_MB}MB limit \u2014 split the recording`);const d=(process.env.OPENAI_BASE_URL??"https://api.openai.com/v1").replace(/\/+$/,""),p=new FormData;p.append("file",new Blob([new Uint8Array(l)],{type:"audio/mpeg"}),"audio.mp3"),p.append("model","whisper-1"),p.append("response_format","verbose_json");const h=new AbortController,f=setTimeout(()=>h.abort(),Nn.TRANSCRIPTION_TIMEOUT_MS);try{const g=await ze(fetch(`${d}/audio/transcriptions`,{method:"POST",headers:{Authorization:`Bearer ${a}`},body:p,signal:h.signal}),Nn.TRANSCRIPTION_TIMEOUT_MS);if(!g.ok){const T=await g.text().catch(()=>"");return i(`the transcription request failed \u2014 HTTP ${g.status}${T?`: ${T.slice(0,200)}`:""}`)}const y=await g.json(),v=typeof y=="object"&&y!==null&&typeof y.text=="string"?y.text.trim():"";return v.length===0?i("Whisper returned an empty transcript for this audio"):(m.debug(`[VideoProcessor] Transcribed ${o} via openai-whisper (${v.length} chars)`),{transcript:v})}catch(g){const y=g instanceof Error?g.message:String(g);return i(`the transcription request failed \u2014 ${y}`)}finally{clearTimeout(f)}}async extractKeyframes(t,r,n,o){if(n<=0)return[];const s=o?.frames,i=typeof s=="number"&&Number.isFinite(s)&&s>0,a=i?Math.min(Math.floor(s),Nn.MAX_FRAMES):Nn.MAX_FRAMES,c=i?Math.max(n/a,Number.EPSILON):this.getFrameInterval(n),l=[];for(let h=0;h<n&&l.length<a;h+=c)l.push(h);l.length===0&&l.push(0);const u=At(r,"frames");await qs.mkdir(u,{recursive:!0});const d=await this.runFfmpegFrameExtraction(t,u,l,c),p=[];for(let h=0;h<l.length;h++){const f=At(u,`frame_${String(h+1).padStart(4,"0")}.jpg`);try{await qs.access(f);const g=await qs.readFile(f),v=(await vht())(g).resize(Nn.FRAME_MAX_DIMENSION,Nn.FRAME_MAX_DIMENSION,{fit:"inside",withoutEnlargement:!0}),T=Gwr.resolveFrameQuality(o?.quality),b=await(o?.format==="png"?v.png({quality:T}):v.jpeg({quality:T})).toBuffer(),S=d[h]??l[h];p.push({buffer:b,timestampSec:S})}catch{}}return p}async runFfmpegFrameExtraction(t,r,n,o){try{return await this.runFfmpegFrameExtractionAttempt(t,r,n,o,"-fps_mode")}catch(s){const i=s instanceof Error?s.message:String(s);if(!/Unrecognized option ['"]?fps_mode\b/i.test(i))throw s;return this.runFfmpegFrameExtractionAttempt(t,r,n,o,"-vsync")}}async runFfmpegFrameExtractionAttempt(t,r,n,o,s){const i=await bP();return new Promise((a,c)=>{const l=`isnan(prev_selected_t)+gte(t-prev_selected_t,${o}-0.001)`,u=/pts_time:\s*(-?\d+(?:\.\d+)?)/,d=[],p=setTimeout(()=>{c(new Error(`ffmpeg frame extraction timed out after ${Nn.FFMPEG_TIMEOUT_MS}ms`))},Nn.FFMPEG_TIMEOUT_MS);i(t).outputOptions(["-vf",`select='${l}',showinfo,scale='min(${Nn.FRAME_MAX_DIMENSION}\\,iw):-2'`,s,"vfr","-q:v","3","-frames:v",String(n.length)]).output(At(r,"frame_%04d.jpg")).on("stderr",h=>{const f=u.exec(h);f&&d.push(Number.parseFloat(f[1]))}).on("end",()=>{clearTimeout(p),a(d)}).on("error",h=>{clearTimeout(p),c(h)}).run()})}getFrameInterval(t){let r=180;for(const o of Nn.FRAME_INTERVALS)if(t<=o.maxDuration){r=o.intervalSec;break}return Math.floor(t/r)>Nn.MAX_FRAMES&&(r=Math.ceil(t/Nn.MAX_FRAMES)),r}async extractSubtitles(t,r){const n=At(r,"subtitles.srt"),o=await bP();await new Promise((s,i)=>{const a=setTimeout(()=>{i(new Error(`ffmpeg subtitle extraction timed out after ${Nn.FFMPEG_TIMEOUT_MS}ms`))},Nn.FFMPEG_TIMEOUT_MS);o(t).outputOptions(["-map","0:s:0","-c:s","srt"]).output(n).on("end",()=>{clearTimeout(a),s()}).on("error",c=>{clearTimeout(a),i(c)}).run()});try{const s=await qs.readFile(n,"utf-8");return this.parseSrtToPlainText(s)}catch{return}}parseSrtToPlainText(t){return t.trim()?t.split(`
821
821
  `).filter(r=>{const n=r.trim();return!(!n||/^\d+$/.test(n)||/^\d{2}:\d{2}:\d{2}[,.]\d{3}\s*-->/.test(n))}).map(r=>r.trim()).join(`
822
822
  `).trim():""}buildTextContent(t,r,n,o,s){const i=[];if(i.push(`[Video File: ${o}]`),i.push(""),i.push("## Video Metadata"),i.push(`- Duration: ${t.durationFormatted}`),i.push(`- Resolution: ${t.width}x${t.height}`),i.push(`- Video Codec: ${t.codec}`),t.fps>0&&i.push(`- Frame Rate: ${t.fps} fps`),t.bitrate>0&&i.push(`- Bitrate: ${(t.bitrate/1e3).toFixed(0)} kbps`),t.audioCodec&&(i.push(`- Audio Codec: ${t.audioCodec}`),t.audioChannels&&i.push(`- Audio Channels: ${t.audioChannels===1?"mono":t.audioChannels===2?"stereo":`${t.audioChannels}ch`}`),t.audioSampleRate&&i.push(`- Audio Sample Rate: ${(t.audioSampleRate/1e3).toFixed(1)} kHz`)),i.push(`- File Size: ${(t.fileSize/(1024*1024)).toFixed(1)} MB`),i.push(""),r.length>0){i.push(`## Keyframes (${r.length} extracted)`),i.push("The images attached below are keyframes from this video, in order. Each was sampled at the timestamp listed here:");for(const[a,c]of r.entries())i.push(`- Frame ${a+1}: ${Qct(c)}`)}else i.push("## Keyframes"),i.push("No keyframes could be extracted from this video (it may be audio-only or use an unsupported codec).");if(s){i.push(""),i.push("## Spoken Audio (transcribed)"),i.push("The following is a machine transcription of the speech in this video:");const a=2e4;s.length>a?i.push(s.substring(0,a)+`
823
823
  ... [truncated, ${s.length-a} more characters]`):i.push(s)}if(n){i.push(""),i.push("## Subtitles / Captions");const a=1e4;n.length>a?i.push(n.substring(0,a)+`
@@ -248,6 +248,7 @@ export declare class VideoProcessor extends BaseFileProcessor<ProcessedVideo> {
248
248
  * real frames were available to select
249
249
  */
250
250
  private runFfmpegFrameExtraction;
251
+ private runFfmpegFrameExtractionAttempt;
251
252
  /**
252
253
  * Determine the frame extraction interval based on video duration.
253
254
  *
@@ -1091,6 +1091,21 @@ export class VideoProcessor extends BaseFileProcessor {
1091
1091
  * real frames were available to select
1092
1092
  */
1093
1093
  async runFfmpegFrameExtraction(videoPath, outputDir, timestamps, intervalSec) {
1094
+ try {
1095
+ return await this.runFfmpegFrameExtractionAttempt(videoPath, outputDir, timestamps, intervalSec, "-fps_mode");
1096
+ }
1097
+ catch (error) {
1098
+ // `-vsync` was removed in ffmpeg 9 and `-fps_mode` only exists from 5.1,
1099
+ // so neither flag works on every ffmpeg. Retry only when this ffmpeg
1100
+ // says it does not know `-fps_mode`; any other failure would repeat.
1101
+ const message = error instanceof Error ? error.message : String(error);
1102
+ if (!/Unrecognized option ['"]?fps_mode\b/i.test(message)) {
1103
+ throw error;
1104
+ }
1105
+ return this.runFfmpegFrameExtractionAttempt(videoPath, outputDir, timestamps, intervalSec, "-vsync");
1106
+ }
1107
+ }
1108
+ async runFfmpegFrameExtractionAttempt(videoPath, outputDir, timestamps, intervalSec, vfrFlag) {
1094
1109
  const ff = await loadFluentFfmpeg();
1095
1110
  return new Promise((resolve, reject) => {
1096
1111
  // Improved select expression to pick exactly one frame per interval
@@ -1105,7 +1120,7 @@ export class VideoProcessor extends BaseFileProcessor {
1105
1120
  .outputOptions([
1106
1121
  "-vf",
1107
1122
  `select='${selectExpr}',showinfo,scale='min(${VIDEO_CONFIG.FRAME_MAX_DIMENSION}\\,iw):-2'`,
1108
- "-vsync",
1123
+ vfrFlag,
1109
1124
  "vfr",
1110
1125
  "-q:v",
1111
1126
  "3",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.41.0",
3
+ "version": "12.41.2",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "The pipe layer of an AI nervous system: one interface connecting provider neurons to your application, across three inference types — generate, stream and decide. `decide` returns typed, calibrated judgements from a non-generative model (~400ms, ~$0.00002/call) for routing, tool selection and context budgeting. MCP-native (4 transports), voice TTS/STT/realtime, RAG, agents, memory, compaction, 9 observability exporters. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · TypeSafe Jev and more.",
6
6
  "author": {
@@ -683,7 +683,7 @@
683
683
  "js-yaml@>=4.0.0 <4.3.2": ">=4.3.2",
684
684
  "js-yaml@>=3.0.0 <3.15.2": ">=3.15.2",
685
685
  "ajv@>=8.0.0 <8.18.0": ">=8.18.0",
686
- "@grpc/grpc-js@<1.14.4": ">=1.14.4",
686
+ "@grpc/grpc-js@<1.14.5": ">=1.14.5",
687
687
  "@protobufjs/utf8@<1.1.1": ">=1.1.1",
688
688
  "fast-uri@<3.1.8": ">=3.1.8 <4",
689
689
  "ip-address@<10.1.1": ">=10.1.1",