trelae-files
v0.1.8
Published
JavaScript SDK for Trelae
Readme
Trelae Files SDK
A powerful TypeScript/JavaScript SDK for managing file storage, upload, manipulation, and access control via the Trelae Files.
Documentation
To learn more about how the Trelae Files works — including concepts like projects, namespaces, file uploads, folder structures, and advanced use cases — refer to the official documentation: Get started with Trelae Files
This guide provides a detailed walkthrough of core ideas and integration examples to help you make the most of the Trelae SDK.
Installation
npm install trelae-files
# or
yarn add trelae-files
# or
pnpm add trelae-filesQuick Start
import { Trelae } from 'trelae-files';
const trelae = new Trelae({
apiKey: 'your_api_key_here'
});
const namespace = trelae.namespace('namespace-id');
const file = trelae.file('file-id');
await file.delete();Configuration
const trelae = new Trelae({
apiKey: 'your_api_key_here', // Required
devMode: true // Optional
});Core Concepts
Namespace
A namespace is a logical container for organizing files. Every file belongs to a namespace.
- Label: Defined by you (e.g.,
"uploads","reports"). - Region: Controls where data is stored.
- Access: Can be public or private (default).
- Public namespaces get a public URL for direct file access.
File
The fundamental object in the SDK.
Supports:
- Upload, download, delete
- Move, copy
- Image manipulation (for
image/*files)
Files can be grouped using the location property (e.g., "assets/images"), simulating folders.
Folder
A virtual structure that helps organize files.
- No actual data — it's just a path-based grouping
- Created automatically when uploading files to a path (e.g.,
"images/logo.png") - Deleting a folder deletes all files and subfolders recursively
API Key
A secure token used to authenticate Trelae API requests. Scoped to your project.
Namespace Usage
Create Namespace
const namespace = trelae.createNamespace({ name: 'my-namespace' });Get Namespace
const namespace = trelae.namespace('namespace-id');Delete Namespace
await namespace.delete();Clear Namespace
await namespace.clear();Get Metadata
const metadata = await namespace.getMetaData();Upload Files
Simple Upload URL
const { id, uploadUrl } = await namespace.getUploadUrl({
name: 'image.png',
location: 'uploads/images',
fileType: 'image/png',
expiry: '2025-08-01T00:00:00.000Z' // Optional
});Multipart Upload (Large Files)
// Step 1: Start upload
const { id, uploadId, partCount, urls } = await namespace.startMultipartUpload({
name: 'big.zip',
location: 'backups',
size: 200_000_000 // bytes
});
// Step 2: Complete upload
await namespace.completeMultipartUpload({
fileId: id,
uploadId,
parts: [
{ partNumber: 1, etag: 'etag-1' },
{ partNumber: 2, etag: 'etag-2' },
]
});
// Optional: Abort upload
await namespace.abortMultipartUpload({ fileId: id, uploadId });Folder Usage
Create Folder
const folder = await namespace.createFolder('assets', 'uploads');Get Folder by ID or Path
const folderById = namespace.folder('folder-id');
const folderByPath = namespace.folder('uploads', 'assets');File Usage
Get File
const file = namespace.file('file-id');
const fileByPath = namespace.file('uploads/images', 'logo.png');Delete File
await file.delete();Move File
await file.move({
newLocation: 'reports',
newName: 'monthly.pdf'
});Copy File
const copy = await file.copy({
newLocation: 'backups',
newName: 'monthly-copy.pdf'
});Get Download URL
const url = await file.getDownloadUrl();Image Manipulation
Available only for files with MIME type image/*.
await file
.resize({ width: 300 })
.rotate({ angle: 90 })
.grayscale({})
.save();Supported Operations
resize({ width, height })crop({ width, height })rotate({ angle })flip({ horizontal, vertical })convert({ format })grayscale({})compress({ quality })border({ top, color })- ...and more
Bulk File Management
Delete Multiple Files
const files = trelae.files(['file-id-1', 'file-id-2']);
await files.delete();Search & Listing
List Files and Folders
const { files, folders } = await namespace.getFiles({
location: 'assets',
limit: 20,
page: 1
});Search Files by Query
const { files, folders } = await namespace.getFiles({
query: 'assets',
});Global Search
const result = await trelae.search({
query: 'assets',
});Delete Location
await namespace.deleteLocation('old-assets');Error Handling
All SDK methods throw structured errors using Utility.
Common Error Types
NamespaceErrorFileDeleteErrorFileUploadUrlErrorFileOperationErrorFileDownloadUrlErrorDeleteLocationErrorClearNamespaceErrorSearchError
Utility
API Error handling
import { handleAPIError } from 'trelae-files';
handleAPIError(data, {
error: 'internal-error',
message: 'Something went wrong'
});Handles:
- Flat API errors
{ error, message } - Zod validation errors
{ error: { issues: [...] } }
Types
TrelaeConfig
interface TrelaeConfig {
apiKey: string;
devMode?: boolean;
}FileMetaData
interface FileMetaData {
fileType: string;
size: number;
status: string;
createdAt: string;
}FileManipulationResult
interface FileManipulationResult {
success: boolean;
message: string;
}ImageOperation (Examples)
{ operation: "resize", params: { width: 300 } }
{ operation: "grayscale", params: {} }
{ operation: "convert", params: { format: "png" } }PDF Tools
Powerful PDF utilities are available on File instances whose fileType is application/pdf.
Convert PDF → Images
const pdf = trelae.file('pdf-file-id');
const { pagesExtracted, files } = await pdf.pdfToImages({
// Convert pages 1 to 3 (inclusive) to PNGs
pageSelection: [{ start: 1, end: 3 }],
format: 'png'
});
// Each entry in `files` is a Trelae `File` you can download, move, etc.PDF → Markdown (OCR)
// Save Markdown + extracted images back to Trelae (default)
const saved = await pdf.pdfToMarkdown({ saveMarkdown: true, location: 'ocr/results' });
// saved.file -> Markdown File
// saved.images -> Array<File> (images detected in the PDF)
// saved.markdown -> string
// Or get raw OCR content without saving
const raw = await pdf.pdfToMarkdown({ saveMarkdown: false });
// raw.markdown -> string
// raw.images -> Inline image metadata/base64Compress PDF
await pdf.compress().save(); // Optimizes streams and font subsetsVideo Tools
Video manipulation is queued via chainable methods and executed on save().
By default, video jobs run asynchronously; poll with getVideoStatus() or pass save({ mode: 'sync' }).
Common Workflow
const video = trelae.file('video-id');
const result = await video
.changeVideoFormat({ format: 'mp4', videoCodec: 'libx264', audioCodec: 'aac', crf: 23, preset: 'medium' })
.trimVideo({ start: 0, duration: 30 })
.scaleVideo({ width: 1280 }) // keepAspect auto-enforced
.addTextVideo({ text: 'Demo', x: 60, y: 60, fontSize: 32 })
.save({ mode: 'async' }); // default is 'async'
// Poll if queued
if (result.type === 'video' && (result.status === 'queued' || result.status === 'running')) {
const status = await video.getVideoStatus(result.operationId);
}Supported Video Operations
changeVideoFormat({ format, videoCodec?, audioCodec?, crf?, preset? })trimVideo({ start?, duration?, end? })scaleVideo({ width?, height?, keepAspect? })rotateFlipVideo({ rotate?, hflip?, vflip? })removeAudio()speedVideo({ videoSpeed?, audioSpeed? })cropVideo({ x, y, width, height })muteSegment({ start, duration })fadeVideo({ type: 'in' | 'out', startTime, duration })addTextVideo({ text, x, y, fontSize?, fontColor?, fontFile?, startTime?, endTime? })addBorderVideo({ color?, top?, bottom?, left?, right? })reverseVideo({ video?, audio? })audioFadeVideo({ type: 'in' | 'out', startTime, duration })motionBlurVideo({ frames?, weights?, outputFps? })grayscaleVideo()colorEQVideo({ brightness?, contrast?, saturation?, gamma? })hueRotateVideo({ degrees, saturation? })boxBlurVideo({ lumaRadius?, lumaPower?, startTime?, endTime? })sharpenVideo({ amount?, size? })volumeVideo({ gain })
Extract Audio From Video
const queued = await video.audioExtractAsync({
namespaceId: 'ns-123',
location: 'audio',
filename: 'clip.mp3',
format: 'mp3',
bitrateKbps: 192,
});
const status = await video.getAudioExtractStatus(queued.operationId);
// Or block until done:
const done = await video.audioExtractSync({
namespaceId: 'ns-123',
location: 'audio',
filename: 'clip.opus',
format: 'opus',
poll: { intervalMs: 1500, timeoutMs: 5 * 60 * 1000 }
});Audio Tools
Audio manipulation is available on any File whose MIME type is audio/*.
Operations are chainable and executed once you call .save().
Workflow
const audio = trelae.file('audio-id');
const result = await audio
.changeAudioFormat({ format: 'mp3', audioCodec: 'libmp3lame', bitrateKbps: 192 })
.trimAudio({ start: 10.5, end: 43.7 })
.speedAudio({ atempo: 1.25 })
.volumeAudio({ gainDb: -3 })
.fadeAudio({ type: 'in', startTime: 0, duration: 5 })
.equalizerAudio({ freqHz: 1000, gainDb: 4 })
.lowpassAudio({ cutoffHz: 1200 })
.highpassAudio({ cutoffHz: 200 })
.normalizeAudio({ targetI: -16, targetTP: -1 })
.muteAudioSegment({ start: 30, duration: 5 })
.removeSilenceAudio({ startThresholdDb: -40, stopThresholdDb: -35 })
.setAudioChannels({ channels: 2, layout: 'stereo' })
.setAudioSampleRate({ sampleRateHz: 44100 })
.save({ mode: 'sync' });Supported Audio Operations
changeAudioFormat({ format, audioCodec?, bitrateKbps?, sampleRateHz?, channels? })trimAudio({ start?, duration?, end? })speedAudio({ atempo })volumeAudio({ gain?, gainDb? })fadeAudio({ type: 'in'|'out', startTime, duration })equalizerAudio({ freqHz, widthQ?, gainDb })lowpassAudio({ cutoffHz, order? })highpassAudio({ cutoffHz, order? })normalizeAudio({ targetI?, targetTP?, targetLRA?, dualMono? })muteAudioSegment({ start, duration })removeSilenceAudio({ startThresholdDb?, startDuration?, stopThresholdDb?, stopDuration? })setAudioChannels({ channels, layout? })setAudioSampleRate({ sampleRateHz })
New Advanced FX
compressorAudio({ threshold, ratio?, attack?, release?, knee?, makeupGain? }) Dynamic range compression.echoAudio({ inGain?, outGain?, delays[], decays[] }) Multi-delay echo (delays > 0, decays between 0–1).panAudio({ layout?, mapping }) Channel panning / remapping.denoiseAudio({ reductionDb?, noiseType? }) Simple denoiser.bassBoostAudio({ gainDb?, frequency?, widthQ? }) Low-frequency enhancement.trebleBoostAudio({ gainDb?, frequency?, widthQ? }) High-frequency enhancement.
example usage
await trelae
.file('audio-id')
.trimAudio({ start: 5, duration: 20 })
.echoAudio({ delays: [200, 400], decays: [0.6, 0.3] })
.compressorAudio({ threshold: -18, ratio: 3 })
.bassBoostAudio({ gainDb: 6, frequency: 120 })
.save({ mode: 'sync' });Extract Frames → ZIP
const framesJob = await video.extractFramesAsync({
namespaceId: 'ns-123',
location: 'frames',
filename: 'frames.zip',
start: 2,
endTime: 7
});
const framesStatus = await video.getExtractFramesStatus(framesJob.operationId);
// Synchronous helper:
await video.extractFramesSync({
namespaceId: 'ns-123',
location: 'frames',
filename: 'frames.zip'
});ZIP & UNZIP
Create archives or expand them in-place. Both operations have Async and Sync helpers.
ZIP
// Enqueue a new ZIP from multiple files
const { operationId, file: zipPlaceholder } = await trelae.zipAsync({
fileIds: ['file-1', 'file-2', 'file-3'],
namespaceId: 'ns-123',
zipName: 'archive.zip',
location: 'exports'
});
// Poll job status
const zipStatus = await trelae.getZipStatus(operationId);
// Or block until completion
const zipped = await trelae.zipSync({
fileIds: ['file-1', 'file-2'],
namespaceId: 'ns-123',
zipName: 'bundle.zip',
location: 'exports'
});UNZIP
// Enqueue extraction of an existing ZIP file
const unzipJob = await trelae.unzipAsync({
fileId: 'zip-file-id',
namespaceId: 'ns-123',
location: 'extracted'
});
const unzipStatus = await trelae.getUnzipStatus(unzipJob.operationId);
// Or block until finished
const unzipped = await trelae.unzipSync({
fileId: 'zip-file-id',
namespaceId: 'ns-123',
location: 'extracted'
});Content Awareness
Trelae Files includes content-aware workflows that combine storage with media intelligence:
- AI Background Removal for images via
file.removeBackground(). - OCR to Markdown from PDFs via
file.pdfToMarkdown({ saveMarkdown }). - Inline image detection during OCR, returning saved
Fileobjects or base64 images. - Video understanding helpers like frame extraction to ZIP and audio extraction, ideal for downstream ML or editing pipelines.
These features compose seamlessly with existing manipulation chains and signed URL access.
Image OCR & Description
In addition to image manipulation, Trelae now supports text extraction and AI-powered descriptions for image files (image/*).
Image → Markdown (OCR)
Extract visible text from an image into Markdown:
const img = trelae.file("file-id");
// Raw Markdown text (default)
const raw = await img.imageToMarkdown();
console.log(raw.markdown);
// Save extracted Markdown back to Trelae
const saved = await img.imageToMarkdown({ saveMarkdown: true, location: "ocr-results" });
console.log(saved.file, saved.markdown);saveMarkdown: false→ returns raw Markdown.saveMarkdown: true→ saves.mdfile to Trelae.- Use cases: scanned docs, receipts, screenshots, handwritten notes.
Describe Image (AI)
Generate a detailed Markdown description of an image using AI (scene, objects, colors, logos, text, etc.):
const img = trelae.file("file-id");
// Raw description
const desc = await img.describeImage();
console.log(desc.markdown);
// Save description into Trelae
const savedDesc = await img.describeImage({ saveMarkdown: true, location: "descriptions" });
console.log(savedDesc.file, savedDesc.markdown);saveMarkdown: false→ returns raw Markdown description.saveMarkdown: true→ saves.mdfile to Trelae.- Use cases: auto-generating alt text, scene metadata, accessibility.
Markdown Tools
Markdown → HTML / PDF
Convert a .md file to HTML or PDF, with optional custom CSS.
const md = trelae.file("markdown-file-id");
const html = await md.markdownConvert({
format: "html",
location: "exports",
name: "readme-render",
css: "body{font-family:Inter,system-ui}",
useDefaultStyles: true
});
const pdf = await md.markdownConvert({
format: "pdf",
location: "exports",
name: "readme"
});CSV Tools
CSV → XLSX / PDF / TSV / JSON
const csv = trelae.file("csv-file-id");
const toXlsx = await csv.csvConvert({
format: "xlsx",
location: "exports",
name: "september-report"
});
const toPdf = await csv.csvConvert({ format: "pdf" });
const toTsv = await csv.csvConvert({ format: "tsv" });
const toJson = await csv.csvConvert({ format: "json" });Works for files uploaded as text/csv, application/csv, or some text/plain CSVs.
Excel Tools
Excel → CSV / TSV / JSON / PDF
const xlsx = trelae.file("excel-file-id");
const toCsv = await xlsx.excelConvert({
format: "csv",
sheet: "Expenses 2025", // or 0 (index)
location: "exports",
name: "expenses-sept"
});
const toPdf = await xlsx.excelConvert({ format: "pdf" });
const toTsv = await xlsx.excelConvert({ format: "tsv" });
const toJson = await xlsx.excelConvert({ format: "json" });Batch Excel Manipulations (Queue → Save)
const book = trelae.file("excel-file-id");
const queued = await book
.addSheet({ name: "Data" })
.insertRows({
sheet: "Data",
startRow: 1,
count: 3,
values: [
["Date", "Item", "Qty", "Price"],
["2025-09-01", "Widget", 3, 9.99],
["2025-09-02", "Gadget", 2, 14.5]
]
})
.setColumnWidth({ sheet: "Data", col: 2, width: 22 })
.dataValidation({
sheet: "Data",
range: "A2:A100",
type: "list",
formulae: ['"Yes,No,Maybe"']
})
.save({ mode: "async" }); // excel jobs default to asyncExcel Job Status
if (queued.type === "excel" && (queued.status === "queued" || queued.status === "running")) {
const status = await book.getExcelStatus(queued.operationId);
// status.status → 'queued' | 'running' | 'completed' | 'failed'
}PowerPoint Tools
PPT / PPTX / PPS / PPSX → PDF
const ppt = trelae.file("ppt-file-id");
const res = await ppt.pptToPdf({
location: "exports",
name: "slides-sept"
});
// res.file → the created PDF FileChainable PPT Editing (Queue → Save)
const deck = trelae.file("ppt-file-id");
const r = await deck
.pptSetProps({ title: "Quarterly Review", author: "Ops Team" })
.pptSetLayout({ preset: "LAYOUT_16x9" })
.pptAddSlide({ layoutName: "TITLE", notes: "Intro slide" })
.pptAddText({
slide: 1,
text: [{ text: "Q3 Results", options: { bold: true, fontSize: 38 } }],
box: { w: 10, h: 1.6, center: true },
options: { margin: 8 }
})
.pptAddImage({
slide: 1,
image: { fileId: "logo-file-id" },
box: { w: 1.8, h: 1.8, x: 0.5, y: 0.5 }
})
.save({ mode: "async" });Supported PPT operations (high-level):
pptSetProps,pptSetLayout,pptAddSlide,pptSetSlideBackground,pptSetNotespptAddText,pptUpdateText,pptAddImage,pptAddShape,pptSetBoxpptAddTable,pptUpdateTableCells,pptAddChart,pptUpdateChartDatapptClearSlide,pptMoveSlide,pptReorderSlides
PPT Job Status
if (r.type === "ppt" && (r.status === "queued" || r.status === "processing")) {
const s = await deck.getPptStatus(r.operationId);
}AI Image Edit
Generate an edited image by describing the change; optionally provide reference image IDs.
const edited = await trelae.file("PRIMARY_IMAGE_ID").imageEdit({
prompt: "Make the sky sunset orange with soft clouds",
outputFormat: "jpeg", // png | jpeg | webp (default: png)
location: "edits/sky",
extraImageIds: ["REF_IMAGE_ID_1", "REF_IMAGE_ID_2"]
});
// edited.file → new File with the edit resultThe primary file must be an image/*. References can guide style/content.
Job Status Helpers (Quick Reference)
Use these to poll long-running tasks:
// Video manipulations:
await file.getVideoStatus(operationId);
// Audio manipulations:
await file.getAudioStatus(operationId);
// Excel manipulations:
await file.getExcelStatus(operationId);
// PPT manipulations:
await file.getPptStatus(operationId);
// Audio extract:
await file.getAudioExtractStatus(operationId);
// Frame extract:
await file.getExtractFramesStatus(operationId);Most media manipulations default to async; pass .save({ mode: "sync" }) where supported if you need to block until completion.
Additional Types Referenced
The SDK exposes additional types used by the new APIs (importable from trelae-files):
PdfToImageOptions/PdfToImageResultFiles— options & result for PDF→Image.PdfToMarkdownOptions/PdfToMarkdownResultFile— options & result for PDF→Markdown (OCR).InlineImageMeta— inline base64 image metadata returned when not saving OCR results.VideoOperation— internal representation for video transformations.VideoStatusResponse— status shape for queued video operations.
Tip: you typically won’t need these types directly unless you’re writing wrappers; the method signatures are strongly typed.
License
MIT License — see LICENSE file.
