mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(plugins): boot enabled plugins after the rpc-registry scan, not before
PluginRuntimeService booted enabled plugins from onModuleInit, but Nest fires
same-module onModuleInit hooks in providers-array order, where the runtime
precedes PluginRpcRegistryService — so every boot-activated plugin's rpc host
was bound from a still-empty registry and its first RPC (typically db.migrate
in onLoad) came back PERMISSION_DENIED on every cold boot, until an admin
deactivated and reactivated it by hand. Move the boot reconcile to
onApplicationBootstrap, which is guaranteed to run after every module's
onModuleInit, registry scan included.
Also fix the denial message, which interpolated the plugin id where the
permission belonged ('db.migrate requires a permission "featured-guides" was
not granted'); it now names both the missing permission and the plugin.
This commit is contained in:
@@ -148,9 +148,9 @@ describe('PluginRuntimeService (M2 end-to-end)', () => {
|
||||
// first activate is covered by the 'counter' happy-path test above.)
|
||||
});
|
||||
|
||||
it('onModuleInit is a no-op when the runtime is disabled', () => {
|
||||
it('onApplicationBootstrap is a no-op when the runtime is disabled', () => {
|
||||
process.env.TREK_PLUGINS_ENABLED = 'false';
|
||||
expect(() => createPluginRuntime(new DatabaseService(dbConn)).onModuleInit()).not.toThrow();
|
||||
expect(() => createPluginRuntime(new DatabaseService(dbConn)).onApplicationBootstrap()).not.toThrow();
|
||||
process.env.TREK_PLUGINS_ENABLED = 'true';
|
||||
});
|
||||
|
||||
@@ -246,26 +246,26 @@ describe('PluginRuntimeService (M2 end-to-end)', () => {
|
||||
expect(testDb.prepare("SELECT COUNT(*) c FROM plugin_user_erasure_queue WHERE plugin_id='counter' AND user_id=9").get()).toMatchObject({ c: 0 });
|
||||
});
|
||||
|
||||
it('onModuleInit boots every ENABLED plugin — even one left in error state', async () => {
|
||||
it('onApplicationBootstrap boots every ENABLED plugin — even one left in error state', async () => {
|
||||
fs.mkdirSync(path.join(codeRoot, 'booter', 'server'), { recursive: true });
|
||||
fs.writeFileSync(path.join(codeRoot, 'booter', 'server', 'index.js'), 'module.exports = { async onLoad() {} };');
|
||||
// status='error' from a previous crash, but enabled=1 → must still boot
|
||||
testDb.prepare("INSERT INTO plugins (id, status, enabled, granted_permissions, config) VALUES ('booter','error',1,'[]','{}')").run();
|
||||
|
||||
const rt = createPluginRuntime(new DatabaseService(dbConn));
|
||||
rt.onModuleInit(); // fire-and-forget spawn
|
||||
rt.onApplicationBootstrap(); // fire-and-forget spawn
|
||||
for (let i = 0; i < 40 && !rt.isActive('booter'); i++) await new Promise((r) => setTimeout(r, 50));
|
||||
expect(rt.isActive('booter')).toBe(true);
|
||||
await rt.deactivate('booter');
|
||||
});
|
||||
|
||||
it('onModuleInit does NOT boot a disabled plugin', async () => {
|
||||
it('onApplicationBootstrap does NOT boot a disabled plugin', async () => {
|
||||
fs.mkdirSync(path.join(codeRoot, 'sleeper', 'server'), { recursive: true });
|
||||
fs.writeFileSync(path.join(codeRoot, 'sleeper', 'server', 'index.js'), 'module.exports = { async onLoad() {} };');
|
||||
testDb.prepare("INSERT INTO plugins (id, status, enabled, granted_permissions, config) VALUES ('sleeper','inactive',0,'[]','{}')").run();
|
||||
|
||||
const rt = createPluginRuntime(new DatabaseService(dbConn));
|
||||
rt.onModuleInit();
|
||||
rt.onApplicationBootstrap();
|
||||
await new Promise((r) => setTimeout(r, 300));
|
||||
expect(rt.isActive('sleeper')).toBe(false);
|
||||
});
|
||||
@@ -701,7 +701,7 @@ describe('TREK host-version gating', () => {
|
||||
process.env.APP_VERSION = '4.0.0';
|
||||
seedRanged('boot-broken', '>=3.2.0 <4.0.0', 1);
|
||||
const rt = createPluginRuntime(new DatabaseService(dbConn));
|
||||
expect(() => rt.onModuleInit()).not.toThrow();
|
||||
expect(() => rt.onApplicationBootstrap()).not.toThrow();
|
||||
for (let i = 0; i < 40; i++) {
|
||||
const row = testDb.prepare("SELECT enabled FROM plugins WHERE id='boot-broken'").get() as { enabled: number };
|
||||
if (row.enabled === 0) break;
|
||||
|
||||
Reference in New Issue
Block a user