@xnetjs/sqlite 0.0.2

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.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Chris Smothers
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,220 @@
1
+ # @xnetjs/sqlite
2
+
3
+ Unified SQLite adapter for xNet across all platforms (Electron, Web, Expo).
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ pnpm add @xnetjs/sqlite
9
+ ```
10
+
11
+ ## Features
12
+
13
+ - **Unified interface** -- Same `SQLiteAdapter` API across all platforms
14
+ - **Platform adapters** -- better-sqlite3 (Electron), sqlite-wasm (Web), expo-sqlite (Expo)
15
+ - **Schema management** -- Version tracking and migrations
16
+ - **Full-text search** -- FTS5 integration helpers
17
+ - **Diagnostics** -- Query analysis and database stats
18
+
19
+ ## Usage
20
+
21
+ ### Memory Adapter (Testing)
22
+
23
+ ```typescript
24
+ import { createMemorySQLiteAdapter } from '@xnetjs/sqlite/memory'
25
+
26
+ const db = await createMemorySQLiteAdapter()
27
+
28
+ // Query data
29
+ const rows = await db.query('SELECT * FROM nodes WHERE schema_id = ?', ['xnet://Page/1.0'])
30
+
31
+ // Insert data
32
+ await db.run('INSERT INTO nodes (id, schema_id, ...) VALUES (?, ?, ...)', [id, schemaId, ...])
33
+
34
+ // Transactions
35
+ await db.transaction(async () => {
36
+ await db.run(...)
37
+ await db.run(...)
38
+ })
39
+
40
+ await db.close()
41
+ ```
42
+
43
+ ### Electron (better-sqlite3)
44
+
45
+ ```typescript
46
+ import { createElectronSQLiteAdapter } from '@xnetjs/sqlite/electron'
47
+
48
+ const db = await createElectronSQLiteAdapter({
49
+ path: 'xnet.db',
50
+ // Optional WAL mode (default: true)
51
+ walMode: true
52
+ })
53
+ ```
54
+
55
+ ### Web (sqlite-wasm + OPFS)
56
+
57
+ ```typescript
58
+ import { createWebSQLiteAdapter } from '@xnetjs/sqlite/web'
59
+
60
+ const db = await createWebSQLiteAdapter({
61
+ path: 'xnet.db'
62
+ })
63
+ ```
64
+
65
+ ### Expo (expo-sqlite)
66
+
67
+ ```typescript
68
+ import { createExpoSQLiteAdapter } from '@xnetjs/sqlite/expo'
69
+
70
+ const db = await createExpoSQLiteAdapter({
71
+ path: 'xnet.db'
72
+ })
73
+ ```
74
+
75
+ ## API
76
+
77
+ ### SQLiteAdapter Interface
78
+
79
+ ```typescript
80
+ interface SQLiteAdapter {
81
+ // Query execution
82
+ query<T>(sql: string, params?: unknown[]): Promise<T[]>
83
+ queryOne<T>(sql: string, params?: unknown[]): Promise<T | null>
84
+ run(sql: string, params?: unknown[]): Promise<RunResult>
85
+ exec(sql: string): Promise<void>
86
+
87
+ // Transactions
88
+ transaction<T>(fn: () => Promise<T>): Promise<T>
89
+ beginTransaction(): Promise<void>
90
+ commit(): Promise<void>
91
+ rollback(): Promise<void>
92
+
93
+ // Prepared statements
94
+ prepare(sql: string): Promise<PreparedStatement>
95
+
96
+ // Schema
97
+ getSchemaVersion(): Promise<number>
98
+ setSchemaVersion(version: number): Promise<void>
99
+ applySchema(version: number, sql: string): Promise<boolean>
100
+
101
+ // Lifecycle
102
+ isOpen(): boolean
103
+ close(): Promise<void>
104
+
105
+ // Utilities
106
+ getDatabaseSize(): Promise<number>
107
+ vacuum(): Promise<void>
108
+ checkpoint(): Promise<number>
109
+ }
110
+ ```
111
+
112
+ ### FTS5 Helpers
113
+
114
+ ```typescript
115
+ import { updateNodeFTS, searchNodes, rebuildFTS } from '@xnetjs/sqlite'
116
+
117
+ // Update FTS index for a node
118
+ await updateNodeFTS(db, nodeId, title, content)
119
+
120
+ // Search nodes
121
+ const results = await searchNodes(db, 'search query', { limit: 10 })
122
+
123
+ // Rebuild entire FTS index
124
+ await rebuildFTS(db, (current, total) => {
125
+ console.log(`Progress: ${current}/${total}`)
126
+ })
127
+ ```
128
+
129
+ ### Diagnostics
130
+
131
+ ```typescript
132
+ import { getDatabaseStats, explainQuery, timeQuery } from '@xnetjs/sqlite'
133
+
134
+ // Get database statistics
135
+ const stats = await getDatabaseStats(db)
136
+ console.log(`Tables: ${stats.tableCount}, Size: ${stats.totalSizeBytes} bytes`)
137
+
138
+ // Analyze a query
139
+ const plan = await explainQuery(db, 'SELECT * FROM nodes WHERE schema_id = ?', ['xnet://Page/1.0'])
140
+ console.log(plan)
141
+
142
+ // Time a query
143
+ const { result, durationMs } = await timeQuery(db, async () => {
144
+ return db.query('SELECT * FROM nodes')
145
+ })
146
+ console.log(`Query took ${durationMs}ms`)
147
+ ```
148
+
149
+ ## Schema
150
+
151
+ The package includes a unified schema (`SCHEMA_DDL`) with the following tables:
152
+
153
+ ### Core Tables
154
+
155
+ - `nodes` - Entity registry
156
+ - `node_properties` - Property storage with LWW
157
+ - `changes` - Event log
158
+
159
+ ### Yjs Tables
160
+
161
+ - `yjs_state` - Document state
162
+ - `yjs_updates` - Incremental updates
163
+ - `yjs_snapshots` - Time travel
164
+
165
+ ### Storage Tables
166
+
167
+ - `blobs` - Content-addressed binary storage
168
+ - `documents` - Generic document storage
169
+ - `updates` - @xnetjs/storage compatibility
170
+ - `snapshots` - @xnetjs/storage compatibility
171
+
172
+ ### Metadata Tables
173
+
174
+ - `_schema_version` - Schema tracking
175
+ - `sync_state` - Sync metadata
176
+
177
+ ### FTS5 Virtual Table
178
+
179
+ - `nodes_fts` - Full-text search index
180
+
181
+ ## Platform Support
182
+
183
+ | Platform | Adapter | SQLite Engine | FTS5 |
184
+ | -------- | ----------------------- | ---------------- | ---- |
185
+ | Electron | `ElectronSQLiteAdapter` | better-sqlite3 | Yes |
186
+ | Web | `WebSQLiteAdapter` | @sqlite.org/wasm | Yes |
187
+ | Expo | `ExpoSQLiteAdapter` | expo-sqlite | Yes |
188
+ | Test | `MemorySQLiteAdapter` | sql.js | No\* |
189
+
190
+ \* sql.js does not include FTS5 extension. FTS-related tests are skipped.
191
+
192
+ ## Browser Support (Web)
193
+
194
+ The Web adapter requires:
195
+
196
+ - Cross-Origin-Opener-Policy: same-origin
197
+ - Cross-Origin-Embedder-Policy: require-corp
198
+ - Chrome 102+, Firefox 111+, Safari 16.4+, Edge 102+
199
+
200
+ ```typescript
201
+ import { checkBrowserSupport } from '@xnetjs/sqlite'
202
+
203
+ const support = await checkBrowserSupport()
204
+ if (!support.supported) {
205
+ console.warn('SQLite not supported:', support.reason)
206
+ }
207
+ ```
208
+
209
+ ## Testing
210
+
211
+ ```bash
212
+ pnpm --filter @xnetjs/sqlite test
213
+ ```
214
+
215
+ ## Dependencies
216
+
217
+ - `sql.js` - WebAssembly SQLite (for memory adapter)
218
+ - `better-sqlite3` - Native SQLite for Node.js (Electron)
219
+ - `@sqlite.org/sqlite-wasm` - Official SQLite WASM (Web)
220
+ - `expo-sqlite` - Expo SQLite (React Native)
@@ -0,0 +1,166 @@
1
+ import { b as SQLiteConfig, a as SQLRow, S as SQLValue, R as RunResult } from './types-C_aHfRDF.js';
2
+
3
+ /**
4
+ * @xnetjs/sqlite - SQLite adapter interface definitions
5
+ */
6
+
7
+ /**
8
+ * Unified SQLite adapter interface.
9
+ *
10
+ * All platform-specific implementations must implement this interface.
11
+ * The interface uses async methods to support both sync (better-sqlite3)
12
+ * and async (sqlite-wasm, expo-sqlite) implementations.
13
+ */
14
+ interface SQLiteAdapter {
15
+ /**
16
+ * Open the database connection.
17
+ * Creates the database file if it doesn't exist.
18
+ */
19
+ open(config: SQLiteConfig): Promise<void>;
20
+ /**
21
+ * Close the database connection.
22
+ * Flushes any pending writes and releases resources.
23
+ */
24
+ close(): Promise<void>;
25
+ /**
26
+ * Check if the database is currently open.
27
+ */
28
+ isOpen(): boolean;
29
+ /**
30
+ * Execute a single SQL statement that returns rows.
31
+ * Use for SELECT queries.
32
+ *
33
+ * @param sql - SQL query string
34
+ * @param params - Bound parameters
35
+ * @returns Array of result rows
36
+ *
37
+ * @example
38
+ * const nodes = await db.query<NodeRow>(
39
+ * 'SELECT * FROM nodes WHERE schemaId = ?',
40
+ * ['xnet://Page/1.0']
41
+ * )
42
+ */
43
+ query<T extends SQLRow = SQLRow>(sql: string, params?: SQLValue[]): Promise<T[]>;
44
+ /**
45
+ * Execute a single SQL statement that returns one row.
46
+ * Use for SELECT queries expecting 0 or 1 result.
47
+ *
48
+ * @param sql - SQL query string
49
+ * @param params - Bound parameters
50
+ * @returns Single row or null if not found
51
+ */
52
+ queryOne<T extends SQLRow = SQLRow>(sql: string, params?: SQLValue[]): Promise<T | null>;
53
+ /**
54
+ * Execute a single SQL statement that modifies data.
55
+ * Use for INSERT, UPDATE, DELETE queries.
56
+ *
57
+ * @param sql - SQL statement
58
+ * @param params - Bound parameters
59
+ * @returns Run result with changes count and last insert ID
60
+ */
61
+ run(sql: string, params?: SQLValue[]): Promise<RunResult>;
62
+ /**
63
+ * Execute raw SQL that may contain multiple statements.
64
+ * Use for schema creation and migrations.
65
+ * Does not support parameter binding.
66
+ *
67
+ * @param sql - SQL statements (may be multiple, separated by semicolons)
68
+ */
69
+ exec(sql: string): Promise<void>;
70
+ /**
71
+ * Execute a function within a transaction.
72
+ * Automatically commits on success, rolls back on error.
73
+ *
74
+ * @param fn - Function to execute within transaction
75
+ * @returns Result of the function
76
+ *
77
+ * @example
78
+ * await db.transaction(async () => {
79
+ * await db.run('INSERT INTO nodes ...')
80
+ * await db.run('INSERT INTO changes ...')
81
+ * })
82
+ */
83
+ transaction<T>(fn: () => Promise<T>): Promise<T>;
84
+ /**
85
+ * Begin a manual transaction.
86
+ * Must be followed by commit() or rollback().
87
+ */
88
+ beginTransaction(): Promise<void>;
89
+ /**
90
+ * Commit the current transaction.
91
+ */
92
+ commit(): Promise<void>;
93
+ /**
94
+ * Rollback the current transaction.
95
+ */
96
+ rollback(): Promise<void>;
97
+ /**
98
+ * Prepare a statement for repeated execution.
99
+ * Useful for bulk operations.
100
+ *
101
+ * @param sql - SQL statement with placeholders
102
+ * @returns Prepared statement handle
103
+ */
104
+ prepare(sql: string): Promise<PreparedStatement>;
105
+ /**
106
+ * Get the current schema version.
107
+ * Returns 0 if no schema has been applied.
108
+ */
109
+ getSchemaVersion(): Promise<number>;
110
+ /**
111
+ * Set the schema version after applying migrations.
112
+ */
113
+ setSchemaVersion(version: number): Promise<void>;
114
+ /**
115
+ * Apply schema SQL if version is outdated.
116
+ * Handles version checking and updating atomically.
117
+ *
118
+ * @param version - Target schema version
119
+ * @param sql - Schema SQL to execute
120
+ * @returns true if schema was applied, false if already up-to-date
121
+ */
122
+ applySchema(version: number, sql: string): Promise<boolean>;
123
+ /**
124
+ * Get database file size in bytes.
125
+ * Returns 0 for in-memory databases.
126
+ */
127
+ getDatabaseSize(): Promise<number>;
128
+ /**
129
+ * Vacuum the database to reclaim space.
130
+ */
131
+ vacuum(): Promise<void>;
132
+ /**
133
+ * Checkpoint WAL file (for WAL mode databases).
134
+ * Returns the number of frames checkpointed.
135
+ */
136
+ checkpoint(): Promise<number>;
137
+ /**
138
+ * Get the current storage mode of the database.
139
+ * Returns 'opfs' if using OPFS-backed persistent storage,
140
+ * or 'memory' if using in-memory fallback.
141
+ */
142
+ getStorageMode(): Promise<'opfs' | 'memory'> | 'opfs' | 'memory';
143
+ }
144
+ /**
145
+ * Prepared statement for repeated execution.
146
+ */
147
+ interface PreparedStatement {
148
+ /**
149
+ * Execute the statement with parameters and return rows.
150
+ */
151
+ query<T extends SQLRow = SQLRow>(params?: SQLValue[]): Promise<T[]>;
152
+ /**
153
+ * Execute the statement with parameters and return one row.
154
+ */
155
+ queryOne<T extends SQLRow = SQLRow>(params?: SQLValue[]): Promise<T | null>;
156
+ /**
157
+ * Execute the statement with parameters for modification.
158
+ */
159
+ run(params?: SQLValue[]): Promise<RunResult>;
160
+ /**
161
+ * Release the prepared statement.
162
+ */
163
+ finalize(): Promise<void>;
164
+ }
165
+
166
+ export type { PreparedStatement as P, SQLiteAdapter as S };
@@ -0,0 +1,106 @@
1
+ import { S as SQLiteAdapter, P as PreparedStatement } from '../adapter-I7yAV6iu.js';
2
+ import { b as SQLiteConfig, a as SQLRow, S as SQLValue, R as RunResult } from '../types-C_aHfRDF.js';
3
+ import Database from 'better-sqlite3';
4
+ export { a as SCHEMA_DDL, S as SCHEMA_VERSION } from '../schema-CjkXTqxn.js';
5
+
6
+ /**
7
+ * @xnetjs/sqlite - Electron SQLite adapter using better-sqlite3
8
+ *
9
+ * better-sqlite3 provides synchronous SQLite access for Node.js/Electron.
10
+ * The async interface is maintained for compatibility with other adapters.
11
+ */
12
+
13
+ /**
14
+ * SQLite adapter for Electron using better-sqlite3.
15
+ *
16
+ * better-sqlite3 is synchronous, which is ideal for Electron's utility process.
17
+ * The async interface is maintained for compatibility with other adapters.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const adapter = new ElectronSQLiteAdapter()
22
+ * await adapter.open({ path: '/path/to/xnet.db' })
23
+ *
24
+ * const nodes = await adapter.query('SELECT * FROM nodes')
25
+ * ```
26
+ */
27
+ declare class ElectronSQLiteAdapter implements SQLiteAdapter {
28
+ private db;
29
+ private config;
30
+ private inTransaction;
31
+ private statementCache;
32
+ open(config: SQLiteConfig): Promise<void>;
33
+ close(): Promise<void>;
34
+ isOpen(): boolean;
35
+ query<T extends SQLRow = SQLRow>(sql: string, params?: SQLValue[]): Promise<T[]>;
36
+ queryOne<T extends SQLRow = SQLRow>(sql: string, params?: SQLValue[]): Promise<T | null>;
37
+ run(sql: string, params?: SQLValue[]): Promise<RunResult>;
38
+ exec(sql: string): Promise<void>;
39
+ transaction<T>(fn: () => Promise<T>): Promise<T>;
40
+ /**
41
+ * Synchronous transaction for performance-critical batch operations.
42
+ * Prefer this over async transaction when the body is synchronous.
43
+ */
44
+ transactionSync<T>(fn: () => T): T;
45
+ beginTransaction(): Promise<void>;
46
+ commit(): Promise<void>;
47
+ rollback(): Promise<void>;
48
+ prepare(sql: string): Promise<PreparedStatement>;
49
+ getSchemaVersion(): Promise<number>;
50
+ setSchemaVersion(version: number): Promise<void>;
51
+ applySchema(version: number, sql: string): Promise<boolean>;
52
+ getDatabaseSize(): Promise<number>;
53
+ vacuum(): Promise<void>;
54
+ checkpoint(): Promise<number>;
55
+ getStorageMode(): 'opfs' | 'memory';
56
+ /**
57
+ * Get a statement from cache or prepare it.
58
+ * Statement caching significantly improves performance for repeated queries.
59
+ */
60
+ private getOrPrepare;
61
+ private ensureOpen;
62
+ private wrapError;
63
+ /**
64
+ * Get the underlying better-sqlite3 database instance.
65
+ * Use for advanced operations not covered by the interface.
66
+ */
67
+ getRawDatabase(): Database.Database;
68
+ /**
69
+ * Create a batch writer for efficient bulk inserts.
70
+ */
71
+ createBatchWriter(options?: {
72
+ maxBatchSize?: number;
73
+ }): ElectronBatchWriter;
74
+ }
75
+ /**
76
+ * Batch writer for efficient bulk operations.
77
+ * Batches multiple writes and executes them in a single transaction.
78
+ */
79
+ declare class ElectronBatchWriter {
80
+ private adapter;
81
+ private pendingOps;
82
+ private maxBatchSize;
83
+ private flushTimer;
84
+ private flushPromise;
85
+ constructor(adapter: ElectronSQLiteAdapter, options?: {
86
+ maxBatchSize?: number;
87
+ });
88
+ /**
89
+ * Queue an operation for batch execution.
90
+ */
91
+ queue(sql: string, params: SQLValue[]): void;
92
+ /**
93
+ * Flush all pending operations.
94
+ */
95
+ flush(): Promise<void>;
96
+ /**
97
+ * Close the batch writer, flushing any pending operations.
98
+ */
99
+ close(): Promise<void>;
100
+ }
101
+ /**
102
+ * Create an ElectronSQLiteAdapter with schema applied.
103
+ */
104
+ declare function createElectronSQLiteAdapter(config: SQLiteConfig): Promise<ElectronSQLiteAdapter>;
105
+
106
+ export { ElectronBatchWriter, ElectronSQLiteAdapter, createElectronSQLiteAdapter };