Getting started
TypeScript
No runtime dependencies — the global fetch on Node 18 and up, and any runtime that provides one.
The key is scoped to a project and can upload, sign and delete. Keep it on your server. Browsers upload through your own endpoints — see Browser uploads.
Install#
npm install @filehutch/sdkimport { FileHutch } from "@filehutch/sdk"
const hutch = new FileHutch({ apiKey: process.env.FILE_HUTCH_API_KEY })Upload#
// One call: request, PUT to storage, complete.
const file = await hutch.upload(bytes, { policy: "avatars", filename: "me.png" })
file.id // "file_abc123" — the only thing you store
file.transforms.avatar // already on the payload for public imagesTakes a Uint8Array, ArrayBuffer, Blob or a string. Content type comes from
the option, then the filename.
The rest of it#
await hutch.project()
await hutch.transforms()
await hutch.file(id)
await hutch.signedUrl(id, { expiresIn: 3600, disposition: "attachment" })
await hutch.transformUrl(id, { transform: "avatar" })
await hutch.deleteFile(id)Responses are plain typed objects in camelCase — with two exceptions.
metadata and the keys of file.transforms are yours, not ours, so they come
back exactly as you wrote them.
Errors#
The API's error codes are the contract, so they map to classes ahead of status. Match on a class or a code, never a message.
import { PolicyError, PlanLimitError } from "@filehutch/sdk"
try {
await hutch.upload(bytes, { policy: "avatars", filename: "huge.png" })
} catch (error) {
if (error instanceof PolicyError) return reply(422, error.message)
if (error instanceof PlanLimitError) return nudgeToUpgrade()
throw error
}