admindb 1.1.0 → 1.2.1
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.
- package/README.md +276 -228
- package/dist/app.d.ts +12 -0
- package/dist/app.js +7 -0
- package/dist/app.js.map +1 -1
- package/dist/args.d.ts +28 -0
- package/dist/args.js +187 -0
- package/dist/args.js.map +1 -0
- package/dist/cli.js +85 -15
- package/dist/cli.js.map +1 -1
- package/dist/data/generator.d.ts +86 -0
- package/dist/data/generator.js +1031 -0
- package/dist/data/generator.js.map +1 -0
- package/dist/db/database.d.ts +4 -0
- package/dist/db/database.js +28 -1
- package/dist/db/database.js.map +1 -1
- package/dist/db/manager.d.ts +6 -0
- package/dist/db/manager.js +31 -0
- package/dist/db/manager.js.map +1 -1
- package/dist/public/css/app.css +1 -1
- package/dist/public/css/input.css +9 -2
- package/dist/public/js/browse.js +8 -1
- package/dist/public/js/databases.js +99 -1
- package/dist/public/js/seed.js +377 -0
- package/dist/routes/api.js +62 -0
- package/dist/routes/api.js.map +1 -1
- package/dist/routes/databases.d.ts +10 -0
- package/dist/routes/databases.js +97 -0
- package/dist/routes/databases.js.map +1 -1
- package/dist/routes/pages.js +24 -0
- package/dist/routes/pages.js.map +1 -1
- package/dist/util.d.ts +5 -0
- package/dist/util.js +13 -0
- package/dist/util.js.map +1 -1
- package/dist/views/layouts/main.hbs +1 -1
- package/dist/views/pages/databases.hbs +41 -0
- package/dist/views/pages/query.hbs +2 -2
- package/dist/views/pages/seed.hbs +86 -0
- package/dist/views/pages/table.hbs +5 -0
- package/dist/views/partials/navbar.hbs +1 -6
- package/dist/views/partials/sidebar.hbs +1 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,60 +1,101 @@
|
|
|
1
1
|
# AdminDB
|
|
2
2
|
|
|
3
|
-
|
|
4
3
|
[](https://www.npmjs.com/package/admindb)
|
|
5
4
|
[](LICENSE)
|
|
6
5
|
[](https://nodejs.org/)
|
|
7
|
-
[](https://github.com/MIbnEKhalid/admindb/actions/workflows/publish.yml)
|
|
8
6
|
[](https://www.npmjs.com/package/admindb)
|
|
7
|
+
[](https://github.com/MIbnEKhalid/admindb/actions/workflows/publish.yml)
|
|
9
8
|
|
|
9
|
+
**A browser-based SQLite administration tool.** Manage a SQLite database
|
|
10
|
+
entirely from the browser — browse and edit rows, run SQL, design schemas,
|
|
11
|
+
import/export and seed data — with no separate frontend app to build or deploy.
|
|
10
12
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
- **No frontend build step.** Handlebars server-rendered UI + vanilla JS +
|
|
14
|
+
Tailwind/DaisyUI; one Express process serves pages, static assets, and the
|
|
15
|
+
JSON API.
|
|
16
|
+
- **Standalone or embeddable.** Run it from the CLI against a file or a folder
|
|
17
|
+
of databases, or mount it inside an existing Express app under any path on
|
|
18
|
+
the same port.
|
|
19
|
+
- **Safe SQL by construction.** Every identifier is quoted and every literal is
|
|
20
|
+
escaped when SQL is generated, and the "Get query / preview" modes only
|
|
21
|
+
produce SQL strings — they never execute.
|
|
17
22
|
|
|
18
|
-
|
|
19
|
-
- **Frontend:** Handlebars server-rendered templates, Tailwind CSS + DaisyUI,
|
|
20
|
-
plain JavaScript (no frontend framework).
|
|
21
|
-
- **Database:** SQLite via [better-sqlite3](https://github.com/WiseLibs/better-sqlite3). Requires
|
|
22
|
-
**Node.js ≥ 20**.
|
|
23
|
+

|
|
23
24
|
|
|
24
|
-
>
|
|
25
|
-
>
|
|
26
|
-
>
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
> protected**.
|
|
32
|
-
> - **It is your responsibility to protect access.** Do **not** expose
|
|
33
|
-
> AdminDB to the public internet or to untrusted networks.
|
|
34
|
-
> - Recommended ways to protect it:
|
|
35
|
-
> - bind the standalone server to `127.0.0.1` (`HOST=127.0.0.1`) and use it
|
|
36
|
-
> only from your own machine, and/or
|
|
37
|
-
> - run it behind a reverse proxy that requires authentication (Basic auth,
|
|
38
|
-
> OAuth, mTLS, …) or inside a VPN / private network.
|
|
39
|
-
>
|
|
40
|
-
> Treat AdminDB as if it were a remote `sqlite3` shell with write access.
|
|
25
|
+
> More screenshots in [`docs/screenshots/`](docs/screenshots/): table browser,
|
|
26
|
+
> query editor, table designer, insert/edit form, schema editor, and the
|
|
27
|
+
> databases landing page.
|
|
28
|
+
|
|
29
|
+
## 30-Second Start
|
|
30
|
+
|
|
31
|
+
No install needed:
|
|
41
32
|
|
|
42
|
-
|
|
33
|
+
```bash
|
|
34
|
+
npx admindb
|
|
35
|
+
# → AdminDB is listening on http://localhost:3000
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
With no arguments the server starts in **manager mode**: a **Databases** landing
|
|
39
|
+
page where you can browse the filesystem and open any SQLite database file
|
|
40
|
+
(`.db` / `.sqlite` / `.sqlite3`), or create new ones. Or point it straight at a
|
|
41
|
+
file:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npx admindb ./data/app.db # open one database
|
|
45
|
+
npx admindb -d ./dbs # manage a folder of databases
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
From a clone:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
git clone https://github.com/MIbnEKhalid/admindb.git
|
|
52
|
+
cd admindb
|
|
53
|
+
npm install
|
|
54
|
+
npm run build
|
|
55
|
+
npm start # serves http://localhost:3000
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
> Requires **Node.js ≥ 20**. Runtime dependencies are `express`,
|
|
59
|
+
> `express-handlebars`, and `better-sqlite3`; the rest is the application.
|
|
60
|
+
|
|
61
|
+
## Why This Exists
|
|
62
|
+
|
|
63
|
+
AdminDB exists because SQLite deserves a proper web admin UI, and desktop tools
|
|
64
|
+
(DBeaver, DB Browser for SQLite) live outside both your browser and your stack.
|
|
65
|
+
Web admin tools like phpMyAdmin target MySQL/Postgres, not SQLite. This one is
|
|
66
|
+
server-rendered, so there is no frontend build step and nothing extra to deploy
|
|
67
|
+
— the same Express process serves pages, assets, and the JSON API. Run it
|
|
68
|
+
standalone from the CLI, or mount it under any path of an existing Express app
|
|
69
|
+
on the same port.
|
|
43
70
|
|
|
44
71
|
## Install
|
|
45
72
|
|
|
73
|
+
### Try it (no install)
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
npx admindb -p 8080 # run on port 8080 without installing
|
|
77
|
+
npx admindb ./app.db # open a database file directly
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Install as a standalone CLI tool
|
|
81
|
+
|
|
82
|
+
Requires **Node.js ≥ 20**:
|
|
83
|
+
|
|
46
84
|
```bash
|
|
47
|
-
npm install admindb
|
|
85
|
+
npm install -g admindb
|
|
86
|
+
admindb # starts the server → open http://localhost:3000
|
|
48
87
|
```
|
|
49
88
|
|
|
50
|
-
|
|
89
|
+
The `admindb` command starts the built-in server and prints the URL to open in
|
|
90
|
+
your browser. See the [CLI reference](#cli-reference) for `--port`,
|
|
91
|
+
`--open <file>`, `--dir <folder>`, `--readonly`, and more.
|
|
51
92
|
|
|
52
|
-
|
|
93
|
+
### Embed AdminDB in your own app
|
|
53
94
|
|
|
54
|
-
AdminDB is an Express app you can mount inside your own application, under
|
|
55
|
-
|
|
95
|
+
AdminDB is an Express app you can mount inside your own application, under your
|
|
96
|
+
own path, on the same port as the rest of your server.
|
|
56
97
|
|
|
57
|
-
|
|
98
|
+
#### Minimal example
|
|
58
99
|
|
|
59
100
|
```ts
|
|
60
101
|
import express from 'express';
|
|
@@ -73,7 +114,7 @@ app.listen(3000);
|
|
|
73
114
|
`createRouter(options)` returns a fully wired Express app (pages + JSON API +
|
|
74
115
|
static assets + view engine). Mounting it is just `app.use('/path', router)`.
|
|
75
116
|
|
|
76
|
-
|
|
117
|
+
#### Options
|
|
77
118
|
|
|
78
119
|
| Option | Type | Description |
|
|
79
120
|
| ---------- | -------------------- | -------------------------------------------------------------- |
|
|
@@ -83,6 +124,8 @@ static assets + view engine). Mounting it is just `app.use('/path', router)`.
|
|
|
83
124
|
| `basePath` | `string` | URL prefix used by templates/assets (e.g. `/admin`). Pass the same prefix you mount at |
|
|
84
125
|
| `logger` | `Logger` | Custom logger (see `createLogger`) |
|
|
85
126
|
| `logLevel` | `'debug'\|'info'\|'warn'\|'error'` | Log verbosity (used when no logger is passed) |
|
|
127
|
+
| `allowBrowse` | `boolean` | Manager mode: show the filesystem file-browser on the databases page. Set `false` to disable it (e.g. when the server was started with specific database files). Default: `true` |
|
|
128
|
+
| `browseRoot` | `string` | Manager mode: restrict the file-browser to this folder (absolute path) — it cannot navigate above it and only databases inside it can be opened |
|
|
86
129
|
| `readonly` | `boolean` | Open the database(s) **read-only**: every write is rejected (403), write controls are disabled in the UI, and a banner is shown. The DB file is opened with `SQLITE_OPEN_READONLY` + `PRAGMA query_only` as a belt-and-suspenders guard. Default: `false` |
|
|
87
130
|
|
|
88
131
|
Example with a custom logger and prefix:
|
|
@@ -100,7 +143,7 @@ app.use('/tools/db', createRouter({
|
|
|
100
143
|
app.listen(3000);
|
|
101
144
|
```
|
|
102
145
|
|
|
103
|
-
|
|
146
|
+
#### Multiple databases
|
|
104
147
|
|
|
105
148
|
Pass a `DbManager` to manage several database files — either from a directory,
|
|
106
149
|
from an explicit list of file paths, or both:
|
|
@@ -113,9 +156,9 @@ const app = express();
|
|
|
113
156
|
app.use('/admin', createRouter({
|
|
114
157
|
manager: new DbManager(
|
|
115
158
|
{
|
|
116
|
-
dir: './data',
|
|
159
|
+
dir: './data', // scan a directory
|
|
117
160
|
files: ['/srv/legacy/app.db', './shared.sqlite'], // and/or explicit paths
|
|
118
|
-
readonly: true,
|
|
161
|
+
readonly: true, // open all databases read-only
|
|
119
162
|
},
|
|
120
163
|
createLogger('info'),
|
|
121
164
|
),
|
|
@@ -130,224 +173,229 @@ In multi-db mode:
|
|
|
130
173
|
`/admin/app.db/tables/users` and `/admin/app.db/api/tables`,
|
|
131
174
|
- file names that collide across sources are deduped (`name__2.db`).
|
|
132
175
|
|
|
176
|
+
### CLI reference
|
|
177
|
+
|
|
178
|
+
The standalone server is a full web app. With no arguments it runs in
|
|
179
|
+
**manager mode**: a **Databases** landing page where you can browse the
|
|
180
|
+
filesystem and open any SQLite database file (`.db` / `.sqlite` / `.sqlite3`),
|
|
181
|
+
or create new ones.
|
|
182
|
+
|
|
183
|
+
| Flag | Description |
|
|
184
|
+
| -------------------- | -------------------------------------------------------- |
|
|
185
|
+
| `-p, --port <port>` | Port to listen on (default `3000`) |
|
|
186
|
+
| `-H, --host <host>` | Host / interface to bind (default `0.0.0.0`) |
|
|
187
|
+
| `-o, --open <file>` | Open a single database file directly |
|
|
188
|
+
| `-d, --dir <dir>` | Manage a folder of database files |
|
|
189
|
+
| `--files <list>` | Comma-separated database file paths to manage |
|
|
190
|
+
| `-b, --base-path <p>`| URL prefix to serve under (default `/`) |
|
|
191
|
+
| `-r, --readonly` | Open databases read-only (all writes disabled) |
|
|
192
|
+
| `-l, --log-level <l>`| `debug` \| `info` \| `warn` \| `error` (default `info`) |
|
|
193
|
+
| `-h, --help` | Show help |
|
|
194
|
+
| `-v, --version` | Show the version |
|
|
195
|
+
|
|
196
|
+
A positional `path` argument opens a database file directly, or manages a
|
|
197
|
+
folder when it is a directory.
|
|
198
|
+
|
|
199
|
+
Every flag has a matching environment variable; **flags override the
|
|
200
|
+
environment**:
|
|
201
|
+
|
|
202
|
+
| Variable | Default | Description |
|
|
203
|
+
| ----------- | ------- | ------------------------------------ |
|
|
204
|
+
| `PORT` | `3000` | Port to listen on |
|
|
205
|
+
| `HOST` | `0.0.0.0` | Host / interface to bind |
|
|
206
|
+
| `DB_PATH` | — | Single SQLite database file |
|
|
207
|
+
| `DB_DIR` | — | Folder of `.db`/`.sqlite` files |
|
|
208
|
+
| `DB_FILES` | — | Comma-separated explicit database file paths |
|
|
209
|
+
| `READONLY` | — | `1` / `true` / `yes` / `on` opens the database(s) read-only |
|
|
210
|
+
| `BASE_PATH` | `''` | URL prefix (e.g. `/admin`) |
|
|
211
|
+
| `LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error` |
|
|
212
|
+
|
|
213
|
+
Examples:
|
|
214
|
+
|
|
215
|
+
```bash
|
|
216
|
+
admindb # manager UI on http://localhost:3000
|
|
217
|
+
admindb -p 8080 # same, on port 8080
|
|
218
|
+
admindb ./data/app.db # open a single database file
|
|
219
|
+
admindb --open ~/notes.sqlite # open a file directly
|
|
220
|
+
admindb -d ./dbs # manage a folder of databases
|
|
221
|
+
admindb --files a.db,b.db -r # open two files read-only
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
```powershell
|
|
225
|
+
$env:DB_DIR='./db'; npm start # PowerShell
|
|
226
|
+
# bash/zsh: DB_DIR=./db npm start
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
When the server runs without an explicit single file, the **Databases** landing
|
|
230
|
+
page lists the managed databases and includes an **"Open an existing
|
|
231
|
+
database"** file browser: navigate folders, pick a database file, and open it.
|
|
232
|
+
Opened files are added to the list so you can switch between databases freely.
|
|
233
|
+
|
|
234
|
+
**File-browser policy:**
|
|
235
|
+
|
|
236
|
+
- When a **folder** is given (`--dir`, a directory path, or `DB_DIR`), browsing
|
|
237
|
+
is limited to that folder — it cannot navigate above it and only databases
|
|
238
|
+
inside it can be opened.
|
|
239
|
+
- When specific **files** are given (`--files`, or `DB_FILES`) without a folder,
|
|
240
|
+
file browsing is **disabled** entirely; only the configured databases are
|
|
241
|
+
listed.
|
|
242
|
+
- With no folder or files, browsing is unrestricted.
|
|
243
|
+
|
|
133
244
|
## Features
|
|
134
245
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
246
|
+
### 🔍 Browse & edit rows
|
|
247
|
+
|
|
248
|
+
- **Table browser** — every table with pagination, sorting (click a column
|
|
249
|
+
header), a sticky header, and per-row actions; composite primary keys are
|
|
250
|
+
supported (values are URL-encoded and comma-joined in the row endpoints).
|
|
251
|
+
- **Type-aware filters** — per-column filter controls: foreign-key dropdowns,
|
|
252
|
+
boolean toggles, date and numeric range inputs, plus the exact (`=value`),
|
|
253
|
+
comparison (`>5`, `<=10`), prefix (`pre*`) and substring (plain text)
|
|
254
|
+
operators on text columns. Filters survive sorting and pagination.
|
|
140
255
|
- **Inline (spreadsheet-style) editing** — double-click any cell to edit it in
|
|
141
256
|
place with a type-aware control (FK dropdown, boolean toggle, date picker,
|
|
142
257
|
number/text input). Changes are staged and highlighted in the grid, then
|
|
143
258
|
applied all at once in a single transaction, or discarded.
|
|
144
|
-
- Insert and delete rows (full CRUD). FK columns become dropdowns
|
|
259
|
+
- **Insert and delete rows** (full CRUD). FK columns become dropdowns; insert
|
|
260
|
+
forms pre-fill column defaults from the schema.
|
|
145
261
|
- **Bulk row operations** — select rows with checkboxes (or "select all"), then
|
|
146
262
|
**delete** them in one transaction (with a warning listing how many rows in
|
|
147
263
|
other tables reference them) or **export** only the selected rows as CSV/JSON.
|
|
148
|
-
- **
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
- **
|
|
159
|
-
|
|
160
|
-
|
|
264
|
+
- **Related rows** — every table that has a foreign key pointing at a table gets
|
|
265
|
+
its own column at the end of that table's grid; each cell shows how many of its
|
|
266
|
+
rows reference that record. Click it to open a nested table with all of the
|
|
267
|
+
referencing table's columns and data for that specific record.
|
|
268
|
+
|
|
269
|
+
### ⚡ Query & run SQL
|
|
270
|
+
|
|
271
|
+
- **Arbitrary SQL runner** — SELECTs render as a table, `COUNT` queries show a
|
|
272
|
+
readable summary, and write statements execute and report affected rows.
|
|
273
|
+
- **Saved named queries** — save a query and reload it from a dropdown.
|
|
274
|
+
- **"Get query" / preview mode** — generate `CREATE` / `INSERT` / `UPDATE` SQL
|
|
275
|
+
from the UI without executing it. The preview modes only return the SQL
|
|
276
|
+
string; they never touch the database.
|
|
277
|
+
- **SQL dump** — export the whole database as a downloadable `CREATE` + `INSERT`
|
|
278
|
+
SQL file.
|
|
279
|
+
|
|
280
|
+
### 🗂️ Design & manage schema
|
|
281
|
+
|
|
282
|
+
- **Visual table designer** — create a table with name, type, primary key,
|
|
283
|
+
not-null / unique, default value, and foreign-key references, with a live
|
|
284
|
+
`CREATE TABLE` SQL preview.
|
|
285
|
+
- **Schema editor** — rename the table, add / rename / drop columns, and drop
|
|
286
|
+
tables, with relationship-safety checks: drops are refused when the column is
|
|
287
|
+
a primary key, has a UNIQUE constraint, is used by an index, is part of a
|
|
288
|
+
foreign key, or is referenced by another table's foreign key. Tables
|
|
289
|
+
referenced by other tables cannot be dropped. Internal (`_`-prefixed) tables
|
|
290
|
+
cannot be renamed or dropped.
|
|
291
|
+
- **Indexes** — create indexes (plain or unique, on one or many columns — pick
|
|
161
292
|
columns in order, with a live `CREATE INDEX` SQL preview) and drop them from
|
|
162
|
-
the schema editor; automatic SQLite indexes are
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
- **
|
|
293
|
+
the schema editor; automatic SQLite (primary-key/unique) indexes are
|
|
294
|
+
protected.
|
|
295
|
+
|
|
296
|
+
### 🔄 Import, export & seed data
|
|
297
|
+
|
|
298
|
+
- **Export** — table rows or query results as **CSV or JSON** (a whole table or
|
|
299
|
+
only selected rows).
|
|
300
|
+
- **CSV import** — paste or upload CSV into a table; the header must match
|
|
301
|
+
existing columns, and the import runs in a single transaction (a failed row
|
|
302
|
+
rolls everything back).
|
|
303
|
+
- **Seed data generator** — fill a table with realistic rows in one go. Each
|
|
304
|
+
column gets an auto-detected strategy (first/last/full name, email, phone,
|
|
305
|
+
city, country, UUID, random integer/decimal/date/datetime/boolean/bytes, a few
|
|
306
|
+
words, a sentence, a fixed value, a random value from a list, or "skip — let
|
|
307
|
+
the DB default apply"); foreign-key columns can sample real values from the
|
|
308
|
+
referenced table. Insert up to 5,000 rows transactionally, or preview the
|
|
309
|
+
generated `INSERT` SQL without executing it.
|
|
310
|
+
|
|
311
|
+
### 🚀 Deploy
|
|
312
|
+
|
|
313
|
+
- **Read-only mode** — open the database(s) without write access: the file is
|
|
168
314
|
opened `SQLITE_OPEN_READONLY` + `query_only`, every write route returns `403`,
|
|
169
315
|
and the UI hides/disables all write controls and shows a banner.
|
|
170
|
-
- **
|
|
316
|
+
- **Standalone CLI / file browser** — `admindb` runs as a full web app; with no
|
|
317
|
+
arguments it opens a **Databases** landing page where you can browse the
|
|
318
|
+
filesystem and open any SQLite database file, or create new ones. Flags set
|
|
319
|
+
the port, open a file, manage a folder, and more (`admindb --help`).
|
|
320
|
+
- **Multiple databases** — directory scanning and/or explicit file lists, each
|
|
171
321
|
with its own workspace under `/{db}/…`.
|
|
172
322
|
|
|
173
|
-
##
|
|
174
|
-
|
|
175
|
-
Home dashboard — stat cards and the table list.
|
|
176
|
-
|
|
177
|
-

|
|
178
|
-
|
|
179
|
-
Table browser — sortable columns, sticky header, and per-row actions.
|
|
180
|
-
|
|
181
|
-

|
|
182
|
-
|
|
183
|
-
Query editor — line-numbered editor with a results table.
|
|
184
|
-
|
|
185
|
-

|
|
186
|
-
|
|
187
|
-
Table designer — visual columns with a live SQL preview.
|
|
188
|
-
|
|
189
|
-

|
|
190
|
-
|
|
191
|
-
Insert / edit form — column defaults are pre-filled.
|
|
323
|
+
## Security warning
|
|
192
324
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
325
|
+
> ⚠️ **This tool exposes full, unauthenticated database AND filesystem access.**
|
|
326
|
+
> Every page and API route (browse, edit, delete, run arbitrary SQL, change the
|
|
327
|
+
> schema, export the whole database, and — in manager mode — browse the
|
|
328
|
+
> filesystem to open database files) is available to **anyone who can reach the
|
|
329
|
+
> server**.
|
|
330
|
+
>
|
|
331
|
+
> - **No authentication or authorization is built in.** The routes are **not
|
|
332
|
+
> protected**.
|
|
333
|
+
> - **It is your responsibility to protect access.** Do **not** expose
|
|
334
|
+
> AdminDB to the public internet or to untrusted networks.
|
|
335
|
+
> - Recommended ways to protect it:
|
|
336
|
+
> - bind the standalone server to `127.0.0.1` (`HOST=127.0.0.1`) and use it
|
|
337
|
+
> only from your own machine, and/or
|
|
338
|
+
> - run it behind a reverse proxy that requires authentication (Basic auth,
|
|
339
|
+
> OAuth, mTLS, …) or inside a VPN / private network.
|
|
340
|
+
>
|
|
341
|
+
> Treat AdminDB as if it were a remote `sqlite3` shell with write access.
|
|
206
342
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
343
|
+
## API
|
|
344
|
+
|
|
345
|
+
All routes live under `basePath` and return the consistent shape
|
|
346
|
+
`{ success, data?, error? }`. In multi-db mode, every route is scoped under the
|
|
347
|
+
database, e.g. `/api/app.db/tables`.
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
GET /api/tables List tables
|
|
351
|
+
GET /api/tables/:table/rows Paginated rows (filters, sorting)
|
|
352
|
+
POST /api/tables/:table/rows Insert row
|
|
353
|
+
PUT /api/tables/:table/row/:id Update row
|
|
354
|
+
DELETE /api/tables/:table/row/:id Delete row
|
|
355
|
+
POST /api/query Run arbitrary SQL
|
|
356
|
+
POST /api/tables Create table
|
|
357
|
+
GET /api/tables/:table/export Download all rows as csv|json
|
|
358
|
+
POST /api/tables/:table/seed Generate and insert seed rows
|
|
211
359
|
```
|
|
212
360
|
|
|
213
|
-
|
|
361
|
+
Plus bulk row operations, CSV import, schema and index management, saved
|
|
362
|
+
queries, a data generator — and, in manager mode, database-file management and
|
|
363
|
+
the filesystem browser.
|
|
214
364
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
| `HOST` | `0.0.0.0` | Host / interface to bind |
|
|
219
|
-
| `DB_PATH` | `admindb.db` | Single SQLite database file |
|
|
220
|
-
| `DB_DIR` | — | Multi-db source 1: a directory of `.db`/`.sqlite` files |
|
|
221
|
-
| `DB_FILES` | — | Multi-db source 2: comma-separated explicit database file paths |
|
|
222
|
-
| `READONLY` | — | `1` / `true` / `yes` / `on` opens the database(s) read-only |
|
|
223
|
-
| `BASE_PATH` | `''` | URL prefix (e.g. `/admin`) |
|
|
224
|
-
| `LOG_LEVEL` | `info` | `debug` \| `info` \| `warn` \| `error` |
|
|
225
|
-
|
|
226
|
-
Multi-db mode activates when `DB_DIR` and/or `DB_FILES` is set:
|
|
227
|
-
|
|
228
|
-
```powershell
|
|
229
|
-
$env:DB_DIR='./db'; npm start # PowerShell
|
|
230
|
-
# bash/zsh: DB_DIR=./db npm start
|
|
231
|
-
```
|
|
365
|
+
> **Full reference:** every endpoint (including seed config/generate, bulk
|
|
366
|
+
> update/delete/export, and the multi-db manager endpoints) is documented in
|
|
367
|
+
> **[`docs/API.md`](docs/API.md)**.
|
|
232
368
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
| Method | Path | Purpose |
|
|
236
|
-
| ------ | ---------------------------------------- | -------------------------------- |
|
|
237
|
-
| GET | `/api/tables` | List tables |
|
|
238
|
-
| GET | `/api/tables/:table/info` | Column + FK metadata, PK columns |
|
|
239
|
-
| GET | `/api/tables/:table/fk-options` | Values for FK dropdowns |
|
|
240
|
-
| GET | `/api/tables/:table/rows?page&limit&f` | Paginated rows (`f` = URL-encoded JSON filters — legacy strings like `{"age":">35"}` or structured conditions like `{"balance":{"op":"gte","value":"100"}}`) |
|
|
241
|
-
| GET | `/api/tables/:table/row/:id` | Single row by (encoded) PK |
|
|
242
|
-
| POST | `/api/tables/:table/rows` | Insert row |
|
|
243
|
-
| POST | `/api/tables/:table/rows/generate` | Generate INSERT SQL (no execute) |
|
|
244
|
-
| POST | `/api/tables/:table/rows/import` | Import CSV (`{ csv }`, header row must match columns) |
|
|
245
|
-
| GET | `/api/tables/:table/export?format=` | Download all rows as `csv` or `json` |
|
|
246
|
-
| PUT | `/api/tables/:table/row/:id` | Update row (`{ values, nulls? }` — `nulls` explicitly sets columns to NULL) |
|
|
247
|
-
| PUT | `/api/tables/:table/row/:id/generate` | Generate UPDATE SQL (no execute) |
|
|
248
|
-
| DELETE | `/api/tables/:table/row/:id` | Delete row |
|
|
249
|
-
| POST | `/api/tables/:table/rows/bulk-impact` | FK-impact preview: how many rows in other tables reference the selected rows |
|
|
250
|
-
| POST | `/api/tables/:table/rows/bulk-delete` | Delete selected rows (`{ ids, confirmImpact }`; transactional) |
|
|
251
|
-
| POST | `/api/tables/:table/rows/bulk-export` | Export only the selected rows as `csv`/`json` (`{ ids, format }`) |
|
|
252
|
-
| POST | `/api/tables/:table/rows/bulk-update` | Apply staged inline edits (`{ updates: [{ id, values?, nulls? }] }`; transactional) |
|
|
253
|
-
| POST | `/api/tables` | Create table |
|
|
254
|
-
| POST | `/api/tables/generate` | Generate CREATE SQL (no execute) |
|
|
255
|
-
| GET | `/api/tables/:table/schema` | Full schema (constraints, indexes, FK refs) |
|
|
256
|
-
| POST | `/api/tables/:table/rename` | Rename the table |
|
|
257
|
-
| POST | `/api/tables/:table/columns` | Add a column |
|
|
258
|
-
| PUT | `/api/tables/:table/columns/:column` | Rename a column |
|
|
259
|
-
| DELETE | `/api/tables/:table/columns/:column` | Drop a column (safety-checked) |
|
|
260
|
-
| DELETE | `/api/tables/:table` | Drop the table (safety-checked) |
|
|
261
|
-
| POST | `/api/tables/:table/indexes` | Create an index (`{ name?, columns[], unique? }`) |
|
|
262
|
-
| DELETE | `/api/tables/:table/indexes/:index` | Drop an index (auto indexes refused) |
|
|
263
|
-
| POST | `/api/query` | Run arbitrary SQL |
|
|
264
|
-
| POST | `/api/query/export` | Run a SELECT and download as `csv`/`json` |
|
|
265
|
-
| GET | `/api/queries` | List saved queries |
|
|
266
|
-
| POST | `/api/queries` | Save a named query |
|
|
267
|
-
| DELETE | `/api/queries/:id` | Delete a saved query |
|
|
268
|
-
|
|
269
|
-
In multi-db mode, every route is scoped under the database, e.g.
|
|
270
|
-
`/api/app.db/tables`. Every API response uses the consistent shape
|
|
271
|
-
`{ success, data?, error? }`.
|
|
272
|
-
|
|
273
|
-
## Behaviour notes
|
|
369
|
+
**Behaviour notes:**
|
|
274
370
|
|
|
275
371
|
- **Empty input = "not set".** Empty form fields are omitted so DB defaults
|
|
276
|
-
apply; `0` is a valid value and is never treated as empty.
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
`CURRENT_TIMESTAMP`-style defaults) so you can see and adjust them.
|
|
280
|
-
- **Row filters.** The filter panel adapts to each column's type: foreign keys
|
|
281
|
-
become dropdowns (with a "not set / NULL" option), booleans become
|
|
282
|
-
any/true/false toggles, and dates and numbers become min/max range inputs.
|
|
283
|
-
Text columns keep the operator syntax: exact match (`=value`), comparison
|
|
284
|
-
(`>5`, `>=5`, `<5`, `<=5`, `!=value`), prefix (`pre*`) and case-insensitive
|
|
285
|
-
substring (plain text). Filters are carried in the URL (as legacy strings or
|
|
286
|
-
structured conditions) and survive sorting and pagination.
|
|
372
|
+
apply; `0` is a valid value and is never treated as empty. Insert forms
|
|
373
|
+
pre-fill column defaults from the schema (string/number/boolean literals and
|
|
374
|
+
`CURRENT_TIMESTAMP`-style defaults).
|
|
287
375
|
- **Inline editing is staged, not instant.** Double-click a cell to edit it in
|
|
288
376
|
place; edits are buffered locally and highlighted in the grid rather than
|
|
289
|
-
written immediately. Press **Apply** to write every pending change
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
only the selected rows. Both delete and export are capped at 1000 rows per
|
|
299
|
-
batch.
|
|
300
|
-
- **CSV import.** The first row must be a header whose names match existing
|
|
301
|
-
columns (unknown or duplicate names are rejected). Empty cells are treated as
|
|
302
|
-
"not set" so database defaults apply. The whole import runs in a single
|
|
303
|
-
transaction — a failed row rolls everything back.
|
|
304
|
-
- **Indexes.** Creating an index takes one or more columns and an optional
|
|
305
|
-
unique flag (the index name is optional too). Only explicitly created indexes
|
|
306
|
-
(`origin = 'c'`) can be dropped from the UI — automatic primary-key/unique
|
|
307
|
-
indexes are protected.
|
|
308
|
-
- **Schema editor.** Drops are refused when the column is a primary key, has a
|
|
309
|
-
UNIQUE constraint, is used by an index, is part of a foreign key, or is
|
|
310
|
-
referenced by another table's foreign key. Tables referenced by other tables
|
|
311
|
-
cannot be dropped. Internal (`_`-prefixed) tables cannot be renamed or dropped.
|
|
377
|
+
written immediately. Press **Apply** to write every pending change in a single
|
|
378
|
+
transaction (the page then reloads so related-row counts stay accurate), or
|
|
379
|
+
**Discard** to revert. Clearing a text/date/number field stages a `NULL`.
|
|
380
|
+
- **Bulk operations** run per page with "select all"; delete first shows an
|
|
381
|
+
FK-impact warning (rows may be cascaded away or orphaned depending on the
|
|
382
|
+
foreign-key action, and the delete can fail if a constraint blocks it). Both
|
|
383
|
+
delete and export are capped at 1000 rows per batch.
|
|
384
|
+
- **CSV import** runs in a single transaction — a failed row rolls everything
|
|
385
|
+
back.
|
|
312
386
|
- **Identifiers are quoted and string values escaped** everywhere SQL is built,
|
|
313
|
-
so generated SQL is correct and safe
|
|
387
|
+
so generated SQL is correct and safe; **"Get query" never executes** — it only
|
|
388
|
+
returns the generated SQL string.
|
|
314
389
|
- **`COUNT` queries** return a readable summary message instead of a table.
|
|
315
|
-
- **"Get query" never executes** — it only returns the generated SQL string.
|
|
316
390
|
- **Internal table** `_saved_queries` stores saved queries and is kept out of
|
|
317
391
|
user-facing FK pickers. Schema initialization is idempotent and safe to run
|
|
318
392
|
repeatedly.
|
|
319
|
-
- Composite primary keys are supported (values are URL-encoded and comma-joined
|
|
320
|
-
in the row endpoints).
|
|
321
|
-
|
|
322
|
-
## Development
|
|
323
|
-
|
|
324
|
-
```bash
|
|
325
|
-
npm install
|
|
326
|
-
npm run build # TypeScript → dist + Tailwind CSS
|
|
327
|
-
npm run dev # tsx watch server + Tailwind watch
|
|
328
|
-
npm test # builds and runs the unit tests
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
`npm test` compiles TypeScript to `dist/` and runs the `node:test` suite
|
|
332
|
-
covering the SQL generator (INSERT / UPDATE / CREATE output, type mapping,
|
|
333
|
-
quoting, rejection of unsupported types), the SQL classifier, CSV parsing and
|
|
334
|
-
serialization, row filters (legacy and structured conditions), the database
|
|
335
|
-
layer (pagination, transactions, bulk update/delete, read-only enforcement),
|
|
336
|
-
and the database manager.
|
|
337
|
-
|
|
338
|
-
## Publishing to npm
|
|
339
393
|
|
|
340
|
-
|
|
341
|
-
and the `LICENSE`. When you are ready to publish:
|
|
342
|
-
|
|
343
|
-
```bash
|
|
344
|
-
npm run build # happens automatically via the prepack script
|
|
345
|
-
npm login
|
|
346
|
-
npm publish
|
|
347
|
-
```
|
|
394
|
+
## Contributing
|
|
348
395
|
|
|
349
|
-
|
|
350
|
-
and
|
|
396
|
+
PRs are welcome. Development workflow (`npm run dev` for live reload, `npm test`
|
|
397
|
+
to build and run the unit suite), project layout, and contribution guidelines
|
|
398
|
+
live in **[`CONTRIBUTING.md`](CONTRIBUTING.md)**.
|
|
351
399
|
|
|
352
400
|
## License
|
|
353
401
|
|
package/dist/app.d.ts
CHANGED
|
@@ -15,6 +15,18 @@ export interface AppOptions {
|
|
|
15
15
|
manager?: DbManager;
|
|
16
16
|
/** Open the database read-only — all write routes are rejected with 403. */
|
|
17
17
|
readonly?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Manager mode: show the filesystem file-browser on the databases landing
|
|
20
|
+
* page. Defaults to `true`. Set to `false` to disable browsing (e.g. when the
|
|
21
|
+
* server was started with specific database files only).
|
|
22
|
+
*/
|
|
23
|
+
allowBrowse?: boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Manager mode: restrict the file-browser to this folder (absolute path).
|
|
26
|
+
* When set, the browser cannot navigate above it and only databases inside it
|
|
27
|
+
* can be opened.
|
|
28
|
+
*/
|
|
29
|
+
browseRoot?: string;
|
|
18
30
|
/** Internal: URL of the databases list (used by per-db apps to link "switch database"). */
|
|
19
31
|
databasesUrl?: string;
|
|
20
32
|
/** Internal: current database id (for locals/display). */
|