feat(plugins): activation, HTTP route proxy + instance settings (M2)

Wires the isolated runtime into TREK. Admins can now activate a plugin from the
panel and its HTTP routes work end to end, still behind the kill switch.

- PluginRuntimeService owns the supervisor: activate spawns the child with its
  granted permissions + decrypted instance config, deactivate kills it, status
  and errors are persisted to the plugins / plugin_error_log tables, and active
  plugins are booted on startup (OnModuleInit).
- Bidirectional RPC: the child now handles host→child invokes (routes/jobs) and
  reports its declared routes on load; the supervisor gained invoke()/routesOf().
- /api/plugins/:id/* proxy controller — a single static route that matches the
  plugin's declared routes, enforces per-route auth (auth:false routes are public
  for OAuth callbacks/webhooks), forwards only a whitelisted request view (never
  the session cookie), and strips unsafe response headers.
- Admin endpoints: POST :id/activate, POST :id/deactivate, GET/PUT :id/config —
  instance settings with secret fields encrypted (apiKeyCrypto) and masked.
- Kill switch moved to its own module so it never collides with test config mocks.

Photo/calendar hook consumers are deferred to a later slice.
This commit is contained in:
mauriceboe
2026-07-03 16:50:23 +02:00
parent 14b348581a
commit d823ac443b
13 changed files with 775 additions and 29 deletions
+7 -5
View File
@@ -1,14 +1,16 @@
import { Module } from '@nestjs/common';
import { PluginsController } from './plugins.controller';
import { PluginsProxyController } from './plugins-proxy.controller';
import { PluginsService } from './plugins.service';
import { PluginRuntimeService } from './plugin-runtime.service';
/**
* Plugin system (#plugins). M0 registers only the read side; the isolated
* runtime supervisor, install pipeline and registry service are added in later
* milestones under this same module.
* Plugin system (#plugins). M0 read side + M2 isolated runtime: the runtime
* service owns the process supervisor and boots active plugins on startup; the
* proxy controller forwards /api/plugins/:id/* to the isolated child.
*/
@Module({
controllers: [PluginsController],
providers: [PluginsService],
controllers: [PluginsController, PluginsProxyController],
providers: [PluginsService, PluginRuntimeService],
})
export class PluginsModule {}