@shumai-one/shumai-transcode 0.1.0 → 0.1.1

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.
@@ -12972,7 +12972,7 @@ Most of the features of Better Auth will not work correctly.`);let l=Q.secrets??
12972
12972
  `).replace(/\r/g,`
12973
12973
  `),VcB=(B)=>{let Q=ucB(B);if(!Q.startsWith("---"))return{yamlString:null,body:Q};let F=Q.indexOf(`
12974
12974
  ---`,3);if(F===-1)return{yamlString:null,body:Q};return{yamlString:Q.slice(4,F),body:Q.slice(F+4).trim()}},o9=(B)=>{let{yamlString:Q,body:F}=VcB(B);if(!Q)return{frontmatter:{},body:F};return{frontmatter:rs(Q)??{},body:F}};class N9{prismaClient;constructor(B=T){this.prismaClient=B}async upsertSkill(B,Q){let F,g;if(Q.githubUrl){let{downloadUrl:W,path:a}=this.parseGithubUrl(Q.githubUrl);g=a,F=await this.downloadGithubZip(W)}else if(Q.assetId){let W=await this.prismaClient.asset.findUnique({where:{id:Q.assetId},include:{storageKey:!0}}),a=W?.storageKey?.key;if(!W||!a)throw Error("Asset not found or has no key");let{buffer:V}=await pB.getObject(process.env.S3_BUCKET||"shumai",a);F=V}else throw Error("Either assetId or githubUrl must be provided");let{name:U,description:I,repackedZip:n}=await this.processSkillZip(F,g);if(await this.prismaClient.skill.findUnique({where:{teamId_name:{teamId:B,name:U}}})&&!Q.override){let W=Error(`Skill with name "${U}" already exists.`);throw W.name="ConflictError",W}let l=h9.createHash("sha256").update(n).digest("hex"),b=`skills/${aF()}.zip`;await pB.putObject(process.env.S3_BUCKET||"shumai",b,n,n.length,"application/zip");let G=await this.prismaClient.asset.create({data:{name:`${U}.zip`,storageKey:{create:{key:b}},type:"file",mediaType:"application/zip",sizeByte:n.length,status:"uploaded"}}),i=await this.prismaClient.skill.upsert({where:{teamId_name:{teamId:B,name:U}},update:{description:I,assetId:G.id,hash:l},create:{name:U,description:I,assetId:G.id,hash:l,teamId:B}});return this.toSkillInfo(i)}async deleteSkill(B){if(!await this.prismaClient.skill.findUnique({where:{id:B}}))return;await this.prismaClient.skill.delete({where:{id:B}})}async updateSkillConfig(B,Q){let F=await this.prismaClient.skill.update({where:{id:B},data:{config:Q}});return this.toSkillInfo(F)}async listSkills(B){return(await this.prismaClient.skill.findMany({where:{teamId:B},orderBy:{id:"desc"}})).map((F)=>this.toSkillInfo(F))}parseGithubUrl(B){let F=new URL(B).pathname.split("/").filter(Boolean);if(F.length<2)throw Error("Invalid GitHub URL: missing owner or repo");let g=F[0],U=F[1],I="main",n;if(F.length>2)if(F[2]==="tree"||F[2]==="blob"){if(F.length<4)throw Error("Invalid GitHub URL: missing ref or path");I=F[3],n=F.slice(4).join("/")}else n=F.slice(2).join("/");return{downloadUrl:`https://codeload.github.com/${g}/${U}/zip/refs/heads/${I}`,path:n}}async downloadGithubZip(B){let Q=await fetch(B);if(!Q.ok){if(B.endsWith("/refs/heads/main")){let F=B.replace("/refs/heads/main","/refs/heads/master"),g=await fetch(F);if(g.ok)return Buffer.from(await g.arrayBuffer())}throw Error(`Failed to download GitHub ZIP from ${B}`)}return Buffer.from(await Q.arrayBuffer())}async processSkillZip(B,Q){let g=new Ms.default(B).getEntries();if(g.length===0)throw Error("The provided ZIP file is empty");let I=g[0].entryName.split("/")[0],n=g.every((m)=>m.entryName.startsWith(`${I}/`)),c=Q||"";if(c.toLowerCase().endsWith("skill.md"))c=c.substring(0,c.toLowerCase().lastIndexOf("skill.md"));let l="";if(n)l=c?`${I}/${c.replace(/\/$/,"")}/`:`${I}/`;else l=c?`${c.replace(/\/$/,"")}/`:"";let b=g.find((m)=>{let C=m.entryName.toLowerCase(),x=l.toLowerCase();return C.startsWith(x)&&C.endsWith("skill.md")});if(!b)throw Error(`SKILL.md not found in ${Q||"root"}`);let G=b.getData().toString("utf8"),{name:i,description:W}=this.parseSkillMd(G),a=new Ms.default,V=b.entryName.substring(0,b.entryName.toLowerCase().lastIndexOf("skill.md"));for(let m of g){if(m.isDirectory)continue;if(m.entryName.startsWith(V)){let C=m.entryName.substring(V.length);a.addFile(C,m.getData())}}return{name:i,description:W,repackedZip:a.toBuffer()}}parseSkillMd(B){let{frontmatter:Q}=o9(B),F=Q.name||"Unnamed Skill",g=Q.description||"";return{name:F,description:g}}toSkillInfo(B){return{id:B.id,name:B.name,description:B.description,config:B.config,assetId:B.assetId,hash:B.hash,createdAt:B.createdAt.toISOString(),updatedAt:B.updatedAt.toISOString()}}}var XfB=new N9;import{execFile as scB}from"child_process";import*as MU from"fs";import*as Y9 from"os";import*as hg from"path";import fl from"sharp";import{promisify as XcB}from"util";var Os={apch:"Apple ProRes 422 High Quality",apcn:"Apple ProRes 422 Standard Definition",apcs:"Apple ProRes 422 LT",apco:"Apple ProRes 422 Proxy",ap4h:"Apple ProRes 4444",jpeg:"JPEG Image","3gvo":"3GPP Video Orientation",a3d1:"Multiview Video Coding",a3d2:"Multiview Video Coding",a3d3:"Multiview Video Coding",a3d4:"Multiview Video Coding",a3ds:"Auro-Cx 3D audio","ac-3":"AC-3 audio","ac-4":"AC-4 audio",alac:"Apple lossless audio codec",alaw:"a-Law",av01:"AV1 video",avc1:"Advanced Video Coding",avc2:"Advanced Video Coding",avc3:"Advanced Video Coding",avc4:"Advanced Video Coding",avcp:"Advanced Video Coding Parameters",dra1:"DRA Audio",drac:"Dirac Video Coder","dts-":"Dependent base layer for DTS layered audio","dts+":"Enhancement layer for DTS layered audio",dtsc:"DTS Coherent Acoustics audio",dtse:"DTS Express low bit rate audio, also known as DTS LBR",dtsh:"DTS-HD High Resolution Audio",dtsl:"DTS-HD Master Audio",dtsx:"DTS:X",dvav:"AVC-based \u201CDolby Vision\u201D",dvhe:"HEVC-based \u201CDolby Vision\u201D","ec-3":"Enhanced AC-3 audio",enca:"Encrypted/Protected audio",encf:"Encrypted/Protected font",encm:"Encrypted/Protected metadata stream",encs:"Encrypted Systems stream",enct:"Encrypted Text",encv:"Encrypted/protected video",fdp:"File delivery hints",fLaC:"Fres Lossless Audio Codec",g719:"ITU-T Recommendation G.719 (2008)",g726:"ITU-T Recommendation G.726 (1990)",hev1:"High Efficiency Video Coding",hvc1:"High Efficiency Video Coding",hvt1:"High Efficiency Video Coding",ixse:"DVB Track Level Index Track",lhe1:"Layered High Efficiency Video Coding",lht1:"Layered High Efficiency Video Coding",lhv1:"Layered High Efficiency Video Coding",m2ts:"MPEG-2 transport stream for DMB",m4ae:"MPEG-4 Audio Enhancement MP4v1/2",mett:"Text timed metadata that is not XML",metx:"XML timed metadata",mha1:"MPEG-H Audio (single stream, uncapsulated)",mha2:"MPEG-H Audio (multi-stream, unencapsulated)",mhm1:"MPEG-H Audio (single stream, MHAS encapsulated)",mhm2:"MPEG-H Audio (multi-stream, MHAS encapsulated)",mjp2:"Motion JPEG 2000",mlix:"DVB Movie level index track",mlpa:"MLP Audio",mp4a:"MPEG-4 Audio",mp4s:"MPEG-4 Systems",mp4v:"MPEG-4 Visual",mvc1:"Multiview coding",mvc2:"Multiview coding",mvc3:"Multiview coding",mvc4:"Multiview coding",mvd1:"Multiview coding",mvd2:"Multiview coding",mvd3:"Multiview coding",mvd4:"Multiview coding",oksd:"OMA Keys",Opus:"Opus audio coding",pm2t:"Protected MPEG-2 Transport",prtp:"Protected RTP Reception",raw:"Uncompressed audio",resv:"Restricted Video",rm2t:"MPEG-2 Transport Reception",rrtp:"RTP reception",rsrp:"SRTP Reception",rtmd:"Real Time Metadata Sample Entry(XAVC Format)",rtp:"RTP Hints",s263:"ITU H.263 video (3GPP format)",samr:"Narrowband AMR voice",sawb:"Wideband AMR voice",sawp:"Extended AMR-WB (AMR-WB+)",sevc:"EVRC Voice",sm2t:"MPEG-2 Transport Server",sqcp:"13K Voice",srtp:"SRTP Hints",ssmv:"SMV Voice",STGS:"Subtitle Sample Entry (HMMP)",stpp:"Subtitles (Timed Text)",svc1:"Scalable Video Coding",svc2:"Scalable Video Coding",svcM:"SVC Metadata",tc64:"64 bit timecode samples",tmcd:"32 bit timecode samples",twos:"Uncompressed 16-bit audio",tx3g:"Timed Text stream",ulaw:"Samples have been compressed using uLaw 2:1.",unid:"Dynamic Range Control (DRC) data",urim:"Binary timed metadata identified by URI","vc-1":"SMPTE VC-1",vp08:"VP8 video",vp09:"VP9 video",wvtt:"WebVTT"};var Kl=XcB(scB);class H9{prismaClient;constructor(B=T){this.prismaClient=B}resolveCodecName(B){let Q=B.mime_codec_string||B.tags?.mime_codec_string;if(Q&&typeof Q==="string"){let F=Q.split(".")[0];if(Os[F])return Os[F]}return B.codec_name}safeParseInt(B){if(B===void 0||B===null)return;let Q=typeof B==="string"?parseInt(B,10):B;return Number.isFinite(Q)?Q:void 0}async getVideoInfo(B){let{stdout:Q}=await Kl("ffprobe",["-v","quiet","-print_format","json","-show_format","-show_streams",B]),F=JSON.parse(Q),g=F.streams.find((c)=>c.codec_type==="video"),U=F.streams.find((c)=>c.codec_type==="audio");if(!g)throw Error("No video stream found");let I=g.r_frame_rate.split("/"),n=parseFloat(I[0])/parseFloat(I[1]);return{originalWidth:g.width,originalHeight:g.height,duration:parseFloat(F.format.duration),bitRate:parseFloat(F.format.bit_rate),frameRate:n,hasAudio:!!U,videoCodec:this.resolveCodecName(g),audioCodec:U?this.resolveCodecName(U):void 0,audioChannels:U?.channels,audioSampleRate:this.safeParseInt(U?.sample_rate),audioBitDepth:this.safeParseInt(U?.bits_per_raw_sample)??this.safeParseInt(U?.bits_per_sample),mimeType:""}}async getImageInfo(B){let Q=B;if(B.startsWith("http")){let g=await fetch(B);if(!g.ok)throw Error(`Failed to fetch image from ${B}: ${g.statusText}`);Q=Buffer.from(await g.arrayBuffer())}let F=await fl(Q,{limitInputPixels:!1}).metadata();return{originalWidth:F.width||0,originalHeight:F.height||0,duration:0,bitRate:0,frameRate:0,hasAudio:!1,mimeType:F.format||""}}async transcodeVideo(B){let Q=`[0:v]scale=w=${B.width}:h=${B.height}:force_original_aspect_ratio=decrease,scale=w='trunc(iw/2)*2':h='trunc(ih/2)*2'`;if(B.frameRate)Q+=`,fps=${B.frameRate}`;Q+="[vout]";let F=["-i",B.inputFile,"-filter_complex",Q,"-map","[vout]"];if(!B.disableAudio)F.push("-map","0:a?");if(F.push("-c:v","libx264","-preset","fast","-crf","23"),!B.disableAudio)F.push("-c:a","aac","-b:a","128k");F.push("-movflags","+faststart","-max_muxing_queue_size","1024",B.outputFile),await Kl("ffmpeg",["-y","-loglevel","warning",...F])}async transcodeImage(B,Q,F,g,U=null){let I=B;if(typeof B==="string"&&B.startsWith("http")){let G=await fetch(B);if(!G.ok)throw Error(`Failed to fetch image from ${B}: ${G.statusText}`);I=Buffer.from(await G.arrayBuffer())}let n=fl(I,{limitInputPixels:!1}),c=7680,l=F>0?Math.min(F,c):c,b=U&&U>0?Math.min(U,c):c;n.resize(l,b,{withoutEnlargement:!0,fit:"inside"}),await n.webp({quality:g}).toFile(Q)}async generateSprite(B,Q,F,g){let I=`[0:v]fps=${100/g},scale=w=480:h=-2,tile=10x10[sprite_out];[0:v]scale=-2:720:force_original_aspect_ratio=decrease,select='eq(n\\,0)'[thumb_out]`;await Kl("ffmpeg",["-y","-loglevel","warning",...["-i",B,"-filter_complex",I,"-map","[sprite_out]","-frames:v","1","-c:v","libwebp","-q:v","75",Q,"-map","[thumb_out]","-c:v","libwebp","-q:v","75","-frames:v","1","-max_muxing_queue_size","1024",F]])}async extractAudio(B,Q,F){await Kl("ffmpeg",["-y","-loglevel","warning",...["-i",B,"-vn","-acodec","libmp3lame","-b:a",F,Q]])}async extractVideoFrames(B){if(B.isImage){let n=hg.join(B.outputDir,"1.webp");return await this.transcodeImage(B.inputFile,n,-1,80,B.frameHeight),[n]}let Q=await this.getVideoInfo(B.inputFile),F=B.numFrames/Q.duration,g=hg.join(B.outputDir,"%d.webp"),U=["-i",B.inputFile,"-vf",`fps=${F},scale=-2:${B.frameHeight}`,"-c:v","libwebp","-q:v","80",g];return await Kl("ffmpeg",["-y","-loglevel","warning",...U]),MU.readdirSync(B.outputDir).filter((n)=>n.endsWith(".webp")).sort((n,c)=>{let l=parseInt(hg.basename(n,".webp")),b=parseInt(hg.basename(c,".webp"));return l-b}).map((n)=>hg.join(B.outputDir,n))}createTempDir(B){return MU.mkdtempSync(hg.join(Y9.tmpdir(),B))}removeDir(B){MU.rmSync(B,{recursive:!0,force:!0})}async createVideoTranscodeTask(B,Q,F){return this.prismaClient.workflowTask.create({data:{assetId:B,projectId:Q,type:OQ.transcode,status:zQ.pending,payload:{projectId:Q,transcode:F}}})}async createImageTranscodeTask(B,Q,F){return this.prismaClient.workflowTask.create({data:{assetId:B,projectId:Q,type:OQ.transcode,status:zQ.pending,payload:{projectId:Q,transcode:F}}})}async takeScreenshots(B){let Q=process.env.S3_BUCKET||"shumai",F=this.createTempDir("screenshot-"),g=hg.join(F,hg.basename(B.assetKey));try{await pB.downloadToFile(Q,B.assetKey,g);let U=[];if(B.count<=1)U=[B.start];else{let c=(B.end-B.start)/B.count;U=Array.from({length:B.count},(l,b)=>B.start+b*c)}let I=B.commentTimestamp;if(I!==void 0&&I!==null){if(I>=B.start&&I<=B.end){let c=0,l=Math.abs(U[0]-I);for(let b=1;b<U.length;b++){let G=Math.abs(U[b]-I);if(G<l)l=G,c=b}U[c]=I}}let n=[];for(let c of U){let l=`shot-${c.toFixed(3)}-${aF()}.webp`,b=hg.join(F,l),G=["-ss",c.toFixed(3),"-i",g,"-vframes","1","-vf","scale=-2:720","-c:v","libwebp","-q:v","80",b];if(await Kl("ffmpeg",["-y","-loglevel","warning",...G]),I!==void 0&&I!==null&&c===I&&B.annotations&&B.annotations.length>0){let a=await fl(b,{limitInputPixels:!1}).metadata(),V=a.width||1280,m=a.height||720,C=L9(V,m,B.annotations),x=hg.join(F,`composite-${l}`);await fl(b,{limitInputPixels:!1}).composite([{input:Buffer.from(C),top:0,left:0}]).toFile(x),MU.renameSync(x,b)}let i=`files/${B.assetId}/screenshots/${l}`,W=MU.readFileSync(b);await pB.putObject(Q,i,W,W.length,"image/webp"),n.push({key:i,timestamp:c})}return n}finally{this.removeDir(F)}}async overlayAnnotations(B){let Q=process.env.S3_BUCKET||"shumai",F=this.createTempDir("annotation-"),g=hg.join(F,hg.basename(B.assetKey));try{await pB.downloadToFile(Q,B.assetKey,g);let U=await fl(g,{limitInputPixels:!1}).metadata(),I=U.width||1920,n=U.height||1080,c=L9(I,n,B.annotations),l=`annotation-${aF()}.webp`,b=hg.join(F,l);await fl(g,{limitInputPixels:!1}).composite([{input:Buffer.from(c),top:0,left:0}]).resize(16383,16383,{fit:"inside",withoutEnlargement:!0}).webp({quality:90}).toFile(b);let G=`files/${B.assetId}/annotations/${l}`,i=MU.readFileSync(b);return await pB.putObject(Q,G,i,i.length,"image/webp"),G}finally{this.removeDir(F)}}}function L9(B,Q,F){let g=Math.max(2,Math.round(Math.max(B,Q)*0.004)),U=[];for(let I of F){let n=I.color||"#ff0000";switch(I.type){case"box":{if(I.points.length<2)continue;let[l,b]=I.points,G=Math.min(l[0],b[0])*B,i=Math.min(l[1],b[1])*Q,W=Math.abs(b[0]-l[0])*B,a=Math.abs(b[1]-l[1])*Q;U.push(`<rect x="${G}" y="${i}" width="${W}" height="${a}" stroke="${n}" stroke-width="${g}" fill="none" />`);break}case"line":case"freehand":{if(I.points.length<2)continue;let l=I.points.map(([b,G])=>`${b*B},${G*Q}`).join(" ");U.push(`<polyline points="${l}" stroke="${n}" stroke-width="${g}" stroke-linecap="round" stroke-linejoin="round" fill="none" />`);break}case"arrow":{if(I.points.length<2)continue;let l=I.points.map(([u,y])=>[u*B,y*Q]),b=l.map(([u,y])=>`${u},${y}`).join(" ");U.push(`<polyline points="${b}" stroke="${n}" stroke-width="${g}" stroke-linecap="round" stroke-linejoin="round" fill="none" />`);let G=l[l.length-1],i=l[l.length-2],W=G[0]-i[0],a=G[1]-i[1],V=Math.atan2(a,W),m=Math.max(12,Math.max(B,Q)*0.015),C=G[0]-m*Math.cos(V-Math.PI/6),x=G[1]-m*Math.sin(V-Math.PI/6),e=G[0]-m*Math.cos(V+Math.PI/6),Z=G[1]-m*Math.sin(V+Math.PI/6);U.push(`<polygon points="${G[0]},${G[1]} ${C},${x} ${e},${Z}" fill="${n}" />`);break}}}return`<svg width="${B}" height="${Q}" viewBox="0 0 ${B} ${Q}" xmlns="http://www.w3.org/2000/svg">${U.join(`
12975
- `)}</svg>`}var xI=new H9;class J9{prismaClient;constructor(B=T){this.prismaClient=B}async createUploadTask(B,Q){let F=Q.files.filter((W)=>!W.name.startsWith(".")),g=F.length===1?F[0].name:`${F.length} Items`,U=0,I=(W)=>{for(let a of W){if(a.name.startsWith("."))continue;if(a.type==="file")U++;else I(a.children)}};I(Q.files);let n=await this.prismaClient.task.create({data:{creatorId:B,type:"upload",name:g,total:U,status:Ai.pending}}),c=await this.prismaClient.asset.findUnique({where:{id:Q.parentId},include:{project:!0}});if(!c)throw Error("Parent asset not found");if(!c.projectId)throw Error("Parent asset has no project");let l=[],b=c.type===RB.file,G=b?c.parentId:c.id,i=[];return await this.prismaClient.$transaction(async(W)=>{let a=await this.createAssetsRecursively(W,B,n.id,c.projectId,G,Q.files,l,i);if(b&&a.length>0)for(let V of a)await Zc.reparentAssets({assetIds:[V],newParentId:c.id,creatorId:B},W);return a}),{taskId:n.id,presignedUrls:l,createdAssets:i}}async createAssetsRecursively(B,Q,F,g,U,I,n,c){let b=(await B.asset.findFirst({where:{parentId:U},orderBy:{sortIndex:"asc"}}))?.sortIndex||void 0,G=[];for(let i of I){if(i.name.startsWith("."))continue;let W=Mg(null,b||null);b=W;let a=i.type==="folder"?RB.folder:RB.file,V=null;if(a===RB.file)V=`files/${aF()}/raw`;let m=await B.asset.create({data:{name:i.name,type:a,storageKey:V?{create:{key:V}}:void 0,sortIndex:W,mediaType:i.mediaType,status:a===RB.folder?cc.uploaded:cc.uploading,sizeByte:i.size,creator:Q?{connect:{id:Q}}:void 0,parent:U?{connect:{id:U}}:void 0,project:{connect:{id:g}},task:{connect:{id:F}}}});if(G.push(m.id),c.push({tempId:i.id,assetId:m.id}),a===RB.folder&&U)await B.asset.update({where:{id:U},data:{fileCount:{increment:1}}});if(i.children&&i.children.length>0)await this.createAssetsRecursively(B,Q,F,g,m.id,i.children,n,c);else if(a===RB.file&&V){let C=await pB.presign(process.env.S3_BUCKET||"shumai",V,"PUT");n.push({id:i.id,fileId:m.id,url:C})}}return G}async confirmFileUpload(B,Q,F){let g=await this.prismaClient.asset.findUnique({where:{id:F.fileId},include:{storageKey:!0,project:{include:{team:!0}}}});if(!g)throw Error("Asset not found");if(!g.project)throw Error("Project not found for asset");let U=g.storageKey?.key;if(!U)throw Error("Asset has no key");if(F.errorMessage){if(await this.prismaClient.asset.delete({where:{id:g.id}}),await this.prismaClient.task.findUnique({where:{id:Q}})){let l=await this.prismaClient.task.update({where:{id:Q},data:{uploaded:{increment:1}}});if(l.uploaded===l.total)await this.prismaClient.task.update({where:{id:Q},data:{status:Ai.completed}})}return}let I=await pB.getObjectSize(process.env.S3_BUCKET||"shumai",U),n=g.project;await this.prismaClient.$transaction(async(c)=>{let l=await c.asset.update({where:{id:g.id},data:{status:cc.uploaded,sizeByte:I}});if(g.parentId)await c.asset.update({where:{id:g.parentId},data:{fileCount:{increment:1}}}),await Zc.updateAncestorsSize(c,g.parentId,l.sizeByte);let b=await c.task.update({where:{id:Q},data:{uploaded:{increment:1}}});if(b.uploaded===(b.total||0))await c.task.update({where:{id:Q},data:{status:Ai.completed}});let G=n.team;if(!G)return;if(!g.projectId)throw Error("Asset project ID is missing");await this.triggerPostUploadWorkflows(c,g.id,G.id,g.projectId)})}async triggerPostUploadWorkflows(B,Q,F,g){let U=await B.asset.findUnique({where:{id:Q}});if(!U)throw Error("Asset not found");let I=await B.team.findUnique({where:{id:F}});if(!I)throw Error("Team not found");let n=await B.agent.findFirst({where:{type:"autofill",enabled:!0,user:{teamMembers:{some:{teamId:I.id}}}}});if(n)await B.workflowTask.create({data:{assetId:U.id,type:OQ.ai_metadata_autofill,status:zQ.pending,teamId:I.id,projectId:g,payload:{projectId:g,agent:{agentId:n.id}}}});let c=U.mediaType?.startsWith("video/"),l=U.mediaType?.startsWith("image/");if(!c&&!l)await B.asset.update({where:{id:U.id},data:{status:cc.processed}});else{let b=I.settings;if(c){let G=b?.transcode?.videoStrategy||"best_match";await new fs(B,U.id,I.id,g).setStrategy(G).withSprite().withPoster().submit()}else if(l)await new Ks(B,U.id,I.id,g).withThumbnail().submit()}}async listUploadTasks(B,Q){let F={creatorId:B,type:"upload"},{data:g,pageInfo:U}=await mg(async(n,c)=>{return this.prismaClient.task.findMany({where:F,orderBy:{id:"desc"},skip:n,take:c})},async()=>this.prismaClient.task.count({where:F}),Q);return{data:g.map((n)=>({id:n.id,name:n.name||"",total:n.total||0,uploaded:n.uploaded,createdAt:n.createdAt.toISOString()})),pageInfo:U}}}var rfB=new J9;function xcB(B){if(!B)return Mg(null,null);return Mg(B,null)}class S9{prismaClient;constructor(B=T){this.prismaClient=B}async createVersionStack(B){let{fileIds:Q,projectId:F,creatorId:g}=B;if(!Q||Q.length===0)throw Error("no file ids provided");return await this.prismaClient.$transaction(async(U)=>{let I=await U.asset.findMany({where:{id:{in:Q}},include:{parent:!0}});if(I.length!==Q.length)throw Error("some files not found");let n=void 0,c=0;for(let a of I){if(a.type!==RB.file)throw Error(`asset ${a.id} is not a file`);if(!a.parentId)throw Error(`file ${a.id} does not have a parent`);if(n===void 0)n=a.parentId;else if(a.parentId!==n)throw Error("files do not have the same parent");c+=a.sizeByte}if(!n)throw Error("files do not have a parent");if(!await U.asset.findUnique({where:{id:n}}))throw Error("parent not found");let G=I[0]?.sortIndex||null,i=await U.asset.create({data:{type:RB.version_stack,fileCount:I.length,sizeByte:c,status:"uploaded",projectId:F,creatorId:g,parentId:n,sortIndex:G}}),W=null;for(let a of Q)W=xcB(W),await U.asset.update({where:{id:a},data:{parentId:i.id,sortIndex:W}});return await U.asset.update({where:{id:n},data:{fileCount:{decrement:I.length-1}}}),i})}async changeStackFileVersion(B){let{stackId:Q,fileId:F,beforeId:g}=B;await this.prismaClient.$transaction(async(U)=>{let I=await U.asset.findUnique({where:{id:Q}});if(!I)throw Error("stack not found");if(I.type!==RB.version_stack)throw Error("asset is not a version stack");let n=await U.asset.findUnique({where:{id:F}});if(!n)throw Error("file not found");if(n.parentId!==Q)throw Error("file is not in the stack");let c;if(g==="-1"){let l=await U.asset.findFirst({where:{parentId:Q},orderBy:{sortIndex:"desc"}});c=Mg(l?.sortIndex||null,null)}else{let l=await U.asset.findUnique({where:{id:g}});if(!l)throw Error("before_id file not found");if(l.parentId!==Q)throw Error("before_id file is not in the stack");let G=(await U.asset.findFirst({where:{parentId:Q,sortIndex:{lt:l.sortIndex}},orderBy:{sortIndex:"desc"}}))?.sortIndex||null;if(G&&G>=l.sortIndex)G=null;c=Mg(G,l.sortIndex)}await U.asset.update({where:{id:F},data:{sortIndex:c}})})}}var jfB=new S9;import{ApplicationFailure as Qn}from"@temporalio/activity";import*as AF from"path";import*as dF from"fs";import*as p9 from"os";import{execFile as ecB}from"child_process";import{promisify as RcB}from"util";var ycB=RcB(ecB);function n0(B){if(B&&typeof B==="object"){let Q=B;return{code:typeof Q.code==="string"?Q.code:void 0,message:typeof Q.message==="string"?Q.message:String(B),name:typeof Q.name==="string"?Q.name:void 0}}return{message:String(B)}}async function AcB(B){try{let Q=B.mediaType.startsWith("video/"),F=B.mediaType.startsWith("image/"),g=B.mediaType.startsWith("audio/"),U=B.mediaType.startsWith("text/")||B.mediaType==="application/pdf"||B.mediaType.includes("msword")||B.mediaType.includes("officedocument")||B.mediaType.includes("vnd.ms-"),I=Q?"video":g?"audio":F?"image":U?"document":"file",n={duration:0,filesize:0,fps:0,frames:0,imageTranscodes:[],videoTranscodes:[],videoPreview:{width:0,height:0},finishedAt:new Date().toISOString(),metadata:null,mimeType:B.mediaType,original:{key:"",downloadUrl:"",filesizeInBytes:0,codec:""}},c=[{key:"file_type",value:I}];if(Q){let l=await xI.getVideoInfo(B.filePath);if(n.duration=l.duration,n.fps=l.frameRate,n.metadata={originalWidth:l.originalWidth,originalHeight:l.originalHeight,duration:l.duration,bitRate:l.bitRate,frameRate:l.frameRate,hasAudio:l.hasAudio,videoCodec:l.videoCodec,audioCodec:l.audioCodec,audioChannels:l.audioChannels,audioSampleRate:l.audioSampleRate,audioBitDepth:l.audioBitDepth,format:{}},c.push({key:"resolution_width",value:l.originalWidth},{key:"resolution_height",value:l.originalHeight},{key:"duration",value:l.duration},{key:"bitRate",value:l.bitRate/1000},{key:"frame_rate",value:l.frameRate}),l.videoCodec)c.push({key:"video_codec",value:l.videoCodec});if(l.audioCodec)c.push({key:"audio_codec",value:l.audioCodec});if(l.audioChannels!==void 0)c.push({key:"audio_channels",value:l.audioChannels});if(l.audioSampleRate!==void 0)c.push({key:"audio_sample_rate",value:l.audioSampleRate});if(l.audioBitDepth!==void 0)c.push({key:"audio_bit_depth",value:l.audioBitDepth})}else if(F){let l=await xI.getImageInfo(B.filePath);n.metadata={originalWidth:l.originalWidth,originalHeight:l.originalHeight,duration:0,bitRate:0,frameRate:0,hasAudio:!1,format:{}},c.push({key:"resolution_width",value:l.originalWidth},{key:"resolution_height",value:l.originalHeight})}return await dp.updateAssetMetadata(B.assetId,c,!0),n}catch(Q){let{name:F,message:g}=n0(Q);if(F?.includes("Prisma")||g.includes("Prisma"))throw Q;throw Qn.create({message:`Failed to get media info: ${g}`,nonRetryable:!0,cause:Q instanceof Error?Q:void 0})}}async function ocB(B){let Q=process.env.S3_BUCKET||"shumai",F=AF.join(AF.dirname(B.assetKey),`video-${B.videoSpec.height}p.mp4`);try{return await pB.headObject(Q,F),{...B.videoSpec,key:F}}catch{}let g=AF.dirname(B.filePath),U=AF.join(g,`video-${B.videoSpec.height}p.mp4`);try{let I=0,n=!1;if(B.videoSpec.resolution==="180p"){if(n=!0,I=24,B.originalFps>0&&B.originalFps<24)I=B.originalFps;if(B.duration*I>1600)I=`160000/${Math.floor(B.duration*100)}`}await xI.transcodeVideo({inputFile:B.filePath,outputFile:U,width:B.videoSpec.width,height:B.videoSpec.height,frameRate:I||void 0,disableAudio:n});let c=dF.readFileSync(U);return await pB.putObject(Q,F,c,c.length,"video/mp4"),{...B.videoSpec,key:F}}catch(I){let{code:n,message:c}=n0(I),l=c.toLowerCase();if(n==="ENOENT"||l.includes("enoent")||l.includes("ffmpeg")||l.includes("ffprobe")||l.includes("spawn")||l.includes("format")||l.includes("no video stream found"))throw Qn.create({message:`Video transcoding failed: ${c}`,nonRetryable:!0,cause:I instanceof Error?I:void 0});throw I}finally{if(dF.existsSync(U))dF.unlinkSync(U)}}async function hcB(B){let Q=process.env.S3_BUCKET||"shumai",F=AF.join(AF.dirname(B.assetKey),`image-${B.imageSpec.width}p.webp`);try{return await pB.headObject(Q,F),{...B.imageSpec,key:F}}catch{}let g=AF.dirname(B.filePath),U=AF.join(g,`image-${B.imageSpec.width}p.webp`);try{await xI.transcodeImage(B.filePath,U,B.imageSpec.width,B.imageSpec.quality);let I=dF.readFileSync(U);return await pB.putObject(Q,F,I,I.length,"image/webp"),{...B.imageSpec,key:F}}catch(I){let{code:n,message:c}=n0(I),l=c.toLowerCase();if(n==="ENOENT"||l.includes("enoent")||l.includes("sharp")||l.includes("spawn")||l.includes("format"))throw Qn.create({message:`Image transcoding failed: ${c}`,nonRetryable:!0,cause:I instanceof Error?I:void 0});throw I}finally{if(dF.existsSync(U))dF.unlinkSync(U)}}async function NcB(B){let Q=process.env.S3_BUCKET||"shumai";try{return await pB.headObject(Q,B.spriteSpec.key),await pB.headObject(Q,B.posterSpec.key),{sprite:B.spriteSpec,poster:B.posterSpec}}catch{}let F=AF.dirname(B.filePath),g=AF.join(F,"sprite.webp"),U=AF.join(F,"poster.webp");try{await xI.generateSprite(B.filePath,g,U,B.mediaInfo.duration);let I=dF.readFileSync(g);await pB.putObject(Q,B.spriteSpec.key,I,I.length,"image/webp");let n=dF.readFileSync(U);return await pB.putObject(Q,B.posterSpec.key,n,n.length,"image/webp"),{sprite:B.spriteSpec,poster:B.posterSpec}}catch(I){let{code:n,message:c}=n0(I),l=c.toLowerCase();if(n==="ENOENT"||l.includes("enoent")||l.includes("ffmpeg")||l.includes("ffprobe")||l.includes("spawn")||l.includes("format"))throw Qn.create({message:`Sprite/Poster generation failed: ${c}`,nonRetryable:!0,cause:I instanceof Error?I:void 0});throw I}finally{if(dF.existsSync(g))dF.unlinkSync(g);if(dF.existsSync(U))dF.unlinkSync(U)}}async function LcB(B){let Q=process.env.S3_BUCKET||"shumai",F=xI.createTempDir("transcode-"),g=AF.join(F,AF.basename(B.assetKey));if(!dF.existsSync(F))dF.mkdirSync(F,{recursive:!0});try{await pB.downloadToFile(Q,B.assetKey,g)}catch(U){let{code:I,message:n}=n0(U),c=n.toLowerCase();if(I==="ENOENT"||c.includes("enoent")||c.includes("nosuchkey"))throw Qn.create({message:`Failed to download media to tmp: ${n}`,nonRetryable:!0,cause:U instanceof Error?U:void 0});throw U}return{filePath:g,tmpDir:F}}async function YcB(B){xI.removeDir(B.tmpDir)}async function HcB(B){let Q=process.env.S3_BUCKET||"shumai",F=await T.asset.findUnique({where:{id:B.assetId},include:{storageKey:!0}}),g=F?.storageKey?.key;if(!F||!g)throw Qn.create({message:"Asset not found or has no key",nonRetryable:!0});let U=AF.join(AF.dirname(g),"info.json"),I=Buffer.from(JSON.stringify(B.mediaInfo));await pB.putObject(Q,U,I,I.length,"application/json"),await T.asset.update({where:{id:B.assetId},data:{media:B.mediaInfo}})}async function JcB(B){try{return await xI.takeScreenshots(B)}catch(Q){let{code:F,message:g}=n0(Q),U=g.toLowerCase();if(F==="ENOENT"||U.includes("enoent")||U.includes("nosuchkey")||U.includes("ffmpeg")||U.includes("sharp"))throw Qn.create({message:`Screenshot extraction failed: ${g}`,nonRetryable:!0,cause:Q instanceof Error?Q:void 0});throw Q}}async function ScB(B){try{return await xI.overlayAnnotations(B)}catch(Q){let{code:F,message:g}=n0(Q),U=g.toLowerCase();if(F==="ENOENT"||U.includes("enoent")||U.includes("nosuchkey")||U.includes("ffmpeg")||U.includes("sharp"))throw Qn.create({message:`Overlay annotations failed: ${g}`,nonRetryable:!0,cause:Q instanceof Error?Q:void 0});throw Q}}async function pcB(B){let{teamId:Q,projectId:F}=B;if(!Q||!F){let I=await T.asset.findUnique({where:{id:B.assetId},include:{project:!0}});if(I)F=F||I.projectId,Q=Q||I.project?.teamId||null}if(!Q)return;let g=await T.agent.findFirst({where:{type:"embedding",enabled:!0,user:{teamMembers:{some:{teamId:Q}}}}});if(!g)return;if(await T.workflowTask.findFirst({where:{assetId:B.assetId,type:OQ.ai_embedding,status:{in:[zQ.pending,zQ.processing]}}}))return;await T.workflowTask.create({data:{assetId:B.assetId,type:OQ.ai_embedding,status:zQ.pending,teamId:Q,projectId:F,payload:{projectId:F??"",agent:{agentId:g.id}}}})}async function EcB(B){let Q=AF.join(p9.tmpdir(),`video-chunk-${Date.now()}.mp4`);try{await ycB("ffmpeg",["-y","-loglevel","warning","-i",B.filePath,"-ss",B.startTime.toString(),"-t",(B.endTime-B.startTime).toString(),"-vf","fps=1","-c:v","libx264","-preset","ultrafast","-crf","28","-an",Q]);let F=dF.readFileSync(Q),g=process.env.S3_BUCKET||"shumai",U=`files/${B.assetId}/tmp-embedding-chunks/chunk-${B.startTime}-${B.endTime}-${aF()}.mp4`;return await pB.putObject(g,U,F,F.length,"video/mp4"),{chunkKey:U}}catch(F){throw Qn.create({message:`Failed to transcode video chunk for ${B.startTime}-${B.endTime}: ${F instanceof Error?F.message:String(F)}`,nonRetryable:!1})}finally{if(dF.existsSync(Q))try{dF.unlinkSync(Q)}catch(F){console.error("Failed to cleanup local chunk file:",F)}}}async function DcB(B){let Q=process.env.S3_BUCKET||"shumai";await pB.deleteObject(Q,B.key)}import{ApplicationFailure as Ps}from"@temporalio/workflow";async function E9(B){let{updateTaskStatusActivity:Q,updateAssetStatusActivity:F,getAssetActivity:g,getMediaInfoActivity:U,transcodeVideoActivity:I,transcodeImageActivity:n,generateSpriteActivity:c,updateAssetMediaActivity:l,getTranscodeWorkerQueueActivity:b,downloadMediaToTmpActivity:G,cleanupTmpDirActivity:i,takeScreenshotsActivity:W,overlayAnnotationsActivity:a,createEmbeddingTaskIfEnabledActivity:V}=xX(),m,C="";try{C=await fQ(Fn,b),await fQ(C,Q,{taskId:B.id,status:"processing"});let x=B.payload;if(x?.screenshot){let E=await fQ(C,g,B.assetId),D=E?.storageKey?.key;if(!E||!D)throw Ps.create({message:"Asset not found or has no key",nonRetryable:!0});let k=await fQ(C,W,{assetKey:D,assetId:E.id,start:x.screenshot.start,end:x.screenshot.end,count:x.screenshot.count,commentTimestamp:x.screenshot.commentTimestamp,annotations:x.screenshot.annotations});await fQ(C,Q,{taskId:B.id,status:"completed",output:{screenshots:k}});return}if(x?.imageAnnotation){let E=await fQ(C,g,B.assetId),D=E?.storageKey?.key;if(E?.media){let v=E.media;if(v.imageTranscodes&&v.imageTranscodes.length>0)D=v.imageTranscodes[0].key||D}if(!E||!D)throw Ps.create({message:"Asset not found or has no key",nonRetryable:!0});let k=await fQ(C,a,{assetKey:D,assetId:E.id,annotations:x.imageAnnotation.annotations});await fQ(C,Q,{taskId:B.id,status:"completed",output:{key:k}});return}await fQ(C,F,{assetId:B.assetId,status:"processing"});let e=await fQ(C,g,B.assetId),Z=e?.storageKey?.key;if(!e||!Z)throw Ps.create({message:"Asset not found or has no key",nonRetryable:!0});let u=await fQ(C,G,{assetKey:Z}),{filePath:y}=u;m=u.tmpDir;let s=B.payload?.transcode||{},R=await fQ(C,U,{filePath:y,assetId:e.id,mediaType:e.mediaType||""});R.original={key:Z,downloadUrl:"",filesizeInBytes:0,codec:""};let{mimeType:A,metadata:N}=R;if(A.startsWith("video/")&&N){let E=kcB(s.videoStrategy||"best_match",N.originalWidth,N.originalHeight);for(let D of E){let[k,v]=zcB(D,N.originalWidth,N.originalHeight),j=await fQ(C,I,{assetKey:Z,filePath:y,videoSpec:{resolution:D,width:k,height:v},duration:N.duration,originalFps:N.frameRate});if(D==="180p")R.videoPreview=j;else R.videoTranscodes.push(j)}R.videoTranscodes.push({key:R.original?.key,width:N.originalWidth,height:N.originalHeight,isRaw:!0})}let H=A.startsWith("image/"),L=vcB(A);if((H||L)&&N){let E={width:N.originalWidth,height:N.originalHeight,quality:90,format:"webp"},D=await fQ(C,n,{assetKey:Z,filePath:y,imageSpec:E});R.imageTranscodes.push(D)}if(s.thumbnail){let E=await fQ(C,n,{assetKey:Z,filePath:y,imageSpec:{width:480,height:0,quality:80,format:"webp"}});R.thumbnail=E}if(s.sprite||s.poster){let E=Z.lastIndexOf("/"),D=E===-1?"":Z.substring(0,E),k={key:D?`${D}/sprite.webp`:"sprite.webp",frames:100,tileX:10,tileY:10},v={key:D?`${D}/poster.webp`:"poster.webp"},p=await fQ(C,c,{assetKey:Z,filePath:y,spriteSpec:k,posterSpec:v,mediaInfo:R});R.sprite=p.sprite,R.poster=p.poster}await fQ(C,l,{assetId:e.id,mediaInfo:R}),await fQ(C,F,{assetId:e.id,status:"processed"}),await fQ(C,V,{assetId:e.id,teamId:B.teamId,projectId:B.projectId}),await fQ(C,Q,{taskId:B.id,status:"completed"})}catch(x){if(console.error(`TranscodeMedia failed for task ${B.id}:`,x),C)await fQ(C,Q,{taskId:B.id,status:"failed",output:{error:x instanceof Error?x.message:String(x)}});throw x}finally{if(m&&C)try{await fQ(C,i,{tmpDir:m})}catch(x){console.error("Failed to cleanup tmp dir:",x)}}}function vcB(B){switch(B){case"image/vnd.adobe.photoshop":case"image/x-photoshop":case"application/x-photoshop":case"image/psd":return!0}return!1}var wcB={"2160p":3840,"1080p":1920,"720p":1280,"540p":960,"360p":640,"180p":320};function zcB(B,Q,F){let g=wcB[B];if(!g)return[0,0];let U,I;if(Q>=F)U=g,I=Math.round(U*(F/Q));else I=g,U=Math.round(I*(Q/F));if(U%2!==0)U++;if(I%2!==0)I++;return[U,I]}var jl=[{name:"2160p",longSide:3840},{name:"1080p",longSide:1920},{name:"720p",longSide:1280},{name:"540p",longSide:960},{name:"360p",longSide:640}];function TcB(B,Q){let F=Math.max(B,Q),g=jl.filter((U)=>U.longSide<=F);if(g.length>0)return g.sort((U,I)=>I.longSide-U.longSide),g[0];return jl[jl.length-1]}function kcB(B,Q,F){let g=["180p"],U=B,I=B;if(I==="single"||I==="disable")U="best_match";else if(I==="full")U="all";let n=TcB(Q,F);if(U==="best_match")g.push(n.name);else if(U==="all"){let c=jl.findIndex((l)=>l.name===n.name);if(c!==-1)for(let l=c;l<jl.length;l++)g.push(jl[l].name)}return g}class fs{db;assetId;teamId;projectId;spec={};constructor(B,Q,F,g){this.db=B;this.assetId=Q;this.teamId=F;this.projectId=g}setStrategy(B){return this.spec.videoStrategy=B,this}withSprite(){return this.spec.sprite=!0,this}withPoster(){return this.spec.poster=!0,this}async submit(){return(await this.db.workflowTask.create({data:{assetId:this.assetId,teamId:this.teamId,projectId:this.projectId,type:OQ.transcode,status:zQ.pending,payload:{projectId:this.projectId,transcode:this.spec}}})).id}}class Ks{db;assetId;teamId;projectId;spec={};constructor(B,Q,F,g){this.db=B;this.assetId=Q;this.teamId=F;this.projectId=g}withThumbnail(){return this.spec.thumbnail=!0,this}async submit(){return(await this.db.workflowTask.create({data:{assetId:this.assetId,teamId:this.teamId,projectId:this.projectId,type:OQ.transcode,status:zQ.pending,payload:{projectId:this.projectId,transcode:this.spec}}})).id}}function D9(){RX(OQ.transcode,E9),yX(js)}import{spawn as rcB}from"child_process";import{existsSync as _l,writeFileSync as M9,readFileSync as di,unlinkSync as Pl,mkdirSync as v9,statSync as w9,createReadStream as McB,openSync as OcB}from"fs";import{join as ai}from"path";import{homedir as fcB}from"os";var O9=ai(fcB(),".shumai"),z9=ai(O9,"pids"),T9=ai(O9,"logs");function bd(B){try{return process.kill(B,0),!0}catch(Q){if(Q&&typeof Q==="object"&&"code"in Q&&Q.code==="EPERM")return!0;return!1}}async function k9(B,Q){if(!_l(Q))return console.log(`No running instance of ${B} found.`),!1;let F=parseInt(di(Q,"utf8").trim(),10);if(isNaN(F)){console.log(`Invalid PID found in ${Q}. Cleaning up file.`);try{Pl(Q)}catch{}return!1}let g=bd(F);if(!g){console.log(`Process ${F} is not running. Cleaning up PID file.`);try{Pl(Q)}catch{}return!1}console.log(`Stopping ${B} (PID: ${F})...`);try{process.kill(F,"SIGTERM")}catch(U){return console.error(`Failed to send SIGTERM to process ${F}:`,U),!1}for(let U=0;U<30;U++){if(!bd(F)){g=!1;break}await new Promise((I)=>setTimeout(I,100))}if(g){console.log(`Process ${F} did not stop gracefully. Sending SIGKILL...`);try{process.kill(F,"SIGKILL")}catch(U){console.error(`Failed to send SIGKILL to process ${F}:`,U)}}try{Pl(Q)}catch{}return console.log(`Successfully stopped ${B}.`),!0}function r9(B,Q,F){if(_l(Q)){let n=parseInt(di(Q,"utf8").trim(),10);if(!isNaN(n)&&n!==process.pid)if(bd(n))console.error(`${B} is already running (PID: ${n}). Use '${B} stop' or '${B} restart'.`),process.exit(1);else try{Pl(Q)}catch{}}console.log(`Starting ${B} in background...`);let g=OcB(F,"w"),U=process.argv.slice(1).filter((n)=>n!=="-d"&&n!=="restart"),I=rcB(process.argv[0],U,{detached:!0,stdio:["ignore",g,g],env:{...process.env,SHUMAI_DAEMONIZED:"true"}});if(I.pid===void 0)console.error(`Failed to spawn background process for ${B}.`),process.exit(1);I.unref(),M9(Q,I.pid.toString(),"utf8"),console.log(`\uD83D\uDE80 Started ${B} in background (PID: ${I.pid}).`),console.log(`\uD83D\uDCC4 Logs are being written to ${F}`),process.exit(0)}function KcB(B,Q){if(!_l(Q))console.log(`No log file found for ${B}.`),process.exit(0);let U=di(Q,"utf8").split(`
12975
+ `)}</svg>`}var xI=new H9;class J9{prismaClient;constructor(B=T){this.prismaClient=B}async createUploadTask(B,Q){let F=Q.files.filter((W)=>!W.name.startsWith(".")),g=F.length===1?F[0].name:`${F.length} Items`,U=0,I=(W)=>{for(let a of W){if(a.name.startsWith("."))continue;if(a.type==="file")U++;else I(a.children)}};I(Q.files);let n=await this.prismaClient.task.create({data:{creatorId:B,type:"upload",name:g,total:U,status:Ai.pending}}),c=await this.prismaClient.asset.findUnique({where:{id:Q.parentId},include:{project:!0}});if(!c)throw Error("Parent asset not found");if(!c.projectId)throw Error("Parent asset has no project");let l=[],b=c.type===RB.file,G=b?c.parentId:c.id,i=[];return await this.prismaClient.$transaction(async(W)=>{let a=await this.createAssetsRecursively(W,B,n.id,c.projectId,G,Q.files,l,i);if(b&&a.length>0)for(let V of a)await Zc.reparentAssets({assetIds:[V],newParentId:c.id,creatorId:B},W);return a}),{taskId:n.id,presignedUrls:l,createdAssets:i}}async createAssetsRecursively(B,Q,F,g,U,I,n,c){let b=(await B.asset.findFirst({where:{parentId:U},orderBy:{sortIndex:"asc"}}))?.sortIndex||void 0,G=[];for(let i of I){if(i.name.startsWith("."))continue;let W=Mg(null,b||null);b=W;let a=i.type==="folder"?RB.folder:RB.file,V=null;if(a===RB.file)V=`files/${aF()}/raw`;let m=await B.asset.create({data:{name:i.name,type:a,storageKey:V?{create:{key:V}}:void 0,sortIndex:W,mediaType:i.mediaType,status:a===RB.folder?cc.uploaded:cc.uploading,sizeByte:i.size,creator:Q?{connect:{id:Q}}:void 0,parent:U?{connect:{id:U}}:void 0,project:{connect:{id:g}},task:{connect:{id:F}}}});if(G.push(m.id),c.push({tempId:i.id,assetId:m.id}),a===RB.folder&&U)await B.asset.update({where:{id:U},data:{fileCount:{increment:1}}});if(i.children&&i.children.length>0)await this.createAssetsRecursively(B,Q,F,g,m.id,i.children,n,c);else if(a===RB.file&&V){let C=await pB.presign(process.env.S3_BUCKET||"shumai",V,"PUT");n.push({id:i.id,fileId:m.id,url:C})}}return G}async confirmFileUpload(B,Q,F){let g=await this.prismaClient.asset.findUnique({where:{id:F.fileId},include:{storageKey:!0,project:{include:{team:!0}}}});if(!g)throw Error("Asset not found");if(!g.project)throw Error("Project not found for asset");let U=g.storageKey?.key;if(!U)throw Error("Asset has no key");if(F.errorMessage){if(await this.prismaClient.asset.delete({where:{id:g.id}}),await this.prismaClient.task.findUnique({where:{id:Q}})){let l=await this.prismaClient.task.update({where:{id:Q},data:{uploaded:{increment:1}}});if(l.uploaded===l.total)await this.prismaClient.task.update({where:{id:Q},data:{status:Ai.completed}})}return}let I=await pB.getObjectSize(process.env.S3_BUCKET||"shumai",U),n=g.project;await this.prismaClient.$transaction(async(c)=>{let l=await c.asset.update({where:{id:g.id},data:{status:cc.uploaded,sizeByte:I}});if(g.parentId)await c.asset.update({where:{id:g.parentId},data:{fileCount:{increment:1}}}),await Zc.updateAncestorsSize(c,g.parentId,l.sizeByte);let b=await c.task.update({where:{id:Q},data:{uploaded:{increment:1}}});if(b.uploaded===(b.total||0))await c.task.update({where:{id:Q},data:{status:Ai.completed}});let G=n.team;if(!G)return;if(!g.projectId)throw Error("Asset project ID is missing");await this.triggerPostUploadWorkflows(c,g.id,G.id,g.projectId)})}async triggerPostUploadWorkflows(B,Q,F,g){let U=await B.asset.findUnique({where:{id:Q}});if(!U)throw Error("Asset not found");let I=await B.team.findUnique({where:{id:F}});if(!I)throw Error("Team not found");let n=await B.agent.findFirst({where:{type:"autofill",enabled:!0,user:{teamMembers:{some:{teamId:I.id}}}}});if(n)await B.workflowTask.create({data:{assetId:U.id,type:OQ.ai_metadata_autofill,status:zQ.pending,teamId:I.id,projectId:g,payload:{projectId:g,agent:{agentId:n.id}}}});let c=U.mediaType?.startsWith("video/"),l=U.mediaType?.startsWith("image/");if(!c&&!l)await B.asset.update({where:{id:U.id},data:{status:cc.processed}});else{let b=I.settings;if(c){let G=b?.transcode?.videoStrategy||"best_match";await new fs(B,U.id,I.id,g).setStrategy(G).withSprite().withPoster().submit()}else if(l)await new Ks(B,U.id,I.id,g).withThumbnail().submit()}}async listUploadTasks(B,Q){let F={creatorId:B,type:"upload"},{data:g,pageInfo:U}=await mg(async(n,c)=>{return this.prismaClient.task.findMany({where:F,orderBy:{id:"desc"},skip:n,take:c})},async()=>this.prismaClient.task.count({where:F}),Q);return{data:g.map((n)=>({id:n.id,name:n.name||"",total:n.total||0,uploaded:n.uploaded,createdAt:n.createdAt.toISOString()})),pageInfo:U}}}var rfB=new J9;function xcB(B){if(!B)return Mg(null,null);return Mg(B,null)}class S9{prismaClient;constructor(B=T){this.prismaClient=B}async createVersionStack(B){let{fileIds:Q,projectId:F,creatorId:g}=B;if(!Q||Q.length===0)throw Error("no file ids provided");return await this.prismaClient.$transaction(async(U)=>{let I=await U.asset.findMany({where:{id:{in:Q}},include:{parent:!0}});if(I.length!==Q.length)throw Error("some files not found");let n=void 0,c=0;for(let a of I){if(a.type!==RB.file)throw Error(`asset ${a.id} is not a file`);if(!a.parentId)throw Error(`file ${a.id} does not have a parent`);if(n===void 0)n=a.parentId;else if(a.parentId!==n)throw Error("files do not have the same parent");c+=a.sizeByte}if(!n)throw Error("files do not have a parent");if(!await U.asset.findUnique({where:{id:n}}))throw Error("parent not found");let G=I.find((a)=>a.id===Q[0])?.sortIndex||null,i=await U.asset.create({data:{type:RB.version_stack,fileCount:I.length,sizeByte:c,status:"uploaded",projectId:F,creatorId:g,parentId:n,sortIndex:G}}),W=null;for(let a of Q)W=xcB(W),await U.asset.update({where:{id:a},data:{parentId:i.id,sortIndex:W}});return await U.asset.update({where:{id:n},data:{fileCount:{decrement:I.length-1}}}),i})}async changeStackFileVersion(B){let{stackId:Q,fileId:F,beforeId:g}=B;await this.prismaClient.$transaction(async(U)=>{let I=await U.asset.findUnique({where:{id:Q}});if(!I)throw Error("stack not found");if(I.type!==RB.version_stack)throw Error("asset is not a version stack");let n=await U.asset.findUnique({where:{id:F}});if(!n)throw Error("file not found");if(n.parentId!==Q)throw Error("file is not in the stack");let c;if(g==="-1"){let l=await U.asset.findFirst({where:{parentId:Q},orderBy:{sortIndex:"desc"}});c=Mg(l?.sortIndex||null,null)}else{let l=await U.asset.findUnique({where:{id:g}});if(!l)throw Error("before_id file not found");if(l.parentId!==Q)throw Error("before_id file is not in the stack");let G=(await U.asset.findFirst({where:{parentId:Q,sortIndex:{lt:l.sortIndex}},orderBy:{sortIndex:"desc"}}))?.sortIndex||null;if(G&&G>=l.sortIndex)G=null;c=Mg(G,l.sortIndex)}await U.asset.update({where:{id:F},data:{sortIndex:c}})})}}var jfB=new S9;import{ApplicationFailure as Qn}from"@temporalio/activity";import*as AF from"path";import*as dF from"fs";import*as p9 from"os";import{execFile as ecB}from"child_process";import{promisify as RcB}from"util";var ycB=RcB(ecB);function n0(B){if(B&&typeof B==="object"){let Q=B;return{code:typeof Q.code==="string"?Q.code:void 0,message:typeof Q.message==="string"?Q.message:String(B),name:typeof Q.name==="string"?Q.name:void 0}}return{message:String(B)}}async function AcB(B){try{let Q=B.mediaType.startsWith("video/"),F=B.mediaType.startsWith("image/"),g=B.mediaType.startsWith("audio/"),U=B.mediaType.startsWith("text/")||B.mediaType==="application/pdf"||B.mediaType.includes("msword")||B.mediaType.includes("officedocument")||B.mediaType.includes("vnd.ms-"),I=Q?"video":g?"audio":F?"image":U?"document":"file",n={duration:0,filesize:0,fps:0,frames:0,imageTranscodes:[],videoTranscodes:[],videoPreview:{width:0,height:0},finishedAt:new Date().toISOString(),metadata:null,mimeType:B.mediaType,original:{key:"",downloadUrl:"",filesizeInBytes:0,codec:""}},c=[{key:"file_type",value:I}];if(Q){let l=await xI.getVideoInfo(B.filePath);if(n.duration=l.duration,n.fps=l.frameRate,n.metadata={originalWidth:l.originalWidth,originalHeight:l.originalHeight,duration:l.duration,bitRate:l.bitRate,frameRate:l.frameRate,hasAudio:l.hasAudio,videoCodec:l.videoCodec,audioCodec:l.audioCodec,audioChannels:l.audioChannels,audioSampleRate:l.audioSampleRate,audioBitDepth:l.audioBitDepth,format:{}},c.push({key:"resolution_width",value:l.originalWidth},{key:"resolution_height",value:l.originalHeight},{key:"duration",value:l.duration},{key:"bitRate",value:l.bitRate/1000},{key:"frame_rate",value:l.frameRate}),l.videoCodec)c.push({key:"video_codec",value:l.videoCodec});if(l.audioCodec)c.push({key:"audio_codec",value:l.audioCodec});if(l.audioChannels!==void 0)c.push({key:"audio_channels",value:l.audioChannels});if(l.audioSampleRate!==void 0)c.push({key:"audio_sample_rate",value:l.audioSampleRate});if(l.audioBitDepth!==void 0)c.push({key:"audio_bit_depth",value:l.audioBitDepth})}else if(F){let l=await xI.getImageInfo(B.filePath);n.metadata={originalWidth:l.originalWidth,originalHeight:l.originalHeight,duration:0,bitRate:0,frameRate:0,hasAudio:!1,format:{}},c.push({key:"resolution_width",value:l.originalWidth},{key:"resolution_height",value:l.originalHeight})}return await dp.updateAssetMetadata(B.assetId,c,!0),n}catch(Q){let{name:F,message:g}=n0(Q);if(F?.includes("Prisma")||g.includes("Prisma"))throw Q;throw Qn.create({message:`Failed to get media info: ${g}`,nonRetryable:!0,cause:Q instanceof Error?Q:void 0})}}async function ocB(B){let Q=process.env.S3_BUCKET||"shumai",F=AF.join(AF.dirname(B.assetKey),`video-${B.videoSpec.height}p.mp4`);try{return await pB.headObject(Q,F),{...B.videoSpec,key:F}}catch{}let g=AF.dirname(B.filePath),U=AF.join(g,`video-${B.videoSpec.height}p.mp4`);try{let I=0,n=!1;if(B.videoSpec.resolution==="180p"){if(n=!0,I=24,B.originalFps>0&&B.originalFps<24)I=B.originalFps;if(B.duration*I>1600)I=`160000/${Math.floor(B.duration*100)}`}await xI.transcodeVideo({inputFile:B.filePath,outputFile:U,width:B.videoSpec.width,height:B.videoSpec.height,frameRate:I||void 0,disableAudio:n});let c=dF.readFileSync(U);return await pB.putObject(Q,F,c,c.length,"video/mp4"),{...B.videoSpec,key:F}}catch(I){let{code:n,message:c}=n0(I),l=c.toLowerCase();if(n==="ENOENT"||l.includes("enoent")||l.includes("ffmpeg")||l.includes("ffprobe")||l.includes("spawn")||l.includes("format")||l.includes("no video stream found"))throw Qn.create({message:`Video transcoding failed: ${c}`,nonRetryable:!0,cause:I instanceof Error?I:void 0});throw I}finally{if(dF.existsSync(U))dF.unlinkSync(U)}}async function hcB(B){let Q=process.env.S3_BUCKET||"shumai",F=AF.join(AF.dirname(B.assetKey),`image-${B.imageSpec.width}p.webp`);try{return await pB.headObject(Q,F),{...B.imageSpec,key:F}}catch{}let g=AF.dirname(B.filePath),U=AF.join(g,`image-${B.imageSpec.width}p.webp`);try{await xI.transcodeImage(B.filePath,U,B.imageSpec.width,B.imageSpec.quality);let I=dF.readFileSync(U);return await pB.putObject(Q,F,I,I.length,"image/webp"),{...B.imageSpec,key:F}}catch(I){let{code:n,message:c}=n0(I),l=c.toLowerCase();if(n==="ENOENT"||l.includes("enoent")||l.includes("sharp")||l.includes("spawn")||l.includes("format"))throw Qn.create({message:`Image transcoding failed: ${c}`,nonRetryable:!0,cause:I instanceof Error?I:void 0});throw I}finally{if(dF.existsSync(U))dF.unlinkSync(U)}}async function NcB(B){let Q=process.env.S3_BUCKET||"shumai";try{return await pB.headObject(Q,B.spriteSpec.key),await pB.headObject(Q,B.posterSpec.key),{sprite:B.spriteSpec,poster:B.posterSpec}}catch{}let F=AF.dirname(B.filePath),g=AF.join(F,"sprite.webp"),U=AF.join(F,"poster.webp");try{await xI.generateSprite(B.filePath,g,U,B.mediaInfo.duration);let I=dF.readFileSync(g);await pB.putObject(Q,B.spriteSpec.key,I,I.length,"image/webp");let n=dF.readFileSync(U);return await pB.putObject(Q,B.posterSpec.key,n,n.length,"image/webp"),{sprite:B.spriteSpec,poster:B.posterSpec}}catch(I){let{code:n,message:c}=n0(I),l=c.toLowerCase();if(n==="ENOENT"||l.includes("enoent")||l.includes("ffmpeg")||l.includes("ffprobe")||l.includes("spawn")||l.includes("format"))throw Qn.create({message:`Sprite/Poster generation failed: ${c}`,nonRetryable:!0,cause:I instanceof Error?I:void 0});throw I}finally{if(dF.existsSync(g))dF.unlinkSync(g);if(dF.existsSync(U))dF.unlinkSync(U)}}async function LcB(B){let Q=process.env.S3_BUCKET||"shumai",F=xI.createTempDir("transcode-"),g=AF.join(F,AF.basename(B.assetKey));if(!dF.existsSync(F))dF.mkdirSync(F,{recursive:!0});try{await pB.downloadToFile(Q,B.assetKey,g)}catch(U){let{code:I,message:n}=n0(U),c=n.toLowerCase();if(I==="ENOENT"||c.includes("enoent")||c.includes("nosuchkey"))throw Qn.create({message:`Failed to download media to tmp: ${n}`,nonRetryable:!0,cause:U instanceof Error?U:void 0});throw U}return{filePath:g,tmpDir:F}}async function YcB(B){xI.removeDir(B.tmpDir)}async function HcB(B){let Q=process.env.S3_BUCKET||"shumai",F=await T.asset.findUnique({where:{id:B.assetId},include:{storageKey:!0}}),g=F?.storageKey?.key;if(!F||!g)throw Qn.create({message:"Asset not found or has no key",nonRetryable:!0});let U=AF.join(AF.dirname(g),"info.json"),I=Buffer.from(JSON.stringify(B.mediaInfo));await pB.putObject(Q,U,I,I.length,"application/json"),await T.asset.update({where:{id:B.assetId},data:{media:B.mediaInfo}})}async function JcB(B){try{return await xI.takeScreenshots(B)}catch(Q){let{code:F,message:g}=n0(Q),U=g.toLowerCase();if(F==="ENOENT"||U.includes("enoent")||U.includes("nosuchkey")||U.includes("ffmpeg")||U.includes("sharp"))throw Qn.create({message:`Screenshot extraction failed: ${g}`,nonRetryable:!0,cause:Q instanceof Error?Q:void 0});throw Q}}async function ScB(B){try{return await xI.overlayAnnotations(B)}catch(Q){let{code:F,message:g}=n0(Q),U=g.toLowerCase();if(F==="ENOENT"||U.includes("enoent")||U.includes("nosuchkey")||U.includes("ffmpeg")||U.includes("sharp"))throw Qn.create({message:`Overlay annotations failed: ${g}`,nonRetryable:!0,cause:Q instanceof Error?Q:void 0});throw Q}}async function pcB(B){let{teamId:Q,projectId:F}=B;if(!Q||!F){let I=await T.asset.findUnique({where:{id:B.assetId},include:{project:!0}});if(I)F=F||I.projectId,Q=Q||I.project?.teamId||null}if(!Q)return;let g=await T.agent.findFirst({where:{type:"embedding",enabled:!0,user:{teamMembers:{some:{teamId:Q}}}}});if(!g)return;if(await T.workflowTask.findFirst({where:{assetId:B.assetId,type:OQ.ai_embedding,status:{in:[zQ.pending,zQ.processing]}}}))return;await T.workflowTask.create({data:{assetId:B.assetId,type:OQ.ai_embedding,status:zQ.pending,teamId:Q,projectId:F,payload:{projectId:F??"",agent:{agentId:g.id}}}})}async function EcB(B){let Q=AF.join(p9.tmpdir(),`video-chunk-${Date.now()}.mp4`);try{await ycB("ffmpeg",["-y","-loglevel","warning","-i",B.filePath,"-ss",B.startTime.toString(),"-t",(B.endTime-B.startTime).toString(),"-vf","fps=1","-c:v","libx264","-preset","ultrafast","-crf","28","-an",Q]);let F=dF.readFileSync(Q),g=process.env.S3_BUCKET||"shumai",U=`files/${B.assetId}/tmp-embedding-chunks/chunk-${B.startTime}-${B.endTime}-${aF()}.mp4`;return await pB.putObject(g,U,F,F.length,"video/mp4"),{chunkKey:U}}catch(F){throw Qn.create({message:`Failed to transcode video chunk for ${B.startTime}-${B.endTime}: ${F instanceof Error?F.message:String(F)}`,nonRetryable:!1})}finally{if(dF.existsSync(Q))try{dF.unlinkSync(Q)}catch(F){console.error("Failed to cleanup local chunk file:",F)}}}async function DcB(B){let Q=process.env.S3_BUCKET||"shumai";await pB.deleteObject(Q,B.key)}import{ApplicationFailure as Ps}from"@temporalio/workflow";async function E9(B){let{updateTaskStatusActivity:Q,updateAssetStatusActivity:F,getAssetActivity:g,getMediaInfoActivity:U,transcodeVideoActivity:I,transcodeImageActivity:n,generateSpriteActivity:c,updateAssetMediaActivity:l,getTranscodeWorkerQueueActivity:b,downloadMediaToTmpActivity:G,cleanupTmpDirActivity:i,takeScreenshotsActivity:W,overlayAnnotationsActivity:a,createEmbeddingTaskIfEnabledActivity:V}=xX(),m,C="";try{C=await fQ(Fn,b),await fQ(C,Q,{taskId:B.id,status:"processing"});let x=B.payload;if(x?.screenshot){let E=await fQ(C,g,B.assetId),D=E?.storageKey?.key;if(!E||!D)throw Ps.create({message:"Asset not found or has no key",nonRetryable:!0});let k=await fQ(C,W,{assetKey:D,assetId:E.id,start:x.screenshot.start,end:x.screenshot.end,count:x.screenshot.count,commentTimestamp:x.screenshot.commentTimestamp,annotations:x.screenshot.annotations});await fQ(C,Q,{taskId:B.id,status:"completed",output:{screenshots:k}});return}if(x?.imageAnnotation){let E=await fQ(C,g,B.assetId),D=E?.storageKey?.key;if(E?.media){let v=E.media;if(v.imageTranscodes&&v.imageTranscodes.length>0)D=v.imageTranscodes[0].key||D}if(!E||!D)throw Ps.create({message:"Asset not found or has no key",nonRetryable:!0});let k=await fQ(C,a,{assetKey:D,assetId:E.id,annotations:x.imageAnnotation.annotations});await fQ(C,Q,{taskId:B.id,status:"completed",output:{key:k}});return}await fQ(C,F,{assetId:B.assetId,status:"processing"});let e=await fQ(C,g,B.assetId),Z=e?.storageKey?.key;if(!e||!Z)throw Ps.create({message:"Asset not found or has no key",nonRetryable:!0});let u=await fQ(C,G,{assetKey:Z}),{filePath:y}=u;m=u.tmpDir;let s=B.payload?.transcode||{},R=await fQ(C,U,{filePath:y,assetId:e.id,mediaType:e.mediaType||""});R.original={key:Z,downloadUrl:"",filesizeInBytes:0,codec:""};let{mimeType:A,metadata:N}=R;if(A.startsWith("video/")&&N){let E=kcB(s.videoStrategy||"best_match",N.originalWidth,N.originalHeight);for(let D of E){let[k,v]=zcB(D,N.originalWidth,N.originalHeight),j=await fQ(C,I,{assetKey:Z,filePath:y,videoSpec:{resolution:D,width:k,height:v},duration:N.duration,originalFps:N.frameRate});if(D==="180p")R.videoPreview=j;else R.videoTranscodes.push(j)}R.videoTranscodes.push({key:R.original?.key,width:N.originalWidth,height:N.originalHeight,isRaw:!0})}let H=A.startsWith("image/"),L=vcB(A);if((H||L)&&N){let E={width:N.originalWidth,height:N.originalHeight,quality:90,format:"webp"},D=await fQ(C,n,{assetKey:Z,filePath:y,imageSpec:E});R.imageTranscodes.push(D)}if(s.thumbnail){let E=await fQ(C,n,{assetKey:Z,filePath:y,imageSpec:{width:480,height:0,quality:80,format:"webp"}});R.thumbnail=E}if(s.sprite||s.poster){let E=Z.lastIndexOf("/"),D=E===-1?"":Z.substring(0,E),k={key:D?`${D}/sprite.webp`:"sprite.webp",frames:100,tileX:10,tileY:10},v={key:D?`${D}/poster.webp`:"poster.webp"},p=await fQ(C,c,{assetKey:Z,filePath:y,spriteSpec:k,posterSpec:v,mediaInfo:R});R.sprite=p.sprite,R.poster=p.poster}await fQ(C,l,{assetId:e.id,mediaInfo:R}),await fQ(C,F,{assetId:e.id,status:"processed"}),await fQ(C,V,{assetId:e.id,teamId:B.teamId,projectId:B.projectId}),await fQ(C,Q,{taskId:B.id,status:"completed"})}catch(x){if(console.error(`TranscodeMedia failed for task ${B.id}:`,x),C)await fQ(C,Q,{taskId:B.id,status:"failed",output:{error:x instanceof Error?x.message:String(x)}});throw x}finally{if(m&&C)try{await fQ(C,i,{tmpDir:m})}catch(x){console.error("Failed to cleanup tmp dir:",x)}}}function vcB(B){switch(B){case"image/vnd.adobe.photoshop":case"image/x-photoshop":case"application/x-photoshop":case"image/psd":return!0}return!1}var wcB={"2160p":3840,"1080p":1920,"720p":1280,"540p":960,"360p":640,"180p":320};function zcB(B,Q,F){let g=wcB[B];if(!g)return[0,0];let U,I;if(Q>=F)U=g,I=Math.round(U*(F/Q));else I=g,U=Math.round(I*(Q/F));if(U%2!==0)U++;if(I%2!==0)I++;return[U,I]}var jl=[{name:"2160p",longSide:3840},{name:"1080p",longSide:1920},{name:"720p",longSide:1280},{name:"540p",longSide:960},{name:"360p",longSide:640}];function TcB(B,Q){let F=Math.max(B,Q),g=jl.filter((U)=>U.longSide<=F);if(g.length>0)return g.sort((U,I)=>I.longSide-U.longSide),g[0];return jl[jl.length-1]}function kcB(B,Q,F){let g=["180p"],U=B,I=B;if(I==="single"||I==="disable")U="best_match";else if(I==="full")U="all";let n=TcB(Q,F);if(U==="best_match")g.push(n.name);else if(U==="all"){let c=jl.findIndex((l)=>l.name===n.name);if(c!==-1)for(let l=c;l<jl.length;l++)g.push(jl[l].name)}return g}class fs{db;assetId;teamId;projectId;spec={};constructor(B,Q,F,g){this.db=B;this.assetId=Q;this.teamId=F;this.projectId=g}setStrategy(B){return this.spec.videoStrategy=B,this}withSprite(){return this.spec.sprite=!0,this}withPoster(){return this.spec.poster=!0,this}async submit(){return(await this.db.workflowTask.create({data:{assetId:this.assetId,teamId:this.teamId,projectId:this.projectId,type:OQ.transcode,status:zQ.pending,payload:{projectId:this.projectId,transcode:this.spec}}})).id}}class Ks{db;assetId;teamId;projectId;spec={};constructor(B,Q,F,g){this.db=B;this.assetId=Q;this.teamId=F;this.projectId=g}withThumbnail(){return this.spec.thumbnail=!0,this}async submit(){return(await this.db.workflowTask.create({data:{assetId:this.assetId,teamId:this.teamId,projectId:this.projectId,type:OQ.transcode,status:zQ.pending,payload:{projectId:this.projectId,transcode:this.spec}}})).id}}function D9(){RX(OQ.transcode,E9),yX(js)}import{spawn as rcB}from"child_process";import{existsSync as _l,writeFileSync as M9,readFileSync as di,unlinkSync as Pl,mkdirSync as v9,statSync as w9,createReadStream as McB,openSync as OcB}from"fs";import{join as ai}from"path";import{homedir as fcB}from"os";var O9=ai(fcB(),".shumai"),z9=ai(O9,"pids"),T9=ai(O9,"logs");function bd(B){try{return process.kill(B,0),!0}catch(Q){if(Q&&typeof Q==="object"&&"code"in Q&&Q.code==="EPERM")return!0;return!1}}async function k9(B,Q){if(!_l(Q))return console.log(`No running instance of ${B} found.`),!1;let F=parseInt(di(Q,"utf8").trim(),10);if(isNaN(F)){console.log(`Invalid PID found in ${Q}. Cleaning up file.`);try{Pl(Q)}catch{}return!1}let g=bd(F);if(!g){console.log(`Process ${F} is not running. Cleaning up PID file.`);try{Pl(Q)}catch{}return!1}console.log(`Stopping ${B} (PID: ${F})...`);try{process.kill(F,"SIGTERM")}catch(U){return console.error(`Failed to send SIGTERM to process ${F}:`,U),!1}for(let U=0;U<30;U++){if(!bd(F)){g=!1;break}await new Promise((I)=>setTimeout(I,100))}if(g){console.log(`Process ${F} did not stop gracefully. Sending SIGKILL...`);try{process.kill(F,"SIGKILL")}catch(U){console.error(`Failed to send SIGKILL to process ${F}:`,U)}}try{Pl(Q)}catch{}return console.log(`Successfully stopped ${B}.`),!0}function r9(B,Q,F){if(_l(Q)){let n=parseInt(di(Q,"utf8").trim(),10);if(!isNaN(n)&&n!==process.pid)if(bd(n))console.error(`${B} is already running (PID: ${n}). Use '${B} stop' or '${B} restart'.`),process.exit(1);else try{Pl(Q)}catch{}}console.log(`Starting ${B} in background...`);let g=OcB(F,"w"),U=process.argv.slice(1).filter((n)=>n!=="-d"&&n!=="restart"),I=rcB(process.argv[0],U,{detached:!0,stdio:["ignore",g,g],env:{...process.env,SHUMAI_DAEMONIZED:"true"}});if(I.pid===void 0)console.error(`Failed to spawn background process for ${B}.`),process.exit(1);I.unref(),M9(Q,I.pid.toString(),"utf8"),console.log(`\uD83D\uDE80 Started ${B} in background (PID: ${I.pid}).`),console.log(`\uD83D\uDCC4 Logs are being written to ${F}`),process.exit(0)}function KcB(B,Q){if(!_l(Q))console.log(`No log file found for ${B}.`),process.exit(0);let U=di(Q,"utf8").split(`
12976
12976
  `).slice(-100).join(`
