rp_supabase_client/
client.rs1use futures::{Stream, StreamExt as _};
2use rp_postgrest::{Postgrest, reqwest};
3use rp_supabase_auth::error::AuthError;
4use rp_supabase_auth::jwt_stream::SupabaseAuthConfig;
5use rp_supabase_auth::types::{AccessTokenResponseSchema, LoginCredentials};
6use rp_supabase_auth::url;
7
8pub const SUPABASE_KEY: &str = "apikey";
9
10pub fn new_authenticated(
15 config: SupabaseAuthConfig,
16 login_info: LoginCredentials,
17) -> Result<
18 impl Stream<Item = Result<(Postgrest, AccessTokenResponseSchema), SupabaseClientError>>,
19 SupabaseClientError,
20> {
21 new_authenticated_with_client(config, login_info, default_client()?)
22}
23
24pub fn new_authenticated_with_client(
30 config: SupabaseAuthConfig,
31 login_info: LoginCredentials,
32 http: reqwest::Client,
33) -> Result<
34 impl Stream<Item = Result<(Postgrest, AccessTokenResponseSchema), SupabaseClientError>>,
35 SupabaseClientError,
36> {
37 let base = anonymous_client_with_client(config.api_key.clone(), &config.url, http.clone())?;
38 let auth_stream = rp_supabase_auth::jwt_stream::JwtStream::new(config)
39 .sign_in_with_client(login_info, http)?;
40 Ok(auth_stream.map(move |item| {
41 let item = item?;
42 let client = match item.access_token.as_ref() {
43 Some(token) => base.clone().auth(token)?,
44 None => base.clone(),
45 };
46 Ok((client, item))
47 }))
48}
49
50pub fn anonymous_client(api_key: String, url: &url::Url) -> Result<Postgrest, SupabaseClientError> {
55 anonymous_client_with_client(api_key, url, default_client()?)
56}
57
58pub fn anonymous_client_with_client(
63 api_key: String,
64 url: &url::Url,
65 http: reqwest::Client,
66) -> Result<Postgrest, SupabaseClientError> {
67 let url = url.join("rest/v1/")?;
68 Ok(Postgrest::new_with_client(url.as_str(), http)?.insert_header(SUPABASE_KEY, api_key)?)
69}
70
71fn default_client() -> Result<reqwest::Client, reqwest::Error> {
73 const MAX_REDIRECTS: usize = 10;
74 reqwest::Client::builder()
75 .redirect(reqwest::redirect::Policy::custom(|attempt| {
76 let same_origin = attempt
77 .previous()
78 .last()
79 .is_some_and(|previous| previous.origin() == attempt.url().origin());
80 if !same_origin {
81 attempt.stop()
82 } else if attempt.previous().len() > MAX_REDIRECTS {
83 attempt.error("too many redirects")
84 } else {
85 attempt.follow()
86 }
87 }))
88 .build()
89}
90
91#[derive(thiserror::Error, Debug)]
92pub enum SupabaseClientError {
93 #[error("Jwt Stream closed unexpectedly")]
94 JwtStreamClosedUnexpectedly,
95 #[error("Refresh stream error")]
96 RefreshStreamError(#[from] rp_supabase_auth::jwt_stream::RefreshStreamError),
97 #[error("Auth sign in error")]
98 AuthSignInError(#[from] rp_supabase_auth::jwt_stream::SignInError),
99 #[error("Url parse error {0}")]
100 UrlParseError(#[from] url::ParseError),
101 #[error("Auth error {0}")]
102 AuthError(#[from] AuthError),
103 #[error(transparent)]
104 Postgrest(#[from] rp_postgrest::Error),
105 #[error(transparent)]
106 Transport(#[from] reqwest::Error),
107}