0.1.5 · Authorized attachment picker
ROM 0.1.5 guide: Authorized attachment picker..
This composition is a ROM 0.1.3 candidate. The installed checks described below passed. Release acceptance remains open.
Import AttachmentPicker from rom-studio/ui/components.
Supply the session-owned client, a disclosed Blob Resource descriptor, and the current authority token.
Replace the authority token after a session or permission change.
The picker reads authorized pages through RomClient.query.
It uses native query anchors for continuation. Continuation tokens belong to one catalog instance.
Search filters the current candidate page. It is not a full-text query.
The flat catalog does not invent folders or storage paths.
Titles use only disclosed fields from the Resource descriptor.
Selection returns the exact { kind, id } reference. Selection does not upload, attach, or mutate a Resource.
Use createAttachments from rom-studio/client for the existing reserve, upload, detach, and recovery lifecycle.
An unknown outcome requires recovery of the existing operation. It does not permit a new upload operation.
The host must dispose controllers when authority changes. The catalog rejects late results after disposal, cancellation, or client generation changes. The picker closes after an authority token change.
Upload composition
Import AttachmentUpload from rom-studio/ui/components.
Supply an optional picker snippet to use another local selection component, such as UppySelection from rom-ui/files/uppy.
Import its argument type, AttachmentUploadPicker, from rom-studio/ui/components.
The snippet receives authority, disabled, maxFiles, maxBytes, and select(files).
Forward these limits and the disabled state to the picker. Call select with one local File.
Studio rejects callbacks after disposal, while an operation is unresolved, or when the selection exceeds its limits.
The existing controller owns reservation, byte transfer, confirmation, and retry. The picker does not confirm an attachment.
Without a snippet, the native local file picker remains the default.
{#snippet picker(state: AttachmentUploadPicker)}
<UppySelection
authority={state.authority}
disabled={state.disabled}
maxFiles={state.maxFiles}
maxBytes={state.maxBytes}
onselect={state.select}
/>
{/snippet}
<AttachmentUpload {client} {authority} {capabilities} {id} {store} {picker} /> Supply the session client, advertised Blob capabilities, authority token, exact Resource ID, and approved store. The component owns and disposes the existing attachment controller for that scope. It uses the shared local file picker and upload queue. It accepts one local file at a time. The file name does not determine the Resource ID or store.
Select a file, then select Upload attachment.
The component reports processing while the existing controller reserves and uploads the bytes.
It does not report measured transfer progress.
After an unknown outcome, select Reconcile to resume the same operation.
The component calls onconfirmed only after the controller receives a successful ROM result.
A later local file selection starts in the selected state. It does not inherit the earlier confirmation.
Host notification failures do not change a confirmed ROM result into an unknown outcome. The component reports notification failure separately.
The eight Chromium and WebKit composition checks use a fixture client. They do not prove backend authorization, durable reload recovery, or a published release.
Optional recovery across reload
Supply recovery to retain an unresolved upload across reload.
Studio keeps the original reservation identity and frozen bytes before the first external request.
Restoration validates the current principal, target slot, capabilities, and digest.
Restoration does not send a request. Select Reconcile to retry the original operation.
The host selects the cache and its privacy policy. No store is opened by default. Use the standard AppSession to construct the binding. Do not construct a principal from cached data.
import { openIndexedDbAttachmentIntentStore } from 'rom-studio/client';
const uploadIntents = await openIndexedDbAttachmentIntentStore({
name: 'app-upload-intents-v1',
maxBytes: capabilities.limits.blob_bytes + 65536,
maxSlots: 16,
});
const recovery = session.attachmentRecovery(target, uploadIntents); <AttachmentUpload {client} {authority} {capabilities} {id} {store} {recovery} /> session is the active session returned by createAppSession from rom-studio/application.
Choose a stable { kind, id } target for the upload context.
For a conversation, use its Resource key. For a creation view, use a distinct, stable local key.
The target selects local recovery. It does not grant ROM access.
Close the host-owned store when its application lifetime ends.
The store commits binary bytes and metadata in one strict IndexedDB transaction. It stores an ArrayBuffer and reconstructs a Blob on read for Chromium and WebKit compatibility. The byte budget includes file bytes and encoded metadata. Browser eviction can remove cached work. The checkpoint contains no cookie, CSRF token, or session secret. Every retry uses the current ROM client and server authorization.
The existing controller remains the owner of reservation, upload, confirmation, and retry. It clears the checkpoint through an atomic version comparison after a successful result. The checkpoint is local intent data. ROM remains the owner of receipts and attachment state.
Four installed real-host journeys passed with native and Uppy selection in Chromium and WebKit. They lose the response after actual byte transfer, reload, and retry the original reservation identity. They then attach the recovered file to a persisted message and download identical bytes. These checks do not establish a published ROM 0.1.3 release.