Features · Install · Usage · Platform
A file abstraction that trusts the bytes, not the extension. Built for backends that take uploads from the open internet: magic-byte MIME detection, size and content validation, and presigned S3 uploads — all stream-first, so a 2 GB upload never buffers into your Lambda memory.
Magic-byte MIME detection catches spoofed uploads. A .php renamed to avatar.png fails validation because the bytes disagree with the claim.
- Magic-byte detection across 100+ file types
FileContentMismatchErrorwhen client-claimed MIME disagrees with the bytesFileSizeError/FileMimeErrorfor oversize or disallowed uploads- One
validate()call, typed error types, map cleanly to HTTP 400
- Stream any file (local, URL, Blob) straight into S3
- Pull S3 objects back through the same validation pipeline
- Presigned upload URLs with
maxSizebaked into the signature, so oversized uploads are rejected by S3 before they hit you
Local filesystem, URL download, S3 object, multipart FormData, or a browser File/Blob — all resolve to the same File instance with the same validation and metadata surface.
Bytes load lazily so a 2 GB upload doesn't buffer into memory. Automatic handling across Node.js and Web streams — you never have to pick the right pipe.
File name, real (detected) MIME type, size, created/modified timestamps, hash/checksum, source type — all on one object.
pnpm add @smooai/file@smooai/file ships as native implementations in TypeScript, Python, Rust, Go, and .NET (C#) — each built with idiomatic patterns for its ecosystem.
| Language | Package | Install |
|---|---|---|
| TypeScript | @smooai/file |
pnpm add @smooai/file |
| Python | smooai-file |
pip install smooai-file |
| Rust | smooai-file |
cargo add smooai-file |
| Go | github.com/SmooAI/file/go/file |
go get github.com/SmooAI/file/go/file |
| .NET (core) | SmooAI.File |
dotnet add package SmooAI.File |
| .NET (S3) | SmooAI.File.S3 |
dotnet add package SmooAI.File.S3 |
Language-specific source lives in the python/, rust/, go/, and dotnet/ directories.
The .NET port uses Mime-Detective for magic-byte MIME sniffing and splits S3 helpers into a sub-package, so consumers who don't need AWS avoid pulling in the AWS SDK.
Jump to a pattern:
- Basic usage
- Streaming operations
- S3 integration
- File type detection
- FormData support
- Web File / Blob (Hono, Next.js, Browser)
- Validation (size, mime, content-vs-claim)
- Base64 encoding
- Presigned upload URL
import File from '@smooai/file';
// Create a file from a local path
const file = await File.createFromFile('path/to/file.txt');
// Read file contents (streams automatically)
const content = await file.readFileString();
console.log(content);
// Get file metadata
console.log(file.metadata);
// {
// name: 'file.txt',
// mimeType: 'text/plain',
// size: 1234,
// extension: 'txt',
// path: 'path/to/file.txt',
// lastModified: Date,
// createdAt: Date
// }import File from '@smooai/file';
// Create a file from a URL (streams automatically)
const file = await File.createFromUrl('https://example.com/large-file.zip');
// Pipe to a destination (streams without loading entire file)
await file.pipeTo(someWritableStream);
// Read as bytes (streams in chunks)
const bytes = await file.readFileBytes();
// Save to filesystem (streams directly)
const { original, newFile } = await file.saveToFile('downloads/file.zip');import File from '@smooai/file';
// Create from S3 (streams automatically)
const file = await File.createFromS3('my-bucket', 'path/to/file.jpg');
// Upload to S3 (streams directly)
await file.uploadToS3('my-bucket', 'remote/file.jpg');
// Save to S3 (creates new file instance)
const { original, newFile } = await file.saveToS3('my-bucket', 'remote/file.jpg');
// Move to S3 (deletes local file if source was local)
const s3File = await file.moveToS3('my-bucket', 'remote/file.jpg');
// Generate signed URL
const signedUrl = await s3File.getSignedUrl(3600); // URL expires in 1 hourimport File from '@smooai/file';
const file = await File.createFromFile('document.xml');
// Get file type information (detected via magic numbers)
console.log(file.mimeType); // 'application/xml'
console.log(file.extension); // 'xml'
// File type is automatically detected from:
// - Magic numbers (via file-type)
// - MIME type headers
// - File extension
// - Custom detectorsimport File from '@smooai/file';
const file = await File.createFromFile('document.pdf');
// Convert to FormData for uploads
const formData = await file.toFormData('document');
// Use with fetch or other HTTP clients
await fetch('https://api.example.com/upload', {
method: 'POST',
body: formData,
});import File from '@smooai/file';
// Hono multipart route
app.post('/upload', async (c) => {
const form = await c.req.formData();
const webFile = form.get('file') as globalThis.File;
// Preserves the web File's name and type hints.
const file = await File.createFromWebFile(webFile);
// …validate, upload, etc.
});import File, { FileValidationError } from '@smooai/file';
const file = await File.createFromWebFile(webFile);
try {
await file.validate({
maxSize: 5 * 1024 * 1024, // 5MB
allowedMimes: ['image/png', 'image/jpeg', 'image/webp'],
expectedMimeType: webFile.type, // compares magic-byte detection vs claimed Content-Type
});
} catch (err) {
if (err instanceof FileValidationError) {
// FileSizeError | FileMimeError | FileContentMismatchError — map to HTTP 400
throw new HTTPException(400, { message: err.message });
}
throw err;
}expectedMimeType is the primary defense against mime-spoofing: a .php file uploaded with Content-Type: image/png will fail because magic-byte detection doesn't match the claim.
import File from '@smooai/file';
const file = await File.createFromUrl('https://s3.example.com/invoice.pdf');
await sendEmail({
attachments: [
{
filename: 'invoice.pdf',
content: await file.toBase64(),
encoding: 'base64',
},
],
});import File from '@smooai/file';
// Server issues a time-limited signed URL the client uploads bytes to directly.
// `maxSize` is baked into the signature so oversized uploads are rejected by S3.
const url = await File.createPresignedUploadUrl({
bucket: Resource.Bucket.name,
key: `avatars/${userId}.png`,
contentType: 'image/png',
expiresIn: 600,
maxSize: 2 * 1024 * 1024,
});- TypeScript
- Node.js File System API
- AWS SDK v3
- file-type for magic number-based MIME type detection
- @smooai/fetch for URL downloads
- @smooai/logger for structured logging
@smooai/file is built and open-sourced by Smoo AI — the AI-powered business platform with AI built into every product: CRM, customer support, campaigns, field service, observability, and developer tools.
- 🧰 More open source from Smoo AI — smoo.ai/open-source
- 🧩 Sibling packages — @smooai/fetch, @smooai/logger, @smooai/config, smooth
Contributions are welcome. This project uses changesets to manage versions and releases.
-
Fork the repository
-
Create your branch (
git checkout -b amazing-feature) -
Make your changes
-
Add a changeset to document them:
pnpm changeset
You'll be prompted to choose a version bump (patch, minor, or major) and describe the change.
-
Commit your changes (
git commit -m 'Add some amazing feature') -
Push to the branch (
git push origin feature/amazing-feature) -
Open a pull request — reference any related issues in the description
The maintainers will review your PR and may request changes before merging.
MIT — see LICENSE.
Brent Rager
Smoo GitHub: https://github.com/SmooAI
Built by Smoo AI — AI built into every product.
