Server SDK
StorageClient runs on your backend and authenticates with your API key. Use it to mint upload URLs, manage files, and run multipart uploads.
Server-only
sonuslab-storage/server in a server-only file (Nitro server/api, Node script, edge function). Constructor
import { StorageClient } from 'sonuslab-storage/server'
const storage = new StorageClient({
apiKey: process.env.SONUSLAB_STORAGE_API_KEY!,
})| Parameter | Type | Description |
|---|---|---|
apiKeyrequired | string | sl_... token from the app Keys tab. |
baseUrl | string | Defaults to https://storage-api.sonuslab.dev. Override only when self-hosting. |
fetch | (typeof fetch)? | Override the fetch implementation (Cloudflare Workers, tests, etc). |
Self-hosting
Running your own storage-api? Pass baseUrl: 'https://storage-api.yourdomain.com' to point the SDK at your deployment.
storage.upload(input)Upload bytes directly from your server. Best for small files (< single PUT limit).
const file = await storage.upload({
name: 'report.pdf',
contentType: 'application/pdf',
data: pdfBuffer,
metadata: { userId: 'abc' },
})| Parameter | Type | Description |
|---|---|---|
namerequired | string | Original file name (visible in the dashboard). |
contentTyperequired | string | MIME type — must match the actual bytes. |
datarequired | Buffer | Uint8Array | Blob | The file contents. |
metadata | Record<string, string> | Arbitrary key/value pairs stored alongside the file. |
storage.presign(input)Mint a short-lived upload URL for the browser.
const presign = await storage.presign({
name: 'avatar.png',
size: file.size,
contentType: 'image/png',
})
// presign.uploadUrl → short-lived upload URL (browser PUTs to it)
// presign.fileId → opaque id used for completeUpload()
// presign.key → final object key| Parameter | Type | Description |
|---|---|---|
namerequired | string | Original file name. |
sizerequired | number | Byte size of the file. Validated against the app maxFileSize. |
contentTyperequired | string | MIME type. |
metadata | Record<string, string> | Stored on the file once the upload finalizes. |
storage.completeUpload({ fileId })Finalize a presigned upload after the browser PUT succeeds.
const file = await storage.completeUpload({ fileId: presign.fileId })| Parameter | Type | Description |
|---|---|---|
fileIdrequired | string | The id returned by presign(). |
storage.initMultipart(input)Start a multipart upload session (server-side, for large files).
const init = await storage.initMultipart({
name: 'movie.mp4',
size: file.size,
contentType: 'video/mp4',
})
// init.uploadId, init.key, init.fileId| Parameter | Type | Description |
|---|---|---|
namerequired | string | Original file name. |
sizerequired | number | Total file size in bytes. |
contentTyperequired | string | MIME type. |
metadata | Record<string, string> | Stored on the file once completed. |
storage.presignMultipartPart(uploadId, key, partNumber)Mint an upload URL for one part of a multipart upload.
const { uploadUrl, partNumber } =
await storage.presignMultipartPart(init.uploadId, init.key, 1)storage.completeMultipart(input)Finalize a multipart upload after all parts succeed.
const file = await storage.completeMultipart({
uploadId: init.uploadId,
key: init.key,
fileId: init.fileId,
parts: [{ partNumber: 1, etag: '...' }, ...],
})| Parameter | Type | Description |
|---|---|---|
uploadIdrequired | string | From initMultipart. |
keyrequired | string | From initMultipart. |
fileIdrequired | string | From initMultipart. |
partsrequired | { partNumber, etag }[] | Ordered list of completed parts. |
storage.abortMultipart(uploadId, key, fileId)Abort a multipart upload (call this if the user cancels).
await storage.abortMultipart(init.uploadId, init.key, init.fileId)storage.listFiles({ limit?, cursor?, search? })Paginated list of files in the app.
const { items, nextCursor } = await storage.listFiles({
limit: 50,
search: 'avatar',
})
while (cursor) {
const page = await storage.listFiles({ cursor })
// ...
}| Parameter | Type | Description |
|---|---|---|
limit | number | Page size. Default 50, max 200. |
cursor | string | Opaque pagination token from a previous call. |
search | string | Substring match against file name. |
storage.getFile(id)Fetch a single file by id.
const file = await storage.getFile('file_abc')storage.deleteFile(id)Soft-delete a file. Recoverable through the grace window, then permanently removed.
await storage.deleteFile('file_abc')