import { chmodSync,mkdirSync,writeFileSync } from 'node:fs'; import { basename,join } from 'node:path';
const MAX_BYTES=45*1024*1024;
export const sanitizeInboundFileName=(name:string)=>{const clean=basename(name.replace(/\\/g,'/')).replace(/^\.+/,'');return clean||'attachment.bin'};
const fetchError=(stage:string)=>new Error(`Telegram ${stage} request failed`);
export async function fetchInboundFile(token:string,fileId:string,fileName:string,messageId:string,deps?:{fetchImpl?:typeof fetch;root?:string}):Promise<string>{const fetchImpl=deps?.fetchImpl??fetch,root=deps?.root??join(process.env.HOME??'','.local/state/overdeck/botmaster/files'),name=sanitizeInboundFileName(fileName),dir=join(root,messageId);let info:Response;try{info=await fetchImpl(`https://api.telegram.org/bot${token}/getFile?file_id=${encodeURIComponent(fileId)}`)}catch{throw fetchError('getFile')}if(!info.ok)throw new Error(`Telegram getFile failed: HTTP ${info.status}`);let result:any;try{const body:any=await info.json();result=body?.result;if(body?.ok!==true||!result?.file_path)throw new Error()}catch{throw new Error('Telegram getFile returned no file path')}if(Number(result.file_size??0)>MAX_BYTES)throw new Error('inbound attachment exceeds 45 MB');let download:Response;try{download=await fetchImpl(`https://api.telegram.org/file/bot${token}/${result.file_path}`)}catch{throw fetchError('file download')}if(!download.ok)throw new Error(`Telegram file download failed: HTTP ${download.status}`);let bytes:Uint8Array;try{bytes=new Uint8Array(await download.arrayBuffer())}catch{throw new Error('Telegram file download could not be read')}if(bytes.byteLength>MAX_BYTES)throw new Error('inbound attachment exceeds 45 MB');mkdirSync(root,{recursive:true,mode:0o700});chmodSync(root,0o700);mkdirSync(dir,{recursive:true,mode:0o700});chmodSync(dir,0o700);const path=join(dir,name);writeFileSync(path,bytes,{mode:0o600});chmodSync(path,0o600);return path}
