Compare commits

...

4 Commits

Author SHA1 Message Date
Ryan Rix 1abac25a0e detangle ArcologyWeb helper 2023-03-03 12:00:12 -08:00
Ryan Rix 22de64460f Arcology.Application detangled 2023-03-03 11:35:33 -08:00
Ryan Rix 2b8356513f add Phoenix etc configuration stubs 2023-03-03 11:34:04 -08:00
Ryan Rix 20ea44391e add mix configuration 2023-03-03 11:33:40 -08:00
15 changed files with 1755 additions and 0 deletions

109
arcology_app.org Normal file
View File

@ -0,0 +1,109 @@
:PROPERTIES:
:ID: 20230303T100429.248407
:END:
#+TITLE: Arcology Elixir Backend Logic
#+AUTO_TANGLE: t
* Setting up the =Arcology= elixir module
This is a module, the submodules are where the interesting things happen. The module doc says what it does:
#+begin_src text :noweb-ref arcology.moduledoc
Arcology keeps the contexts that define your domain
and business logic.
Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others.
#+end_src
#+begin_src elixir :tangle lib/arcology.ex :noweb yes
defmodule Arcology do
@moduledoc """
<<arcology.moduledoc>>
"""
end
#+end_src
* =Arcology.Application= Elixir Application Startup
#+begin_src elixir :tangle lib/arcology/application.ex :noweb yes
defmodule Arcology.Application do
@moduledoc false
use Application
<<start_2>>
<<config_change_3>>
end
#+end_src
So =Arcology.Application.start/2= is the entrypoint of the Phoenix [[https://hexdocs.pm/elixir/Application.html][OTP application]], it starts up a bunch of other *Supervised*[fn:1] Elixir processes and makes sure they keep running.
** =Arcology.Application.start/2=
We start the Ecto repository [[roam:Arcology.Repo]]:
#+begin_src elixir :noweb-ref app-children
Arcology.Repo
#+end_src
We start the PubSub messaging system:
#+begin_src elixir :noweb-ref app-children
{Phoenix.PubSub, name: Arcology.PubSub}
#+end_src
We start [[https://github.com/sneako/finch][Finch]], an HTTP client:
#+begin_src elixir :noweb-ref app-children
{Finch, name: Arcology.Finch}
#+end_src
We start the [[roam:ArcologyWeb.Endpoint]] which handles HTTP requests from the web.
#+begin_src elixir :noweb-ref app-children
ArcologyWeb.Endpoint
#+end_src
We will also start the =ArcologyWeb.Telemetry= server provided by Phoenix [n.b. this code block isn't directly included so that i can generate decent list-syntax without relying on metaprogramming or not being able to detangle this to my heart's content]
This supervisor is configured to only restart a single process when the process dies; for other applications you may want it to restart *all* children, or to only restart "younger" processes which may rely on state within the dead process. This is pretty simple for now. Check out [[https://hexdocs.pm/elixir/Supervisor.html][the docs]] if you care.
#+begin_src elixir :noweb-ref start_2 :noweb yes
@impl true
def start(_type, _args) do
children = [
ArcologyWeb.Telemetry
, <<app-children>>
]
opts = [strategy: :one_for_one, name: Arcology.Supervisor]
Supervisor.start_link(children, opts)
end
#+end_src
This =config_change= function is a stub that sends new configuration to the =ArcologyWeb.Endpoint= process when the appication is upgraded. I'll probably just restart the thing in place, but for highly-available OTP applications this sort of stuff is bread-and-butter.
#+begin_src elixir :noweb-ref config_change_3
@impl true
def config_change(changed, _new, removed) do
ArcologyWeb.Endpoint.config_change(changed, removed)
:ok
end
#+end_src
* =Arcology.Mailer=
This is a stub for now -- maybe i'll send mails for new posts in the future but *shrug*:
#+begin_src elixir :tangle lib/arcology/mailer.ex
defmodule Arcology.Mailer do
use Swoosh.Mailer, otp_app: :arcology
end
#+end_src
* Footnotes
[fn:1] Elixir is built on Erlang, and Erlang has a process-based Actor model, you can send messages to processes whose IDs you have. The Supervisor is responsible for starting and managing the lifecycle of these processes. See [[https://www.erlang.org/doc/design_principles/sup_princ.html][the OTP Design Principles]] doc.

177
arcology_web.org Normal file
View File

@ -0,0 +1,177 @@
:PROPERTIES:
:ID: 20230303T095957.835101
:ROAM_ALIASES: ArcologyWeb
:END:
#+TITLE: Arcology Web Elixir Application
* Setting up the =ArcologyWeb= module
:PROPERTIES:
:ID: 20230303T114356.700426
:ROAM_ALIASES: ArcologyWeb
:END:
Much of this is boilerplate which I include here only to understand and take apart how Phoenix operates. There's not a whole lot hiding "under the hood" compared to, say, Ruby on Rails, which I really appreciate, to be honest.
So starting with the moduledoc:
#+begin_src text :noweb-ref ArcologyWeb.moduledoc
The entrypoint for defining your web interface, such
as controllers, components, channels, and so on.
This can be used in your application as:
use ArcologyWeb, :controller
use ArcologyWeb, :html
The definitions below will be executed for every controller,
component, etc, so keep them short and clean, focused
on imports, uses and aliases.
Do NOT define functions inside the quoted expressions
below. Instead, define additional modules and import
those modules here.
#+end_src
This is pretty straightforward, right? Our controllers and views can include a bunch of standard behavior (auth, logging, rate limiting, etc) by invoking those =use= statements. There are a bunch of functions defined below which will be exposed in that fashion using this "magic" =__using__= macro:
#+begin_src elixir :noweb-ref ArcologyWeb.__using__
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
#+end_src
Some of the helpers include some extra helpers shared among them by "unquoting" a function which returns "quoted" =import= and =alias= statements -- this is the sort of indirection which makes sense in my Lisp brain, but it can be really off-putting to people who aren't exposed to this sort of pattern. The basic idea here is to provide those statements in the function which is "used in" rather than in the private helpers where they would be executed were they not quoted.
These functions import functionality for HTML rendering, [[https://hexdocs.pm/phoenix/1.7.0-rc.0/Phoenix.VerifiedRoutes.html][compile-time Verified Route]] generation, and translations:
#+begin_src elixir :noweb-ref quoted-helpers
defp html_helpers do
quote do
# HTML escaping functionality
import Phoenix.HTML
# Core UI components and translation
import ArcologyWeb.CoreComponents
import ArcologyWeb.Gettext
# Shortcut for generating JS commands
alias Phoenix.LiveView.JS
# Routes generation with the ~p sigil
unquote(verified_routes())
end
end
def verified_routes do
quote do
use Phoenix.VerifiedRoutes,
endpoint: ArcologyWeb.Endpoint,
router: ArcologyWeb.Router,
statics: ArcologyWeb.static_paths()
end
end
#+end_src
Use'ing =:router= in [[roam:ArcologyWeb.Router]] lets me customize the behavior of the router by introducing [[https://hexdocs.pm/plug/readme.html][Plugs]]; I'll be adding a Plug to attempt to load Arcology pages rather than using a "greedy" route which I used in (for example) the FastAPI [[id:20220225T175638.482695][Arcology Domain Router]].
#+begin_src elixir :noweb-ref helpers
def router do
quote do
use Phoenix.Router, helpers: false
# Import common connection and controller functions to use in pipelines
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
end
end
#+end_src
Routing, controlling, viewing, etc, can all be skipped for =static_paths=, these are files that can just be served out of the filesystem where the application is built and bundled:
#+begin_src elixir :noweb-ref helpers
def static_paths, do: ~w(assets fonts images favicon.ico robots.txt)
#+end_src
The =:controller= helper sets up rendering rules, provides access to translations
#+begin_src elixir :noweb-ref helpers
def controller do
quote do
use Phoenix.Controller,
formats: [:html, :json],
layouts: [html: ArcologyWeb.Layouts]
import Plug.Conn
import ArcologyWeb.Gettext
unquote(verified_routes())
end
end
#+end_src
The =:live_view=, =:live_component=, and =:html= helpers set up HTML rendering and dynamic LiveView components using the quoted helpers described above.
#+begin_src elixir :noweb-ref helpers
def live_view do
quote do
use Phoenix.LiveView,
layout: {ArcologyWeb.Layouts, :app}
unquote(html_helpers())
end
end
def live_component do
quote do
use Phoenix.LiveComponent
unquote(html_helpers())
end
end
def html do
quote do
use Phoenix.Component
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_csrf_token: 0, view_module: 1, view_template: 1]
# Include general helpers for rendering HTML
unquote(html_helpers())
end
end
#+end_src
The =:channel= helper will provide =Phoenix.Channel= helpers to PubSub channels, if I decide to use them.
#+begin_src elixir :noweb-ref helpers
def channel do
quote do
use Phoenix.Channel
end
end
#+end_src
#+begin_src elixir :noweb yes :tangle lib/arcology_web.ex
defmodule ArcologyWeb do
@moduledoc """
<<ArcologyWeb.moduledoc>>
"""
<<helpers>>
<<quoted_helpers>>
<<ArcologyWeb.__using__>>
end
#+end_src
* =ArcologyWeb.Endpoint= helpers
:PROPERTIES:
:ID: 20230303T104626.041201
:END:

51
config/config.exs Normal file
View File

@ -0,0 +1,51 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Config module.
#
# This configuration file is loaded before any dependency and
# is restricted to this project.
# General application configuration
import Config
config :arcology,
ecto_repos: [Arcology.Repo]
config :arcology, ArcologyWeb.Endpoint,
url: [host: "localhost"],
render_errors: [
formats: [html: ArcologyWeb.ErrorHTML, json: ArcologyWeb.ErrorJSON],
layout: false
],
pubsub_server: Arcology.PubSub,
live_view: [signing_salt: "OgcteMC0"]
config :arcology, Arcology.Mailer, adapter: Swoosh.Adapters.Local
config :esbuild,
version: "0.14.41",
default: [
args:
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
# Configure tailwind (the version is required)
config :tailwind,
version: "3.2.4",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
),
cd: Path.expand("../assets", __DIR__)
]
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
config :phoenix, :json_library, Jason
import_config "#{config_env()}.exs"

39
config/dev.exs Normal file
View File

@ -0,0 +1,39 @@
import Config
config :arcology, Arcology.Repo,
database: Path.expand("../arcology.db", Path.dirname(__ENV__.file)),
pool_size: 5,
stacktrace: true,
show_sensitive_data_on_connection_error: true
config :arcology, ArcologyWeb.Endpoint,
# Binding to loopback ipv4 address prevents access from other machines.
# Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
http: [ip: {127, 0, 0, 1}, port: 4000],
check_origin: false,
code_reloader: true,
debug_errors: true,
secret_key_base: "PkJnuIpBpXQpUqGrc7ynUHYyXvAB40b03rjay/9WuKmzEN9H9GaELBdGOok2GQih",
watchers: [
esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
]
config :arcology, ArcologyWeb.Endpoint,
live_reload: [
patterns: [
~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
~r"priv/gettext/.*(po)$",
~r"lib/arcology_web/(controllers|live|components)/.*(ex|heex)$"
]
]
config :arcology, dev_routes: true
config :logger, :console, format: "[$level] $message\n"
config :phoenix, :stacktrace_depth, 20
config :phoenix, :plug_init_mode, :runtime
config :swoosh, :api_client, false

21
config/prod.exs Normal file
View File

@ -0,0 +1,21 @@
import Config
# For production, don't forget to configure the url host
# to something meaningful, Phoenix uses this information
# when generating URLs.
# Note we also include the path to a cache manifest
# containing the digested version of static files. This
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :arcology, ArcologyWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
# Configures Swoosh API Client
config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Arcology.Finch
# Do not print debug messages in production
config :logger, level: :info
# Runtime production configuration, including reading
# of environment variables, is done on config/runtime.exs.

36
config/runtime.exs Normal file
View File

@ -0,0 +1,36 @@
if System.get_env("PHX_SERVER") do
config :arcology, ArcologyWeb.Endpoint, server: true
end
if config_env() == :prod do
database_path =
System.get_env("DATABASE_PATH") ||
raise """
environment variable DATABASE_PATH is missing.
For example: /etc/arcology/arcology.db
"""
config :arcology, Arcology.Repo,
database: database_path,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "5")
secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
raise """
environment variable SECRET_KEY_BASE is missing.
You can generate one by calling: mix phx.gen.secret
"""
host = System.get_env("PHX_HOST") || "example.com"
port = String.to_integer(System.get_env("PORT") || "4000")
config :arcology, ArcologyWeb.Endpoint,
url: [host: host, port: 443, scheme: "https"],
http: [
ip: {127, 0, 0, 1},
port: port
],
secret_key_base: secret_key_base
end

30
config/test.exs Normal file
View File

@ -0,0 +1,30 @@
import Config
# Configure your database
#
# The MIX_TEST_PARTITION environment variable can be used
# to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information.
config :arcology, Arcology.Repo,
database: Path.expand("../arcology_test.db", Path.dirname(__ENV__.file)),
pool_size: 5,
pool: Ecto.Adapters.SQL.Sandbox
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :arcology, ArcologyWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4002],
secret_key_base: "4EDyvZHi6tCmgax6tx/v9e6L9kQmXt8qnhsqYE78k7P82uy71Ge7Zl6jPMolA+RR",
server: false
# In test we don't send emails.
config :arcology, Arcology.Mailer, adapter: Swoosh.Adapters.Test
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false
# Print only warnings and errors during test
config :logger, level: :warning
# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime

9
lib/arcology.ex Normal file
View File

@ -0,0 +1,9 @@
defmodule Arcology do
@moduledoc """
Arcology keeps the contexts that define your domain
and business logic.
Contexts are also responsible for managing your data, regardless
if it comes from the database, an external API or others.
"""
end

View File

@ -0,0 +1,25 @@
defmodule Arcology.Application do
@moduledoc false
use Application
@impl true
def start(_type, _args) do
children = [
ArcologyWeb.Telemetry
, Arcology.Repo
, {Phoenix.PubSub, name: Arcology.PubSub}
, {Finch, name: Arcology.Finch}
, ArcologyWeb.Endpoint
]
opts = [strategy: :one_for_one, name: Arcology.Supervisor]
Supervisor.start_link(children, opts)
end
@impl true
def config_change(changed, _new, removed) do
ArcologyWeb.Endpoint.config_change(changed, removed)
:ok
end
end

3
lib/arcology/mailer.ex Normal file
View File

@ -0,0 +1,3 @@
defmodule Arcology.Mailer do
use Swoosh.Mailer, otp_app: :arcology
end

113
lib/arcology_web.ex Normal file
View File

@ -0,0 +1,113 @@
defmodule ArcologyWeb do
@moduledoc """
The entrypoint for defining your web interface, such
as controllers, components, channels, and so on.
This can be used in your application as:
use ArcologyWeb, :controller
use ArcologyWeb, :html
The definitions below will be executed for every controller,
component, etc, so keep them short and clean, focused
on imports, uses and aliases.
Do NOT define functions inside the quoted expressions
below. Instead, define additional modules and import
those modules here.
"""
def static_paths, do: ~w(assets fonts images favicon.ico robots.txt)
def router do
quote do
use Phoenix.Router, helpers: false
# Import common connection and controller functions to use in pipelines
import Plug.Conn
import Phoenix.Controller
import Phoenix.LiveView.Router
end
end
def channel do
quote do
use Phoenix.Channel
end
end
def controller do
quote do
use Phoenix.Controller,
formats: [:html, :json],
layouts: [html: ArcologyWeb.Layouts]
import Plug.Conn
import ArcologyWeb.Gettext
unquote(verified_routes())
end
end
def live_view do
quote do
use Phoenix.LiveView,
layout: {ArcologyWeb.Layouts, :app}
unquote(html_helpers())
end
end
def live_component do
quote do
use Phoenix.LiveComponent
unquote(html_helpers())
end
end
def html do
quote do
use Phoenix.Component
# Import convenience functions from controllers
import Phoenix.Controller,
only: [get_csrf_token: 0, view_module: 1, view_template: 1]
# Include general helpers for rendering HTML
unquote(html_helpers())
end
end
defp html_helpers do
quote do
# HTML escaping functionality
import Phoenix.HTML
# Core UI components and translation
import ArcologyWeb.CoreComponents
import ArcologyWeb.Gettext
# Shortcut for generating JS commands
alias Phoenix.LiveView.JS
# Routes generation with the ~p sigil
unquote(verified_routes())
end
end
def verified_routes do
quote do
use Phoenix.VerifiedRoutes,
endpoint: ArcologyWeb.Endpoint,
router: ArcologyWeb.Router,
statics: ArcologyWeb.static_paths()
end
end
@doc """
When used, dispatch to the appropriate controller/view/etc.
"""
defmacro __using__(which) when is_atom(which) do
apply(__MODULE__, which, [])
end
end

61
mix.exs Normal file
View File

@ -0,0 +1,61 @@
defmodule Arcology.MixProject do
use Mix.Project
def project do
[
app: :arcology,
version: "0.1.0",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
]
end
def application do
[
mod: {Arcology.Application, []},
extra_applications: [:logger, :runtime_tools]
]
end
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
defp deps do
[
{:phoenix, "~> 1.7.1"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"},
{:ecto_sqlite3, ">= 0.0.0"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.18.16"},
{:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.7.2"},
{:esbuild, "~> 0.5", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.1.8", runtime: Mix.env() == :dev},
{:swoosh, "~> 1.3"},
{:finch, "~> 0.13"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"}
]
end
defp aliases do
[
setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
"assets.build": ["tailwind default", "esbuild default"],
"assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
]
end
end

46
mix.lock Normal file
View File

@ -0,0 +1,46 @@
%{
"castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"},
"cc_precompiler": {:hex, :cc_precompiler, "0.1.6", "68894618428c8a4e7fcbc0b2e2dda0c19ca13f98b2507a2fcf813a72ca5a0723", [:mix], [{:elixir_make, "~> 0.7.3", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "238b56c19dfe679a371e604ef33d0371a858a414eeca3a2e09af8bd74178e00c"},
"connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"db_connection": {:hex, :db_connection, "2.4.3", "3b9aac9f27347ec65b271847e6baeb4443d8474289bd18c1d6f4de655b70c94d", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c127c15b0fa6cfb32eed07465e05da6c815b032508d4ed7c116122871df73c12"},
"decimal": {:hex, :decimal, "2.0.0", "a78296e617b0f5dd4c6caf57c714431347912ffb1d0842e998e9792b5642d697", [:mix], [], "hexpm", "34666e9c55dea81013e77d9d87370fe6cb6291d1ef32f46a1600230b1d44f577"},
"ecto": {:hex, :ecto, "3.9.4", "3ee68e25dbe0c36f980f1ba5dd41ee0d3eb0873bccae8aeaf1a2647242bffa35", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "de5f988c142a3aa4ec18b85a4ec34a2390b65b24f02385c1144252ff6ff8ee75"},
"ecto_sql": {:hex, :ecto_sql, "3.9.2", "34227501abe92dba10d9c3495ab6770e75e79b836d114c41108a4bf2ce200ad5", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9.2", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "1eb5eeb4358fdbcd42eac11c1fbd87e3affd7904e639d77903c1358b2abd3f70"},
"ecto_sqlite3": {:hex, :ecto_sqlite3, "0.9.1", "6cb740afcb0af882cf9dfbac7ff8db863600d3bb24454c840d506e05b1508d6e", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto, "~> 3.9", [hex: :ecto, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.9", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:exqlite, "~> 0.9", [hex: :exqlite, repo: "hexpm", optional: false]}], "hexpm", "cc7664d9210c232370e67e89331056cf0a35e74862cd57e893e7035eacbd4afc"},
"elixir_make": {:hex, :elixir_make, "0.7.5", "784cc00f5fa24239067cc04d449437dcc5f59353c44eb08f188b2b146568738a", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: true]}], "hexpm", "c3d63e8d5c92fa3880d89ecd41de59473fa2e83eeb68148155e25e8b95aa2887"},
"esbuild": {:hex, :esbuild, "0.6.1", "a774bfa7b4512a1211bf15880b462be12a4c48ed753a170c68c63b2c95888150", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "569f7409fb5a932211573fc20e2a930a0d5cf3377c5b4f6506c651b1783a1678"},
"expo": {:hex, :expo, "0.4.0", "bbe4bf455e2eb2ebd2f1e7d83530ce50fb9990eb88fc47855c515bfdf1c6626f", [:mix], [], "hexpm", "a8ed1683ec8b7c7fa53fd7a41b2c6935f539168a6bb0616d7fd6b58a36f3abf2"},
"exqlite": {:hex, :exqlite, "0.13.5", "2904bdf1fe5fcb5c7e0d2e991178bb2b7c534c339bfa3e4966bf40e34fadf512", [:make, :mix], [{:cc_precompiler, "~> 0.1", [hex: :cc_precompiler, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "32fe5badecc3491975dbc39b1104e77cde35c23a9e1cb47ce9ee3b4945c90666"},
"file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"finch": {:hex, :finch, "0.14.0", "619bfdee18fc135190bf590356c4bf5d5f71f916adb12aec94caa3fa9267a4bc", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5459acaf18c4fdb47a8c22fb3baff5d8173106217c8e56c5ba0b93e66501a8dd"},
"floki": {:hex, :floki, "0.34.2", "5fad07ef153b3b8ec110b6b155ec3780c4b2c4906297d0b4be1a7162d04a7e02", [:mix], [], "hexpm", "26b9d50f0f01796bc6be611ca815c5e0de034d2128e39cc9702eee6b66a4d1c8"},
"gettext": {:hex, :gettext, "0.22.1", "e7942988383c3d9eed4bdc22fc63e712b655ae94a672a27e4900e3d4a2c43581", [:mix], [{:expo, "~> 0.4.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "ad105b8dab668ee3f90c0d3d94ba75e9aead27a62495c101d94f2657a190ac5d"},
"hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"},
"jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"},
"mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"},
"mint": {:hex, :mint, "1.5.0", "fa2d1ea301f5cc42f45c3fabbd268742a932be49c11c0f054af1dd67d3f7515e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "8a61c2d469c657f6cb76ea547d523c3a593d24901b1d97bf92bf4a83eaa2517b"},
"nimble_options": {:hex, :nimble_options, "0.5.2", "42703307b924880f8c08d97719da7472673391905f528259915782bb346e0a1b", [:mix], [], "hexpm", "4da7f904b915fd71db549bcdc25f8d56f378ef7ae07dc1d372cbe72ba950dce0"},
"nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"phoenix": {:hex, :phoenix, "1.7.1", "a029bde19d9c3b559e5c3d06c78b76e81396bedd456a6acedb42f9c7b2e535a9", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.4", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "ea9d4a85c3592e37efa07d0dc013254fda445885facaefddcbf646375c116457"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"phoenix_html": {:hex, :phoenix_html, "3.3.1", "4788757e804a30baac6b3fc9695bf5562465dd3f1da8eb8460ad5b404d9a2178", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "bed1906edd4906a15fd7b412b85b05e521e1f67c9a85418c55999277e553d0d3"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.7.2", "97cc4ff2dba1ebe504db72cb45098cb8e91f11160528b980bd282cc45c73b29c", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.18.3", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "0e5fdf063c7a3b620c566a30fcf68b7ee02e5e46fe48ee46a6ec3ba382dc05b7"},
"phoenix_live_reload": {:hex, :phoenix_live_reload, "1.4.1", "2aff698f5e47369decde4357ba91fc9c37c6487a512b41732818f2204a8ef1d3", [:mix], [{:file_system, "~> 0.2.1 or ~> 0.3", [hex: :file_system, repo: "hexpm", optional: false]}, {:phoenix, "~> 1.4", [hex: :phoenix, repo: "hexpm", optional: false]}], "hexpm", "9bffb834e7ddf08467fe54ae58b5785507aaba6255568ae22b4d46e2bb3615ab"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.18.16", "781c6a3ac49e0451ca403848b40807171caea400896fe8ed8e5ddd6106ad5580", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "09e6ae2babe62f74bfcd1e3cac1a9b0e2c262557cc566300a843425c9cb6842a"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"phoenix_template": {:hex, :phoenix_template, "1.0.1", "85f79e3ad1b0180abb43f9725973e3b8c2c3354a87245f91431eec60553ed3ef", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "157dc078f6226334c91cb32c1865bf3911686f8bcd6bcff86736f6253e6993ee"},
"plug": {:hex, :plug, "1.14.0", "ba4f558468f69cbd9f6b356d25443d0b796fbdc887e03fa89001384a9cac638f", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "bf020432c7d4feb7b3af16a0c2701455cbbbb95e5b6866132cb09eb0c29adc14"},
"plug_cowboy": {:hex, :plug_cowboy, "2.6.0", "d1cf12ff96a1ca4f52207c5271a6c351a4733f413803488d75b70ccf44aebec2", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "073cf20b753ce6682ed72905cd62a2d4bd9bad1bf9f7feb02a1b8e525bd94fa6"},
"plug_crypto": {:hex, :plug_crypto, "1.2.3", "8f77d13aeb32bfd9e654cb68f0af517b371fb34c56c9f2b58fe3df1235c1251a", [:mix], [], "hexpm", "b5672099c6ad5c202c45f5a403f21a3411247f164e4a8fab056e5cd8a290f4a2"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"swoosh": {:hex, :swoosh, "1.9.1", "0a5d7bf9954eb41d7e55525bc0940379982b090abbaef67cd8e1fd2ed7f8ca1a", [:mix], [{:cowboy, "~> 1.1 or ~> 2.4", [hex: :cowboy, repo: "hexpm", optional: true]}, {:ex_aws, "~> 2.1", [hex: :ex_aws, repo: "hexpm", optional: true]}, {:finch, "~> 0.6", [hex: :finch, repo: "hexpm", optional: true]}, {:gen_smtp, "~> 0.13 or ~> 1.0", [hex: :gen_smtp, repo: "hexpm", optional: true]}, {:hackney, "~> 1.9", [hex: :hackney, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mail, "~> 0.2", [hex: :mail, repo: "hexpm", optional: true]}, {:mime, "~> 1.1 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_cowboy, ">= 1.0.0", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "76dffff3ffcab80f249d5937a592eaef7cc49ac6f4cdd27e622868326ed6371e"},
"tailwind": {:hex, :tailwind, "0.1.10", "21ed80ae1f411f747ee513470578acaaa1d0eb40170005350c5b0b6d07e2d624", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}], "hexpm", "e0fc474dfa8ed7a4573851ac69c5fd3ca70fbb0a5bada574d1d657ebc6f2f1f1"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
"telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"websock": {:hex, :websock, "0.4.3", "184ac396bdcd3dfceb5b74c17d221af659dd559a95b1b92041ecb51c9b728093", [:mix], [], "hexpm", "5e4dd85f305f43fd3d3e25d70bec4a45228dfed60f0f3b072d8eddff335539cf"},
"websock_adapter": {:hex, :websock_adapter, "0.4.5", "30038a3715067f51a9580562c05a3a8d501126030336ffc6edb53bf57d6d2d26", [:mix], [{:bandit, "~> 0.6", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.4", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "1d9812dc7e703c205049426fd4fe0852a247a825f91b099e53dc96f68bafe4c8"},
}

584
mix.nix Normal file
View File

@ -0,0 +1,584 @@
{ lib, beamPackages, overrides ? (x: y: {}) }:
let
buildRebar3 = lib.makeOverridable beamPackages.buildRebar3;
buildMix = lib.makeOverridable beamPackages.buildMix;
buildErlangMk = lib.makeOverridable beamPackages.buildErlangMk;
self = packages // (overrides self packages);
packages = with beamPackages; with self; {
castore = buildMix rec {
name = "castore";
version = "0.1.22";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1b1cl89fzkykimxwgm8mwb9wmxcrd8qk8hfc83pa2npb8zgpcxf1";
};
beamDeps = [];
};
cc_precompiler = buildMix rec {
name = "cc_precompiler";
version = "0.1.6";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0370g10xg2xg14p3mjpf2jj5ia3i0cyz6kk03qvrlrzykp0md2r3";
};
beamDeps = [ elixir_make ];
};
connection = buildMix rec {
name = "connection";
version = "1.1.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1746n8ba11amp1xhwzp38yfii2h051za8ndxlwdykyqqljq1wb3j";
};
beamDeps = [];
};
cowboy = buildErlangMk rec {
name = "cowboy";
version = "2.9.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1phv0a1zbgk7imfgcm0dlacm7hbjcdygb0pqmx4s26jf9f9rywic";
};
beamDeps = [ cowlib ranch ];
};
cowboy_telemetry = buildRebar3 rec {
name = "cowboy_telemetry";
version = "0.4.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1pn90is3k9dq64wbijvzkqb6ldfqvwiqi7ymc8dx6ra5xv0vm63x";
};
beamDeps = [ cowboy telemetry ];
};
cowlib = buildRebar3 rec {
name = "cowlib";
version = "2.11.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1ac6pj3x4vdbsa8hvmbzpdfc4k0v1p102jbd39snai8wnah9sgib";
};
beamDeps = [];
};
db_connection = buildMix rec {
name = "db_connection";
version = "2.4.3";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "04iwywfqf8k125yfvm084l1mp0bcv82mwih7xlpb7kx61xdw29y1";
};
beamDeps = [ connection telemetry ];
};
decimal = buildMix rec {
name = "decimal";
version = "2.0.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0xzm8hfhn8q02rmg8cpgs68n5jz61wvqg7bxww9i1a6yanf6wril";
};
beamDeps = [];
};
ecto = buildMix rec {
name = "ecto";
version = "3.9.4";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0xgfz1pzylj22k0qa8zh4idvd4139b1lwnmq33na8fia2j69hpyy";
};
beamDeps = [ decimal jason telemetry ];
};
ecto_sql = buildMix rec {
name = "ecto_sql";
version = "3.9.2";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0w1zplm8ndf10dwxffg60iwzvbz3hyyiy761x91cvnwg6nsfxd8y";
};
beamDeps = [ db_connection ecto telemetry ];
};
ecto_sqlite3 = buildMix rec {
name = "ecto_sqlite3";
version = "0.9.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1z2apnn5w0z7jgl5gkb293kka2ngaq8372bywrq268qc47cn8xnc";
};
beamDeps = [ decimal ecto ecto_sql exqlite ];
};
elixir_make = buildMix rec {
name = "elixir_make";
version = "0.7.5";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "11r8maaqnpp2an0i8s7b7vla4gs7b7g43kcyv203iyljbj6kxmn3";
};
beamDeps = [ castore ];
};
esbuild = buildMix rec {
name = "esbuild";
version = "0.6.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0y0n79wb2lf60rjlynvw6zrmq38ajcm0xhizaw8j54sszc4p97sn";
};
beamDeps = [ castore ];
};
expo = buildMix rec {
name = "expo";
version = "0.4.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1wmbycv8mdfngxnn3c3bi8b3kx9md4n1p96p7yjpyz4bxj1idvd8";
};
beamDeps = [];
};
exqlite = buildMix rec {
name = "exqlite";
version = "0.13.5";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0rh6r52ljfzfx5yb874y7b13bpkwww2136y3vdsijjf3xjnmpzij";
};
beamDeps = [ cc_precompiler db_connection elixir_make ];
};
file_system = buildMix rec {
name = "file_system";
version = "0.2.10";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1p0myxmnjjds8bbg69dd6fvhk8q3n7lb78zd4qvmjajnzgdmw6a1";
};
beamDeps = [];
};
finch = buildMix rec {
name = "finch";
version = "0.14.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1pd805jyd4qbpb2md3kw443325yqynpkpyr2iixb9zf432psqnal";
};
beamDeps = [ castore mime mint nimble_options nimble_pool telemetry ];
};
floki = buildMix rec {
name = "floki";
version = "0.34.2";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1j6ilik6pviff34rrqr8456h7pp0qlash731pv36ny811w7xbf96";
};
beamDeps = [];
};
gettext = buildMix rec {
name = "gettext";
version = "0.22.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0pdcj2hmf9jgv40w3594lqksvbp9fnx98g8d1kwy73k6mf6mn45d";
};
beamDeps = [ expo ];
};
hpax = buildMix rec {
name = "hpax";
version = "0.1.2";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "04wci9ifsfyd2pbcrnpgh2aq0a8fi1lpkrzb91kz3x93b8yq91rc";
};
beamDeps = [];
};
jason = buildMix rec {
name = "jason";
version = "1.4.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0891p2yrg3ri04p302cxfww3fi16pvvw1kh4r91zg85jhl87k8vr";
};
beamDeps = [ decimal ];
};
mime = buildMix rec {
name = "mime";
version = "2.0.3";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0szzdfalafpawjrrwbrplhkgxjv8837mlxbkpbn5xlj4vgq0p8r7";
};
beamDeps = [];
};
mint = buildMix rec {
name = "mint";
version = "1.5.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0ysilbm86jmzjazrf78vj0j3sn9s7i97sm7afv5zcmy6d7ac4qca";
};
beamDeps = [ castore hpax ];
};
nimble_options = buildMix rec {
name = "nimble_options";
version = "0.5.2";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1q6wa2ljprybfb9w2zg0gbppiwsnimgw5kcvakdp3z8mp42gk9sd";
};
beamDeps = [];
};
nimble_pool = buildMix rec {
name = "nimble_pool";
version = "0.2.6";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0gv59waa505mz2gi956sj1aa6844c65w2dp2qh2jfgsx15am0w8w";
};
beamDeps = [];
};
phoenix = buildMix rec {
name = "phoenix";
version = "1.7.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0mv425f3fipnrgfyzjpshmc49njg4l9w03bxl3pkfbjrqf2lm7ga";
};
beamDeps = [ castore jason phoenix_pubsub phoenix_template plug plug_cowboy plug_crypto telemetry websock_adapter ];
};
phoenix_ecto = buildMix rec {
name = "phoenix_ecto";
version = "4.4.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1h9wnjmxns8y8dsr0r41ks66gscaqm7ivk4gsh5y07nkiralx1h9";
};
beamDeps = [ ecto phoenix_html plug ];
};
phoenix_html = buildMix rec {
name = "phoenix_html";
version = "3.3.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1lyhagjpg4lran6431csgkvf28g50mdvh4mlsxgs21j9vmp91ldy";
};
beamDeps = [ plug ];
};
phoenix_live_dashboard = buildMix rec {
name = "phoenix_live_dashboard";
version = "0.7.2";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1dq5vj1a6fzclr3fwj7y8rg2xq3yigvgqc3aaq664fvs7h3dypqf";
};
beamDeps = [ ecto mime phoenix_live_view telemetry_metrics ];
};
phoenix_live_reload = buildMix rec {
name = "phoenix_live_reload";
version = "1.4.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1aqm6sxy4ijd5gi8lmjmcaxal1smg2smibjlzrkq9w6xwwsbizwv";
};
beamDeps = [ file_system phoenix ];
};
phoenix_live_view = buildMix rec {
name = "phoenix_live_view";
version = "0.18.16";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0al4nsf5qhj3m0066mncawjjcb0fkcdaqg0yrnzp8bz6mcmsxrh9";
};
beamDeps = [ jason phoenix phoenix_html phoenix_template telemetry ];
};
phoenix_pubsub = buildMix rec {
name = "phoenix_pubsub";
version = "2.1.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1nfqrmbrq45if9pgk6g6vqiply2sxc40is3bfanphn7a3rnpqdl1";
};
beamDeps = [];
};
phoenix_template = buildMix rec {
name = "phoenix_template";
version = "1.0.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1vlkd4z2bxinczwcysydidpnh49rpxjihb5k3k4k8qr2yrwc0z8m";
};
beamDeps = [ phoenix_html ];
};
plug = buildMix rec {
name = "plug";
version = "1.14.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "056wkb1b17mh5h9ncs2vbswvpjsm2iqc580nmyrvgznlqwr080mz";
};
beamDeps = [ mime plug_crypto telemetry ];
};
plug_cowboy = buildMix rec {
name = "plug_cowboy";
version = "2.6.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "19jgv5dm53hv5aqgxxzr3fnrpgfll9ics199swp6iriwfl5z4g07";
};
beamDeps = [ cowboy cowboy_telemetry plug ];
};
plug_crypto = buildMix rec {
name = "plug_crypto";
version = "1.2.3";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "18plj2idhp3f0nmqyjjf2rzj849l3br0797m8ln20p5dqscj0rxm";
};
beamDeps = [];
};
ranch = buildRebar3 rec {
name = "ranch";
version = "1.8.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1rfz5ld54pkd2w25jadyznia2vb7aw9bclck21fizargd39wzys9";
};
beamDeps = [];
};
swoosh = buildMix rec {
name = "swoosh";
version = "1.9.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "07ipsrp34s18c9zd5kglqsdc8z7gxa9aadsrklj0zf6azzrzzpvn";
};
beamDeps = [ cowboy finch jason mime plug_cowboy telemetry ];
};
tailwind = buildMix rec {
name = "tailwind";
version = "0.1.10";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1wgiyb3fnmyns5sabbav1axhz9rwzp2nkb2i71bs9mwfz96lgz70";
};
beamDeps = [ castore ];
};
telemetry = buildRebar3 rec {
name = "telemetry";
version = "1.2.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1mgyx9zw92g6w8fp9pblm3b0bghwxwwcbslrixq23ipzisfwxnfs";
};
beamDeps = [];
};
telemetry_metrics = buildMix rec {
name = "telemetry_metrics";
version = "0.6.1";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1iilk2n75kn9i95fdp8mpxvn3rcn3ghln7p77cijqws13j3y1sbv";
};
beamDeps = [ telemetry ];
};
telemetry_poller = buildRebar3 rec {
name = "telemetry_poller";
version = "1.0.0";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "0vjgxkxn9ll1gc6xd8jh4b0ldmg9l7fsfg7w63d44gvcssplx8mk";
};
beamDeps = [ telemetry ];
};
websock = buildMix rec {
name = "websock";
version = "0.4.3";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1krralrzzpcf5l3kn3qgsvz8s8j59bn0pmr57qyzshsz61gxhkay";
};
beamDeps = [];
};
websock_adapter = buildMix rec {
name = "websock_adapter";
version = "0.4.5";
src = fetchHex {
pkg = "${name}";
version = "${version}";
sha256 = "1j74my5zd5nwafg0j6zr4nl4g8jj13zd8vs295820g3hgvf1560x";
};
beamDeps = [ plug plug_cowboy websock ];
};
};
in self

