wisewigdocs

Assets

R2AssetStore is the Cloudflare reference adapter for images, videos, and downloadable files. It allocates opaque, tenant-and-site-scoped R2 keys and applies a separate MIME allowlist, byte ceiling, signature check, and delivery policy to each kind.

KindAccepted typesMaximumDelivery
ImageAVIF, JPEG, PNG, WebP10 MiBInline immutable original; bounded Image Resizing URLs are optional
VideoMP4, WebM100 MiBInline immutable object suitable for progressive browser playback
DownloadPDF, UTF-8 plain text, CSV25 MiBImmutable object with Content-Disposition: attachment and a sanitized filename

The metering transform checks the actual streamed byte count and the declared format’s identifying bytes before R2 accepts an object; disguised files fail closed. File names containing control characters are rejected, and the response fallback filename is sanitized before it reaches R2 metadata. HTML, SVG, JavaScript, arbitrary binaries, executables, ZIP archives, and Office ZIP containers are not accepted.

The upload URL returned by createUpload() is an authenticated Worker-route identifier, not a bearer-signed R2 URL. Morning Bell’s /api/media route authenticates the caller, authorizes media.manage for the hostname-derived site, allocates the key, creates an uploading tenant-workspace record, and streams the request to R2. A validation failure moves the record to quarantined; only ready records appear in the picker.

R2 objects receive immutable public cache headers plus tenant/site/kind metadata. An object key from another tenant is rejected before it can be written or exposed. imageDeliveryUrl() creates bounded same-site Cloudflare Image Resizing URLs while content continues to reference the immutable original. The editor filters the same ready-asset library for hero images, video sections, and download sections. Deletion checks draft and published hero images, video sources/posters, downloadable files, and settings logos; it deletes R2 first, then tombstones metadata. In-use assets are rejected.

This implementation provides allowlisting, signature validation, bounded streaming, and quarantine, not an antivirus claim. A hosted installation that expands the file allowlist must add an external malware scanner before promoting higher-risk uploads to ready.

R2 video support is intentionally simple progressive delivery. Adaptive bitrate encoding, generated posters, captions, playback analytics, and long-form video processing would require a video adapter such as Cloudflare Stream; they are not implied by the MP4/WebM component.

External video embeds

The video component also accepts a YouTube watch/share URL or copied iframe snippet. parseVideoEmbed() extracts an allowlisted YouTube video ID and accessible title; the raw HTML, pasted host, dimensions, scripts, and query parameters are discarded. Documents persist only the typed { provider: "youtube", videoId, title } record. The Astro renderer constructs its own lazy, sandboxed youtube-nocookie.com iframe without autoplay or JavaScript API parameters.

This is not a general arbitrary-embed escape hatch. HTTP URLs, lookalike domains, malformed IDs, script tags, and unsupported providers fail schema validation. Additional providers require a framework parser, schema member, renderer, and security tests rather than an editor-controlled iframe URL.