@@ -5,23 +5,23 @@ const stream_1 = require("stream");
55const fs_1 = require ( "fs" ) ;
66const os_1 = require ( "os" ) ;
77const path_1 = require ( "path" ) ;
8- const fs_2 = require ( "fs" ) ;
98const promises_1 = require ( "stream/promises" ) ;
9+ const uuid_1 = require ( "uuid" ) ;
10+ const mime = require ( "mime-types" ) ;
1011/**
1112 * @param pathOrUrl - a file path or a URL
1213 * @returns a Readable stream of the file content
1314 */
1415async function getFileStream ( pathOrUrl ) {
1516 if ( isUrl ( pathOrUrl ) ) {
1617 const response = await fetch ( pathOrUrl ) ;
17- if ( ! response . ok ) {
18+ if ( ! response . ok || ! response . body ) {
1819 throw new Error ( `Failed to fetch ${ pathOrUrl } : ${ response . status } ${ response . statusText } ` ) ;
1920 }
2021 return stream_1 . Readable . fromWeb ( response . body ) ;
2122 }
2223 else {
23- // Check if file exists first (this will throw if file doesn't exist)
24- await fs_1 . promises . stat ( pathOrUrl ) ;
24+ await safeStat ( pathOrUrl ) ;
2525 return fs_1 . createReadStream ( pathOrUrl ) ;
2626 }
2727}
@@ -48,12 +48,22 @@ function isUrl(pathOrUrl) {
4848 return false ;
4949 }
5050}
51+ async function safeStat ( path ) {
52+ try {
53+ return await fs_1 . promises . stat ( path ) ;
54+ }
55+ catch ( _a ) {
56+ throw new Error ( `File not found: ${ path } ` ) ;
57+ }
58+ }
5159async function getLocalFileStreamAndMetadata ( filePath ) {
52- const stats = await fs_1 . promises . stat ( filePath ) ;
60+ const stats = await safeStat ( filePath ) ;
61+ const contentType = mime . lookup ( filePath ) || undefined ;
5362 const metadata = {
5463 size : stats . size ,
5564 lastModified : stats . mtime ,
56- name : filePath . split ( "/" ) . pop ( ) || filePath . split ( "\\" ) . pop ( ) ,
65+ name : path_1 . basename ( filePath ) ,
66+ contentType,
5767 } ;
5868 const stream = fs_1 . createReadStream ( filePath ) ;
5969 return {
@@ -63,7 +73,7 @@ async function getLocalFileStreamAndMetadata(filePath) {
6373}
6474async function getRemoteFileStreamAndMetadata ( url ) {
6575 const response = await fetch ( url ) ;
66- if ( ! response . ok ) {
76+ if ( ! response . ok || ! response . body ) {
6777 throw new Error ( `Failed to fetch ${ url } : ${ response . status } ${ response . statusText } ` ) ;
6878 }
6979 const headers = response . headers ;
@@ -98,35 +108,43 @@ async function getRemoteFileStreamAndMetadata(url) {
98108}
99109async function downloadToTemporaryFile ( response , baseMetadata ) {
100110 // Generate unique temporary file path
101- const tempFileName = `file-stream-${ Date . now ( ) } -${ Math . random ( ) . toString ( 36 )
102- . substring ( 2 ) } `;
111+ const tempFileName = `file-stream-${ uuid_1 . v4 ( ) } ` ;
103112 const tempFilePath = path_1 . join ( os_1 . tmpdir ( ) , tempFileName ) ;
104113 // Download to temporary file
105- const fileStream = fs_2 . createWriteStream ( tempFilePath ) ;
114+ const fileStream = fs_1 . createWriteStream ( tempFilePath ) ;
106115 const webStream = stream_1 . Readable . fromWeb ( response . body ) ;
107- await promises_1 . pipeline ( webStream , fileStream ) ;
108- // Get file stats
109- const stats = await fs_1 . promises . stat ( tempFilePath ) ;
110- const metadata = {
111- ...baseMetadata ,
112- size : stats . size ,
113- } ;
114- // Create a readable stream that cleans up the temp file when done
115- const stream = fs_1 . createReadStream ( tempFilePath ) ;
116- // Clean up temp file when stream is closed or ends
117- const cleanup = async ( ) => {
116+ try {
117+ await promises_1 . pipeline ( webStream , fileStream ) ;
118+ const stats = await fs_1 . promises . stat ( tempFilePath ) ;
119+ const metadata = {
120+ ...baseMetadata ,
121+ size : stats . size ,
122+ } ;
123+ const stream = fs_1 . createReadStream ( tempFilePath ) ;
124+ const cleanup = async ( ) => {
125+ try {
126+ await fs_1 . promises . unlink ( tempFilePath ) ;
127+ }
128+ catch ( _a ) {
129+ // Ignore cleanup errors
130+ }
131+ } ;
132+ stream . on ( "close" , cleanup ) ;
133+ stream . on ( "end" , cleanup ) ;
134+ stream . on ( "error" , cleanup ) ;
135+ return {
136+ stream,
137+ metadata,
138+ } ;
139+ }
140+ catch ( err ) {
141+ // Cleanup on error
118142 try {
119143 await fs_1 . promises . unlink ( tempFilePath ) ;
120144 }
121145 catch ( _a ) {
122- // Ignore cleanup errors (file might already be deleted)
146+ // Ignore cleanup errors
123147 }
124- } ;
125- stream . on ( "close" , cleanup ) ;
126- stream . on ( "end" , cleanup ) ;
127- stream . on ( "error" , cleanup ) ;
128- return {
129- stream,
130- metadata,
131- } ;
148+ throw err ;
149+ }
132150}
0 commit comments