All notable changes to Storehouse are documented in this file.
The format follows Keep a Changelog, and Storehouse follows Semantic Versioning.
[Unreleased]
[0.1.0]
The first release: the storage of Kotoba and Hakushi, taken out of them.
Added
Storehouse.store/2: a file checked by its bytes and stored under a new, safe key, as aStorehouse.File, with:accept,:max_bytes,:max_pixels,:keyand:preview.Storehouse.Check: the type of a file from its bytes (PNG, JPEG, GIF and WebP images with their width and height, a JPEG's turned as its EXIF says; PDF; MP4 and WebM video; ZIP and Office documents; plain text), and every other file asapplication/octet-stream.Storehouse.Adapter, the behaviour of a store (Kotoba's and Hakushi's callbacks),Storehouse.LocalandStorehouse.Local.Plug, which serves files with their checked type, safe headers and byte ranges.Storehouse.fetch/2: a file from an address of the hosts an app allows, with redirects checked and the download stopped at:max_bytes.Storehouse.S3: Amazon S3, and the stores that speak its API (Cloudflare R2, MinIO, Tigris, LocalStack), with no other library: it signs its requests itself (Signature Version 4).- Direct uploads:
Storehouse.presign_upload/4signs an upload the browser makes straight to the store (its key, type and size), andStorehouse.verify_upload/2checks the file there by its first bytes, and deletes it when it is not what it said.Storehouse.Live.allow/3does both for a LiveView upload, with the uploader ofstorehouse.js.Storehouse.Local.Plugtakes direct uploads too, for development. - Private files:
Storehouse.signed_url/2, from S3 or the local plug (private: trueserves only signed URLs), andStorehouse.Redirect, a lasting URL that checks the person and redirects to a signed one. Storehouse.Live.consume/3: the files of a LiveView upload, each stored once, with a result for each.- Streamed uploads:
Storehouse.Live.allow/3withmode: :streamsends a file through the LiveView and on to the store as each chunk comes (Storehouse.Live.Writer), with no file on the app's disk: to S3 in the parts of a multipart upload, each with its checksum, two in flight from a process of their own, the upload held back when they are; its first bytes checked on the way. The optional adapter callbacksstream_open/2,stream_write/2,stream_close/1andstream_abort/1(Storehouse.S3,Storehouse.Local). - Temporary, then permanent:
cache: truestores a file under the temporary prefix (Storehouse.cache_prefix/0), andStorehouse.promote/2makes it permanent with a copy in the store (the optional adapter callbackcopy/2: S3's CopyObject, the local disk's copy). Storehouse.Ecto: files in a record's columns (Storehouse.Ecto.File, or a list of them), put withput_file/4, checked against the field's limits, made permanent in the save's transaction, and, withupdate/3anddelete/3, deleted from the store once the record no longer has them.- Checksums: each
Storehouse.Filehas the SHA-256 of its bytes (checksum, Base64), sent to S3 with the file (x-amz-checksum-sha256), which checks and keeps it;Storehouse.checksum/1gives it of a copy, and the optional adapter callbackchecksum/1gives a stored file's.
file or the reason a file was refused.Telemetry: `[:storehouse, :store :fetch :presign_upload :verify_upload :delete, :start :stop :exception]` spans, with the - Keys (
Storehouse.key/2,safe_name/2,valid_key?/1), display names (clean_name/1) andsafe_url?/1.