### Develop Tauri App Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/CLAUDE.md Starts the Tauri development server for the todo-list example. Navigate to the example directory and use bun to run the development server. ```bash cd examples/todo-list && bun run tauri dev ``` -------------------------------- ### Build and Run Example App Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Steps to build the JS plugin API package and run the example application. ```bash pnpm install pnpm build cd examples/todo-list pnpm install pnpm run tauri dev ``` -------------------------------- ### Install Dependencies Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/examples/todo-list/README.md Install project dependencies using Bun. Ensure you have Bun or Node.js v18+ installed. ```bash bun install ``` -------------------------------- ### Start Development Server Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/examples/todo-list/README.md Start the Tauri development server to run the application. This command compiles and launches the app. ```bash bun run tauri dev ``` -------------------------------- ### Complete Tauri Application Setup with Drizzle ORM Source: https://context7.com/huakunshen/tauri-plugin-libsql/llms.txt Full example showing database initialization, migrations, and Drizzle ORM usage in a Tauri application. It bundles migrations at build time, loads the database connection, runs pending migrations, and returns a Drizzle instance for type-safe operations. ```typescript // src/lib/db.ts import { drizzle } from "drizzle-orm/sqlite-proxy"; import { Database, migrate, createDrizzleProxy } from "tauri-plugin-libsql-api"; import * as schema from "./schema"; const DB_PATH = "sqlite:app.db"; export async function initDatabase() { // Bundle migrations at build time const migrations = import.meta.glob("../../drizzle/*.sql", { eager: true, query: "?raw", import: "default", }); // Load database connection await Database.load(DB_PATH); // Run pending migrations await migrate(DB_PATH, migrations); // Return Drizzle instance return drizzle(createDrizzleProxy(DB_PATH), { schema }); } // Usage in app import { eq } from "drizzle-orm"; const db = await initDatabase(); // Create user const [user] = await db .insert(schema.users) .values({ name: "Alice", email: "alice@example.com" }) .returning(); // Create todo for user await db.insert(schema.todos).values({ userId: user.id, title: "Complete project", }); // Query with join const userTodos = await db .select({ todoId: schema.todos.id, todoTitle: schema.todos.title, userName: schema.users.name, }) .from(schema.todos) .leftJoin(schema.users, eq(schema.todos.userId, schema.users.id)); ``` -------------------------------- ### Install Tauri Plugin libsql API (JavaScript/TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Install the JavaScript/TypeScript API package for the Tauri Plugin libsql. ```bash npm install tauri-plugin-libsql-api # or pnpm add tauri-plugin-libsql-api ``` -------------------------------- ### Install tauri-plugin-libsql-api Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Install the necessary API package for your Tauri application using npm. ```bash npm install tauri-plugin-libsql-api ``` -------------------------------- ### Database.load() Simple Usage (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Basic example of loading a SQLite database using a file path. ```typescript // Simple const db = await Database.load("sqlite:myapp.db"); ``` -------------------------------- ### Tauri Plugin LibSQL Startup Sequence Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/AGENTS.md Example TypeScript code demonstrating the startup sequence for using the tauri-plugin-libsql. It covers loading the database, running migrations, and initializing Drizzle ORM. ```typescript // 1. Load database await Database.load('sqlite:app.db'); // 2. Run migrations (before any queries!) await migrate('sqlite:app.db', migrations); // 3. Now safe to use Drizzle const db = drizzle(createDrizzleProxy('sqlite:app.db'), { schema }); ``` -------------------------------- ### Demo App: Local SQLite Todo List Component Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Example of using the TodoList component with a local SQLite database file. Writes are instant with this configuration. ```svelte ``` -------------------------------- ### App Startup with Tauri Plugin LibSQL Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md Example of integrating tauri-plugin-libsql into a Svelte application startup. It loads the database, runs migrations, and initializes Drizzle ORM with the defined schema. ```typescript import { Database, migrate, createDrizzleProxy } from 'tauri-plugin-libsql-api'; import { drizzle } from 'drizzle-orm/sqlite-proxy'; import * as schema from './schema'; // import.meta.glob path is relative to this source file const migrations = import.meta.glob('../drizzle/*.sql', { eager: true, query: '?raw', import: 'default', }); const dbPath = 'sqlite:myapp.db'; await Database.load(dbPath); await migrate(dbPath, migrations); const db = drizzle(createDrizzleProxy(dbPath), { schema }); ``` -------------------------------- ### Install Tauri Plugin libsql (Rust) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Add the tauri-plugin-libsql dependency to your Rust project's Cargo.toml file. ```toml [dependencies] tauri-plugin-libsql = "0.1.0" ``` -------------------------------- ### API Reference: Database.load Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Provides the signature and usage examples for the `Database.load` method, including options for simple loading and encrypted databases. ```APIDOC ## API Reference ### `Database.load(pathOrOptions)` ### Description Loads a SQLite database connection. Accepts either a simple path string or an options object for more advanced configurations like encryption. ### Usage **Simple Path** ```typescript // Simple const db = await Database.load("sqlite:myapp.db"); ``` **With Encryption** ```typescript // With encryption const db = await Database.load({ path: "sqlite:myapp.db", encryption: { cipher: "aes256cbc", key: myKey }, }); ``` ``` -------------------------------- ### Start Dev Server with Encryption Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/examples/todo-list/README.md Run the Tauri development server with AES-256 encryption enabled for the local database. The encryption key is automatically padded or truncated to 32 bytes. ```bash LIBSQL_ENCRYPTION_KEY=my-secret-key bun run tauri dev ``` -------------------------------- ### Drizzle ORM Setup (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Integrates Drizzle ORM with Tauri Plugin LibSQL using a proxy. The proxy lazily loads the database connection. ```typescript import { drizzle } from "drizzle-orm/sqlite-proxy"; import { createDrizzleProxy } from "tauri-plugin-libsql-api"; import * as schema from "./schema"; const db = drizzle(createDrizzleProxy("sqlite:myapp.db"), { schema }); const users = await db.select().from(schema.users); ``` -------------------------------- ### Configure Plugin-level Encryption Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md Example of configuring AES-256-CBC encryption for the tauri-plugin-libsql at the plugin level. The encryption key is managed within the Rust backend, recommended for security. ```rust // src-tauri/src/lib.rs let config = tauri_plugin_libsql::Config { base_path: Some(cwd), encryption: Some(tauri_plugin_libsql::EncryptionConfig { cipher: tauri_plugin_libsql::Cipher::Aes256Cbc, key: my_32_byte_vec, // Vec }), }; tauri::Builder::default() .plugin(tauri_plugin_libsql::init_with_config(config)) ... ``` -------------------------------- ### Per-Database Encryption Setup (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Loads a SQLite database with per-database encryption directly from the frontend. Generates a random 32-byte key. ```typescript const key = new Uint8Array(32); crypto.getRandomValues(key); const db = await Database.load({ path: "sqlite:secrets.db", encryption: { cipher: "aes256cbc", key: Array.from(key), // number[] or Uint8Array }, }); ``` -------------------------------- ### Migrate with Custom Table Name (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Example of running migrations with a custom table name for tracking migration status. ```typescript await migrate("sqlite:myapp.db", migrations, { migrationsTable: "__my_migrations", // default: '__drizzle_migrations' }); ``` -------------------------------- ### Demo App: Turso Embedded Replica Todo List Component Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Example of using the TodoList component with Turso for remote data synchronization. Writes involve network latency. ```svelte ``` -------------------------------- ### Get Plugin Configuration Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Retrieve the current configuration of the tauri-plugin-libsql, including whether the database is encrypted. ```typescript import { getConfig } from 'tauri-plugin-libsql-api'; const { encrypted } = await getConfig(); ``` -------------------------------- ### Configure Permissions for Tauri Libsql Commands Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md Define permissions in `permissions/default.toml` to allow specific Tauri commands for the Libsql plugin. This example allows all commands related to load, execute, select, and close operations. ```json { "permissions": [ "libsql:allow-load", "libsql:allow-execute", "libsql:allow-select", "libsql:allow-close" ] } ``` -------------------------------- ### Mutex Lock Discipline Example Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/src/AGENTS.md Demonstrates the correct way to handle mutex locks in asynchronous Rust to avoid deadlocks. Clone the `Arc` while holding the lock and release the lock before making `await` calls. ```rust let conn = { let instances = db_instances.0.lock().await; instances.get(&db).ok_or(...)?.clone() }; conn.execute(...).await // lock released ``` -------------------------------- ### Feature-Gated Code Example Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/src/AGENTS.md Illustrates how to conditionally compile code based on feature flags. Use `#[cfg(feature = "...")]` for code that requires a specific feature, and `#[cfg(not(feature = "..."))]` for fallback or unsupported implementations. ```rust #[cfg(feature = "replication")] async fn open_replica(...) -> Result { ... } ``` ```rust #[cfg(not(feature = "replication"))] async fn open_replica(...) -> Result { Err(Error::OperationNotSupported("replication feature required".into())) } ``` -------------------------------- ### Run Migrations on Startup (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Loads the database, applies pending migrations using the bundled SQL files, and then allows safe querying. Assumes Vite bundling. ```typescript import { Database, migrate } from "tauri-plugin-libsql-api"; // Vite bundles these SQL files into the app at build time const migrations = import.meta.glob("./drizzle/*.sql", { eager: true, query: "?raw", import: "default", }); // Startup sequence: load → migrate → query await Database.load("sqlite:myapp.db"); await migrate("sqlite:myapp.db", migrations); // Now safe to query const db = drizzle(createDrizzleProxy("sqlite:myapp.db"), { schema }); ``` -------------------------------- ### Run Migrations at Startup Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Pre-bundle SQL migration files using Vite's import.meta.glob and run them at application startup using the migrate function. This ensures the database schema is up-to-date before queries are executed. ```typescript import { Database, migrate } from 'tauri-plugin-libsql-api'; // Vite 在构建时将这些 SQL 文件打包到应用中 const migrations = import.meta.glob('./drizzle/*.sql', { eager: true, query: '?raw', import: 'default', }); // 启动顺序:加载 → 迁移 → 查询 await Database.load('sqlite:myapp.db'); await migrate('sqlite:myapp.db', migrations); // 现在可以安全地查询 const db = drizzle(createDrizzleProxy('sqlite:myapp.db'), { schema }); ``` -------------------------------- ### Tauri Plugin LibSQL Startup Sequence Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/CLAUDE.md Demonstrates the correct startup sequence for using the tauri-plugin-libsql. It covers loading the database, running migrations, and initializing Drizzle ORM. ```typescript // 1. Load database await Database.load('sqlite:app.db'); // 2. Run migrations (before any queries!) await migrate('sqlite:app.db', migrations); // 3. Now safe to use Drizzle const db = drizzle(createDrizzleProxy('sqlite:app.db'), { schema }); ``` -------------------------------- ### Database Startup Sequence Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/examples/todo-list/README.md Illustrates the sequence of operations for initializing a database instance within the TodoList component. This includes loading the database, running migrations, and then performing queries. ```typescript // 1. Open/create the database file (initial Turso sync if syncUrl set) dbInstance = await Database.load(options); // 2. Run pending migrations await migrate(dbPath, migrations); // 3. Now safe to query await loadTodos(); ``` -------------------------------- ### Configure libsql Builder for Different Modes Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Demonstrates how to initialize the libsql builder for local-only databases, embedded replicas with Turso sync, and includes a call to sync data upon connection. ```rust // Local only let db = Builder::new_local("myapp.db").build().await?; // Embedded replica (local file + Turso sync) let db = Builder::new_remote_replica("local.db", "libsql://mydb.turso.io", "token") .build().await?; // Initial sync on connect db.sync().await?; ``` -------------------------------- ### Initialize and Migrate Database with Drizzle Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/guest-js/AGENTS.md This pattern shows how to bundle SQL migrations, load the database, run migrations, and initialize a Drizzle ORM instance. Ensure migrations are bundled correctly and queries are made after migration. ```typescript import { Database, migrate, createDrizzleProxy } from 'tauri-plugin-libsql-api'; import { drizzle } from 'drizzle-orm/sqlite-proxy'; import * as schema from './schema'; // 1. Bundle migrations at build time const migrations = import.meta.glob('../drizzle/*.sql', { eager: true, query: '?raw', import: 'default', }); // 2. Load → migrate → use const dbPath = 'sqlite:app.db'; await Database.load(dbPath); await migrate(dbPath, migrations); const db = drizzle(createDrizzleProxy(dbPath), { schema }); ``` -------------------------------- ### Get Plugin Configuration (getConfig) Source: https://context7.com/huakunshen/tauri-plugin-libsql/llms.txt Retrieves plugin configuration information, including whether encryption is enabled at the plugin level. ```APIDOC ## getConfig ### Description Retrieves plugin configuration info, including whether encryption is enabled at the plugin level. ### Method `getConfig(): Promise<{ encrypted: boolean }>` ### Parameters None ### Request Example ```typescript import { getConfig } from "tauri-plugin-libsql-api"; const config = await getConfig(); if (config.encrypted) { console.log("Plugin-level encryption is enabled"); } else { console.log("Using per-database encryption or no encryption"); } ``` ### Response #### Success Response (200) - **encrypted** (boolean) - Indicates whether plugin-level encryption is enabled. ``` ```APIDOC #### Response Example ```json { "encrypted": true } ``` ``` -------------------------------- ### Database.load Source: https://context7.com/huakunshen/tauri-plugin-libsql/llms.txt Initializes a database connection. Supports simple path strings, encryption configuration, and Turso embedded replica mode. ```APIDOC ## Database.load ### Description Initializes a database connection and returns a Database instance. Supports simple path strings, encryption configuration, and Turso embedded replica mode for cloud sync. ### Method `Database.load()` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body - **path** (string | object) - Required - The database path or configuration object. - If string: `sqlite:myapp.db` or `sqlite::memory:` - If object: - **path** (string) - Required - The database file path. - **encryption** (object) - Optional - Encryption configuration. - **cipher** (string) - Required - Encryption cipher, e.g., `aes256cbc`. - **key** (Array) - Required - 32-byte encryption key. - **syncUrl** (string) - Optional - Turso sync URL. - **authToken** (string) - Optional - Turso authentication token. ### Request Example ```typescript // Simple database load const db = await Database.load("sqlite:myapp.db"); // In-memory database const memDb = await Database.load("sqlite::memory:"); // With AES-256-CBC encryption const key = new Uint8Array(32); crypto.getRandomValues(key); const encryptedDb = await Database.load({ path: "sqlite:secrets.db", encryption: { cipher: "aes256cbc", key: Array.from(key), // 32-byte key required }, }); // Turso embedded replica (requires `replication` feature in Cargo.toml) const replicaDb = await Database.load({ path: "sqlite:local.db", syncUrl: "libsql://mydb-org.turso.io", authToken: "your-turso-auth-token", }); ``` ### Response #### Success Response (200) - **Database** (object) - An instance of the Database class. #### Response Example ```typescript // Assuming successful load, db is a Database instance const db = await Database.load("sqlite:myapp.db"); ``` ``` -------------------------------- ### Get Turso Credentials Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/examples/todo-list/README.md Retrieve your Turso database URL and create an authentication token. These are required to connect the embedded replica to your remote Turso database. ```bash # Get your credentials turso db show --url turso db tokens create ``` -------------------------------- ### Initialize Database and Run Migrations Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md This sequence demonstrates the essential steps for initializing the database connection and applying pending migrations before using Drizzle ORM. Ensure migrations are run before any table queries to prevent errors. ```typescript // 1. Open/create the database file await Database.load('sqlite:myapp.db'); // 2. Run pending migrations — must come before any table queries await migrate('sqlite:myapp.db', migrations); // 3. Now safe to use Drizzle const db = drizzle(createDrizzleProxy('sqlite:myapp.db'), { schema }); ``` -------------------------------- ### Configuration Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Retrieves the configuration settings for the LibSQL plugin. ```APIDOC ## `getConfig()` ### Description Retrieves the configuration of the LibSQL plugin, including whether encryption is enabled. ### Method `getConfig` ### Parameters None ### Request Example ```typescript import { getConfig } from "tauri-plugin-libsql-api"; const { encrypted } = await getConfig(); ``` ### Response #### Success Response (200) - **encrypted** (boolean) - Indicates if the database is configured with encryption. #### Response Example ```json { "encrypted": true } ``` ``` -------------------------------- ### Drizzle ORM Integration Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Provides setup instructions for integrating Drizzle ORM with Tauri Plugin LibSQL, including basic usage and encrypted database connections. ```APIDOC ## Drizzle ORM Integration ### Description Integrate Drizzle ORM with Tauri Plugin LibSQL for a type-safe database experience. ### Setup ```typescript import { drizzle } from "drizzle-orm/sqlite-proxy"; import { createDrizzleProxy } from "tauri-plugin-libsql-api"; import * as schema from "./schema"; const db = drizzle(createDrizzleProxy("sqlite:myapp.db"), { schema }); const users = await db.select().from(schema.users); ``` `createDrizzleProxy` lazily loads the database connection on first use, eliminating the need for a separate `Database.load()` call. ``` ```APIDOC ### With Encryption ```typescript import { createDrizzleProxyWithEncryption } from "tauri-plugin-libsql-api"; const db = drizzle( createDrizzleProxyWithEncryption({ path: "sqlite:encrypted.db", encryption: { cipher: "aes256cbc", key: myKey32Bytes, // number[] | Uint8Array, 32 bytes }, }), { schema }, ); ``` ``` -------------------------------- ### Drizzle ORM Configuration Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md Configuration file for Drizzle Kit, specifying the dialect as 'sqlite' and the location of your schema files. This setup is necessary for generating database migrations. ```typescript import { defineConfig } from 'drizzle-kit'; export default defineConfig({ dialect: 'sqlite', schema: './src/lib/schema.ts', out: './drizzle', }); ``` -------------------------------- ### Load and Use Database (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Demonstrates loading a SQLite database, executing an insert, selecting data, and closing the connection. ```typescript import { Database } from "tauri-plugin-libsql-api"; const db = await Database.load("sqlite:myapp.db"); await db.execute("INSERT INTO users (name) VALUES ($1)", ["Alice"]); const users = await db.select<{ id: number; name: string }[]>( "SELECT * FROM users", ); await db.close(); ``` -------------------------------- ### Define SQLite Table Schema Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Define your database schema using Drizzle ORM's SQLite core functions. This example shows a simple 'users' table. ```typescript import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core'; export const users = sqliteTable('users', { id: integer('id').primaryKey({ autoIncrement: true }), name: text('name').notNull(), }); ``` -------------------------------- ### Comparison with @tauri-apps/plugin-sql Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md A comparative overview of features between tauri-plugin-libsql and @tauri-apps/plugin-sql. ```APIDOC ## Comparison with @tauri-apps/plugin-sql | Feature | tauri-plugin-libsql | @tauri-apps/plugin-sql | |---------------------|---------------------|------------------------| | SQLite | ✅ libsql | ✅ sqlx | | Encryption | ✅ Built-in AES-256-CBC | ❌ | | Drizzle ORM | ✅ | ✅ | | Migration Runner | ✅ Browser-safe | ❌ | | MySQL / PostgreSQL | ❌ | ✅ | | API Compatibility | Partial | Full | ``` -------------------------------- ### Build JS Package for Tauri Libsql Plugin Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md Run this command at the repository root after modifying files in `guest-js/` to build the JavaScript package using Rollup. The output is placed in `dist-js/`. ```bash npm run build # at repo root — runs rollup, outputs dist-js/ ``` -------------------------------- ### Initialize Tauri Plugin LibSQL in Rust Source: https://context7.com/huakunshen/tauri-plugin-libsql/llms.txt Configure the Tauri plugin in your Rust backend with optional base path and default encryption settings. Default initialization places databases in the current working directory. ```rust use std::path::PathBuf; // Default initialization (databases in current working directory) tauri::Builder::default() .plugin(tauri_plugin_libsql::init()) .run(tauri::generate_context!()) .expect("error while running tauri application"); // With custom base path let config = tauri_plugin_libsql::Config { base_path: Some(PathBuf::from("/path/to/databases")), encryption: None, }; tauri::Builder::default() .plugin(tauri_plugin_libsql::init_with_config(config)) .run(tauri::generate_context!()) .expect("error running application"); // With plugin-level encryption (applies to all databases) let config = tauri_plugin_libsql::Config { base_path: None, encryption: Some(tauri_plugin_libsql::EncryptionConfig { cipher: tauri_plugin_libsql::Cipher::Aes256Cbc, key: vec![/* 32 bytes */], }), }; tauri::Builder::default() .plugin(tauri_plugin_libsql::init_with_config(config)) .run(tauri::generate_context!()) .expect("error running application"); ``` -------------------------------- ### Initialize Database Connection Source: https://context7.com/huakunshen/tauri-plugin-libsql/llms.txt Use Database.load to initialize a connection. Supports file paths, in-memory databases, AES-256-CBC encryption, and Turso embedded replica mode. For encryption, a 32-byte key is required. ```typescript import { Database } from "tauri-plugin-libsql-api"; // Simple database load const db = await Database.load("sqlite:myapp.db"); // In-memory database const memDb = await Database.load("sqlite::memory:"); // With AES-256-CBC encryption const key = new Uint8Array(32); crypto.getRandomValues(key); const encryptedDb = await Database.load({ path: "sqlite:secrets.db", encryption: { cipher: "aes256cbc", key: Array.from(key), // 32-byte key required }, }); // Turso embedded replica (requires `replication` feature in Cargo.toml) const replicaDb = await Database.load({ path: "sqlite:local.db", syncUrl: "libsql://mydb-org.turso.io", authToken: "your-turso-auth-token", }); ``` -------------------------------- ### Define Drizzle Schema for SQLite Source: https://context7.com/huakunshen/tauri-plugin-libsql/llms.txt Define your database schema using drizzle-orm/sqlite-core for type-safe queries and automatic migration generation. This example shows user and todo tables with common fields and relationships. ```typescript import { sql } from "drizzle-orm"; import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; export const users = sqliteTable("users", { id: integer("id").primaryKey({ autoIncrement: true }), name: text("name").notNull(), email: text("email").unique(), createdAt: text("created_at").default(sql`(current_timestamp)`), }); export const todos = sqliteTable("todos", { id: integer("id").primaryKey({ autoIncrement: true }), userId: integer("user_id").references(() => users.id), title: text("title").notNull(), completed: integer("completed").notNull().default(0), createdAt: text("created_at").default(sql`(current_timestamp)`), }); // Infer types for TypeScript export type User = typeof users.$inferSelect; export type NewUser = typeof users.$inferInsert; export type Todo = typeof todos.$inferSelect; export type NewTodo = typeof todos.$inferInsert; ``` -------------------------------- ### Load Database with Simple Path Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Load a SQLite database using a simple file path. This is the most basic way to connect to a local database. ```typescript // 简单用法 const db = await Database.load('sqlite:myapp.db'); ``` -------------------------------- ### Initialize tauri-plugin-libsql in Tauri App Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Initialize the tauri-plugin-libsql within your Tauri application's main Rust file. ```rust // src-tauri/src/lib.rs tauri::Builder::default() .plugin(tauri_plugin_libsql::init()) .run(tauri::generate_context!()) .expect("error while running tauri application"); ``` -------------------------------- ### Inline SQL Migrations with Vite Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md This code demonstrates how Vite can resolve SQL files at build time for use with the migration runner. The SQL text is inlined into the JavaScript bundle, eliminating the need for runtime filesystem access. ```typescript // Vite resolves these at build time — the SQL text is inlined into the JS bundle const migrations = import.meta.glob("./drizzle/*.sql", { eager: true, query: "?raw", import: "default", }); await migrate("sqlite:myapp.db", migrations); ``` -------------------------------- ### Configure Tauri Permissions for LibSQL Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Add the necessary permissions for the libsql plugin in your `tauri.conf.json` file. You can either enable all permissions or configure fine-grained access. ```json { "plugins": { "libsql": {} } } ``` ```json { "identifier": "libsql:default", "permissions": [ "libsql:allow-load", "libsql:allow-batch", "libsql:allow-execute", "libsql:allow-select", "libsql:allow-close" ] } ``` -------------------------------- ### Database Loading and Encryption Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Demonstrates how to load a SQLite database, with options for encryption using AES-256-CBC. ```APIDOC ## Database.load(pathOrOptions) ### Description Loads a SQLite database connection. Supports both simple path strings and options objects for advanced configurations like encryption. ### Method `Database.load(pathOrOptions: string | { path: string; encryption?: { cipher: string; key: any } }): Promise ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example ```typescript // Simple usage const db = await Database.load('sqlite:myapp.db'); // With encryption const db = await Database.load({ path: 'sqlite:myapp.db', encryption: { cipher: 'aes256cbc', key: myKey }, }); ``` ### Response #### Success Response (200) - **db** (Database) - An instance of the Database object. #### Response Example ```json // Successful database connection object (conceptual) { // ... database object properties ... } ``` ``` -------------------------------- ### Execute Batched SQL Queries with BEGIN/COMMIT Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Manually manage transactions with BEGIN, individual execute calls, and COMMIT to ensure writes are correctly routed through the embedded replica's write path. This is a workaround for `execute_batch()` issues with embedded replicas in libsql 0.9.x. ```rust pub async fn batch(&self, queries: Vec) -> Result<(), Error> { self.conn.execute("BEGIN", Params::None).await?; for query in &queries { if let Err(e) = self.conn.execute(query.as_str(), Params::None).await { let _ = self.conn.execute("ROLLBACK", Params::None).await; return Err(Error::Libsql(e)); } } if let Err(e) = self.conn.execute("COMMIT", Params::None).await { let _ = self.conn.execute("ROLLBACK", Params::None).await; return Err(Error::Libsql(e)); } Ok(()) } ``` -------------------------------- ### Run Migrations with Custom Options Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Run database migrations with custom options, such as specifying a different table name for tracking migrations. The `migrations` object should be populated using `import.meta.glob`. ```typescript await migrate('sqlite:myapp.db', migrations, { migrationsTable: '__my_migrations', // 默认:'__drizzle_migrations' }); ``` -------------------------------- ### Apply Drizzle Migrations and Initialize DB Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Loads the database and applies pending migrations using the inlined migration files before initializing Drizzle ORM. Ensure migrations are applied before querying. ```typescript await Database.load("sqlite:myapp.db"); await migrate("sqlite:myapp.db", migrations); // Now safe to use Drizzle const db = drizzle(createDrizzleProxy("sqlite:myapp.db"), { schema }); ``` -------------------------------- ### Tauri Permissions for LibSQL Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Details the necessary permissions to be added to `tauri.conf.json` for the libSQL plugin. ```APIDOC ## Permissions Add the following to your `tauri.conf.json`: ```json { "plugins": { "libsql": {} } } ``` Or configure fine-grained capabilities: ```json { "identifier": "libsql:default", "permissions": [ "libsql:allow-load", "libsql:allow-batch", "libsql:allow-execute", "libsql:allow-select", "libsql:allow-close" ] } ``` ``` -------------------------------- ### Tauri Configuration Permissions Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Details the necessary permissions to be added to `tauri.conf.json` for the LibSQL plugin. ```APIDOC ## Permissions Add the following to your `tauri.conf.json` to enable the LibSQL plugin: ```json { "plugins": { "libsql": {} } } ``` Alternatively, configure granular capabilities: ```json { "identifier": "libsql:default", "permissions": [ "libsql:allow-load", "libsql:allow-batch", "libsql:allow-execute", "libsql:allow-select", "libsql:allow-close" ] } ``` ``` -------------------------------- ### Load SQL Migrations with Vite Glob Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/blog-post.md Uses Vite's `import.meta.glob` to inline SQL migration files into the JavaScript bundle at build time, enabling their use with Drizzle's migration function. ```typescript const migrations = import.meta.glob("./drizzle/*.sql", { eager: true, query: "?raw", // import as raw string import: "default", }); ``` -------------------------------- ### Generate Database Migrations Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/examples/todo-list/README.md Generate new SQL migration files based on schema changes. After editing `src/lib/schema.ts`, run this command to create the migration file. ```bash bun run db:generate ``` -------------------------------- ### Register Plugin with Default Configuration (Rust) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Register the tauri-plugin-libsql with default settings in your Tauri application's main Rust file. Databases will resolve relative to the current working directory. ```rust // src-tauri/src/lib.rs // Default: databases resolve relative to current working directory tauri::Builder::default() .plugin(tauri_plugin_libsql::init()) .run(tauri::generate_context!()) .expect("error while running tauri application"); ``` -------------------------------- ### Build JS Package Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/CLAUDE.md Builds the JavaScript package for the tauri-plugin-libsql. This command is essential for preparing the frontend assets. ```bash npm run build # or: rollup -c ``` -------------------------------- ### Run Database Migrations Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md The `migrate` function from `tauri-plugin-libsql-api` runs SQL migration files against a specified database path. It supports glob patterns for discovering migration files. ```typescript import { migrate } from "tauri-plugin-libsql-api"; const migrations = import.meta.glob("./drizzle/*.sql", { eager: true, query: "?raw", import: "default", }); await migrate("sqlite:myapp.db", migrations); ``` -------------------------------- ### Tauri Plugin LibSQL Project Structure Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Overview of the tauri-plugin-libsql project directory structure, detailing the purpose of key subdirectories and files. ```tree tauri-plugin-libsql/ ├── src/ # Rust plugin │ ├── lib.rs # Plugin init, command registration │ ├── commands.rs # load, execute, select, close, ping │ ├── wrapper.rs # DbConnection around libsql │ ├── decode.rs # libsql::Value → serde_json::Value │ ├── models.rs # Cipher, EncryptionConfig, QueryResult │ ├── error.rs # Error types │ ├── desktop.rs # Desktop config & base_path │ └── mobile.rs # Mobile stub ├── guest-js/ # TypeScript source │ ├── index.ts # Database class, getConfig, re-exports │ ├── drizzle.ts # createDrizzleProxy, createDrizzleProxyWithEncryption │ └── migrate.ts # migrate() — browser-safe migration runner ├── permissions/ # Tauri permission files ├── examples/todo-list/ # Demo: Todo app with Drizzle + migrations (15 MB .app / 6 MB .dmg) ├── SKILL.md # AI skill context for Claude Code and other assistants ├── build.rs ├── Cargo.toml └── package.json ``` -------------------------------- ### Plugin Architecture Overview Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/SKILL.md Illustrates the communication flow between the frontend TypeScript code and the Rust plugin backend for various database operations. ```text Frontend (TS) Rust Plugin ───────────────── ───────────────────────── Database.load() ──invoke──▶ commands::load() migrate() ──invoke──▶ commands::batch() (DDL in transaction) db.execute() ──invoke──▶ commands::execute() db.select() ──invoke──▶ commands::select() db.batch() ──invoke──▶ commands::batch() db.sync() ──invoke──▶ commands::sync() db.close() ──invoke──▶ commands::close() │ wrapper::DbConnection │ catch_unwind (panic → proper Error) ├── open_local() — LibsqlBuilder::new_local ├── open_replica() — new_remote_replica + initial sync └── open_remote() — LibsqlBuilder::new_remote ▼ libsql (SQLite / Turso) ``` -------------------------------- ### Database Class Usage (TypeScript) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Demonstrates basic database operations using the Database class, including loading a database, executing SQL statements, selecting data, and closing the connection. ```APIDOC ## Database Class Usage (TypeScript) ### Description This section shows how to use the `Database` class to interact with a SQLite database in your Tauri application. ### Code Example ```typescript import { Database } from "tauri-plugin-libsql-api"; const db = await Database.load("sqlite:myapp.db"); await db.execute("INSERT INTO users (name) VALUES ($1)", ["Alice"]); const users = await db.select<{ id: number; name: string }[]>( "SELECT * FROM users", ); await db.close(); ``` ``` -------------------------------- ### Load Database with Embedded Replica Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Load the database with a local replica file, specifying the sync URL and auth token. An initial sync pulls the latest data from Turso. Subsequent sync calls pull incremental changes. ```typescript import { Database, migrate } from "tauri-plugin-libsql-api"; const db = await Database.load({ path: "sqlite:local.db", // local replica file syncUrl: "libsql://mydb-org.turso.io", authToken: "your-turso-auth-token", }); // Sync on demand (e.g. on app resume / network reconnect) await db.sync(); ``` -------------------------------- ### Configure Per-Database Encryption from Frontend Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.zh-CN.md Configure encryption for a specific database directly from the frontend. Ensure the key is 32 bytes and consider secure storage for the key. ```typescript const key = new Uint8Array(32); crypto.getRandomValues(key); const db = await Database.load({ path: 'sqlite:secrets.db', encryption: { cipher: 'aes256cbc', key: Array.from(key), // number[] 或 Uint8Array }, }); ``` -------------------------------- ### Migrations with Drizzle ORM Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Explains how to set up and run database migrations within a Tauri application using Drizzle ORM and the plugin's `migrate` function. ```APIDOC ## Migrations ### Description This section details how to manage database migrations within a Tauri application using Drizzle ORM and the plugin's `migrate` function, which is designed to work with bundled SQL files. ### Workflow **1. Define your schema** (`src/lib/schema.ts`): ```typescript import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core"; export const users = sqliteTable("users", { id: integer("id").primaryKey({ autoIncrement: true }), name: text("name").notNull(), }); ``` **2. Configure drizzle-kit** (`drizzle.config.ts`): ```typescript import { defineConfig } from "drizzle-kit"; export default defineConfig({ dialect: "sqlite", schema: "./src/lib/schema.ts", out: "./drizzle", }); ``` **3. Generate migration files**: ```bash npx drizzle-kit generate # creates drizzle/0000_init.sql, drizzle/0001_add_column.sql, etc. ``` **4. Run migrations on startup**: ```typescript import { Database, migrate } from "tauri-plugin-libsql-api"; // Vite bundles these SQL files into the app at build time const migrations = import.meta.glob("./drizzle/*.sql", { eager: true, query: "?raw", import: "default", }); // Startup sequence: load → migrate → query await Database.load("sqlite:myapp.db"); await migrate("sqlite:myapp.db", migrations); // Now safe to query const db = drizzle(createDrizzleProxy("sqlite:myapp.db"), { schema }); ``` ``` ```APIDOC ### How `migrate()` works - Creates a `__drizzle_migrations` tracking table if it doesn't exist. - Parses migration filenames by their numeric prefix (`0000_`, `0001_`, etc.). - Applies only pending migrations in order. - Records each applied migration by filename. ### Adding schema changes ```bash # 1. Edit src/lib/schema.ts # 2. Generate new migration npx drizzle-kit generate # 3. New migration runs automatically on next app launch ``` ### Options ```typescript await migrate("sqlite:myapp.db", migrations, { migrationsTable: "__my_migrations", // default: '__drizzle_migrations' }); ``` ``` -------------------------------- ### Register Plugin with Custom Base Path (Rust) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Register the tauri-plugin-libsql with a custom base path for storing databases. This ensures databases are stored in a fixed location, independent of the current working directory. ```rust use std::path::PathBuf; let config = tauri_plugin_libsql::Config { base_path: Some(PathBuf::from("/path/to/data")), encryption: None, }; tauri::Builder::default() .plugin(tauri_plugin_libsql::init_with_config(config)) .run(tauri::generate_context!()) .expect("error while running tauri application"); ``` -------------------------------- ### Generate Migrations (Bash) Source: https://github.com/huakunshen/tauri-plugin-libsql/blob/main/README.md Command to generate SQL migration files using drizzle-kit. This is a prerequisite for the migration workflow. ```bash npx drizzle-kit generate # creates drizzle/0000_init.sql, drizzle/0001_add_column.sql, etc. ```