* Copy images when duplicating a cloud strategy Duplicating a cloud strategy now runs as one server mutation, strategies:duplicate. It copies pages, page settings, live elements and lineups under fresh publicIds, and gives the copy its own imageAssets row for each image it shows, pointing at the same R2 object. The cleanup worker already deletes bytes only when no other row points at them, so deleting either strategy leaves the other's images intact. The client previously rebuilt the copy op by op and never created asset rows, so the copy's placed images and lineup images had nothing to render, and deleting the original deleted their bytes. A duplicate is refused while an image is still uploading (client and server), and failures now show a message instead of throwing silently. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Show "Image unavailable" for a cloud image with no asset A cloud image whose asset row did not exist showed "Syncing image" forever: a copy's image before the duplicate fix, or an image whose asset was cleaned up. The page snapshot is a live query over the page's assets, so once it has loaded, a missing row means no bytes are on the server and no upload has started anywhere. Such an image now shows "Image unavailable", unless this device still has its upload queued. A pending asset and a page still loading keep the spinner. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Expect images that land before their upload An image element (or lineup image) and its upload reach the server independently. When the content landed first, nothing recorded that an image was coming: a duplicate made meanwhile copied no asset and succeeded without the image for good, and other devices showed "Image unavailable" for an image that was only slow. applyBatch now gives each image that accepted content newly shows a pending placeholder asset row when nothing exists for it. The upload intent adopts the placeholder, deleting the image element drops it, and the stale-upload sweep removes it if the upload never comes, after which the image reads as unavailable. Duplicate already refuses while an image is pending, so it now waits for these too. Also from review: - a duplicated lineup group's agent and abilities point at the copy's group id; - duplicating while browsing someone else's folder lands in the caller's library root instead of failing; - a missing asset stays "Syncing image" until the upload queue can answer (account known, outbox readable), so startup does not flash "Image unavailable". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
15 files changedLine totals unavailable