@@ -10,6 +10,7 @@ extern crate napi_derive;
1010use napi:: bindgen_prelude:: { Array , FromNapiValue , ToNapiValue } ;
1111use napi:: { Env , JsUnknown , Result , ValueType } ;
1212use once_cell:: sync:: OnceCell ;
13+ use std:: str:: FromStr ;
1314use std:: sync:: atomic:: { AtomicBool , Ordering } ;
1415use std:: sync:: Arc ;
1516use std:: time:: Duration ;
@@ -167,6 +168,8 @@ pub struct Options {
167168 pub authToken : Option < String > ,
168169 pub syncUrl : Option < String > ,
169170 pub syncPeriod : Option < f64 > ,
171+ pub encryptionCipher : Option < String > ,
172+ pub encryptionKey : Option < String > ,
170173}
171174
172175/// Database connection.
@@ -191,23 +194,45 @@ impl Database {
191194 ensure_logger ( ) ;
192195 let rt = runtime ( ) ?;
193196 let remote = is_remote_path ( & path) ;
194-
195197 let db = if remote {
196198 let auth_token = opts
197199 . as_ref ( )
198200 . and_then ( |o| o. authToken . as_ref ( ) )
199201 . cloned ( )
200202 . unwrap_or_default ( ) ;
201-
202203 let builder = libsql:: Builder :: new_remote ( path. clone ( ) , auth_token) ;
203204 rt. block_on ( builder. build ( ) ) . map_err ( Error :: from) ?
204205 } else if let Some ( options) = & opts {
205206 if let Some ( sync_url) = & options. syncUrl {
206207 let auth_token = options. authToken . as_ref ( ) . cloned ( ) . unwrap_or_default ( ) ;
207208
209+ let encryption_cipher: String = opts
210+ . as_ref ( )
211+ . and_then ( |o| o. encryptionCipher . as_ref ( ) )
212+ . cloned ( )
213+ . unwrap_or ( "aes256cbc" . to_string ( ) ) ;
214+ let cipher = libsql:: Cipher :: from_str ( & encryption_cipher) . map_err ( |_| {
215+ throw_sqlite_error (
216+ "Invalid encryption cipher" . to_string ( ) ,
217+ "SQLITE_INVALID_ENCRYPTION_CIPHER" . to_string ( ) ,
218+ 0 ,
219+ )
220+ } ) ?;
221+ let encryption_key = opts
222+ . as_ref ( )
223+ . and_then ( |o| o. encryptionKey . as_ref ( ) )
224+ . cloned ( )
225+ . unwrap_or ( "" . to_string ( ) ) ;
226+
208227 let mut builder =
209228 libsql:: Builder :: new_remote_replica ( path. clone ( ) , sync_url. clone ( ) , auth_token) ;
210229
230+ if encryption_key. len ( ) > 0 {
231+ let encryption_config =
232+ libsql:: EncryptionConfig :: new ( cipher, encryption_key. into ( ) ) ;
233+ builder = builder. encryption_config ( encryption_config) ;
234+ }
235+
211236 if let Some ( period) = options. syncPeriod {
212237 if period > 0.0 {
213238 builder = builder. sync_interval ( std:: time:: Duration :: from_secs_f64 ( period) ) ;
@@ -349,22 +374,23 @@ impl Database {
349374
350375 rt. block_on ( async move {
351376 let conn = conn. lock ( ) . await ;
352-
377+
353378 // Enable extension loading
354379 conn. load_extension_enable ( ) . map_err ( Error :: from) ?;
355-
380+
356381 // Load the extension
357382 if let Err ( err) = conn. load_extension ( & path, entry_point. as_deref ( ) ) {
358383 // Disable extension loading on error
359384 let _ = conn. load_extension_disable ( ) ;
360385 return Err ( Error :: from ( err) ) ;
361386 }
362-
387+
363388 // Disable extension loading after successful load
364389 conn. load_extension_disable ( ) . map_err ( Error :: from) ?;
365-
390+
366391 Ok ( ( ) )
367- } ) . map_err ( |e| napi:: Error :: from ( e) )
392+ } )
393+ . map_err ( |e| napi:: Error :: from ( e) )
368394 }
369395
370396 #[ napi]
0 commit comments