diff --git a/lib/pinecone.ex b/lib/pinecone.ex index 32b5599..3e6a295 100644 --- a/lib/pinecone.ex +++ b/lib/pinecone.ex @@ -10,22 +10,6 @@ defmodule Pinecone do @type error_type :: {:error, String.t()} @type index_type :: %Index{name: String.t(), project_name: String.t()} - ## General Operations - - @doc """ - Retrieves Pinecone project name. - - ## Options - - * `:config` - client configuration used to override application - level configuration. Defaults to `nil` - """ - @spec whoami(opts :: keyword()) :: success_type(map()) | error_type() - def whoami(opts \\ []) do - opts = Keyword.validate!(opts, [:config]) - get(:indices, "actions/whoami", opts[:config]) - end - ## Index Operations @doc """ @@ -36,9 +20,11 @@ defmodule Pinecone do * `:project_name` - project name to use to override application configuration. Defaults to `nil` """ + @spec index(String.t(), Keyword.t()) :: Index.t() def index(index_name, opts \\ []) when is_binary(index_name) do opts = Keyword.validate!(opts, [:project_name]) project_name = opts[:project_name] || Pinecone.Config.project_name() + %Index{name: index_name, project_name: project_name} end @@ -50,10 +36,14 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ - @spec list_indices(opts :: keyword()) :: success_type(list()) | error_type() + @spec list_indices() :: success_type(list(map)) | error_type() + @spec list_indices(opts :: keyword()) :: success_type(list(map)) | error_type() def list_indices(opts \\ []) do opts = Keyword.validate!(opts, [:config]) - get(:indices, "databases", opts[:config]) + + with {:ok, %{"indexes" => indexes}} <- get(:indices, "", opts[:config]) do + {:ok, indexes} + end end @doc """ @@ -64,13 +54,16 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec describe_index(index_name :: String.t()) :: + success_type(map()) | error_type() @spec describe_index(index_name :: String.t(), opts :: keyword()) :: success_type(map()) | error_type() def describe_index(index_name, opts \\ []) do opts = Keyword.validate!(opts, [:config]) - get(:indices, "databases/#{index_name}", opts[:config]) + get(:indices, index_name, opts[:config]) end + @valid_clouds ["gcp", "aws", "azure"] @valid_metric_types [:euclidean, :cosine, :dotproduct] @valid_pod_types [:s1, :p1, :p2] @valid_pod_sizes [:x1, :x2, :x4, :x8] @@ -104,41 +97,82 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec create_index(index_name :: String.t()) :: + success_type(map) | error_type() @spec create_index(index_name :: String.t(), opts :: keyword()) :: - success_type(String.t()) | error_type() + success_type(map) | error_type() def create_index(index_name, opts \\ []) do opts = Keyword.validate!(opts, [ :config, dimension: 384, metric: :euclidean, - pods: 1, - replicas: 1, - shards: 1, - pod_type: {:p1, :x1}, - metadata: [] + spec: [] ]) + # TODO: validate metadata validate!("index_name", index_name, :binary) validate!("dimension", opts[:dimension], :non_negative_integer) - validate!("pods", opts[:pods], :non_negative_integer) - validate!("replicas", opts[:replicas], :non_negative_integer) - validate!("shards", opts[:shards], :non_negative_integer) validate!("metric", opts[:metric], :one_of, @valid_metric_types) - validate!("pod_type", opts[:pod_type], :one_of, @valid_pods) - # TODO: validate metadata + + spec_params = validate_create_index_opts(opts[:spec]) body = %{ "name" => index_name, "dimension" => opts[:dimension], "metric" => Atom.to_string(opts[:metric]), - "pods" => opts[:pods], - "replicas" => opts[:replicas], - "shards" => opts[:shards], - "pod_type" => to_pod_type(opts[:pod_type]) + "spec" => spec_params } - post(:indices, "databases", body, opts[:config]) + post(:indices, "", body, opts[:config]) + end + + defp validate_create_index_opts(spec_opts) do + case spec_opts do + [serverless: serverless_opts] -> + serverless_opts = + Keyword.validate!(serverless_opts, + cloud: "aws", + region: "us-west-2" + ) + + validate!("cloud", serverless_opts[:cloud], :one_of, @valid_clouds) + validate!("region", serverless_opts[:region], :binary) + + %{ + "serverless" => %{ + "cloud" => serverless_opts[:cloud], + "region" => serverless_opts[:region] + } + } + + [pod: pod_opts] -> + pod_opts = + Keyword.validate!(pod_opts, + pods: 1, + replicas: 1, + shards: 1, + pod_type: {:p1, :x1}, + metadata: [] + ) + + validate!("pods", pod_opts[:pods], :non_negative_integer) + validate!("replicas", pod_opts[:replicas], :non_negative_integer) + validate!("shards", pod_opts[:shards], :non_negative_integer) + validate!("pod_type", pod_opts[:pod_type], :one_of, @valid_pods) + + %{ + "pod" => %{ + "pods" => pod_opts[:pods], + "replicas" => pod_opts[:replicas], + "shards" => pod_opts[:shards], + "pod_type" => to_pod_type(pod_opts[:pod_type]) + } + } + + _ -> + raise "Must provide `serverless` or `pod` under the `spec` key when creating indexes" + end end @doc """ @@ -149,12 +183,14 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec delete_index(index_name :: String.t()) :: + success_type(String.t()) | error_type() @spec delete_index(index_name :: String.t(), opts :: keyword()) :: success_type(String.t()) | error_type() def delete_index(index_name, opts \\ []) do opts = Keyword.validate!(opts, [:config]) - delete(:indices, "databases/#{index_name}", opts[:config]) + delete(:indices, index_name, opts[:config]) end @doc """ @@ -172,6 +208,8 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec configure_index(index_name :: String.t()) :: + success_type(String.t()) | error_type() @spec configure_index(index_name :: String.t(), opts :: keyword()) :: success_type(String.t()) | error_type() def configure_index(index_name, opts \\ []) do @@ -185,7 +223,7 @@ defmodule Pinecone do "pod_type" => to_pod_type(opts[:pod_type]) } - patch(:indices, "databases/#{index_name}", body, opts[:config]) + patch(:indices, index_name, body, opts[:config]) end ## Vector operations @@ -198,6 +236,8 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec describe_index_stats(index :: index_type()) :: + success_type(map()) | error_type() @spec describe_index_stats(index :: index_type(), opts :: keyword()) :: success_type(map()) | error_type() def describe_index_stats(%Index{name: name, project_name: project_name}, opts \\ []) do @@ -225,6 +265,8 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec upsert_vectors(index :: index_type(), vectors :: list()) :: + success_type(map()) | error_type() @spec upsert_vectors(index :: index_type(), vectors :: list(), opts :: keyword()) :: success_type(map()) | error_type() def upsert_vectors(%Index{name: name, project_name: project_name}, vectors, opts \\ []) do @@ -251,6 +293,8 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec fetch_vectors(index :: index_type(), ids :: list()) :: + success_type(map()) | error_type() @spec fetch_vectors(index :: index_type(), ids :: list(), opts :: keyword()) :: success_type(map()) | error_type() def fetch_vectors(%Index{name: name, project_name: project_name}, ids, opts \\ []) do @@ -272,6 +316,8 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec delete_vectors(index :: index_type(), ids :: list()) :: + success_type(String.t()) | error_type() @spec delete_vectors(index :: index_type(), ids :: list(), opts :: keyword()) :: success_type(String.t()) | error_type() def delete_vectors(%Index{name: name, project_name: project_name}, ids, opts \\ []) @@ -298,6 +344,8 @@ defmodule Pinecone do * `:filter` - metadata filter to apply to the deletion. See https://docs.pinecone.io/docs/metadata-filtering """ + @spec delete_all_vectors(index :: index_type()) :: + success_type(String.t()) | error_type() @spec delete_all_vectors(index :: index_type(), opts :: keyword()) :: success_type(String.t()) | error_type() def delete_all_vectors(%Index{name: name, project_name: project_name}, opts \\ []) do @@ -335,6 +383,8 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec query(index :: index_type(), vector :: list()) :: + success_type(map()) | error_type() @spec query(index :: index_type(), vector :: list(), opts :: keyword()) :: success_type(map()) | error_type() def query(%Index{name: name, project_name: project_name}, vector, opts \\ []) do @@ -382,6 +432,10 @@ defmodule Pinecone do index_name :: String.t(), opts :: keyword() ) :: success_type(String.t()) | error_type() + @spec create_collection( + collection_name :: String.t(), + index_name :: String.t() + ) :: success_type(String.t()) | error_type() def create_collection(collection_name, index_name, opts \\ []) when is_binary(collection_name) and is_binary(index_name) do opts = Keyword.validate!(opts, [:config]) @@ -391,7 +445,7 @@ defmodule Pinecone do "source" => index_name } - post(:collections, "collections", body, opts[:config]) + post(:collections, "", body, opts[:config]) end @doc """ @@ -402,12 +456,14 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec describe_collection(collection_name :: String.t()) :: + success_type(map()) | error_type() @spec describe_collection(collection_name :: String.t(), opts :: keyword()) :: success_type(map()) | error_type() def describe_collection(collection_name, opts \\ []) when is_binary(collection_name) do opts = Keyword.validate!(opts, [:config]) - get(:collections, "collections/#{collection_name}", opts[:config]) + get(:collections, collection_name, opts[:config]) end @doc """ @@ -418,11 +474,12 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec list_collections() :: success_type(list()) | error_type() @spec list_collections(opts :: keyword()) :: success_type(list()) | error_type() def list_collections(opts \\ []) do opts = Keyword.validate!(opts, [:config]) - get(:collections, "collections", opts[:config]) + get(:collections, "", opts[:config]) end @doc """ @@ -433,12 +490,14 @@ defmodule Pinecone do * `:config` - client configuration used to override application level configuration. Defaults to `nil` """ + @spec delete_collection(collection_name :: String.t()) :: + success_type(String.t()) | error_type() @spec delete_collection(collection_name :: String.t(), opts :: keyword()) :: success_type(String.t()) | error_type() def delete_collection(collection_name, opts \\ []) when is_binary(collection_name) do opts = Keyword.validate!(opts, [:config]) - get(:collections, "collections/#{collection_name}", opts[:config]) + get(:collections, collection_name, opts[:config]) end defp to_pod_type({type, size}), do: "#{Atom.to_string(type)}.#{Atom.to_string(size)}" diff --git a/lib/pinecone/config.ex b/lib/pinecone/config.ex index 5c7099a..4a9f2c6 100644 --- a/lib/pinecone/config.ex +++ b/lib/pinecone/config.ex @@ -1,9 +1,9 @@ defmodule Pinecone.Config do @moduledoc false - def api_key(), do: Application.get_env(:pinecone, :api_key) + def api_key, do: Application.get_env(:pinecone, :api_key) - def environment(), do: Application.get_env(:pinecone, :environment) + def environment, do: Application.get_env(:pinecone, :environment) - def project_name(), do: Application.get_env(:pinecone, :project_name) + def project_name, do: Application.get_env(:pinecone, :project_name) end diff --git a/lib/pinecone/http.ex b/lib/pinecone/http.ex index 67544d4..7169e1e 100644 --- a/lib/pinecone/http.ex +++ b/lib/pinecone/http.ex @@ -43,7 +43,7 @@ defmodule Pinecone.Http do defp parse_response({:error, _reason} = error), do: error - defp url(type, endpoint, env) when type in [:indices, :collections] do + defp url(:indices, "actions/whoami" = endpoint, env) do env = if env do env @@ -54,15 +54,16 @@ defmodule Pinecone.Http do "https://controller.#{env}.pinecone.io/#{endpoint}" end - defp url({:vectors, slug}, endpoint, env) do - env = - if env do - env - else - Pinecone.Config.environment() - end + defp url(:indices, endpoint, _env) do + Path.join("https://api.pinecone.io/indexes", endpoint) + end - "https://#{slug}.svc.#{env}.pinecone.io/#{endpoint}" + defp url(:collections, endpoint, _env) do + Path.join("https://api.pinecone.io/collections", endpoint) + end + + defp url({:vectors, slug}, endpoint, env) do + Path.join("https://#{slug}.svc.#{env}.pinecone.io", endpoint) end defp headers(api_key) do diff --git a/lib/pinecone/index.ex b/lib/pinecone/index.ex index 1fbbacf..25499c6 100644 --- a/lib/pinecone/index.ex +++ b/lib/pinecone/index.ex @@ -4,4 +4,9 @@ defmodule Pinecone.Index do """ defstruct [:name, :project_name] + + @type t :: %__MODULE__{ + name: String.t(), + project_name: String.t() + } end diff --git a/mix.exs b/mix.exs index 69daced..01a18a4 100644 --- a/mix.exs +++ b/mix.exs @@ -24,7 +24,7 @@ defmodule Pinecone.MixProject do {:dialyxir, "~> 1.0", only: [:dev, :test], runtime: false}, {:credo, "~> 1.5", only: [:dev, :test], runtime: false}, {:jason, "~> 1.4"}, - {:req, "~> 0.3.1"} + {:req, "~> 0.3"} ] end end diff --git a/mix.lock b/mix.lock index 997bec5..77a863d 100644 --- a/mix.lock +++ b/mix.lock @@ -1,17 +1,17 @@ %{ - "bunt": {:hex, :bunt, "0.2.1", "e2d4792f7bc0ced7583ab54922808919518d0e57ee162901a16a1b6664ef3b14", [:mix], [], "hexpm", "a330bfb4245239787b15005e66ae6845c9cd524a288f0d141c148b02603777a5"}, - "castore": {:hex, :castore, "0.1.22", "4127549e411bedd012ca3a308dede574f43819fe9394254ca55ab4895abfa1a2", [:mix], [], "hexpm", "c17576df47eb5aa1ee40cc4134316a99f5cad3e215d5c77b8dd3cfef12a22cac"}, - "credo": {:hex, :credo, "1.6.7", "323f5734350fd23a456f2688b9430e7d517afb313fbd38671b8a4449798a7854", [:mix], [{:bunt, "~> 0.2.1", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "41e110bfb007f7eda7f897c10bf019ceab9a0b269ce79f015d54b0dcf4fc7dd3"}, - "dialyxir": {:hex, :dialyxir, "1.2.0", "58344b3e87c2e7095304c81a9ae65cb68b613e28340690dfe1a5597fd08dec37", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "61072136427a851674cab81762be4dbeae7679f85b1272b6d25c3a839aff8463"}, + "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, + "castore": {:hex, :castore, "1.0.5", "9eeebb394cc9a0f3ae56b813459f990abb0a3dedee1be6b27fdb50301930502f", [:mix], [], "hexpm", "8d7c597c3e4a64c395980882d4bca3cebb8d74197c590dc272cfd3b6a6310578"}, + "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"}, + "dialyxir": {:hex, :dialyxir, "1.4.3", "edd0124f358f0b9e95bfe53a9fcf806d615d8f838e2202a9f430d59566b6b53b", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "bf2cfb75cd5c5006bec30141b131663299c661a864ec7fbbc72dfa557487a986"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"}, - "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"}, - "finch": {:hex, :finch, "0.14.0", "619bfdee18fc135190bf590356c4bf5d5f71f916adb12aec94caa3fa9267a4bc", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "5459acaf18c4fdb47a8c22fb3baff5d8173106217c8e56c5ba0b93e66501a8dd"}, + "file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, + "finch": {:hex, :finch, "0.17.0", "17d06e1d44d891d20dbd437335eebe844e2426a0cd7e3a3e220b461127c73f70", [: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", "8d014a661bb6a437263d4b5abf0bcbd3cf0deb26b1e8596f2a271d22e48934c7"}, "hpax": {:hex, :hpax, "0.1.2", "09a75600d9d8bbd064cdd741f21fc06fc1f4cf3d0fcc335e5aa19be1a7235c84", [:mix], [], "hexpm", "2c87843d5a23f5f16748ebe77969880e29809580efdaccd615cd3bed628a8c13"}, - "jason": {:hex, :jason, "1.4.0", "e855647bc964a44e2f67df589ccf49105ae039d4179db7f6271dfd3843dc27e6", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "79a3791085b2a0f743ca04cec0f7be26443738779d09302e01318f97bdb82121"}, - "mime": {:hex, :mime, "2.0.3", "3676436d3d1f7b81b5a2d2bd8405f412c677558c81b1c92be58c00562bb59095", [:mix], [], "hexpm", "27a30bf0db44d25eecba73755acf4068cbfe26a4372f9eb3e4ea3a45956bff6b"}, - "mint": {:hex, :mint, "1.4.2", "50330223429a6e1260b2ca5415f69b0ab086141bc76dc2fbf34d7c389a6675b2", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "ce75a5bbcc59b4d7d8d70f8b2fc284b1751ffb35c7b6a6302b5192f8ab4ddd80"}, - "nimble_options": {:hex, :nimble_options, "0.5.2", "42703307b924880f8c08d97719da7472673391905f528259915782bb346e0a1b", [:mix], [], "hexpm", "4da7f904b915fd71db549bcdc25f8d56f378ef7ae07dc1d372cbe72ba950dce0"}, - "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"}, - "req": {:hex, :req, "0.3.4", "a485fd02ea1c5aa24e80ca67e5d66aa9730bad78a6e5cd38345172b50d259ee6", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "11391a99b9425a2126f7a44340506afd5c3e3e68353d7342546dc3c23c5c514d"}, + "jason": {:hex, :jason, "1.4.1", "af1504e35f629ddcdd6addb3513c3853991f694921b1b9368b0bd32beb9f1b63", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "fbb01ecdfd565b56261302f7e1fcc27c4fb8f32d56eab74db621fc154604a7a1"}, + "mime": {:hex, :mime, "2.0.5", "dc34c8efd439abe6ae0343edbb8556f4d63f178594894720607772a041b04b02", [:mix], [], "hexpm", "da0d64a365c45bc9935cc5c8a7fc5e49a0e0f9932a761c55d6c52b142780a05c"}, + "mint": {:hex, :mint, "1.5.2", "4805e059f96028948870d23d7783613b7e6b0e2fb4e98d720383852a760067fd", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "d77d9e9ce4eb35941907f1d3df38d8f750c357865353e21d335bdcdf6d892a02"}, + "nimble_options": {:hex, :nimble_options, "1.1.0", "3b31a57ede9cb1502071fade751ab0c7b8dbe75a9a4c2b5bbb0943a690b63172", [:mix], [], "hexpm", "8bbbb3941af3ca9acc7835f5655ea062111c9c27bcac53e004460dfd19008a99"}, + "nimble_pool": {:hex, :nimble_pool, "1.0.0", "5eb82705d138f4dd4423f69ceb19ac667b3b492ae570c9f5c900bb3d2f50a847", [:mix], [], "hexpm", "80be3b882d2d351882256087078e1b1952a28bf98d0a287be87e4a24a710b67a"}, + "req": {:hex, :req, "0.4.8", "2b754a3925ddbf4ad78c56f30208ced6aefe111a7ea07fb56c23dccc13eb87ae", [:mix], [{:brotli, "~> 0.3.1", [hex: :brotli, repo: "hexpm", optional: true]}, {:ezstd, "~> 1.0", [hex: :ezstd, repo: "hexpm", optional: true]}, {:finch, "~> 0.9", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:nimble_csv, "~> 1.0", [hex: :nimble_csv, repo: "hexpm", optional: true]}, {:plug, "~> 1.0", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "7146e51d52593bb7f20d00b5308a5d7d17d663d6e85cd071452b613a8277100c"}, "telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, }