# Storehouse v0.2.0 - Table of Contents > Files for Phoenix: uploads checked by their bytes, stored under safe keys on the local disk or in a store of your own, and served safely. ## Pages - [Storehouse](readme.md) - [Stores](stores.md) - [Serving](serving.md) - [LiveView](liveview.md) - [Direct uploads](direct_uploads.md) - [Uploads from any client](any_client.md) - [Private files](private_files.md) - [Ecto](ecto.md) - [After the upload](analysis.md) - [Variants](variants.md) - [Work out of the request](background.md) - [Features](features.md) - [Changelog](changelog.md) ## Modules - [Storehouse.Metadata](Storehouse.Metadata.md): A file's own metadata (`Storehouse.File`'s `:metadata`): a map the app keeps with the file, in its record's column and in the JSON it sends, of what a person entered (a caption, a credit, a description for readers who cannot see it) and what the app decided. - Files - [Storehouse](Storehouse.md): Files for Phoenix: a file checked by its bytes (`Storehouse.Check`), stored under a new, safe key through a store of the app's (`Storehouse.Adapter`: the local disk, S3, …), and served safely (`Storehouse.Local.Plug`). - [Storehouse.Check](Storehouse.Check.md): The type of a file, from its bytes. - [Storehouse.File](Storehouse.File.md): A stored file: what `Storehouse.store/2` gives, and what an app keeps in its records (or a document's data) to show and serve it again. - [Storehouse.ReadError](Storehouse.ReadError.md): Raised while a stream of `Storehouse.stream/2` is taken, when the store fails to give the next chunk: its `:key`, and the store's `:reason`. - Archives - [Storehouse.Archive](Storehouse.Archive.md): An archive of files, stored ones and the app's own, made as a stream: an export of an account's files, a folder to download, a backup. Nothing is written to the disk and no more than a chunk is in memory, however large the archive. - [Storehouse.Archive.Entry](Storehouse.Archive.Entry.md): A file of an archive, as a format (`Storehouse.Archive.Format`) is given it - [Storehouse.Archive.Format](Storehouse.Archive.Format.md): A format of archive (`Storehouse.Archive`): zip (`Storehouse.Archive.Zip`, the default), tar (`Storehouse.Archive.Tar`), or one of the app's. - [Storehouse.Archive.Tar](Storehouse.Archive.Tar.md): The tar format of `Storehouse.Archive`: for Unix tools and backups, gzipped (`.tar.gz`) or not, made as a stream. - [Storehouse.Archive.Zip](Storehouse.Archive.Zip.md): The zip format of `Storehouse.Archive`, its default: opened by every system, as it is made, with nothing on the disk. - Stores - [Storehouse.Adapter](Storehouse.Adapter.md): A store of files: the local disk (`Storehouse.Local`), S3, another object store, a database. Name it in the config - [Storehouse.Local](Storehouse.Local.md): A `Storehouse.Adapter` that keeps files in a directory on the local disk. - [Storehouse.Local.Plug](Storehouse.Local.Plug.md): Serves the files of `Storehouse.Local`, and takes the ones a browser uploads straight to it, when the store signed the upload. - [Storehouse.Mirror](Storehouse.Mirror.md): A store that keeps its files in a primary store and copies them to others, its mirrors: to move to another provider without stopping (new files go to both, the old ones are copied, then the app reads from the new one), or to keep a second copy in another provider or region. - [Storehouse.S3](Storehouse.S3.md): A `Storehouse.Adapter` for Amazon S3, and the stores that speak its API: Cloudflare R2, MinIO, Tigris, Backblaze B2, DigitalOcean Spaces, Google Cloud Storage's interoperability. With no dependency: it signs its requests itself (AWS Signature Version 4). - Analysis - [Storehouse.Analysis](Storehouse.Analysis.md): What an analysis step (`Storehouse.Analyzer`) made of a file, kept in the file's `:analysis`, by the step's name - [Storehouse.Analyzer](Storehouse.Analyzer.md): Work on a file after it is stored: what it is read for (an image's EXIF, a placeholder, a video's length, a PDF's pages), each step an analyzer, what it made of the file kept in the file's `:analysis`, by its name, as a `Storehouse.Analysis`: its status, its result, why it failed. - [Storehouse.Analyzer.BlurHash](Storehouse.Analyzer.BlurHash.md): A step (`Storehouse.Analyzer`) that makes a photograph's [BlurHash](https://blurha.sh) (`Storehouse.Image.BlurHash`), under `"blurhash"`: a string of 20 to 30 characters, kept with the file, that a page decodes into a blur. - [Storehouse.Analyzer.EditMetadata](Storehouse.Analyzer.EditMetadata.md): A step (`Storehouse.Analyzer`) that edits the metadata inside a stored file without re-encoding it, and writes the edited file back over the original, under `"edit_metadata"`. - [Storehouse.Analyzer.Placeholder](Storehouse.Analyzer.Placeholder.md): A step (`Storehouse.Analyzer`) that makes what a page shows while a photograph loads, under `"placeholder"` - [Storehouse.Analyzer.Size](Storehouse.Analyzer.Size.md): A step (`Storehouse.Analyzer`) that asks the store the file's size and type as stored, without reading it: `%{"bytes" => …, "content_type" => …}`, under `"size"`. For a file uploaded straight to the store, whose size was what the browser said until then. - [Storehouse.Analyzer.ThumbHash](Storehouse.Analyzer.ThumbHash.md): A step (`Storehouse.Analyzer`) that makes a photograph's [ThumbHash](https://evanw.github.io/thumbhash/) (`Storehouse.Image.ThumbHash`), under `"thumbhash"`: about 25 bytes, kept with the file, that a page decodes into a blur of its colours, proportions and transparency. - Images - [Storehouse.Image.BlurHash](Storehouse.Image.BlurHash.md): [BlurHash](https://blurha.sh): an image's placeholder as a short string, 20 to 30 characters, for a page to decode into a blur (`blurhash` on npm, and ports in most languages). The same string as its reference implementation, from the image's pixels: `Storehouse.Analyzer.BlurHash` gives it from a stored file. - [Storehouse.Image.JPEG](Storehouse.Image.JPEG.md): Edits the metadata inside a JPEG without re-encoding it: removes where a photo was taken, keeps only a few tags, or writes an author's name, and never touches the image's data. - [Storehouse.Image.MetadataEditor](Storehouse.Image.MetadataEditor.md): What edits the metadata inside a stored file for the `Storehouse.Analyzer.EditMetadata` step: Storehouse's own (`Storehouse.Image.MetadataEditor.Builtin`, in Elixir, for JPEG, PNG and WebP), or one of the app's, around ExifTool, a NIF, a service. - [Storehouse.Image.MetadataEditor.Builtin](Storehouse.Image.MetadataEditor.Builtin.md): Storehouse's own metadata editor (`Storehouse.Image.MetadataEditor`), in Elixir, with no dependency: JPEG (`Storehouse.Image.JPEG`), PNG (`Storehouse.Image.PNG`) and WebP (`Storehouse.Image.WebP`), each reading only a file's metadata into memory and copying its image data from file to file. Other types (HEIC, AVIF, TIFF, a camera's raw files) are `:unsupported`: an editor around ExifTool edits those. - [Storehouse.Image.PNG](Storehouse.Image.PNG.md): Edits the metadata inside a PNG without re-encoding it, as `Storehouse.Image.JPEG` does a JPEG's: the same changes, the same tags. - [Storehouse.Image.ThumbHash](Storehouse.Image.ThumbHash.md): [ThumbHash](https://evanw.github.io/thumbhash/): an image's placeholder in about 25 bytes, its colours, its proportions and its transparency, for a page to decode into a blur (`thumbhash` on npm, and ports in most languages). The same bytes as its reference implementation, from the image's pixels: `Storehouse.Analyzer.ThumbHash` gives them from a stored file. - [Storehouse.Image.WebP](Storehouse.Image.WebP.md): Edits the metadata inside a WebP without re-encoding it, as `Storehouse.Image.JPEG` does a JPEG's: the same changes, the same tags. - Variants - [Storehouse.Analyzer.Warm](Storehouse.Analyzer.Warm.md): A step (`Storehouse.Analyzer`) that makes an image's sizes before a visitor asks for them (`Storehouse.Responsive.warm/3`), under `"warm"`: for an app that runs its steps out of the request already (`Storehouse.analyze_later/3`), on a queue of their own. - [Storehouse.Components](Storehouse.Components.md): Function components for HEEx, from `Storehouse.Responsive`'s data. - [Storehouse.Renderer](Storehouse.Renderer.md): What makes a file's variants (`Storehouse.Variants`), or the URLs of the service that makes them. A renderer does one or both - [Storehouse.Renderer.Imgproxy](Storehouse.Renderer.Imgproxy.md): The URLs of variants [imgproxy](https://imgproxy.net) renders (`Storehouse.Renderer`): signed, so only the presets' sizes are ever rendered, and the same every time, for a CDN in front of it to keep. The app renders nothing, and stores nothing. - [Storehouse.Renderer.Vix](Storehouse.Renderer.Vix.md): Renders variants in the app, with libvips through Vix (`Storehouse.Renderer`): the default renderer when Vix is loaded. - [Storehouse.Responsive](Storehouse.Responsive.md): What a page needs to show a photograph at every screen's size, from a preset of variants with a ladder of widths (`Storehouse.Variants`): its `src`, its `srcset`, its size, its placeholder. As data, for a JSON API, or as an `` (`Storehouse.Components.img/1`). - [Storehouse.Variant](Storehouse.Variant.md): One size of a file, in one format, as a preset makes it: what a renderer (`Storehouse.Renderer`) is given to render it, or to build its URL. - [Storehouse.Variants](Storehouse.Variants.md): A file's other sizes and formats, by preset: a photograph's thumbnail, its sizes for a `srcset`, its WebP. Only the presets' sizes are ever made, so no one can have the server render at a size they choose. - [Storehouse.Variants.Plug](Storehouse.Variants.Plug.md): Serves variants (`Storehouse.Variants`) at the URLs `Storehouse.variant_url/3` gives, making each the first time it is asked for: `GET //--`. - Work out of the request - [Storehouse.Job](Storehouse.Job.md): A piece of Storehouse's work done out of the request: a file's analysis, a deletion, a mirror's copy. A runner keeps it and runs it (`Storehouse.Runner`). - [Storehouse.Runner](Storehouse.Runner.md): What keeps and runs Storehouse's work out of the request (`Storehouse.Job`): files analyzed later (`Storehouse.analyze_later/3`), deleted later (`Storehouse.delete_later/2`), copied to a mirror (`Storehouse.Mirror`). One runner does all of it, and another takes its place with no other change. - [Storehouse.Runner.Memory](Storehouse.Runner.Memory.md): A runner (`Storehouse.Runner`) in a process of the app's: each job run beside the app's requests, and when it fails, again after a while (a second, then twice as long each time, up to five minutes), up to its `:max_attempts`. Then it is given up (`Storehouse.Job.discarded/3`). - [Storehouse.Runner.Oban](Storehouse.Runner.Oban.md): A runner (`Storehouse.Runner`) in Oban: each job an Oban job (`Storehouse.Runner.Oban.Worker`), kept in the app's database, so it outlives a deploy, and retried with Oban's backoff, up to the job's `:max_attempts`. A job waiting is not inserted twice (Oban's `unique`). - [Storehouse.Runner.Oban.Worker](Storehouse.Runner.Oban.Worker.md): The Oban worker of `Storehouse.Runner.Oban`: a job's map (`Storehouse.Job.to_map/1`) as its arguments, run with `Storehouse.Job.run/1`, retried by Oban when it fails. - Cleanup - [Storehouse.Sweeper](Storehouse.Sweeper.md): Sweeps, every `:every` seconds, on a store with no lifecycle rule (the local disk, MinIO) - Events - [Storehouse.Notify](Storehouse.Notify.md): What happens to files, told to the app as it happens: a file stored, its analysis done or a step of it failed, a file deleted. For a page that shows the files to everyone who has it open, as their analysis comes in. - [Storehouse.Notify.PubSub](Storehouse.Notify.PubSub.md): Broadcasts what happens to files (`Storehouse.Notify`) on the app's `Phoenix.PubSub`, as `{:storehouse, event, info}`. - Tests - [Storehouse.Memory](Storehouse.Memory.md): A `Storehouse.Adapter` that keeps files in memory, for tests: every callback, the optional ones too, with no disk, no bucket and no container, and each test's files its own, as Ecto's sandbox keeps each test's rows. - [Storehouse.Test](Storehouse.Test.md): Assertions on the files a test stored, with `Storehouse.Memory` - Private files - [Storehouse.Proxy](Storehouse.Proxy.md): A file of the store sent through the app: it checks that the person may see it, then streams it from the store, a part at a time, so that the bucket's address never leaves the app and a CDN in front keeps what it may. The sibling of `Storehouse.Redirect`, which sends the person to a signed URL instead. - [Storehouse.Redirect](Storehouse.Redirect.md): A lasting URL of your app for a file that is not public: it checks that the person may see the file, then redirects to a URL the store signs for a few minutes (`Storehouse.signed_url/2`). Keep this URL in your records and documents, not the signed one, which expires. - A CDN in front - [Storehouse.Purge](Storehouse.Purge.md): What a CDN in front forgets when a file is deleted: the file's URLs, its variants' (`Storehouse.Variants`), and its cache tag. Keys are never reused, so a file kept for a year never changes; it only goes, and a CDN would go on serving it. A purger tells the CDN. - [Storehouse.Purge.Cloudflare](Storehouse.Purge.Cloudflare.md): A purger (`Storehouse.Purge`) for Cloudflare's cache: a zone's `purge_cache`, with an API token that may purge it. - Resumable uploads (tus) - [Storehouse.Tus](Storehouse.Tus.md): The uploads in progress of `Storehouse.Tus.Plug`: their state, kept in ETS by this process, and those that expired, given up every `:sweep_every` seconds (their parts deleted from the store). - [Storehouse.Tus.Plug](Storehouse.Tus.Plug.md): Resumable uploads through the app, by the [tus](https://tus.io) protocol (1.0.0): for clients that speak it (Uppy's Tus plugin, tus-js-client, the mobile and desktop clients), and for stores the browser cannot send to straight (the local disk). A connection lost halfway carries on from the last byte the app has. - [Storehouse.Tus.State](Storehouse.Tus.State.md): Where `Storehouse.Tus.Plug` keeps each upload between requests: its key, size, offset, metadata and, on a store of multipart uploads, its parts and the bytes not yet a part. `Storehouse.Tus.State.ETS` is the default, one node's. - [Storehouse.Tus.State.ETS](Storehouse.Tus.State.ETS.md): `Storehouse.Tus.State` in ETS, in the table of the `Storehouse.Tus` process, which the app starts: one node's. - Any client - [Storehouse.Batch](Storehouse.Batch.md): Uploads straight to the store, many at a time: what a frontend that is not a LiveView (React, Vue, a native app) asks of the app around the browser's `PUT`s. `presign/2` signs a batch, `register/2` checks the files once they are there. `Storehouse.Plug.Presign` and `Storehouse.Plug.Register` answer them in JSON. - [Storehouse.Plug.Multipart](Storehouse.Plug.Multipart.md): Very large files sent from the browser straight to the store in parts (`Storehouse.presign_multipart/4`), for the JavaScript client or a frontend of the app's own: JSON endpoints beside `Storehouse.Plug.Presign`. - [Storehouse.Plug.Presign](Storehouse.Plug.Presign.md): Signs uploads straight to the store for a frontend that is not a LiveView: a JSON endpoint in front of `Storehouse.Batch.presign/2`. - [Storehouse.Plug.Register](Storehouse.Plug.Register.md): Checks the files a browser uploaded straight to the store, signed by `Storehouse.Plug.Presign`, and gives them to the app: a JSON endpoint in front of `Storehouse.Batch.register/2`. - LiveView - [Storehouse.Live](Storehouse.Live.md): The files of a LiveView upload, stored. - [Storehouse.Live.Writer](Storehouse.Live.Writer.md): A LiveView upload writer (`Phoenix.LiveView.UploadWriter`) that streams each chunk on to the store as it comes, with no file on the app's disk: to S3 in the parts of a multipart upload, to the local disk in its place. `Storehouse.Live.allow/3` with `mode: :stream` gives it to the upload. - Ecto - [Storehouse.Ecto](Storehouse.Ecto.md): Files in records, with Ecto: a column of type `Storehouse.Ecto.File` (or a list of them), files put in a changeset with `put_file/4`, made permanent when the record is saved, and deleted once nothing has them. - [Storehouse.Ecto.File](Storehouse.Ecto.File.md): An Ecto type for a stored file (`Storehouse.File`) in a record's column: a map (`jsonb` in PostgreSQL) of its key, URL, name, type, size, checksum, width, height, metadata (`Storehouse.Metadata`) and analysis (`Storehouse.Analysis`, each step's as `Storehouse.Analysis.to_map/1`). No table of files: the record has its file. - A library of files - [Storehouse.Ecto.Blob](Storehouse.Ecto.Blob.md): A library of files: a row a file, owned by someone (an account, a site), referenced from many records, kept when the record that first used it is deleted. Its tables are `Storehouse.Ecto.Migrations`'s; which records use each file is `Storehouse.Ecto.Usage`'s. - [Storehouse.Ecto.Blob.Schema](Storehouse.Ecto.Blob.Schema.md): A blob schema of the app's own (`Storehouse.Ecto.Blob`): its primary key a UUID, its timestamps in microseconds, its usage table, and `fields/0` in its `schema` block. - [Storehouse.Ecto.Migrations](Storehouse.Ecto.Migrations.md): The tables of a library of files (`Storehouse.Ecto.Blob`, `Storehouse.Ecto.Usage`), for a migration of the app's - [Storehouse.Ecto.Usage](Storehouse.Ecto.Usage.md): Which records use each file of a library (`Storehouse.Ecto.Blob`): kept as the records change, so the library can say what each file is used by, and refuse to delete one that is used. ## Mix Tasks - [mix storehouse.copy](Mix.Tasks.Storehouse.Copy.md): Copies the files of one store to another (`Storehouse.copy_prefix/2`), with its progress: to move to another provider, fill a mirror (`Storehouse.Mirror`), or bring a production account's files into development. - [mix storehouse.reprocess](Mix.Tasks.Storehouse.Reprocess.md): Runs analysis steps over the files of a field in every record of a schema (`Storehouse.Ecto.reprocess/5`), with its progress: a step added after files were stored, files from before analysis existed.