Current section

Files

Jump to
Raw

README.md

<div align="center">
# ๐Ÿงฉ MishkaInstaller
**A runtime plugin / event engine and pre-built library installer for Elixir.** โœจ
[![Hex.pm](https://img.shields.io/hexpm/v/mishka_installer.svg?style=flat-square)](https://hex.pm/packages/mishka_installer)
[![Hex Downloads](https://img.shields.io/hexpm/dt/mishka_installer.svg?style=flat-square)](https://hex.pm/packages/mishka_installer)
[![CI](https://img.shields.io/github/actions/workflow/status/mishka-group/mishka_installer/ci.yml?style=flat-square)](https://github.com/mishka-group/mishka_installer/actions/workflows/ci.yml)
[![License](https://img.shields.io/hexpm/l/mishka_installer.svg?style=flat-square)](https://github.com/mishka-group/mishka_installer/blob/master/LICENSE)
[![GitHub Sponsors](https://img.shields.io/badge/Sponsor-mishka--group-ea4aaa?style=flat-square&logo=github)](https://github.com/sponsors/mishka-group)
[![Buy Me a Coffee](https://img.shields.io/badge/Buy_Me_a_Coffee-mishkagroup-ffdd00?style=flat-square&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/mishkagroup)
</div>
---
> [!WARNING]
> **๐Ÿ”ง Low maintenance.** The author currently only responds to pull requests. Don't use `master`; the current release line is `0.1.7`.
---
## ๐Ÿ’ญ Why?
Build apps whose features are **activated as plugins at runtime** โ€” registration, SMS, social login โ€” **without touching the core source**. Each feature becomes an **event**; anyone can attach plugins to it from outside your app.
---
## โœจ Features
- ๐Ÿ”Œ **Events & Hooks** โ€” register plugins for an event; they run in **priority + dependency** order.
- โšก **Fast dispatch** โ€” each event compiles to a module, so `Hook.call/3` is a direct call: no GenServer, no DB on the read path.
- ๐Ÿฉบ **Health checks** โ€” optional per-plugin `health_check/0`, inspected via `Hook.event_health/1`.
- ๐ŸŒ **Multi-node** โ€” the Mnesia-backed store joins & replicates across a cluster automatically.
- ๐Ÿ“ฆ **Runtime installer** โ€” load **pre-built `ebin`** artifacts (local path, URL, or GitHub release). Works in a `mix release`.
---
## ๐Ÿ”Œ Events & Hooks
Define a plugin for an event โ€” it auto-registers and runs whenever the event is called:
```elixir
defmodule RegisterEmailSender do
use MishkaInstaller.Event.Hook, event: "after_success_login"
@impl true
def call(entries), do: {:reply, entries}
end
```
```elixir
# tweak defaults
use MishkaInstaller.Event.Hook,
event: "after_success_login",
initial: %{depends: [SomeEvent], priority: 20}
```
Call every plugin registered for an event:
```elixir
alias MishkaInstaller.Event.Hook
Hook.call("after_success_login", params)
Hook.call("after_success_login", params, private: keep_this) # extra data, untouched by plugins
Hook.call("after_success_login", params, return: true) # return the original input
```
To start a plugin automatically, add its module to your supervision tree:
```elixir
children = [RegisterEmailSender, ...]
```
> [!NOTE]
> A plugin's `depends` always run **before** it (cycles are rejected at registration), and a plugin can return `{:reply, :halt, state}` to stop the rest of the chain. See `MishkaInstaller.Event.Hook`.
[![Run in Livebook](https://livebook.dev/badge/v1/pink.svg)](https://livebook.dev/run?url=https%3A%2F%2Fgithub.com%2Fmishka-group%2Fmishka_installer%2Fblob%2Fmaster%2Fguidance%2Fevent%2Fhook.livemd)
---
## ๐Ÿ“ฆ Installer
Load an **already-compiled `ebin`** at runtime โ€” no source compilation, so it's release-safe:
```elixir
alias MishkaInstaller.Installer.Installer
Installer.install(%{app: "demo", version: "0.1.0", type: :path, path: "/ext/demo-0.1.0"})
Installer.install(%{app: "demo", version: "0.1.0", type: :url, path: "https://.../demo-ebin.tar.gz"})
Installer.install(%{app: "demo", version: "0.1.0", type: :github_tag, path: "owner/repo", tag: "0.1.0"})
Installer.install(%{app: "demo", version: "0.1.0", type: :github_latest_release, path: "owner/repo"})
Installer.uninstall(%{app: "demo", version: "0.1.0"})
```
> [!NOTE]
> Remote installs (`:url`/`:github_*`) are **fail-closed**: they require the source host/repo in `config :mishka_installer, :allowlist, url_hosts:/github_repos:`. Optional `checksum:` (sha256) pins the artifact; `:protected_apps` guards apps from being overwritten/removed. See `MishkaInstaller.Installer.Installer`.
---
## ๐Ÿญ Production deployment
An installed library is a pre-built `ebin` on disk plus a Mnesia record; on every boot it is replayed (put back on the code path and started). So **both** the `ebin`s and the Mnesia data must live on a **persistent (mounted) volume** โ€” otherwise installs do not survive a restart/redeploy. Point both at your volume (here `/data`):
```elixir
# config/runtime.exs โ€” /data is your mounted volume
config :mishka_installer,
project_path: "/data",
extensions_path: "/data/extensions"
config :mishka_installer, MishkaInstaller.MnesiaRepo,
mnesia_dir: "/data/mnesia",
essential: [MishkaInstaller.Event.Event, MishkaInstaller.Installer.Installer]
```
`:extensions_path` is where `ebin`s are written; `mnesia_dir` is where the records live; `:essential` are the tables created on boot (the plugin and install stores โ€” keep both). Just depend on `:mishka_installer`; its supervision tree starts automatically outside `:test`.
> A real release restart proof lives in `test/integration/production_release/` โ€” run it with `mix test --only production_release`.
---
## ๐Ÿš€ Installation
```elixir
def deps do
[{:mishka_installer, "~> 0.1.10"}]
end
```
Docs: [hexdocs.pm/mishka_installer](https://hexdocs.pm/mishka_installer)
---
## ๐Ÿ’– Funding & sponsorship
MishkaInstaller is open-source software developed by [Mishka Group](https://github.com/mishka-group). If your team or company benefits from it, please consider supporting continued development:
<div align="center">
[![GitHub Sponsors](https://img.shields.io/badge/GitHub_Sponsors-mishka--group-ea4aaa?style=for-the-badge&logo=github&logoColor=white)](https://github.com/sponsors/mishka-group)
&nbsp;&nbsp;&nbsp;
[![Buy Me a Coffee](https://img.shields.io/badge/Buy_Me_a_Coffee-mishkagroup-ffdd00?style=for-the-badge&logo=buy-me-a-coffee&logoColor=black)](https://www.buymeacoffee.com/mishkagroup)
**โ˜• Donate / sponsor:**
[github.com/sponsors/mishka-group](https://github.com/sponsors/mishka-group) ยท [buymeacoffee.com/mishkagroup](https://www.buymeacoffee.com/mishkagroup)
</div>
Thank you. ๐Ÿ’š
---
## ๐Ÿ“œ License
Apache License 2.0 โ€” see [`LICENSE`](https://github.com/mishka-group/mishka_installer/blob/master/LICENSE).
Copyright ยฉ Mishka Group and contributors.