Hyperclay Local
  1. Hyperclay Local
  2. Docs
  3. Serving documents
  4. Metadata and uploads

Metadata and uploads

Inspect host capabilities and document metadata with GET /_/meta, and upload attachments with POST /_/upload.

Documents running in Hyperclay Local discover what the host supports through GET /_/meta and upload file attachments through POST /_/upload. For how ClayJS uses these endpoints in the browser, see Host compatibility and upload and quickcrop.

GET /_/meta#

GET /_/meta returns the capabilities of the local server and, when a Document-URL (or Page-URL) header names a document that exists on disk, the metadata and limits for that document:

HTTP
GET /_/meta
Document-URL: http://localhost:4321/index.html
JSON
{
  "spec": 1,
  "extensions": ["conditional", "format", "sync", "upload", "live-data", "live-provenance"],
  "document": {
    "etag": "…",
    "writable": true,
    "maxBytes": 20971520,
    "upload": { "allowed": true, "maxBytes": 26214400 }
  }
}
  • extensions: Announces supported host capabilities, including "conditional" (conditional saves and save receipts), "format" (formathtml="true" support), "sync" (tab live sync), "upload" (attachment uploads), "live-data", and "live-provenance".
  • document: Included only when Document-URL (or Page-URL) names an existing file. If no header is sent or the named document does not exist, the document key is omitted.
  • document.saveId: Included when the current bytes on disk were written by a save that carried a Save-ID header (see Saving and stale-write protection).
  • document.people.me: Included when Use my profile in files is turned on under Options then Profile…, returning your Hyperclay account profile (cached for offline use) or your local display name. This field is answered only to requests from the folder’s own origin (see Settings and profile).

POST /_/upload#

POST /_/upload stores an attachment file in the folder’s uploads/ directory instead of embedding it as a data: URL inside the HTML document. Send a multipart/form-data request with one part named file and a Document-URL header:

Shell
curl -X POST http://localhost:4321/_/upload \
  -H 'Document-URL: http://localhost:4321/index.html' \
  -F 'file=@note.txt'
JSON
{
  "msg": "Uploaded",
  "msgType": "success",
  "uploads": [
    {
      "name": "note-2cf24d.txt",
      "url": "/_/uploads/assets-index/note-2cf24d.txt",
      "bytes": 5
    }
  ]
}

Where uploads are stored and linked#

  • Directory layout: Files are stored in uploads/assets-<document stem>/ inside the served folder and linked as /_/uploads/assets-<document stem>/<filename>, matching the layout used on hyperclay.com so a synced folder stays byte-identical on both sides and moving a document does not strand its files. Uploads into a folder with no document land in that folder’s uploads/assets-<stem>/ directory and keep their /_/uploads/ link.
  • Content-addressed filenames: The stored filename is <stem>-<first 6 hex of the sha256 of the bytes><ext>. Uploading identical bytes converges on the same file, while different bytes never collide (the hash prefix lengthens automatically if a 6-character prefix would collide). Characters that Windows cannot store (< > : " | ? * and control characters) are stripped from upload names so filenames work across macOS, Windows, Linux, and hyperclay.com.
  • URL encoding and serving: url in the JSON response is percent-encoded for every byte outside the unreserved set and can be placed directly into src or href. The /_/uploads/ route serves only files inside the real uploads/ folder (refusing symlinks out of the folder) and sends X-Content-Type-Options: nosniff on every response.
  • Zip export: When you export a document with Export a File as Zip…, /_/uploads/ links are rewritten to relative uploads/… paths and packaged alongside the document (see Export as zip).

Limits, refused file types, and error codes#

  • Maximum file size: 26214400 bytes (25 MB). A file larger than 25 MB is refused with 413 and "code":"too-large". (When cloud sync is enabled, attachments larger than your hyperclay.com plan’s per-file cap are still saved locally and served on localhost, but stay on your computer until your plan limit allows them; see What syncs.)
  • Refused extensions: Web-page and executable script types are refused: .html, .htm, .xhtml, .htmlclay, .js, .mjs, .cjs, .xml, .xht, .xsl, and .xslt. Uploading any of these returns 415:
    JSON
    {"msg":"That kind of file cannot be uploaded.","msgType":"error","code":"unsupported-type"}
    
    If a web-page file type is placed inside uploads/ on disk by hand, /_/uploads/ serves it as a download with nosniff so it cannot execute script on the app’s origin.
  • SVG files: .svg and .svgz files are allowed because /_/uploads/ and the static file server serve them inert with Content-Disposition: attachment and X-Content-Type-Options: nosniff.
  • Target document check: When Document-URL names a document path, that document must already exist; otherwise POST /_/upload returns 404 with "code":"not-found".
  • Error code values: bad-request, forbidden, not-found, conflict, too-large, and unsupported-type.