Files
Toju/server/src/routes/plugin-support.ts
2026-04-29 01:14:30 +02:00

149 lines
4.1 KiB
TypeScript

import { Response, Router } from 'express';
import {
deletePluginEventDefinition,
deletePluginRequirement,
getPluginRequirementsSnapshot,
PluginSupportError,
upsertPluginEventDefinition,
upsertPluginRequirement
} from '../services/plugin-support.service';
import { broadcastToServer } from '../websocket/broadcast';
const router = Router();
function sendPluginSupportError(error: unknown, res: Response): void {
if (error instanceof PluginSupportError) {
res.status(error.status).json({ error: error.message, errorCode: error.code });
return;
}
console.error('Unhandled plugin support error:', error);
res.status(500).json({ error: 'Internal server error', errorCode: 'INTERNAL_ERROR' });
}
function readActorUserId(value: unknown): string {
return typeof value === 'string' ? value.trim() : '';
}
async function broadcastRequirementsSnapshot(serverId: string): Promise<void> {
const snapshot = await getPluginRequirementsSnapshot(serverId);
broadcastToServer(serverId, {
type: 'plugin_requirements_changed',
serverId,
snapshot
});
}
router.get('/:serverId/plugins', async (req, res) => {
try {
res.json(await getPluginRequirementsSnapshot(req.params.serverId));
} catch (error) {
sendPluginSupportError(error, res);
}
});
router.put('/:serverId/plugins/:pluginId/requirement', async (req, res) => {
const { serverId, pluginId } = req.params;
try {
const requirement = await upsertPluginRequirement({
actorUserId: readActorUserId(req.body.actorUserId),
installUrl: req.body.installUrl,
manifest: req.body.manifest,
pluginId,
reason: req.body.reason,
serverId,
sourceUrl: req.body.sourceUrl,
status: req.body.status,
versionRange: req.body.versionRange
});
await broadcastRequirementsSnapshot(serverId);
res.json({ requirement });
} catch (error) {
sendPluginSupportError(error, res);
}
});
router.delete('/:serverId/plugins/:pluginId/requirement', async (req, res) => {
const { serverId, pluginId } = req.params;
try {
await deletePluginRequirement({
actorUserId: readActorUserId(req.body.actorUserId),
pluginId,
serverId
});
await broadcastRequirementsSnapshot(serverId);
res.json({ ok: true });
} catch (error) {
sendPluginSupportError(error, res);
}
});
router.put('/:serverId/plugins/:pluginId/events/:eventName', async (req, res) => {
const { serverId, pluginId, eventName } = req.params;
try {
const eventDefinition = await upsertPluginEventDefinition({
actorUserId: readActorUserId(req.body.actorUserId),
direction: req.body.direction,
eventName,
maxPayloadBytes: req.body.maxPayloadBytes,
pluginId,
rateLimitJson: req.body.rateLimitJson,
schemaJson: req.body.schemaJson,
scope: req.body.scope,
serverId
});
await broadcastRequirementsSnapshot(serverId);
res.json({ eventDefinition });
} catch (error) {
sendPluginSupportError(error, res);
}
});
router.delete('/:serverId/plugins/:pluginId/events/:eventName', async (req, res) => {
const { serverId, pluginId, eventName } = req.params;
try {
await deletePluginEventDefinition({
actorUserId: readActorUserId(req.body.actorUserId),
eventName,
pluginId,
serverId
});
await broadcastRequirementsSnapshot(serverId);
res.json({ ok: true });
} catch (error) {
sendPluginSupportError(error, res);
}
});
router.get('/:serverId/plugins/:pluginId/data', (_req, res) => {
res.status(410).json({
error: 'Plugin data persistence is disabled on the signal server',
errorCode: 'PLUGIN_DATA_DISABLED'
});
});
router.put('/:serverId/plugins/:pluginId/data/:key', (_req, res) => {
res.status(410).json({
error: 'Plugin data persistence is disabled on the signal server',
errorCode: 'PLUGIN_DATA_DISABLED'
});
});
router.delete('/:serverId/plugins/:pluginId/data/:key', (_req, res) => {
res.status(410).json({
error: 'Plugin data persistence is disabled on the signal server',
errorCode: 'PLUGIN_DATA_DISABLED'
});
});
export default router;