Storage behaviour used to publish, read, list and delete sitemap files.
An adapter is configured as a {module, opts} tuple. Keys are always relative
to the adapter root (a directory, a bucket prefix, ...), use / as separator
and never start with /.
Built-in adapters:
SiteMaps.Adapters.FileSystem- local disk and network mounts (NFS, EFS, SMB)SiteMaps.Adapters.S3- AWS S3 and S3-compatible stores (MinIO, Spaces, Wasabi, Ceph)SiteMaps.Adapters.R2- Cloudflare R2SiteMaps.Adapters.Memory- in-memory storage for testsSiteMaps.Adapters.Noop- discards every write (dry runs)
read/2 returns the raw stored bytes, so a .gz key comes back gzipped.
A missing key is always reported as {:error, :not_found} and deleting a
missing key is :ok. last_modified is kept with second precision by every
adapter.
Every adapter rejects keys failing validate_key/1 with {:error, :invalid_key}.
Summary
Functions
Content type derived from the key extension.
Deletes key. Deleting a missing key is :ok.
Lists the keys starting with prefix, sorted.
Reads the raw bytes stored under key.
Checks that key is a relative path without empty, . or .. segments,
segments named like a temporary file (.<name>.tmp), whitespace, control
characters or the URL-sensitive characters ?, # and %.
Stores source under key.
Types
@type key() :: String.t()
@type opts() :: keyword()
@type read_meta() :: %{ content_type: String.t() | nil, last_modified: DateTime.t() | nil }
@type write_meta() :: %{ optional(:content_type) => String.t(), optional(:cache_control) => String.t() | nil, optional(:last_modified) => DateTime.t() | nil }
Callbacks
Functions
Content type derived from the key extension.
iex> SiteMaps.Adapter.content_type("posts/sitemap1.xml.gz")
"application/gzip"
iex> SiteMaps.Adapter.content_type("sitemap.xml")
"application/xml"
Deletes key. Deleting a missing key is :ok.
Lists the keys starting with prefix, sorted.
Reads the raw bytes stored under key.
@spec validate_key(term()) :: :ok | {:error, :invalid_key}
Checks that key is a relative path without empty, . or .. segments,
segments named like a temporary file (.<name>.tmp), whitespace, control
characters or the URL-sensitive characters ?, # and %.
iex> SiteMaps.Adapter.validate_key("posts/sitemap1.xml")
:ok
iex> SiteMaps.Adapter.validate_key("/sitemap.xml")
{:error, :invalid_key}
iex> SiteMaps.Adapter.validate_key("sitemap.xml?v=1")
{:error, :invalid_key}
@spec write(t(), key(), source(), write_meta()) :: :ok | {:error, term()}
Stores source under key.