Skip to content

Commit a58a4fe

Browse files
pmorris-devclaude
andcommitted
docs: document cross-window access and unbounded fetchAll
Add Security Considerations section to README covering shared state across windows, resource limits, unbounded fetchAll, and path validation. Add @remarks to the Database class and fetchAll() in TypeScript, and a doc comment to the Rust fetch_all command. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 4537d47 commit a58a4fe

3 files changed

Lines changed: 50 additions & 1 deletion

File tree

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,41 @@ Working Tauri demo apps are in the [`examples/`](examples) directory:
948948
See the [toolkit crate README](crates/sqlx-sqlite-toolkit/README.md#examples)
949949
for setup instructions.
950950

951+
## Security Considerations
952+
953+
### Cross-Window Shared State
954+
955+
Database instances are shared across all webviews/windows within the same Tauri
956+
application. A database loaded in one window is accessible from any other window
957+
without calling `load()` again. Writes from one window are immediately visible
958+
to reads in another, and closing a database affects all windows.
959+
960+
### Resource Limits
961+
962+
The plugin enforces several resource limits to prevent denial-of-service from
963+
untrusted or buggy frontend code:
964+
965+
* **Database count**: Maximum 50 concurrently loaded databases (configurable
966+
via `Builder::max_databases()`)
967+
* **Interruptible transaction timeout**: Transactions that exceed the idle
968+
timeout (default 5 minutes) are automatically rolled back on the next
969+
access attempt (configurable via `Builder::transaction_timeout()`)
970+
* **Observer channel capacity**: Capped at 10,000 (default 256)
971+
* **Observed tables**: Maximum 100 tables per `observe()` call
972+
* **Subscriptions**: Maximum 100 active subscriptions per database
973+
974+
### Unbounded Result Sets
975+
976+
`fetchAll()` returns the entire result set in a single response with no built-in
977+
size limit. For large or unbounded queries, prefer `fetchPage()` with keyset
978+
pagination to keep memory usage bounded on both the Rust and TypeScript sides.
979+
980+
### Path Validation
981+
982+
Database paths are validated to prevent directory traversal. Absolute paths,
983+
`..` segments, and null bytes are rejected. All paths are resolved relative to
984+
the app config directory.
985+
951986
## Development
952987

953988
This project follows

guest-js/index.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -757,6 +757,12 @@ class TransactionBuilder implements PromiseLike<WriteQueryResult[]> {
757757
*
758758
* The `Database` class serves as the primary interface for
759759
* communicating with SQLite databases through the plugin.
760+
*
761+
* @remarks
762+
* Database instances are shared across all webviews/windows within the same Tauri
763+
* application. A database loaded in one window is accessible from any other window
764+
* without calling `load()` again. This means writes from one window are immediately
765+
* visible to reads in another, and closing a database affects all windows.
760766
*/
761767
export default class Database {
762768
public path: string;
@@ -930,6 +936,11 @@ export default class Database {
930936
*
931937
* SQLite uses `$1`, `$2`, etc. for parameter binding.
932938
*
939+
* @remarks
940+
* This method returns the entire result set in a single response. For large or
941+
* unbounded queries, prefer {@link fetchPage} with keyset pagination to keep memory
942+
* usage bounded on both the Rust and TypeScript sides.
943+
*
933944
* @param query - SQL SELECT query
934945
* @param bindValues - Optional parameter values
935946
*

src/commands.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -290,7 +290,10 @@ pub async fn execute_transaction(
290290
}
291291
}
292292

293-
/// Execute a SELECT query returning all matching rows
293+
/// Execute a SELECT query returning all matching rows.
294+
///
295+
/// Returns the entire result set in a single response. For large or unbounded queries,
296+
/// prefer `fetch_page` with keyset pagination to keep memory usage bounded.
294297
#[tauri::command]
295298
pub async fn fetch_all(
296299
db_instances: State<'_, DbInstances>,

0 commit comments

Comments
 (0)