supabase/
lib.rs

1#![allow(clippy::result_large_err)]
2
3//! # Supabase Rust Client Library
4//!
5//! A comprehensive, production-ready Rust client library for Supabase with full cross-platform support (native + WASM).
6//!
7//! ## 🚀 Version 0.3.1 - Enhanced Authentication
8//!
9//! This release introduces a comprehensive authentication system with OAuth providers,
10//! phone authentication, magic links, anonymous sign-in, and real-time auth state events,
11//! plus advanced cross-platform error handling with detailed context and retry logic.
12//!
13//! ## ✨ Features
14//!
15//! - **🔐 Authentication**: Complete auth system with OAuth, phone, magic links, anonymous sign-in
16//! - **🗄️ Database**: Advanced PostgreSQL operations with joins, transactions, logical operators
17//! - **📁 Storage**: File upload, download, and management
18//! - **⚡ Realtime**: WebSocket subscriptions for live data
19//! - **🔧 Functions**: Edge Functions invocation
20//! - **🌐 Cross-Platform**: Native (Tokio) and WASM support
21//! - **🛡️ Type Safe**: Full type safety with comprehensive error handling
22//! - **📚 Well Documented**: Extensive documentation with examples
23//!
24//! ## 🚀 Quick Start
25//!
26//! ```rust
27//! use supabase::auth::AuthEvent;
28//! use serde::{Deserialize, Serialize};
29//!
30//! #[derive(Debug, Serialize, Deserialize)]
31//! struct User {
32//!     id: i32,
33//!     name: String,
34//!     email: String,
35//! }
36//!
37//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
38//!     let client = supabase::Client::new("https://example.supabase.co", "valid-key")?;
39//!
40//!     // Set up authentication event listener
41//!     let _handle = client.auth().on_auth_state_change(|event, session| {
42//!         match event {
43//!             AuthEvent::SignedIn => println!("User signed in!"),
44//!             AuthEvent::SignedOut => println!("User signed out!"),
45//!             AuthEvent::TokenRefreshed => println!("Token refreshed!"),
46//!             _ => {}
47//!         }
48//!     });
49//!
50//!     // Sign up a new user
51//!     let auth_response = client.auth()
52//!         .sign_up_with_email_and_password("user@example.com", "secure_password")
53//!         .await?;
54//!
55//!     println!("User created: {:?}", auth_response.user);
56//!
57//!     // Complex database query with JOIN
58//!     let posts_with_users: Vec<serde_json::Value> = client.database()
59//!         .from("posts")
60//!         .select("title, content, users(name, email)")
61//!         .inner_join("users", "name, email")
62//!         .eq("published", "true")
63//!         .execute()
64//!         .await?;
65//!
66//!     println!("Found {} posts with users", posts_with_users.len());
67//!
68//!     Ok(())
69//! }
70//! ```
71//!
72//! ## 🔐 Authentication Examples
73//!
74//! ### OAuth Providers
75//!
76//! ```rust
77//! use supabase::auth::{OAuthProvider, OAuthOptions};
78//!
79//! # async fn example() -> supabase::Result<()> {
80//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
81//! // Google OAuth
82//! let options = OAuthOptions {
83//!     redirect_to: Some("https://myapp.com/callback".to_string()),
84//!     scopes: Some(vec!["email".to_string(), "profile".to_string()]),
85//!     ..Default::default()
86//! };
87//!
88//! let response = client.auth()
89//!     .sign_in_with_oauth(OAuthProvider::Google, Some(options))
90//!     .await?;
91//!
92//! println!("Redirect to: {}", response.url);
93//! # Ok(())
94//! # }
95//! ```
96//!
97//! ### Phone Authentication
98//!
99//! ```rust
100//! # async fn example() -> supabase::Result<()> {
101//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
102//! // Sign up with phone
103//! let auth_response = client.auth()
104//!     .sign_up_with_phone("+1234567890", "secure_password", None)
105//!     .await?;
106//!
107//! // Verify OTP
108//! let verified = client.auth()
109//!     .verify_otp("+1234567890", "123456", "sms")
110//!     .await?;
111//! # Ok(())
112//! # }
113//! ```
114//!
115//! ### Magic Links
116//!
117//! ```rust
118//! # async fn example() -> supabase::Result<()> {
119//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
120//! // Send magic link
121//! client.auth()
122//!     .sign_in_with_magic_link(
123//!         "user@example.com",
124//!         Some("https://myapp.com/callback".to_string()),
125//!         None
126//!     )
127//!     .await?;
128//!
129//! println!("Magic link sent!");
130//! # Ok(())
131//! # }
132//! ```
133//!
134//! ### Anonymous Sign-in
135//!
136//! ```rust
137//! # async fn example() -> supabase::Result<()> {
138//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
139//! // Create anonymous user
140//! let auth_response = client.auth()
141//!     .sign_in_anonymously(None)
142//!     .await?;
143//!
144//! if let Some(user) = auth_response.user {
145//!     println!("Anonymous user created: {}", user.id);
146//! }
147//! # Ok(())
148//! # }
149//! ```
150//!
151//! ## 🗄️ Advanced Database Operations
152//!
153//! ### Complex Queries
154//!
155//! ```rust,no_run
156//! # use supabase::Client;
157//! # use supabase::types::OrderDirection;
158//! # use serde_json::Value;
159//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
160//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
161//!   let posts: Vec<Value> = client.database()
162//!       .from("posts")
163//!       .select("*")
164//!       .and(|q| q.eq("published", "true").gte("created_at", "2024-01-01"))
165//!       .or(|q| q.eq("author", "admin").eq("status", "featured"))
166//!       .not(|q| q.eq("deleted", "true"))
167//!       .order("created_at", OrderDirection::Descending)
168//!       .limit(10)
169//!       .execute()
170//!       .await?;
171//! # Ok(())
172//! # }
173//! ```
174//!
175//! ### Query Joins
176//!
177//! ```rust,no_run
178//! # use supabase::Client;
179//! # use serde_json::Value;
180//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
181//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
182//!   let posts_with_authors: Vec<Value> = client.database()
183//!       .from("posts")
184//!       .select("id, title, users(name, email)")
185//!       .inner_join_as("users", "name", "author_name")
186//!       .execute()
187//!       .await?;
188//! # Ok(())
189//! # }
190//! ```
191//!
192//! ### Transactions
193//!
194//! ```rust,no_run
195//! # use supabase::Client;
196//! # use serde::{Deserialize, Serialize};
197//! # use serde_json::json;
198//! #
199//! # #[derive(Debug, Deserialize, Serialize)]
200//! # struct User { id: i32, name: String, email: String }
201//! #
202//! # async fn example() -> Result<(), Box<dyn std::error::Error>> {
203//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
204//!   let result: Vec<User> = client.database()
205//!       .begin_transaction()
206//!       .insert("users", json!({"name": "John", "email": "john@example.com"}))
207//!       .update("profiles", json!({"updated_at": "now()"}), "user_id = $1")
208//!       .commit()
209//!       .await?;
210//! # Ok(())
211//! # }
212//! ```
213//!
214//! ## 🌐 Cross-Platform Support
215//!
216//! This library works seamlessly across different platforms:
217//!
218//! ### Native Applications (Tokio)
219//! ```rust
220//! // Full async/await support with Tokio runtime
221//! #[tokio::main]
222//! async fn main() -> supabase::Result<()> {
223//!     let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
224//!     // All operations available
225//!     Ok(())
226//! }
227//! ```
228//!
229//! ### WebAssembly (WASM)
230//! ```rust
231//! use wasm_bindgen::prelude::*;
232//!
233//! #[wasm_bindgen]
234//! pub async fn initialize_supabase() -> Result<(), JsValue> {
235//!     let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")
236//!         .map_err(|e| JsValue::from_str(&e.to_string()))?;
237//!
238//!     // Enhanced error handling with platform-specific context
239//!     match client.database().from("users").select("*").execute::<serde_json::Value>().await {
240//!         Ok(users) => web_sys::console::log_1(&format!("Found {} users", users.len()).into()),
241//!         Err(e) => {
242//!             let error_msg = format!("Database error: {}", e);
243//!             web_sys::console::error_1(&error_msg.clone().into());
244//!             return Err(JsValue::from_str(&error_msg));
245//!         }
246//!     }
247//!     Ok(())
248//! }
249//! ```
250//!
251//! ## 🛡️ Enhanced Error Handling
252//!
253//! v0.3.1 introduces comprehensive error context with platform-specific information:
254//!
255//! ```rust
256//! use supabase::error::{ErrorContext, PlatformContext};
257//!
258//! # async fn example() -> supabase::Result<()> {
259//! # let client = supabase::Client::new("https://example.supabase.co", "your-anon-key")?;
260//! match client.auth().sign_in_with_email_and_password("user@example.com", "password").await {
261//!     Ok(response) => println!("Success!"),
262//!     Err(e) => {
263//!         // Check if error is retryable
264//!         if e.is_retryable() {
265//!             if let Some(retry_after) = e.retry_after() {
266//!                 println!("Retry after {} seconds", retry_after);
267//!             }
268//!         }
269//!
270//!         // Get platform-specific context
271//!         if let Some(context) = e.context() {
272//!             match &context.platform {
273//!                 Some(PlatformContext::Wasm { user_agent, available_apis, .. }) => {
274//!                     println!("WASM environment: {:?}", user_agent);
275//!                     println!("Available APIs: {:?}", available_apis);
276//!                 }
277//!                 Some(PlatformContext::Native { os_info, .. }) => {
278//!                     println!("Native environment: {:?}", os_info);
279//!                 }
280//!                 None => {}
281//!             }
282//!         }
283//!
284//!         // Get HTTP status code if available
285//!         if let Some(status) = e.status_code() {
286//!             println!("HTTP Status: {}", status);
287//!         }
288//!     }
289//! }
290//! # Ok(())
291//! # }
292//! ```
293//!
294//! ## 📚 Module Organization
295//!
296//! - [`auth`] - Authentication operations and OAuth providers
297//! - [`database`] - PostgreSQL database operations with advanced querying
298//! - [`storage`] - File upload, download, and management
299//! - [`realtime`] - WebSocket subscriptions for live data
300//! - [`functions`] - Edge Functions invocation
301//! - [`error`] - Enhanced error types with platform-specific context
302//! - [`types`] - Common type definitions and configurations
303//!
304//! ## 🔧 Configuration
305//!
306//! ```rust,no_run
307//! use supabase::{Client, types::{SupabaseConfig, HttpConfig, AuthConfig}};
308//! use std::time::Duration;
309//!
310//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
311//! let client = Client::new("YOUR_URL", "YOUR_KEY")?;
312//! # Ok(())
313//! # }
314//! ```
315//!
316//! ## 🚧 Version History
317//!
318//! - **v0.3.1**: Enhanced Authentication with OAuth, phone auth, magic links, anonymous sign-in, improved error context
319//! - **v0.3.0**: Advanced Database Operations with joins, transactions, logical operators, C FFI foundation
320//! - **v0.2.0**: Production-ready client with comprehensive testing and documentation
321//!
322//! ## 📄 License
323//!
324//! This project is licensed under the MIT License.
325
326#[cfg(feature = "auth")]
327pub mod auth;
328
329pub mod client;
330
331#[cfg(feature = "database")]
332pub mod database;
333
334pub mod error;
335
336#[cfg(feature = "realtime")]
337pub mod realtime;
338
339#[cfg(feature = "storage")]
340pub mod storage;
341
342#[cfg(feature = "functions")]
343pub mod functions;
344
345#[cfg(feature = "ffi")]
346pub mod ffi;
347
348pub mod types;
349
350// Internal modules
351#[cfg(feature = "realtime")]
352mod async_runtime;
353
354#[cfg(feature = "realtime")]
355mod websocket;
356
357pub use client::Client;
358pub use error::{Error, Result};
359
360#[cfg(feature = "auth")]
361pub use auth::Auth;
362
363#[cfg(feature = "database")]
364pub use database::Database;
365
366#[cfg(feature = "realtime")]
367pub use realtime::Realtime;
368
369#[cfg(feature = "storage")]
370pub use storage::Storage;
371
372#[cfg(feature = "functions")]
373pub use functions::Functions;
374
375/// Commonly used types and traits for convenient importing
376///
377/// This module re-exports the most frequently used types to make them
378/// easily accessible with a single import.
379///
380/// ## Usage
381///
382/// ```rust
383/// use supabase::prelude::*;
384///
385/// // Now you have access to Client, Error, Result, and all common types
386/// # fn example() -> Result<()> {
387/// let client = Client::new("https://example.supabase.co", "your-anon-key")?;
388/// # Ok(())
389/// # }
390/// ```
391pub mod prelude {
392
393    pub use crate::types::*;
394    pub use crate::{Client, Error, Result};
395
396    #[cfg(feature = "auth")]
397    pub use crate::auth::{Auth, AuthResponse, Session, User};
398
399    #[cfg(feature = "database")]
400    pub use crate::database::{
401        Database, DeleteBuilder, InsertBuilder, QueryBuilder, UpdateBuilder,
402    };
403
404    #[cfg(feature = "storage")]
405    pub use crate::storage::{Bucket, FileObject, Storage};
406
407    #[cfg(feature = "functions")]
408    pub use crate::functions::Functions;
409
410    #[cfg(feature = "realtime")]
411    pub use crate::realtime::{Realtime, RealtimeEvent, RealtimeMessage};
412}