@optimystic/quereus-plugin-optimystic 0.3.0

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 (45) hide show
  1. package/README.md +358 -0
  2. package/dist/index.d.ts +96 -0
  3. package/dist/index.js +2973 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/plugin-B1lVAVv0.d.ts +596 -0
  6. package/dist/plugin.d.ts +4 -0
  7. package/dist/plugin.js +2873 -0
  8. package/dist/plugin.js.map +1 -0
  9. package/examples/README.md +232 -0
  10. package/examples/quoomb.config.absolute.json +22 -0
  11. package/examples/quoomb.config.dev.json +16 -0
  12. package/examples/quoomb.config.linked.json +25 -0
  13. package/examples/quoomb.config.local.json +22 -0
  14. package/examples/quoomb.config.node1.json +23 -0
  15. package/examples/quoomb.config.node2.env.json +28 -0
  16. package/examples/quoomb.config.node2.json +29 -0
  17. package/examples/quoomb.config.single-node.json +25 -0
  18. package/examples/quoomb.config.web.json +30 -0
  19. package/examples/start-mesh.ps1 +48 -0
  20. package/examples/start-mesh.sh +44 -0
  21. package/examples/test-comprehensive.sql +25 -0
  22. package/examples/test-manual-plugin.txt +23 -0
  23. package/examples/test-multi-insert.sql +11 -0
  24. package/examples/test-network.sql +20 -0
  25. package/examples/test-plugin.sql +20 -0
  26. package/examples/test-single-insert.sql +20 -0
  27. package/examples/test-single-node.sql +20 -0
  28. package/package.json +131 -0
  29. package/src/functions/transaction-id.ts +29 -0
  30. package/src/index.ts +42 -0
  31. package/src/optimystic-adapter/collection-factory.ts +337 -0
  32. package/src/optimystic-adapter/key-network.ts +106 -0
  33. package/src/optimystic-adapter/txn-bridge.ts +272 -0
  34. package/src/optimystic-adapter/vtab-connection.ts +76 -0
  35. package/src/optimystic-module.ts +1064 -0
  36. package/src/plugin.ts +64 -0
  37. package/src/schema/index-manager.ts +266 -0
  38. package/src/schema/row-codec.ts +312 -0
  39. package/src/schema/schema-manager.ts +217 -0
  40. package/src/schema/statistics-collector.ts +173 -0
  41. package/src/transaction/index.ts +16 -0
  42. package/src/transaction/quereus-engine.ts +174 -0
  43. package/src/types.ts +91 -0
  44. package/src/util/generate-transaction-id.ts +41 -0
  45. package/test/README.md +313 -0
