@semics-tech/mongolite 1.2.0 → 1.4.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 (99) hide show
  1. package/README.md +91 -20
  2. package/dist/bin/mongolite-debug.d.ts +6 -1
  3. package/dist/bin/mongolite-debug.js +6 -113
  4. package/dist/bin/mongolite-debug.js.map +1 -1
  5. package/dist/bin/mongolite.d.ts +13 -0
  6. package/dist/bin/mongolite.js +172 -0
  7. package/dist/bin/mongolite.js.map +1 -0
  8. package/dist/cjs/bin/mongolite-debug.js +6 -149
  9. package/dist/cjs/bin/mongolite.js +207 -0
  10. package/dist/cjs/cli/discover.js +156 -0
  11. package/dist/cjs/cli/explorer.js +929 -0
  12. package/dist/cjs/cli/filter-builder.js +276 -0
  13. package/dist/cjs/cli/format.js +161 -0
  14. package/dist/cjs/cli/schema.js +211 -0
  15. package/dist/cjs/cli/ui.js +431 -0
  16. package/dist/cjs/collection.js +8 -1
  17. package/dist/cjs/cursors/findCursor.js +20 -8
  18. package/dist/cjs/index.js +108 -1
  19. package/dist/cjs/mongo-client.js +18 -1
  20. package/dist/cjs/server.js +164 -0
  21. package/dist/cjs/sync/commands.js +126 -0
  22. package/dist/cjs/sync/diff.js +174 -0
  23. package/dist/cjs/sync/httpSink.js +159 -0
  24. package/dist/cjs/sync/index.js +40 -0
  25. package/dist/cjs/sync/mongoExecutor.js +306 -0
  26. package/dist/cjs/sync/mongoSink.js +161 -0
  27. package/dist/cjs/sync/outbox.js +358 -0
  28. package/dist/cjs/sync/protocol.js +177 -0
  29. package/dist/cjs/sync/replicator.js +747 -0
  30. package/dist/cjs/sync/shadow.js +178 -0
  31. package/dist/cjs/sync/types.js +2 -0
  32. package/dist/cli/discover.d.ts +40 -0
  33. package/dist/cli/discover.js +146 -0
  34. package/dist/cli/discover.js.map +1 -0
  35. package/dist/cli/explorer.d.ts +59 -0
  36. package/dist/cli/explorer.js +923 -0
  37. package/dist/cli/explorer.js.map +1 -0
  38. package/dist/cli/filter-builder.d.ts +52 -0
  39. package/dist/cli/filter-builder.js +268 -0
  40. package/dist/cli/filter-builder.js.map +1 -0
  41. package/dist/cli/format.d.ts +29 -0
  42. package/dist/cli/format.js +153 -0
  43. package/dist/cli/format.js.map +1 -0
  44. package/dist/cli/schema.d.ts +58 -0
  45. package/dist/cli/schema.js +205 -0
  46. package/dist/cli/schema.js.map +1 -0
  47. package/dist/cli/ui.d.ts +71 -0
  48. package/dist/cli/ui.js +379 -0
  49. package/dist/cli/ui.js.map +1 -0
  50. package/dist/cloudflare.d.ts +1 -1
  51. package/dist/cloudflare.js.map +1 -1
  52. package/dist/collection.js +8 -1
  53. package/dist/collection.js.map +1 -1
  54. package/dist/cursors/findCursor.d.ts +12 -0
  55. package/dist/cursors/findCursor.js +20 -8
  56. package/dist/cursors/findCursor.js.map +1 -1
  57. package/dist/index.d.ts +68 -2
  58. package/dist/index.js +96 -1
  59. package/dist/index.js.map +1 -1
  60. package/dist/mongo-client.d.ts +13 -0
  61. package/dist/mongo-client.js +18 -1
  62. package/dist/mongo-client.js.map +1 -1
  63. package/dist/server.d.ts +97 -0
  64. package/dist/server.js +158 -0
  65. package/dist/server.js.map +1 -0
  66. package/dist/sync/commands.d.ts +49 -0
  67. package/dist/sync/commands.js +118 -0
  68. package/dist/sync/commands.js.map +1 -0
  69. package/dist/sync/diff.d.ts +55 -0
  70. package/dist/sync/diff.js +169 -0
  71. package/dist/sync/diff.js.map +1 -0
  72. package/dist/sync/httpSink.d.ts +93 -0
  73. package/dist/sync/httpSink.js +155 -0
  74. package/dist/sync/httpSink.js.map +1 -0
  75. package/dist/sync/index.d.ts +17 -0
  76. package/dist/sync/index.js +10 -0
  77. package/dist/sync/index.js.map +1 -0
  78. package/dist/sync/mongoExecutor.d.ts +37 -0
  79. package/dist/sync/mongoExecutor.js +302 -0
  80. package/dist/sync/mongoExecutor.js.map +1 -0
  81. package/dist/sync/mongoSink.d.ts +109 -0
  82. package/dist/sync/mongoSink.js +123 -0
  83. package/dist/sync/mongoSink.js.map +1 -0
  84. package/dist/sync/outbox.d.ts +120 -0
  85. package/dist/sync/outbox.js +355 -0
  86. package/dist/sync/outbox.js.map +1 -0
  87. package/dist/sync/protocol.d.ts +93 -0
  88. package/dist/sync/protocol.js +168 -0
  89. package/dist/sync/protocol.js.map +1 -0
  90. package/dist/sync/replicator.d.ts +177 -0
  91. package/dist/sync/replicator.js +744 -0
  92. package/dist/sync/replicator.js.map +1 -0
  93. package/dist/sync/shadow.d.ts +54 -0
  94. package/dist/sync/shadow.js +173 -0
  95. package/dist/sync/shadow.js.map +1 -0
  96. package/dist/sync/types.d.ts +388 -0
  97. package/dist/sync/types.js +2 -0
  98. package/dist/sync/types.js.map +1 -0
  99. package/package.json +16 -1
