From 7bba861ef6d6aaae2957978fec6e7fd9a3f44fbc Mon Sep 17 00:00:00 2001 From: zoey Date: Wed, 15 Jan 2025 22:30:13 -0300 Subject: [PATCH] feat: follow supabase_potion release (#5) --- .dialyzerignore | 0 .github/workflows/ci.yml | 155 +++++++++++- .gitignore | 2 + .wakatime-project | 1 + Earthfile | 33 --- README.md | 13 +- flake.lock | 63 +---- flake.nix | 63 ++--- lib/supabase/go_true.ex | 6 +- lib/supabase/go_true/admin.ex | 20 +- lib/supabase/go_true/admin_behaviour.ex | 19 +- lib/supabase/go_true/admin_handler.ex | 76 +++--- lib/supabase/go_true/auth.ex | 2 +- lib/supabase/go_true/live_view.ex | 11 +- lib/supabase/go_true/plug.ex | 20 +- lib/supabase/go_true/request.ex | 18 ++ .../go_true/schemas/invite_user_params.ex | 4 +- .../go_true/schemas/sign_in_with_id_token.ex | 4 +- .../go_true/schemas/sign_in_with_oauth.ex | 4 +- .../go_true/schemas/sign_in_with_otp.ex | 4 +- .../go_true/schemas/sign_in_with_password.ex | 14 +- .../go_true/schemas/sign_in_with_sso.ex | 4 +- lib/supabase/go_true/schemas/user_params.ex | 9 + lib/supabase/go_true/schemas/verify_otp.ex | 20 +- lib/supabase/go_true/user_handler.ex | 232 +++++++++++------- lib/supabase/go_true_behaviour.ex | 32 +-- mix.exs | 15 +- mix.lock | 34 +-- test/supabase_test.exs | 74 ------ 29 files changed, 509 insertions(+), 443 deletions(-) create mode 100644 .dialyzerignore create mode 100644 .wakatime-project delete mode 100644 Earthfile create mode 100644 lib/supabase/go_true/request.ex delete mode 100644 test/supabase_test.exs diff --git a/.dialyzerignore b/.dialyzerignore new file mode 100644 index 0000000..e69de29 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 911454d..3c251f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,9 +12,12 @@ jobs: lint: runs-on: ubuntu-latest + env: + MIX_ENV: test + strategy: matrix: - elixir: [1.17.0] + elixir: [1.18.1] otp: [27.0] steps: @@ -27,8 +30,30 @@ jobs: elixir-version: ${{ matrix.elixir }} otp-version: ${{ matrix.otp }} - - name: Install dependencies - run: mix deps.get + - name: Cache Elixir deps + uses: actions/cache@v1 + id: deps-cache + with: + path: deps + key: ${{ runner.os }}-mix-${{ env.MIX_ENV }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} + + - name: Cache Elixir _build + uses: actions/cache@v1 + id: build-cache + with: + path: _build + key: ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} + + - name: Install deps + if: steps.deps-cache.outputs.cache-hit != 'true' + run: | + mix local.rebar --force + mix local.hex --force + mix deps.get --only ${{ env.MIX_ENV }} + + - name: Compile deps + if: steps.build-cache.outputs.cache-hit != 'true' + run: mix deps.compile --warnings-as-errors - name: Clean build run: mix clean @@ -38,3 +63,127 @@ jobs: - name: Run Credo run: mix credo --strict + + static-analisys: + runs-on: ubuntu-latest + + env: + MIX_ENV: test + + strategy: + matrix: + elixir: [1.18.1] + otp: [27.0] + + steps: + - 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: Cache Elixir deps + uses: actions/cache@v1 + id: deps-cache + with: + path: deps + key: ${{ runner.os }}-mix-${{ env.MIX_ENV }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} + + - name: Cache Elixir _build + uses: actions/cache@v1 + id: build-cache + with: + path: _build + key: ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} + + - name: Install deps + if: steps.deps-cache.outputs.cache-hit != 'true' + run: | + mix local.rebar --force + mix local.hex --force + mix deps.get --only ${{ env.MIX_ENV }} + + - name: Compile deps + if: steps.build-cache.outputs.cache-hit != 'true' + run: mix deps.compile --warnings-as-errors + + # Don't cache PLTs based on mix.lock hash, as Dialyzer can incrementally update even old ones + # Cache key based on Elixir & Erlang version (also useful when running in matrix) + - name: Restore PLT cache + uses: actions/cache/restore@v3 + id: plt_cache + with: + key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt + restore-keys: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt + path: priv/plts + + # Create PLTs if no cache was found + - name: Create PLTs + if: steps.plt_cache.outputs.cache-hit != 'true' + run: mix dialyzer --plt + + - name: Save PLT cache + uses: actions/cache/save@v3 + if: steps.plt_cache.outputs.cache-hit != 'true' + id: plt_cache_save + with: + key: ${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-plt + path: priv/plts + + - name: Run dialyzer + run: mix dialyzer --format github + + test: + runs-on: ubuntu-latest + + env: + MIX_ENV: test + + strategy: + matrix: + elixir: [1.18.1] + otp: [27.0] + + steps: + - 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: Cache Elixir deps + uses: actions/cache@v1 + id: deps-cache + with: + path: deps + key: ${{ runner.os }}-mix-${{ env.MIX_ENV }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} + + - name: Cache Elixir _build + uses: actions/cache@v1 + id: build-cache + with: + path: _build + key: ${{ runner.os }}-build-${{ env.MIX_ENV }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }} + + - name: Install deps + if: steps.deps-cache.outputs.cache-hit != 'true' + run: | + mix local.rebar --force + mix local.hex --force + mix deps.get --only ${{ env.MIX_ENV }} + + - name: Compile deps + if: steps.build-cache.outputs.cache-hit != 'true' + run: mix deps.compile --warnings-as-errors + + - name: Clean build + run: mix clean + + - name: Run tests + run: mix test diff --git a/.gitignore b/.gitignore index 3613e55..789bbf2 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,5 @@ result .elixir_ls/ .elixir-tools/ .lexical/ + +/priv/plts/ diff --git a/.wakatime-project b/.wakatime-project new file mode 100644 index 0000000..f735dcd --- /dev/null +++ b/.wakatime-project @@ -0,0 +1 @@ +gotrue-ex diff --git a/Earthfile b/Earthfile deleted file mode 100644 index c695654..0000000 --- a/Earthfile +++ /dev/null @@ -1,33 +0,0 @@ -VERSION 0.7 - -ARG MIX_ENV=test - -deps: - ARG ELIXIR=1.15.7 - ARG OTP=26.1.2 - FROM hexpm/elixir:${ELIXIR}-erlang-${OTP}-alpine-3.17.5 - RUN apk add --no-cache build-base - WORKDIR /src - RUN mix local.rebar --force - RUN mix local.hex --force - COPY mix.exs mix.lock ./ - COPY --dir lib . # check .earthlyignore - RUN mix deps.get - RUN mix deps.compile --force - RUN mix compile - SAVE ARTIFACT /src/_build AS LOCAL _build - SAVE ARTIFACT /src/deps AS LOCAL deps - -ci: - FROM +deps - COPY .formatter.exs . - RUN mix clean - RUN mix compile --warning-as-errors - RUN mix format --check-formatted - RUN mix credo --strict - -test: - FROM +deps - COPY mix.exs mix.lock ./ - COPY --dir lib ./ - RUN mix test diff --git a/README.md b/README.md index 3d60d03..c2bae12 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # Supabase GoTrue +> ![WARNING] +> This library is under development and for so expect breaking changes + [Auth](https://supabase.com/docs/guides/auth) implementation for the [Supabase Potion](https://hexdocs.pm/supabase_potion) SDK in Elixir. ## Installation @@ -7,8 +10,8 @@ ```elixir def deps do [ - {:supabase_potion, "~> 0.5"}, - {:supabase_gotrue, "~> 0.3"} + {:supabase_potion, "~> 0.6"}, + {:supabase_gotrue, "~> 0.4"} ] end ``` @@ -36,7 +39,7 @@ iex> Supabase.GoTrue.Admin.create_user(client, %{} = params) There are sample apps in the `examples` directory that demonstrate how to use the `Supabase.GoTrue` module in your application. -Check the [Supabase Potion examples showcase](https://github.com/zoedsoupe/supabase-ex?tab=readme-ov-file#examples)! +Check the [Supabase Potion examples showcase](https://github.com/supabase-community/supabase-ex?tab=readme-ov-file#examples)! ### Configuration @@ -85,7 +88,7 @@ end > [!WARNING] > The `client` options must be a module that implements the `Supabase.Client.Behaviour` behaviour. -> It should be a [Self Managed Client](https://github.com/zoedsoupe/supabase-ex?tab=readme-ov-file#self-managed-clients) but it can be a [One off Client](https://github.com/zoedsoupe/supabase-ex?tab=readme-ov-file#one-off-clients) if you correctly manage the client state on your application. +> It should be a [Self Managed Client](https://github.com/supabase-community/supabase-ex?tab=readme-ov-file#self-managed-clients) but it can be a [One off Client](https://github.com/supabase-community/supabase-ex?tab=readme-ov-file#one-off-clients) if you correctly manage the client state on your application. So, considering that you have something like this on your `config.exs`: @@ -204,7 +207,7 @@ end > [!WARNING] > The `client` options must be a module that implements the `Supabase.Client.Behaviour` behaviour. -> It should be a [Self Managed Client](https://github.com/zoedsoupe/supabase-ex?tab=readme-ov-file#self-managed-clients) but it can be a [One off Client](https://github.com/zoedsoupe/supabase-ex?tab=readme-ov-file#one-off-clients) if you correctly manage the client state on your application. +> It should be a [Self Managed Client](https://github.com/supabase-community/supabase-ex?tab=readme-ov-file#self-managed-clients) but it can be a [One off Client](https://github.com/supabase-community/supabase-ex?tab=readme-ov-file#one-off-clients) if you correctly manage the client state on your application. So, considering that you have something like this on your `config.exs`: diff --git a/flake.lock b/flake.lock index 555c356..527d389 100644 --- a/flake.lock +++ b/flake.lock @@ -1,77 +1,24 @@ { "nodes": { - "flake-parts": { - "inputs": { - "nixpkgs-lib": "nixpkgs-lib" - }, - "locked": { - "lastModified": 1712014858, - "narHash": "sha256-sB4SWl2lX95bExY2gMFG5HIzvva5AVMJd4Igm+GpZNw=", - "owner": "hercules-ci", - "repo": "flake-parts", - "rev": "9126214d0a59633752a136528f5f3b9aa8565b7d", - "type": "github" - }, - "original": { - "owner": "hercules-ci", - "repo": "flake-parts", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1724819573, - "narHash": "sha256-GnR7/ibgIH1vhoy8cYdmXE6iyZqKqFxQSVkFgosBh6w=", + "lastModified": 1736867362, + "narHash": "sha256-i/UJ5I7HoqmFMwZEH6vAvBxOrjjOJNU739lnZnhUln8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "71e91c409d1e654808b2621f28a327acfdad8dc2", + "rev": "9c6b49aeac36e2ed73a8c472f1546f6d9cf1addc", "type": "github" }, "original": { "owner": "NixOS", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs-lib": { - "locked": { - "dir": "lib", - "lastModified": 1711703276, - "narHash": "sha256-iMUFArF0WCatKK6RzfUJknjem0H9m4KgorO/p3Dopkk=", - "owner": "NixOS", - "repo": "nixpkgs", - "rev": "d8fe5e6c92d0d190646fb9f1056741a229980089", - "type": "github" - }, - "original": { - "dir": "lib", - "owner": "NixOS", - "ref": "nixos-unstable", + "ref": "nixos-24.11", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { - "flake-parts": "flake-parts", - "nixpkgs": "nixpkgs", - "systems": "systems" - } - }, - "systems": { - "locked": { - "lastModified": 1681028828, - "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", - "owner": "nix-systems", - "repo": "default", - "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", - "type": "github" - }, - "original": { - "owner": "nix-systems", - "repo": "default", - "type": "github" + "nixpkgs": "nixpkgs" } } }, diff --git a/flake.nix b/flake.nix index 56ef225..b8ba073 100644 --- a/flake.nix +++ b/flake.nix @@ -1,43 +1,34 @@ { description = "Supabase SDK for Elixir"; - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - flake-parts.url = "github:hercules-ci/flake-parts"; - systems.url = "github:nix-systems/default"; - }; + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + + outputs = {nixpkgs, ...}: let + inherit (nixpkgs.lib) genAttrs; + inherit (nixpkgs.lib.systems) flakeExposed; + forAllSystems = f: + genAttrs flakeExposed (system: f (import nixpkgs {inherit system;})); + in { + devShells = forAllSystems (pkgs: let + inherit (pkgs) mkShell; + inherit (pkgs.beam.interpreters) erlang_27; + inherit (pkgs.beam) packagesWith; + beam = packagesWith erlang_27; + elixir_1_18 = beam.elixir.override { + version = "1.18.1"; - outputs = { - flake-parts, - systems, - ... - } @ inputs: - flake-parts.lib.mkFlake {inherit inputs;} { - systems = import systems; - perSystem = { - pkgs, - system, - ... - }: let - inherit (pkgs.beam.interpreters) erlang_27; - inherit (pkgs.beam) packagesWith; - beam = packagesWith erlang_27; - in { - _module.args.pkgs = import inputs.nixpkgs { - inherit system; - config.allowUnfree = true; + src = pkgs.fetchFromGitHub { + owner = "elixir-lang"; + repo = "elixir"; + rev = "v1.18.1"; + sha256 = "sha256-zJNAoyqSj/KdJ1Cqau90QCJihjwHA+HO7nnD1Ugd768="; }; - devShells.default = with pkgs; - mkShell { - name = "gotrue-ex"; - packages = with pkgs; - [beam.elixir_1_17] - ++ lib.optional stdenv.isLinux [inotify-tools] - ++ lib.optional stdenv.isDarwin [ - darwin.apple_sdk.frameworks.CoreServices - darwin.apple_sdk.frameworks.CoreFoundation - ]; - }; }; - }; + in { + default = mkShell { + name = "supabase-ex"; + packages = with pkgs; [elixir_1_18 postgresql]; + }; + }); + }; } diff --git a/lib/supabase/go_true.ex b/lib/supabase/go_true.ex index a4157df..e26b94e 100644 --- a/lib/supabase/go_true.ex +++ b/lib/supabase/go_true.ex @@ -39,7 +39,7 @@ defmodule Supabase.GoTrue do @impl true def get_user(%Client{} = client, %Session{} = session) do with {:ok, response} <- UserHandler.get_user(client, session.access_token) do - User.parse(response) + User.parse(response.body) end end @@ -116,7 +116,7 @@ defmodule Supabase.GoTrue do @impl true def verify_otp(%Client{} = client, params) do with{:ok, response} <- UserHandler.verify_otp(client, params) do - Session.parse(response) + Session.parse(response.body) end end @@ -155,7 +155,7 @@ defmodule Supabase.GoTrue do 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) + Session.parse(response.body) end end diff --git a/lib/supabase/go_true/admin.ex b/lib/supabase/go_true/admin.ex index beb025e..c6b5dea 100644 --- a/lib/supabase/go_true/admin.ex +++ b/lib/supabase/go_true/admin.ex @@ -7,7 +7,7 @@ defmodule Supabase.GoTrue.Admin do """ alias Supabase.Client - alias Supabase.Fetcher + alias Supabase.Fetcher.Response alias Supabase.GoTrue.AdminHandler alias Supabase.GoTrue.Schemas.AdminUserParams alias Supabase.GoTrue.Schemas.GenerateLink @@ -36,8 +36,8 @@ defmodule Supabase.GoTrue.Admin 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 + {:error, %{code: :not_found}} -> :ok + {:error, %{code: :unauthorized}} -> :ok err -> err end end @@ -57,7 +57,7 @@ defmodule Supabase.GoTrue.Admin do 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) + User.parse(response.body) end end @@ -75,7 +75,7 @@ defmodule Supabase.GoTrue.Admin do def generate_link(%Client{} = client, attrs) do with {:ok, params} <- GenerateLink.parse(attrs), {:ok, response} <- AdminHandler.generate_link(client, params) do - GenerateLink.properties(response) + GenerateLink.properties(response.body) end end @@ -93,7 +93,7 @@ defmodule Supabase.GoTrue.Admin do def create_user(%Client{} = client, attrs) do with {:ok, params} <- AdminUserParams.parse(attrs), {:ok, response} <- AdminHandler.create_user(client, params) do - User.parse(response) + User.parse(response.body) end end @@ -128,7 +128,7 @@ defmodule Supabase.GoTrue.Admin do @impl true def get_user_by_id(%Client{} = client, user_id) do with {:ok, response} <- AdminHandler.get_user(client, user_id) do - User.parse(response) + User.parse(response.body) end end @@ -147,11 +147,11 @@ defmodule Supabase.GoTrue.Admin 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") + total = Response.get_header(response, "x-total-count") links = response - |> Fetcher.get_header("link", "") + |> Response.get_header("link", "") |> String.split(",", trim: true) next = parse_next_page_count(links) @@ -199,7 +199,7 @@ defmodule Supabase.GoTrue.Admin do 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) + User.parse(response.body) end end end diff --git a/lib/supabase/go_true/admin_behaviour.ex b/lib/supabase/go_true/admin_behaviour.ex index 2e1de31..baf0a01 100644 --- a/lib/supabase/go_true/admin_behaviour.ex +++ b/lib/supabase/go_true/admin_behaviour.ex @@ -8,15 +8,14 @@ defmodule Supabase.GoTrue.AdminBehaviour do @type scope :: :global | :local | :others @type invite_options :: %{data: map, redirect_to: String.t()} - @callback sign_out(Client.t(), Session.t(), scope) :: :ok | {:error, atom} - @callback invite_user_by_email(Client.t(), email, invite_options) :: :ok | {:error, atom} + @callback sign_out(Client.t(), Session.t(), scope) :: :ok | {:error, Supabase.Error.t()} + @callback invite_user_by_email(Client.t(), email, invite_options) :: + :ok | {:error, Supabase.Error.t()} when email: String.t() - @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.t(), Ecto.UUID.t(), keyword) :: - {:ok, User.t()} | {:error, atom} + @callback generate_link(Client.t(), map) :: Supabase.result(String.t()) + @callback create_user(Client.t(), map) :: Supabase.result(User.t()) + @callback list_users(Client.t()) :: Supabase.result(list(User.t())) + @callback get_user_by_id(Client.t(), Ecto.UUID.t()) :: Supabase.result(User.t()) + @callback update_user_by_id(Client.t(), Ecto.UUID.t(), map) :: Supabase.result(User.t()) + @callback delete_user(Client.t(), Ecto.UUID.t(), keyword) :: Supabase.result(User.t()) end diff --git a/lib/supabase/go_true/admin_handler.ex b/lib/supabase/go_true/admin_handler.ex index 031f041..d17a2d8 100644 --- a/lib/supabase/go_true/admin_handler.ex +++ b/lib/supabase/go_true/admin_handler.ex @@ -3,6 +3,8 @@ defmodule Supabase.GoTrue.AdminHandler do alias Supabase.Client alias Supabase.Fetcher + alias Supabase.Fetcher.Request + alias Supabase.GoTrue alias Supabase.GoTrue.Schemas.InviteUserParams @invite "/invite" @@ -18,81 +20,77 @@ defmodule Supabase.GoTrue.AdminHandler do end def sign_out(%Client{} = client, access_token, scope) do - endpoint = Client.retrieve_auth_url(client, sign_out(scope)) - headers = Fetcher.apply_client_headers(client, access_token) - Fetcher.post(endpoint, nil, headers, resolve_json: true) + client + |> GoTrue.Request.base(sign_out(scope)) + |> Request.with_method(:post) + |> Request.with_headers(%{"authorization" => "Bearer #{access_token}"}) + |> Fetcher.request() end def invite_user(%Client{} = client, email, %InviteUserParams{} = opts) do - headers = Fetcher.apply_client_headers(client, client.conn.api_key, %{"redirect_to" => opts.redirect_to}) body = %{email: email, data: opts.data} client - |> Client.retrieve_auth_url(@invite) - |> Fetcher.post(body, headers, resolve_json: true) + |> GoTrue.Request.base(@invite) + |> Request.with_body(body) + |> Request.with_method(:post) + |> Request.with_headers(%{"redirect_to" => opts.redirect_to}) + |> Fetcher.request() end def generate_link(%Client{} = client, %{type: _, redirect_to: redirect_to} = params) do - headers = Fetcher.apply_client_headers(client, client.conn.api_key, %{"redirect_to" => redirect_to}) - client - |> Client.retrieve_auth_url(@generate_link) - |> Fetcher.post(params, headers, resolve_json: true) + |> GoTrue.Request.base(@generate_link) + |> Request.with_body(params) + |> Request.with_method(:post) + |> Request.with_headers(%{"redirect_to" => redirect_to}) + |> Fetcher.request() end def create_user(%Client{} = client, params) do - headers = Fetcher.apply_client_headers(client, client.conn.api_key) - client - |> Client.retrieve_auth_url(@users) - |> Fetcher.post(params, headers, resolve_json: true) + |> GoTrue.Request.base(@users) + |> Request.with_body(params) + |> Request.with_method(:post) + |> Fetcher.request() end def delete_user(%Client{} = client, id, params) do - headers = Fetcher.apply_client_headers(client, client.conn.api_key) body = %{should_soft_delete: params[:should_soft_delete] || false} uri = single_user_endpoint(id) client - |> Client.retrieve_auth_url(uri) - |> Fetcher.delete(body, headers, resolve_json: true) + |> GoTrue.Request.base(uri) + |> Request.with_body(body) + |> Request.with_method(:delete) + |> Fetcher.request() end def get_user(%Client{} = client, id) do - headers = Fetcher.apply_client_headers(client, client.conn.api_key) uri = single_user_endpoint(id) client - |> Client.retrieve_auth_url(uri) - |> Fetcher.get(nil, headers, resolve_json: true) + |> GoTrue.Request.base(uri) + |> Fetcher.request() end def list_users(%Client{} = client, params) do - query = URI.encode_query %{ - page: to_string(Map.get(params, :page, 1)), - per_page: to_string(Map.get(params, :per_page, nil)) - } - - headers = Fetcher.apply_client_headers(client, client.conn.api_key) - client - |> Client.retrieve_auth_url(@users) - |> URI.new!() - |> URI.append_query(query) - |> Fetcher.get(nil, headers, resolve_json: false) - |> case do - {:ok, resp} when resp.status == 200 -> {:ok, Map.update!(resp, :body, &Jason.decode!/1)} - {:ok, resp} -> {:ok, Fetcher.format_response(resp)} - {:error, _} = err -> err - end + |> GoTrue.Request.base(@users) + |> Request.with_query(%{ + "page" => to_string(Map.get(params, :page, 1)), + "per_page" => to_string(Map.get(params, :per_page, nil)) + }) + |> Fetcher.request() end def update_user(%Client{} = client, id, params) do - headers = Fetcher.apply_client_headers(client, client.conn.api_key) uri = single_user_endpoint(id) client - |> Client.retrieve_auth_url(uri) - |> Fetcher.put(params, headers, resolve_json: true) + |> GoTrue.Request.base(uri) + |> Request.with_body(params) + |> Request.with_method(:put) + |> Fetcher.request() end end diff --git a/lib/supabase/go_true/auth.ex b/lib/supabase/go_true/auth.ex index e2f1560..ec048a7 100644 --- a/lib/supabase/go_true/auth.ex +++ b/lib/supabase/go_true/auth.ex @@ -53,7 +53,7 @@ defmodule Supabase.GoTrue.Auth do end defp network_failure_changeset(failure, attrs) do - cast(failure, attrs, ~w[max_retries max_interval]) + cast(failure, attrs, ~w[max_retries max_interval]a) end def parse_mfa(attrs) do diff --git a/lib/supabase/go_true/live_view.ex b/lib/supabase/go_true/live_view.ex index d952b9f..718e159 100644 --- a/lib/supabase/go_true/live_view.ex +++ b/lib/supabase/go_true/live_view.ex @@ -31,8 +31,9 @@ if Code.ensure_loaded?(Phoenix.LiveView) do """ defmacro __using__(opts) do + alias Supabase.GoTrue.MissingConfig module = __CALLER__.module - Supabase.GoTrue.MissingConfig.ensure_opts!(opts, module) + MissingConfig.ensure_opts!(opts, module) client = opts[:client] signed_in_path = opts[:signed_in_path] @@ -49,6 +50,7 @@ if Code.ensure_loaded?(Phoenix.LiveView) do alias Supabase.GoTrue.User Code.ensure_loaded!(unquote(client)) + if not function_exported?(unquote(client), :get_client, 0) do raise Supabase.GoTrue.MissingConfig, key: :client, module: unquote(module) end @@ -75,13 +77,13 @@ if Code.ensure_loaded?(Phoenix.LiveView) do session = %Session{access_token: user_token} {:ok, client} = @client.get_client() user_token && Admin.sign_out(client, session, scope) - # avoid compilation warnings - apply(unquote(endpoint), :broadcast_from, [ + + unquote(endpoint).broadcast_from( self(), socket.id, "disconnect", %{user: user} - ]) + ) end @doc """ @@ -112,7 +114,6 @@ if Code.ensure_loaded?(Phoenix.LiveView) do end """ def on_mount(:mount_current_user, _params, session, socket) do - IO.inspect(session, label: "SESSION") {:cont, mount_current_user(session, socket)} end diff --git a/lib/supabase/go_true/plug.ex b/lib/supabase/go_true/plug.ex index 5c5638e..6ec7523 100644 --- a/lib/supabase/go_true/plug.ex +++ b/lib/supabase/go_true/plug.ex @@ -19,8 +19,9 @@ if Code.ensure_loaded?(Plug) do """ defmacro __using__(opts) do + alias Supabase.GoTrue.MissingConfig module = __CALLER__.module - Supabase.GoTrue.MissingConfig.ensure_opts!(opts, module) + MissingConfig.ensure_opts!(opts, module) client = opts[:client] signed_in_path = opts[:signed_in_path] @@ -29,6 +30,7 @@ if Code.ensure_loaded?(Plug) do session_cookie_name = opts[:session_cookie] || "_supabase_go_true_session_cookie" session_cookie_options = opts[:session_cookie_options] || [sign: true, same_site: "Lax"] + # credo:disable-for-next-line quote do import Plug.Conn import Phoenix.Controller @@ -58,7 +60,7 @@ if Code.ensure_loaded?(Plug) do {:ok, client} = @client.get_client() with {:ok, session} <- GoTrue.sign_in_with_password(client, params) do - do_login(client, conn, session, params) + do_login(conn, session, params) end end @@ -66,7 +68,7 @@ if Code.ensure_loaded?(Plug) do {:ok, client} = @client.get_client() with {:ok, session} <- GoTrue.sign_in_with_id_token(client, params) do - do_login(client, conn, session, params) + do_login(conn, session, params) end end @@ -74,7 +76,7 @@ if Code.ensure_loaded?(Plug) do {:ok, client} = @client.get_client() with {:ok, session} <- GoTrue.sign_in_with_oauth(client, params) do - do_login(client, conn, session, params) + do_login(conn, session, params) end end @@ -82,7 +84,7 @@ if Code.ensure_loaded?(Plug) do {:ok, client} = @client.get_client() with {:ok, session} <- GoTrue.sign_in_with_sso(client, params) do - do_login(client, conn, session, params) + do_login(conn, session, params) end end @@ -90,14 +92,14 @@ if Code.ensure_loaded?(Plug) do {:ok, client} = @client.get_client() with {:ok, session} <- GoTrue.sign_in_with_otp(client, params) do - do_login(client, conn, session, params) + do_login(conn, session, params) end end - defp do_login(%Supabase.Client{} = client, conn, session, params) do + defp do_login(conn, session, params) do user_return_to = get_session(conn, :user_return_to) - :ok = Supabase.Client.update_access_token(client, session.access_token) + :ok = @client.set_auth(session.access_token) conn |> renew_session() @@ -136,7 +138,7 @@ if Code.ensure_loaded?(Plug) do live_socket_id = get_session(conn, :live_socket_id) if live_socket_id do - apply(unquote(endpoint), :broadcast, [live_socket_id, "disconnect", %{}]) + unquote(endpoint).broadcast(live_socket_id, "disconnect", %{}) end conn diff --git a/lib/supabase/go_true/request.ex b/lib/supabase/go_true/request.ex new file mode 100644 index 0000000..2c72ad8 --- /dev/null +++ b/lib/supabase/go_true/request.ex @@ -0,0 +1,18 @@ +defmodule Supabase.GoTrue.Request do + @moduledoc false + + alias Supabase.Fetcher.Request + + def base(%Supabase.Client{} = client, path) do + client + |> Request.new() + |> Request.with_auth_url(path) + |> Request.with_http_client(http_client()) + |> Request.with_headers(%{"accept" => "application/json"}) + end + + defp http_client do + alias Supabase.Fetcher.Adapter.Finch + Application.get_env(:supabase_gotrue, :http_client, Finch) + end +end diff --git a/lib/supabase/go_true/schemas/invite_user_params.ex b/lib/supabase/go_true/schemas/invite_user_params.ex index ede5c33..0447825 100644 --- a/lib/supabase/go_true/schemas/invite_user_params.ex +++ b/lib/supabase/go_true/schemas/invite_user_params.ex @@ -7,7 +7,9 @@ defmodule Supabase.GoTrue.Schemas.InviteUserParams do * `redirect_to` - The redirect URL. """ - use Supabase, :schema + use Ecto.Schema + + import Ecto.Changeset @type t :: %__MODULE__{ data: map, diff --git a/lib/supabase/go_true/schemas/sign_in_with_id_token.ex b/lib/supabase/go_true/schemas/sign_in_with_id_token.ex index 64fa673..56020e1 100644 --- a/lib/supabase/go_true/schemas/sign_in_with_id_token.ex +++ b/lib/supabase/go_true/schemas/sign_in_with_id_token.ex @@ -11,7 +11,9 @@ defmodule Supabase.GoTrue.Schemas.SignInWithIdToken do - `captcha_token` - The captcha token. """ - use Supabase, :schema + use Ecto.Schema + + import Ecto.Changeset @type t :: %__MODULE__{ provider: :google | :apple | :azure | :facebook, diff --git a/lib/supabase/go_true/schemas/sign_in_with_oauth.ex b/lib/supabase/go_true/schemas/sign_in_with_oauth.ex index 67fe2a6..9f80dc4 100644 --- a/lib/supabase/go_true/schemas/sign_in_with_oauth.ex +++ b/lib/supabase/go_true/schemas/sign_in_with_oauth.ex @@ -11,7 +11,9 @@ defmodule Supabase.GoTrue.Schemas.SignInWithOauth do - `skip_browser_redirect` - Whether to skip the browser redirect. """ - use Supabase, :schema + use Ecto.Schema + + import Ecto.Changeset alias Supabase.GoTrue.User.Identity diff --git a/lib/supabase/go_true/schemas/sign_in_with_otp.ex b/lib/supabase/go_true/schemas/sign_in_with_otp.ex index 2308596..9716622 100644 --- a/lib/supabase/go_true/schemas/sign_in_with_otp.ex +++ b/lib/supabase/go_true/schemas/sign_in_with_otp.ex @@ -12,7 +12,9 @@ defmodule Supabase.GoTrue.Schemas.SignInWithOTP do - `channel` - The channel for the OTP. """ - use Supabase, :schema + use Ecto.Schema + + import Ecto.Changeset import Supabase.GoTrue.Validations diff --git a/lib/supabase/go_true/schemas/sign_in_with_password.ex b/lib/supabase/go_true/schemas/sign_in_with_password.ex index f8b1814..71879b8 100644 --- a/lib/supabase/go_true/schemas/sign_in_with_password.ex +++ b/lib/supabase/go_true/schemas/sign_in_with_password.ex @@ -15,6 +15,18 @@ defmodule Supabase.GoTrue.Schemas.SignInWithPassword do import Ecto.Changeset + @type t :: %__MODULE__{ + email: String.t() | nil, + phone: String.t() | nil, + password: String.t() | nil, + options: + %__MODULE__.Options{ + data: map | nil, + captcha_token: String.t() | nil + } + | nil + } + @primary_key false embedded_schema do field(:email, :string) @@ -51,6 +63,6 @@ defmodule Supabase.GoTrue.Schemas.SignInWithPassword do end defp options_changeset(options, attrs) do - cast(options, attrs, ~w[email_redirect_to data captcha_token]a) + cast(options, attrs, ~w[data captcha_token]a) end end diff --git a/lib/supabase/go_true/schemas/sign_in_with_sso.ex b/lib/supabase/go_true/schemas/sign_in_with_sso.ex index 436e8c9..ae4dd98 100644 --- a/lib/supabase/go_true/schemas/sign_in_with_sso.ex +++ b/lib/supabase/go_true/schemas/sign_in_with_sso.ex @@ -10,7 +10,9 @@ defmodule Supabase.GoTrue.Schemas.SignInWithSSO do - `captcha_token` - The captcha token. """ - use Supabase, :schema + use Ecto.Schema + + import Ecto.Changeset import Supabase.GoTrue.Validations diff --git a/lib/supabase/go_true/schemas/user_params.ex b/lib/supabase/go_true/schemas/user_params.ex index 3d22d81..1828ce6 100644 --- a/lib/supabase/go_true/schemas/user_params.ex +++ b/lib/supabase/go_true/schemas/user_params.ex @@ -13,6 +13,15 @@ defmodule Supabase.GoTrue.Schemas.UserParams do import Ecto.Changeset + @type t :: %{ + data: map | nil, + email: String.t() | nil, + phone: String.t() | nil, + password: String.t() | nil, + nonce: String.t() | nil, + email_redirect_to: String.t() | nil + } + @types %{ data: :map, email: :string, diff --git a/lib/supabase/go_true/schemas/verify_otp.ex b/lib/supabase/go_true/schemas/verify_otp.ex index 7f34eee..f2e98f7 100644 --- a/lib/supabase/go_true/schemas/verify_otp.ex +++ b/lib/supabase/go_true/schemas/verify_otp.ex @@ -28,7 +28,9 @@ defmodule Supabase.GoTrue.Schemas.VerifyOTP do - `captcha_token` - The captcha token. """ - use Supabase, :schema + use Ecto.Schema + + import Ecto.Changeset @type options :: %{redirect_to: String.t(), captcha_token: String.t()} @type mobile :: %{phone: String.t(), token: String.t(), type: String.t(), options: options} @@ -96,16 +98,12 @@ defmodule Supabase.GoTrue.Schemas.VerifyOTP do defp options_changeset(%Ecto.Changeset{} = changeset) do if options = get_change(changeset, :options) do - {%{}, @options_types} - |> cast(options, Map.keys(@options_types)) - |> apply_action(:parse) - |> case do - {:ok, option} -> put_change(changeset, :options, option) - {:error, error_changeset} -> - for {field, {err, info}} <- error_changeset.errors, reduce: changeset do - changeset -> add_error(changeset, "options.#{field}", err, info) - end - end + {:ok, result} = + {%{}, @options_types} + |> cast(options, Map.keys(@options_types)) + |> apply_action(:parse) + + put_change(changeset, :options, result) else changeset end diff --git a/lib/supabase/go_true/user_handler.ex b/lib/supabase/go_true/user_handler.ex index d902cfa..1f60321 100644 --- a/lib/supabase/go_true/user_handler.ex +++ b/lib/supabase/go_true/user_handler.ex @@ -3,6 +3,8 @@ defmodule Supabase.GoTrue.UserHandler do alias Supabase.Client alias Supabase.Fetcher + alias Supabase.Fetcher.Request + alias Supabase.GoTrue alias Supabase.GoTrue.PKCE alias Supabase.GoTrue.Schemas.SignInRequest alias Supabase.GoTrue.Schemas.SignInWithIdToken @@ -25,20 +27,21 @@ defmodule Supabase.GoTrue.UserHandler do @reset_pass_uri "/recover" @resend_signup_uri "/resend" - def get_user(%Client{} = client, access_token) do - headers = Fetcher.apply_client_headers(client, access_token) - + def get_user(%Client{} = client, access_token) when is_binary(access_token) do client - |> Client.retrieve_auth_url(@single_user_uri) - |> Fetcher.get(nil, headers, resolve_json: true) + |> GoTrue.Request.base(@single_user_uri) + |> Request.with_headers(%{"authorization" => "Bearer #{access_token}"}) + |> Fetcher.request() end def verify_otp(%Client{} = client, %{} = params) 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) + with {:ok, body} <- VerifyOTP.to_request(params) do + client + |> GoTrue.Request.base(@verify_otp_uri) + |> Request.with_query(%{"redirect_to" => get_in(body, [:options, :redirect_to])}) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Fetcher.request() end end @@ -46,22 +49,38 @@ defmodule Supabase.GoTrue.UserHandler do when client.auth.flow_type == :pkce do {challenge, method} = generate_pkce() - with {:ok, request} <- SignInRequest.create(signin, challenge, method), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @otp_uri), - endpoint = append_query(endpoint, %{redirect_to: request.redirect_to}), - {:ok, response} <- Fetcher.post(endpoint, request, headers, resolve_json: true) do - if is_nil(signin.email), do: {:ok, response["data"]["message_id"]}, else: :ok + with {:ok, body} <- SignInRequest.create(signin, challenge, method) do + client + |> GoTrue.Request.base(@otp_uri) + |> Request.with_body(body) + |> Request.with_method(:post) + |> Request.with_query(%{"redirect_to" => body.redirect_to}) + |> Fetcher.request() + |> then(fn + {:ok, resp} -> + if is_nil(signin.email), do: {:ok, resp["data"]["message_id"]}, else: :ok + + err -> + err + end) end end def sign_in_with_otp(%Client{} = client, %SignInWithOTP{} = signin) do - with {:ok, request} <- SignInRequest.create(signin), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @otp_uri), - endpoint = append_query(endpoint, %{redirect_to: request.redirect_to}), - {:ok, response} <- Fetcher.post(endpoint, request, headers, resolve_json: true) do - if is_nil(signin.email), do: {:ok, response["data"]["message_id"]}, else: :ok + with {:ok, body} <- SignInRequest.create(signin) do + client + |> GoTrue.Request.base(@otp_uri) + |> Request.with_body(body) + |> Request.with_method(:post) + |> Request.with_query(%{"redirect_to" => body.redirect_to}) + |> Fetcher.request() + |> then(fn + {:ok, resp} -> + if is_nil(signin.email), do: {:ok, resp["data"]["message_id"]}, else: :ok + + err -> + err + end) end end @@ -69,22 +88,32 @@ defmodule Supabase.GoTrue.UserHandler do when client.auth.flow_type == :pkce do {challenge, method} = generate_pkce() - with {:ok, request} <- SignInRequest.create(signin, challenge, method), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @sso_uri), - endpoint = append_query(endpoint, %{redirect_to: request.redirect_to}), - {:ok, response} <- Fetcher.post(endpoint, request, headers, resolve_json: true) do - {:ok, response["data"]["url"]} + with {:ok, body} <- SignInRequest.create(signin, challenge, method) do + client + |> GoTrue.Request.base(@sso_uri) + |> Request.with_body(body) + |> Request.with_method(:post) + |> Request.with_query(%{"redirect_to" => body.redirect_to}) + |> Fetcher.request() + |> then(fn + {:ok, resp} -> {:ok, resp["data"]["url"]} + err -> err + end) end end def sign_in_with_sso(%Client{} = client, %SignInWithSSO{} = signin) do - with {:ok, request} <- SignInRequest.create(signin), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @sso_uri), - endpoint = append_query(endpoint, %{redirect_to: request.redirect_to}), - {:ok, response} <- Fetcher.post(endpoint, request, headers, resolve_json: true) do - {:ok, response["data"]["url"]} + with {:ok, body} <- SignInRequest.create(signin) do + client + |> GoTrue.Request.base(@sso_uri) + |> Request.with_body(body) + |> Request.with_method(:post) + |> Request.with_query(%{"redirect_to" => body.redirect_to}) + |> Fetcher.request() + |> then(fn + {:ok, resp} -> {:ok, resp["data"]["url"]} + err -> err + end) end end @@ -102,35 +131,44 @@ defmodule Supabase.GoTrue.UserHandler do end end - defp sign_in_request(%Client{} = client, %SignInRequest{} = request, grant_type) + defp sign_in_request(%Client{} = client, %SignInRequest{} = body, grant_type) when grant_type in @grant_types do - headers = Fetcher.apply_client_headers(client) - client - |> Client.retrieve_auth_url(@sign_in_uri) - |> append_query(%{grant_type: grant_type, redirect_to: request.redirect_to}) - |> Fetcher.post(request, headers, resolve_json: true) + |> GoTrue.Request.base(@sign_in_uri) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Request.with_query(%{ + "grant_type" => grant_type, + "redirect_to" => body.redirect_to + }) + |> Fetcher.request() end def sign_up(%Client{} = client, %SignUpWithPassword{} = signup) when client.auth.flow_type == :pkce do {challenge, method} = generate_pkce() - with {:ok, request} <- SignUpRequest.create(signup, challenge, method), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @sign_up_uri), - {:ok, response} <- Fetcher.post(endpoint, request, headers, resolve_json: true), - {:ok, user} <- User.parse(response) do + with {:ok, body} <- SignUpRequest.create(signup, challenge, method), + {:ok, resp} <- + client + |> GoTrue.Request.base(@sign_up_uri) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Fetcher.request(), + {:ok, user} <- User.parse(resp.body) do {:ok, user, challenge} end end def sign_up(%Client{} = client, %SignUpWithPassword{} = signup) do - with {:ok, request} <- SignUpRequest.create(signup), - headers = Fetcher.apply_client_headers(client), - endpoint = Client.retrieve_auth_url(client, @sign_up_uri), - {:ok, response} <- Fetcher.post(endpoint, request, headers, resolve_json: true) do - User.parse(response) + with {:ok, body} <- SignUpRequest.create(signup), + {:ok, resp} <- + client + |> GoTrue.Request.base(@sign_up_uri) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Fetcher.request() do + User.parse(resp.body) end end @@ -145,13 +183,14 @@ defmodule Supabase.GoTrue.UserHandler do go_true_meta_security: %{captcha_token: opts[:captcha_token]} } - headers = Fetcher.apply_client_headers(client) - endpoint = Client.retrieve_auth_url(client, @reset_pass_uri) - endpoint = append_query(endpoint, %{redirect_to: opts[:redirect_to]}) + builder = + client + |> GoTrue.Request.base(@reset_pass_uri) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Request.with_query(%{"redirect_to" => opts[:redirect_to]}) - with {:ok, _} <- Fetcher.post(endpoint, body, headers) do - :ok - end + with {:ok, _} <- Fetcher.request(builder), do: :ok end def recover_password(%Client{} = client, email, %{} = opts) do @@ -160,13 +199,14 @@ defmodule Supabase.GoTrue.UserHandler do go_true_meta_security: %{captcha_token: opts[:captcha_token]} } - headers = Fetcher.apply_client_headers(client) - endpoint = Client.retrieve_auth_url(client, @reset_pass_uri) - endpoint = append_query(endpoint, %{redirect_to: opts[:redirect_to]}) + builder = + client + |> GoTrue.Request.base(@reset_pass_uri) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Request.with_query(%{"redirect_to" => opts[:redirect_to]}) - with {:ok, _} <- Fetcher.post(endpoint, body, headers) do - :ok - end + with {:ok, _} <- Fetcher.request(builder), do: :ok end def resend_signup(%Client{} = client, email, %{} = opts) do @@ -176,13 +216,14 @@ defmodule Supabase.GoTrue.UserHandler do go_true_meta_security: %{captcha_token: opts[:captcha_token]} } - headers = Fetcher.apply_client_headers(client) - endpoint = Client.retrieve_auth_url(client, @resend_signup_uri) - endpoint = append_query(endpoint, %{redirect_to: opts[:redirect_to]}) + builder = + client + |> GoTrue.Request.base(@resend_signup_uri) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Request.with_query(%{"redirect_to" => opts[:redirect_to]}) - with {:ok, _} <- Fetcher.post(endpoint, body, headers) do - :ok - end + with {:ok, _} <- Fetcher.request(builder), do: :ok end def update_user(%Client{} = client, conn, %{} = params) @@ -196,20 +237,25 @@ defmodule Supabase.GoTrue.UserHandler do end body = Map.merge(params, %{code_challenge: challenge, code_challenge_method: method}) - headers = Fetcher.apply_client_headers(client, access_token) - endpoint = Client.retrieve_auth_url(client, @single_user_uri) - endpoint = append_query(endpoint, %{redirect_to: params[:email_redirect_to]}) + + builder = + client + |> GoTrue.Request.base(@single_user_uri) + |> Request.with_headers(%{"authorization" => "Bearer #{access_token}"}) + |> Request.with_method(:post) + |> Request.with_body(body) + |> Request.with_query(%{"redirect_to" => params[:email_redirect_to]}) session = %{"user_token" => access_token} auth_module = Supabase.GoTrue.get_auth_module!() - with {:ok, _} <- Fetcher.put(endpoint, body, headers) do + with {:ok, _} <- Fetcher.request(builder) do case conn do %Plug.Conn{} -> - {:ok, apply(auth_module, :fetch_current_user, [conn, nil])} + {:ok, auth_module.fetch_current_user(conn, nil)} %Phoenix.LiveView.Socket{} -> - {:ok, apply(auth_module, :mount_current_user, [session, conn])} + {:ok, auth_module.mount_current_user(session, conn)} end end end @@ -221,20 +267,24 @@ defmodule Supabase.GoTrue.UserHandler do %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) - endpoint = append_query(endpoint, %{redirect_to: params[:email_redirect_to]}) + builder = + client + |> GoTrue.Request.base(@single_user_uri) + |> Request.with_headers(%{"authorization" => "Bearer #{access_token}"}) + |> Request.with_method(:post) + |> Request.with_body(params) + |> Request.with_query(%{"redirect_to" => params[:email_redirect_to]}) session = %{"user_token" => access_token} auth_module = Supabase.GoTrue.get_auth_module!() - with {:ok, _} <- Fetcher.put(endpoint, params, headers) do + with {:ok, _} <- Fetcher.request(builder) do case conn do %Plug.Conn{} -> - {:ok, apply(auth_module, :fetch_current_user, [conn, nil])} + {:ok, auth_module.fetch_current_user(conn, nil)} %Phoenix.LiveView.Socket{} -> - {:ok, apply(auth_module, :mount_current_user, [session, conn])} + {:ok, auth_module.mount_current_user(session, conn)} end end end @@ -244,28 +294,22 @@ defmodule Supabase.GoTrue.UserHandler do {challenge, method} = generate_pkce() pkce_query = %{code_challenge: challenge, code_challenge_method: method} oauth_query = SignInWithOauth.options_to_query(oauth) + query = Map.merge(pkce_query, oauth_query) |> Map.new(fn {k, v} -> {to_string(k), v} end) client - |> Client.retrieve_auth_url(@oauth_uri) - |> append_query(Map.merge(pkce_query, oauth_query)) + |> GoTrue.Request.base(@oauth_uri) + |> Request.with_query(query) + |> then(& &1.url) end def get_url_for_provider(%Client{} = client, %SignInWithOauth{} = oauth) do oauth_query = SignInWithOauth.options_to_query(oauth) + query = Map.new(oauth_query, fn {k, v} -> {to_string(k), v} end) client - |> Client.retrieve_auth_url(@oauth_uri) - |> append_query(oauth_query) - end - - defp append_query(%URI{} = uri, query) do - query = Map.filter(query, &(not is_nil(elem(&1, 1)))) - encoded = URI.encode_query(query) - URI.append_query(uri, encoded) - end - - defp append_query(uri, query) when is_binary(uri) do - append_query(URI.new!(uri), query) + |> GoTrue.Request.base(@oauth_uri) + |> Request.with_query(query) + |> then(& &1.url) end defp generate_pkce do diff --git a/lib/supabase/go_true_behaviour.ex b/lib/supabase/go_true_behaviour.ex index 181109d..b22ba09 100644 --- a/lib/supabase/go_true_behaviour.ex +++ b/lib/supabase/go_true_behaviour.ex @@ -2,30 +2,18 @@ defmodule Supabase.GoTrueBehaviour do @moduledoc false alias Supabase.Client - alias Supabase.GoTrue.Schemas.SignInWithIdToken - alias Supabase.GoTrue.Schemas.SignInWithOauth - alias Supabase.GoTrue.Schemas.SignInWithOTP - alias Supabase.GoTrue.Schemas.SignInWithPassword - alias Supabase.GoTrue.Schemas.SignInWithSSO - alias Supabase.GoTrue.Schemas.SignUpWithPassword - alias Supabase.GoTrue.Schemas.VerifyOTP alias Supabase.GoTrue.Session alias Supabase.GoTrue.User - @type sign_in_response :: - {:ok, Session.t()} - | {:error, Ecto.Changeset.t()} - | {:error, :invalid_grant} - | {:error, {:invalid_grant, :invalid_credentials}} + @type sign_in_response :: Supabase.result(Session.t()) | {:error, Ecto.Changeset.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.t(), SignUpWithPassword.t()) :: - {:ok, User.t(), binary} | {:error, atom} + @callback get_user(Client.t(), Session.t()) :: Supabase.result(User.t()) + @callback sign_in_with_oauth(Client.t(), map) :: + {:ok, atom, URI.t()} | {:error, Supabase.Error.t()} + @callback verify_otp(Client.t(), map) :: sign_in_response + @callback sign_in_with_otp(Client.t(), map) :: :ok | Supabase.result(Ecto.UUID.t()) + @callback sign_in_with_sso(Client.t(), map) :: Supabase.result(URI.t()) + @callback sign_in_with_id_token(Client.t(), map) :: sign_in_response + @callback sign_in_with_password(Client.t(), map) :: sign_in_response + @callback sign_up(Client.t(), map) :: {:ok, User.t(), binary} | {:error, Supabase.Error.t()} end diff --git a/mix.exs b/mix.exs index 720a7f9..3d105f5 100644 --- a/mix.exs +++ b/mix.exs @@ -1,8 +1,8 @@ defmodule SupabaseAuth.MixProject do use Mix.Project - @version "0.3.10" - @source_url "https://github.com/zoedsoupe/gotrue-ex" + @version "0.4.0" + @source_url "https://github.com/supabase-community/auth-ex" def project do [ @@ -13,7 +13,8 @@ defmodule SupabaseAuth.MixProject do deps: deps(), docs: docs(), package: package(), - description: description() + description: description(), + dialyzer: [plt_local_path: "priv/plts", ignore_warnings: ".dialyzerignore"] ] end @@ -27,12 +28,12 @@ defmodule SupabaseAuth.MixProject do # Run "mix help deps" to learn about dependencies. defp deps do [ - {:supabase_potion, "~> 0.4"}, + {:supabase_potion, "~> 0.6"}, {:plug, "~> 1.15", optional: true}, - {:phoenix_live_view, "~> 0.20", optional: true}, - {:ex_doc, ">= 0.0.0", runtime: false}, + {:phoenix_live_view, "~> 1.0", optional: true}, + {:ex_doc, ">= 0.0.0", only: :dev, runtime: false}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, - {:dialyxir, "~> 1.3", only: [:dev], runtime: false} + {:dialyxir, "~> 1.3", only: [:dev, :test], runtime: false} ] end diff --git a/mix.lock b/mix.lock index 14c930a..e74e6ce 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.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.41", "ab34711c9dc6212dda44fcd20ecb87ac3f3fce6f0ca2f28d4a00e4154f8cd599", [:mix], [], "hexpm", "a81a04c7e34b6617c2792e291b5a2e57ab316365c2644ddc553bb9ed863ebefa"}, - "ecto": {:hex, :ecto, "3.12.3", "1a9111560731f6c3606924c81c870a68a34c819f6d4f03822f370ea31a582208", [: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", "9efd91506ae722f95e48dc49e70d0cb632ede3b7a23896252a60a14ac6d59165"}, + "castore": {:hex, :castore, "1.0.11", "4bbd584741601eb658007339ea730b082cc61f3554cf2e8f39bf693a11b49073", [:mix], [], "hexpm", "e03990b4db988df56262852f20de0f659871c35154691427a5047f4967a16a62"}, + "credo": {:hex, :credo, "1.7.11", "d3e805f7ddf6c9c854fd36f089649d7cf6ba74c42bc3795d587814e3c9847102", [: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", "56826b4306843253a66e47ae45e98e7d284ee1f95d53d1612bb483f88a8cf219"}, + "decimal": {:hex, :decimal, "2.3.0", "3ad6255aa77b4a3c4f818171b12d237500e63525c2fd056699967a3e7ea20f62", [:mix], [], "hexpm", "a4d66355cb29cb47c3cf30e71329e58361cfcb37c34235ef3bf1d7bf3773aeac"}, + "dialyxir": {:hex, :dialyxir, "1.4.5", "ca1571ac18e0f88d4ab245f0b60fa31ff1b12cbae2b11bd25d207f865e8ae78a", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "b0fb08bb8107c750db5c0b324fa2df5ceaa0f9307690ee3c1f6ba5b9eb5d35c3"}, + "earmark_parser": {:hex, :earmark_parser, "1.4.42", "f23d856f41919f17cd06a493923a722d87a2d684f143a1e663c04a2b93100682", [:mix], [], "hexpm", "6915b6ca369b5f7346636a2f41c6a6d78b5af419d61a611079189233358b8b8b"}, + "ecto": {:hex, :ecto, "3.12.5", "4a312960ce612e17337e7cefcf9be45b95a3be6b36b6f94dfb3d8c361d631866", [: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", "6eb18e80bef8bb57e17f5a7f068a1719fbda384d40fc37acb8eb8aeca493b6ea"}, "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"}, + "ex_doc": {:hex, :ex_doc, "0.36.1", "4197d034f93e0b89ec79fac56e226107824adcce8d2dd0a26f5ed3a95efc36b1", [:mix], [{:earmark_parser, "~> 1.4.42", [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", "d7d26a7cf965dacadcd48f9fa7b5953d7d0cfa3b44fa7a65514427da44eafd89"}, + "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, "finch": {:hex, :finch, "0.19.0", "c644641491ea854fc5c1bbaef36bfc764e3f08e7185e1f084e35e0672241b76d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.6.2 or ~> 1.7", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 1.1", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "fc5324ce209125d1e2fa0fcd2634601c52a787aff1cd33ee833664a5af4ea2b6"}, - "hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, + "hpax": {:hex, :hpax, "1.0.2", "762df951b0c399ff67cc57c3995ec3cf46d696e41f0bba17da0518d94acd4aac", [:mix], [], "hexpm", "2f09b4c1074e0abd846747329eaa26d535be0eb3d189fa69d812bfb8bfefd32f"}, "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": {:hex, :makeup, "1.2.1", "e90ac1c65589ef354378def3ba19d401e739ee7ee06fb47f94c687016e3713d1", [:mix], [{:nimble_parsec, "~> 1.4", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "d36484867b0bae0fea568d10131197a4c2e47056a6fbe84922bf6ba71c8d17ce"}, + "makeup_elixir": {:hex, :makeup_elixir, "1.0.1", "e928a4f984e795e41e3abd27bfc09f51db16ab8ba1aebdba2b3a575437efafc2", [: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", "7284900d412a3e5cfd97fdaed4f5ed389b8f2b4cb49efc0eb3bd10e2febf9507"}, "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_parsec": {:hex, :nimble_parsec, "1.4.1", "f41275a0354c736db4b1d255b5d2a27c91028e55c21ea3145b938e22649ffa3f", [:mix], [], "hexpm", "605e44204998f138d6e13be366c8e81af860e726c8177caf50067e1b618fe522"}, "nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, - "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.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": {:hex, :phoenix, "1.7.18", "5310c21443514be44ed93c422e15870aef254cf1b3619e4f91538e7529d2b2e4", [: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", "1797fcc82108442a66f2c77a643a62980f342bfeb63d6c9a515ab8294870004e"}, + "phoenix_html": {:hex, :phoenix_html, "4.2.0", "83a4d351b66f472ebcce242e4ae48af1b781866f00ef0eb34c15030d4e2069ac", [:mix], [], "hexpm", "9713b3f238d07043583a94296cc4bbdceacd3b3a6c74667f4df13971e7866ec8"}, + "phoenix_live_view": {:hex, :phoenix_live_view, "1.0.2", "e7b1dd68c86326e2c45cc81da41e332cc8aa7228a7161e2c811dcd7f1dd14db1", [: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", "8a40265b0cd7d3a35f136dfa3cc048e3b198fc3718763411a78c323a44ebebee"}, "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.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.5.1", "3f604c875edc8895010552f6b36ba03fe5f281813234e337adb930dd2f7df178", [: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", "c26a9e99fd61fc546694c7a5ae48c4c8ab36295230eb28de04818e1b59610c23"}, + "supabase_potion": {:hex, :supabase_potion, "0.6.0", "0375ec2415e0a5176d63456bba1f589fb196bcbc7c72e40c19094c1299b5d23a", [:mix], [{:ecto, "~> 3.10", [hex: :ecto, repo: "hexpm", optional: false]}, {:finch, "~> 0.16", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}], "hexpm", "ac45726b5098cf8b351d974f874631b1c2159174a712086552043a043f5e3f05"}, "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.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"}, + "websock_adapter": {:hex, :websock_adapter, "0.5.8", "3b97dc94e407e2d1fc666b2fb9acf6be81a1798a2602294aac000260a7c4a47d", [: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", "315b9a1865552212b5f35140ad194e67ce31af45bcee443d4ecb96b5fd3f3782"}, } diff --git a/test/supabase_test.exs b/test/supabase_test.exs deleted file mode 100644 index 05a7b89..0000000 --- a/test/supabase_test.exs +++ /dev/null @@ -1,74 +0,0 @@ -defmodule SupabaseTest do - use ExUnit.Case, async: true - - alias Supabase.Client - alias Supabase.ClientRegistry - alias Supabase.MissingSupabaseConfig - - describe "init_client/1" do - test "should return a valid PID on valid attrs" do - {:ok, pid} = - Supabase.init_client(%{ - name: :test, - conn: %{ - base_url: "https://test.supabase.co", - api_key: "test" - } - }) - - assert pid == ClientRegistry.lookup(:test) - assert {:ok, client} = Client.retrieve_client(:test) - assert client.name == :test - assert client.conn.base_url == "https://test.supabase.co" - assert client.conn.api_key == "test" - end - - test "should return an error changeset on invalid attrs" do - {:error, changeset} = Supabase.init_client(%{}) - - assert changeset.errors == [ - name: {"can't be blank", [validation: :required]}, - conn: {"can't be blank", [validation: :required]} - ] - - {:error, changeset} = Supabase.init_client(%{name: :test, conn: %{}}) - assert conn = changeset.changes.conn - - assert conn.errors == [ - api_key: {"can't be blank", [validation: :required]}, - base_url: {"can't be blank", [validation: :required]} - ] - end - end - - describe "init_client!/1" do - test "should return a valid PID on valid attrs" do - pid = - Supabase.init_client!(%{ - name: :test2, - conn: %{ - base_url: "https://test.supabase.co", - api_key: "test" - } - }) - - assert pid == ClientRegistry.lookup(:test2) - assert {:ok, client} = Client.retrieve_client(:test2) - assert client.name == :test2 - assert client.conn.base_url == "https://test.supabase.co" - assert client.conn.api_key == "test" - end - - test "should raise MissingSupabaseConfig on missing base_url" do - assert_raise MissingSupabaseConfig, fn -> - Supabase.init_client!(%{name: :test, conn: %{api_key: "test"}}) - end - end - - test "should raise MissingSupabaseConfig on missing api_key" do - assert_raise MissingSupabaseConfig, fn -> - Supabase.init_client!(%{name: :test, conn: %{base_url: "https://test.supabase.co"}}) - end - end - end -end