Commit af061f9
authored
feat(db): add LibreDB embedded provider (#95)
* docs(features): update headings and fix markdown indentation in FEATURES.md
* docs(providers): add design specification for LibreDB provider
* docs(providers): add approved design spec for LibreDB embedded provider
* docs(plans): add LibreDB embedded provider implementation plan
* feat(db): register libredb database type and @libredb/libredb dependency
* feat(db): add LibreDBProvider lifecycle, metadata, and factory wiring
* fix(db): validate libredb path on connect to prevent silent in-memory open
* feat(db): implement libredb getSchema prefix grouping
* feat(db): implement libredb query command grammar
* fix(db): reject unmatched quotes in libredb command parsing
* test(db): lock libredb monitoring surface
* feat(ui): make libredb selectable with a file-path connection form
* docs(providers): add libredb provider reference (tri-sync)
* docs(db): clarify disconnect close-guard comment in libredb provider
* feat(libredb): catalog-aware schema and reserved-namespace filtering (@libredb/libredb 0.0.3)
Upgrade the embedded LibreDB provider for @libredb/libredb 0.0.3, which adds a
persisted catalog and a public reserved-namespace contract.
- Catalog-aware getSchema: read catalog(db) to render faithful per-kind views.
Relational tables show their declared columns and types (primary key marked);
document collections show a generic id/document pair; uncataloged keys keep
the raw key/value view. Cataloged-but-empty namespaces are surfaced too. The
query grammar (get/put/delete/prefix/range) is unchanged.
- Reserved-namespace filtering: internal keys (the catalog, and any future
reserved sub-namespace) are excluded from getSchema and from range/prefix
query results via the package's pinned isReservedKey predicate, accessed
through the lazily-loaded module rather than a hardcoded prefix. isReservedKey
is marker-based (U+0000), so it hides the entire reserved namespace, not just
catalog entries; the database forbids user namespace names under the marker
(assertUserName), so no user data can be hidden.
- Require @libredb/libredb ^0.0.3.
Tri-sync: provider code, integration tests (catalog-aware, reserved-namespace,
and a widening case; 22 pass), and docs/providers/libredb.md updated together.
Gate green: typecheck, lint (0 errors), test, build, build:lib.
* docs(archived): add superseded design spec for LibreDB provider
* fix(libredb): address PR review notes
- ConnectionModal: correct font-mediumr -> font-medium on the new file-path label
- docs/providers/libredb.md: use 'bun run test' (not bare 'bun test') per CLAUDE.md
- docs/archived design sketch: connection example uses the 'database' field, not 'path'
- provider: drop redundant prepareQuery override (base default suffices; not called by query())
* fix(libredb): address follow-up PR review notes
- archived design doc: fix relative link to ../providers/libredb.md (was broken from docs/archived/)
- ConnectionModal: use a provider-neutral file-path placeholder (the form is shared by all file-based providers, not just libredb)
* chore(.gitignore): add data/ directory to ignore list
* docs(providers): add libredb to DATABASE_PROVIDERS overview
* feat(libredb): wire schema-explorer Scan/Generate Command for libredb
The shared query generators treated every queryLanguage:'json' provider as
MongoDB, so libredb's menu actions emitted unrunnable Mongo find JSON. Add an
optional ProviderCapabilities.queryDialect discriminator (undefined for all
existing providers -> zero behavior change) and route generation to LibreDB
commands when queryDialect==='libredb':
- Scan Keys -> 'prefix <group>:' (or 'get <name>' for a bare key)
- Generate Command -> a runnable, comment-free get/put/delete cheatsheet
Open-closed: no other provider touched. Covered by query-generators unit tests
and the libredb capabilities test; docs/providers/libredb.md section 5.3 added.
* feat(libredb): explanatory, runnable Generate Command cheatsheet
Make the schema-explorer 'Generate Command' output self-explanatory and
directly runnable:
- Parser skips blank and '#' comment lines and runs the first real command, so
a commented multi-line cheatsheet runs directly (select a line, or run-all
runs the first command). Comments only count when a line starts with '#'.
- Generator emits a use-case comment above each command, and every command line
is a concrete, directly-runnable example (no <placeholder> tokens). The put
example value is column-aware: JSON object from a relational table's columns,
a small object for a document collection, or a plain string for raw kv.
Covered by query-generators unit tests and new provider comment-handling tests;
docs/providers/libredb.md 5.1/5.3 updated.
* feat(libredb): dedicated Monaco syntax highlighting for libredb command tabs
libredb tabs reused the JSON Monaco language, so commands rendered flat (and
'#' comments / verbs were not coloured). Add a first-class 'libredb' tab type
(mirroring the existing 'redis' precedent), driven off capabilities.queryDialect,
and a minimal Monaco language (verbs as keywords, '#' line comments, strings,
numbers) that maps onto the existing db-dark theme. The editor language is
derived from the tab type at both render sites (standalone Studio + embedded
StudioWorkspace), so highlighting works in both. No other provider affected.
Extended the QueryEditor test's Monaco mock with the languages API now used in
beforeMount.
* fix(libredb): drop unused LIBREDB_LANGUAGE_ID export (knip)
* fix(libredb): address Copilot review — path hardening, catalog reconciliation, editor polish
- connect() now resolves + validates the file path (path.resolve + reject
traversal/null-byte), mirroring the SQLite provider; the resolved path is
reused for open()/statSync. Closes the CodeQL 'uncontrolled data in path'
alert and the sibling-parity gap. (test: null-byte path rejected)
- catalogEntryFor() only reconciles ':*' prefix groups; a bare (no-colon) key
is never catalog-upgraded even if its name matches a namespace. (test:
bare key stays key/value)
- Monaco tokenizer: a key like 'users:1' is one identifier token, not
'users' + number.
- Hide the Format button for languages without a formatter (libredb), instead
of showing an affordance that does nothing.
All local gates green: lint, typecheck, knip, test (18 groups), build, build:lib, helm.
* fix(docker): bundle @libredb/libredb into the standalone runner image
The libredb provider lazy-imports @libredb/libredb, so Next.js output-file
tracing leaves it out of the standalone server bundle and a libredb connection
would fail at runtime with 'package not available' inside the container. Copy
it explicitly (same pattern as better-sqlite3) so the provider works in Docker.
Verified: package present + file create/WAL/fsync succeed as the non-root
nextjs user, persisting to /app/data.1 parent ed42647 commit af061f9
29 files changed
Lines changed: 3135 additions & 39 deletions
File tree
- docs
- archived
- providers
- superpowers
- plans
- specs
- src
- components
- icons
- hooks
- lib
- db
- providers/embedded
- editor
- seed
- workspace
- tests
- components
- integration/db
- unit/lib
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
104 | 104 | | |
105 | 105 | | |
106 | 106 | | |
| 107 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
63 | 69 | | |
64 | 70 | | |
65 | 71 | | |
| |||
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
30 | 30 | | |
31 | 31 | | |
32 | 32 | | |
33 | | - | |
34 | | - | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
35 | 37 | | |
36 | 38 | | |
37 | 39 | | |
| |||
48 | 50 | | |
49 | 51 | | |
50 | 52 | | |
51 | | - | |
| 53 | + | |
| 54 | + | |
52 | 55 | | |
53 | 56 | | |
54 | | - | |
| 57 | + | |
55 | 58 | | |
56 | 59 | | |
57 | 60 | | |
| |||
90 | 93 | | |
91 | 94 | | |
92 | 95 | | |
93 | | - | |
| 96 | + | |
94 | 97 | | |
95 | 98 | | |
96 | 99 | | |
| |||
102 | 105 | | |
103 | 106 | | |
104 | 107 | | |
| 108 | + | |
105 | 109 | | |
106 | 110 | | |
107 | 111 | | |
| |||
351 | 355 | | |
352 | 356 | | |
353 | 357 | | |
| 358 | + | |
354 | 359 | | |
355 | 360 | | |
356 | 361 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| |||
122 | 122 | | |
123 | 123 | | |
124 | 124 | | |
125 | | - | |
| 125 | + | |
126 | 126 | | |
127 | 127 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
0 commit comments