From 12fab59a63c86c7847b55a04fa1c893305d8944b Mon Sep 17 00:00:00 2001 From: Zoey de Souza Pessanha Date: Fri, 30 Aug 2024 02:23:36 -0300 Subject: [PATCH] feat: follow base SDK update --- .github/workflows/ci.yml | 61 +++++----- .github/workflows/release.yml | 4 +- LICENSE | 14 +-- flake.lock | 8 +- flake.nix | 10 +- lib/supabase/go_true.ex | 151 ++++-------------------- lib/supabase/go_true/admin.ex | 41 +++---- lib/supabase/go_true/admin_behaviour.ex | 16 +-- lib/supabase/go_true/admin_handler.ex | 1 + lib/supabase/go_true/live_view.ex | 12 +- lib/supabase/go_true/plug.ex | 1 - lib/supabase/go_true/user_handler.ex | 34 +++--- lib/supabase/go_true/validations.ex | 2 + lib/supabase/go_true_behaviour.ex | 17 +-- mix.exs | 8 +- mix.lock | 38 +++--- 16 files changed, 157 insertions(+), 261 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a87a3ef..911454d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,38 +2,39 @@ name: ci on: push: - branches: [ main ] + branches: + - main pull_request: - branches: [ main ] + branches: + - main jobs: - build: + lint: runs-on: ubuntu-latest - env: - GHCR_USERNAME: ${{ github.actor }} - GHCR_TOKEN: ${{ secrets.GHCR_TOKEN }} - FORCE_COLOR: 1 + + strategy: + matrix: + elixir: [1.17.0] + otp: [27.0] + steps: - - uses: actions/checkout@v3 - - name: Put back the git branch into git (Earthly uses it for tagging) - run: | - branch="" - if [ -n "$GITHUB_HEAD_REF" ]; then - branch="$GITHUB_HEAD_REF" - else - branch="${GITHUB_REF##*/}" - fi - git checkout -b "$branch" || true - - name: Docker Login - run: docker login https://ghcr.io --username "$GHCR_USERNAME" --password "$GHCR_TOKEN" - - name: Download latest earthly - run: "sudo /bin/sh -c 'wget https://github.com/earthly/earthly/releases/latest/download/earthly-linux-amd64 -O /usr/local/bin/earthly && chmod +x /usr/local/bin/earthly'" - - - name: Earthly version - run: earthly --version - - - name: Run CI - run: earthly -P +ci - - - name: Run Tests - run: earthly -P +test + - name: Checkout code + uses: actions/checkout@v3 + + - name: Set up Elixir + uses: erlef/setup-beam@v1 + with: + elixir-version: ${{ matrix.elixir }} + otp-version: ${{ matrix.otp }} + + - name: Install dependencies + run: mix deps.get + + - name: Clean build + run: mix clean + + - name: Check code formatting + run: mix format --check-formatted + + - name: Run Credo + run: mix credo --strict diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4aec11c..c2e38c5 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -13,8 +13,8 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - elixir: [1.15.7] - otp: [26.1.2] + elixir: [1.17.0] + otp: [27.0] steps: - uses: actions/checkout@v3 - name: Set up Elixir diff --git a/LICENSE b/LICENSE index d448fa4..a115477 100644 --- a/LICENSE +++ b/LICENSE @@ -1,13 +1,7 @@ - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - Version 2, December 2004 +Copyright 2023 zoedsoupe - Copyright (C) 2023 Zoey Pessanha +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - Everyone is permitted to copy and distribute verbatim or modified - copies of this license document, and changing it is allowed as long - as the name is changed. +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. You just DO WHAT THE FUCK YOU WANT TO. +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/flake.lock b/flake.lock index cd953c6..555c356 100644 --- a/flake.lock +++ b/flake.lock @@ -20,16 +20,16 @@ }, "nixpkgs": { "locked": { - "lastModified": 1713564160, - "narHash": "sha256-YguPZpiejgzLEcO36/SZULjJQ55iWcjAmf3lYiyV1Fo=", + "lastModified": 1724819573, + "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "bc194f70731cc5d2b046a6c1b3b15f170f05999c", + "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-23.11", + "ref": "nixos-unstable", "repo": "nixpkgs", "type": "github" } diff --git a/flake.nix b/flake.nix index 2941d2c..56ef225 100644 --- a/flake.nix +++ b/flake.nix @@ -1,8 +1,8 @@ { - description = "Supabase GoTrue SDK for Elixir"; + description = "Supabase SDK for Elixir"; inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-23.11"; + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; flake-parts.url = "github:hercules-ci/flake-parts"; systems.url = "github:nix-systems/default"; }; @@ -19,9 +19,9 @@ system, ... }: let - inherit (pkgs.beam.interpreters) erlangR26; + inherit (pkgs.beam.interpreters) erlang_27; inherit (pkgs.beam) packagesWith; - beam = packagesWith erlangR26; + beam = packagesWith erlang_27; in { _module.args.pkgs = import inputs.nixpkgs { inherit system; @@ -31,7 +31,7 @@ mkShell { name = "gotrue-ex"; packages = with pkgs; - [beam.elixir_1_16] + [beam.elixir_1_17] ++ lib.optional stdenv.isLinux [inotify-tools] ++ lib.optional stdenv.isDarwin [ darwin.apple_sdk.frameworks.CoreServices diff --git a/lib/supabase/go_true.ex b/lib/supabase/go_true.ex index f7165c8..550d6d6 100644 --- a/lib/supabase/go_true.ex +++ b/lib/supabase/go_true.ex @@ -10,8 +10,6 @@ defmodule Supabase.GoTrue do And also refer to functions and submodules documentation for more information. """ - import Supabase.Client, only: [is_client: 1] - alias Supabase.Client alias Supabase.GoTrue.Schemas.SignInWithIdToken alias Supabase.GoTrue.Schemas.SignInWithOauth @@ -24,8 +22,6 @@ defmodule Supabase.GoTrue do alias Supabase.GoTrue.User alias Supabase.GoTrue.UserHandler - @opaque client :: pid | module - @behaviour Supabase.GoTrueBehaviour @doc """ @@ -41,9 +37,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.User{}} """ @impl true - def get_user(client, %Session{} = session) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, response} <- UserHandler.get_user(client, session.access_token) do + def get_user(%Client{} = client, %Session{} = session) do + with {:ok, response} <- UserHandler.get_user(client, session.access_token) do User.parse(response) end end @@ -61,9 +56,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.User{}} """ @impl true - def sign_in_with_id_token(client, credentials) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, credentials} <- SignInWithIdToken.parse(credentials) do + def sign_in_with_id_token(%Client{} = client, credentials) do + with {:ok, credentials} <- SignInWithIdToken.parse(credentials) do UserHandler.sign_in_with_id_token(client, credentials) end end @@ -81,9 +75,8 @@ defmodule Supabase.GoTrue do {:ok, atom, URI.t()} """ @impl true - def sign_in_with_oauth(client, credentials) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, credentials} <- SignInWithOauth.parse(credentials) do + def sign_in_with_oauth(%Client{} = client, credentials) do + with{:ok, credentials} <- SignInWithOauth.parse(credentials) do url = UserHandler.get_url_for_provider(client, credentials) {:ok, credentials.provider, url} end @@ -102,9 +95,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.Session{}} """ @impl true - def sign_in_with_otp(client, credentials) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, credentials} <- SignInWithOTP.parse(credentials) do + def sign_in_with_otp(%Client{} = client, credentials) do + with{:ok, credentials} <- SignInWithOTP.parse(credentials) do UserHandler.sign_in_with_otp(client, credentials) end end @@ -122,9 +114,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.Session{}} """ @impl true - def verify_otp(client, params) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, response} <- UserHandler.verify_otp(client, params) do + def verify_otp(%Client{} = client, params) do + with{:ok, response} <- UserHandler.verify_otp(client, params) do Session.parse(response) end end @@ -142,9 +133,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.User{}} """ @impl true - def sign_in_with_sso(client, credentials) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, credentials} <- SignInWithSSO.parse(credentials) do + def sign_in_with_sso(%Client{} = client, credentials) do + with{:ok, credentials} <- SignInWithSSO.parse(credentials) do UserHandler.sign_in_with_sso(client, credentials) end end @@ -162,9 +152,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.Session{}} """ @impl true - def sign_in_with_password(client, credentials) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, credentials} <- SignInWithPassword.parse(credentials), + def sign_in_with_password(%Client{} = client, credentials) do + with{:ok, credentials} <- SignInWithPassword.parse(credentials), {:ok, response} <- UserHandler.sign_in_with_password(client, credentials) do Session.parse(response) end @@ -183,9 +172,8 @@ defmodule Supabase.GoTrue do {:ok, %Supabase.GoTrue.User{}} """ @impl true - def sign_up(client, credentials) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, credentials} <- SignUpWithPassword.parse(credentials) do + def sign_up(%Client{} = client, credentials) do + with {:ok, credentials} <- SignUpWithPassword.parse(credentials) do UserHandler.sign_up(client, credentials) end end @@ -204,12 +192,10 @@ defmodule Supabase.GoTrue do iex> Supabase.GoTrue.reset_password_for_email(client, "john@example.com", redirect_to: "http://localohst:4000/reset-pass") :ok """ - @spec reset_password_for_email(Client.client(), String.t, opts) :: :ok | {:error, term} + @spec reset_password_for_email(Client.t(), String.t, opts) :: :ok | {:error, term} when opts: [redirect_to: String.t] | [captcha_token: String.t] | [redirect_to: String.t, captcha_token: String.t] - def reset_password_for_email(client, email, opts) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client) do + def reset_password_for_email(%Client{} = client, email, opts) do UserHandler.recover_password(client, email, Map.new(opts)) - end end @doc """ @@ -226,12 +212,10 @@ defmodule Supabase.GoTrue do iex> Supabase.GoTrue.resend(client, "john@example.com", redirect_to: "http://localohst:4000/reset-pass") :ok """ - @spec resend(Client.client(), String.t, opts) :: :ok | {:error, term} + @spec resend(Client.t(), String.t, opts) :: :ok | {:error, term} when opts: [redirect_to: String.t] | [captcha_token: String.t] | [redirect_to: String.t, captcha_token: String.t] - def resend(client, email, opts) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client) do + def resend(%Client{} = client, email, opts) do UserHandler.resend_signup(client, email, Map.new(opts)) - end end @doc """ @@ -241,17 +225,16 @@ defmodule Supabase.GoTrue do - `client` - The `Supabase` client to use for the request. - `conn` - The current `Plug.Conn` or `Phoenix.LiveView.Socket` to get current user - `attrs` - Check `UserParams` - + ## Examples iex> params = %{email: "another@example.com", password: "new-pass"} iex> Supabase.GoTrue.update_user(client, conn, params) {:ok, conn} """ - @spec update_user(Client.client, conn, UserParams.t) :: {:ok, conn} | {:error, term} + @spec update_user(Client.t, conn, UserParams.t) :: {:ok, conn} | {:error, term} when conn: Plug.Conn.t | Phoenix.LiveView.Socket.t - def update_user(client, conn, attrs) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, params} <- UserParams.parse(attrs) do + def update_user(%Client{} = client, conn, attrs) do + with{:ok, params} <- UserParams.parse(attrs) do if conn.assigns.current_user do UserHandler.update_user(client, conn, params) else @@ -259,90 +242,4 @@ defmodule Supabase.GoTrue do end end end - - defmacrop wrap_gotrue_functions(module) do - quote unquote: false, bind_quoted: [module: module] do - for {fun, arity} <- module.__info__(:functions) do - if arity == 1 do - quote do - @doc """ - Check `Supabase.GoTrue.#{unquote(fun)}/#{unquote(arity)}` - """ - def unquote(fun)() do - apply(unquote(module), unquote(fun), [@client]) - end - end - else - args = for idx <- 2..arity, do: Macro.var(:"arg#{idx}", module) - - quote do - @doc """ - Check `Supabase.GoTrue.#{unquote(fun)}/#{unquote(arity)}` - """ - def unquote(fun)(unquote_splicing(args)) do - args = [unquote_splicing(args)] - apply(unquote(module), unquote(fun), [@client | args]) - end - end - end - end - end - end - - defmacro __using__([{:client, client} | opts]) do - config = Macro.escape(Keyword.get(opts, :config, %{})) - - gotrue_functions = wrap_gotrue_functions(Supabase.GoTrue) - gotrue_admin_functions = wrap_gotrue_functions(Supabase.GoTrue.Admin) - - quote location: :keep do - @client unquote(client) - - def child_spec(opts) do - %{ - id: __MODULE__, - start: {__MODULE__, :start_link, [opts]}, - type: :supervisor - } - end - - def start_link(opts \\ []) do - manage_clients? = Application.get_env(:supabase_potion, :manage_clients, true) - - if manage_clients? do - Supabase.init_client(unquote(client), unquote(config)) - else - - base_url = - Application.get_env(:supabase_potion, :supabase_base_url) || - raise Supabase.MissingSupabaseConfig, :url - - api_key = - Application.get_env(:supabase_potion, :supabase_api_key) || - raise Supabase.MissingSupabaseConfig, :key - - config = - unquote(config) - |> Map.put(:conn, %{base_url: base_url, api_key: api_key}) - |> Map.put(:name, unquote(client)) - - opts = [name: unquote(client), client_info: config] - Supabase.Client.start_link(opts) - end - |> then(fn - {:ok, pid} -> {:ok, pid} - {:error, {:already_started, pid}} -> {:ok, pid} - err -> err - end) - end - - unquote(gotrue_functions) - - defmodule Admin do - @client unquote(client) - - unquote(gotrue_admin_functions) - end - end - end end diff --git a/lib/supabase/go_true/admin.ex b/lib/supabase/go_true/admin.ex index fd33fcf..beb025e 100644 --- a/lib/supabase/go_true/admin.ex +++ b/lib/supabase/go_true/admin.ex @@ -6,8 +6,6 @@ defmodule Supabase.GoTrue.Admin do You can find more information about the GoTrue admin API at https://supabase.io/docs/reference/javascript/auth-admin-api """ - import Supabase.Client, only: [is_client: 1] - alias Supabase.Client alias Supabase.Fetcher alias Supabase.GoTrue.AdminHandler @@ -35,15 +33,13 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.sign_out(pid | client_name, session, "global") """ @impl true - def sign_out(client, %Session{} = session, scope) when is_client(client) and scope in @scopes do - with {:ok, client} <- Client.retrieve_client(client) do + def sign_out(%Client{} = client, %Session{} = session, scope) when scope in @scopes do case AdminHandler.sign_out(client, session.access_token, scope) do {:ok, _} -> :ok {:error, :not_found} -> :ok {:error, :unauthorized} -> :ok err -> err end - end end @doc """ @@ -58,9 +54,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.invite_user_by_email(pid | client_name, "john@example.com", %{}) """ @impl true - def invite_user_by_email(client, email, options \\ %{}) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, options} <- InviteUserParams.parse(options), + def invite_user_by_email(%Client{} = client, email, options \\ %{}) do + with {:ok, options} <- InviteUserParams.parse(options), {:ok, response} <- AdminHandler.invite_user(client, email, options) do User.parse(response) end @@ -77,9 +72,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.generate_link(pid | client_name, %{}) """ @impl true - def generate_link(client, attrs) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, params} <- GenerateLink.parse(attrs), + def generate_link(%Client{} = client, attrs) do + with {:ok, params} <- GenerateLink.parse(attrs), {:ok, response} <- AdminHandler.generate_link(client, params) do GenerateLink.properties(response) end @@ -96,9 +90,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.create_user(pid | client_name, %{}) """ @impl true - def create_user(client, attrs) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, params} <- AdminUserParams.parse(attrs), + def create_user(%Client{} = client, attrs) do + with {:ok, params} <- AdminUserParams.parse(attrs), {:ok, response} <- AdminHandler.create_user(client, params) do User.parse(response) end @@ -116,9 +109,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.update_user(pid | client_name, "user_id", %{}) """ @impl true - def delete_user(client, user_id, opts \\ [should_soft_delete: false]) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, _} <- AdminHandler.delete_user(client, user_id, opts) do + def delete_user(%Client{} = client, user_id, opts \\ [should_soft_delete: false]) do + with {:ok, _} <- AdminHandler.delete_user(client, user_id, opts) do :ok end end @@ -134,9 +126,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.get_user_by_id(pid | client_name, "user_id") """ @impl true - def get_user_by_id(client, user_id) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, response} <- AdminHandler.get_user(client, user_id) do + def get_user_by_id(%Client{} = client, user_id) do + with {:ok, response} <- AdminHandler.get_user(client, user_id) do User.parse(response) end end @@ -152,9 +143,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.list_users(pid | client_name, %{}) """ @impl true - def list_users(client, params \\ %{}) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, params} <- PaginationParams.page_params(params), + def list_users(%Client{} = client, params \\ %{}) do + with {:ok, params} <- PaginationParams.page_params(params), {:ok, response} <- AdminHandler.list_users(client, params), {:ok, users} <- User.parse_list(response.body["users"]) do total = Fetcher.get_header(response, "x-total-count") @@ -206,9 +196,8 @@ defmodule Supabase.GoTrue.Admin do iex> Supabase.GoTrue.Admin.update_user(pid | client_name, "user_id", %{}) """ @impl true - def update_user_by_id(client, user_id, attrs) when is_client(client) do - with {:ok, client} <- Client.retrieve_client(client), - {:ok, params} <- AdminUserParams.parse_update(attrs), + def update_user_by_id(%Client{} = client, user_id, attrs) do + with {:ok, params} <- AdminUserParams.parse_update(attrs), {:ok, response} <- AdminHandler.update_user(client, user_id, params) do User.parse(response) end diff --git a/lib/supabase/go_true/admin_behaviour.ex b/lib/supabase/go_true/admin_behaviour.ex index 7161690..2e1de31 100644 --- a/lib/supabase/go_true/admin_behaviour.ex +++ b/lib/supabase/go_true/admin_behaviour.ex @@ -8,15 +8,15 @@ defmodule Supabase.GoTrue.AdminBehaviour do @type scope :: :global | :local | :others @type invite_options :: %{data: map, redirect_to: String.t()} - @callback sign_out(Client.client(), Session.t(), scope) :: :ok | {:error, atom} - @callback invite_user_by_email(Client.client(), email, invite_options) :: :ok | {:error, atom} + @callback sign_out(Client.t(), Session.t(), scope) :: :ok | {:error, atom} + @callback invite_user_by_email(Client.t(), email, invite_options) :: :ok | {:error, atom} when email: String.t() - @callback generate_link(Client.client(), map) :: {:ok, String.t()} | {:error, atom} - @callback create_user(Client.client(), map) :: {:ok, User.t()} | {:error, atom} - @callback list_users(Client.client()) :: {:ok, list(User.t())} | {:error, atom} - @callback get_user_by_id(Client.client(), Ecto.UUID.t()) :: {:ok, User.t()} | {:error, atom} - @callback update_user_by_id(Client.client(), Ecto.UUID.t(), map) :: + @callback generate_link(Client.t(), map) :: {:ok, String.t()} | {:error, atom} + @callback create_user(Client.t(), map) :: {:ok, User.t()} | {:error, atom} + @callback list_users(Client.t()) :: {:ok, list(User.t())} | {:error, atom} + @callback get_user_by_id(Client.t(), Ecto.UUID.t()) :: {:ok, User.t()} | {:error, atom} + @callback update_user_by_id(Client.t(), Ecto.UUID.t(), map) :: {:ok, User.t()} | {:error, atom} - @callback delete_user(Client.client(), Ecto.UUID.t(), keyword) :: + @callback delete_user(Client.t(), Ecto.UUID.t(), keyword) :: {:ok, User.t()} | {:error, atom} end diff --git a/lib/supabase/go_true/admin_handler.ex b/lib/supabase/go_true/admin_handler.ex index c4fbf01..031f041 100644 --- a/lib/supabase/go_true/admin_handler.ex +++ b/lib/supabase/go_true/admin_handler.ex @@ -77,6 +77,7 @@ defmodule Supabase.GoTrue.AdminHandler do client |> Client.retrieve_auth_url(@users) + |> URI.new!() |> URI.append_query(query) |> Fetcher.get(nil, headers, resolve_json: false) |> case do diff --git a/lib/supabase/go_true/live_view.ex b/lib/supabase/go_true/live_view.ex index e9ad74e..a12f470 100644 --- a/lib/supabase/go_true/live_view.ex +++ b/lib/supabase/go_true/live_view.ex @@ -119,10 +119,7 @@ defmodule Supabase.GoTrue.LiveView do socket |> assign_new(:current_user, fn -> session = %Session{access_token: user_token} - case GoTrue.get_user(@client, session) do - {:ok, %User{} = user} -> user - _ -> nil - end + maybe_get_current_user(session) end) |> assign_new(:user_token, fn -> user_token end) @@ -130,4 +127,11 @@ defmodule Supabase.GoTrue.LiveView do assign_new(socket, :current_user, fn -> nil end) end end + + defp maybe_get_current_user(session) do + case GoTrue.get_user(@client, session) do + {:ok, %User{} = user} -> user + _ -> nil + end + end end diff --git a/lib/supabase/go_true/plug.ex b/lib/supabase/go_true/plug.ex index 06e8a31..bcd4827 100644 --- a/lib/supabase/go_true/plug.ex +++ b/lib/supabase/go_true/plug.ex @@ -122,7 +122,6 @@ defmodule Supabase.GoTrue.Plug do |> redirect(to: @not_authenticated_path) end - @doc """ Retrieves the current user from the session or a signed cookie, assigning it to the connection's assigns. diff --git a/lib/supabase/go_true/user_handler.ex b/lib/supabase/go_true/user_handler.ex index 68a8cbc..529250c 100644 --- a/lib/supabase/go_true/user_handler.ex +++ b/lib/supabase/go_true/user_handler.ex @@ -36,10 +36,10 @@ defmodule Supabase.GoTrue.UserHandler do end def verify_otp(%Client{} = client, %{} = params) do - with {:ok, request} <- VerifyOTP.to_request(params), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @verify_otp_uri), - endpoint = append_query(endpoint, %{redirect_to: get_in(request, [:options, :redirect_to])}) do + with {:ok, request} <- VerifyOTP.to_request(params) do + headers = Fetcher.apply_client_headers(client) + endpoint = Client.retrieve_auth_url(client, @verify_otp_uri) + endpoint = append_query(endpoint, %{redirect_to: get_in(request, [:options, :redirect_to])}) Fetcher.post(endpoint, request, headers, resolve_json: true) end end @@ -137,7 +137,7 @@ defmodule Supabase.GoTrue.UserHandler do end def recover_password(%Client{} = client, email, %{} = opts) - when client.auth.flow_type == :pkce do + when client.auth.flow_type == :pkce do {challenge, method} = generate_pkce() body = %{ @@ -188,13 +188,14 @@ defmodule Supabase.GoTrue.UserHandler do end def update_user(%Client{} = client, conn, %{} = params) - when client.auth.flow_type == :pkce do + when client.auth.flow_type == :pkce do {challenge, method} = generate_pkce() - access_token = case conn do - %Plug.Conn{} -> Plug.Conn.get_session(conn, :user_token) - %Phoenix.LiveView.Socket{} -> conn.assigns.user_token - end + access_token = + case conn do + %Plug.Conn{} -> Plug.Conn.get_session(conn, :user_token) + %Phoenix.LiveView.Socket{} -> conn.assigns.user_token + end body = Map.merge(params, %{code_challenge: challenge, code_challenge_method: method}) headers = Fetcher.apply_client_headers(client, access_token) @@ -212,10 +213,11 @@ defmodule Supabase.GoTrue.UserHandler do end def update_user(%Client{} = client, conn, %{} = params) do - access_token = case conn do - %Plug.Conn{} -> Plug.Conn.get_session(conn, :user_token) - %Phoenix.LiveView.Socket{} -> conn.assigns.user_token - end + access_token = + case conn do + %Plug.Conn{} -> Plug.Conn.get_session(conn, :user_token) + %Phoenix.LiveView.Socket{} -> conn.assigns.user_token + end headers = Fetcher.apply_client_headers(client, access_token) endpoint = Client.retrieve_auth_url(client, @single_user_uri) @@ -256,6 +258,10 @@ defmodule Supabase.GoTrue.UserHandler do URI.append_query(uri, encoded) end + defp append_query(uri, query) when is_binary(uri) do + append_query(URI.new!(uri), query) + end + defp generate_pkce do verifier = PKCE.generate_verifier() challenge = PKCE.generate_challenge(verifier) diff --git a/lib/supabase/go_true/validations.ex b/lib/supabase/go_true/validations.ex index 1e8d687..038c07d 100644 --- a/lib/supabase/go_true/validations.ex +++ b/lib/supabase/go_true/validations.ex @@ -1,4 +1,6 @@ defmodule Supabase.GoTrue.Validations do + @moduledoc false + import Ecto.Changeset @spec validate_required_inclusion(changeset :: Ecto.Changeset.t(), fields :: [atom()]) :: Ecto.Changeset.t() diff --git a/lib/supabase/go_true_behaviour.ex b/lib/supabase/go_true_behaviour.ex index 889d43d..181109d 100644 --- a/lib/supabase/go_true_behaviour.ex +++ b/lib/supabase/go_true_behaviour.ex @@ -14,17 +14,18 @@ defmodule Supabase.GoTrueBehaviour do @type sign_in_response :: {:ok, Session.t()} + | {:error, Ecto.Changeset.t()} | {:error, :invalid_grant} | {:error, {:invalid_grant, :invalid_credentials}} - @callback get_user(Client.client(), Session.t()) :: {:ok, User.t()} | {:error, atom} - @callback sign_in_with_oauth(Client.client(), SignInWithOauth.t()) :: {:ok, atom, URI.t()} - @callback verify_otp(Client.client(), VerifyOTP.t()) :: sign_in_response - @callback sign_in_with_otp(Client.client(), SignInWithOTP.t()) :: :ok | {:ok, Ecto.UUID.t()} - @callback sign_in_with_sso(Client.client(), SignInWithSSO.t()) :: {:ok, URI.t()} - @callback sign_in_with_id_token(Client.client(), SignInWithIdToken.t()) :: sign_in_response - @callback sign_in_with_password(Client.client(), SignInWithPassword.t()) :: + @callback get_user(Client.t(), Session.t()) :: {:ok, User.t()} | {:error, atom} + @callback sign_in_with_oauth(Client.t(), SignInWithOauth.t()) :: {:ok, atom, URI.t()} + @callback verify_otp(Client.t(), VerifyOTP.t()) :: sign_in_response + @callback sign_in_with_otp(Client.t(), SignInWithOTP.t()) :: :ok | {:ok, Ecto.UUID.t()} + @callback sign_in_with_sso(Client.t(), SignInWithSSO.t()) :: {:ok, URI.t()} + @callback sign_in_with_id_token(Client.t(), SignInWithIdToken.t()) :: sign_in_response + @callback sign_in_with_password(Client.t(), SignInWithPassword.t()) :: sign_in_response - @callback sign_up(Client.client(), SignUpWithPassword.t()) :: + @callback sign_up(Client.t(), SignUpWithPassword.t()) :: {:ok, User.t(), binary} | {:error, atom} end diff --git a/mix.exs b/mix.exs index 7c4c6f8..1b1d812 100644 --- a/mix.exs +++ b/mix.exs @@ -1,7 +1,7 @@ defmodule SupabaseAuth.MixProject do use Mix.Project - @version "0.3.7" + @version "0.3.8" @source_url "https://github.com/zoedsoupe/gotrue-ex" def project do @@ -28,9 +28,11 @@ defmodule SupabaseAuth.MixProject do defp deps do [ {:plug, "~> 1.15"}, - {:supabase_potion, "~> 0.3"}, + {:supabase_potion, "~> 0.4"}, {:phoenix_live_view, "~> 0.20"}, - {:ex_doc, ">= 0.0.0", runtime: false} + {:ex_doc, ">= 0.0.0", runtime: false}, + {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, + {:dialyxir, "~> 1.3", only: [:dev], runtime: false} ] end diff --git a/mix.lock b/mix.lock index 37a3994..232f31d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,34 +1,34 @@ %{ "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, - "castore": {:hex, :castore, "1.0.7", "b651241514e5f6956028147fe6637f7ac13802537e895a724f90bf3e36ddd1dd", [:mix], [], "hexpm", "da7785a4b0d2a021cd1292a60875a784b6caef71e76bf4917bdee1f390455cf5"}, - "credo": {:hex, :credo, "1.7.3", "05bb11eaf2f2b8db370ecaa6a6bda2ec49b2acd5e0418bc106b73b07128c0436", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "35ea675a094c934c22fb1dca3696f3c31f2728ae6ef5a53b5d648c11180a4535"}, + "castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, + "credo": {:hex, :credo, "1.7.7", "771445037228f763f9b2afd612b6aa2fd8e28432a95dbbc60d8e03ce71ba4446", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "8bc87496c9aaacdc3f90f01b7b0582467b69b4bd2441fe8aae3109d843cc2f2e"}, "decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, - "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"}, - "ecto": {:hex, :ecto, "3.11.2", "e1d26be989db350a633667c5cda9c3d115ae779b66da567c68c80cfb26a8c9ee", [:mix], [{:decimal, "~> 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", "3c38bca2c6f8d8023f2145326cc8a80100c3ffe4dcbd9842ff867f7fc6156c65"}, - "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "ex_doc": {:hex, :ex_doc, "0.32.2", "f60bbeb6ccbe75d005763e2a328e6f05e0624232f2393bc693611c2d3ae9fa0e", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "a4480305cdfe7fdfcbb77d1092c76161626d9a7aa4fb698aee745996e34602df"}, - "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, + "ecto": {:hex, :ecto, "3.12.2", "bae2094f038e9664ce5f089e5f3b6132a535d8b018bd280a485c2f33df5c0ce1", [:mix], [{:decimal, "~> 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", "492e67c70f3a71c6afe80d946d3ced52ecc57c53c9829791bfff1830ff5a1f0c"}, + "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, + "ex_doc": {:hex, :ex_doc, "0.34.2", "13eedf3844ccdce25cfd837b99bea9ad92c4e511233199440488d217c92571e8", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "5ce5f16b41208a50106afed3de6a2ed34f4acfd65715b82a0b84b49d995f95c1"}, + "file_system": {:hex, :file_system, "1.0.1", "79e8ceaddb0416f8b8cd02a0127bdbababe7bf4a23d2a395b983c1f8b3f73edd", [:mix], [], "hexpm", "4414d1f38863ddf9120720cd976fce5bdde8e91d8283353f0e31850fa89feb9e"}, "finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [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 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, - "hpax": {:hex, :hpax, "0.2.0", "5a58219adcb75977b2edce5eb22051de9362f08236220c9e859a47111c194ff5", [:mix], [], "hexpm", "bea06558cdae85bed075e6c036993d43cd54d447f76d8190a8db0dc5893fa2f1"}, - "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, + "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"}, "makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"}, - "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"}, - "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, - "mint": {:hex, :mint, "1.6.0", "88a4f91cd690508a04ff1c3e28952f322528934be541844d54e0ceb765f01d5e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "3c5ae85d90a5aca0a49c0d8b67360bbe407f3b54f1030a111047ff988e8fefaa"}, - "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, + "makeup_erlang": {:hex, :makeup_erlang, "1.0.1", "c7f58c120b2b5aa5fd80d540a89fdf866ed42f1f3994e4fe189abebeab610839", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "8a89a1eeccc2d798d6ea15496a6e4870b75e014d1af514b1b71fa33134f57814"}, + "mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, + "mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, + "nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, - "phoenix": {:hex, :phoenix, "1.7.12", "1cc589e0eab99f593a8aa38ec45f15d25297dd6187ee801c8de8947090b5a9d3", [: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.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", "d646192fbade9f485b01bc9920c139bfdd19d0f8df3d73fd8eaf2dfbe0d2837c"}, + "phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [: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.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", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"}, "phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"}, - "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.14", "70fa101aa0539e81bed4238777498f6215e9dda3461bdaa067cad6908110c364", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {: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 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", "82f6d006c5264f979ed5eb75593d808bbe39020f20df2e78426f4f2d570e2402"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {: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 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", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"}, "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.15.3", "712976f504418f6dff0a3e554c40d705a9bcf89a7ccef92fc6a5ef8f16a30a97", [: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", "cc4365a3c010a56af402e0809208873d113e9c38c401cabd88027ef4f5c01fd2"}, + "plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [: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", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"}, "plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"}, - "supabase_potion": {:hex, :supabase_potion, "0.3.7", "2b535db03ee22c7c30c18b4732f72a435559e6e94c68b5c282cd120311065641", [:mix], [{:ecto, "~> 3.10", [hex: :ecto, repo: "hexpm", optional: false]}, {:ex_doc, ">= 0.0.0", [hex: :ex_doc, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "4048c79b7d091334c95b75dbee1b0ed524c0ff678a62882f92d3c8d81aece611"}, - "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, + "supabase_potion": {:hex, :supabase_potion, "0.4.1", "82536a87eb570f4a803d5ada066652aa55096d4886790b7c926044243baffe9c", [:mix], [{:ecto, "~> 3.10", [hex: :ecto, repo: "hexpm", optional: false]}, {:ex_doc, ">= 0.0.0", [hex: :ex_doc, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "f5300e616c8b9c2114e89bfd581c82e2749e530125aa724f70e7096e37ea583d"}, + "telemetry": {:hex, :telemetry, "1.3.0", "fedebbae410d715cf8e7062c96a1ef32ec22e764197f70cda73d82778d61e7a2", [:rebar3], [], "hexpm", "7015fc8919dbe63764f4b4b87a95b7c0996bd539e0d499be6ec9d7f3875b79e6"}, "websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"}, - "websock_adapter": {:hex, :websock_adapter, "0.5.6", "0437fe56e093fd4ac422de33bf8fc89f7bc1416a3f2d732d8b2c8fd54792fe60", [: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", "e04378d26b0af627817ae84c92083b7e97aca3121196679b73c73b99d0d133ea"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [: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", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"}, }