package/README.md CHANGED
@@ -24,6 +24,8 @@ A MongoDB-like client backed by SQLite. Use a familiar MongoDB API with the simp
24
24
  - **Update operators** — `$set`, `$inc`, `$push`, `$pull`, `$addToSet`, `$mul`, and more
25
25
  - **Indexing** — create, list, and drop indexes including unique and compound indexes
26
26
  - **Change streams** — real-time change tracking via `collection.watch()`
27
+ - **MongoDB sync** — replicate local writes upstream, surviving restarts and offline periods
28
+ - **HTTP sync** — post the same changes to a remote API when MongoDB is unreachable
27
29
  - **JSON safety** — validates documents before insert, and a corrupted row can't break queries for the rest of the collection
28
30
  - **TypeScript** — fully typed with strict mode
29
31
 
@@ -69,29 +71,43 @@ async function main() {
69
71
  main();
70
72
  ```
71
73
 
74
+ ## Explore a database from the terminal
75
+
76
+ ```bash
77
+ npx mongolite
78
+ ```
79
+
80
+ Picks up the SQLite files around you, lists the collections it finds inside,
81
+ and builds queries out of plain-English choices — "age is at least 30",
82
+ "skills contains SQL" — using fields inferred from your actual documents. It
83
+ prints the MongoDB filter it built alongside the results, and raw filters and
84
+ raw SQL are a menu item away when you want them. See [the CLI docs](./docs/CLI.md).
85
+
72
86
  ## How does it compare?
73
87
 
74
- | | MongoLite | lowdb | better-sqlite3 (raw) | NeDB | PouchDB | MongoDB |
75
- |---|---|---|---|---|---|---|
76
- | MongoDB query API (`$set`, `$elemMatch`, aggregation...) | ✅ | ❌ (plain object access) | ❌ (raw SQL) | ✅ | ❌ (Mango/CouchDB-style) | ✅ |
77
- | Runs in the browser | ✅ (sql.js) | ✅ | ❌ (native binding) | ✅ | ✅ (IndexedDB) | ❌ |
78
- | Runs on the edge (Cloudflare Durable Objects) | ✅ | ❌ | ❌ (native binding) | ❌ | ❌ | ❌ |
79
- | Zero infrastructure (no server process) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
80
- | TypeScript, strict mode | ✅ | ✅ | ✅ | ⚠️ (community types) | ⚠️ (community types) | ✅ |
81
- | Actively maintained | ✅ | ✅ | ✅ | ❌ (unmaintained) | ⚠️ (slow-moving) | ✅ |
88
+ | | MongoLite | lowdb | better-sqlite3 (raw) | NeDB | PouchDB | MongoDB |
89
+ | -------------------------------------------------------- | ----------- | ------------------------ | -------------------- | -------------------- | ------------------------ | ------- |
90
+ | MongoDB query API (`$set`, `$elemMatch`, aggregation...) | ✅ | ❌ (plain object access) | ❌ (raw SQL) | ✅ | ❌ (Mango/CouchDB-style) | ✅ |
91
+ | Runs in the browser | ✅ (sql.js) | ✅ | ❌ (native binding) | ✅ | ✅ (IndexedDB) | ❌ |
92
+ | Runs on the edge (Cloudflare Durable Objects) | ✅ | ❌ | ❌ (native binding) | ❌ | ❌ | ❌ |
93
+ | Zero infrastructure (no server process) | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ |
94
+ | TypeScript, strict mode | ✅ | ✅ | ✅ | ⚠️ (community types) | ⚠️ (community types) | ✅ |
95
+ | Actively maintained | ✅ | ✅ | ✅ | ❌ (unmaintained) | ⚠️ (slow-moving) | ✅ |
82
96
 
83
97
  MongoLite's niche: the MongoDB query API you already know, running anywhere SQLite runs — a local file, an in-memory test database, the browser, or a Cloudflare Durable Object — without standing up a MongoDB server.
84
98
 
85
99
  ## Documentation
86
100
 
87
- | Topic | Description |
88
- |-------|-------------|
89
- | [API Reference](./docs/API.md) | Full API docs: methods, query operators, update operators |
90
- | [Change Streams](./docs/CHANGE_STREAMS.md) | Real-time change tracking with `collection.watch()` |
91
- | [JSON Safety](./docs/JSON_SAFETY.md) | Document validation and corrupted data recovery |
92
- | [Query Debugger](./docs/DEBUGGER.md) | Interactive CLI for debugging queries and inspecting SQL |
93
- | [Benchmarks](./docs/BENCHMARKS.md) | Performance benchmarks and storage characteristics |
94
- | [Cloudflare Durable Objects](./docs/CLOUDFLARE.md) | Using MongoLite inside a Cloudflare Durable Object |
101
+ | Topic | Description |
102
+ | -------------------------------------------------- | ---------------------------------------------------------------------- |
103
+ | [API Reference](./docs/API.md) | Full API docs: methods, query operators, update operators |
104
+ | [Change Streams](./docs/CHANGE_STREAMS.md) | Real-time change tracking with `collection.watch()` |
105
+ | [Syncing to MongoDB](./docs/SYNC.md) | Replication to an upstream MongoDB, directly or through an HTTP API |
106
+ | [JSON Safety](./docs/JSON_SAFETY.md) | Document validation and corrupted data recovery |
107
+ | [CLI](./docs/CLI.md) | `npx mongolite` — guided explorer for browsing and querying a database |
108
+ | [Query Debugger](./docs/DEBUGGER.md) | The older command-driven REPL (`npx mongolite --repl`) |
109
+ | [Benchmarks](./docs/BENCHMARKS.md) | Performance benchmarks and storage characteristics |
110
+ | [Cloudflare Durable Objects](./docs/CLOUDFLARE.md) | Using MongoLite inside a Cloudflare Durable Object |
95
111
 
96
112
  ## Backend Examples
97
113
 
@@ -112,9 +128,9 @@ await client.close();
112
128
  ```typescript
113
129
  const client = new MongoLite({
114
130
  filePath: './myapp.sqlite',
115
- WAL: true, // Write-Ahead Logging. Default: true
116
- busyTimeout: 5000, // ms to wait for a lock before SQLITE_BUSY. Default: 5000
117
- shared: true, // reuse one connection per file in this process. Default: false
131
+ WAL: true, // Write-Ahead Logging. Default: true
132
+ busyTimeout: 5000, // ms to wait for a lock before SQLITE_BUSY. Default: 5000
133
+ shared: true, // reuse one connection per file in this process. Default: false
118
134
  readOnly: false,
119
135
  verbose: false,
120
136
  });
@@ -136,7 +152,7 @@ await a.close(); // b keeps working — the handle is reference counted
136
152
  await b.close(); // last holder out actually closes it
137
153
  ```
138
154
 
139
- Connections are only shared when the resolved path *and* every setting that
155
+ Connections are only shared when the resolved path _and_ every setting that
140
156
  changes the handle's behaviour match. `:memory:` databases are never shared,
141
157
  since two `:memory:` opens are two unrelated databases.
142
158
 
@@ -180,6 +196,7 @@ await client.close();
180
196
  ```
181
197
 
182
198
  <a id="native-nodesqlite-vs-better-sqlite3"></a>
199
+
183
200
  > **Which one should I use?** `node:sqlite` (the default) is still marked
184
201
  > experimental upstream but requires no native build step, which is why it's
185
202
  > the default here. `better-sqlite3` is the older, more battle-tested native
@@ -235,6 +252,60 @@ export class MyDurableObject extends DurableObject {
235
252
 
236
253
  > See [docs/CLOUDFLARE.md](./docs/CLOUDFLARE.md) for the full guide, supported operations, and limitations.
237
254
 
255
+ ## Syncing to MongoDB
256
+
257
+ Point MongoLite at an upstream MongoDB deployment and every insert, update and
258
+ delete is replicated to it. The local database becomes a local-first write layer
259
+ that converges upstream — through restarts, network outages and offline periods.
260
+
261
+ Requires the optional `mongodb` peer dependency (`npm install mongodb`).
262
+
263
+ ```typescript
264
+ const client = new MongoLite('./app.sqlite');
265
+ await client.connect();
266
+
267
+ const sync = client.syncToMongo({
268
+ connectionString: 'mongodb+srv://user:pass@cluster.example.com/app',
269
+ collections: ['users', 'orders'], // Omit to replicate everything
270
+ });
271
+
272
+ await sync.start();
273
+
274
+ // Ordinary writes — replication happens in the background.
275
+ await client.collection('users').insertOne({ name: 'Alice', age: 30 });
276
+
277
+ await sync.stop({ flush: true }); // Push anything still queued on shutdown
278
+ ```
279
+
280
+ Changes are captured by SQLite triggers into a durable outbox **inside the same
281
+ transaction as the write itself**, so a change is either committed locally _and_
282
+ queued for replication, or neither. A background worker coalesces the queue, applies
283
+ it upstream, and only then advances a persisted checkpoint — so an outage parks the
284
+ backlog rather than losing it, and a restart resumes exactly where it stopped.
285
+
286
+ Upstream is treated as the source of truth. Each push is a conditional write against
287
+ the version it last saw, and carries only the fields that actually changed, so a
288
+ concurrent edit by another writer is detected rather than silently overwritten.
289
+
290
+ Where the local instance cannot reach MongoDB directly, `syncToHttp` posts the same
291
+ operations to a remote API instead, and `@semics-tech/mongolite/server` applies them on
292
+ the far side:
293
+
294
+ ```typescript
295
+ const sync = client.syncToHttp({
296
+ baseUrl: 'https://api.example.com',
297
+ database: 'app',
298
+ getAuthHeaders: async () => ({ Authorization: `Bearer ${await getAccessToken()}` }),
299
+ });
300
+ ```
301
+
302
+ The version predicates travel with each operation and conflicts come back in the
303
+ response, so the HTTP hop is pure transport — replication behaves the same either way.
304
+
305
+ > See [docs/SYNC.md](./docs/SYNC.md) for the full guide: syncing through an HTTP API,
306
+ > advanced authentication (X.509, mTLS, AWS IAM, Azure managed identity), filtering and
307
+ > reshaping documents, dead-letter handling, multiple upstreams, and custom sinks.
308
+
238
309
  ## Development
239
310
 
240
311
  ```bash
@@ -1,2 +1,7 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ /**
3
+ * `mongolite-debug` is kept as an alias of `mongolite` so existing scripts and
4
+ * muscle memory keep working. It runs the same guided explorer; pass `--repl`
5
+ * for the original command-driven debugger (`.use`, `.find`, `.sql`, …).
6
+ */
7
+ import './mongolite.js';
@@ -1,115 +1,8 @@
1
1
  #!/usr/bin/env node
2
- import { QueryDebugger } from '../debugger/query-debugger.js';
3
- import path from 'path';
4
- // CLI argument parsing
5
- function parseArgs() {
6
- const args = process.argv.slice(2);
7
- const options = {};
8
- for (let i = 0; i < args.length; i++) {
9
- const arg = args[i];
10
- if (arg === '--verbose' || arg === '-v') {
11
- options.verbose = true;
12
- }
13
- else if (arg === '--collection' || arg === '-c') {
14
- options.collection = args[++i];
15
- }
16
- else if (arg === '--database' || arg === '-d') {
17
- options.database = args[++i];
18
- }
19
- else if (arg === '--help' || arg === '-h') {
20
- options.help = true;
21
- }
22
- }
23
- return options;
24
- }
25
- function showHelp() {
26
- console.log('MongoLite Query Debugger');
27
- console.log('');
28
- console.log('Interactive debugging tool for MongoLite queries.');
29
- console.log('');
30
- console.log('Usage: npx mongolite-debug [options]');
31
- console.log('');
32
- console.log('Options:');
33
- console.log(' -d, --database <path> Database file path (default: ./mongolite.db)');
34
- console.log(' -c, --collection <name> Initial collection to use');
35
- console.log(' -v, --verbose Enable verbose output');
36
- console.log(' -h, --help Show this help');
37
- console.log('');
38
- console.log('Interactive Commands:');
39
- console.log(' .help Show available commands');
40
- console.log(' .collections List all collections');
41
- console.log(' .use <collection> Select a collection to work with');
42
- console.log(' .find <filter> Convert find filter to SQL and execute');
43
- console.log(' .sql <query> Execute raw SQL query');
44
- console.log(' .last Show last generated SQL');
45
- console.log(' .sample [count] Show sample documents from current collection');
46
- console.log(' .exit Exit the debugger');
47
- console.log('');
48
- console.log('Examples:');
49
- console.log(' npx mongolite-debug -d ./myapp.db -c users');
50
- console.log(' npx mongolite-debug --verbose');
51
- console.log('');
52
- console.log(' # Inside the debugger:');
53
- console.log(' .use users');
54
- console.log(' .find {"age": {"$gt": 25}}');
55
- console.log(' .sql SELECT * FROM users WHERE json_extract(data, "$.age") > 25');
56
- console.log('');
57
- }
58
- async function main() {
59
- const options = parseArgs();
60
- if (options.help) {
61
- showHelp();
62
- process.exit(0);
63
- }
64
- // Set default database path if not provided
65
- if (!options.database) {
66
- // Look for common database files in the current directory
67
- const cwd = process.cwd();
68
- const commonNames = [
69
- 'mongolite.db',
70
- 'mongolite.sqlite',
71
- 'database.db',
72
- 'database.sqlite',
73
- 'app.db',
74
- 'app.sqlite',
75
- ];
76
- // Check if any common database files exist
77
- const { existsSync } = await import('fs');
78
- let foundDb = false;
79
- for (const name of commonNames) {
80
- const dbPath = path.join(cwd, name);
81
- if (existsSync(dbPath)) {
82
- options.database = dbPath;
83
- foundDb = true;
84
- break;
85
- }
86
- }
87
- if (!foundDb) {
88
- options.database = path.join(cwd, 'mongolite.db');
89
- }
90
- }
91
- console.log('🔍 MongoLite Query Debugger (npx version)');
92
- console.log(`📁 Database: ${options.database}`);
93
- if (options.collection) {
94
- console.log(`📋 Initial collection: ${options.collection}`);
95
- }
96
- console.log('');
97
- try {
98
- const queryDebugger = new QueryDebugger(options);
99
- await queryDebugger.start();
100
- }
101
- catch (error) {
102
- console.error('Fatal error:', error instanceof Error ? error.message : error);
103
- if (error instanceof Error && error.message.includes('SQLITE_CANTOPEN')) {
104
- console.error('');
105
- console.error('💡 Tip: Make sure the database file exists or specify a different path with -d');
106
- console.error(' Example: npx mongolite-debug -d ./path/to/your/database.db');
107
- }
108
- process.exit(1);
109
- }
110
- }
111
- main().catch((error) => {
112
- console.error('Unexpected error:', error);
113
- process.exit(1);
114
- });
2
+ /**
3
+ * `mongolite-debug` is kept as an alias of `mongolite` so existing scripts and
4
+ * muscle memory keep working. It runs the same guided explorer; pass `--repl`
5
+ * for the original command-driven debugger (`.use`, `.find`, `.sql`, …).
6
+ */
7
+ import './mongolite.js';
115
8
  //# sourceMappingURL=mongolite-debug.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mongolite-debug.js","sourceRoot":"","sources":["../../src/bin/mongolite-debug.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mongolite-debug.js","sourceRoot":"","sources":["../../src/bin/mongolite-debug.ts"],"names":[],"mappings":";AACA;;;;GAIG;AACH,OAAO,gBAAgB,CAAC"}
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ interface CliOptions {
3
+ database?: string;
4
+ collection?: string;
5
+ verbose: boolean;
6
+ help: boolean;
7
+ version: boolean;
8
+ repl: boolean;
9
+ sampleSize?: number;
10
+ pageSize?: number;
11
+ }
12
+ export declare function parseArgs(argv: string[]): CliOptions;
13
+ export {};
@@ -0,0 +1,172 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * `mongolite` — the guided explorer for MongoLite databases.
4
+ *
5
+ * Running it with no arguments is the intended path: it finds your database
6
+ * files, lists the collections it finds inside, and walks you through a query.
7
+ * Flags are shortcuts for people who already know where they are going, and
8
+ * `--repl` drops into the older command-driven debugger.
9
+ */
10
+ import { Explorer } from '../cli/explorer.js';
11
+ import { QueryDebugger } from '../debugger/query-debugger.js';
12
+ import { closePrompts, style } from '../cli/ui.js';
13
+ export function parseArgs(argv) {
14
+ const options = { verbose: false, help: false, version: false, repl: false };
15
+ const positional = [];
16
+ for (let index = 0; index < argv.length; index += 1) {
17
+ const arg = argv[index];
18
+ switch (arg) {
19
+ case '--database':
20
+ case '-d':
21
+ options.database = argv[++index];
22
+ break;
23
+ case '--collection':
24
+ case '-c':
25
+ options.collection = argv[++index];
26
+ break;
27
+ case '--verbose':
28
+ case '-v':
29
+ options.verbose = true;
30
+ break;
31
+ case '--repl':
32
+ case '--expert':
33
+ options.repl = true;
34
+ break;
35
+ case '--sample':
36
+ options.sampleSize = Number(argv[++index]);
37
+ break;
38
+ case '--page-size':
39
+ options.pageSize = Number(argv[++index]);
40
+ break;
41
+ case '--help':
42
+ case '-h':
43
+ options.help = true;
44
+ break;
45
+ case '--version':
46
+ case '-V':
47
+ options.version = true;
48
+ break;
49
+ default:
50
+ if (arg.startsWith('-')) {
51
+ throw new Error(`Unknown option: ${arg}`);
52
+ }
53
+ positional.push(arg);
54
+ break;
55
+ }
56
+ }
57
+ // `mongolite ./app.db users` is the shape people try first, so support it.
58
+ if (!options.database && positional[0])
59
+ options.database = positional[0];
60
+ if (!options.collection && positional[1])
61
+ options.collection = positional[1];
62
+ return options;
63
+ }
64
+ function showHelp() {
65
+ const lines = [
66
+ `${style.bold('mongolite')} — explore a MongoLite (SQLite-backed) database`,
67
+ '',
68
+ style.bold('Usage'),
69
+ ' npx mongolite Start the guided explorer',
70
+ ' npx mongolite ./app.db Open a specific database',
71
+ ' npx mongolite ./app.db users Open a specific collection',
72
+ '',
73
+ style.bold('Options'),
74
+ ' -d, --database <path> Database file to open (otherwise you get a list to pick from)',
75
+ ' -c, --collection <name> Collection to start in',
76
+ ' --sample <n> Documents to sample when inferring fields (default 200)',
77
+ ' --page-size <n> Results shown per page (default 20)',
78
+ ' --repl Use the older command-driven debugger instead',
79
+ ' -v, --verbose Log the SQL being built',
80
+ ' -h, --help Show this help',
81
+ ' -V, --version Show the version',
82
+ '',
83
+ style.bold('In the explorer'),
84
+ ' ↑/↓ move · type to filter the list · enter to choose · esc to go back · Ctrl+C to quit',
85
+ '',
86
+ 'No MongoDB knowledge is needed: pick a field, pick a condition in plain English,',
87
+ 'and the filter it builds is printed so you can learn the syntax as you go.',
88
+ 'If you already know it, "Write a MongoDB filter yourself" and "Run raw SQL" are',
89
+ 'under Advanced.',
90
+ '',
91
+ ];
92
+ process.stdout.write(`${lines.join('\n')}\n`);
93
+ }
94
+ /**
95
+ * Find the package version by walking up from the running script.
96
+ * Deliberately avoids `import.meta` and `__dirname` so the same source compiles
97
+ * for both the ESM and CommonJS builds.
98
+ */
99
+ async function showVersion() {
100
+ const { readFileSync, existsSync } = await import('node:fs');
101
+ const { dirname, join, parse } = await import('node:path');
102
+ let dir = dirname(process.argv[1] ?? process.cwd());
103
+ const { root } = parse(dir);
104
+ while (dir && dir !== root) {
105
+ const candidate = join(dir, 'package.json');
106
+ if (existsSync(candidate)) {
107
+ try {
108
+ const pkg = JSON.parse(readFileSync(candidate, 'utf8'));
109
+ if (pkg.version) {
110
+ process.stdout.write(`${pkg.version}\n`);
111
+ return;
112
+ }
113
+ }
114
+ catch {
115
+ // Unreadable package.json - keep walking up.
116
+ }
117
+ }
118
+ dir = dirname(dir);
119
+ }
120
+ process.stdout.write('unknown\n');
121
+ }
122
+ async function main() {
123
+ let options;
124
+ try {
125
+ options = parseArgs(process.argv.slice(2));
126
+ }
127
+ catch (error) {
128
+ process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
129
+ process.stderr.write('Run with --help to see the available options.\n');
130
+ process.exit(1);
131
+ return;
132
+ }
133
+ if (options.help) {
134
+ showHelp();
135
+ return;
136
+ }
137
+ if (options.version) {
138
+ await showVersion();
139
+ return;
140
+ }
141
+ if (options.repl) {
142
+ const queryDebugger = new QueryDebugger({
143
+ database: options.database,
144
+ collection: options.collection,
145
+ verbose: options.verbose,
146
+ });
147
+ await queryDebugger.start();
148
+ return;
149
+ }
150
+ const explorer = new Explorer({
151
+ database: options.database,
152
+ collection: options.collection,
153
+ verbose: options.verbose,
154
+ sampleSize: Number.isFinite(options.sampleSize) ? options.sampleSize : undefined,
155
+ pageSize: Number.isFinite(options.pageSize) ? options.pageSize : undefined,
156
+ });
157
+ await explorer.run();
158
+ }
159
+ main()
160
+ .then(() => {
161
+ closePrompts();
162
+ process.exit(0);
163
+ })
164
+ .catch((error) => {
165
+ const text = error instanceof Error ? error.message : String(error);
166
+ process.stderr.write(`\n✖ ${text}\n`);
167
+ if (text.includes('SQLITE_CANTOPEN') || text.includes('unable to open')) {
168
+ process.stderr.write(' The file may not exist, or may not be readable.\n');
169
+ }
170
+ process.exit(1);
171
+ });
172
+ //# sourceMappingURL=mongolite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongolite.js","sourceRoot":"","sources":["../../src/bin/mongolite.ts"],"names":[],"mappings":"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"}
@@ -1,152 +1,9 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
- if (k2 === undefined) k2 = k;
5
- var desc = Object.getOwnPropertyDescriptor(m, k);
6
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
- desc = { enumerable: true, get: function() { return m[k]; } };
8
- }
9
- Object.defineProperty(o, k2, desc);
10
- }) : (function(o, m, k, k2) {
11
- if (k2 === undefined) k2 = k;
12
- o[k2] = m[k];
13
- }));
14
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
- Object.defineProperty(o, "default", { enumerable: true, value: v });
16
- }) : function(o, v) {
17
- o["default"] = v;
18
- });
19
- var __importStar = (this && this.__importStar) || (function () {
20
- var ownKeys = function(o) {
21
- ownKeys = Object.getOwnPropertyNames || function (o) {
22
- var ar = [];
23
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
- return ar;
25
- };
26
- return ownKeys(o);
27
- };
28
- return function (mod) {
29
- if (mod && mod.__esModule) return mod;
30
- var result = {};
31
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
- __setModuleDefault(result, mod);
33
- return result;
34
- };
35
- })();
36
- var __importDefault = (this && this.__importDefault) || function (mod) {
37
- return (mod && mod.__esModule) ? mod : { "default": mod };
38
- };
39
3
  Object.defineProperty(exports, "__esModule", { value: true });
40
- const query_debugger_js_1 = require("../debugger/query-debugger.js");
41
- const path_1 = __importDefault(require("path"));
42
- // CLI argument parsing
43
- function parseArgs() {
44
- const args = process.argv.slice(2);
45
- const options = {};
46
- for (let i = 0; i < args.length; i++) {
47
- const arg = args[i];
48
- if (arg === '--verbose' || arg === '-v') {
49
- options.verbose = true;
50
- }
51
- else if (arg === '--collection' || arg === '-c') {
52
- options.collection = args[++i];
53
- }
54
- else if (arg === '--database' || arg === '-d') {
55
- options.database = args[++i];
56
- }
57
- else if (arg === '--help' || arg === '-h') {
58
- options.help = true;
59
- }
60
- }
61
- return options;
62
- }
63
- function showHelp() {
64
- console.log('MongoLite Query Debugger');
65
- console.log('');
66
- console.log('Interactive debugging tool for MongoLite queries.');
67
- console.log('');
68
- console.log('Usage: npx mongolite-debug [options]');
69
- console.log('');
70
- console.log('Options:');
71
- console.log(' -d, --database <path> Database file path (default: ./mongolite.db)');
72
- console.log(' -c, --collection <name> Initial collection to use');
73
- console.log(' -v, --verbose Enable verbose output');
74
- console.log(' -h, --help Show this help');
75
- console.log('');
76
- console.log('Interactive Commands:');
77
- console.log(' .help Show available commands');
78
- console.log(' .collections List all collections');
79
- console.log(' .use <collection> Select a collection to work with');
80
- console.log(' .find <filter> Convert find filter to SQL and execute');
81
- console.log(' .sql <query> Execute raw SQL query');
82
- console.log(' .last Show last generated SQL');
83
- console.log(' .sample [count] Show sample documents from current collection');
84
- console.log(' .exit Exit the debugger');
85
- console.log('');
86
- console.log('Examples:');
87
- console.log(' npx mongolite-debug -d ./myapp.db -c users');
88
- console.log(' npx mongolite-debug --verbose');
89
- console.log('');
90
- console.log(' # Inside the debugger:');
91
- console.log(' .use users');
92
- console.log(' .find {"age": {"$gt": 25}}');
93
- console.log(' .sql SELECT * FROM users WHERE json_extract(data, "$.age") > 25');
94
- console.log('');
95
- }
96
- async function main() {
97
- const options = parseArgs();
98
- if (options.help) {
99
- showHelp();
100
- process.exit(0);
101
- }
102
- // Set default database path if not provided
103
- if (!options.database) {
104
- // Look for common database files in the current directory
105
- const cwd = process.cwd();
106
- const commonNames = [
107
- 'mongolite.db',
108
- 'mongolite.sqlite',
109
- 'database.db',
110
- 'database.sqlite',
111
- 'app.db',
112
- 'app.sqlite',
113
- ];
114
- // Check if any common database files exist
115
- const { existsSync } = await Promise.resolve().then(() => __importStar(require('fs')));
116
- let foundDb = false;
117
- for (const name of commonNames) {
118
- const dbPath = path_1.default.join(cwd, name);
119
- if (existsSync(dbPath)) {
120
- options.database = dbPath;
121
- foundDb = true;
122
- break;
123
- }
124
- }
125
- if (!foundDb) {
126
- options.database = path_1.default.join(cwd, 'mongolite.db');
127
- }
128
- }
129
- console.log('🔍 MongoLite Query Debugger (npx version)');
130
- console.log(`📁 Database: ${options.database}`);
131
- if (options.collection) {
132
- console.log(`📋 Initial collection: ${options.collection}`);
133
- }
134
- console.log('');
135
- try {
136
- const queryDebugger = new query_debugger_js_1.QueryDebugger(options);
137
- await queryDebugger.start();
138
- }
139
- catch (error) {
140
- console.error('Fatal error:', error instanceof Error ? error.message : error);
141
- if (error instanceof Error && error.message.includes('SQLITE_CANTOPEN')) {
142
- console.error('');
143
- console.error('💡 Tip: Make sure the database file exists or specify a different path with -d');
144
- console.error(' Example: npx mongolite-debug -d ./path/to/your/database.db');
145
- }
146
- process.exit(1);
147
- }
148
- }
149
- main().catch((error) => {
150
- console.error('Unexpected error:', error);
151
- process.exit(1);
152
- });
4
+ /**
5
+ * `mongolite-debug` is kept as an alias of `mongolite` so existing scripts and
6
+ * muscle memory keep working. It runs the same guided explorer; pass `--repl`
7
+ * for the original command-driven debugger (`.use`, `.find`, `.sql`, …).
8
+ */
9
+ require("./mongolite.js");