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}