Quickstart
From zero to a working upload in under five minutes.
1
Create an app
Head to /apps and click New App. Pick a name, region, visibility, and a max file size.
2
Create an API key
Open the app's Keys tab and click Create. Copy the sl_... token shown — it's displayed exactly once.
Store it securely
The key is hashed at rest. If you lose it, rotate and re-deploy — there's no recovery.
3
Install the package
bun add sonuslab-storage Vue is an optional peer dependency — only required if you import from sonuslab-storage/vue.
4
First upload (server)
For small files (think reports, avatars, attachments), upload the bytes straight from your server.
server/upload-report.ts
import { StorageClient } from 'sonuslab-storage/server'
import { readFile } from 'node:fs/promises'
const storage = new StorageClient({
apiKey: process.env.SONUSLAB_STORAGE_API_KEY!,
})
const data = await readFile('./report.pdf')
const file = await storage.upload({
name: 'report.pdf',
contentType: 'application/pdf',
data,
metadata: { userId: 'abc' },
})
console.log(file.id, file.key, file.url)5
First browser upload
For user-driven uploads, the browser uploads bytes via a short-lived upload URL. Wire up two server routes (presign + complete), then call uploadFile from your component.
server/api/upload/presign.post.ts
import { StorageClient } from 'sonuslab-storage/server'
const storage = new StorageClient({
apiKey: process.env.SONUSLAB_STORAGE_API_KEY!,
})
export default defineEventHandler(async (event) => {
const body = await readBody(event)
return storage.presign(body)
})server/api/upload/complete.post.ts
export default defineEventHandler(async (event) => {
const { fileId } = await readBody(event)
return storage.completeUpload({ fileId })
})components/Uploader.vue (browser)
<script setup lang='ts'>
import { uploadFile } from 'sonuslab-storage/client'
async function onChange(e: Event) {
const file = (e.target as HTMLInputElement).files?.[0]
if (!file) return
const result = await uploadFile({
file,
presignEndpoint: '/api/upload/presign',
completeEndpoint: '/api/upload/complete',
onProgress: (p) => console.log(`${p.percent}%`),
})
console.log('uploaded', result.fileId, result.key)
}
</script>
<template>
<input type='file' @change='onChange' />
</template>Next steps
- Vue integration — useUpload composable and headless StorageUpload component.
- Webhooks — react to upload.completed events server-side.
- Multipart uploads — for files larger than your single-PUT limit.