Skip to content
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/nice-taxis-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@core/sync-service': patch
---

Add optional PhoenixLiveDashboard with configurable port to listen on.
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ Real-time sync for Postgres.
- [What is Electric?](#what-is-electric)
- [Getting Started](#getting-started)
- [HTTP API Docs](#http-api-docs)
- [Phoenix LiveDashboard](#phoenix-livedashboard)
- [Developing Electric](#developing-electric)
- [Mac setup](#mac-setup)
- [Contributing](#contributing)
Expand Down Expand Up @@ -98,6 +99,20 @@ Again, see the [Quickstart](https://electric-sql.com/docs/quickstart) and the [D

The HTTP API is defined in an [OpenAPI spec](https://swagger.io/specification/) in [website/electric-api.yaml](./website/electric-api.yaml).

## Phoenix LiveDashboard

Electric includes an optional [Phoenix LiveDashboard](https://github.com/phoenixframework/phoenix_live_dashboard) for real-time monitoring of the running system (VM metrics, process info, ETS tables, etc.).

To enable it, set the `ELECTRIC_LIVE_DASHBOARD_PORT` environment variable:

```sh
ELECTRIC_LIVE_DASHBOARD_PORT=4000
```

The dashboard will be available at `http://localhost:4000` (or whichever port you choose). When the variable is not set, the dashboard is not started.

> **WARNING: The LiveDashboard endpoint is completely unauthenticated.** Anyone with network access to the port can view internal system state. In production, you **must** restrict access to this port using firewall rules, network policies, or similar controls. Do not expose it to the public internet.

## Developing Electric

We use [asdf](https://asdf-vm.com/) to install Elixir, Erlang, and Node.js. Versions are defined in [.tool-versions](.tool-versions).
Expand Down
2 changes: 1 addition & 1 deletion packages/sync-service/.formatter.exs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"],
import_deps: [:plug, :stream_data]
import_deps: [:plug, :stream_data, :phoenix]
]
30 changes: 30 additions & 0 deletions packages/sync-service/config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ replication_stream_id =
)

prometheus_port = env!("ELECTRIC_PROMETHEUS_PORT", :integer, nil)
live_dashboard_port = env!("ELECTRIC_LIVE_DASHBOARD_PORT", :integer, nil)

call_home_telemetry_url =
env!(
Expand Down Expand Up @@ -240,6 +241,7 @@ config :electric,
env!("ELECTRIC_TELEMETRY_LONG_MESSAGE_QUEUE_DISABLE_THRESHOLD", :integer, nil),
telemetry_statsd_host: statsd_host,
prometheus_port: prometheus_port,
live_dashboard_port: live_dashboard_port,
db_pool_size: env!("ELECTRIC_DB_POOL_SIZE", :integer, nil),
replication_stream_id: replication_stream_id,
replication_slot_temporary?: env!("CLEANUP_REPLICATION_SLOTS_ON_SHUTDOWN", :boolean, nil),
Expand Down Expand Up @@ -387,3 +389,31 @@ if Electric.telemetry_enabled?() do
config :opentelemetry, processors: []
end
end

# Phoenix LiveDashboard Endpoint Configuration
#
# WARNING: The dashboard is completely unauthenticated and exposes internal
# system state (VM metrics, process info, ETS tables, etc.). In production,
# ensure the dashboard port is firewalled or otherwise restricted to trusted
# networks only.
if live_dashboard_port do
dashboard_ip =
if env!("ELECTRIC_LISTEN_ON_IPV6", :boolean, false),
do: {0, 0, 0, 0, 0, 0, 0, 0},
else: {0, 0, 0, 0}

config :electric, Electric.LiveDashboardEndpoint,
adapter: Bandit.PhoenixAdapter,
http: [
port: live_dashboard_port,
ip: dashboard_ip
],
Comment thread
alco marked this conversation as resolved.
server: true,
render_errors: [
formats: [html: Electric.ErrorView],
layout: false
],
live_view: [signing_salt: "r5zw+GcXjt3wP3Z/snFRqQ5uH2cm8Vb7ldc8t0POZdo="],
secret_key_base: Base.encode64(:crypto.strong_rand_bytes(48)),
pubsub_server: Electric.PubSub
end
12 changes: 11 additions & 1 deletion packages/sync-service/lib/electric/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ defmodule Electric.Application do
application_telemetry(config),
[{Electric.StackSupervisor, Keyword.put(config, :name, Electric.StackSupervisor)}],
api_server_children(config),
prometheus_endpoint(Electric.Config.get_env(:prometheus_port))
prometheus_endpoint(Electric.Config.get_env(:prometheus_port)),
live_dashboard_endpoint(Application.get_env(:electric, :live_dashboard_port))
Comment thread
alco marked this conversation as resolved.
Outdated
])
end

Expand Down Expand Up @@ -270,6 +271,15 @@ defmodule Electric.Application do
]
end

defp live_dashboard_endpoint(nil), do: []

defp live_dashboard_endpoint(_port) do
[
{Phoenix.PubSub, name: Electric.PubSub},
Electric.LiveDashboardEndpoint
Comment thread
alco marked this conversation as resolved.
Outdated
]
end

@doc false
# REQUIRED (but undocumented) public API for Phoenix.Sync
def api_server do
Expand Down
10 changes: 10 additions & 0 deletions packages/sync-service/lib/electric/error_view.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Electric.ErrorView do
Comment thread
alco marked this conversation as resolved.
Outdated
@moduledoc """
Error view for the LiveDashboard endpoint.
Handles rendering of HTTP errors.
"""

def render(template, _assigns) do
Phoenix.Controller.status_message_from_template(template)
end
end
12 changes: 12 additions & 0 deletions packages/sync-service/lib/electric/favicon_controller.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule Electric.FaviconController do
Comment thread
alco marked this conversation as resolved.
Outdated
@moduledoc """
Simple controller to handle favicon requests.
Returns a 204 No Content response to avoid 500 errors.
"""

use Phoenix.Controller, formats: [:html]

def show(conn, _params) do
send_resp(conn, 204, "")
end
end
44 changes: 44 additions & 0 deletions packages/sync-service/lib/electric/live_dashboard_endpoint.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
defmodule Electric.LiveDashboardEndpoint do
Comment thread
alco marked this conversation as resolved.
Outdated
@moduledoc """
Phoenix Endpoint for serving LiveDashboard on a separate port.
This runs independently from the main Plug-based HTTP server.

**WARNING: This endpoint is completely unauthenticated.** It exposes internal
system state (VM metrics, process info, etc.). In production, ensure the
dashboard port is not publicly accessible — use firewall rules or network
policies to restrict access.
"""

use Phoenix.Endpoint, otp_app: :electric

# LiveView socket for dashboard interactions
socket "/live", Phoenix.LiveView.Socket,
websocket: true,
longpoll: true

# Serve static assets for LiveDashboard
plug Plug.Static,
at: "/",
from: :phoenix_live_dashboard,
gzip: false,
only: ~w(assets fonts images priv)

# Session configuration for LiveView
plug Plug.Session,
store: :cookie,
key: "_live_dashboard_key",
signing_salt: "abc43s8Z",
same_site: "Lax"

# Parse request body for LiveView
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
json_decoder: Jason

plug Plug.MethodOverride
plug Plug.Head

# Route all requests to the LiveDashboard router
plug Electric.LiveDashboardRouter
end
26 changes: 26 additions & 0 deletions packages/sync-service/lib/electric/live_dashboard_router.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
defmodule Electric.LiveDashboardRouter do
Comment thread
alco marked this conversation as resolved.
Outdated
@moduledoc """
Phoenix Router for LiveDashboard.
Mounts the dashboard at the root path.
"""

use Phoenix.Router
import Phoenix.LiveDashboard.Router

pipeline :browser do
plug :accepts, ["html", "json"]
plug :fetch_session
plug :put_root_layout, html: {Phoenix.LiveDashboard.LayoutView, :root}
plug :protect_from_forgery
plug :put_secure_browser_headers
end

scope "/" do
pipe_through :browser

# Handle favicon requests gracefully
get "/favicon.ico", Electric.FaviconController, :show

live_dashboard "/", ecto_repos: []
end
end
3 changes: 2 additions & 1 deletion packages/sync-service/mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ defmodule Electric.MixProject do
{:remote_ip, "~> 1.2"},
{:req, "~> 0.5"},
{:stream_split, "~> 0.1"},
{:tz, "~> 0.28"}
{:tz, "~> 0.28"},
{:phoenix_live_dashboard, "~> 0.8"}
],
dev_and_test_deps(),
telemetry_deps(Mix.target())
Expand Down
11 changes: 9 additions & 2 deletions packages/sync-service/mix.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
%{
"acceptor_pool": {:hex, :acceptor_pool, "1.0.1", "d88c2e8a0be9216cf513fbcd3e5a4beb36bee3ff4168e85d6152c6f899359cdb", [:rebar3], [], "hexpm", "f172f3d74513e8edd445c257d596fc84dbdd56d2c6fa287434269648ae5a421e"},
"backoff": {:hex, :backoff, "1.1.6", "83b72ed2108ba1ee8f7d1c22e0b4a00cfe3593a67dbc792799e8cce9f42f796b", [:rebar3], [], "hexpm", "cf0cfff8995fb20562f822e5cc47d8ccf664c5ecdc26a684cbe85c225f9d7c39"},
"bandit": {:hex, :bandit, "1.10.3", "1e5d168fa79ec8de2860d1b4d878d97d4fbbe2fdbe7b0a7d9315a4359d1d4bb9", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "99a52d909c48db65ca598e1962797659e3c0f1d06e825a50c3d75b74a5e2db18"},
"bandit": {:hex, :bandit, "1.10.4", "02b9734c67c5916a008e7eb7e2ba68aaea6f8177094a5f8d95f1fb99069aac17", [:mix], [{:hpax, "~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}, {:plug, "~> 1.18", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:thousand_island, "~> 1.0", [hex: :thousand_island, repo: "hexpm", optional: false]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "a5faf501042ac1f31d736d9d4a813b3db4ef812e634583b6a457b0928798a51d"},
"cc_precompiler": {:hex, :cc_precompiler, "0.1.11", "8c844d0b9fb98a3edea067f94f616b3f6b29b959b6b3bf25fee94ffe34364768", [:mix], [{:elixir_make, "~> 0.7", [hex: :elixir_make, repo: "hexpm", optional: false]}], "hexpm", "3427232caf0835f94680e5bcf082408a70b48ad68a5f5c0b02a3bea9f3a075b9"},
"chatterbox": {:hex, :ts_chatterbox, "0.15.1", "5cac4d15dd7ad61fc3c4415ce4826fc563d4643dee897a558ec4ea0b1c835c9c", [:rebar3], [{:hpack, "~> 0.3.0", [hex: :hpack_erl, repo: "hexpm", optional: false]}], "hexpm", "4f75b91451338bc0da5f52f3480fa6ef6e3a2aeecfc33686d6b3d0a0948f31aa"},
"combine": {:hex, :combine, "0.10.0", "eff8224eeb56498a2af13011d142c5e7997a80c8f5b97c499f84c841032e429f", [:mix], [], "hexpm", "1b1dbc1790073076580d0d1d64e42eae2366583e7aecd455d1215b0d16f2451b"},
Expand Down Expand Up @@ -41,11 +41,17 @@
"opentelemetry_telemetry": {:hex, :opentelemetry_telemetry, "1.1.2", "410ab4d76b0921f42dbccbe5a7c831b8125282850be649ee1f70050d3961118a", [:mix, :rebar3], [{:opentelemetry_api, "~> 1.3", [hex: :opentelemetry_api, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.1", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "641ab469deb181957ac6d59bce6e1321d5fe2a56df444fc9c19afcad623ab253"},
"otel_metric_exporter": {:hex, :otel_metric_exporter, "0.4.3", "c8e47eae9f222e100b590eb95246e49ea4a376bf3595067ee089ddfc7169405a", [:mix], [{:finch, "~> 0.19", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:protobuf, "~> 0.15", [hex: :protobuf, repo: "hexpm", optional: false]}, {:retry, "~> 0.19", [hex: :retry, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "6cdb0a9bcd6f4bee3e70b7b8664af8b6d23156e978ccedde47782f56b6636531"},
"pg_query_ex": {:hex, :pg_query_ex, "0.10.0", "3dc3a20f90173bd6e893db58062a6bbeda583bd7962793235da0cde046ac52da", [:make, :mix], [{:elixir_make, "~> 0.4", [hex: :elixir_make, repo: "hexpm", optional: false]}, {:protox, "~> 2.0", [hex: :protox, repo: "hexpm", optional: false]}], "hexpm", "783f2082ff9534298eab5570a9317f510c425fcbe4ae88d502561207fdd1bdd9"},
"phoenix": {:hex, :phoenix, "1.8.5", "919db335247e6d4891764dc3063415b0d2457641c5f9b3751b5df03d8e20bbcf", [:mix], [{:bandit, "~> 1.0", [hex: :bandit, repo: "hexpm", optional: true]}, {: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.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "83b2bb125127e02e9f475c8e3e92736325b5b01b0b9b05407bcb4083b7a32485"},
"phoenix_html": {:hex, :phoenix_html, "4.3.0", "d3577a5df4b6954cd7890c84d955c470b5310bb49647f0a114a6eeecc850f7ad", [:mix], [], "hexpm", "3eaa290a78bab0f075f791a46a981bbe769d94bc776869f4f3063a14f30497ad"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.7", "405880012cb4b706f26dd1c6349125bfc903fb9e44d1ea668adaf4e04d4884b7", [: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]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "3a8625cab39ec261d48a13b7468dc619c0ede099601b084e343968309bd4d7d7"},
"phoenix_live_view": {:hex, :phoenix_live_view, "1.1.28", "8a8e123d018025f756605a2fb02a4854f0d3cd7b207f710fef1fd5d9d72d0254", [:mix], [{:igniter, ">= 0.6.16 and < 1.0.0-0", [hex: :igniter, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:lazy_html, "~> 0.1.0", [hex: :lazy_html, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0 or ~> 1.8.0-rc", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [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]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "24faad535b65089642c3a7d84088109dc58f49c1f1c5a978659855d643466353"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.2.0", "ff3a5616e1bed6804de7773b92cbccfc0b0f473faf1f63d7daf1206c7aeaaa6f", [:mix], [], "hexpm", "adc313a5bf7136039f63cfd9668fde73bba0765e0614cba80c06ac9460ff3e96"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"plug": {:hex, :plug, "1.19.1", "09bac17ae7a001a68ae393658aa23c7e38782be5c5c00c80be82901262c394c0", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "560a0017a8f6d5d30146916862aaf9300b7280063651dd7e532b8be168511e62"},
"plug_crypto": {:hex, :plug_crypto, "2.1.1", "19bda8184399cb24afa10be734f84a16ea0a2bc65054e23a62bb10f06bc89491", [:mix], [], "hexpm", "6470bce6ffe41c8bd497612ffde1a7e4af67f36a15eea5f921af71cf3e11247c"},
"postgrex": {:hex, :postgrex, "0.22.0", "fb027b58b6eab1f6de5396a2abcdaaeb168f9ed4eccbb594e6ac393b02078cbd", [:mix], [{:db_connection, "~> 2.9", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "a68c4261e299597909e03e6f8ff5a13876f5caadaddd0d23af0d0a61afcc5d84"},
"protobuf": {:hex, :protobuf, "0.13.0", "7a9d9aeb039f68a81717eb2efd6928fdf44f03d2c0dfdcedc7b560f5f5aae93d", [:mix], [{:jason, "~> 1.2", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "21092a223e3c6c144c1a291ab082a7ead32821ba77073b72c68515aa51fef570"},
"protox": {:hex, :protox, "2.0.4", "2a86ae3699696c5d92e15804968ce6a6827a8d9516d0bbabcf16584dec710ae1", [:mix], [], "hexpm", "8ac5a03bb84da4c75d76dc29cd46008081c2068ad0f6f0da4c051093d6e24c01"},
"protox": {:hex, :protox, "2.0.7", "fa4639568a045f034fc756ad62b0edf59c934f6ad2aa163a8ba457209d54f8cb", [:mix], [], "hexpm", "42efb28326e7003f4a2d3a809176b8ba2f01a950e36f6470364b64c288919cb2"},
"remote_ip": {:hex, :remote_ip, "1.2.0", "fb078e12a44414f4cef5a75963c33008fe169b806572ccd17257c208a7bc760f", [:mix], [{:combine, "~> 0.10", [hex: :combine, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "2ff91de19c48149ce19ed230a81d377186e4412552a597d6a5137373e5877cb7"},
"repatch": {:hex, :repatch, "1.6.1", "e2bc55d7358de5727a7d989886d9aebd6497ccab4232b41dcae54f8fd6539c19", [:mix], [{:ex2ms, "~> 1.7.0", [hex: :ex2ms, repo: "hexpm", optional: false]}], "hexpm", "486f80b503fad097ae9ff33f3c7ad3a24c2bad85e694d76ff214e15d13cf9d25"},
"req": {:hex, :req, "0.5.17", "0096ddd5b0ed6f576a03dde4b158a0c727215b15d2795e59e0916c6971066ede", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.17", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0.6 or ~> 2.1", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "0b8bc6ffdfebbc07968e59d3ff96d52f2202d0536f10fef4dc11dc02a2a43e39"},
Expand All @@ -63,4 +69,5 @@
"tls_certificate_check": {:hex, :tls_certificate_check, "1.31.0", "9a910b54d8cb96cc810cabf4c0129f21360f82022b20180849f1442a25ccbb04", [:rebar3], [{:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "9d2b41b128d5507bd8ad93e1a998e06d0ab2f9a772af343f4c00bf76c6be1532"},
"tz": {:hex, :tz, "0.28.1", "717f5ffddfd1e475e2a233e221dc0b4b76c35c4b3650b060c8e3ba29dd6632e9", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:mint, "~> 1.6", [hex: :mint, repo: "hexpm", optional: true]}], "hexpm", "bfdca1aa1902643c6c43b77c1fb0cb3d744fd2f09a8a98405468afdee0848c8a"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.9", "43dc3ba6d89ef5dec5b1d0a39698436a1e856d000d84bf31a3149862b01a287f", [:mix], [{:bandit, ">= 0.6.0", [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.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "5534d5c9adad3c18a0f58a9371220d75a803bf0b9a3d87e6fe072faaeed76a08"},
}
Loading