refactor(plugins): async DB-touching methods; transactions through UnitOfWork

This commit is contained in:
jubnl
2026-09-22 00:00:53 +02:00
parent e413308227
commit e28dc6de28
68 changed files with 743 additions and 706 deletions
@@ -39,7 +39,7 @@ export class PluginFrameController {
constructor(private readonly runtime: PluginRuntimeService) {}
@Get('*path')
serve(@Param('pluginId') pluginId: string, @Req() req: Request, @Res() res: Response): void {
async serve(@Param('pluginId') pluginId: string, @Req() req: Request, @Res() res: Response): Promise<void> {
if (!pluginsEnabled() || !this.runtime.isActive(pluginId)) {
res.status(404).send('Plugin not available');
return;
@@ -87,7 +87,7 @@ export class PluginFrameController {
// The sandbox + per-plugin CSP are the isolation boundary here, not CORP:
// these files are the plugin's own public client code.
res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin');
res.setHeader('Content-Security-Policy', this.frameCsp(pluginId, req.get('host')));
res.setHeader('Content-Security-Policy', await this.frameCsp(pluginId, req.get('host')));
// Explicit { root } + basename, not the absolute path: under the Nest
// ExpressAdapter, res.sendFile(absolutePath) resolves against the rewritten
// req.url and 404s spuriously (same trap as files-download.controller.ts).
@@ -95,7 +95,7 @@ export class PluginFrameController {
}
/** Per-plugin, locked-down CSP for the sandboxed frame document. */
private frameCsp(pluginId: string, host: string | undefined): string {
private async frameCsp(pluginId: string, host: string | undefined): Promise<string> {
// The frame must be able to reach exactly what the CHILD may reach. The child's egress
// guard is the union of the manifest's http:outbound:<host> grants AND the hosts an admin
// added post-install for an operatorEgress plugin (plugin-runtime.service: activate()).
@@ -108,7 +108,7 @@ export class PluginFrameController {
// admin writer's EGRESS_HOST_RE), but never interpolate anything that isn't a clean
// host/wildcard into connect-src — a stray space or `*` would inject an extra CSP source.
const outbound = [
...new Set([...this.runtime.outboundHostsOf(pluginId), ...this.runtime.operatorEgressHosts(pluginId)]),
...new Set([...(await this.runtime.outboundHostsOf(pluginId)), ...(await this.runtime.operatorEgressHosts(pluginId))]),
].filter((h) => /^(\*\.[a-z0-9-]+(\.[a-z0-9-]+)+|[a-z0-9-]+(\.[a-z0-9-]+)*)$/i.test(h));
// The frame runs at an OPAQUE origin (sandbox without allow-same-origin), so
// 'self' matches nothing and the plugin's own <script src>/<link> files would