SonusLab StorageSonusLab Storage

Vue

Reactive upload state for Vue 3. Same upload flow as browser uploads, wrapped in a composable plus a headless component.

useUpload

Import from sonuslab-storage/vue. Returns reactive status, progress, and error refs plus upload() and reset() methods.

Uploader.vue
<script setup lang="ts">
  import { useUpload } from 'sonuslab-storage/vue'

  const { upload, status, progress, error, reset } = useUpload({
    presignEndpoint: '/api/upload/presign',
    completeEndpoint: '/api/upload/complete',
  })

  function onChange(e: Event) {
    const file = (e.target as HTMLInputElement).files?.[0]
    if (file) upload(file)
  }
</script>

<template>
  <input type="file" @change="onChange" :disabled="status === 'uploading'" />

  <p v-if="status === 'uploading'">{{ progress?.percent ?? 0 }}%</p>
  <template v-if="status === 'error'">
    <p>{{ error?.message }}</p>
    <button @click="reset">Retry</button>
  </template>
</template>

Reactive refs

ParameterTypeDescription
statusRef<'idle' | 'uploading' | 'complete' | 'error'>Current upload state.
progressRef<{ loaded, total, percent } | null>Live progress during the PUT (0–100).
errorRef<Error | null>Populated when status is error.
resultRef<UploadResult | null>fileId + key after status becomes complete.

Methods

ParameterTypeDescription
upload(file)(file: File | Blob) => Promise<UploadResult>Run the presign → PUT → complete flow.
reset()() => voidClear status, progress, error, and result back to idle.
cancel()() => voidAbort the in-flight upload.

Lifecycle callbacks

Pass these in useUpload({ ... }) for side-effects without watching status.

ParameterTypeDescription
onStart(file: File) => voidFires when upload() is invoked, before any network I/O.
onComplete(result: UploadResult) => voidFires after the complete step resolves.
onError(err: Error) => voidFires when the upload rejects (after status becomes error).

<StorageUpload>

A headless component wrapping useUpload. The default slot receives status, progress, trigger, and inputProps — bring your own markup.

AvatarUpload.vue
<script setup lang="ts">
  import { StorageUpload } from 'sonuslab-storage/vue'
</script>

<template>
  <StorageUpload
    presign-endpoint="/api/upload/presign"
    complete-endpoint="/api/upload/complete"
    accept="image/*"
    :max-size="10_000_000"
    @complete="(r) => console.log(r.fileId)"
  >
    <template #default="{ status, progress, trigger, inputProps }">
      <button :disabled="status === 'uploading'" @click="trigger">
        {{ status === 'uploading' ? `Uploading ${progress?.percent ?? 0}%` : 'Upload' }}
      </button>
      <input v-bind="inputProps" />
    </template>
  </StorageUpload>
</template>

Props

ParameterTypeDescription
presign-endpointrequiredstringURL of the presign route on your server.
complete-endpointrequiredstringURL of the complete route on your server.
acceptstringStandard accept attribute (e.g. image/*).
multiplebooleanAllow multiple files.
max-sizenumberClient-side size check, in bytes.

Events

ParameterTypeDescription
complete(result: { fileId, key }) => voidEmitted when an upload finalizes successfully.
error(err: Error) => voidEmitted on any failure.
progress(p: { loaded, total, percent }) => voidEmitted during the PUT.