- A server-side write. The bytes are already on your server when the model answers, so they go up with
put. There is no browser upload here. - A new path per generation.
generations/${user.id}/${generationId}is written once and never overwritten, socache: 'immutable'is unconditionally safe. - A row per generation. It holds the prompt, the path and the URL, and it is what the gallery reads.
Storing a generation
Read the model’s response as aBlob and hand it to put. A Blob carries its own length and its own type, so nothing has to be declared.
lib/generations.ts
image/png or image/webp alike. If the response carries no Content-Type, pass contentType yourself, or the object is stored as application/octet-stream and a browser downloads it instead of rendering it.
Plenty of providers answer with JSON pointing at a temporary URL instead. Fetch that URL and store what comes back the same way:
put takes the response stream with a size; see Writing.
The route
app/api/generate/route.ts
The gallery
The bucket cannot answer “what has this user generated”. Your table can, so read rows and render the URL stored on each one:app/gallery/page.tsx
immutable under a path that is never reused, so a browser or CDN that has seen one keeps it for a year and there is nothing to invalidate.
If the gallery is not public, create the bucket as private instead. blob.url is undefined there, so the row keeps only the path, and a route of yours checks ownership and calls signedReadUrl at click time. That shape is in Private documents.
Deleting
Delete the row first, then the object. The gallery stops showing the image immediately, and if the second step fails the leftover is an object nobody links to rather than a broken image.del treats an already missing object as success, so it is safe to retry.
app/actions.ts
Next steps
Writing
Which bodies
put accepts, and what a stream needs.Caching
immutable, revalidate, and what each one stores.Deleting
One path, an array, and what a partial delete reports.
Private documents
The same shape on a private bucket, with signed reads.