| 83 | const jsonData = JSON.stringify(data, null, 2); |
| 84 | await uploadToS3(key, new TextEncoder().encode(jsonData), { |
| 85 | contentType: 'application/json' |
| 86 | }); |
| 87 | } |
| 88 | |
| 89 | function createFileUploadStream( |
| 90 | sourcePath: string, |
| 91 | onProgress: (bytes: number) => void |
| 92 | ): ReadableStream<Uint8Array> { |
| 93 | let uploaded = 0; |
| 94 | // SAFETY: Node's Readable.toWeb returns a byte stream for this file stream. |
| 95 | const source = Readable.toWeb( |
| 96 | createReadStream(sourcePath, { highWaterMark: TRANSFER_CHUNK_SIZE }) |
| 97 | ) as ReadableStream<Uint8Array>; |
| 98 | |
| 99 | return source.pipeThrough( |
| 100 | new TransformStream<Uint8Array, Uint8Array>({ |
| 101 | transform(chunk, controller) { |
| 102 | uploaded += chunk.byteLength; |
| 103 | onProgress(uploaded); |
| 104 | controller.enqueue(chunk); |
| 105 | } |
| 106 | }) |
| 107 | ); |
| 108 | } |
| 109 | |
| 110 | // Helper to upload file to S3 with progress tracking |
| 111 | export async function uploadFileToS3(key: string, sourcePath: string): Promise<number> { |
| 112 | const sizeInBytes = (await stat(sourcePath)).size; |