diff --git a/.env.dev b/.env.dev index 2b1dd6d..a833016 100644 --- a/.env.dev +++ b/.env.dev @@ -1,2 +1,3 @@ +export SUPABASE_LOCAL=1 export SUPABASE_URL=http://127.0.0.1:54321 export SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6InNlcnZpY2Vfcm9sZSIsImV4cCI6MTk4MzgxMjk5Nn0.EGIM96RAZx35lJzdJsyH-qQwv8Hdp7fsn3W0YpN81IU diff --git a/.gitignore b/.gitignore index 501f9c7..89e949a 100644 --- a/.gitignore +++ b/.gitignore @@ -25,3 +25,5 @@ supabase_functions-*.tar /priv/plts/ .env.dev +/.claude/ +/.expert/ diff --git a/lib/supabase/functions.ex b/lib/supabase/functions.ex index 0e6584d..e3865b4 100644 --- a/lib/supabase/functions.ex +++ b/lib/supabase/functions.ex @@ -77,6 +77,7 @@ defmodule Supabase.Functions do |> Request.with_headers(custom_headers) |> execute_request(opts[:on_response]) |> maybe_decode_body() + |> handle_response() end defp maybe_define_region(req, nil), do: req @@ -128,4 +129,20 @@ defmodule Supabase.Functions do defp decoder_from_content_type(_) do fn body -> {:ok, Function.identity(body)} end end + + defp handle_response({:ok, %Response{} = resp}) do + if Response.get_header(resp, "x-relay-error") == "true" do + {:error, + Supabase.Error.new( + service: :functions, + code: :relay_error, + message: "Relay Error invoking the Edge Function", + metadata: resp + )} + else + {:ok, resp} + end + end + + defp handle_response(other), do: other end diff --git a/mix.exs b/mix.exs index 373f39f..b5835ad 100644 --- a/mix.exs +++ b/mix.exs @@ -25,10 +25,18 @@ defmodule Supabase.Functions.MixProject do ] end + defp supabase_dep do + if System.get_env("SUPABASE_LOCAL") == "1" do + {:supabase_potion, path: "../supabase-ex"} + else + {:supabase_potion, "~> 0.6"} + end + end + # Run "mix help deps" to learn about dependencies. defp deps do [ - {:supabase_potion, "~> 0.6"}, + supabase_dep(), {:mox, "~> 1.0", only: :test}, {:ex_doc, ">= 0.0.0", only: [:dev], runtime: false}, {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, diff --git a/mix.lock b/mix.lock index 1b7b1f7..4c86239 100644 --- a/mix.lock +++ b/mix.lock @@ -4,7 +4,7 @@ "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.44", "f20830dd6b5c77afe2b063777ddbbff09f9759396500cdbe7523efd58d7a339c", [:mix], [], "hexpm", "4778ac752b4701a5599215f7030989c989ffdc4f6df457c5f36938cc2d2a2750"}, - "ecto": {:hex, :ecto, "3.13.2", "7d0c0863f3fc8d71d17fc3ad3b9424beae13f02712ad84191a826c7169484f01", [: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", "669d9291370513ff56e7b7e7081b7af3283d02e046cf3d403053c557894a0b3e"}, + "ecto": {:hex, :ecto, "3.13.5", "9d4a69700183f33bf97208294768e561f5c7f1ecf417e0fa1006e4a91713a834", [: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", "df9efebf70cf94142739ba357499661ef5dbb559ef902b68ea1f3c1fabce36de"}, "erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "ex_doc": {:hex, :ex_doc, "0.38.2", "504d25eef296b4dec3b8e33e810bc8b5344d565998cd83914ffe1b8503737c02", [:mix], [{:earmark_parser, "~> 1.4.44", [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", "732f2d972e42c116a70802f9898c51b54916e542cc50968ac6980512ec90f42b"}, "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, diff --git a/test/supabase/functions_test.exs b/test/supabase/functions_test.exs index 2fbd85c..d32c011 100644 --- a/test/supabase/functions_test.exs +++ b/test/supabase/functions_test.exs @@ -172,5 +172,21 @@ defmodule Supabase.FunctionsTest do assert response.body == %{"success" => true} end + + test "handles relay errors", %{client: client} do + expect(@mock, :stream, fn _request, _ -> + {:ok, + %Finch.Response{ + status: 200, + headers: %{"content-type" => "application/json", "x-relay-error" => "true"}, + body: ~s({"error": "Relay Error"}) + }} + end) + + assert {:error, error} = + Functions.invoke(client, "test-function", http_client: @mock) + + assert error.code == :relay_error + end end end