Example

Browser-to-browser file transfer

Send a File through an action and receive its bytes on the other side. Metadata carries the filename and type; progress callbacks keep the UI up to date.

Send a file with metadata and progress

This sketch accepts files up to 100 MiB. Trystero splits the payload into chunks and returns a Uint8Array to the receiver. Wrap those bytes in a Blob before creating a download URL.

import {joinRoom} from 'trystero'

const room = joinRoom({appId: 'dev.trystero.examples.fileDrop'}, dropId)
const fileAction = room.makeAction('file', {
  onReceive: ({byteLength}) => byteLength <= 100 * 1024 ** 2
})

fileAction.onReceiveProgress = (progress, {peerId, metadata}) => {
  updateProgress(peerId, metadata?.name ?? 'download', progress)
}

fileAction.onMessage = (bytes, {peerId, metadata}) => {
  const blob = new Blob([bytes], {type: metadata?.type})
  const url = URL.createObjectURL(blob)
  showDownload({
    peerId,
    url,
    name: metadata?.name ?? 'download',
    size: blob.size
  })
}

fileInput.onchange = async () => {
  const file = fileInput.files?.[0]

  if (!file) return

  try {
    await fileAction.send(file, {
      metadata: {name: file.name, type: file.type},
      onProgress: progress => showSendingProgress(file.name, progress)
    })
  } catch (error) {
    showTransferError(error)
  }
}

The input and display functions belong to your app. Revoke each object URL when its download is removed. Progress is a fraction from 0 to 1. Sending without a target broadcasts the file to every connected peer.

Rooms have a default 256 MiB receive budget. Set maxReceiveBytes if you need a different limit. Files must fit in the receiver’s memory.