Files and uploads
Where an app on LazyFrog keeps uploaded and generated files: a file store that survives publishes, public file links and an S3-compatible API.
/datais the environment's file store: it survives restarts and publishes, and is in every snapshot. Files under/data/public/are served to everyone at/files/<path>(5-minute cache). Other files are private.- An S3-compatible API over
/datais atS3_ENDPOINT(http://s3.local), bucketS3_BUCKET, keysS3_ACCESS_KEY/S3_SECRET_KEY, regionS3_REGION; the AWS SDK variables are set too, sonew S3Client({ forcePathStyle: true })orboto3.client("s3")work with no options. An object's key is its path under/data(public/avatars/1.pngis/files/avatars/1.png). - Visitor uploads and private downloads: presign on the server with a second client whose
endpointisS3_PUBLIC_ENDPOINT(the site's own address +/_lf/s3) andforcePathStyle: true; the browser then PUTs or GETs that URL on the same origin (no CORS). A test or app on another origin (an e2e suite athttp://localhost:4173) is refused until routing.json has acorsrule for/_lf/s3/*allowing that origin (a preview-only test origin is fine; the URL's signature stays the credential), or presign through the app's own origin. Presigned URLs last at most 15 minutes (expiresIn≤ 900). Each request is capped at 100,000,000 bytes (95 MiB) at the edge: use multipart with parts of 64 MiB or less (@aws-sdk/lib-storageUpload, boto3upload_fileobj) for larger files. Sign the type (signableHeaders: new Set(["content-type"])) and upload visitors' files to a private key, then check them on the server (type, size, re-encode images) and copy them to a new final key (underpublic/or private) that you serve: a presigned PUT can't cap the size, and the upload key stays writable until its URL expires, so never serve the key that was uploaded to. Files served from/filesnever run as the site (they are sandboxed, and HTML downloads). - A deleted or replaced public file stays in the edge cache up to its max-age (5 minutes unless the object or routing sets another): to take a photo down at once, give it a new name and stop linking the old one. Content-hashed names can be cached for a year.
/files/*and/_lf/*are the platform's; an app's own/files/...route still works for any path with no file in/data/public/.- The user's photos, and images your app made in the chat, come in with
fs_import(see "Their own photos and files"). An image your app's image generation made always takesgenerated: true(anything you created, not a file the user attached), or it is recorded as the user's own photo; the same file again withgenerated: truecorrects that.
For your AI: this page as Markdown · llms.txt