Skip to content

Files & Media

Store files and media from your app. Every file gets a permanent public URL.

Media in Proyecta comes in two layers. Most apps use the built-in CMS media capability — image and file uploads that the AI wires into your admin panel and forms for you. Under that, a lower-level Files API gives you direct control when you need it. Both store to CDN-backed object storage and hand back a permanent public URL.

The chat input accepts images directly — paste a screenshot or drag an image file onto the input. Supported formats: PNG, JPEG, WebP, GIF, AVIF. Maximum size: 10 MB per image.

Chat attachments are part of the message, not your file library. For persistent storage, use the built-in media uploads or the Files API.

Built-in media uploads (the CMS media capability)

Section titled “Built-in media uploads (the CMS media capability)”

Most apps don’t touch the Files API directly — media is a built-in CMS capability. The app template ships two upload hooks in @/hooks/useContent, and the AI wires them into your UI. You describe what you want (“an image field on my products”, “a file upload on my contact form”) and Proyecta uses the right one:

Hook Where it’s used Endpoint Size cap
useAssetUpload() Admin media library — backs the asset picker in the admin panel’s content editor POST /v1/public/files 10 MB
useFormFileUpload() Public form files — visitor uploads on a <FormBlock/> file field (receipts, photos) POST /v1/public/uploads 5 MB

Both hooks return a permanent public url you store on the content entry (admin) or form submission (public). A few things to know:

  • Both caps are enforced in code, not by plan — 10 MB for admin media, 5 MB for public form files.
  • Accepted types are images (except SVG) and PDF only. SVG is rejected for safety; large images are automatically downscaled before upload.
  • You don’t call these directly — the AI mounts them. Reach for the Files API below only for lower-level or custom file handling.

Every published Proyecta app can store and serve files. From your app’s pages this is a single call — the multi-step signed-upload dance is handled for you:

import * as platform from '@/lib/platformClient.ts';
// Upload straight from a file input — one call, no signed-URL juggling
async function onPick(file: File) {
const asset = await platform.assetDirectUpload({
blob: file,
filename: file.name,
mimeType: file.type,
});
console.log(asset.url); // permanent public URL
}
// List what's stored
const { assets, hasMore } = await platform.assetList({ limit: 20 });
// Remove one
await platform.assetDelete(asset.id);

Private files. Pass visibility: 'private' to store a file out of the public bucket with no permanent URL. Read it back with a short-lived link instead:

const { url, expiresAt } = await platform.assetSignedUrl(asset.id, { variant: 'thumbnail' });

Use private + signed URLs for anything that shouldn’t be guessable — customer uploads, ID documents, paid downloads.

File uploads are handled through the AI builder. Ask the AI to build the upload flow for you:

  • "Let users upload a profile photo and store it in Proyecta Files"
  • "Add an image gallery where signed-in users can upload and view their photos"
  • "Let me attach PDF invoices to orders"

The AI wires up the upload in your app code and references the returned public URL.

Are the file URLs public?

Yes. Any file returned by the Files API has a permanent public URL. Don’t upload anything you don’t want exposed.

How big can a file be?

File sizes are capped in code, not by plan: 10 MB for admin media-library uploads (useAssetUpload), 5 MB for public form-file uploads (useFormFileUpload), and 10 MB for chat attachments. Built-in media uploads accept images (except SVG) and PDF only.

Can I resize or crop images at the URL?

On-the-fly image transforms (resize, crop, format conversion) are on the roadmap.

  • Image transformations via URL parameters (resize, crop, format conversion)
  • Folder organization — create and manage folder paths for stored files