From cdb1a57614068fcfefa145bc6df45c9def7ccc6a Mon Sep 17 00:00:00 2001 From: Elizabeth Hunt Date: Sun, 14 Dec 2025 22:43:24 -0800 Subject: Updates --- src/storage/index.ts | 79 +++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 63 insertions(+), 16 deletions(-) (limited to 'src/storage/index.ts') diff --git a/src/storage/index.ts b/src/storage/index.ts index 2c8ffb2..631fc2e 100644 --- a/src/storage/index.ts +++ b/src/storage/index.ts @@ -1,9 +1,23 @@ import { randomUUID } from 'crypto'; import { mkdir, writeFile, readFile } from 'fs/promises'; -import { join } from 'path'; +import { basename, join } from 'path'; import { isSafeRouteName, type RouteConfig, type StoredRequest } from '../types/index.js'; import { Either, type IEither } from '@emprespresso/pengueno'; +type IncomingUpload = { + fieldName: string; + filename: string; + contentType: string; + size: number; + data: Uint8Array; +}; + +function sanitizeFilename(filename: string): string { + const base = basename(filename); + const safe = base.replace(/[^a-zA-Z0-9._-]/g, '_'); + return safe.length > 0 ? safe.slice(0, 200) : 'upload.bin'; +} + export class Storage { private routes: Map = new Map(); @@ -83,7 +97,7 @@ export class Storage { method: string, headers: Record, body: unknown, - files?: StoredRequest['files'], + uploads?: IncomingUpload[], ): Promise> { if (!isSafeRouteName(routeName)) { return Either.left(new Error('Invalid route name')); @@ -91,21 +105,54 @@ export class Storage { const timestamp = Date.now(); const uuid = randomUUID(); - const filename = `${timestamp}_${uuid}.json`; - - const stored: StoredRequest = { - timestamp, - uuid, - routeName, - method, - headers, - body, - files, - }; - - const filepath = join(this.dataDir, routeName, filename); + const baseName = `${timestamp}_${uuid}`; + const routeDir = join(this.dataDir, routeName); + try { - await writeFile(filepath, JSON.stringify(stored, null, 2)); + await mkdir(routeDir, { recursive: true }); + + const requestDir = join(routeDir, baseName); + await mkdir(requestDir, { recursive: true }); + + const files: StoredRequest['files'] = uploads?.length + ? await (async () => { + const filesDir = join(requestDir, 'files'); + await mkdir(filesDir, { recursive: true }); + + const storedFiles: NonNullable = []; + for (let i = 0; i < uploads.length; i++) { + const upload = uploads[i]; + const safeOriginal = sanitizeFilename(upload.filename); + const savedName = `${i}_${safeOriginal}`; + const diskPath = join(filesDir, savedName); + await writeFile(diskPath, Buffer.from(upload.data)); + + storedFiles.push({ + fieldName: upload.fieldName, + originalFilename: upload.filename, + filename: savedName, + contentType: upload.contentType, + size: upload.size, + path: join('files', savedName), + }); + } + + return storedFiles; + })() + : undefined; + + const stored: StoredRequest = { + timestamp, + uuid, + routeName, + method, + headers, + body, + files, + }; + + await writeFile(join(requestDir, 'request.json'), JSON.stringify(stored, null, 2)); + await writeFile(join(requestDir, 'body.json'), JSON.stringify(body, null, 2)); return Either.right(stored); } catch (err) { return Either.left(err instanceof Error ? err : new Error(String(err))); -- cgit v1.2.3-70-g09d2