plugins: enable, disable, delete — and uninstall is gone
Three states all read as "stopped": disabled, uninstalled, and uninstalled-with-the-directory-still- there. Nothing on screen distinguished them, and the one that mattered was invisible — an uninstalled plugin kept its directory, which silently decided what the next install would run. That is how a jellyfin install on alpha re-applied a checkout from two days earlier while reporting success at every step. So uninstall stops being a verb. What it did survives as the first half of deleting: it stops the sidecar, removes the install row and the PM2 entry, unpublishes the copies, and revokes grants naming permissions that are about to stop existing. Delete is offered only on a plugin that is not running — disable is one reversible click, so a live plugin is always two deliberate steps from gone. It opens a confirmation carrying a checkbox, "also delete all its data", unticked and never inherited from last time. Unticked, the directory goes and the rows stay, and they appear in the orphan list further down the same screen. Ticked, the tables go with it, which is the only way to a machine that has never had the plugin. The checkbox picks between two ROUTES, not a body flag on one: a flag can be added to a request by anything that already knows how to call the safe verb, and the difference here is somebody's rows. Grants are revoked either way, which is load-bearing until the permissions work tomorrow: a grant naming a key the platform no longer recognises made the whole permissions screen unsaveable, because the page submits every grant it loaded. Also corrected two rationales that the change made false — the runbook's "uninstall never destroys data" verification table, and npm-deps.ts explaining directory survival in terms of uninstall. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -78,9 +78,11 @@ Music added the field; see its PLUGIN.md for what it is guarding against.
|
||||
**Nothing may branch on provenance** except `mountPrefix()`. First-party and third-party differing
|
||||
anywhere else means two systems, and only one gets tested.
|
||||
|
||||
**Uninstall never destroys data.** The generated schema barrel follows plugin **directories**, not the
|
||||
install table — `db:push` drops what it cannot see, so following installs would delete a plugin's tables
|
||||
on uninstall. Only deleting a plugin's source can lose its data.
|
||||
**Only an explicit tick destroys data.** The generated schema barrel follows plugin **directories**, not
|
||||
the install table — `db:push` drops what it cannot see, so following installs would delete a plugin's
|
||||
tables the moment it was stopped. Deleting a plugin removes its directory, and the confirmation's
|
||||
"also delete all its data" checkbox is the one thing that drops its tables. Unticked, the rows outlive
|
||||
the plugin and show up in the orphan list on the same screen.
|
||||
|
||||
---
|
||||
|
||||
@@ -125,9 +127,9 @@ Then through `/plugins`, watching PM2 and the browser at each step:
|
||||
| permissions page | its permission is listed, read/write/none |
|
||||
| disable | route 404s, sidecar stops, **tables and rows survive** |
|
||||
| enable | comes back |
|
||||
| uninstall | route gone, `pm2 list` loses it, **data still there** |
|
||||
| `bun db:push` while uninstalled | **do not run this — see "What changed on 2026-08-16"** |
|
||||
| install again | identical to the first install |
|
||||
| delete, checkbox unticked | route gone, `pm2 list` loses it, directory gone, **data still there** |
|
||||
| install again | fresh clone, and it finds those rows |
|
||||
| delete, checkbox ticked | tables dropped too — a machine that never had it |
|
||||
|
||||
A normal refresh is enough; the shell is `no-store`. When the log's last line appears, the bundle exists.
|
||||
|
||||
@@ -220,15 +222,21 @@ no terminal it applies NOTHING and exits 0, so an install reports success and th
|
||||
query with 42P01. `--force` would be worse if it worked: the destructive statements are `drop table` for
|
||||
every plugin whose directory is absent.
|
||||
|
||||
So: the row in the verification table that says to run `bun db:push` while uninstalled is struck out. The
|
||||
property it was checking — uninstall does not destroy data — is now checked by reinstalling and finding
|
||||
your rows still there.
|
||||
So: the row in the verification table that said to run `bun db:push` while stopped is gone. The property
|
||||
it was checking — stopping a plugin does not destroy data — is now checked by deleting it with the
|
||||
checkbox unticked, installing again, and finding your rows still there.
|
||||
|
||||
**Use `purge` to test the install twice.** Uninstall deliberately keeps the directory and the tables, so a
|
||||
second install is not a fresh one: the marketplace hides a plugin whose directory exists, and the tables
|
||||
are already there. The Marketplace screen has "Delete <plugin> and all its data" — it drops the tables,
|
||||
deletes the directory and regenerates the barrel, and afterwards the plugin installs from the catalogue
|
||||
exactly as a stranger's machine would. **That is the only honest test of an install.**
|
||||
**Delete WITH the checkbox to test the install twice.** Anything less is not a fresh install: the
|
||||
marketplace hides a plugin whose directory exists, and tables that are already there make `db:push` a
|
||||
no-op, so a broken schema stays broken and passes. Ticked, it drops the tables, deletes the directory and
|
||||
regenerates the barrel — and afterwards the plugin installs from the catalogue exactly as a stranger's
|
||||
machine would. **That is the only honest test of an install.**
|
||||
|
||||
**Uninstall was removed on 2026-08-21.** It sat between disable and delete, keeping the directory and the
|
||||
data, and the screen could not show the difference: an uninstalled plugin stayed in the list under a
|
||||
heading that said "Installed" while its directory silently decided what the next install would run. That
|
||||
is not hypothetical — it is how a jellyfin install on alpha re-applied a checkout from two days earlier,
|
||||
reporting success at every step. The verbs are now enable, disable and delete.
|
||||
|
||||
**The install now verifies its own tables.** After the push it asks Postgres whether each declared table
|
||||
exists and fails the install naming what is missing. If your extraction reports "schema push reported
|
||||
|
||||
Reference in New Issue
Block a user