File operations

Upload, download, list, and delete files using the EmuView SDK with the presigned R2 URL flow.

#File operations

The EmuView SDK handles file uploads, downloads, listing, and deletion. Behind the scenes, uploads use a three-step presigned URL flow — files go directly from the browser to Cloudflare R2 without passing through the Worker.

#Prerequisites

  • An EmuView SDK instance configured with authentication
  • For uploads: an authenticated user with system/files:create permission
import { EmuView } from '@emuview/sdk';

const sdk = new EmuView({
	url: 'https://your-api.example.com',
	auth: { apiKey: 'sk-your-api-key' }
});

#Steps

#1. Upload a file

The sdk.files.upload() method wraps the full presigned URL flow into a single call:

const fileInput = document.querySelector('input[type=file]');
const file = fileInput.files[0];

const { fileId } = await sdk.files.upload(file, {
	filename: file.name,
	mimeType: file.type,
	collection: 'products' // optional: associate with a collection
});

console.log(`Uploaded file: ${fileId}`);

After uploading, store the fileId in a record's file field:

await sdk.collection('products').update('b10b01964f804a55b140be7dad738c8f', {
	image: fileId
});
Note

The SDK handles all three steps (request token, PUT to R2, confirm upload) automatically. For custom upload flows, use the Files API endpoints directly.

#2. Download a file

Get a presigned download URL for a file. The URL expires after 5 minutes.

const downloadUrl = await sdk.files.getDownloadUrl('file_a1b2c3d4e5f6a7b8');

// Use the URL in an <img> tag, <a> download link, or fetch()
const img = document.createElement('img');
img.src = downloadUrl;

Request a thumbnail variant for images:

const thumbUrl = await sdk.files.getDownloadUrl('file_a1b2c3d4e5f6a7b8', {
	size: 'thumbnail'
});

#3. List all files

Retrieve all completed files in the current project:

const files = await sdk.files.list();

for (const file of files) {
	console.log(`${file.filename} (${file.mimeType}, ${file.sizeBytes} bytes)`);
}

The response includes metadata for each file:

// Each file object:
{
  id: 'file_a1b2c3d4e5f6a7b8',
  filename: 'product-photo.jpg',
  mimeType: 'image/jpeg',
  sizeBytes: 2048576,
  collectionName: 'products',
  uploadedBy: 'usr_01HXK5M9ABCDEF',
  createdAt: 1718900000,
}

#4. Delete a file

Delete a file, its thumbnails, and metadata:

await sdk.files.delete('file_a1b2c3d4e5f6a7b8');
Warning

Deletion is permanent. The original file, all size variants (thumbnails), and the database record are removed.

#What you learned

  • How to upload files with a single SDK call
  • How to get presigned download URLs (with optional size variants)
  • How to list and delete files

#Next steps

  • Files API — raw HTTP endpoints for custom upload flows
  • Collections — store file IDs in record fields using the file field type

#Error handling

File operations throw ApiError on failure:

import { ApiError } from '@emuview/sdk';

try {
	await sdk.files.upload(largeFile, {
		filename: 'backup.zip',
		mimeType: 'application/zip'
	});
} catch (err) {
	if (err instanceof ApiError) {
		if (err.code === 'limit_exceeded') {
			console.error('File exceeds project storage quota (5 GB default)');
		}
	}
}

#Common errors

Code Status Cause
limit_exceeded 400 File size exceeds project storage quota
forbidden 403 User lacks file upload/download/delete permission
not_found 404 File ID does not exist or upload was not confirmed

#Storage limits

Limit Default
Project storage quota 5 GB
Max upload size 100 MB per file
Upload URL expiry 120 seconds
Download URL expiry 300 seconds (5 minutes)