sqlite-sync-core 0.2.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 (63) hide show
  1. sqlite_sync_core-0.2.0/LICENSE +46 -0
  2. sqlite_sync_core-0.2.0/PKG-INFO +379 -0
  3. sqlite_sync_core-0.2.0/README.md +341 -0
  4. sqlite_sync_core-0.2.0/pyproject.toml +66 -0
  5. sqlite_sync_core-0.2.0/setup.cfg +4 -0
  6. sqlite_sync_core-0.2.0/src/sqlite_sync/__init__.py +59 -0
  7. sqlite_sync_core-0.2.0/src/sqlite_sync/audit/__init__.py +19 -0
  8. sqlite_sync_core-0.2.0/src/sqlite_sync/audit/import_log.py +159 -0
  9. sqlite_sync_core-0.2.0/src/sqlite_sync/bundle/__init__.py +26 -0
  10. sqlite_sync_core-0.2.0/src/sqlite_sync/bundle/format.py +97 -0
  11. sqlite_sync_core-0.2.0/src/sqlite_sync/bundle/generate.py +200 -0
  12. sqlite_sync_core-0.2.0/src/sqlite_sync/bundle/validate.py +205 -0
  13. sqlite_sync_core-0.2.0/src/sqlite_sync/capture/__init__.py +17 -0
  14. sqlite_sync_core-0.2.0/src/sqlite_sync/capture/change_capture.py +90 -0
  15. sqlite_sync_core-0.2.0/src/sqlite_sync/config.py +48 -0
  16. sqlite_sync_core-0.2.0/src/sqlite_sync/crash_safety.py +204 -0
  17. sqlite_sync_core-0.2.0/src/sqlite_sync/db/__init__.py +38 -0
  18. sqlite_sync_core-0.2.0/src/sqlite_sync/db/connection.py +164 -0
  19. sqlite_sync_core-0.2.0/src/sqlite_sync/db/migrations.py +232 -0
  20. sqlite_sync_core-0.2.0/src/sqlite_sync/db/schema.py +183 -0
  21. sqlite_sync_core-0.2.0/src/sqlite_sync/db/triggers.py +362 -0
  22. sqlite_sync_core-0.2.0/src/sqlite_sync/engine.py +541 -0
  23. sqlite_sync_core-0.2.0/src/sqlite_sync/errors.py +176 -0
  24. sqlite_sync_core-0.2.0/src/sqlite_sync/import_apply/__init__.py +43 -0
  25. sqlite_sync_core-0.2.0/src/sqlite_sync/import_apply/apply.py +185 -0
  26. sqlite_sync_core-0.2.0/src/sqlite_sync/import_apply/conflict.py +223 -0
  27. sqlite_sync_core-0.2.0/src/sqlite_sync/import_apply/dedup.py +67 -0
  28. sqlite_sync_core-0.2.0/src/sqlite_sync/import_apply/ordering.py +70 -0
  29. sqlite_sync_core-0.2.0/src/sqlite_sync/invariants.py +193 -0
  30. sqlite_sync_core-0.2.0/src/sqlite_sync/log/__init__.py +47 -0
  31. sqlite_sync_core-0.2.0/src/sqlite_sync/log/operations.py +350 -0
  32. sqlite_sync_core-0.2.0/src/sqlite_sync/log/vector_clock.py +218 -0
  33. sqlite_sync_core-0.2.0/src/sqlite_sync/log_compaction.py +277 -0
  34. sqlite_sync_core-0.2.0/src/sqlite_sync/metrics.py +716 -0
  35. sqlite_sync_core-0.2.0/src/sqlite_sync/network/client.py +79 -0
  36. sqlite_sync_core-0.2.0/src/sqlite_sync/network/peer_discovery.py +498 -0
  37. sqlite_sync_core-0.2.0/src/sqlite_sync/network/protocol.py +22 -0
  38. sqlite_sync_core-0.2.0/src/sqlite_sync/network/server.py +43 -0
  39. sqlite_sync_core-0.2.0/src/sqlite_sync/resolution/__init__.py +215 -0
  40. sqlite_sync_core-0.2.0/src/sqlite_sync/schema_evolution.py +242 -0
  41. sqlite_sync_core-0.2.0/src/sqlite_sync/security.py +758 -0
  42. sqlite_sync_core-0.2.0/src/sqlite_sync/server/__init__.py +10 -0
  43. sqlite_sync_core-0.2.0/src/sqlite_sync/server/auth.py +770 -0
  44. sqlite_sync_core-0.2.0/src/sqlite_sync/server/http_server.py +720 -0
  45. sqlite_sync_core-0.2.0/src/sqlite_sync/sync_loop.py +206 -0
  46. sqlite_sync_core-0.2.0/src/sqlite_sync/transport/__init__.py +15 -0
  47. sqlite_sync_core-0.2.0/src/sqlite_sync/transport/base.py +85 -0
  48. sqlite_sync_core-0.2.0/src/sqlite_sync/transport/http_transport.py +151 -0
  49. sqlite_sync_core-0.2.0/src/sqlite_sync/transport/websocket_transport.py +209 -0
  50. sqlite_sync_core-0.2.0/src/sqlite_sync/utils/__init__.py +4 -0
  51. sqlite_sync_core-0.2.0/src/sqlite_sync/utils/hashing.py +114 -0
  52. sqlite_sync_core-0.2.0/src/sqlite_sync/utils/msgpack_codec.py +158 -0
  53. sqlite_sync_core-0.2.0/src/sqlite_sync/utils/uuid7.py +117 -0
  54. sqlite_sync_core-0.2.0/src/sqlite_sync_core.egg-info/PKG-INFO +379 -0
  55. sqlite_sync_core-0.2.0/src/sqlite_sync_core.egg-info/SOURCES.txt +61 -0
  56. sqlite_sync_core-0.2.0/src/sqlite_sync_core.egg-info/dependency_links.txt +1 -0
  57. sqlite_sync_core-0.2.0/src/sqlite_sync_core.egg-info/requires.txt +18 -0
  58. sqlite_sync_core-0.2.0/src/sqlite_sync_core.egg-info/top_level.txt +1 -0
  59. sqlite_sync_core-0.2.0/tests/test_conflicts.py +307 -0
  60. sqlite_sync_core-0.2.0/tests/test_determinism.py +224 -0
  61. sqlite_sync_core-0.2.0/tests/test_idempotency.py +189 -0
  62. sqlite_sync_core-0.2.0/tests/test_invariants.py +171 -0
  63. sqlite_sync_core-0.2.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,379 @@
