Let a reader upload a project file, download it later, or remove it. The
@pathmx/uppy package adds the upload controls and stores an attachment record
and binary file in the reader's writable Home.
Start with the local account and writable Home setup in an initialized project. Then install the uploader:
bun run pmx plugins add uppy
The default policy accepts JPEG, PNG, WebP, GIF, PDF, and ZIP files, up to
25 MiB per file and five selected files per declaration. Configure the
deployment policy through a repository Plugin when needed. Use this configured
entrypoint instead of also activating the default package in pathmx.plugins:
// plugins/attachment.plugin.ts
import { UppyAttachmentPlugin } from "@pathmx/uppy"
export default UppyAttachmentPlugin({
limits: {
maxFileSize: 50 * 1024 * 1024,
maxFiles: 5,
allowedFileTypes: ["image/*", ".pdf", ".zip"],
},
})
Create paths/project.page.md:
# Share your project
<x-auth-session />
<x-attachment-upload
name="project"
label="Upload project PDF"
accept=".pdf"
max-files="1"
max-size="25 MiB"
/>
Run bun run dev, open /project.page, and sign in as Ada. Select a PDF smaller
than 25 MiB and upload it. The saved selection offers its file for download and
removal; reload and download it to verify persistence. Try a PNG: this declaration
only accepts PDF, so choose an allowed file and retry. Its limits cannot widen
the deployment policy. If uploads are unavailable, check admission and Home write
access. Production needs configured credentials
and persistent writable hosting.
In Playwright, select the file through the real file input with setInputFiles,
then submit the uploader's normal control. For the native multipart form, submit
that form rather than posting a hand-built replacement request. Verify the saved
file survives reload and downloads with the expected bytes, and that another
Actor cannot retrieve it. A hung automation upload command alone does not prove
that the application's multipart route failed.
The native multipart form works without JavaScript on HTTP hosts. With JavaScript, Uppy Dashboard uses the document's active View connection for uploads; the same Component works with HTTP and browser-worker hosts. Removal forms and download links use that connection too.
Browser hosts preserve binary files and their media types in IndexedDB, alongside the readable Attachment State Source. Upload success confirms that the file and its record were saved. Retrying the same request after a lost response reuses the record. Worker transfers buffer file bodies; streaming and byte-by-byte upload progress are not supported.
The file write precedes the Source commit. An ordinary failed Source commit removes the new file; a crash between these writes can leave an unreferenced file. The pair is not a single atomic transaction.
A domain Plugin can use the reader returned by createUppyAttachmentPlugin()
from @pathmx/uppy. It resolves validated records for one Actor, Source, and named
selection. Ordinary Actions consume saved record ids or hrefs rather than raw
browser file objects; Attachment State retains binary authority and lifecycle
metadata. The uploader above is complete without a custom domain Plugin.
See Actions for transaction and authorization setup when attaching those saved records to domain work.