npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

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-files

Quick 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

  • NamespaceError
  • FileDeleteError
  • FileUploadUrlError
  • FileOperationError
  • FileDownloadUrlError
  • DeleteLocationError
  • ClearNamespaceError
  • SearchError

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/base64

Compress PDF

await pdf.compress().save(); // Optimizes streams and font subsets

Video 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 File objects 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 .md file 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 .md file 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 async

Excel 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 File

Chainable 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, pptSetNotes
  • pptAddText, pptUpdateText, pptAddImage, pptAddShape, pptSetBox
  • pptAddTable, pptUpdateTableCells, pptAddChart, pptUpdateChartData
  • pptClearSlide, 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 result

The 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.