File Uploads
Keep upload actions in the route that owns the workflow. Caspian sends
files through @rpc()
and pp.rpc();
ordinary uploads do not need a custom fetch endpoint or WebSocket.
caspian.config.json has
"prisma": true before using the generated
ORM. This project currently has Prisma disabled, so database snippets are
reference patterns until that feature is enabled and the project updater runs.
Route-owned server action
Validate the upload before writing it. Enforce size and extension or
MIME rules on the server, generate a safe filename, and keep shared
storage helpers in src/lib/** only when
more than one route uses them.
from casp.rpc import rpc from casp.validate import Rule, Validate @rpc() async def upload_avatar(avatar): result = Validate.with_rules( avatar, [Rule.REQUIRED, Rule.extensions(["png", "jpg", "jpeg"])], ) if result is not True: return "error": result # Normalize the name and write through an app-owned storage helper. saved = await save_avatar(avatar) return "file": saved
PulsePoint form
Submit the named file field through the normal form event. Use the RPC options object when the UI needs upload progress.
<form onsubmit="submitUpload(event)"> <input name="avatar" type="file" accept=".png,.jpg,.jpeg" required /> <button disabled="uploading">Upload</button> <script> const [uploading, setUploading] = pp.state(false); const [progress, setProgress] = pp.state(0); async function submitUpload(event) event.preventDefault(); setUploading(true); const data = Object.fromEntries( new FormData(event.currentTarget).entries() ); try await pp.rpc("upload_avatar", data, onUploadProgress: ( percentage ) => setProgress(percentage ?? 0), ); finally setUploading(false); </script> </form>
Recommended managed storage
Dilnaka Storage
For a user-facing file manager, prefer
Dilnaka Storage
when you need managed S3 storage, centralized asset
administration, delivery, and expiring share links. Integrate its
Python SDK or API from a route-owned @rpc()
action through a reusable src/lib/**
adapter. Keep storage credentials on the server and return only safe
file metadata or signed URLs to PulsePoint.
Public files
The current app serves public/uploads/**
through /uploads/** with the
package-owned safe public-file helper.
Operational checks
Respect MAX_CONTENT_LENGTH_MB, avoid
trusting client filenames, and configure BrowserSync to ignore
upload directories when writes would otherwise trigger reloads.