sqlite-sync-core 0.1.0__tar.gz

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 (48) hide show
  1. sqlite_sync_core-0.1.0/LICENSE +46 -0
  2. sqlite_sync_core-0.1.0/PKG-INFO +326 -0
  3. sqlite_sync_core-0.1.0/README.md +297 -0
  4. sqlite_sync_core-0.1.0/pyproject.toml +54 -0
  5. sqlite_sync_core-0.1.0/setup.cfg +4 -0
  6. sqlite_sync_core-0.1.0/src/sqlite_sync/__init__.py +24 -0
  7. sqlite_sync_core-0.1.0/src/sqlite_sync/audit/__init__.py +19 -0
  8. sqlite_sync_core-0.1.0/src/sqlite_sync/audit/import_log.py +159 -0
  9. sqlite_sync_core-0.1.0/src/sqlite_sync/bundle/__init__.py +26 -0
  10. sqlite_sync_core-0.1.0/src/sqlite_sync/bundle/format.py +97 -0
  11. sqlite_sync_core-0.1.0/src/sqlite_sync/bundle/generate.py +200 -0
  12. sqlite_sync_core-0.1.0/src/sqlite_sync/bundle/validate.py +205 -0
  13. sqlite_sync_core-0.1.0/src/sqlite_sync/capture/__init__.py +17 -0
  14. sqlite_sync_core-0.1.0/src/sqlite_sync/capture/change_capture.py +90 -0
  15. sqlite_sync_core-0.1.0/src/sqlite_sync/config.py +48 -0
  16. sqlite_sync_core-0.1.0/src/sqlite_sync/db/__init__.py +38 -0
  17. sqlite_sync_core-0.1.0/src/sqlite_sync/db/connection.py +164 -0
  18. sqlite_sync_core-0.1.0/src/sqlite_sync/db/migrations.py +232 -0
  19. sqlite_sync_core-0.1.0/src/sqlite_sync/db/schema.py +183 -0
  20. sqlite_sync_core-0.1.0/src/sqlite_sync/db/triggers.py +362 -0
  21. sqlite_sync_core-0.1.0/src/sqlite_sync/engine.py +541 -0
  22. sqlite_sync_core-0.1.0/src/sqlite_sync/errors.py +176 -0
  23. sqlite_sync_core-0.1.0/src/sqlite_sync/import_apply/__init__.py +43 -0
  24. sqlite_sync_core-0.1.0/src/sqlite_sync/import_apply/apply.py +185 -0
  25. sqlite_sync_core-0.1.0/src/sqlite_sync/import_apply/conflict.py +223 -0
  26. sqlite_sync_core-0.1.0/src/sqlite_sync/import_apply/dedup.py +67 -0
  27. sqlite_sync_core-0.1.0/src/sqlite_sync/import_apply/ordering.py +70 -0
  28. sqlite_sync_core-0.1.0/src/sqlite_sync/invariants.py +193 -0
  29. sqlite_sync_core-0.1.0/src/sqlite_sync/log/__init__.py +47 -0
  30. sqlite_sync_core-0.1.0/src/sqlite_sync/log/operations.py +350 -0
  31. sqlite_sync_core-0.1.0/src/sqlite_sync/log/vector_clock.py +218 -0
  32. sqlite_sync_core-0.1.0/src/sqlite_sync/network/client.py +79 -0
  33. sqlite_sync_core-0.1.0/src/sqlite_sync/network/protocol.py +22 -0
  34. sqlite_sync_core-0.1.0/src/sqlite_sync/network/server.py +43 -0
  35. sqlite_sync_core-0.1.0/src/sqlite_sync/utils/__init__.py +4 -0
  36. sqlite_sync_core-0.1.0/src/sqlite_sync/utils/hashing.py +114 -0
  37. sqlite_sync_core-0.1.0/src/sqlite_sync/utils/msgpack_codec.py +158 -0
  38. sqlite_sync_core-0.1.0/src/sqlite_sync/utils/uuid7.py +117 -0
  39. sqlite_sync_core-0.1.0/src/sqlite_sync_core.egg-info/PKG-INFO +326 -0
  40. sqlite_sync_core-0.1.0/src/sqlite_sync_core.egg-info/SOURCES.txt +46 -0
  41. sqlite_sync_core-0.1.0/src/sqlite_sync_core.egg-info/dependency_links.txt +1 -0
  42. sqlite_sync_core-0.1.0/src/sqlite_sync_core.egg-info/requires.txt +6 -0
  43. sqlite_sync_core-0.1.0/src/sqlite_sync_core.egg-info/top_level.txt +1 -0
  44. sqlite_sync_core-0.1.0/tests/test_conflicts.py +307 -0
  45. sqlite_sync_core-0.1.0/tests/test_determinism.py +224 -0
  46. sqlite_sync_core-0.1.0/tests/test_idempotency.py +189 -0
  47. sqlite_sync_core-0.1.0/tests/test_invariants.py +171 -0
  48. sqlite_sync_core-0.1.0/tests/test_minimal.py +3 -0
