tetherdb 0.1.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 (194) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/bin/tetherdb.js +7 -0
  4. package/dist/cli/args.d.cts +20 -0
  5. package/dist/cli/args.d.ts +20 -0
  6. package/dist/cli/args.d.ts.map +1 -0
  7. package/dist/cli/backend.d.cts +15 -0
  8. package/dist/cli/backend.d.ts +15 -0
  9. package/dist/cli/backend.d.ts.map +1 -0
  10. package/dist/cli/cli.d.cts +8 -0
  11. package/dist/cli/cli.d.ts +8 -0
  12. package/dist/cli/cli.d.ts.map +1 -0
  13. package/dist/cli/commands/apps.d.cts +9 -0
  14. package/dist/cli/commands/apps.d.ts +9 -0
  15. package/dist/cli/commands/apps.d.ts.map +1 -0
  16. package/dist/cli/commands/help.d.cts +5 -0
  17. package/dist/cli/commands/help.d.ts +5 -0
  18. package/dist/cli/commands/help.d.ts.map +1 -0
  19. package/dist/cli/commands/index.d.cts +8 -0
  20. package/dist/cli/commands/index.d.ts +8 -0
  21. package/dist/cli/commands/index.d.ts.map +1 -0
  22. package/dist/cli/commands/maintenance.d.cts +9 -0
  23. package/dist/cli/commands/maintenance.d.ts +9 -0
  24. package/dist/cli/commands/maintenance.d.ts.map +1 -0
  25. package/dist/cli/commands/serve.d.cts +14 -0
  26. package/dist/cli/commands/serve.d.ts +14 -0
  27. package/dist/cli/commands/serve.d.ts.map +1 -0
  28. package/dist/cli/commands/status.d.cts +9 -0
  29. package/dist/cli/commands/status.d.ts +9 -0
  30. package/dist/cli/commands/status.d.ts.map +1 -0
  31. package/dist/cli/commands/tables.d.cts +9 -0
  32. package/dist/cli/commands/tables.d.ts +9 -0
  33. package/dist/cli/commands/tables.d.ts.map +1 -0
  34. package/dist/cli/commands/users.d.cts +9 -0
  35. package/dist/cli/commands/users.d.ts +9 -0
  36. package/dist/cli/commands/users.d.ts.map +1 -0
  37. package/dist/cli/index.cjs +3999 -0
  38. package/dist/cli/index.cjs.map +1 -0
  39. package/dist/cli/index.d.cts +7 -0
  40. package/dist/cli/index.d.ts +7 -0
  41. package/dist/cli/index.d.ts.map +1 -0
  42. package/dist/cli/index.js +3958 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/client/auth.d.cts +155 -0
  45. package/dist/client/auth.d.ts +155 -0
  46. package/dist/client/auth.d.ts.map +1 -0
  47. package/dist/client/client.d.cts +122 -0
  48. package/dist/client/client.d.ts +122 -0
  49. package/dist/client/client.d.ts.map +1 -0
  50. package/dist/client/errors.d.cts +39 -0
  51. package/dist/client/errors.d.ts +39 -0
  52. package/dist/client/errors.d.ts.map +1 -0
  53. package/dist/client/index.cjs +1742 -0
  54. package/dist/client/index.cjs.map +1 -0
  55. package/dist/client/index.d.cts +12 -0
  56. package/dist/client/index.d.ts +12 -0
  57. package/dist/client/index.d.ts.map +1 -0
  58. package/dist/client/index.js +1707 -0
  59. package/dist/client/index.js.map +1 -0
  60. package/dist/client/shared/event.d.cts +29 -0
  61. package/dist/client/shared/event.d.ts +29 -0
  62. package/dist/client/shared/event.d.ts.map +1 -0
  63. package/dist/client/shared/id.d.cts +5 -0
  64. package/dist/client/shared/id.d.ts +5 -0
  65. package/dist/client/shared/id.d.ts.map +1 -0
  66. package/dist/client/storage.d.cts +183 -0
  67. package/dist/client/storage.d.ts +183 -0
  68. package/dist/client/storage.d.ts.map +1 -0
  69. package/dist/client/sync.d.cts +126 -0
  70. package/dist/client/sync.d.ts +126 -0
  71. package/dist/client/sync.d.ts.map +1 -0
  72. package/dist/client/table.d.cts +146 -0
  73. package/dist/client/table.d.ts +146 -0
  74. package/dist/client/table.d.ts.map +1 -0
  75. package/dist/index.cjs +1742 -0
  76. package/dist/index.cjs.map +1 -0
  77. package/dist/index.d.cts +7 -0
  78. package/dist/index.d.ts +7 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +1707 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/server/crypto.d.cts +55 -0
  83. package/dist/server/crypto.d.ts +55 -0
  84. package/dist/server/crypto.d.ts.map +1 -0
  85. package/dist/server/errors.d.cts +39 -0
  86. package/dist/server/errors.d.ts +39 -0
  87. package/dist/server/errors.d.ts.map +1 -0
  88. package/dist/server/index.cjs +3621 -0
  89. package/dist/server/index.cjs.map +1 -0
  90. package/dist/server/index.d.cts +10 -0
  91. package/dist/server/index.d.ts +10 -0
  92. package/dist/server/index.d.ts.map +1 -0
  93. package/dist/server/index.js +3569 -0
  94. package/dist/server/index.js.map +1 -0
  95. package/dist/server/lock.d.cts +56 -0
  96. package/dist/server/lock.d.ts +56 -0
  97. package/dist/server/lock.d.ts.map +1 -0
  98. package/dist/server/rate-limiter.d.cts +81 -0
  99. package/dist/server/rate-limiter.d.ts +81 -0
  100. package/dist/server/rate-limiter.d.ts.map +1 -0
  101. package/dist/server/server.d.cts +206 -0
  102. package/dist/server/server.d.ts +206 -0
  103. package/dist/server/server.d.ts.map +1 -0
  104. package/dist/server/storage/app.d.cts +70 -0
  105. package/dist/server/storage/app.d.ts +70 -0
  106. package/dist/server/storage/app.d.ts.map +1 -0
  107. package/dist/server/storage/base/app.d.cts +42 -0
  108. package/dist/server/storage/base/app.d.ts +42 -0
  109. package/dist/server/storage/base/app.d.ts.map +1 -0
  110. package/dist/server/storage/base/index.d.cts +5 -0
  111. package/dist/server/storage/base/index.d.ts +5 -0
  112. package/dist/server/storage/base/index.d.ts.map +1 -0
  113. package/dist/server/storage/base/storage.d.cts +40 -0
  114. package/dist/server/storage/base/storage.d.ts +40 -0
  115. package/dist/server/storage/base/storage.d.ts.map +1 -0
  116. package/dist/server/storage/base/table.d.cts +32 -0
  117. package/dist/server/storage/base/table.d.ts +32 -0
  118. package/dist/server/storage/base/table.d.ts.map +1 -0
  119. package/dist/server/storage/base/user.d.cts +31 -0
  120. package/dist/server/storage/base/user.d.ts +31 -0
  121. package/dist/server/storage/base/user.d.ts.map +1 -0
  122. package/dist/server/storage/file/app.d.cts +50 -0
  123. package/dist/server/storage/file/app.d.ts +50 -0
  124. package/dist/server/storage/file/app.d.ts.map +1 -0
  125. package/dist/server/storage/file/index.d.cts +5 -0
  126. package/dist/server/storage/file/index.d.ts +5 -0
  127. package/dist/server/storage/file/index.d.ts.map +1 -0
  128. package/dist/server/storage/file/storage.d.cts +67 -0
  129. package/dist/server/storage/file/storage.d.ts +67 -0
  130. package/dist/server/storage/file/storage.d.ts.map +1 -0
  131. package/dist/server/storage/file/table.d.cts +14 -0
  132. package/dist/server/storage/file/table.d.ts +14 -0
  133. package/dist/server/storage/file/table.d.ts.map +1 -0
  134. package/dist/server/storage/file/user.d.cts +14 -0
  135. package/dist/server/storage/file/user.d.ts +14 -0
  136. package/dist/server/storage/file/user.d.ts.map +1 -0
  137. package/dist/server/storage/index.d.cts +14 -0
  138. package/dist/server/storage/index.d.ts +14 -0
  139. package/dist/server/storage/index.d.ts.map +1 -0
  140. package/dist/server/storage/memory/app.d.cts +29 -0
  141. package/dist/server/storage/memory/app.d.ts +29 -0
  142. package/dist/server/storage/memory/app.d.ts.map +1 -0
  143. package/dist/server/storage/memory/index.d.cts +5 -0
  144. package/dist/server/storage/memory/index.d.ts +5 -0
  145. package/dist/server/storage/memory/index.d.ts.map +1 -0
  146. package/dist/server/storage/memory/storage.d.cts +47 -0
  147. package/dist/server/storage/memory/storage.d.ts +47 -0
  148. package/dist/server/storage/memory/storage.d.ts.map +1 -0
  149. package/dist/server/storage/memory/table.d.cts +17 -0
  150. package/dist/server/storage/memory/table.d.ts +17 -0
  151. package/dist/server/storage/memory/table.d.ts.map +1 -0
  152. package/dist/server/storage/memory/user.d.cts +21 -0
  153. package/dist/server/storage/memory/user.d.ts +21 -0
  154. package/dist/server/storage/memory/user.d.ts.map +1 -0
  155. package/dist/server/storage/sqlite/app.d.cts +31 -0
  156. package/dist/server/storage/sqlite/app.d.ts +31 -0
  157. package/dist/server/storage/sqlite/app.d.ts.map +1 -0
  158. package/dist/server/storage/sqlite/index.d.cts +5 -0
  159. package/dist/server/storage/sqlite/index.d.ts +5 -0
  160. package/dist/server/storage/sqlite/index.d.ts.map +1 -0
  161. package/dist/server/storage/sqlite/storage.d.cts +92 -0
  162. package/dist/server/storage/sqlite/storage.d.ts +92 -0
  163. package/dist/server/storage/sqlite/storage.d.ts.map +1 -0
  164. package/dist/server/storage/sqlite/table.d.cts +15 -0
  165. package/dist/server/storage/sqlite/table.d.ts +15 -0
  166. package/dist/server/storage/sqlite/table.d.ts.map +1 -0
  167. package/dist/server/storage/sqlite/user.d.cts +14 -0
  168. package/dist/server/storage/sqlite/user.d.ts +14 -0
  169. package/dist/server/storage/sqlite/user.d.ts.map +1 -0
  170. package/dist/server/storage/storage.d.cts +152 -0
  171. package/dist/server/storage/storage.d.ts +152 -0
  172. package/dist/server/storage/storage.d.ts.map +1 -0
  173. package/dist/server/storage/table.d.cts +45 -0
  174. package/dist/server/storage/table.d.ts +45 -0
  175. package/dist/server/storage/table.d.ts.map +1 -0
  176. package/dist/server/storage/user.d.cts +45 -0
  177. package/dist/server/storage/user.d.ts +45 -0
  178. package/dist/server/storage/user.d.ts.map +1 -0
  179. package/dist/server/sync.d.cts +67 -0
  180. package/dist/server/sync.d.ts +67 -0
  181. package/dist/server/sync.d.ts.map +1 -0
  182. package/dist/server/validate.d.cts +113 -0
  183. package/dist/server/validate.d.ts +113 -0
  184. package/dist/server/validate.d.ts.map +1 -0
  185. package/dist/shared/clock.d.cts +22 -0
  186. package/dist/shared/clock.d.ts +22 -0
  187. package/dist/shared/clock.d.ts.map +1 -0
  188. package/dist/shared/path.d.cts +12 -0
  189. package/dist/shared/path.d.ts +12 -0
  190. package/dist/shared/path.d.ts.map +1 -0
  191. package/dist/shared/types.d.cts +234 -0
  192. package/dist/shared/types.d.ts +234 -0
  193. package/dist/shared/types.d.ts.map +1 -0
  194. package/package.json +133 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Lukas Renggli
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,277 @@
1
+ # ⚡ TetherDB
2
+
3
+ **Lightweight, local-first TypeScript database with reactive IndexedDB storage and real-time two-way WebSocket sync.**
4
+
5
+ [![NPM Version](https://img.shields.io/npm/v/tetherdb.svg?style=flat-square&color=blue)](https://www.npmjs.com/package/tetherdb)
6
+ [![Build Status](https://img.shields.io/github/actions/workflow/status/renggli/typescript-tetherdb/ci.yml?branch=main&style=flat-square)](https://github.com/renggli/typescript-tetherdb/actions)
7
+ [![Code Coverage](https://img.shields.io/codecov/c/github/renggli/typescript-tetherdb?style=flat-square)](https://codecov.io/gh/renggli/typescript-tetherdb)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
9
+ [![License: MIT](https://img.shields.io/badge/License-MIT-green?style=flat-square)](LICENSE)
10
+
11
+ *Open-source under the [MIT License](LICENSE).*
12
+
13
+ [Features](#features) •
14
+ [Installation](#installation) •
15
+ [Quick Start](#quick-start) •
16
+ [Framework Integration](#framework-integration) •
17
+ [CLI & Server](#cli--server-administration) •
18
+ [Production Deployment](#production-deployment) •
19
+ [Example App](#example-application)
20
+
21
+ ## Features
22
+
23
+ - **📱 Offline-First & Local-First**: Mutations apply immediately to browser IndexedDB with zero latency and queue in an atomic outbox for background synchronization.
24
+ - **🔄 Real-Time Two-Way Sync**: Fast, bi-directional WebSocket sync with delta diff catch-up on reconnect, adaptive full snapshots, and automatic live broadcast to active sessions.
25
+ - **⚖️ Deterministic Conflict Resolution**: Last-Write-Wins (LWW) conflict handling powered by monotonically increasing logical clocks and deterministic tie-breaking.
26
+ - **🏢 Multi-Tenant & Multi-App**: Host multiple independent web applications on a single domain and server instance. Data and WebSocket streams are strictly isolated by `appId` and user account.
27
+ - **🚀 Seamless Offline-to-Cloud Onboarding**: Start using the local database immediately without an account; attach live cloud sync on demand with a single `client.login()` or `client.register()` call.
28
+ - **🗄️ Pluggable Server Storage**: Built-in persistence engines for SQLite (`SqliteStorage`), sharded filesystem directories (`FileStorage`), and ephemeral testing (`MemoryStorage`).
29
+ - **🔐 Built-in Authentication**: Password hashing using scrypt with salt and HMAC-signed session tokens with automatic session persistence and recovery.
30
+ - **⚡ Batch-by-Default Performance**: High-throughput atomic mutations (`putAll`, `deleteAll`, `getAll`) and coalesced WebSocket frame transmission.
31
+
32
+ ## Installation
33
+
34
+ Install from npm:
35
+
36
+ ```bash
37
+ npm install tetherdb
38
+ ```
39
+
40
+ Or install directly from GitHub:
41
+
42
+ ```bash
43
+ npm install github:renggli/typescript-tetherdb
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ### 1. Launch a Server (Zero-Config)
49
+
50
+ You can launch a standalone TetherDB server in seconds using the CLI:
51
+
52
+ ```bash
53
+ # Start server with persistent SQLite storage on port 8080
54
+ npx tetherdb --sqlite=./data --port=8080
55
+ ```
56
+
57
+ Or embed it programmatically in your Node.js backend:
58
+
59
+ ```typescript
60
+ import { SqliteStorage, startServer } from 'tetherdb/server';
61
+
62
+ const running = await startServer({
63
+ port: 8080,
64
+ storage: new SqliteStorage({ baseDir: './data' }),
65
+ });
66
+
67
+ console.log(`TetherDB server listening on http://${running.host}:${running.port}`);
68
+ ```
69
+
70
+ ### 2. Client Setup: Instant Local-First Storage
71
+
72
+ TetherDB works out of the box in the browser. Writes are instant and persist offline:
73
+
74
+ ```typescript
75
+ import { TetherClient } from 'tetherdb/client';
76
+
77
+ interface Todo {
78
+ title: string;
79
+ completed: boolean;
80
+ }
81
+
82
+ // 1. Initialize client with server endpoint
83
+ const client = new TetherClient('my-todo-app', {
84
+ url: 'http://localhost:8080',
85
+ });
86
+
87
+ // 2. Obtain a typed table
88
+ const todos = client.table<Todo>('todos');
89
+
90
+ // 3. React to local and remote data changes
91
+ const unsubscribe = todos.onChange.register((events) => {
92
+ for (const { op, id, data, isRemote } of events) {
93
+ console.log(`Table event [${op}] on ${id} (remote: ${isRemote}):`, data);
94
+ }
95
+ });
96
+
97
+ // 4. Instant local writes (offline-ready)
98
+ await todos.put('task-1', {
99
+ title: 'Try TetherDB',
100
+ completed: false,
101
+ });
102
+
103
+ // Batch operations execute in a single atomic transaction
104
+ await todos.putAll([
105
+ { id: 'task-2', data: { title: 'Add offline support', completed: true } },
106
+ { id: 'task-3', data: { title: 'Sync with cloud', completed: false } },
107
+ ]);
108
+
109
+ // Read data
110
+ const item = await todos.get('task-1');
111
+ const allItems = await todos.getAll();
112
+ ```
113
+
114
+ ### 3. Attach Live Cloud Sync & Authentication
115
+
116
+ Connect your local data to the cloud whenever the user registers or signs in:
117
+
118
+ ```typescript
119
+ // Register or login to initiate real-time synchronization
120
+ await client.register({
121
+ username: 'alice',
122
+ password: 'secure-password',
123
+ remember: true, // Persists session token across browser reloads
124
+ });
125
+
126
+ // Monitor live connection and sync status
127
+ client.onSyncStatusChange.register((status) => {
128
+ // 'disconnected' | 'connecting' | 'connected' | 'syncing' | 'synced'
129
+ console.log('Sync status:', status);
130
+ });
131
+ ```
132
+
133
+ ## Framework Integration
134
+
135
+ ### React Hook Example
136
+
137
+ Bind any TetherDB table to component state with automatic real-time updates:
138
+
139
+ ```typescript
140
+ import { useEffect, useState } from 'react';
141
+ import type { Table } from 'tetherdb/client';
142
+
143
+ export function useTable<T>(table: Table<T>): T[] {
144
+ const [items, setItems] = useState<T[]>([]);
145
+
146
+ useEffect(() => {
147
+ // 1. Initial local load
148
+ table.getAll().then(setItems);
149
+
150
+ // 2. Subscribe to live changes (local writes & remote sync broadcasts)
151
+ const unsubscribe = table.onChange.register(() => {
152
+ table.getAll().then(setItems);
153
+ });
154
+
155
+ return unsubscribe;
156
+ }, [table]);
157
+
158
+ return items;
159
+ }
160
+ ```
161
+
162
+ ## CLI & Server Administration
163
+
164
+ TetherDB includes a full CLI suite for running servers and managing databases:
165
+
166
+ ```bash
167
+ # Start standalone server with SQLite persistence
168
+ npx tetherdb --sqlite=./data --port=8080
169
+
170
+ # Start with filesystem storage
171
+ npx tetherdb --file=./data --port=8080
172
+
173
+ # Manage apps, tables, and users
174
+ npx tetherdb apps list --sqlite=./data
175
+ npx tetherdb apps add my-todo-app --sqlite=./data
176
+ npx tetherdb tables add my-todo-app todos --sqlite=./data
177
+ npx tetherdb users add alice secret --sqlite=./data
178
+
179
+ # Run database maintenance & compaction
180
+ npx tetherdb maintenance checkpoint --sqlite=./data
181
+ npx tetherdb maintenance vacuum --sqlite=./data
182
+ npx tetherdb maintenance prune my-todo-app 1000 --sqlite=./data
183
+ ```
184
+
185
+ ## HTTP & WebSocket Endpoints
186
+
187
+ | Method | Endpoint | Description | Authentication |
188
+ | :--- | :--- | :--- | :--- |
189
+ | `GET` | `/health` | Server uptime and health probe | Public |
190
+ | `GET` | `/ready` | Storage backend readiness check | Public |
191
+ | `GET` | `/metrics` | Connected clients and application metrics | Public |
192
+ | `POST` | `/auth/register` | Create a new user account | Public |
193
+ | `POST` | `/auth/login` | Log in and receive a signed session token | Public |
194
+ | `WS` | `/sync` | Bi-directional WebSocket synchronization stream | Token handshake |
195
+
196
+ ## Production Deployment
197
+
198
+ ### Storage Engines
199
+
200
+ TetherDB supports pluggable server storage backends:
201
+
202
+ | Engine | CLI Flag | Pros | Cons |
203
+ | :--- | :--- | :--- | :--- |
204
+ | **SQLite** (`SqliteStorage`) | `--sqlite=<dir>` | • High throughput & ACID safety<br>• WAL mode concurrency<br>• Built-in compaction (`vacuum`, `prune`) | • Single-node filesystem binding |
205
+ | **Filesystem** (`FileStorage`) | `--file=<dir>` | • Human-readable JSON structure<br>• Zero binary dependencies<br>• Direct inspection & simple backup | • I/O overhead on large tables<br>• Lower concurrent write throughput |
206
+ | **In-Memory** (`MemoryStorage`) | `--memory` | • Zero disk I/O, ultra-fast<br>• Zero configuration | • Ephemeral (data lost on restart) |
207
+
208
+ #### When to Use Which
209
+
210
+ - **SQLite (`--sqlite`) — Best for Production (Recommended)**: Ideal for multi-user and high-concurrency apps requiring fast transactional persistence and operational maintenance tools (`vacuum`, `checkpoint`, `prune`).
211
+ - **Filesystem (`--file`) — Best for Lightweight / Embedded**: Ideal for low-traffic apps, resource-constrained environments, or setups where direct inspection and editing of JSON files is desired.
212
+ - **In-Memory (`--memory`) — Best for Testing & CI/CD**: Ideal for automated unit/integration test suites, ephemeral pipelines, and rapid local prototyping.
213
+
214
+ ### Reverse Proxy & SSL Termination
215
+
216
+ For production, run TetherDB behind a reverse proxy (such as Caddy or Nginx) to handle SSL/TLS and proxy WebSocket connections:
217
+
218
+ #### Caddy
219
+
220
+ ```caddy
221
+ api.example.com {
222
+ reverse_proxy localhost:8080
223
+ }
224
+ ```
225
+
226
+ #### Nginx
227
+
228
+ ```nginx
229
+ server {
230
+ listen 443 ssl http2;
231
+ server_name api.example.com;
232
+
233
+ ssl_certificate /path/to/cert.pem;
234
+ ssl_certificate_key /path/to/key.pem;
235
+
236
+ location / {
237
+ proxy_pass http://127.0.0.1:8080;
238
+ proxy_http_version 1.1;
239
+ proxy_set_header Upgrade $http_upgrade;
240
+ proxy_set_header Connection "upgrade";
241
+ proxy_set_header Host $host;
242
+ proxy_buffering off;
243
+ }
244
+ }
245
+ ```
246
+
247
+ ## Example Application
248
+
249
+ Check out the included real-time multi-client collaborative Todo app in [`examples/todo/`](examples/todo):
250
+
251
+ ```bash
252
+ # Build packages and start example app
253
+ npm run build
254
+ npm run example:todo
255
+ ```
256
+
257
+ Open `http://localhost:3000` in multiple browser windows or simulate offline mode in DevTools to see seamless local-first persistence and instant background synchronization.
258
+
259
+ ## Development & Testing
260
+
261
+ ```bash
262
+ # Format code & lint fix
263
+ npm run format
264
+ npm run lint
265
+
266
+ # Type check
267
+ npm run typecheck
268
+
269
+ # Run unit and integration tests
270
+ npm test
271
+
272
+ # Run tests with coverage
273
+ npm run test:coverage
274
+
275
+ # Build bundle & type definitions
276
+ npm run build
277
+ ```
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { runCli } from '../dist/cli/index.js';
3
+
4
+ runCli().catch((err) => {
5
+ console.error('Failed to start TetherDB CLI:', err);
6
+ process.exit(1);
7
+ });
@@ -0,0 +1,20 @@
1
+ import type { BackendType } from './backend.cjs';
2
+ /**
3
+ * Parsed CLI arguments and configuration options.
4
+ */
5
+ export interface ParsedCliArgs {
6
+ command: string;
7
+ positionalArgs: string[];
8
+ port: number;
9
+ host: string;
10
+ backend: BackendType;
11
+ dir: string;
12
+ }
13
+ /**
14
+ * Parses raw command-line arguments into structured options.
15
+ *
16
+ * @param args - Command line arguments.
17
+ * @returns Parsed CLI configuration.
18
+ */
19
+ export declare function parseCliArgs(args: string[]): ParsedCliArgs;
20
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1,20 @@
1
+ import type { BackendType } from './backend.js';
2
+ /**
3
+ * Parsed CLI arguments and configuration options.
4
+ */
5
+ export interface ParsedCliArgs {
6
+ command: string;
7
+ positionalArgs: string[];
8
+ port: number;
9
+ host: string;
10
+ backend: BackendType;
11
+ dir: string;
12
+ }
13
+ /**
14
+ * Parses raw command-line arguments into structured options.
15
+ *
16
+ * @param args - Command line arguments.
17
+ * @returns Parsed CLI configuration.
18
+ */
19
+ export declare function parseCliArgs(args: string[]): ParsedCliArgs;
20
+ //# sourceMappingURL=args.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"args.d.ts","sourceRoot":"","sources":["../../src/cli/args.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,aAAa,CAsC1D"}
@@ -0,0 +1,15 @@
1
+ import { type Storage, type StorageOptions } from '../server/index.cjs';
2
+ /**
3
+ * Backend persistence type for TetherDB server.
4
+ */
5
+ export type BackendType = 'memory' | 'file' | 'sqlite';
6
+ /**
7
+ * Instantiates the matching Storage implementation for a given backend type and directory.
8
+ *
9
+ * @param backend - Target backend ('memory', 'file', or 'sqlite'). Defaults to 'memory'.
10
+ * @param baseDir - Directory path for file and sqlite backends. Defaults to '.data'.
11
+ * @param options - Optional storage configuration and limits.
12
+ * @returns Instantiated `Storage` engine.
13
+ */
14
+ export declare function createBackend(backend?: BackendType, baseDir?: string, options?: StorageOptions): Storage;
15
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1,15 @@
1
+ import { type Storage, type StorageOptions } from '../server/index.js';
2
+ /**
3
+ * Backend persistence type for TetherDB server.
4
+ */
5
+ export type BackendType = 'memory' | 'file' | 'sqlite';
6
+ /**
7
+ * Instantiates the matching Storage implementation for a given backend type and directory.
8
+ *
9
+ * @param backend - Target backend ('memory', 'file', or 'sqlite'). Defaults to 'memory'.
10
+ * @param baseDir - Directory path for file and sqlite backends. Defaults to '.data'.
11
+ * @param options - Optional storage configuration and limits.
12
+ * @returns Instantiated `Storage` engine.
13
+ */
14
+ export declare function createBackend(backend?: BackendType, baseDir?: string, options?: StorageOptions): Storage;
15
+ //# sourceMappingURL=backend.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../../src/cli/backend.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,OAAO,EACZ,KAAK,cAAc,EAGpB,MAAM,oBAAoB,CAAC;AAE5B;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,OAAO,GAAE,WAAsB,EAC/B,OAAO,SAAU,EACjB,OAAO,CAAC,EAAE,cAAc,GACvB,OAAO,CAeT"}
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standard command line interface for TetherDB.
4
+ *
5
+ * @param args - CLI arguments (defaults to process.argv.slice(2)).
6
+ */
7
+ export declare function runCli(args?: string[]): Promise<void>;
8
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Standard command line interface for TetherDB.
4
+ *
5
+ * @param args - CLI arguments (defaults to process.argv.slice(2)).
6
+ */
7
+ export declare function runCli(args?: string[]): Promise<void>;
8
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli/cli.ts"],"names":[],"mappings":";AAoBA;;;;GAIG;AACH,wBAAsB,MAAM,CAC1B,IAAI,GAAE,MAAM,EAA0B,GACrC,OAAO,CAAC,IAAI,CAAC,CAyCf"}
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.cjs';
2
+ /**
3
+ * Handles the 'apps' command family (list, add, rm).
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param args - Positional arguments: `[command, action, appId]`.
7
+ */
8
+ export declare function handleAppsCommand(storage: Storage, [, action, appId]: string[]): Promise<void>;
9
+ //# sourceMappingURL=apps.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.js';
2
+ /**
3
+ * Handles the 'apps' command family (list, add, rm).
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param args - Positional arguments: `[command, action, appId]`.
7
+ */
8
+ export declare function handleAppsCommand(storage: Storage, [, action, appId]: string[]): Promise<void>;
9
+ //# sourceMappingURL=apps.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apps.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/apps.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGb,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,OAAO,EAAE,OAAO,EAChB,CAAC,EAAE,MAAe,EAAE,KAAK,CAAC,EAAE,MAAM,EAAE,GACnC,OAAO,CAAC,IAAI,CAAC,CAwCf"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Displays command-line interface usage instructions.
3
+ */
4
+ export declare function printHelp(): void;
5
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Displays command-line interface usage instructions.
3
+ */
4
+ export declare function printHelp(): void;
5
+ //# sourceMappingURL=help.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,SAAS,IAAI,IAAI,CAkChC"}
@@ -0,0 +1,8 @@
1
+ export { handleAppsCommand } from './apps.cjs';
2
+ export { printHelp } from './help.cjs';
3
+ export { handleMaintenanceCommand } from './maintenance.cjs';
4
+ export { handleServeCommand } from './serve.cjs';
5
+ export { handleStatusCommand } from './status.cjs';
6
+ export { handleTablesCommand } from './tables.cjs';
7
+ export { handleUsersCommand } from './users.cjs';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,8 @@
1
+ export { handleAppsCommand } from './apps.js';
2
+ export { printHelp } from './help.js';
3
+ export { handleMaintenanceCommand } from './maintenance.js';
4
+ export { handleServeCommand } from './serve.js';
5
+ export { handleStatusCommand } from './status.js';
6
+ export { handleTablesCommand } from './tables.js';
7
+ export { handleUsersCommand } from './users.js';
8
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,wBAAwB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.cjs';
2
+ /**
3
+ * Handles the 'maintenance' command to execute maintenance routines.
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param positionalArgs - Positional CLI arguments (e.g. ['maintenance', 'checkpoint', 'my-app']).
7
+ */
8
+ export declare function handleMaintenanceCommand(storage: Storage, positionalArgs: string[]): Promise<void>;
9
+ //# sourceMappingURL=maintenance.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.js';
2
+ /**
3
+ * Handles the 'maintenance' command to execute maintenance routines.
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param positionalArgs - Positional CLI arguments (e.g. ['maintenance', 'checkpoint', 'my-app']).
7
+ */
8
+ export declare function handleMaintenanceCommand(storage: Storage, positionalArgs: string[]): Promise<void>;
9
+ //# sourceMappingURL=maintenance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenance.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/maintenance.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGb,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CAsCf"}
@@ -0,0 +1,14 @@
1
+ import { type RunningServer, type Storage } from '../../server/index.cjs';
2
+ import type { BackendType } from '../backend.cjs';
3
+ /**
4
+ * Handles the 'serve' command to launch the HTTP and WebSocket synchronization server.
5
+ *
6
+ * @param storage - Instantiated Storage engine.
7
+ * @param backend - Storage backend type ('memory', 'file', or 'sqlite').
8
+ * @param dir - Data directory for file-based backends.
9
+ * @param port - HTTP port to bind.
10
+ * @param host - Network interface to bind.
11
+ * @returns Handle to the running server.
12
+ */
13
+ export declare function handleServeCommand(storage: Storage, backend: BackendType, dir: string, port: number, host: string): Promise<RunningServer>;
14
+ //# sourceMappingURL=serve.d.ts.map
@@ -0,0 +1,14 @@
1
+ import { type RunningServer, type Storage } from '../../server/index.js';
2
+ import type { BackendType } from '../backend.js';
3
+ /**
4
+ * Handles the 'serve' command to launch the HTTP and WebSocket synchronization server.
5
+ *
6
+ * @param storage - Instantiated Storage engine.
7
+ * @param backend - Storage backend type ('memory', 'file', or 'sqlite').
8
+ * @param dir - Data directory for file-based backends.
9
+ * @param port - HTTP port to bind.
10
+ * @param host - Network interface to bind.
11
+ * @returns Handle to the running server.
12
+ */
13
+ export declare function handleServeCommand(storage: Storage, backend: BackendType, dir: string, port: number, host: string): Promise<RunningServer>;
14
+ //# sourceMappingURL=serve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/serve.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,OAAO,EAEb,MAAM,uBAAuB,CAAC;AAC/B,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,WAAW,EACpB,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,aAAa,CAAC,CA8BxB"}
@@ -0,0 +1,9 @@
1
+ import type { Storage } from '../../server/index.cjs';
2
+ /**
3
+ * Handles the 'status' command to display storage backend statistics.
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param positionalArgs - Positional CLI arguments (e.g. ['status', 'my-app']).
7
+ */
8
+ export declare function handleStatusCommand(storage: Storage, positionalArgs: string[]): Promise<void>;
9
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1,9 @@
1
+ import type { Storage } from '../../server/index.js';
2
+ /**
3
+ * Handles the 'status' command to display storage backend statistics.
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param positionalArgs - Positional CLI arguments (e.g. ['status', 'my-app']).
7
+ */
8
+ export declare function handleStatusCommand(storage: Storage, positionalArgs: string[]): Promise<void>;
9
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAGrD;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,cAAc,EAAE,MAAM,EAAE,GACvB,OAAO,CAAC,IAAI,CAAC,CAiCf"}
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.cjs';
2
+ /**
3
+ * Handles the 'tables' command family (list, add, rm, <appid>).
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param args - Positional arguments: `[command, action, appId, ...tableNames]`.
7
+ */
8
+ export declare function handleTablesCommand(storage: Storage, args: string[]): Promise<void>;
9
+ //# sourceMappingURL=tables.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.js';
2
+ /**
3
+ * Handles the 'tables' command family (list, add, rm, <appid>).
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param args - Positional arguments: `[command, action, appId, ...tableNames]`.
7
+ */
8
+ export declare function handleTablesCommand(storage: Storage, args: string[]): Promise<void>;
9
+ //# sourceMappingURL=tables.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tables.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/tables.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGb,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,MAAM,EAAE,GACb,OAAO,CAAC,IAAI,CAAC,CAuEf"}
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.cjs';
2
+ /**
3
+ * Handles the 'users' command family (list, add, rm).
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param args - Positional arguments: `[command, action, arg1, arg2]`.
7
+ */
8
+ export declare function handleUsersCommand(storage: Storage, [, action, arg1, arg2]: string[]): Promise<void>;
9
+ //# sourceMappingURL=users.d.ts.map
@@ -0,0 +1,9 @@
1
+ import { type Storage } from '../../server/index.js';
2
+ /**
3
+ * Handles the 'users' command family (list, add, rm).
4
+ *
5
+ * @param storage - Instantiated Storage engine.
6
+ * @param args - Positional arguments: `[command, action, arg1, arg2]`.
7
+ */
8
+ export declare function handleUsersCommand(storage: Storage, [, action, arg1, arg2]: string[]): Promise<void>;
9
+ //# sourceMappingURL=users.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"users.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/users.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,OAAO,EAGb,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,OAAO,EAChB,CAAC,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,GACxC,OAAO,CAAC,IAAI,CAAC,CA0Cf"}