feat: plugins v1
This commit is contained in:
208
server/src/routes/plugin-support.ts
Normal file
208
server/src/routes/plugin-support.ts
Normal file
@@ -0,0 +1,208 @@
|
||||
import { Response, Router } from 'express';
|
||||
import {
|
||||
deletePluginData,
|
||||
deletePluginEventDefinition,
|
||||
deletePluginRequirement,
|
||||
getPluginRequirementsSnapshot,
|
||||
listPluginData,
|
||||
PluginSupportError,
|
||||
upsertPluginData,
|
||||
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),
|
||||
pluginId,
|
||||
reason: req.body.reason,
|
||||
serverId,
|
||||
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', async (req, res) => {
|
||||
const { serverId, pluginId } = req.params;
|
||||
|
||||
try {
|
||||
const records = await listPluginData({
|
||||
actorUserId: readActorUserId(req.query.userId),
|
||||
key: req.query.key,
|
||||
ownerId: req.query.ownerId,
|
||||
pluginId,
|
||||
scope: req.query.scope,
|
||||
serverId
|
||||
});
|
||||
|
||||
res.json({ records });
|
||||
} catch (error) {
|
||||
sendPluginSupportError(error, res);
|
||||
}
|
||||
});
|
||||
|
||||
router.put('/:serverId/plugins/:pluginId/data/:key', async (req, res) => {
|
||||
const { serverId, pluginId, key } = req.params;
|
||||
|
||||
try {
|
||||
const record = await upsertPluginData({
|
||||
actorUserId: readActorUserId(req.body.actorUserId),
|
||||
key,
|
||||
ownerId: req.body.ownerId,
|
||||
pluginId,
|
||||
schemaVersion: req.body.schemaVersion,
|
||||
scope: req.body.scope,
|
||||
serverId,
|
||||
value: req.body.value
|
||||
});
|
||||
|
||||
broadcastToServer(serverId, {
|
||||
type: 'plugin_data_changed',
|
||||
serverId,
|
||||
pluginId: record.pluginId,
|
||||
scope: record.scope,
|
||||
ownerId: record.ownerId,
|
||||
key: record.key,
|
||||
updatedAt: record.updatedAt
|
||||
});
|
||||
|
||||
res.json({ record });
|
||||
} catch (error) {
|
||||
sendPluginSupportError(error, res);
|
||||
}
|
||||
});
|
||||
|
||||
router.delete('/:serverId/plugins/:pluginId/data/:key', async (req, res) => {
|
||||
const { serverId, pluginId, key } = req.params;
|
||||
const scope = req.body.scope ?? req.query.scope;
|
||||
const ownerId = req.body.ownerId ?? req.query.ownerId;
|
||||
|
||||
try {
|
||||
await deletePluginData({
|
||||
actorUserId: readActorUserId(req.body.actorUserId),
|
||||
key,
|
||||
ownerId,
|
||||
pluginId,
|
||||
scope,
|
||||
serverId
|
||||
});
|
||||
|
||||
broadcastToServer(serverId, {
|
||||
type: 'plugin_data_changed',
|
||||
serverId,
|
||||
pluginId,
|
||||
scope: typeof scope === 'string' ? scope : 'server',
|
||||
ownerId: typeof ownerId === 'string' && ownerId.trim() ? ownerId.trim() : undefined,
|
||||
key,
|
||||
updatedAt: Date.now()
|
||||
});
|
||||
|
||||
res.json({ ok: true });
|
||||
} catch (error) {
|
||||
sendPluginSupportError(error, res);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user