@@ -0,0 +1,46 @@
1
+ # SQLite Sync Core License
2
+
3
+ Copyright (c) 2024 VisionQuantech, India
4
+
5
+ ## Dual License
6
+
7
+ This software is available under two license options:
8
+
9
+ ### 1. Open Source License (AGPL-3.0)
10
+
11
+ For **non-commercial** and **open-source projects**, this software is licensed under the [GNU Affero General Public License v3.0](https://www.gnu.org/licenses/agpl-3.0.html).
12
+
13
+ You may use, modify, and distribute this software freely, provided that:
14
+
15
+ - Your project is also open source under a compatible license
16
+ - You include this license notice
17
+ - Any modifications are also open sourced under AGPL-3.0
18
+ - Network use counts as distribution (SaaS must open source)
19
+
20
+ ### 2. Commercial License
21
+
22
+ For **commercial use**, **proprietary software**, or **closed-source projects**, you must purchase a commercial license.
23
+
24
+ **Commercial use includes:**
25
+
26
+ - Using this library in proprietary/closed-source software
27
+ - Using this library in SaaS products without open-sourcing
28
+ - Any use where you cannot comply with AGPL-3.0 terms
29
+
30
+ **Contact for licensing:**
31
+
32
+ - Email: <shivaysinghrajput@proton.me>
33
+ - Email: <shivaysinghrajput@outlook.com>
34
+ - Email: <vbs.visionquanteh@proton.me>
35
+
36
+ ---
37
+
38
+ **AGPL-3.0 Summary:**
39
+
40
+ - ✅ Free for personal projects
41
+ - ✅ Free for open-source projects (with AGPL-3.0 compatible license)
42
+ - ✅ Free for educational/research use
43
+ - ❌ NOT free for closed-source commercial products
44
+ - ❌ NOT free for proprietary SaaS without open-sourcing
45
+
46
+ For the full AGPL-3.0 license text, see: <https://www.gnu.org/licenses/agpl-3.0.html>
@@ -0,0 +1,326 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlite-sync-core
3
+ Version: 0.1.0
4
+ Summary: Universal SQLite Synchronization Core - A dependency-grade, local-first, offline-first SQLite synchronization primitive
5
+ License: MIT
6
+ Project-URL: Homepage, https://github.com/shivay00001/sqlite-sync-core
7
+ Project-URL: Documentation, https://github.com/shivay00001/sqlite-sync-core#readme
8
+ Project-URL: Repository, https://github.com/shivay00001/sqlite-sync-core.git
9
+ Project-URL: Issues, https://github.com/shivay00001/sqlite-sync-core/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: MIT License
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Topic :: Database
18
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
19
+ Classifier: Typing :: Typed
20
+ Requires-Python: >=3.11
21
+ Description-Content-Type: text/markdown
22
+ License-File: LICENSE
23
+ Requires-Dist: msgpack>=1.0.0
24
+ Requires-Dist: websockets>=12.0
25
+ Provides-Extra: dev
26
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
27
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
28
+ Dynamic: license-file
29
+
30
+ # Universal SQLite Synchronization Core
31
+
32
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
33
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
34
+ [![Status: Production Ready](https://img.shields.io/badge/status-production--ready-brightgreen.svg)](https://github.com/shivay00001/sqlite-sync-core)
35
+
36
+ **A product of [VisionQuantech](https://github.com/shivay00001), India 🇮🇳**
37
+
38
+ **A dependency-grade, local-first, offline-first SQLite synchronization primitive.**
39
+
40
+ Captures database changes as structured operations, packages them into self-contained bundles, and applies them deterministically across disconnected devices.
41
+
42
+ ---
43
+
44
+ ## Features
45
+
46
+ - 🔒 **Append-only log** – Operations are immutable history
47
+ - 🕐 **Vector clocks** – Causality tracking across devices
48
+ - ⚔️ **Conflict detection** – Never auto-merges, preserves conflicts
49
+ - 🔄 **Deterministic replay** – Same operations = same result everywhere
50
+ - 📦 **Transport agnostic** – Bundles work over USB, email, Bluetooth, anything
51
+ - 🚫 **Zero infrastructure** – No servers, no cloud, no network required
52
+
53
+ ---
54
+
55
+ ## Installation
56
+
57
+ ### From PyPI
58
+
59
+ ```bash
60
+ pip install sqlite-sync-core
61
+ ```
62
+
63
+ ### From GitHub (Development)
64
+
65
+ ```bash
66
+ git clone https://github.com/shivay00001/sqlite-sync-core.git
67
+ cd sqlite-sync-core
68
+ pip install -e .
69
+ ```
70
+
71
+ ---
72
+
73
+ ## Real-Time Network Sync
74
+
75
+ SQLite Sync Core now supports real-time synchronization over WebSockets.
76
+
77
+ ### Start the Reference Server
78
+
79
+ ```bash
80
+ python -m sqlite_sync.network.server
81
+ ```
82
+
83
+ ### Connect a Client
84
+
85
+ ```python
86
+ from sqlite_sync import SyncEngine
87
+ from sqlite_sync.network.client import SyncClient
88
+
89
+ engine = SyncEngine("my_app.db")
90
+ engine.initialize()
91
+
92
+ client = SyncClient(engine, "ws://localhost:8765")
93
+ await client.connect()
94
+
95
+ # Listen for remote changes
96
+ asyncio.create_task(client.listen())
97
+
98
+ # Send local changes
99
+ ops = engine.get_new_operations()
100
+ for op in ops:
101
+ await client.send_operation(op)
102
+ ```
103
+
104
+ ---
105
+
106
+ ## Integration Examples
107
+
108
+ See the `examples/` directory for full integration samples:
109
+
110
+ - `basic_usage.py`: Simple CLI setup.
111
+ - `network_sync.py`: Real-time sync between two peers.
112
+ - `desktop_example.py`: Coming soon (GUI integration).
113
+
114
+ ### Requirements
115
+
116
+ - Python 3.11+
117
+ - `msgpack` (auto-installed)
118
+
119
+ ---
120
+
121
+ ## Quick Start
122
+
123
+ ```python
124
+ from sqlite_sync import SyncEngine
125
+
126
+ # Initialize sync-enabled database
127
+ engine = SyncEngine("my_database.db")
128
+ engine.initialize()
129
+
130
+ # Create a user table
131
+ engine.connection.execute("""
132
+ CREATE TABLE todos (
133
+ id INTEGER PRIMARY KEY,
134
+ title TEXT NOT NULL,
135
+ done INTEGER DEFAULT 0
136
+ )
137
+ """)
138
+
139
+ # Enable sync for the table
140
+ engine.enable_sync_for_table("todos")
141
+
142
+ # Now any INSERT/UPDATE/DELETE is automatically captured!
143
+ engine.connection.execute("INSERT INTO todos (title) VALUES ('Buy milk')")
144
+ ```
145
+
146
+ ---
147
+
148
+ ## Syncing Between Devices
149
+
150
+ ### Device A: Generate a bundle
151
+
152
+ ```python
153
+ from sqlite_sync import SyncEngine
154
+
155
+ engine_a = SyncEngine("device_a.db")
156
+ engine_a.initialize()
157
+
158
+ # Generate bundle for Device B
159
+ bundle_path = engine_a.generate_bundle(
160
+ peer_device_id=device_b_id, # 16-byte UUID
161
+ output_path="sync_bundle.db"
162
+ )
163
+ # Send bundle_path to Device B (USB, email, cloud, etc.)
164
+ ```
165
+
166
+ ### Device B: Import the bundle
167
+
168
+ ```python
169
+ engine_b = SyncEngine("device_b.db")
170
+ engine_b.initialize()
171
+
172
+ # Import received bundle
173
+ result = engine_b.import_bundle("sync_bundle.db")
174
+
175
+ print(f"Applied: {result.applied_count}")
176
+ print(f"Conflicts: {result.conflict_count}")
177
+ print(f"Duplicates: {result.duplicate_count}")
178
+ ```
179
+
180
+ ---
181
+
182
+ ## Handling Conflicts
183
+
184
+ Conflicts occur when two devices modify the same row independently.
185
+
186
+ ```python
187
+ # Get all unresolved conflicts
188
+ conflicts = engine.get_unresolved_conflicts()
189
+
190
+ for conflict in conflicts:
191
+ print(f"Table: {conflict.table_name}")
192
+ print(f"Row PK: {conflict.row_pk}")
193
+ print(f"Local op: {conflict.local_op_id.hex()}")
194
+ print(f"Remote op: {conflict.remote_op_id.hex()}")
195
+ ```
196
+
197
+ > **Note:** This library intentionally does NOT auto-resolve conflicts.
198
+ > You must implement your own resolution strategy.
199
+
200
+ ---
201
+
202
+ ## Core Invariants
203
+
204
+ | # | Invariant | Description |
205
+ |---|-----------|-------------|
206
+ | 1 | **Append-only** | `sync_operations` only grows, never modified |
207
+ | 2 | **Causal consistency** | Vector clocks ensure happens-before |
208
+ | 3 | **Deterministic ordering** | Same operations always sort identically |
209
+ | 4 | **Explicit conflicts** | Concurrent writes preserved as records |
210
+ | 5 | **Idempotent import** | Same bundle × N imports = same result |
211
+ | 6 | **Transport independence** | Bundles are self-contained SQLite files |
212
+
213
+ ---
214
+
215
+ ## API Reference
216
+
217
+ ### `SyncEngine`
218
+
219
+ | Method | Description |
220
+ |--------|-------------|
221
+ | `initialize()` | Initialize sync tables, returns device ID |
222
+ | `enable_sync_for_table(name)` | Install triggers for a table |
223
+ | `generate_bundle(peer_id, path)` | Create bundle for peer |
224
+ | `import_bundle(path)` | Import bundle, returns `ImportResult` |
225
+ | `get_unresolved_conflicts()` | Get all pending conflicts |
226
+ | `get_vector_clock()` | Get current vector clock |
227
+ | `close()` | Close database connection |
228
+
229
+ ### `ImportResult`
230
+
231
+ | Field | Type | Description |
232
+ |-------|------|-------------|
233
+ | `bundle_id` | bytes | UUID of imported bundle |
234
+ | `source_device_id` | bytes | Device that created bundle |
235
+ | `total_operations` | int | Total ops in bundle |
236
+ | `applied_count` | int | Successfully applied |
237
+ | `conflict_count` | int | Conflicts detected |
238
+ | `duplicate_count` | int | Already had these ops |
239
+ | `skipped` | bool | True if bundle already imported |
240
+
241
+ ---
242
+
243
+ ## Project Structure
244
+
245
+ ```
246
+ sqlite_sync_core/
247
+ ├── src/sqlite_sync/
248
+ │ ├── engine.py # Main SyncEngine class
249
+ │ ├── config.py # Configuration constants
250
+ │ ├── errors.py # Exception classes
251
+ │ ├── invariants.py # Core invariant enforcement
252
+ │ ├── db/ # Database layer
253
+ │ │ ├── schema.py # Table definitions
254
+ │ │ ├── migrations.py # Initialization
255
+ │ │ ├── triggers.py # Change capture triggers
256
+ │ │ └── connection.py # Connection management
257
+ │ ├── bundle/ # Bundle operations
258
+ │ │ ├── generate.py # Bundle creation
259
+ │ │ ├── validate.py # Bundle validation
260
+ │ │ └── format.py # Bundle metadata
261
+ │ ├── import_apply/ # Import pipeline
262
+ │ │ ├── apply.py # Apply operations
263
+ │ │ ├── conflict.py # Conflict detection
264
+ │ │ ├── ordering.py # Deterministic sort
265
+ │ │ └── dedup.py # Deduplication
266
+ │ ├── log/ # Operation log
267
+ │ │ ├── operations.py # SyncOperation dataclass
268
+ │ │ └── vector_clock.py# Vector clock logic
269
+ │ └── utils/ # Utilities
270
+ │ ├── uuid7.py # UUID v7 generation
271
+ │ ├── hashing.py # SHA-256 utilities
272
+ │ └── msgpack_codec.py# Serialization
273
+ ├── tests/ # Test suite
274
+ ├── pyproject.toml # Package config
275
+ └── README.md
276
+ ```
277
+
278
+ ---
279
+
280
+ ## Running Tests
281
+
282
+ ```bash
283
+ # Using the custom test runner (no pytest required)
284
+ python run_verification.py
285
+
286
+ # Or with pytest
287
+ pip install pytest
288
+ pytest tests/ -v
289
+ ```
290
+
291
+ ---
292
+
293
+ ## License
294
+
295
+ **Dual License Model:**
296
+
297
+ | Use Case | License | Cost |
298
+ |----------|---------|------|
299
+ | Personal projects | AGPL-3.0 | **Free** |
300
+ | Open-source projects | AGPL-3.0 | **Free** |
301
+ | Educational/Research | AGPL-3.0 | **Free** |
302
+ | Commercial / Proprietary | Commercial License | **Paid** |
303
+
304
+ > **Commercial use** (closed-source, SaaS, proprietary) requires a paid license.
305
+ >
306
+ > **Contact for licensing:**
307
+ >
308
+ > - <shivaysinghrajput@proton.me>
309
+ > - <shivaysinghrajput@outlook.com>
310
+ > - <vbs.visionquanteh@proton.me>
311
+
312
+ See [LICENSE](./LICENSE) for full terms.
313
+
314
+ ---
315
+
316
+ ## Contributing
317
+
318
+ 1. Fork the repository
319
+ 2. Create a feature branch
320
+ 3. Make your changes
321
+ 4. Run the test suite
322
+ 5. Submit a pull request
323
+
324
+ ---
325
+
326
+ **Built with ❤️ for offline-first applications**
@@ -0,0 +1,297 @@
1
+ # Universal SQLite Synchronization Core
2
+
3
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
4
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
5
+ [![Status: Production Ready](https://img.shields.io/badge/status-production--ready-brightgreen.svg)](https://github.com/shivay00001/sqlite-sync-core)
6
+
7
+ **A product of [VisionQuantech](https://github.com/shivay00001), India 🇮🇳**
8
+
9
+ **A dependency-grade, local-first, offline-first SQLite synchronization primitive.**
10
+
11
+ Captures database changes as structured operations, packages them into self-contained bundles, and applies them deterministically across disconnected devices.
12
+
13
+ ---
14
+
15
+ ## Features
16
+
17
+ - 🔒 **Append-only log** – Operations are immutable history
18
+ - 🕐 **Vector clocks** – Causality tracking across devices
19
+ - ⚔️ **Conflict detection** – Never auto-merges, preserves conflicts
20
+ - 🔄 **Deterministic replay** – Same operations = same result everywhere
21
+ - 📦 **Transport agnostic** – Bundles work over USB, email, Bluetooth, anything
22
+ - 🚫 **Zero infrastructure** – No servers, no cloud, no network required
23
+
24
+ ---
25
+
26
+ ## Installation
27
+
28
+ ### From PyPI
29
+
30
+ ```bash
31
+ pip install sqlite-sync-core
32
+ ```
33
+
34
+ ### From GitHub (Development)
35
+
36
+ ```bash
37
+ git clone https://github.com/shivay00001/sqlite-sync-core.git
38
+ cd sqlite-sync-core
39
+ pip install -e .
40
+ ```
41
+
42
+ ---
43
+
44
+ ## Real-Time Network Sync
45
+
46
+ SQLite Sync Core now supports real-time synchronization over WebSockets.
47
+
48
+ ### Start the Reference Server
49
+
50
+ ```bash
51
+ python -m sqlite_sync.network.server
52
+ ```
53
+
54
+ ### Connect a Client
55
+
56
+ ```python
57
+ from sqlite_sync import SyncEngine
58
+ from sqlite_sync.network.client import SyncClient
59
+
60
+ engine = SyncEngine("my_app.db")
61
+ engine.initialize()
62
+
63
+ client = SyncClient(engine, "ws://localhost:8765")
64
+ await client.connect()
65
+
66
+ # Listen for remote changes
67
+ asyncio.create_task(client.listen())
68
+
69
+ # Send local changes
70
+ ops = engine.get_new_operations()
71
+ for op in ops:
72
+ await client.send_operation(op)
73
+ ```
74
+
75
+ ---
76
+
77
+ ## Integration Examples
78
+
79
+ See the `examples/` directory for full integration samples:
80
+
81
+ - `basic_usage.py`: Simple CLI setup.
82
+ - `network_sync.py`: Real-time sync between two peers.
83
+ - `desktop_example.py`: Coming soon (GUI integration).
84
+
85
+ ### Requirements
86
+
87
+ - Python 3.11+
88
+ - `msgpack` (auto-installed)
89
+
90
+ ---
91
+
92
+ ## Quick Start
93
+
94
+ ```python
95
+ from sqlite_sync import SyncEngine
96
+
97
+ # Initialize sync-enabled database
98
+ engine = SyncEngine("my_database.db")
99
+ engine.initialize()
100
+
101
+ # Create a user table
102
+ engine.connection.execute("""
103
+ CREATE TABLE todos (
104
+ id INTEGER PRIMARY KEY,
105
+ title TEXT NOT NULL,
106
+ done INTEGER DEFAULT 0
107
+ )
108
+ """)
109
+
110
+ # Enable sync for the table
111
+ engine.enable_sync_for_table("todos")
112
+
113
+ # Now any INSERT/UPDATE/DELETE is automatically captured!
114
+ engine.connection.execute("INSERT INTO todos (title) VALUES ('Buy milk')")
115
+ ```
116
+
117
+ ---
118
+
119
+ ## Syncing Between Devices
120
+
121
+ ### Device A: Generate a bundle
122
+
123
+ ```python
124
+ from sqlite_sync import SyncEngine
125
+
126
+ engine_a = SyncEngine("device_a.db")
127
+ engine_a.initialize()
128
+
129
+ # Generate bundle for Device B
130
+ bundle_path = engine_a.generate_bundle(
131
+ peer_device_id=device_b_id, # 16-byte UUID
132
+ output_path="sync_bundle.db"
133
+ )
134
+ # Send bundle_path to Device B (USB, email, cloud, etc.)
135
+ ```
136
+
137
+ ### Device B: Import the bundle
138
+
139
+ ```python
140
+ engine_b = SyncEngine("device_b.db")
141
+ engine_b.initialize()
142
+
143
+ # Import received bundle
144
+ result = engine_b.import_bundle("sync_bundle.db")
145
+
146
+ print(f"Applied: {result.applied_count}")
147
+ print(f"Conflicts: {result.conflict_count}")
148
+ print(f"Duplicates: {result.duplicate_count}")
149
+ ```
150
+
151
+ ---
152
+
153
+ ## Handling Conflicts
154
+
155
+ Conflicts occur when two devices modify the same row independently.
156
+
157
+ ```python
158
+ # Get all unresolved conflicts
159
+ conflicts = engine.get_unresolved_conflicts()
160
+
161
+ for conflict in conflicts:
162
+ print(f"Table: {conflict.table_name}")
163
+ print(f"Row PK: {conflict.row_pk}")
164
+ print(f"Local op: {conflict.local_op_id.hex()}")
165
+ print(f"Remote op: {conflict.remote_op_id.hex()}")
166
+ ```
167
+
168
+ > **Note:** This library intentionally does NOT auto-resolve conflicts.
169
+ > You must implement your own resolution strategy.
170
+
171
+ ---
172
+
173
+ ## Core Invariants
174
+
175
+ | # | Invariant | Description |
176
+ |---|-----------|-------------|
177
+ | 1 | **Append-only** | `sync_operations` only grows, never modified |
178
+ | 2 | **Causal consistency** | Vector clocks ensure happens-before |
179
+ | 3 | **Deterministic ordering** | Same operations always sort identically |
180
+ | 4 | **Explicit conflicts** | Concurrent writes preserved as records |
181
+ | 5 | **Idempotent import** | Same bundle × N imports = same result |
182
+ | 6 | **Transport independence** | Bundles are self-contained SQLite files |
183
+
184
+ ---
185
+
186
+ ## API Reference
187
+
188
+ ### `SyncEngine`
189
+
190
+ | Method | Description |
191
+ |--------|-------------|
192
+ | `initialize()` | Initialize sync tables, returns device ID |
193
+ | `enable_sync_for_table(name)` | Install triggers for a table |
194
+ | `generate_bundle(peer_id, path)` | Create bundle for peer |
195
+ | `import_bundle(path)` | Import bundle, returns `ImportResult` |
196
+ | `get_unresolved_conflicts()` | Get all pending conflicts |
197
+ | `get_vector_clock()` | Get current vector clock |
198
+ | `close()` | Close database connection |
199
+
200
+ ### `ImportResult`
201
+
202
+ | Field | Type | Description |
203
+ |-------|------|-------------|
204
+ | `bundle_id` | bytes | UUID of imported bundle |
205
+ | `source_device_id` | bytes | Device that created bundle |
206
+ | `total_operations` | int | Total ops in bundle |
207
+ | `applied_count` | int | Successfully applied |
208
+ | `conflict_count` | int | Conflicts detected |
209
+ | `duplicate_count` | int | Already had these ops |
210
+ | `skipped` | bool | True if bundle already imported |
211
+
212
+ ---
213
+
214
+ ## Project Structure
215
+
216
+ ```
217
+ sqlite_sync_core/
218
+ ├── src/sqlite_sync/
219
+ │ ├── engine.py # Main SyncEngine class
220
+ │ ├── config.py # Configuration constants
221
+ │ ├── errors.py # Exception classes
222
+ │ ├── invariants.py # Core invariant enforcement
223
+ │ ├── db/ # Database layer
224
+ │ │ ├── schema.py # Table definitions
225
+ │ │ ├── migrations.py # Initialization
226
+ │ │ ├── triggers.py # Change capture triggers
227
+ │ │ └── connection.py # Connection management
228
+ │ ├── bundle/ # Bundle operations
229
+ │ │ ├── generate.py # Bundle creation
230
+ │ │ ├── validate.py # Bundle validation
231
+ │ │ └── format.py # Bundle metadata
232
+ │ ├── import_apply/ # Import pipeline
233
+ │ │ ├── apply.py # Apply operations
234
+ │ │ ├── conflict.py # Conflict detection
235
+ │ │ ├── ordering.py # Deterministic sort
236
+ │ │ └── dedup.py # Deduplication
237
+ │ ├── log/ # Operation log
238
+ │ │ ├── operations.py # SyncOperation dataclass
239
+ │ │ └── vector_clock.py# Vector clock logic
240
+ │ └── utils/ # Utilities
241
+ │ ├── uuid7.py # UUID v7 generation
242
+ │ ├── hashing.py # SHA-256 utilities
243
+ │ └── msgpack_codec.py# Serialization
244
+ ├── tests/ # Test suite
245
+ ├── pyproject.toml # Package config
246
+ └── README.md
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Running Tests
252
+
253
+ ```bash
254
+ # Using the custom test runner (no pytest required)
255
+ python run_verification.py
256
+
257
+ # Or with pytest
258
+ pip install pytest
259
+ pytest tests/ -v
260
+ ```
261
+
262
+ ---
263
+
264
+ ## License
265
+
266
+ **Dual License Model:**
267
+
268
+ | Use Case | License | Cost |
269
+ |----------|---------|------|
270
+ | Personal projects | AGPL-3.0 | **Free** |
271
+ | Open-source projects | AGPL-3.0 | **Free** |
272
+ | Educational/Research | AGPL-3.0 | **Free** |
273
+ | Commercial / Proprietary | Commercial License | **Paid** |
274
+
275
+ > **Commercial use** (closed-source, SaaS, proprietary) requires a paid license.
276
+ >
277
+ > **Contact for licensing:**
278
+ >
279
+ > - <shivaysinghrajput@proton.me>
280
+ > - <shivaysinghrajput@outlook.com>
281
+ > - <vbs.visionquanteh@proton.me>
282
+
283
+ See [LICENSE](./LICENSE) for full terms.
284
+
285
+ ---
286
+
287
+ ## Contributing
288
+
289
+ 1. Fork the repository
290
+ 2. Create a feature branch
291
+ 3. Make your changes
292
+ 4. Run the test suite
293
+ 5. Submit a pull request
294
+
295
+ ---
296
+
297
+ **Built with ❤️ for offline-first applications**