Lucerna (Lucerna v0.0.1-alpha.0)
Lucerna SDK for Elixir — feature gates, experiments and identity.
Add one child to your supervision tree:
children = [
{Lucerna, server_key: System.fetch_env!("LUCERNA_SERVER_KEY")}
]then read anywhere — no process on the hot path, reads never raise:
identity = Lucerna.Identity.new!(user_id: "u_42", email: "sofia@acme.com")
Lucerna.Gates.flag("settings_sso", identity) #=> true / false
Lucerna.Gates.experiment("checkout_copy", identity) #=> "urgent" / nil
Lucerna.Gates.switch("checkout") #=> false means killed
Lucerna.identify(identity) # self-sync to People — the only call
# that transmits email/nameThe tree is: a Finch pool (unless you inject your own transport), the
ETS snapshot Lucerna.Gates.Store, and the Lucerna.Gates.Sync
poller. Sync fetches the compiled runtime at boot and every
refresh_interval (default 10s); fetch failures serve the stale
snapshot — never "off". See Lucerna.Config for every option.
Multiple isolated instances: give each a :name and pass
name: MyName to reads.
Summary
Functions
Delivers queued events (experiment exposures) now instead of on the
refresh cadence — for scripts and tests; a running app never needs it.
Always :ok, even when the instance isn't running.
Sends an identity to People — the self-sync, and the only path
that transmits email/name (gates reads never transmit anything).
Accepts a Lucerna.Identity, map, or keyword list; unlike gates
reads this validates strictly — a bad or missing identity is a
programming error and raises ArgumentError.
Starts a Lucerna instance. Options are validated here —
see Lucerna.Config.new!/1; bad options raise at boot, never later.
Functions
@spec flush(keyword()) :: :ok
Delivers queued events (experiment exposures) now instead of on the
refresh cadence — for scripts and tests; a running app never needs it.
Always :ok, even when the instance isn't running.
@spec identify( Lucerna.Identity.t() | map() | keyword(), keyword() ) :: :ok
Sends an identity to People — the self-sync, and the only path
that transmits email/name (gates reads never transmit anything).
Accepts a Lucerna.Identity, map, or keyword list; unlike gates
reads this validates strictly — a bad or missing identity is a
programming error and raises ArgumentError.
Delivery is async and fire-and-forget through Lucerna.Reporting
under :identity_key (defaults to :server_key): one attempt, no
retry — the server upserts idempotently, so the next identify is
the retry. An exact resend of the last delivered payload is skipped.
Lucerna.flush/1 returns only after every identify queued before it
has been attempted.
@spec start_link(keyword()) :: Supervisor.on_start()
Starts a Lucerna instance. Options are validated here —
see Lucerna.Config.new!/1; bad options raise at boot, never later.