1
+ Metadata-Version: 2.4
2
+ Name: sqlite-sync-core
3
+ Version: 0.2.0
4
+ Summary: Universal SQLite Synchronization Core - A dependency-grade, local-first, offline-first SQLite synchronization primitive
5
+ License: AGPL-3.0
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 :: 4 - Beta
11
+ Classifier: Intended Audience :: Developers
12
+ Classifier: License :: OSI Approved :: GNU Affero General Public License v3
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
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
29
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
30
+ Provides-Extra: server
31
+ Requires-Dist: flask>=3.0.0; extra == "server"
32
+ Provides-Extra: crypto
33
+ Requires-Dist: cryptography>=41.0.0; extra == "crypto"
34
+ Provides-Extra: all
35
+ Requires-Dist: flask>=3.0.0; extra == "all"
36
+ Requires-Dist: cryptography>=41.0.0; extra == "all"
37
+ Dynamic: license-file
38
+
39
+ # sqlite-sync-core
40
+
41
+ [![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)
42
+ [![License: AGPL-3.0](https://img.shields.io/badge/License-AGPL--3.0-blue.svg)](https://www.gnu.org/licenses/agpl-3.0)
43
+ [![PyPI](https://img.shields.io/pypi/v/sqlite-sync-core.svg)](https://pypi.org/project/sqlite-sync-core/)
44
+ [![Status: Production Ready](https://img.shields.io/badge/status-production--ready-brightgreen.svg)](https://github.com/shivay00001/sqlite-sync-core)
45
+
46
+ **A deterministic, infrastructure-free, local-first SQLite synchronization engine designed for offline-critical and privacy-sensitive systems.**
47
+
48
+ Built by [VisionQuantech](https://github.com/shivay00001), India 🇮🇳
49
+
50
+ ---
51
+
52
+ ## Why sqlite-sync-core?
53
+
54
+ | Feature | sqlite-sync-core | Firebase | Supabase |
55
+ |---------|------------------|----------|----------|
56
+ | **No server required** | ✅ | ❌ | ❌ |
57
+ | **Works offline** | ✅ | ⚠️ Limited | ⚠️ Limited |
58
+ | **Transport agnostic** | ✅ USB, Email, HTTP, WS | Proprietary | WebSocket only |
59
+ | **Explicit conflicts** | ✅ Never auto-overwrites | ❌ LWW | ❌ LWW |
60
+ | **Deterministic replay** | ✅ Git-like correctness | ❌ | ❌ |
61
+ | **No telemetry** | ✅ | ❌ | ❌ |
62
+ | **Self-hosted** | ✅ | ❌ | ✅ |
63
+
64
+ ---
65
+
66
+ ## Installation
67
+
68
+ ```bash
69
+ # Basic installation
70
+ pip install sqlite-sync-core
71
+
72
+ # With HTTP server support
73
+ pip install sqlite-sync-core[server]
74
+
75
+ # With encryption support
76
+ pip install sqlite-sync-core[crypto]
77
+
78
+ # Everything
79
+ pip install sqlite-sync-core[all]
80
+ ```
81
+
82
+ ---
83
+
84
+ ## Quick Start
85
+
86
+ ### Initialize a Sync-Enabled Database
87
+
88
+ ```python
89
+ from sqlite_sync import SyncEngine
90
+
91
+ engine = SyncEngine("my_app.db")
92
+ device_id = engine.initialize()
93
+
94
+ # Create your table
95
+ engine.connection.execute("""
96
+ CREATE TABLE todos (
97
+ id INTEGER PRIMARY KEY,
98
+ title TEXT NOT NULL,
99
+ done INTEGER DEFAULT 0
100
+ )
101
+ """)
102
+
103
+ # Enable sync for this table
104
+ engine.enable_sync_for_table("todos")
105
+
106
+ # All changes are now automatically captured!
107
+ engine.connection.execute("INSERT INTO todos (title) VALUES ('Buy milk')")
108
+ engine.connection.commit()
109
+ ```
110
+
111
+ ### Sync via File Transfer (USB, Email, Cloud Drive)
112
+
113
+ ```python
114
+ # Device A: Generate bundle
115
+ bundle_path = engine_a.generate_bundle(
116
+ peer_device_id=device_b_id,
117
+ output_path="sync_bundle.db"
118
+ )
119
+ # Send bundle_path via any method: USB, email, Dropbox, etc.
120
+
121
+ # Device B: Import bundle
122
+ result = engine_b.import_bundle("sync_bundle.db")
123
+ print(f"Applied: {result.applied_count}, Conflicts: {result.conflict_count}")
124
+ ```
125
+
126
+ ### Sync via HTTP (Real-time)
127
+
128
+ ```python
129
+ from sqlite_sync.transport import HTTPTransport
130
+ from sqlite_sync.sync_loop import SyncLoop, SyncLoopConfig
131
+
132
+ # Create transport
133
+ transport = HTTPTransport(
134
+ base_url="http://localhost:8080",
135
+ device_id=engine.device_id
136
+ )
137
+
138
+ # Create background sync loop
139
+ sync_loop = SyncLoop(
140
+ engine=engine,
141
+ transport=transport,
142
+ config=SyncLoopConfig(interval_seconds=30)
143
+ )
144
+
145
+ await sync_loop.start() # Syncs automatically in background
146
+ ```
147
+
148
+ ### Sync via WebSocket (Real-time Bidirectional)
149
+
150
+ ```python
151
+ from sqlite_sync.transport import WebSocketTransport
152
+
153
+ transport = WebSocketTransport(
154
+ url="ws://localhost:8765",
155
+ device_id=engine.device_id,
156
+ on_operation_received=lambda op: print(f"Received: {op.op_type}")
157
+ )
158
+
159
+ await transport.connect()
160
+ await transport.send_operations(engine.get_new_operations())
161
+ ```
162
+
163
+ ---
164
+
165
+ ## Conflict Resolution
166
+
167
+ sqlite-sync-core detects conflicts but gives YOU control over resolution.
168
+
169
+ ### Built-in Strategies
170
+
171
+ ```python
172
+ from sqlite_sync.resolution import ResolutionStrategy, get_resolver
173
+
174
+ # Last-Write-Wins (simple but may lose data)
175
+ resolver = get_resolver(ResolutionStrategy.LAST_WRITE_WINS)
176
+
177
+ # Field-level merge (preserves non-conflicting fields)
178
+ resolver = get_resolver(ResolutionStrategy.FIELD_MERGE, prefer_local=True)
179
+
180
+ # Manual (keep for user review)
181
+ resolver = get_resolver(ResolutionStrategy.MANUAL)
182
+
183
+ # Custom (your business logic)
184
+ def my_resolver(context):
185
+ # Your logic here
186
+ return ResolutionResult(resolved=True, winning_op=context.local_op, ...)
187
+
188
+ resolver = get_resolver(ResolutionStrategy.CUSTOM, resolver_fn=my_resolver)
189
+ ```
190
+
191
+ ### Handle Conflicts
192
+
193
+ ```python
194
+ conflicts = engine.get_unresolved_conflicts()
195
+ for conflict in conflicts:
196
+ print(f"Conflict on {conflict.table_name}, row {conflict.row_pk.hex()}")
197
+ print(f"Local op: {conflict.local_op_id.hex()}")
198
+ print(f"Remote op: {conflict.remote_op_id.hex()}")
199
+ ```
200
+
201
+ ---
202
+
203
+ ## Advanced Features
204
+
205
+ ### Log Compaction
206
+
207
+ ```python
208
+ from sqlite_sync.log_compaction import LogCompactor
209
+
210
+ compactor = LogCompactor(engine.connection)
211
+
212
+ # Create snapshot for new devices
213
+ snapshot = compactor.create_snapshot()
214
+
215
+ # Prune old operations
216
+ compactor.prune_acknowledged_ops(safe_op_id)
217
+
218
+ # Full compaction
219
+ result = compactor.compact_log()
220
+ print(f"Removed {result.ops_removed} operations")
221
+ ```
222
+
223
+ ### Schema Evolution
224
+
225
+ ```python
226
+ from sqlite_sync.schema_evolution import SchemaManager
227
+
228
+ schema = SchemaManager(engine.connection)
229
+
230
+ # Safe column addition (syncs across devices)
231
+ migration = schema.add_column(
232
+ table_name="todos",
233
+ column_name="priority",
234
+ column_type="INTEGER",
235
+ default_value=1
236
+ )
237
+
238
+ # Check compatibility
239
+ if schema.check_compatibility(remote_version=1):
240
+ print("Compatible!")
241
+ ```
242
+
243
+ ### Security
244
+
245
+ ```python
246
+ from sqlite_sync.security import SecurityManager
247
+
248
+ security = SecurityManager(
249
+ device_id=engine.device_id,
250
+ signing_key=my_secret_key
251
+ )
252
+
253
+ # Sign bundles
254
+ signed = security.sign_bundle(bundle_data)
255
+
256
+ # Encrypt bundles (requires cryptography package)
257
+ encrypted = security.encrypt_bundle(bundle_data, password="secret")
258
+ decrypted = security.decrypt_bundle(encrypted, password="secret")
259
+ ```
260
+
261
+ ### Crash Safety
262
+
263
+ ```python
264
+ from sqlite_sync.crash_safety import CrashSafeExecutor
265
+
266
+ executor = CrashSafeExecutor(engine.connection)
267
+
268
+ # Resume after crash
269
+ checkpoint = executor.get_incomplete_checkpoint()
270
+ if checkpoint:
271
+ print(f"Resuming from {checkpoint.last_applied_op_id.hex()}")
272
+
273
+ # Atomic operations
274
+ with executor.atomic_operation():
275
+ engine.apply_operation(op1)
276
+ engine.apply_operation(op2) # Both or neither
277
+ ```
278
+
279
+ ---
280
+
281
+ ## Run the Sync Server
282
+
283
+ ```bash
284
+ # Start HTTP sync server
285
+ python -m sqlite_sync.server.http_server
286
+
287
+ # Or in code
288
+ from sqlite_sync.server import run_server
289
+ run_server(host="0.0.0.0", port=8080)
290
+ ```
291
+
292
+ ---
293
+
294
+ ## Examples
295
+
296
+ See the `examples/` directory:
297
+
298
+ | Example | Description |
299
+ |---------|-------------|
300
+ | `basic_usage.py` | Simple CLI sync demo |
301
+ | `desktop_demo.py` | Local sync between databases |
302
+ | `http_sync_demo.py` | Client/server network sync |
303
+ | `network_sync.py` | WebSocket real-time sync |
304
+
305
+ ---
306
+
307
+ ## Core Invariants
308
+
309
+ | # | Invariant | Description |
310
+ |---|-----------|-------------|
311
+ | 1 | **Append-only** | Operations never modified |
312
+ | 2 | **Causal consistency** | Vector clocks ensure ordering |
313
+ | 3 | **Deterministic** | Same ops = same result everywhere |
314
+ | 4 | **Explicit conflicts** | Never silently overwrites |
315
+ | 5 | **Idempotent** | Import same bundle N times = same result |
316
+ | 6 | **Transport agnostic** | Bundles work anywhere |
317
+
318
+ ---
319
+
320
+ ## Architecture
321
+
322
+ ```
323
+ ┌─────────────────────────────────────────────────────────┐
324
+ │ Your Application │
325
+ ├─────────────────────────────────────────────────────────┤
326
+ │ SyncEngine │
327
+ │ ┌─────────┐ ┌─────────────┐ ┌──────────────────────┐ │
328
+ │ │ Capture │ │ Resolution │ │ Schema Evolution │ │
329
+ │ └─────────┘ └─────────────┘ └──────────────────────┘ │
330
+ │ ┌─────────┐ ┌─────────────┐ ┌──────────────────────┐ │
331
+ │ │ Bundle │ │ Compaction │ │ Security │ │
332
+ │ └─────────┘ └─────────────┘ └──────────────────────┘ │
333
+ ├─────────────────────────────────────────────────────────┤
334
+ │ Transport Layer (Pluggable) │
335
+ │ ┌──────┐ ┌───────────┐ ┌───────┐ ┌───────────────┐ │
336
+ │ │ HTTP │ │ WebSocket │ │ File │ │ Custom/P2P │ │
337
+ │ └──────┘ └───────────┘ └───────┘ └───────────────┘ │
338
+ └─────────────────────────────────────────────────────────┘
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Use Cases
344
+
345
+ - **Offline-first mobile apps** - Works without internet
346
+ - **Air-gapped systems** - Defense, government, NGOs
347
+ - **Privacy-sensitive applications** - Medical, legal, finance
348
+ - **Field operations** - Works with USB/SD card transfer
349
+ - **Embedded systems** - IoT with intermittent connectivity
350
+ - **Multi-device personal apps** - Notes, todos, journals
351
+
352
+ ---
353
+
354
+ ## License
355
+
356
+ **Dual License:**
357
+
358
+ | Use Case | License | Cost |
359
+ |----------|---------|------|
360
+ | Personal/Open Source | AGPL-3.0 | **Free** |
361
+ | Commercial/Proprietary | Commercial | **Paid** |
362
+
363
+ Contact for commercial licensing:
364
+
365
+ - <shivaysinghrajput@proton.me>
366
+ - <shivaysinghrajput@outlook.com>
367
+
368
+ ---
369
+
370
+ ## Contributing
371
+
372
+ 1. Fork the repository
373
+ 2. Create a feature branch
374
+ 3. Run tests: `pytest tests/ -v`
375
+ 4. Submit a pull request
376
+
377
+ ---
378
+
379
+ **Built with ❤️ for offline-first applications**