12977
12977
  `);process.stdout.write(U+`
12978
12978
  `);let I=w9(Q).size,n=setInterval(()=>{try{if(_l(Q)){let l=w9(Q);if(l.size>I)McB(Q,{start:I,end:l.size-1}).pipe(process.stdout,{end:!1}),I=l.size;else if(l.size<I)I=l.size}}catch{}},250),c=()=>{clearInterval(n),process.exit(0)};process.on("SIGINT",c),process.on("SIGTERM",c)}async function f9(B,Q){let F=ai(z9,`${B}.pid`),g=ai(T9,`${B}.log`);v9(z9,{recursive:!0}),v9(T9,{recursive:!0});let U=process.argv.slice(2),I=U.includes("stop"),n=U.includes("restart"),c=U.includes("logs"),l=U.includes("-d")&&process.env.SHUMAI_DAEMONIZED!=="true";if(I)await k9(B,F),process.exit(0);if(n)await k9(B,F),await new Promise((i)=>setTimeout(i,500)),r9(B,F,g),process.exit(0);if(c)return KcB(B,g),new Promise(()=>{});if(l)r9(B,F,g),process.exit(0);if(_l(F)){let i=parseInt(di(F,"utf8").trim(),10);if(!isNaN(i)&&i!==process.pid)if(bd(i))console.error(`${B} is already running (PID: ${i}). Use '${B} stop' or '${B} restart'.`),process.exit(1);else try{Pl(F)}catch{}}M9(F,process.pid.toString(),"utf8");let b=()=>{try{if(_l(F)){let i=di(F,"utf8").trim();if(parseInt(i,10)===process.pid)Pl(F)}}catch{}};process.on("exit",b);let G=(i)=>{if(process.listenerCount(i)===1)process.exit(0)};process.on("SIGINT",()=>G("SIGINT")),process.on("SIGTERM",()=>G("SIGTERM")),await Q()}ZX(process.cwd(),!1);if(process.argv.includes("--check"))console.log("\u2705 Transcode worker evaluated successfully!"),process.exit(0);async function PcB(){D9(),console.log("\uD83D\uDE80 Starting Transcode Worker...");let B={};{let{default:Q}=await Promise.resolve().then(() => (j9(),K9));B.workflowBundle=Q}await cb.startWorkers(Fn,B)}f9("shumai-transcode",PcB).catch((B)=>{console.error(B),process.exit(1)});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shumai-one/shumai-transcode",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Media transcoding worker for the shumai media workspace",
5
5
  "type": "module",
6
6
  "bin": {
@@ -26,12 +26,12 @@
26
26
  "zod": "4.4.3"
27
27
  },
28
28
  "optionalDependencies": {
29
- "@shumai-one/shumai-transcode-darwin-arm64": "0.1.0",
30
- "@shumai-one/shumai-transcode-darwin-x64": "0.1.0",
31
- "@shumai-one/shumai-transcode-linux-arm64": "0.1.0",
32
- "@shumai-one/shumai-transcode-linux-x64": "0.1.0",
33
- "@shumai-one/shumai-transcode-win32-arm64": "0.1.0",
34
- "@shumai-one/shumai-transcode-win32-x64": "0.1.0"
29
+ "@shumai-one/shumai-transcode-darwin-arm64": "0.1.1",
30
+ "@shumai-one/shumai-transcode-darwin-x64": "0.1.1",
31
+ "@shumai-one/shumai-transcode-linux-arm64": "0.1.1",
32
+ "@shumai-one/shumai-transcode-linux-x64": "0.1.1",
33
+ "@shumai-one/shumai-transcode-win32-arm64": "0.1.1",
34
+ "@shumai-one/shumai-transcode-win32-x64": "0.1.1"
35
35
  },
36
36
  "repository": {
37
37
  "type": "git",