Point a failed discovery at the stale plugins/ copy, and document upgrading
CI / full-gate (push) Successful in 2m39s
CI / full-gate (push) Successful in 2m39s
This commit is contained in:
@@ -67,6 +67,18 @@ for (const c of badCases) {
|
||||
});
|
||||
}
|
||||
|
||||
// The reader of a discovery failure is usually an operator whose plugins/ copy went stale after an
|
||||
// upgrade, not the author of the manifest — so the message has to carry the remedy, not just the
|
||||
// rule. A pre-existing `plugins/admin` gating on the old `admin` permission is exactly this case.
|
||||
test("a discovery failure tells the operator their plugins/ copy may just be out of date", async (t) => {
|
||||
const dir = scaffold(t, { "admin/plugin.ts": `export default { apiVersion: "1.0.0", routes: [{ method: "GET", path: "/users", permission: "admin", handler: () => ({ html: "x" }) }] };` });
|
||||
await assert.rejects(discoverPlugins({ dir }), (err: Error) => {
|
||||
assert.match(err.message, /gates on "admin"/); // what is wrong
|
||||
assert.match(err.message, /re-copy it/); // …and what to do about it
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
test("a route + nav node may be marked public and load fine", async (t) => {
|
||||
const dir = scaffold(t, { "pub/plugin.ts": `export default { apiVersion: "1.0.0", nav: [{ href: "/pub", id: "n", label: "N", public: true }], routes: [{ method: "GET", path: "/", public: true, handler: () => ({ html: "x" }) }] };` });
|
||||
const plugins = await discoverPlugins({ dir });
|
||||
|
||||
@@ -65,7 +65,14 @@ export async function discoverPlugins(options: DiscoverOptions = {}): Promise<Pl
|
||||
}
|
||||
|
||||
if (errors.length) {
|
||||
throw new Error(`Plugin discovery failed:\n${errors.map((e) => ` - ${e}`).join("\n")}`);
|
||||
// `plugins/` is a drop-in mount the operator owns, so the reader of this message often didn't
|
||||
// write the manifest — they copied it. Tightening a contract rule breaks those copies at boot,
|
||||
// and the rule alone doesn't tell them the remedy is one command.
|
||||
throw new Error(
|
||||
`Plugin discovery failed:\n${errors.map((e) => ` - ${e}`).join("\n")}\n` +
|
||||
`A plugin under plugins/ is your own copy. If it came from examples/, re-copy it — ` +
|
||||
`the host contract may have changed since (see README → Upgrading).`,
|
||||
);
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user