Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.deep.space/llms.txt

Use this file to discover all available pages before exploring further.

The useR2Files hook handles uploads, listings, deletions, and signed URLs against the app’s R2 bucket. All operations route through the platform’s file gateway, so end users never touch raw R2 credentials. For patterns and worked examples, see the file uploads guide.
import { useR2Files, isImageFile, formatFileSize } from 'deepspace'
import type { R2FileInfo, R2Scope } from 'deepspace'

useR2Files(options?)

type R2UploadResult = {
  success: boolean
  key?: string
  url?: string
  name?: string
  error?: string
}

function useR2Files(options?: R2Scope): {
  upload:       (file: File | Blob, name?: string) => Promise<R2UploadResult>
  uploadBase64: (base64Data: string, name: string, mimeType?: string) => Promise<R2UploadResult>
  deleteFile:   (fileOrKey: R2FileInfo | string) => Promise<{ success: boolean; error?: string }>
  downloadFile: (fileOrKey: R2FileInfo | string, fileName?: string) => Promise<{ success: boolean; error?: string }>
  readFile:     (fileOrKey: R2FileInfo | string) => Promise<Response>
  list:         (prefix?: string) => Promise<R2FileInfo[]>
  getUrl:       (fileOrKey: R2FileInfo | string) => string
  isUploading:  boolean
}
options is the R2Scope itself - pass { scope: 'self' } (or omit entirely; 'self' is the only valid scope). Every method that takes a file accepts either an R2FileInfo object from list() or a raw key string.
upload accepts a File (from <input type="file"> or a drag-drop event) or a Blob and an optional display name. Returns R2UploadResult - check success and read the key field.
const { upload, isUploading } = useR2Files()

async function onFileChange(e: React.ChangeEvent<HTMLInputElement>) {
  const file = e.target.files?.[0]
  if (!file) return
  const result = await upload(file, file.name)
  if (!result.success) return console.error(result.error)
  console.log('uploaded:', result.key)
}
list() is an async function - call it and store the result in component state rather than reading a reactive array.

R2FileInfo

type R2FileInfo = {
  key: string
  size: number
  uploaded: string
  url: string
  originalName?: string
  uploadedBy?: string
}
There is no mimeType / contentType field on R2FileInfo. Capture the MIME type at upload time and store it in a sidecar collection if you need it later. See storing metadata.

Scoping - R2Scope

type R2Scope = { scope?: 'self' }
The hook is always scoped to the current app (scope: 'self') - the platform derives the bucket prefix from the request’s hostname. There is no per-user, per-room, or cross-app scope option exposed by useR2Files.
const { upload, list } = useR2Files()             // implicit { scope: 'self' }
const { upload, list } = useR2Files({ scope: 'self' }) // equivalent

Display helpers

HelperSignature
isImageFile(mimeType: string)Returns true for image/* MIMEs
formatFileSize(bytes: number)Returns '1.2 MB', '456 KB', etc.

Local dev limitation

R2 uploads require an APP_IDENTITY_TOKEN minted by the deploy worker. The CLI does not provision this token locally, so upload() round-trips return 401 from the platform file gateway. In local dev, assert that uploads are dispatched; the full flow works only against deployed apps.

See also