|
1 | 1 | import { FilePathOrFileObject } from 'types';
|
2 | 2 | import { BaseFilesHandler } from './BaseFilesHandler';
|
3 | 3 | import { FormDataRequest } from 'types/API';
|
| 4 | +import { isNode } from 'runtime'; |
4 | 5 |
|
5 | 6 | export class NodeFilesHandler extends BaseFilesHandler {
|
6 | 7 | private async convertReadableStream(readableStream: ReadableStream): Promise<NodeJS.ReadableStream> {
|
7 |
| - try { |
8 |
| - if (typeof window === 'undefined') { |
9 |
| - const { Readable } = await import('stream'); |
10 |
| - const reader = readableStream.getReader(); |
| 8 | + if (!isNode) { |
| 9 | + throw new Error('Stream conversion is not supported in browser environment'); |
| 10 | + } |
11 | 11 |
|
12 |
| - return new Readable({ |
13 |
| - async read() { |
14 |
| - const { done, value } = await reader.read(); |
15 |
| - if (done) { |
16 |
| - this.push(null); |
17 |
| - } else { |
18 |
| - this.push(value); |
19 |
| - } |
20 |
| - }, |
21 |
| - }); |
22 |
| - } else { |
23 |
| - throw new Error('Stream conversion is not supported in browser environment'); |
24 |
| - } |
25 |
| - } catch (error) { |
26 |
| - console.error('Error in convertReadableStream:', error); |
27 |
| - throw error; |
| 12 | + const { Readable } = await import('stream'); |
| 13 | + const reader = readableStream.getReader(); |
| 14 | + |
| 15 | + return new Readable({ |
| 16 | + async read() { |
| 17 | + const { done, value } = await reader.read(); |
| 18 | + done ? this.push(null) : this.push(value); |
| 19 | + }, |
| 20 | + }); |
| 21 | + } |
| 22 | + |
| 23 | + private async handleStringFile(filePath: string, formData: any): Promise<void> { |
| 24 | + // eslint-disable-line @typescript-eslint/no-explicit-any |
| 25 | + if (!isNode) { |
| 26 | + throw new Error('File system operations are not supported in browser environment'); |
| 27 | + } |
| 28 | + |
| 29 | + const fs = await import('fs').then((m) => m.default || m); |
| 30 | + if (!fs.existsSync(filePath)) { |
| 31 | + throw new Error(`File not found: ${filePath}`); |
28 | 32 | }
|
| 33 | + |
| 34 | + formData.append('file', fs.createReadStream(filePath), { |
| 35 | + filename: filePath.split('/').pop(), |
| 36 | + }); |
29 | 37 | }
|
30 | 38 |
|
31 | 39 | async prepareFormDataRequest(file: FilePathOrFileObject): Promise<FormDataRequest> {
|
32 |
| - console.log('Preparing form data request for Node.js'); |
33 | 40 | try {
|
34 |
| - const FormData = await import('form-data').then(m => m.default || m); |
35 |
| - console.log('Successfully imported form-data module'); |
36 |
| - |
| 41 | + const FormData = await import('form-data').then((m) => m.default || m); |
37 | 42 | const formData = new FormData();
|
38 |
| - console.log('Created new FormData instance'); |
39 | 43 |
|
40 | 44 | if (typeof file === 'string') {
|
41 |
| - if (typeof window === 'undefined') { |
42 |
| - const fs = await import('fs').then(m => m.default || m); |
43 |
| - if (!fs.existsSync(file)) { |
44 |
| - throw new Error(`File not found: ${file}`); |
45 |
| - } |
46 |
| - console.log(`Appending file from path: ${file}`); |
47 |
| - formData.append('file', fs.createReadStream(file), { filename: file.split('/').pop() }); |
48 |
| - } else { |
49 |
| - throw new Error('File system operations are not supported in browser environment'); |
50 |
| - } |
51 |
| - } else if (file && typeof file === 'object') { |
52 |
| - console.log('Processing file object:', file); |
53 |
| - if ('buffer' in file) { |
54 |
| - console.log('Appending file from buffer'); |
55 |
| - formData.append('file', file.buffer, { filename: file.name, contentType: file.type }); |
56 |
| - } else if ('stream' in file && typeof file.stream === 'function') { |
57 |
| - console.log('Converting and appending file from stream'); |
58 |
| - const nodeStream = await this.convertReadableStream(file.stream()); |
59 |
| - formData.append('file', nodeStream, { filename: file.name, contentType: file.type }); |
60 |
| - } else { |
61 |
| - throw new Error(`Invalid file object structure: ${JSON.stringify(file)}`); |
62 |
| - } |
63 |
| - } else { |
| 45 | + await this.handleStringFile(file, formData); |
| 46 | + return this.createFormDataResponse(formData); |
| 47 | + } |
| 48 | + |
| 49 | + if (!file || typeof file !== 'object') { |
64 | 50 | throw new Error(`Unsupported file type for Node.js file upload flow: ${file}`);
|
65 | 51 | }
|
66 | 52 |
|
67 |
| - const formDataHeaders = { 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}` }; |
68 |
| - console.log('FormData preparation completed successfully'); |
| 53 | + if ('buffer' in file) { |
| 54 | + formData.append('file', file.buffer, { |
| 55 | + filename: file.name, |
| 56 | + contentType: file.type, |
| 57 | + }); |
| 58 | + return this.createFormDataResponse(formData); |
| 59 | + } |
| 60 | + |
| 61 | + if ('stream' in file && typeof file.stream === 'function') { |
| 62 | + const nodeStream = await this.convertReadableStream(file.stream()); |
| 63 | + formData.append('file', nodeStream, { |
| 64 | + filename: file.name, |
| 65 | + contentType: file.type, |
| 66 | + }); |
| 67 | + return this.createFormDataResponse(formData); |
| 68 | + } |
69 | 69 |
|
70 |
| - return { formData, headers: formDataHeaders }; |
| 70 | + throw new Error(`Unsupported file type for Node.js file upload flow: ${file}`); |
71 | 71 | } catch (error) {
|
72 | 72 | console.error('Error in prepareFormDataRequest:', error);
|
73 |
| - console.error('Error details:', error instanceof Error ? error.message : String(error)); |
74 | 73 | throw error;
|
75 | 74 | }
|
76 | 75 | }
|
| 76 | + |
| 77 | + private createFormDataResponse(formData: any): FormDataRequest { |
| 78 | + // eslint-disable-line @typescript-eslint/no-explicit-any |
| 79 | + return { |
| 80 | + formData, |
| 81 | + headers: { |
| 82 | + 'Content-Type': `multipart/form-data; boundary=${formData.getBoundary()}`, |
| 83 | + }, |
| 84 | + }; |
| 85 | + } |
77 | 86 | }
|
0 commit comments