1use wasm_bindgen::prelude::*;
8use serde_json::Value as JsonValue;
9
10use supabase_client_sdk::prelude::*;
11
12fn to_js_err(e: impl std::fmt::Display) -> JsValue {
15 JsValue::from_str(&e.to_string())
16}
17
18fn to_js_value(val: &impl serde::Serialize) -> Result<JsValue, JsValue> {
19 serde_wasm_bindgen::to_value(val).map_err(to_js_err)
20}
21
22fn json_to_row(json: JsonValue) -> Result<Row, JsValue> {
24 match json {
25 JsonValue::Object(map) => {
26 let mut row = Row::new();
27 for (k, v) in map {
28 row.set(k, v);
29 }
30 Ok(row)
31 }
32 _ => Err(JsValue::from_str("expected a JSON object")),
33 }
34}
35
36#[wasm_bindgen]
40pub struct WasmSupabaseClient {
41 inner: SupabaseClient,
42 url: String,
43 key: String,
44}
45
46#[wasm_bindgen]
47impl WasmSupabaseClient {
48 #[wasm_bindgen(constructor)]
53 pub fn new(url: &str, key: &str) -> Result<WasmSupabaseClient, JsValue> {
54 let config = SupabaseConfig::new(url, key);
55 let inner = SupabaseClient::new(config).map_err(to_js_err)?;
56 Ok(WasmSupabaseClient {
57 inner,
58 url: url.to_string(),
59 key: key.to_string(),
60 })
61 }
62
63 pub async fn from_select(&self, table: &str, columns: &str) -> Result<JsValue, JsValue> {
65 let response = self.inner.from(table).select(columns).execute().await;
66 let rows = response.into_result().map_err(to_js_err)?;
67 to_js_value(&rows)
68 }
69
70 pub async fn from_insert(&self, table: &str, data: JsValue) -> Result<JsValue, JsValue> {
72 let json: JsonValue = serde_wasm_bindgen::from_value(data)?;
73 let row = json_to_row(json)?;
74 let response = self.inner.from(table).insert(row).execute().await;
75 let result = response.into_result().map_err(to_js_err)?;
76 to_js_value(&result)
77 }
78
79 pub async fn from_update(
81 &self,
82 table: &str,
83 data: JsValue,
84 column: &str,
85 value: &str,
86 ) -> Result<JsValue, JsValue> {
87 let json: JsonValue = serde_wasm_bindgen::from_value(data)?;
88 let row = json_to_row(json)?;
89 let response = self
90 .inner
91 .from(table)
92 .update(row)
93 .eq(column, value)
94 .execute()
95 .await;
96 let result = response.into_result().map_err(to_js_err)?;
97 to_js_value(&result)
98 }
99
100 pub async fn from_delete(
102 &self,
103 table: &str,
104 column: &str,
105 value: &str,
106 ) -> Result<JsValue, JsValue> {
107 let response = self
108 .inner
109 .from(table)
110 .delete()
111 .eq(column, value)
112 .execute()
113 .await;
114 let result = response.into_result().map_err(to_js_err)?;
115 to_js_value(&result)
116 }
117
118 pub fn auth(&self) -> Result<WasmAuthClient, JsValue> {
120 let auth = AuthClient::new(&self.url, &self.key).map_err(to_js_err)?;
121 Ok(WasmAuthClient { inner: auth })
122 }
123
124 pub fn realtime(&self) -> Result<WasmRealtimeClient, JsValue> {
126 let rt = RealtimeClient::new(&self.url, &self.key).map_err(to_js_err)?;
127 Ok(WasmRealtimeClient { inner: rt })
128 }
129
130 pub fn storage(&self) -> Result<WasmStorageClient, JsValue> {
132 let storage = supabase_client_sdk::supabase_client_storage::StorageClient::new(
133 &self.url,
134 &self.key,
135 ).map_err(to_js_err)?;
136 Ok(WasmStorageClient { inner: storage })
137 }
138
139 pub fn functions(&self) -> Result<WasmFunctionsClient, JsValue> {
141 let functions = supabase_client_sdk::supabase_client_functions::FunctionsClient::new(
142 &self.url,
143 &self.key,
144 ).map_err(to_js_err)?;
145 Ok(WasmFunctionsClient { inner: functions })
146 }
147
148 pub fn graphql(&self) -> Result<WasmGraphqlClient, JsValue> {
150 let graphql = supabase_client_sdk::supabase_client_graphql::GraphqlClient::new(
151 &self.url,
152 &self.key,
153 ).map_err(to_js_err)?;
154 Ok(WasmGraphqlClient { inner: graphql })
155 }
156}
157
158#[wasm_bindgen]
162pub struct WasmAuthClient {
163 inner: AuthClient,
164}
165
166#[wasm_bindgen]
167impl WasmAuthClient {
168 pub async fn sign_up(&self, email: &str, password: &str) -> Result<JsValue, JsValue> {
170 let resp = self.inner.sign_up_with_email(email, password).await.map_err(to_js_err)?;
171 to_js_value(&resp)
172 }
173
174 pub async fn sign_in_with_password(&self, email: &str, password: &str) -> Result<JsValue, JsValue> {
176 let session = self.inner.sign_in_with_password_email(email, password).await.map_err(to_js_err)?;
177 to_js_value(&session)
178 }
179
180 pub async fn sign_in_anonymous(&self) -> Result<JsValue, JsValue> {
182 let session = self.inner.sign_in_anonymous().await.map_err(to_js_err)?;
183 to_js_value(&session)
184 }
185
186 pub async fn sign_in_with_otp(&self, email: &str) -> Result<(), JsValue> {
188 self.inner.sign_in_with_otp_email(email).await.map_err(to_js_err)
189 }
190
191 pub async fn get_session(&self) -> Result<JsValue, JsValue> {
193 match self.inner.get_session().await {
194 Some(session) => to_js_value(&session),
195 None => Ok(JsValue::NULL),
196 }
197 }
198
199 pub async fn refresh_session(&self) -> Result<JsValue, JsValue> {
201 let session = self.inner.refresh_current_session().await.map_err(to_js_err)?;
202 to_js_value(&session)
203 }
204
205 pub async fn sign_out(&self) -> Result<(), JsValue> {
207 self.inner.sign_out_current().await.map_err(to_js_err)
208 }
209
210 pub async fn get_user(&self, access_token: &str) -> Result<JsValue, JsValue> {
212 let user = self.inner.get_user(access_token).await.map_err(to_js_err)?;
213 to_js_value(&user)
214 }
215
216 pub async fn reset_password_for_email(&self, email: &str) -> Result<(), JsValue> {
218 self.inner.reset_password_for_email(email, None).await.map_err(to_js_err)
219 }
220
221 pub fn get_oauth_url(&self, provider: &str) -> Result<String, JsValue> {
223 let provider = match provider {
224 "google" => supabase_client_sdk::supabase_client_auth::OAuthProvider::Google,
225 "github" => supabase_client_sdk::supabase_client_auth::OAuthProvider::GitHub,
226 "apple" => supabase_client_sdk::supabase_client_auth::OAuthProvider::Apple,
227 "facebook" => supabase_client_sdk::supabase_client_auth::OAuthProvider::Facebook,
228 "twitter" => supabase_client_sdk::supabase_client_auth::OAuthProvider::Twitter,
229 "discord" => supabase_client_sdk::supabase_client_auth::OAuthProvider::Discord,
230 other => supabase_client_sdk::supabase_client_auth::OAuthProvider::Custom(other.to_string()),
231 };
232 self.inner.get_oauth_sign_in_url(provider, None, None).map_err(to_js_err)
233 }
234}
235
236#[wasm_bindgen]
240pub struct WasmRealtimeClient {
241 inner: RealtimeClient,
242}
243
244#[wasm_bindgen]
245impl WasmRealtimeClient {
246 pub async fn connect(&self) -> Result<(), JsValue> {
248 self.inner.connect().await.map_err(to_js_err)
249 }
250
251 pub async fn disconnect(&self) -> Result<(), JsValue> {
253 self.inner.disconnect().await.map_err(to_js_err)
254 }
255
256 pub fn is_connected(&self) -> bool {
258 self.inner.is_connected()
259 }
260}
261
262#[wasm_bindgen]
266pub struct WasmStorageClient {
267 inner: supabase_client_sdk::supabase_client_storage::StorageClient,
268}
269
270#[wasm_bindgen]
271impl WasmStorageClient {
272 pub async fn list_buckets(&self) -> Result<JsValue, JsValue> {
274 let buckets = self.inner.list_buckets().await.map_err(to_js_err)?;
275 to_js_value(&buckets)
276 }
277
278 pub async fn get_bucket(&self, id: &str) -> Result<JsValue, JsValue> {
280 let bucket = self.inner.get_bucket(id).await.map_err(to_js_err)?;
281 to_js_value(&bucket)
282 }
283}
284
285#[wasm_bindgen]
289pub struct WasmFunctionsClient {
290 inner: supabase_client_sdk::supabase_client_functions::FunctionsClient,
291}
292
293#[wasm_bindgen]
294impl WasmFunctionsClient {
295 pub async fn invoke(&self, function_name: &str, body: JsValue) -> Result<JsValue, JsValue> {
297 let json: JsonValue = serde_wasm_bindgen::from_value(body)?;
298 let options = InvokeOptions::default().body(json);
299 let response = self.inner
300 .invoke(function_name, options)
301 .await
302 .map_err(to_js_err)?;
303 let result: JsonValue = response.json().map_err(to_js_err)?;
304 to_js_value(&result)
305 }
306}
307
308#[wasm_bindgen]
312pub struct WasmGraphqlClient {
313 inner: supabase_client_sdk::supabase_client_graphql::GraphqlClient,
314}
315
316#[wasm_bindgen]
317impl WasmGraphqlClient {
318 pub async fn execute(
323 &self,
324 query: &str,
325 variables: JsValue,
326 ) -> Result<JsValue, JsValue> {
327 let vars: Option<JsonValue> = if variables.is_null() || variables.is_undefined() {
328 None
329 } else {
330 Some(serde_wasm_bindgen::from_value(variables)?)
331 };
332
333 let response = self.inner
334 .execute_raw(query, vars, None)
335 .await
336 .map_err(to_js_err)?;
337
338 to_js_value(&response.data)
339 }
340
341 pub fn set_auth(&self, token: &str) {
343 self.inner.set_auth(token);
344 }
345}