package/README.md ADDED
@@ -0,0 +1,358 @@
1
+ # @optimystic/quereus-plugin-optimystic
2
+
3
+ A Quereus virtual table plugin that provides SQL access to Optimystic distributed tree collections.
4
+
5
+ ## What's New
6
+
7
+ - ✨ **TransactionId() function** - Get unique transaction identifiers for audit logging
8
+ - 🔧 **Transaction-specific caching** - Better isolation and no stale data
9
+ - 🧪 **Distributed testing** - Automated tests for multi-node operations
10
+
11
+ See [CHANGELOG.md](./CHANGELOG.md) for details.
12
+
13
+ ## Overview
14
+
15
+ This plugin allows you to query and manipulate Optimystic distributed tree collections using standard SQL syntax through Quereus. It bridges the gap between SQL databases and Optimystic's distributed data structures.
16
+
17
+ For cryptographic functions (hashing, signing, verification), see the separate [@optimystic/quereus-plugin-crypto](../quereus-plugin-crypto) package.
18
+
19
+ **📖 New to Optimystic SQL? See [QUICK-START.md](./QUICK-START.md) for a 5-minute tutorial!**
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @optimystic/quereus-plugin-optimystic
25
+ ```
26
+
27
+ ## Quick Start
28
+
29
+ ### Using Quoomb (Interactive SQL Console)
30
+
31
+ The easiest way to get started is with [Quoomb](https://github.com/Digithought/quereus/tree/main/packages/quoomb-cli), the interactive SQL console for Quereus:
32
+
33
+ ```bash
34
+ # Install Quoomb globally
35
+ npm install -g @quereus/quoomb-cli
36
+
37
+ # Start with Optimystic plugin using example config
38
+ quoomb --config node_modules/@optimystic/quereus-plugin-optimystic/examples/quoomb.config.dev.json
39
+ ```
40
+
41
+ Then in the Quoomb console:
42
+
43
+ ```sql
44
+ CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)
45
+ USING optimystic('tree://app/users');
46
+
47
+ INSERT INTO users VALUES (1, 'Alice'), (2, 'Bob');
48
+
49
+ SELECT * FROM users;
50
+ ```
51
+
52
+ **See [examples/README.md](./examples/README.md) for multi-node mesh setup and more configurations.**
53
+
54
+ ### Programmatic Usage
55
+
56
+ ```typescript
57
+ import { Database } from '@quereus/quereus';
58
+ import { loadPlugin } from '@quereus/quereus/util/plugin-loader.js';
59
+
60
+ const db = new Database();
61
+
62
+ // Load and register the plugin
63
+ await loadPlugin('npm:@optimystic/quereus-plugin-optimystic', db, {
64
+ default_transactor: 'network',
65
+ default_key_network: 'libp2p',
66
+ enable_cache: true
67
+ });
68
+
69
+ // Create a virtual table backed by an Optimystic tree collection
70
+ await db.exec(`
71
+ CREATE TABLE users USING optimystic(
72
+ 'tree://myapp/users',
73
+ transactor='network',
74
+ keyNetwork='libp2p'
75
+ )
76
+ `);
77
+
78
+ // Query the distributed data
79
+ const users = await db.all('SELECT * FROM users WHERE id = ?', ['user123']);
80
+ ```
81
+
82
+ ## Plugin Settings
83
+
84
+ The plugin can be configured when loading with the following settings:
85
+
86
+ - **default_transactor**: Default transactor type (`'network'`, `'test'`, or custom) - default: `'network'`
87
+ - **default_key_network**: Default key network type (`'libp2p'`, `'test'`, or custom) - default: `'libp2p'`
88
+ - **default_port**: Default port for libp2p nodes (0 = random) - default: `0`
89
+ - **default_network_name**: Default network identifier - default: `'optimystic'`
90
+ - **enable_cache**: Whether to cache collections between queries - default: `true`
91
+
92
+ ```typescript
93
+ await loadPlugin('npm:@optimystic/quereus-plugin-optimystic', db, {
94
+ default_transactor: 'network',
95
+ default_key_network: 'libp2p',
96
+ default_port: 0,
97
+ default_network_name: 'myapp',
98
+ enable_cache: true
99
+ });
100
+ ```
101
+
102
+ ## Virtual Table Options
103
+
104
+ The plugin supports various configuration options passed as arguments to the `USING` clause:
105
+
106
+ ### Basic Options
107
+
108
+ - **collectionUri** (required): URI identifying the tree collection (e.g., `'tree://myapp/users'`)
109
+ - **transactor**: Type of transactor to use (`'network'`, `'test'`, or custom)
110
+ - **keyNetwork**: Type of key network (`'libp2p'`, `'test'`, or custom)
111
+
112
+ ### Network Options
113
+
114
+ - **port**: Port for libp2p node (default: from plugin settings)
115
+ - **networkName**: Network identifier (default: from plugin settings)
116
+ - **cache**: Enable local caching (default: from plugin settings)
117
+ - **encoding**: Row encoding format (`'json'` or `'msgpack'`, default: `'json'`)
118
+
119
+ ### Example with Options
120
+
121
+ ```sql
122
+ CREATE TABLE products USING optimystic(
123
+ 'tree://store/products',
124
+ transactor='network',
125
+ keyNetwork='libp2p',
126
+ port=8080,
127
+ networkName='mystore',
128
+ cache=true,
129
+ encoding='json'
130
+ );
131
+ ```
132
+
133
+ ## SQL Operations
134
+
135
+ ### SELECT Queries
136
+
137
+ ```sql
138
+ -- Point lookups (optimized)
139
+ SELECT * FROM users WHERE id = 'user123';
140
+
141
+ -- Range scans
142
+ SELECT * FROM users WHERE id BETWEEN 'user100' AND 'user200';
143
+
144
+ -- Full table scans
145
+ SELECT * FROM users ORDER BY id;
146
+ ```
147
+
148
+ ### INSERT Operations
149
+
150
+ ```sql
151
+ INSERT INTO users (id, data)
152
+ VALUES ('user456', '{"name": "Alice", "email": "alice@example.com"}');
153
+ ```
154
+
155
+ ### UPDATE Operations
156
+
157
+ ```sql
158
+ UPDATE users
159
+ SET data = '{"name": "Alice Smith", "email": "alice.smith@example.com"}'
160
+ WHERE id = 'user456';
161
+ ```
162
+
163
+ ### DELETE Operations
164
+
165
+ ```sql
166
+ DELETE FROM users WHERE id = 'user456';
167
+ ```
168
+
169
+ ## Data Model
170
+
171
+ The plugin provides a simple key-value interface to Optimystic tree collections:
172
+
173
+ - **Primary Key**: The `id` column serves as the tree key (TEXT type)
174
+ - **Data**: The `data` column stores the value (TEXT type, can be JSON)
175
+ - **Schema**: Fixed schema with `id` and `data` columns
176
+
177
+ ### Example Schema
178
+
179
+ ```sql
180
+ -- The schema is automatically defined as:
181
+ CREATE TABLE optimystic_tree (
182
+ id TEXT PRIMARY KEY,
183
+ data TEXT
184
+ );
185
+ ```
186
+
187
+ ### Storing Complex Data
188
+
189
+ ```sql
190
+ -- Store JSON data in the data column
191
+ INSERT INTO users VALUES ('user123', '{"name": "Alice", "email": "alice@example.com"}');
192
+
193
+ -- Query JSON data using Quereus JSON functions
194
+ SELECT id, json_extract(data, '$.name') as name
195
+ FROM users
196
+ WHERE json_extract(data, '$.email') LIKE '%@example.com';
197
+ ```
198
+
199
+ ## Transactions
200
+
201
+ The plugin supports Quereus transactions, which map to Optimystic's sync mechanism:
202
+
203
+ ```typescript
204
+ await db.exec('BEGIN');
205
+ await db.exec("INSERT INTO users VALUES ('u1', '{\"name\": \"John\", \"email\": \"john@example.com\"}')");
206
+ await db.exec("INSERT INTO users VALUES ('u2', '{\"name\": \"Jane\", \"email\": \"jane@example.com\"}')");
207
+ await db.exec('COMMIT'); // Syncs changes to the distributed network
208
+ ```
209
+
210
+ - **BEGIN**: Creates a new Optimystic transactor
211
+ - **COMMIT**: Syncs all collections used in the transaction
212
+ - **ROLLBACK**: Discards local changes and clears collection cache
213
+
214
+ ### TransactionId() Function
215
+
216
+ The plugin provides a `TransactionId()` SQL function that returns a unique identifier for the current transaction:
217
+
218
+ ```sql
219
+ -- Get transaction ID
220
+ BEGIN;
221
+ SELECT TransactionId(); -- Returns base64url-encoded 32-byte ID
222
+ COMMIT;
223
+
224
+ -- Use in WITH CONTEXT clause
225
+ CREATE TABLE audit_log (
226
+ id TEXT PRIMARY KEY,
227
+ action TEXT,
228
+ txn_id TEXT DEFAULT context_txn_id
229
+ ) USING optimystic('tree://app/audit')
230
+ WITH CONTEXT (
231
+ context_txn_id TEXT
232
+ );
233
+
234
+ INSERT INTO audit_log (id, action)
235
+ WITH CONTEXT context_txn_id = TransactionId()
236
+ VALUES ('log1', 'user_created');
237
+ ```
238
+
239
+ **Features:**
240
+ - Returns NULL outside of transactions
241
+ - Returns the same ID throughout a transaction
242
+ - Different ID for each transaction
243
+ - 32-byte format: 16 bytes SHA-256(peer ID) + 16 bytes random
244
+ - Base64url encoded for safe use in SQL
245
+ - Works immediately after BEGIN (no DML required)
246
+
247
+ ## Cryptographic Functions
248
+
249
+ For cryptographic functions (hashing, signing, verification, random bytes), use the separate [@optimystic/quereus-plugin-crypto](../quereus-plugin-crypto) package:
250
+
251
+ ```typescript
252
+ // Load both plugins
253
+ await loadPlugin('npm:@optimystic/quereus-plugin-optimystic', db);
254
+ await loadPlugin('npm:@optimystic/quereus-plugin-crypto', db);
255
+
256
+ // Use crypto functions in SQL
257
+ const hash = await db.get("SELECT digest('hello world', 'sha256', 'utf8', 'base64url') as hash");
258
+ const nonce = await db.get("SELECT random_bytes(256) as nonce");
259
+ ```
260
+
261
+ See the [crypto plugin documentation](../quereus-plugin-crypto/README.md) for complete details.
262
+
263
+ ## Custom Networks and Transactors
264
+
265
+ You can register custom implementations for advanced use cases:
266
+
267
+ ```typescript
268
+ import { registerKeyNetwork, registerTransactor } from '@optimystic/quereus-plugin-optimystic';
269
+
270
+ // Register a custom key network
271
+ registerKeyNetwork('mynetwork', MyCustomKeyNetwork);
272
+
273
+ // Register a custom transactor
274
+ registerTransactor('mytransactor', MyCustomTransactor);
275
+
276
+ // Use in SQL
277
+ await db.exec(`
278
+ CREATE TABLE data USING optimystic(
279
+ 'tree://app/data',
280
+ transactor='mytransactor',
281
+ keyNetwork='mynetwork'
282
+ )
283
+ `);
284
+ ```
285
+
286
+ ## Performance Considerations
287
+
288
+ ### Query Optimization
289
+
290
+ - **Point Lookups**: Queries with `WHERE id = ?` are highly optimized
291
+ - **Range Scans**: Queries with `WHERE id BETWEEN ? AND ?` use efficient tree iteration
292
+ - **Full Scans**: Queries without key constraints iterate the entire collection
293
+
294
+ ### Caching
295
+
296
+ - Collections are cached within transactions and between queries
297
+ - Set `cache=false` to disable caching if memory is a concern
298
+ - Cache is automatically cleared on rollback
299
+
300
+ ### Network Efficiency
301
+
302
+ - Use transactions to batch multiple operations
303
+ - Consider using `'test'` transactor for local development
304
+ - Configure appropriate libp2p options for your network topology
305
+
306
+ ## Error Handling
307
+
308
+ The plugin maps Optimystic errors to appropriate SQL error codes:
309
+
310
+ - **Collection not found**: `SQLITE_CONSTRAINT_PRIMARYKEY`
311
+ - **Network timeouts**: `SQLITE_BUSY`
312
+ - **Decoding failures**: `SQLITE_CORRUPT`
313
+ - **Configuration errors**: `SQLITE_ERROR`
314
+
315
+ ## Limitations
316
+
317
+ - Primary key must be TEXT type (tree keys are strings)
318
+ - No secondary indexes (use appropriate WHERE clauses for performance)
319
+ - Cross-collection transactions not yet supported
320
+ - Savepoints not implemented
321
+
322
+ ## Development
323
+
324
+ ### Building
325
+
326
+ ```bash
327
+ npm run build
328
+ ```
329
+
330
+ ### Type Checking
331
+
332
+ ```bash
333
+ npm run typecheck
334
+ ```
335
+
336
+ ### Testing
337
+
338
+ ```bash
339
+ # Run all tests
340
+ npm test
341
+
342
+ # Run only distributed tests
343
+ npm exec aegir test -t node -- --grep "Distributed"
344
+
345
+ # Manual interactive mesh test
346
+ npm run build
347
+ node dist/test/manual-mesh-test.js
348
+ ```
349
+
350
+ See [test/README.md](./test/README.md) for detailed testing documentation.
351
+
352
+ ## License
353
+
354
+ MIT
355
+
356
+ ## Contributing
357
+
358
+ Contributions are welcome! Please see the main Optimystic repository for contribution guidelines.
@@ -0,0 +1,96 @@
1
+ export { C as ColumnDefinition, L as LibP2PNodeOptions, O as OptimysticModule, b as OptimysticTreeOptions, a as OptimysticVirtualTable, P as ParsedOptimysticTreeOptions, R as RowData, T as TransactionState, r as register } from './plugin-B1lVAVv0.js';
2
+ import { IKeyNetwork, ITransactionEngine, TransactionCoordinator, Transaction, ExecutionResult } from '@optimystic/db-core';
3
+ import { Database, SqlParameters } from '@quereus/quereus';
4
+ import '@libp2p/interface';
5
+
6
+ /**
7
+ * Register a custom key network implementation
8
+ */
9
+ declare function registerKeyNetwork(name: string, implementation: new (...args: any[]) => IKeyNetwork): void;
10
+ /**
11
+ * Register a custom transactor implementation
12
+ */
13
+ declare function registerTransactor(name: string, implementation: new (...args: any[]) => any): void;
14
+
15
+ /**
16
+ * Engine ID for Quereus SQL transactions.
17
+ * Format: "quereus@{version}" where version matches the quereus package version.
18
+ */
19
+ declare const QUEREUS_ENGINE_ID = "quereus@0.5.3";
20
+ /**
21
+ * Statement format for Quereus transactions.
22
+ * Each statement is a SQL string with optional parameters.
23
+ */
24
+ type QuereusStatement = {
25
+ /** The SQL statement to execute */
26
+ sql: string;
27
+ /** Optional parameters for the statement */
28
+ params?: SqlParameters;
29
+ };
30
+ /**
31
+ * Quereus-specific transaction engine for SQL execution.
32
+ *
33
+ * This engine:
34
+ * 1. Executes SQL statements through a Quereus database
35
+ * 2. Collects resulting actions from the virtual table module
36
+ * 3. Computes schema hash for validation
37
+ *
38
+ * Used for both initial execution (client creating transaction) and
39
+ * re-execution (validators verifying transaction).
40
+ */
41
+ declare class QuereusEngine implements ITransactionEngine {
42
+ private readonly db;
43
+ private readonly coordinator;
44
+ private schemaHashCache;
45
+ private schemaVersion;
46
+ constructor(db: Database, coordinator: TransactionCoordinator);
47
+ /**
48
+ * Execute a transaction's statements and produce actions.
49
+ *
50
+ * For initial execution: Executes SQL through Quereus, which triggers
51
+ * the Optimystic virtual table module to apply actions.
52
+ *
53
+ * For validation: Re-executes the same SQL statements to verify
54
+ * they produce the same operations.
55
+ */
56
+ execute(transaction: Transaction): Promise<ExecutionResult>;
57
+ /**
58
+ * Get the schema hash for this engine.
59
+ *
60
+ * The schema hash is used for validation - all participants must have
61
+ * matching schema hashes for a transaction to be valid.
62
+ *
63
+ * Uses caching to avoid recomputing if schema hasn't changed.
64
+ */
65
+ getSchemaHash(): Promise<string>;
66
+ /**
67
+ * Invalidate the schema hash cache.
68
+ * Call this when the schema changes (e.g., after DDL statements).
69
+ */
70
+ invalidateSchemaCache(): void;
71
+ /**
72
+ * Get the current schema version number.
73
+ * Increments each time the schema cache is invalidated.
74
+ */
75
+ getSchemaVersion(): number;
76
+ /**
77
+ * Compute the schema hash from the database catalog.
78
+ *
79
+ * Uses the schema() table-valued function to get schema information,
80
+ * then hashes the canonical representation using SHA-256.
81
+ */
82
+ private computeSchemaHash;
83
+ }
84
+ /**
85
+ * Helper to create Quereus statement JSON for a transaction.
86
+ */
87
+ declare function createQuereusStatement(sql: string, params?: SqlParameters): string;
88
+ /**
89
+ * Helper to create an array of Quereus statements for a transaction.
90
+ */
91
+ declare function createQuereusStatements(statements: Array<{
92
+ sql: string;
93
+ params?: SqlParameters;
94
+ }>): string[];
95
+
96
+ export { QUEREUS_ENGINE_ID, QuereusEngine, type QuereusStatement, createQuereusStatement, createQuereusStatements, registerKeyNetwork, registerTransactor };