451
setup.org
View File

@ -2,6 +2,7 @@
:ID: 20230302T132603.040866
:END:
#+TITLE: Arcology Phoenix Setup
#+filetags: :Project:
#+ARCOLOGY_KEY: arcology/phx/setup
#+ARCOLOGY_ALLOW_CRAWL: t
@ -138,3 +139,453 @@ mixNixDeps = import ./mix.nix {
});
};
#+end_src
* =mix.exs= project configuration
#+begin_src elixir :noweb-ref project
def project do
[
app: :arcology,
version: "0.1.0",
elixir: "~> 1.14",
elixirc_paths: elixirc_paths(Mix.env()),
start_permanent: Mix.env() == :prod,
aliases: aliases(),
deps: deps()
]
end
#+end_src
This instructs Mix to load [[roam:Arcology.Application]] as the entrypoint:
#+begin_src elixir :noweb-ref application
def application do
[
mod: {Arcology.Application, []},
extra_applications: [:logger, :runtime_tools]
]
end
#+end_src
Specifies which paths to compile per environment.
#+begin_src elixir :noweb-ref paths
defp elixirc_paths(:test), do: ["lib", "test/support"]
defp elixirc_paths(_), do: ["lib"]
#+end_src
Here's what we depend on:
#+begin_src elixir :noweb-ref deps
defp deps do
[
{:phoenix, "~> 1.7.1"},
{:phoenix_ecto, "~> 4.4"},
{:ecto_sql, "~> 3.6"},
{:ecto_sqlite3, ">= 0.0.0"},
{:phoenix_html, "~> 3.3"},
{:phoenix_live_reload, "~> 1.2", only: :dev},
{:phoenix_live_view, "~> 0.18.16"},
{:floki, ">= 0.30.0", only: :test},
{:phoenix_live_dashboard, "~> 0.7.2"},
{:esbuild, "~> 0.5", runtime: Mix.env() == :dev},
{:tailwind, "~> 0.1.8", runtime: Mix.env() == :dev},
{:swoosh, "~> 1.3"},
{:finch, "~> 0.13"},
{:telemetry_metrics, "~> 0.6"},
{:telemetry_poller, "~> 1.0"},
{:gettext, "~> 0.20"},
{:jason, "~> 1.2"},
{:plug_cowboy, "~> 2.5"}
]
end
#+end_src
Aliases are shortcuts or tasks specific to the current project.
For example, to install project dependencies and perform other setup tasks, run [[shell:mix setup]]. See [[https://hexdocs.pm/mix/1.12/Mix.html#module-aliases][the documentation]] for `Mix` for more info on aliases.
#+begin_src elixir :noweb-ref aliases
defp aliases do
[
setup: ["deps.get", "ecto.setup", "assets.setup", "assets.build"],
"ecto.setup": ["ecto.create", "ecto.migrate", "run priv/repo/seeds.exs"],
"ecto.reset": ["ecto.drop", "ecto.setup"],
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
"assets.build": ["tailwind default", "esbuild default"],
"assets.deploy": ["tailwind default --minify", "esbuild default --minify", "phx.digest"]
]
end
#+end_src
#+begin_src elixir :tangle mix.exs :noweb yes
defmodule Arcology.MixProject do
use Mix.Project
<<project>>
<<application>>
<<paths>>
<<deps>>
<<aliases>>
end
#+end_src
* Runtime Project Configuration
#+begin_src elixir :tangle config/config.exs
# This file is responsible for configuring your application
# and its dependencies with the aid of the Config module.
#
# This configuration file is loaded before any dependency and
# is restricted to this project.
# General application configuration
import Config
#+end_src
Tell Phoenix to load [[roam:Arcology.Repo]]
#+begin_src elixir :tangle config/config.exs
config :arcology,
ecto_repos: [Arcology.Repo]
#+end_src
Configure [[id:20230303T104626.041201][=ArcologyWeb.Endpoint=]], instruct it to use =Arcology.PubSub= as its message-passing layer.
#+begin_src elixir :tangle config/config.exs
config :arcology, ArcologyWeb.Endpoint,
url: [host: "localhost"],
render_errors: [
formats: [html: ArcologyWeb.ErrorHTML, json: ArcologyWeb.ErrorJSON],
layout: false
],
pubsub_server: Arcology.PubSub,
live_view: [signing_salt: "OgcteMC0"]
#+end_src
Configures the mailer
By default it uses the "Local" adapter which stores the emails
locally. You can see the emails in your browser, at "/dev/mailbox".
For production it's recommended to configure a different adapter
at the `config/runtime.exs`.
#+begin_src elixir :tangle config/config.exs
config :arcology, Arcology.Mailer, adapter: Swoosh.Adapters.Local
#+end_src
Configure =esbuild= for Javascript packaging. Sure beats a webpack setup!! I hope!!!!
#+begin_src elixir :tangle config/config.exs
config :esbuild,
version: "0.14.41",
default: [
args:
~w(js/app.js --bundle --target=es2017 --outdir=../priv/static/assets --external:/fonts/* --external:/images/*),
cd: Path.expand("../assets", __DIR__),
env: %{"NODE_PATH" => Path.expand("../deps", __DIR__)}
]
#+end_src
Configure Tailwind for components CSS; I might just ship the same 40 CSS rules I've been using for a while, though, tbh. This stuff is auto-generated:
#+begin_src elixir :tangle config/config.exs
# Configure tailwind (the version is required)
config :tailwind,
version: "3.2.4",
default: [
args: ~w(
--config=tailwind.config.js
--input=css/app.css
--output=../priv/static/assets/app.css
),
cd: Path.expand("../assets", __DIR__)
]
#+end_src
Configures Elixir's Logger:
#+begin_src elixir :tangle config/config.exs
config :logger, :console,
format: "$time $metadata[$level] $message\n",
metadata: [:request_id]
#+end_src
Use [[https://github.com/michalmuskala/jason][Jason]] for JSON parsing in Phoenix; in the past I used Poison which require a NIF, but this seems like a good middle-ground between fast and cheap.
#+begin_src elixir :tangle config/config.exs
config :phoenix, :json_library, Jason
#+end_src
Import environment specific config. This must remain at the bottom of this file so it overrides the configuration defined above.
#+begin_src elixir :tangle config/config.exs
import_config "#{config_env()}.exs"
#+end_src
** Dev
This will override the code in the parent =config.exs=.
#+begin_src elixir :tangle config/dev.exs
import Config
#+end_src
In production this will read an environment variable, but in dev we can just use the local directory to store the [[id:arcology/arroyo-page][Arroyo Arcology Generator]]'s DB.
#+begin_src elixir :tangle config/dev.exs
config :arcology, Arcology.Repo,
database: Path.expand("../arcology.db", Path.dirname(__ENV__.file)),
pool_size: 5,
stacktrace: true,
show_sensitive_data_on_connection_error: true
#+end_src
Dev build will bind to [[http://localhost:4000]] and have debug helpers installed code reloading enabled for Elixir, CSS, and Javascript.
#+begin_src elixir :tangle config/dev.exs
config :arcology, ArcologyWeb.Endpoint,
# Binding to loopback ipv4 address prevents access from other machines.
# Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
http: [ip: {127, 0, 0, 1}, port: 4000],
check_origin: false,
code_reloader: true,
debug_errors: true,
secret_key_base: "PkJnuIpBpXQpUqGrc7ynUHYyXvAB40b03rjay/9WuKmzEN9H9GaELBdGOok2GQih",
watchers: [
esbuild: {Esbuild, :install_and_run, [:default, ~w(--sourcemap=inline --watch)]},
tailwind: {Tailwind, :install_and_run, [:default, ~w(--watch)]}
]
#+end_src
Phoenix's LiveReload is pretty slick -- it will automatically reload your browser page if CSS, JS, or Elixir Web modules, etc are changed:
#+begin_src elixir :tangle config/dev.exs
config :arcology, ArcologyWeb.Endpoint,
live_reload: [
patterns: [
~r"priv/static/.*(js|css|png|jpeg|jpg|gif|svg)$",
~r"priv/gettext/.*(po)$",
~r"lib/arcology_web/(controllers|live|components)/.*(ex|heex)$"
]
]
#+end_src
Enable dev routes for dashboard and mailbox
#+begin_src elixir :tangle config/dev.exs
config :arcology, dev_routes: true
#+end_src
Do not include metadata nor timestamps in development logs
#+begin_src elixir :tangle config/dev.exs
config :logger, :console, format: "[$level] $message\n"
#+end_src
Set a higher stacktrace during development. The auto-generated comment says "Avoid configuring such in production as building large stacktraces may be expensive."
#+begin_src elixir :tangle config/dev.exs
config :phoenix, :stacktrace_depth, 20
#+end_src
Initialize plugs at runtime for faster development compilation:
#+begin_src elixir :tangle config/dev.exs
config :phoenix, :plug_init_mode, :runtime
#+end_src
Disable [[https://github.com/swoosh/swoosh][swoosh]] api client as it is only required for production adapters, this is for the Mailer, and I probably don't care to set this up in prod, but yanno...
#+begin_src elixir :tangle config/dev.exs
config :swoosh, :api_client, false
#+end_src
** Test
I promise myself I'll figure out how to write tests for Arcology this time around.............
#+begin_src elixir :tangle config/test.exs
import Config
# Configure your database
#
# The MIX_TEST_PARTITION environment variable can be used
# to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information.
config :arcology, Arcology.Repo,
database: Path.expand("../arcology_test.db", Path.dirname(__ENV__.file)),
pool_size: 5,
pool: Ecto.Adapters.SQL.Sandbox
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :arcology, ArcologyWeb.Endpoint,
http: [ip: {127, 0, 0, 1}, port: 4002],
secret_key_base: "4EDyvZHi6tCmgax6tx/v9e6L9kQmXt8qnhsqYE78k7P82uy71Ge7Zl6jPMolA+RR",
server: false
# In test we don't send emails.
config :arcology, Arcology.Mailer, adapter: Swoosh.Adapters.Test
# Disable swoosh api client as it is only required for production adapters.
config :swoosh, :api_client, false
# Print only warnings and errors during test
config :logger, level: :warning
# Initialize plugs at runtime for faster test compilation
config :phoenix, :plug_init_mode, :runtime
#+end_src
** NEXT Prod
This is mostly overridden by the runtime configuration below.
#+begin_src elixir :tangle config/prod.exs
import Config
# For production, don't forget to configure the url host
# to something meaningful, Phoenix uses this information
# when generating URLs.
# Note we also include the path to a cache manifest
# containing the digested version of static files. This
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :arcology, ArcologyWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
# Configures Swoosh API Client
config :swoosh, api_client: Swoosh.ApiClient.Finch, finch_name: Arcology.Finch
# Do not print debug messages in production
config :logger, level: :info
# Runtime production configuration, including reading
# of environment variables, is done on config/runtime.exs.
#+end_src
** Runtime
These helpers are used to set up the process with environment variables at runtime. These will be important when it comes to deploying Arcology on [[id:20211120T220054.226284][the Wobserver]].
Only start the web server if =PHX_SERVER= is set; this is done automatically by the =bin/server= wrapper script installed by =mix phx.gen.release=.
#+begin_src elixir :tangle config/runtime.exs
if System.get_env("PHX_SERVER") do
config :arcology, ArcologyWeb.Endpoint, server: true
end
#+end_src
Only =prod= is runtime configured:
#+begin_src elixir :tangle config/runtime.exs
if config_env() == :prod do
#+end_src
The database is pointed to with =DATABASE_PATH=:
#+begin_src elixir :tangle config/runtime.exs
database_path =
System.get_env("DATABASE_PATH") ||
raise """
environment variable DATABASE_PATH is missing.
For example: /etc/arcology/arcology.db
"""
config :arcology, Arcology.Repo,
database: database_path,
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "5")
#+end_src
The secret key base is used to sign/encrypt cookies and other secrets. A default value is used in config/dev.exs and config/test.exs but you want to use a different value for prod and you most likely don't want to check this value into version control, so we use an environment variable instead.
#+begin_src elixir :tangle config/runtime.exs
secret_key_base =
System.get_env("SECRET_KEY_BASE") ||
raise """
environment variable SECRET_KEY_BASE is missing.
You can generate one by calling: mix phx.gen.secret
"""
#+end_src
=PHX_HOST= and =PORT= are used to configure the route/URL generation. The app is configured to listen only to the loopback IPv4 interface since [[id:e4998eda-d14a-48ee-9661-3d7d1bead53c][Nginx]] will be handling the actual edge and SSL and whatnot. Otherwise it would be configured according to [[https://hexdocs.pm/plug_cowboy/Plug.Cowboy.html][Plug.Cowboy]] documentation.
#+begin_src elixir :tangle config/runtime.exs
host = System.get_env("PHX_HOST") || "example.com"
port = String.to_integer(System.get_env("PORT") || "4000")
config :arcology, ArcologyWeb.Endpoint,
url: [host: host, port: 443, scheme: "https"],
http: [
ip: {127, 0, 0, 1},
port: port
],
secret_key_base: secret_key_base
#+end_src
These aren't used right now:
#+begin_src elixir
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key
# to your endpoint configuration:
#
# config :arcology, ArcologyWeb.Endpoint,
# https: [
# ...,
# port: 443,
# cipher_suite: :strong,
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH")
# ]
#
# The `cipher_suite` is set to `:strong` to support only the
# latest and more secure SSL ciphers. This means old browsers
# and clients may not be supported. You can set it to
# `:compatible` for wider support.
#
# `:keyfile` and `:certfile` expect an absolute path to the key
# and cert in disk or a relative path inside priv, for example
# "priv/ssl/server.key". For all supported SSL configuration
# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
#
# We also recommend setting `force_ssl` in your endpoint, ensuring
# no data is ever sent via http, always redirecting to https:
#
# config :arcology, ArcologyWeb.Endpoint,
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.
# ## Configuring the mailer
#
# In production you need to configure the mailer to use a different adapter.
# Also, you may need to configure the Swoosh API client of your choice if you
# are not using SMTP. Here is an example of the configuration:
#
# config :arcology, Arcology.Mailer,
# adapter: Swoosh.Adapters.Mailgun,
# api_key: System.get_env("MAILGUN_API_KEY"),
# domain: System.get_env("MAILGUN_DOMAIN")
#
# For this example you need include a HTTP client required by Swoosh API client.
# Swoosh supports Hackney and Finch out of the box:
#
# config :swoosh, :api_client, Swoosh.ApiClient.Hackney
#
# See https://hexdocs.pm/swoosh/Swoosh.html#module-installation for details.
#+end_src
#+begin_src elixir :tangle config/runtime.exs
end
#+end_src