@uploadflow/core
v0.1.0
Published
Framework-agnostic file-upload pipeline core: storage adapters (Azure/S3/local), magic-byte validation, presigned uploads
Downloads
184
Maintainers
Readme
@uploadflow/core
Framework-agnostic engine for the uploadflow file-upload pipeline. Zero framework dependencies —
use it directly in Express, Fastify, workers, or plain Node, or via @uploadflow/nestjs /
@uploadflow/express.
npm i @uploadflow/core
# storage driver (optional peer) — install the one you use:
npm i @azure/storage-blob
# or: npm i @aws-sdk/client-s3 @aws-sdk/lib-storage @aws-sdk/s3-request-presigner
# local disk driver needs nothingWhat's inside
StorageService+ adapters:AzureBlobAdapter(real SAS),S3Adapter,LocalAdapter, or your own.FileValidatorService— magic-byte content detection + size + allowlist.PresignService— presigned PUT +confirm()with staging→permanent promotion and orphan handling.processDirectUpload()/runLinkedUpload()— the pipeline used by the framework adapters.InMemoryAttachmentStore+ theAttachmentStore/StorageAdapterinterfaces.
Direct use (any framework)
import { StorageService, FileValidatorService, processDirectUpload } from '@uploadflow/core';
const storage = new StorageService({
storage: { driver: 's3', s3: { region, bucket, accessKeyId, secretAccessKey } },
urlMode: 'signed',
});
const validator = new FileValidatorService({ allow: ['image/*'], maxFileSize: '5mb' });
// `file` is { buffer, originalName, mimeType, size }
const stored = await processDirectUpload(file, storage, validator);
// stored = { key, url, size, mime, originalName }Presigned flow
import { PresignService } from '@uploadflow/core';
const presign = new PresignService(storage, validator);
const { uploadUrl, key } = await presign.getUploadUrl({ filename: 'a.png', contentType: 'image/png' });
// client PUTs the bytes to uploadUrl (staging/), then:
const stored = await presign.confirm(key); // validates content, promotes staging → permanentConfiguration reference
interface UploadOptions {
storage: {
driver: 'azure' | 's3' | 'local' | StorageAdapter;
azure?: { account; accountKey; container; endpoint? };
s3?: { region; bucket; accessKeyId; secretAccessKey; endpoint?; forcePathStyle?; publicBaseUrl? };
local?: { basePath; publicBaseUrl?; signingSecret? };
};
validation?: {
maxFileSize?: number | string; // '5mb' | bytes
allow?: string[]; // ['image/*','video/mp4']; omit = any
magicBytes?: boolean; // default true
signaturelessTypes?: string[]; // text types accepted without a signature
};
presign?: { expiresIn?: number }; // seconds, default 3600
urlMode?: 'signed' | 'public'; // default 'signed'
stagingPrefix?: string; // default 'staging/'
stagingTtlHours?: number; // default 24 (lifecycle TTL you configure on the bucket)
keyStrategy?: (i) => string; // default `${uuid}.${ext}`
}Custom storage adapter
Implement StorageAdapter (upload, download, delete, exists, getSignedUploadUrl,
getSignedDownloadUrl, copy, publicUrl, readRange) and pass the instance as storage.driver.
Errors
UploadflowError carries code + statusCode: INVALID_FILE_TYPE/CONTENT_UNVERIFIED (400),
FILE_TOO_LARGE (413), NOT_FOUND (404), ADAPTER_MISSING/CONFIG (500).
Full docs: https://github.com/OWNER/uploadflow#readme
MIT
