@tursodatabase/sync-react-native 0.5.0-pre.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/README.md +117 -0
  2. package/android/CMakeLists.txt +53 -0
  3. package/android/build.gradle +84 -0
  4. package/android/cpp-adapter.cpp +49 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/turso/sync/reactnative/TursoBridge.java +44 -0
  7. package/android/src/main/java/com/turso/sync/reactnative/TursoModule.java +82 -0
  8. package/android/src/main/java/com/turso/sync/reactnative/TursoPackage.java +29 -0
  9. package/cpp/TursoConnectionHostObject.cpp +179 -0
  10. package/cpp/TursoConnectionHostObject.h +52 -0
  11. package/cpp/TursoDatabaseHostObject.cpp +98 -0
  12. package/cpp/TursoDatabaseHostObject.h +49 -0
  13. package/cpp/TursoHostObject.cpp +561 -0
  14. package/cpp/TursoHostObject.h +24 -0
  15. package/cpp/TursoStatementHostObject.cpp +414 -0
  16. package/cpp/TursoStatementHostObject.h +65 -0
  17. package/cpp/TursoSyncChangesHostObject.cpp +41 -0
  18. package/cpp/TursoSyncChangesHostObject.h +52 -0
  19. package/cpp/TursoSyncDatabaseHostObject.cpp +328 -0
  20. package/cpp/TursoSyncDatabaseHostObject.h +61 -0
  21. package/cpp/TursoSyncIoItemHostObject.cpp +304 -0
  22. package/cpp/TursoSyncIoItemHostObject.h +52 -0
  23. package/cpp/TursoSyncOperationHostObject.cpp +168 -0
  24. package/cpp/TursoSyncOperationHostObject.h +53 -0
  25. package/ios/TursoModule.h +8 -0
  26. package/ios/TursoModule.mm +95 -0
  27. package/lib/commonjs/Database.js +445 -0
  28. package/lib/commonjs/Database.js.map +1 -0
  29. package/lib/commonjs/Statement.js +339 -0
  30. package/lib/commonjs/Statement.js.map +1 -0
  31. package/lib/commonjs/index.js +229 -0
  32. package/lib/commonjs/index.js.map +1 -0
  33. package/lib/commonjs/internal/asyncOperation.js +124 -0
  34. package/lib/commonjs/internal/asyncOperation.js.map +1 -0
  35. package/lib/commonjs/internal/ioProcessor.js +315 -0
  36. package/lib/commonjs/internal/ioProcessor.js.map +1 -0
  37. package/lib/commonjs/package.json +1 -0
  38. package/lib/commonjs/types.js +133 -0
  39. package/lib/commonjs/types.js.map +1 -0
  40. package/lib/module/Database.js +441 -0
  41. package/lib/module/Database.js.map +1 -0
  42. package/lib/module/Statement.js +335 -0
  43. package/lib/module/Statement.js.map +1 -0
  44. package/lib/module/index.js +205 -0
  45. package/lib/module/index.js.map +1 -0
  46. package/lib/module/internal/asyncOperation.js +116 -0
  47. package/lib/module/internal/asyncOperation.js.map +1 -0
  48. package/lib/module/internal/ioProcessor.js +309 -0
  49. package/lib/module/internal/ioProcessor.js.map +1 -0
  50. package/lib/module/package.json +1 -0
  51. package/lib/module/types.js +163 -0
  52. package/lib/module/types.js.map +1 -0
  53. package/lib/typescript/Database.d.ts +140 -0
  54. package/lib/typescript/Database.d.ts.map +1 -0
  55. package/lib/typescript/Statement.d.ts +105 -0
  56. package/lib/typescript/Statement.d.ts.map +1 -0
  57. package/lib/typescript/index.d.ts +175 -0
  58. package/lib/typescript/index.d.ts.map +1 -0
  59. package/lib/typescript/internal/asyncOperation.d.ts +39 -0
  60. package/lib/typescript/internal/asyncOperation.d.ts.map +1 -0
  61. package/lib/typescript/internal/ioProcessor.d.ts +48 -0
  62. package/lib/typescript/internal/ioProcessor.d.ts.map +1 -0
  63. package/lib/typescript/types.d.ts +316 -0
  64. package/lib/typescript/types.d.ts.map +1 -0
  65. package/package.json +97 -0
  66. package/src/Database.ts +480 -0
  67. package/src/Statement.ts +372 -0
  68. package/src/index.ts +240 -0
  69. package/src/internal/asyncOperation.ts +147 -0
  70. package/src/internal/ioProcessor.ts +328 -0
  71. package/src/types.ts +391 -0
  72. package/turso-sync-react-native.podspec +56 -0
