PhoenixKit.Integrations.ObjectStorageServices (phoenix_kit v2.52.2)

Copy Markdown View Source

The service-by-service setup form of the object_storage integration.

"S3-compatible" is a protocol, not a place to connect to: the same access key and secret reach Amazon S3, Cloudflare R2, Backblaze B2, Tigris, Wasabi, DigitalOcean Spaces and a self-hosted MinIO, but what else the form must ask differs for each (a region you pick, an account id the endpoint is built from, nothing at all), and what the endpoint is differs too. The form therefore opens on a choice of service and shows only the fields that service needs.

What is stored does not change: access_key, secret_key, region and endpoint (everything that reads a connection — the validator, a bucket — keeps reading those four). The form works out region and endpoint from what the service asks: a Backblaze region becomes s3.<region>.backblazeb2.com, an R2 account id becomes <account>.r2.cloudflarestorage.com. Three more keys remember what was chosen so an edit shows it again: service, account_id and jurisdiction.

A connection saved before the choice existed has no service; current/1 infers it from the endpoint, so an old Backblaze connection opens as Backblaze and nothing has to be migrated.

This module is the provider's :setup_module: PhoenixKit.Integrations.Providers calls fields/1, attrs/1, changed/2 and saved/2, and the two integration forms go through those, so the admin and the personal form cannot drift.

Summary

Functions

The keys to store for a submitted form: the service and what it asked, with region and endpoint worked out. Every service-specific key is present (blank when the service does not use it), so switching a connection's service leaves nothing of the old one behind. A blank secret is left out, which means "keep the one already saved".

The Storage.Bucket provider a bucket on this service is created as. A service the bucket has no provider of its own for is an S3 bucket with an endpoint.

The typed values once incoming (the form as it was just sent) arrives over previous. Changing the service drops what the old one asked — a region of one provider is not a region of the next — and keeps the keys, which are the same shape everywhere. Decided by comparing the service, not by which input fired, so it holds however the change event was made.

The service a set of values (typed, or saved) is for: the chosen one, else — for a connection saved before the choice existed — the one its endpoint belongs to, else nil (a brand-new form, with nothing chosen yet).

The fields to show for the values typed so far. The first is always the service; the forms send their full values on change, and the rest follow from it.

The service an endpoint host belongs to (other for one nobody knows).

The name of the service a connection is for (Tigris, Cloudflare R2, …), nil for one with nothing saved yet. For the lists, where the provider's own name ("Object Storage (S3-compatible)") is the same for all of them.

A service's name.

The saved values the form may show next to the typed ones. A connection being switched to another service shows none of the old service's region, endpoint or account (they would be rendered as if they belonged to the new one).

The service keys, in the order the form lists them.

Types

values()

@type values() :: %{optional(String.t()) => term()}

Functions

attrs(params)

@spec attrs(values()) :: %{required(String.t()) => String.t()}

The keys to store for a submitted form: the service and what it asked, with region and endpoint worked out. Every service-specific key is present (blank when the service does not use it), so switching a connection's service leaves nothing of the old one behind. A blank secret is left out, which means "keep the one already saved".

bucket_provider(arg1)

@spec bucket_provider(String.t() | nil) :: String.t()

The Storage.Bucket provider a bucket on this service is created as. A service the bucket has no provider of its own for is an S3 bucket with an endpoint.

changed(previous, incoming)

@spec changed(values(), values()) :: values()

The typed values once incoming (the form as it was just sent) arrives over previous. Changing the service drops what the old one asked — a region of one provider is not a region of the next — and keeps the keys, which are the same shape everywhere. Decided by comparing the service, not by which input fired, so it holds however the change event was made.

current(values)

@spec current(values()) :: String.t() | nil

The service a set of values (typed, or saved) is for: the chosen one, else — for a connection saved before the choice existed — the one its endpoint belongs to, else nil (a brand-new form, with nothing chosen yet).

fields(values)

@spec fields(values()) :: [map()]

The fields to show for the values typed so far. The first is always the service; the forms send their full values on change, and the rest follow from it.

infer(endpoint)

@spec infer(String.t()) :: String.t()

The service an endpoint host belongs to (other for one nobody knows).

label(data)

@spec label(values()) :: String.t() | nil

The name of the service a connection is for (Tigris, Cloudflare R2, …), nil for one with nothing saved yet. For the lists, where the provider's own name ("Object Storage (S3-compatible)") is the same for all of them.

name(binary)

@spec name(String.t()) :: String.t()

A service's name.

saved(data, typed)

@spec saved(values(), values()) :: values()

The saved values the form may show next to the typed ones. A connection being switched to another service shows none of the old service's region, endpoint or account (they would be rendered as if they belonged to the new one).

service_keys()

@spec service_keys() :: [String.t()]

The service keys, in the order the form lists them.