Skip to content

Commit ee81d15

Browse files
feat: add Tauri sqlite persisted collection package (#1369)
* feat: add Tauri sqlite persisted collection package Wrap the official Tauri SQL plugin in the shared SQLite persistence layer so persisted collections can run in Tauri apps without shipping repo-owned Rust code. Add contract coverage and a real Tauri conformance harness to validate the runtime integration end to end. Made-with: Cursor * fix: add missing tauri persistence coverage and clean e2e lockfile Add runtime persistence contract and integration tests for the Tauri package, expand placeholder parser edge-case coverage, drop unused jsx tsconfig option, and stop tracking the e2e Cargo.lock. Also refresh pnpm-lock.yaml so lockfile validation succeeds. Made-with: Cursor * lock file * format * fix: exclude tauri e2e build artifacts from ts checking Prevent the tauri e2e app tsconfig from checking emitted dist JavaScript so CI does not report implicit-any and nullable errors against bundled output. Made-with: Cursor * fix: scope tauri tsconfig to source TypeScript files Avoid including generated e2e app build artifacts in Vitest typechecking by narrowing e2e includes to TypeScript and excluding app dist/target outputs. Made-with: Cursor * ci: apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
1 parent d0b9b52 commit ee81d15

38 files changed

+3028
-6
lines changed
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
# @tanstack/db-tauri-sqlite-persisted-collection
2+
3+
Thin SQLite persistence for Tauri apps using `@tauri-apps/plugin-sql`.
4+
5+
## Public API
6+
7+
- `createTauriSQLitePersistence(...)`
8+
- `persistedCollectionOptions(...)` (re-exported from core)
9+
10+
## Install
11+
12+
```bash
13+
pnpm add @tanstack/db-tauri-sqlite-persisted-collection @tauri-apps/plugin-sql
14+
```
15+
16+
## Consumer-side Tauri setup
17+
18+
Install the official SQL plugin in your Tauri app:
19+
20+
```bash
21+
cd src-tauri
22+
cargo add tauri-plugin-sql --features sqlite
23+
```
24+
25+
Register the plugin in `src-tauri/src/main.rs`:
26+
27+
```rust
28+
fn main() {
29+
tauri::Builder::default()
30+
.plugin(tauri_plugin_sql::Builder::default().build())
31+
.run(tauri::generate_context!())
32+
.expect("error while running tauri application");
33+
}
34+
```
35+
36+
Enable the SQL permissions in `src-tauri/capabilities/default.json`:
37+
38+
```json
39+
{
40+
"permissions": ["core:default", "sql:default", "sql:allow-execute"]
41+
}
42+
```
43+
44+
## Quick start
45+
46+
```ts
47+
import Database from '@tauri-apps/plugin-sql'
48+
import { createCollection } from '@tanstack/db'
49+
import {
50+
createTauriSQLitePersistence,
51+
persistedCollectionOptions,
52+
} from '@tanstack/db-tauri-sqlite-persisted-collection'
53+
54+
type Todo = {
55+
id: string
56+
title: string
57+
completed: boolean
58+
}
59+
60+
const database = await Database.load(`sqlite:tanstack-db.sqlite`)
61+
62+
const persistence = createTauriSQLitePersistence({
63+
database,
64+
})
65+
66+
export const todosCollection = createCollection(
67+
persistedCollectionOptions<Todo, string>({
68+
id: `todos`,
69+
getKey: (todo) => todo.id,
70+
persistence,
71+
schemaVersion: 1,
72+
}),
73+
)
74+
```
75+
76+
## Notes
77+
78+
- `createTauriSQLitePersistence` is shared across collections.
79+
- Reuse a single `Database.load('sqlite:...')` handle per SQLite file when using
80+
this package. Opening multiple plugin handles to the same file can reintroduce
81+
SQLite locking behavior outside this package's serialized transaction queue.
82+
- Mode defaults (`sync-present` vs `sync-absent`) are inferred from whether a
83+
`sync` config is present in `persistedCollectionOptions`.
84+
- This package expects a database handle created by
85+
`@tauri-apps/plugin-sql`, typically from `Database.load('sqlite:...')`.
86+
- The database path is resolved by Tauri's SQL plugin, not by this package.
87+
- This package does not publish or require package-specific Rust code. Only the
88+
app-level Tauri SQL plugin registration shown above is required.
89+
90+
## Testing
91+
92+
- `pnpm --filter @tanstack/db-tauri-sqlite-persisted-collection test`
93+
runs the driver and shared adapter contract tests.
94+
- `pnpm --filter @tanstack/db-tauri-sqlite-persisted-collection test:e2e`
95+
builds the repo-local Tauri harness and runs the persisted collection
96+
conformance suite inside a real Tauri runtime.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>Tauri SQLite E2E</title>
7+
</head>
8+
<body>
9+
<main>
10+
<p id="status">Booting Tauri persisted collection e2e runtime</p>
11+
<pre id="details"></pre>
12+
</main>
13+
<script type="module">
14+
const reportUrl = '%VITE_TANSTACK_DB_TAURI_E2E_REPORT_URL%'
15+
16+
if (reportUrl && !reportUrl.startsWith('%')) {
17+
fetch(reportUrl, {
18+
method: 'POST',
19+
headers: {
20+
'content-type': 'application/json',
21+
},
22+
body: JSON.stringify({
23+
kind: 'status',
24+
phase: 'html-loaded',
25+
}),
26+
}).catch(() => {})
27+
}
28+
29+
import('/src/main.ts').catch((error) => {
30+
if (reportUrl && !reportUrl.startsWith('%')) {
31+
fetch(reportUrl, {
32+
method: 'POST',
33+
headers: {
34+
'content-type': 'application/json',
35+
},
36+
body: JSON.stringify({
37+
kind: 'status',
38+
phase: 'main-import-failed',
39+
details: {
40+
message: String(error?.message ?? error),
41+
},
42+
}),
43+
}).catch(() => {})
44+
}
45+
})
46+
</script>
47+
</body>
48+
</html>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"name": "@tanstack/db-tauri-sqlite-persisted-collection-e2e-app",
3+
"private": true,
4+
"version": "0.0.0",
5+
"type": "module",
6+
"scripts": {
7+
"build": "vite build",
8+
"dev": "vite",
9+
"tauri": "tauri"
10+
},
11+
"dependencies": {
12+
"@tauri-apps/api": "^2.10.1",
13+
"@tauri-apps/plugin-sql": "^2.3.2",
14+
"@tanstack/db": "workspace:*",
15+
"@tanstack/db-tauri-sqlite-persisted-collection": "workspace:*"
16+
},
17+
"devDependencies": {
18+
"@tauri-apps/cli": "^2.10.1",
19+
"@types/node": "^25.2.2",
20+
"typescript": "^5.9.3",
21+
"vite": "^7.3.1"
22+
}
23+
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/target
2+
/gen
3+
/Cargo.lock
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "db-tauri-sqlite-persisted-collection-e2e-app"
3+
version = "0.0.0"
4+
description = "Repo-local Tauri e2e harness for TanStack DB SQLite persistence"
5+
authors = ["TanStack Team"]
6+
edition = "2021"
7+
8+
[build-dependencies]
9+
tauri-build = { version = "2.5.6", features = [] }
10+
11+
[dependencies]
12+
serde_json = "1"
13+
tauri = { version = "2.10.3", features = [] }
14+
tauri-plugin-sql = { version = "2.3.2", features = ["sqlite"] }
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
fn main() {
2+
tauri_build::build()
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
{
2+
"identifier": "default",
3+
"description": "Default capability for the Tauri SQLite e2e harness",
4+
"windows": ["main"],
5+
"permissions": ["core:default", "sql:default", "sql:allow-execute"]
6+
}
70 Bytes
Loading
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
2+
3+
fn main() {
4+
tauri::Builder::default()
5+
.plugin(tauri_plugin_sql::Builder::default().build())
6+
.run(tauri::generate_context!())
7+
.expect("error while running Tauri e2e application");
8+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
{
2+
"$schema": "https://schema.tauri.app/config/2",
3+
"productName": "TanStack DB Tauri E2E",
4+
"version": "0.0.0",
5+
"identifier": "com.tanstack.db.tauri.e2e",
6+
"build": {
7+
"beforeDevCommand": "pnpm dev --host 127.0.0.1 --port 1420",
8+
"devUrl": "http://127.0.0.1:1420",
9+
"frontendDist": "../dist"
10+
},
11+
"app": {
12+
"windows": [
13+
{
14+
"title": "TanStack DB Tauri E2E",
15+
"width": 1280,
16+
"height": 900
17+
}
18+
],
19+
"security": {
20+
"csp": null
21+
}
22+
},
23+
"bundle": {
24+
"active": false,
25+
"icon": []
26+
}
27+
}

0 commit comments

Comments
 (0)