Server SDK
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!,
})
| Name | Type | Required | Description |
|---|---|---|---|
apiKey | string | yes | sl_... token from the app Keys tab. |
baseUrl | string | no | Defaults to https://storage-api.sonuslab.dev. Override only when self-hosting. |
fetch | typeof fetch | no | 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 (under the single PUT limit).
const file = await storage.upload({
name: 'report.pdf',
contentType: 'application/pdf',
data: pdfBuffer,
metadata: { userId: 'abc' },
})
| Name | Type | Required | Description |
|---|---|---|---|
name | string | yes | Original file name (visible in the dashboard). |
contentType | string | yes | MIME type — must match the actual bytes. |
data | Buffer | Uint8Array | Blob | yes | The file contents. |
metadata | Record<string, string> | no | 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
| Name | Type | Required | Description |
|---|---|---|---|
name | string | yes | Original file name. |
size | number | yes | Byte size of the file. Validated against the app maxFileSize. |
contentType | string | yes | MIME type. |
metadata | Record<string, string> | no | 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 })
| Name | Type | Required | Description |
|---|---|---|---|
fileId | string | yes | 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
| Name | Type | Required | Description |
|---|---|---|---|
name | string | yes | Original file name. |
size | number | yes | Total file size in bytes. |
contentType | string | yes | MIME type. |
metadata | Record<string, string> | no | 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: '...' }, ...],
})
| Name | Type | Required | Description |
|---|---|---|---|
uploadId | string | yes | From initMultipart. |
key | string | yes | From initMultipart. |
fileId | string | yes | From initMultipart. |
parts | { partNumber, etag }[] | yes | 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 })
// ...
}
| Name | 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.getDownloadUrl(id, opts?)
Resolve a readable URL for a file. Returns the stable CDN URL on public apps, a short-lived presigned GET on private ones.
const url = await storage.getDownloadUrl('file_abc', { expiresIn: 600 })
| Name | Type | Description |
|---|---|---|
expiresIn | number | Lifetime in seconds, 1–604800. Default 300. Ignored on public apps — the CDN URL never expires. |
storage.download(id)
Fetch the stored bytes plus the file record.
const { data, file } = await storage.download('file_abc')
// data : Uint8Array — ciphertext if the file was uploaded encrypted
// file : StorageFile
storage.deleteFile(id)
Soft-delete a file. Recoverable through the grace window, then permanently removed.
await storage.deleteFile('file_abc')
