New:Microsoft Teams Notifications Are Now Available in Socket.Learn more
Get Started

@encody/vue

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@encody/vue

Encody client SDK — resumable upload queue with Vue composables

npmnpm
Version
0.4.0
Version published
Weekly downloads
6
-60%
Maintainers
1
Weekly downloads
 
Created
Source

@encody/vue

TUS-based resumable upload queue with a Vue 3 composable. Handles concurrency, retries, SSE status updates, file validation, and error codes out of the box.

Install

npm install @encody/vue

Usage

import { useEncody } from '@encody/vue'

const { add, clear, files, isActive } = useEncody({
  token: () => getTokenFromBackend()
})

All options accept a raw value or a Vue ref — the composable stays reactive either way.

Live demo and playground: demo.encody.io

Options

OptionDefaultDescription
baseUrl'https://app.encody.io'API origin. Override for on-prem or enterprise installs.
endpoint{baseUrl}/media/uploadTUS upload endpoint. Derived from baseUrl if omitted.
sseUrl{baseUrl}/api/upload-eventsSSE endpoint for real-time status updates. Derived from baseUrl if omitted.
tokenasync () => string — called before each upload and on SSE reconnect. Must return a short-lived JWT. Never expose your API key to the browser — request the token from your own backend, which exchanges the API key for a JWT against the Encody API.
concurrency3Max parallel uploads.
retryDelays[0, 3000, 10000, 30000]Backoff delays in ms between TUS retries. Pass [] to disable.
maxSizenullMax file size in bytes. null = unlimited.
allowedTypes[]Allowed MIME types. Supports wildcards (image/*). Empty = all types allowed.

Token flow

The token function is called by the SDK before every upload and on SSE reconnect. It must return a short-lived JWT issued by the Encody API.

Your API key must never leave your server. The recommended flow is:

Browser  →  POST /token  →  Your backend  →  POST /api/token  →  Encody API
                                              (Authorization: Bearer ek_...)

Minimal Node.js token endpoint (no dependencies):

// token-server.mjs
import { createServer } from 'node:http'

const {
  PORT = 3000,
  ENCODY_API_KEY,
  ENCODY_BASE_URL = 'https://app.encody.io'
} = process.env

createServer(async (req, res) => {
  if (req.method !== 'POST' || req.url !== '/token') {
    res.writeHead(404).end()
    return
  }

  const { token } = await fetch(`${ENCODY_BASE_URL}/api/token`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${ENCODY_API_KEY}` }
  }).then(r => r.json())

  res.writeHead(200, { 'Content-Type': 'application/json' })
  res.end(JSON.stringify({ token }))
}).listen(PORT)
ENCODY_API_KEY=ek_... node token-server.mjs

Then pass it to useEncody:

const { add, files } = useEncody({
  token: async () => {
    const res = await fetch('/token', { method: 'POST' })
    return (await res.json()).token
  }
})

Composable return value

const {
  add, // add files to the queue
  clear, // clear the queue
  files, // ComputedRef<FileRecord[]> — reactive queue state
  isActive, // ComputedRef<boolean> — true while any upload is in progress
  file, // (id) => { retry, cancel, pause, resume, updateMeta }
  useFile, // (id | Ref<id>) => ComputedRef<FileRecord> — reactive single file
  useBatch, // (batchId) => { files, progress, isComplete, hasFailed }
  on, // (event, handler) => void
  off // (event, handler) => void
} = useEncody(options)

add(input, options?)

// single file
add(file)

// multiple files — auto-grouped as a batch
add([file1, file2])

// with custom meta (stored to DB, accessible server-side)
add(files, { meta: { folderId: '123', tag: 'avatar' } })

// per-file meta
add([
  { file: fileA, meta: { tag: 'cover' } },
  { file: fileB, meta: { tag: 'thumb' } }
])

file(id)

file(id).retry()
file(id).cancel()
file(id).pause()
file(id).resume()
file(id).updateMeta({ tag: 'updated' })

Events

on('file:uploading', ({ fileId, filename, size, meta }) => {})
on('file:ready', ({ fileId, url, meta }) => {})
on('file:failed', ({ fileId, code, error, meta }) => {})
on('file:progress', ({ fileId, progress, meta }) => {})
on('batch:complete', ({ batchId, files }) => {})
on('batch:failed', ({ batchId, failed, succeeded }) => {})
on('sse:error', () => {})

FileRecord shape

{
  id:          string,
  status:      'queued' | 'uploading' | 'processing' | 'ready' | 'failed' | 'cancelled',
  progress:    number,   // 0–99 during upload, 99 during processing, 100 when ready
  name:        string,
  size:        number,
  mimeType:    string,
  meta:        object,
  batchId:     string | null,
  error:       string | null,
  errorCode:   ErrorCode | null,
  url:         string | null,  // populated when status === 'ready'
}

Error codes

import { defaultMessages, EncodyError, ErrorCode } from '@encody/vue'

ErrorCode.TOKEN_EMPTY // token() returned falsy
ErrorCode.UPLOAD_FAILED // network or server error
ErrorCode.VIRUS_DETECTED // antivirus flagged the file
ErrorCode.SSE_ERROR // SSE connection failed repeatedly
ErrorCode.FILE_TOO_LARGE // exceeds maxSize
ErrorCode.FILE_TYPE_NOT_ALLOWED // not in allowedTypes

Use defaultMessages[code] as fallbacks, override per code for i18n:

const messages = {
  [ErrorCode.FILE_TOO_LARGE]: 'Die Datei ist zu groß'
}

function errorMessage(file) {
  return messages[file.errorCode] ?? file.error
}

Framework-agnostic core

import { createEncody } from '@encody/vue/core'

const instance = createEncody({ token, baseUrl })
instance.add(files)
instance.on('file:ready', handler)
instance.destroy()

License

MIT

Author

Marcus Spiegel spiegel@uscreen.de — published and supported by u|screen

FAQs

Package last updated on 20 Apr 2026

Related posts