package/README.md ADDED
@@ -0,0 +1,117 @@
1
+ # Turso Sync React Native SDK
2
+
3
+ React Native bindings for Turso embedded replicas - sync your local SQLite database with Turso cloud.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @tursodatabase/sync-react-native
9
+ ```
10
+
11
+ ### iOS
12
+
13
+ ```bash
14
+ cd ios && pod install
15
+ ```
16
+
17
+ ### Android
18
+
19
+ Requires `minSdkVersion` 21+ in `android/build.gradle`.
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { Database, getDbPath } from '@tursodatabase/sync-react-native';
25
+
26
+ // Get platform-specific writable path
27
+ const dbPath = getDbPath('myapp.db');
28
+
29
+ // Create database with sync
30
+ const db = new Database({
31
+ path: dbPath,
32
+ url: 'libsql://your-db.turso.io',
33
+ authToken: 'your-auth-token',
34
+ });
35
+
36
+ // Connect (bootstraps from remote if empty)
37
+ await db.connect();
38
+
39
+ // Query local replica (fast)
40
+ const users = await db.all('SELECT * FROM users');
41
+
42
+ // Make local changes
43
+ await db.run('INSERT INTO users (name) VALUES (?)', ['Alice']);
44
+
45
+ // Sync with remote
46
+ await db.push(); // Push local changes
47
+ await db.pull(); // Pull remote changes
48
+
49
+ // Close when done
50
+ await db.close();
51
+ ```
52
+
53
+ ## Local-Only Database
54
+
55
+ ```typescript
56
+ const db = new Database({ path: getDbPath('local.db') });
57
+ await db.connect();
58
+
59
+ await db.exec('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
60
+ await db.run('INSERT INTO users (name) VALUES (?)', ['Bob']);
61
+ const user = await db.get('SELECT * FROM users WHERE id = ?', [1]);
62
+
63
+ await db.close();
64
+ ```
65
+
66
+ ## Encrypted Remote Database
67
+
68
+ ```typescript
69
+ const db = new Database({
70
+ path: getDbPath('encrypted.db'),
71
+ url: 'libsql://your-db.turso.io',
72
+ authToken: 'your-auth-token',
73
+ remoteEncryption: {
74
+ cipher: 'aes256gcm',
75
+ key: 'base64-encoded-key',
76
+ },
77
+ });
78
+ ```
79
+
80
+ ## API
81
+
82
+ ### Database Methods
83
+
84
+ | Method | Description |
85
+ |--------|-------------|
86
+ | `connect()` | Open/bootstrap the database |
87
+ | `exec(sql)` | Execute SQL (no results) |
88
+ | `run(sql, params?)` | Execute SQL, return `{ changes, lastInsertRowid }` |
89
+ | `get(sql, params?)` | Query single row |
90
+ | `all(sql, params?)` | Query all rows |
91
+ | `prepare(sql)` | Create prepared statement |
92
+ | `close()` | Close database |
93
+
94
+ ### Sync Methods (when `url` is provided)
95
+
96
+ | Method | Description |
97
+ |--------|-------------|
98
+ | `push()` | Push local changes to remote |
99
+ | `pull()` | Pull remote changes to local |
100
+ | `sync()` | Push then pull |
101
+ | `stats()` | Get sync statistics |
102
+
103
+ ### Transactions
104
+
105
+ ```typescript
106
+ await db.transaction(async () => {
107
+ await db.run('INSERT INTO users (name) VALUES (?)', ['Alice']);
108
+ await db.run('INSERT INTO users (name) VALUES (?)', ['Bob']);
109
+ // Commits on success, rolls back on error
110
+ });
111
+ ```
112
+
113
+ ## Links
114
+
115
+ - [Turso Documentation](https://docs.turso.tech)
116
+ - [GitHub](https://github.com/tursodatabase/turso)
117
+ - [npm](https://www.npmjs.com/package/@tursodatabase/sync-react-native)
@@ -0,0 +1,53 @@
1
+ cmake_minimum_required(VERSION 3.22)
2
+ project(turso-sync-react-native)
3
+
4
+ set(CMAKE_CXX_STANDARD 20)
5
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
6
+
7
+ # Find packages
8
+ find_package(ReactAndroid REQUIRED CONFIG)
9
+ find_package(fbjni REQUIRED CONFIG)
10
+
11
+ # Source files
12
+ set(TURSO_SOURCES
13
+ cpp-adapter.cpp
14
+ ../cpp/TursoHostObject.cpp
15
+ ../cpp/TursoDatabaseHostObject.cpp
16
+ ../cpp/TursoConnectionHostObject.cpp
17
+ ../cpp/TursoStatementHostObject.cpp
18
+ ../cpp/TursoSyncDatabaseHostObject.cpp
19
+ ../cpp/TursoSyncOperationHostObject.cpp
20
+ ../cpp/TursoSyncIoItemHostObject.cpp
21
+ ../cpp/TursoSyncChangesHostObject.cpp
22
+ )
23
+
24
+ # Create shared library
25
+ add_library(${PROJECT_NAME} SHARED ${TURSO_SOURCES})
26
+
27
+ # 16KB page alignment for Android 15+ compatibility
28
+ target_link_options(${PROJECT_NAME} PRIVATE "-Wl,-z,max-page-size=16384")
29
+
30
+ # Include directories
31
+ target_include_directories(${PROJECT_NAME} PRIVATE
32
+ ../cpp
33
+ ../libs/android
34
+ )
35
+
36
+ # Pre-built Rust shared library (.so) loaded at runtime
37
+ add_library(turso_sync_sdk_kit SHARED IMPORTED)
38
+
39
+ # IMPORTED_NO_SONAME is important to properly adjust import paths for runtime by linker (so they will not be reused from build time)
40
+ set_target_properties(turso_sync_sdk_kit PROPERTIES
41
+ IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../libs/android/${ANDROID_ABI}/libturso_sync_sdk_kit.so
42
+ IMPORTED_NO_SONAME TRUE
43
+ )
44
+
45
+ # Link libraries (record runtime dependency on Rust .so)
46
+ target_link_libraries(${PROJECT_NAME}
47
+ ReactAndroid::jsi
48
+ ReactAndroid::reactnative
49
+ fbjni::fbjni
50
+ turso_sync_sdk_kit
51
+ android
52
+ log
53
+ )
@@ -0,0 +1,84 @@
1
+ buildscript {
2
+ repositories {
3
+ google()
4
+ mavenCentral()
5
+ }
6
+ dependencies {
7
+ classpath "com.android.tools.build:gradle:8.2.0"
8
+ }
9
+ }
10
+
11
+ plugins {
12
+ id "com.android.library"
13
+ }
14
+
15
+ def reactNativeArchitectures() {
16
+ def value = project.getProperties().get("reactNativeArchitectures")
17
+ return value ? value.split(",") : ["armeabi-v7a", "arm64-v8a", "x86", "x86_64"]
18
+ }
19
+
20
+ android {
21
+ namespace "com.turso.sync.reactnative"
22
+ compileSdk 34
23
+
24
+ defaultConfig {
25
+ minSdk 24
26
+ targetSdk 34
27
+
28
+ externalNativeBuild {
29
+ cmake {
30
+ cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
31
+ abiFilters(*reactNativeArchitectures())
32
+ arguments "-DANDROID_STL=c++_shared"
33
+ }
34
+ }
35
+ }
36
+
37
+ buildFeatures {
38
+ prefab true
39
+ buildConfig true
40
+ }
41
+
42
+ externalNativeBuild {
43
+ cmake {
44
+ path "CMakeLists.txt"
45
+ }
46
+ }
47
+
48
+ buildTypes {
49
+ release {
50
+ minifyEnabled false
51
+ }
52
+ }
53
+
54
+ packaging {
55
+ excludes += [
56
+ "**/libjsi.so",
57
+ "**/libfbjni.so",
58
+ "**/libc++_shared.so",
59
+ "**/libreactnative.so"
60
+ ]
61
+ }
62
+ sourceSets {
63
+ main {
64
+ jniLibs.srcDirs = ["../libs/android"]
65
+ }
66
+ }
67
+ }
68
+
69
+ repositories {
70
+ google()
71
+ mavenCentral()
72
+ }
73
+
74
+ dependencies {
75
+ compileOnly "com.facebook.react:react-android"
76
+ }
77
+
78
+ // Task to build Rust library for Android
79
+ task buildRustLibrary(type: Exec) {
80
+ workingDir "${projectDir}/.."
81
+ commandLine "make", "android"
82
+ }
83
+
84
+ preBuild.dependsOn buildRustLibrary
@@ -0,0 +1,49 @@
1
+ #include "TursoHostObject.h"
2
+ #include <ReactCommon/CallInvokerHolder.h>
3
+ #include <fbjni/fbjni.h>
4
+ #include <jni.h>
5
+ #include <jsi/jsi.h>
6
+ #include <typeinfo>
7
+
8
+ namespace jsi = facebook::jsi;
9
+ namespace react = facebook::react;
10
+ namespace jni = facebook::jni;
11
+
12
+ // This file is not using raw jni but rather fbjni, do not change how the native
13
+ // functions are registered
14
+ // https://github.com/facebookincubator/fbjni/blob/main/docs/quickref.md
15
+ struct TursoBridge : jni::JavaClass<TursoBridge>
16
+ {
17
+ static constexpr auto kJavaDescriptor = "Lcom/turso/sync/reactnative/TursoBridge;";
18
+
19
+ static void registerNatives()
20
+ {
21
+ javaClassStatic()->registerNatives(
22
+ {makeNativeMethod("installNativeJsi", TursoBridge::installNativeJsi),
23
+ makeNativeMethod("clearStateNativeJsi", TursoBridge::clearStateNativeJsi)});
24
+ }
25
+
26
+ private:
27
+ static void installNativeJsi(
28
+ jni::alias_ref<jni::JObject> thiz, jlong jsiRuntimePtr,
29
+ jni::alias_ref<react::CallInvokerHolder::javaobject> jsCallInvokerHolder,
30
+ jni::alias_ref<jni::JString> dbPath)
31
+ {
32
+ auto jsiRuntime = reinterpret_cast<jsi::Runtime *>(jsiRuntimePtr);
33
+ auto jsCallInvoker = jsCallInvokerHolder->cthis()->getCallInvoker();
34
+ std::string dbPathStr = dbPath->toStdString();
35
+
36
+ turso::install(*jsiRuntime, jsCallInvoker, dbPathStr.c_str());
37
+ }
38
+
39
+ static void clearStateNativeJsi(jni::alias_ref<jni::JObject> thiz)
40
+ {
41
+ turso::invalidate();
42
+ }
43
+ };
44
+
45
+ JNIEXPORT jint JNI_OnLoad(JavaVM *vm, void *)
46
+ {
47
+ return jni::initialize(vm, []
48
+ { TursoBridge::registerNatives(); });
49
+ }
@@ -0,0 +1,2 @@
1
+ <manifest xmlns:android="http://schemas.android.com/apk/res/android">
2
+ </manifest>
@@ -0,0 +1,44 @@
1
+ package com.turso.sync.reactnative;
2
+
3
+ import com.facebook.react.bridge.ReactContext;
4
+ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
5
+
6
+ import java.lang.Exception;
7
+
8
+ // bridge layer, installNativeJsi/clearStateNativeJsi methods are set through cpp-adapter.cpp
9
+ public class TursoBridge {
10
+ private static final TursoBridge instance = new TursoBridge();
11
+
12
+ public static TursoBridge getInstance() {
13
+ return instance;
14
+ }
15
+
16
+ private TursoBridge() {
17
+ }
18
+
19
+ private native void installNativeJsi(
20
+ long jsContextNativePointer,
21
+ CallInvokerHolderImpl jsCallInvokerHolder,
22
+ String dbPath);
23
+
24
+ private native void clearStateNativeJsi();
25
+
26
+ public void install(ReactContext context) throws Exception {
27
+ long jsContextPointer = context.getJavaScriptContextHolder().get();
28
+ if (jsContextPointer == 0) {
29
+ throw new Exception("jsContextPointer == 0");
30
+ }
31
+ CallInvokerHolderImpl jsCallInvokerHolder = (CallInvokerHolderImpl) context.getCatalystInstance()
32
+ .getJSCallInvokerHolder();
33
+
34
+ // getDatabasePath(...) returns file path - so we pass dummy value and remove it
35
+ // after to get directory path
36
+ String dbPath = context.getDatabasePath("tursoDatabaseFile").getAbsolutePath().replace("tursoDatabaseFile", "");
37
+
38
+ installNativeJsi(jsContextPointer, jsCallInvokerHolder, dbPath);
39
+ }
40
+
41
+ public void invalidate() {
42
+ clearStateNativeJsi();
43
+ }
44
+ }
@@ -0,0 +1,82 @@
1
+ package com.turso.sync.reactnative;
2
+
3
+ import java.io.File;
4
+ import java.lang.Exception;
5
+ import java.util.HashMap;
6
+ import java.util.Map;
7
+
8
+ import androidx.annotation.NonNull;
9
+
10
+ import com.facebook.react.bridge.ReactApplicationContext;
11
+ import com.facebook.react.bridge.ReactContextBaseJavaModule;
12
+ import com.facebook.react.bridge.ReactMethod;
13
+ import com.facebook.react.module.annotations.ReactModule;
14
+ import com.facebook.react.turbomodule.core.CallInvokerHolderImpl;
15
+
16
+ // The React Native bridge - exposes methods to JavaScript
17
+ @ReactModule(name = TursoModule.NAME)
18
+ public class TursoModule extends ReactContextBaseJavaModule {
19
+ public static final String NAME = "Turso";
20
+
21
+ static {
22
+ System.loadLibrary("turso_sync_sdk_kit");
23
+ System.loadLibrary("turso-sync-react-native");
24
+ }
25
+
26
+ public TursoModule(ReactApplicationContext reactContext) {
27
+ super(reactContext);
28
+ }
29
+
30
+ @Override
31
+ @NonNull
32
+ public String getName() {
33
+ return NAME;
34
+ }
35
+
36
+ @Override
37
+ public Map<String, Object> getConstants() {
38
+ final Map<String, Object> constants = new HashMap<>();
39
+ ReactApplicationContext context = getReactApplicationContext();
40
+
41
+ // getDatabasePath(...) returns file path - so we pass dummy value and remove it
42
+ // after to get directory path
43
+ String dbPath = context.getDatabasePath("tursoDatabaseFile").getAbsolutePath().replace("tursoDatabaseFile", "");
44
+ constants.put("ANDROID_DATABASE_PATH", dbPath);
45
+
46
+ String filesPath = context.getFilesDir().getAbsolutePath();
47
+ constants.put("ANDROID_FILES_PATH", filesPath);
48
+
49
+ File externalFilesDir = context.getExternalFilesDir(null);
50
+ constants.put("ANDROID_EXTERNAL_FILES_PATH",
51
+ externalFilesDir != null ? externalFilesDir.getAbsolutePath() : null);
52
+
53
+ // populate Android and IOS constants to simplify JS code (e.g.
54
+ // IOS_DOCUMENT_PATH ?? ANDROID_DATABASE_PATH)
55
+ constants.put("IOS_DOCUMENT_PATH", null);
56
+ constants.put("IOS_LIBRARY_PATH", null);
57
+
58
+ return constants;
59
+ }
60
+
61
+ @ReactMethod(isBlockingSynchronousMethod = true)
62
+ public boolean install() {
63
+ try {
64
+ ReactApplicationContext context = getReactApplicationContext();
65
+ // Install native module
66
+ TursoBridge.getInstance().install(context);
67
+ return true;
68
+ } catch (Exception e) {
69
+ return false;
70
+ }
71
+ }
72
+
73
+ @Override
74
+ public void invalidate() {
75
+ super.invalidate();
76
+ TursoBridge.getInstance().invalidate();
77
+ }
78
+
79
+ private native void installNativeJsi(long jsiRuntimePtr, Object callInvokerHolder, String dbPath);
80
+
81
+ private native void clearStateNativeJsi();
82
+ }
@@ -0,0 +1,29 @@
1
+ package com.turso.sync.reactnative;
2
+
3
+ import androidx.annotation.NonNull;
4
+
5
+ import com.facebook.react.ReactPackage;
6
+ import com.facebook.react.bridge.NativeModule;
7
+ import com.facebook.react.bridge.ReactApplicationContext;
8
+ import com.facebook.react.uimanager.ViewManager;
9
+
10
+ import java.util.ArrayList;
11
+ import java.util.Collections;
12
+ import java.util.List;
13
+
14
+ // Entry point for React Native's module registration system
15
+ public class TursoPackage implements ReactPackage {
16
+ @NonNull
17
+ @Override
18
+ public List<NativeModule> createNativeModules(@NonNull ReactApplicationContext reactContext) {
19
+ List<NativeModule> modules = new ArrayList<>();
20
+ modules.add(new TursoModule(reactContext));
21
+ return modules;
22
+ }
23
+
24
+ @NonNull
25
+ @Override
26
+ public List<ViewManager> createViewManagers(@NonNull ReactApplicationContext reactContext) {
27
+ return Collections.emptyList();
28
+ }
29
+ }
@@ -0,0 +1,179 @@
1
+ #include "TursoConnectionHostObject.h"
2
+ #include "TursoStatementHostObject.h"
3
+
4
+ extern "C" {
5
+ #include <turso.h>
6
+ }
7
+
8
+ namespace turso {
9
+
10
+ TursoConnectionHostObject::~TursoConnectionHostObject() {
11
+ if (conn_) {
12
+ turso_connection_deinit(conn_);
13
+ conn_ = nullptr;
14
+ }
15
+ }
16
+
17
+ void TursoConnectionHostObject::throwError(jsi::Runtime &rt, const char *error) {
18
+ throw jsi::JSError(rt, error ? error : "Unknown error");
19
+ }
20
+
21
+ jsi::Value TursoConnectionHostObject::get(jsi::Runtime &rt, const jsi::PropNameID &name) {
22
+ auto propName = name.utf8(rt);
23
+
24
+ if (propName == "prepareSingle") {
25
+ return jsi::Function::createFromHostFunction(
26
+ rt, name, 1,
27
+ [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, size_t count) -> jsi::Value {
28
+ return this->prepareSingle(rt, args, count);
29
+ }
30
+ );
31
+ }
32
+
33
+ if (propName == "prepareFirst") {
34
+ return jsi::Function::createFromHostFunction(
35
+ rt, name, 1,
36
+ [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, size_t count) -> jsi::Value {
37
+ return this->prepareFirst(rt, args, count);
38
+ }
39
+ );
40
+ }
41
+
42
+ if (propName == "lastInsertRowid") {
43
+ return jsi::Function::createFromHostFunction(
44
+ rt, name, 0,
45
+ [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, size_t) -> jsi::Value {
46
+ return this->lastInsertRowid(rt);
47
+ }
48
+ );
49
+ }
50
+
51
+ if (propName == "getAutocommit") {
52
+ return jsi::Function::createFromHostFunction(
53
+ rt, name, 0,
54
+ [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, size_t) -> jsi::Value {
55
+ return this->getAutocommit(rt);
56
+ }
57
+ );
58
+ }
59
+
60
+ if (propName == "setBusyTimeout") {
61
+ return jsi::Function::createFromHostFunction(
62
+ rt, name, 1,
63
+ [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *args, size_t count) -> jsi::Value {
64
+ return this->setBusyTimeout(rt, args, count);
65
+ }
66
+ );
67
+ }
68
+
69
+ if (propName == "close") {
70
+ return jsi::Function::createFromHostFunction(
71
+ rt, name, 0,
72
+ [this](jsi::Runtime &rt, const jsi::Value &, const jsi::Value *, size_t) -> jsi::Value {
73
+ return this->close(rt);
74
+ }
75
+ );
76
+ }
77
+
78
+ return jsi::Value::undefined();
79
+ }
80
+
81
+ void TursoConnectionHostObject::set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi::Value &value) {
82
+ // Read-only object
83
+ }
84
+
85
+ std::vector<jsi::PropNameID> TursoConnectionHostObject::getPropertyNames(jsi::Runtime &rt) {
86
+ std::vector<jsi::PropNameID> props;
87
+ props.emplace_back(jsi::PropNameID::forAscii(rt, "prepareSingle"));
88
+ props.emplace_back(jsi::PropNameID::forAscii(rt, "prepareFirst"));
89
+ props.emplace_back(jsi::PropNameID::forAscii(rt, "lastInsertRowid"));
90
+ props.emplace_back(jsi::PropNameID::forAscii(rt, "getAutocommit"));
91
+ props.emplace_back(jsi::PropNameID::forAscii(rt, "setBusyTimeout"));
92
+ props.emplace_back(jsi::PropNameID::forAscii(rt, "close"));
93
+ return props;
94
+ }
95
+
96
+ // 1:1 C API mapping - NO logic, just calls through to C API
97
+ jsi::Value TursoConnectionHostObject::prepareSingle(jsi::Runtime &rt, const jsi::Value *args, size_t count) {
98
+ if (count < 1 || !args[0].isString()) {
99
+ throw jsi::JSError(rt, "prepareSingle: expected string argument");
100
+ }
101
+
102
+ std::string sql = args[0].asString(rt).utf8(rt);
103
+ turso_statement_t* statement = nullptr;
104
+ const char* error = nullptr;
105
+
106
+ turso_status_code_t status = turso_connection_prepare_single(conn_, sql.c_str(), &statement, &error);
107
+
108
+ if (status != TURSO_OK) {
109
+ throwError(rt, error);
110
+ }
111
+
112
+ // Wrap statement in TursoStatementHostObject
113
+ auto statementObj = std::make_shared<TursoStatementHostObject>(statement);
114
+ return jsi::Object::createFromHostObject(rt, statementObj);
115
+ }
116
+
117
+ jsi::Value TursoConnectionHostObject::prepareFirst(jsi::Runtime &rt, const jsi::Value *args, size_t count) {
118
+ if (count < 1 || !args[0].isString()) {
119
+ throw jsi::JSError(rt, "prepareFirst: expected string argument");
120
+ }
121
+
122
+ std::string sql = args[0].asString(rt).utf8(rt);
123
+ turso_statement_t* statement = nullptr;
124
+ size_t tail_idx = 0;
125
+ const char* error = nullptr;
126
+
127
+ turso_status_code_t status = turso_connection_prepare_first(conn_, sql.c_str(), &statement, &tail_idx, &error);
128
+
129
+ if (status != TURSO_OK) {
130
+ throwError(rt, error);
131
+ }
132
+
133
+ // If statement is null, return null (no valid statement parsed)
134
+ if (!statement) {
135
+ return jsi::Value::null();
136
+ }
137
+
138
+ // Return object with statement and tail_idx
139
+ jsi::Object result(rt);
140
+ auto statementObj = std::make_shared<TursoStatementHostObject>(statement);
141
+ result.setProperty(rt, "statement", jsi::Object::createFromHostObject(rt, statementObj));
142
+ result.setProperty(rt, "tailIdx", jsi::Value(static_cast<double>(tail_idx)));
143
+
144
+ return result;
145
+ }
146
+
147
+ jsi::Value TursoConnectionHostObject::lastInsertRowid(jsi::Runtime &rt) {
148
+ int64_t rowid = turso_connection_last_insert_rowid(conn_);
149
+ return jsi::Value(static_cast<double>(rowid));
150
+ }
151
+
152
+ jsi::Value TursoConnectionHostObject::getAutocommit(jsi::Runtime &rt) {
153
+ bool autocommit = turso_connection_get_autocommit(conn_);
154
+ return jsi::Value(autocommit);
155
+ }
156
+
157
+ jsi::Value TursoConnectionHostObject::setBusyTimeout(jsi::Runtime &rt, const jsi::Value *args, size_t count) {
158
+ if (count < 1 || !args[0].isNumber()) {
159
+ throw jsi::JSError(rt, "setBusyTimeout: expected number argument");
160
+ }
161
+
162
+ int64_t timeout_ms = static_cast<int64_t>(args[0].asNumber());
163
+ turso_connection_set_busy_timeout_ms(conn_, timeout_ms);
164
+
165
+ return jsi::Value::undefined();
166
+ }
167
+
168
+ jsi::Value TursoConnectionHostObject::close(jsi::Runtime &rt) {
169
+ const char* error = nullptr;
170
+ turso_status_code_t status = turso_connection_close(conn_, &error);
171
+
172
+ if (status != TURSO_OK) {
173
+ throwError(rt, error);
174
+ }
175
+
176
+ return jsi::Value::undefined();
177
+ }
178
+
179
+ } // namespace turso
@@ -0,0 +1,52 @@
1
+ #pragma once
2
+
3
+ #include <jsi/jsi.h>
4
+ #include <memory>
5
+ #include <string>
6
+
7
+ // Forward declarations for Turso C API types
8
+ extern "C" {
9
+ struct turso_connection;
10
+ struct turso_statement;
11
+ typedef struct turso_connection turso_connection_t;
12
+ typedef struct turso_statement turso_statement_t;
13
+ }
14
+
15
+ namespace turso {
16
+
17
+ using namespace facebook;
18
+
19
+ /**
20
+ * TursoConnectionHostObject wraps turso_connection_t* (core SDK-KIT type for database connection).
21
+ * This is a THIN wrapper - 1:1 mapping of SDK-KIT C API with NO logic.
22
+ * All logic belongs in TypeScript or Rust, not here.
23
+ */
24
+ class TursoConnectionHostObject : public jsi::HostObject {
25
+ public:
26
+ TursoConnectionHostObject(turso_connection_t* conn) : conn_(conn) {}
27
+ ~TursoConnectionHostObject();
28
+
29
+ // JSI HostObject interface
30
+ jsi::Value get(jsi::Runtime &rt, const jsi::PropNameID &name) override;
31
+ void set(jsi::Runtime &rt, const jsi::PropNameID &name, const jsi::Value &value) override;
32
+ std::vector<jsi::PropNameID> getPropertyNames(jsi::Runtime &rt) override;
33
+
34
+ // Direct access to wrapped pointer (for internal use)
35
+ turso_connection_t* getConnection() const { return conn_; }
36
+
37
+ private:
38
+ turso_connection_t* conn_ = nullptr;
39
+
40
+ // Helper to throw JS errors
41
+ void throwError(jsi::Runtime &rt, const char *error);
42
+
43
+ // 1:1 C API mapping methods (NO logic - just calls through to C API)
44
+ jsi::Value prepareSingle(jsi::Runtime &rt, const jsi::Value *args, size_t count);
45
+ jsi::Value prepareFirst(jsi::Runtime &rt, const jsi::Value *args, size_t count);
46
+ jsi::Value lastInsertRowid(jsi::Runtime &rt);
47
+ jsi::Value getAutocommit(jsi::Runtime &rt);
48
+ jsi::Value setBusyTimeout(jsi::Runtime &rt, const jsi::Value *args, size_t count);
49
+ jsi::Value close(jsi::Runtime &rt);
50
+ };
51
+
52
+ } // namespace turso