mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-23 19:46:42 +02:00
feat(storage): cleanup buckets, add file-size validation and bulk delete
- Remove archived LIGHTWRITE and NUTRIPHI from BUCKETS - Add missing PLANTA and PROJECTDOC buckets (were in Docker init but not in code) - Add maxSizeBytes option to upload() and uploadMultipart() for size enforcement - Add deleteMany() with automatic batching (1000 keys per S3 request) - Add factories for createPlantaStorage() and createProjectDocStorage() - Update tests (62 passing) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
720602343e
commit
01c4d3a9d1
6 changed files with 106 additions and 8 deletions
|
|
@ -3,6 +3,7 @@ import {
|
|||
PutObjectCommand,
|
||||
GetObjectCommand,
|
||||
DeleteObjectCommand,
|
||||
DeleteObjectsCommand,
|
||||
ListObjectsV2Command,
|
||||
HeadObjectCommand,
|
||||
type PutObjectCommandInput,
|
||||
|
|
@ -62,6 +63,15 @@ export class StorageClient {
|
|||
body: Buffer | Uint8Array | string | ReadableStream,
|
||||
options: UploadOptions = {}
|
||||
): Promise<UploadResult> {
|
||||
if (options.maxSizeBytes && typeof body !== 'string' && !(body instanceof ReadableStream)) {
|
||||
const size = body.byteLength;
|
||||
if (size > options.maxSizeBytes) {
|
||||
throw new Error(
|
||||
`File size ${size} bytes exceeds maximum allowed ${options.maxSizeBytes} bytes`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const input: PutObjectCommandInput = {
|
||||
Bucket: this.bucket.name,
|
||||
Key: key,
|
||||
|
|
@ -95,6 +105,15 @@ export class StorageClient {
|
|||
body: Buffer | Uint8Array | ReadableStream,
|
||||
options: UploadOptions = {}
|
||||
): Promise<UploadResult> {
|
||||
if (options.maxSizeBytes && !(body instanceof ReadableStream)) {
|
||||
const size = body.byteLength;
|
||||
if (size > options.maxSizeBytes) {
|
||||
throw new Error(
|
||||
`File size ${size} bytes exceeds maximum allowed ${options.maxSizeBytes} bytes`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const upload = new Upload({
|
||||
client: this.client,
|
||||
params: {
|
||||
|
|
@ -173,6 +192,27 @@ export class StorageClient {
|
|||
await this.client.send(command);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete multiple files from the bucket in a single request.
|
||||
* S3 supports up to 1000 keys per request; this method batches automatically.
|
||||
*/
|
||||
async deleteMany(keys: string[]): Promise<void> {
|
||||
if (keys.length === 0) return;
|
||||
|
||||
const BATCH_SIZE = 1000;
|
||||
for (let i = 0; i < keys.length; i += BATCH_SIZE) {
|
||||
const batch = keys.slice(i, i + BATCH_SIZE);
|
||||
const command = new DeleteObjectsCommand({
|
||||
Bucket: this.bucket.name,
|
||||
Delete: {
|
||||
Objects: batch.map((key) => ({ Key: key })),
|
||||
Quiet: true,
|
||||
},
|
||||
});
|
||||
await this.client.send(command);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a file exists
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue