Add internal daemon routes and service management scripts
This commit is contained in:
@@ -7,6 +7,7 @@ import dbPlugin from './plugins/db.js';
|
||||
import authPlugin from './plugins/auth.js';
|
||||
import authRoutes from './routes/auth/index.js';
|
||||
import organizationRoutes from './routes/organizations/index.js';
|
||||
import internalRoutes from './routes/internal/index.js';
|
||||
import daemonNodeRoutes from './routes/nodes/daemon.js';
|
||||
import nodeRoutes from './routes/nodes/index.js';
|
||||
import serverRoutes from './routes/servers/index.js';
|
||||
@@ -85,6 +86,7 @@ await app.register(authRoutes, { prefix: '/api/auth' });
|
||||
await app.register(organizationRoutes, { prefix: '/api/organizations' });
|
||||
await app.register(adminRoutes, { prefix: '/api/admin' });
|
||||
await app.register(daemonNodeRoutes, { prefix: '/api/nodes' });
|
||||
await app.register(internalRoutes, { prefix: '/api/internal' });
|
||||
|
||||
// Nested org routes: nodes and servers are scoped to an org
|
||||
await app.register(
|
||||
|
||||
@@ -0,0 +1,72 @@
|
||||
import { Type } from '@sinclair/typebox';
|
||||
import type { FastifyInstance, FastifyRequest } from 'fastify';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { nodes } from '@source/database';
|
||||
import { AppError } from '../../lib/errors.js';
|
||||
|
||||
function extractBearerToken(authHeader?: string): string | null {
|
||||
if (!authHeader) return null;
|
||||
const [scheme, token] = authHeader.split(' ');
|
||||
if (!scheme || !token || scheme.toLowerCase() !== 'bearer') return null;
|
||||
return token;
|
||||
}
|
||||
|
||||
async function requireDaemonToken(app: FastifyInstance, request: FastifyRequest): Promise<void> {
|
||||
const token = extractBearerToken(
|
||||
typeof request.headers.authorization === 'string'
|
||||
? request.headers.authorization
|
||||
: undefined,
|
||||
);
|
||||
|
||||
if (!token) {
|
||||
throw AppError.unauthorized('Missing daemon bearer token', 'DAEMON_AUTH_MISSING');
|
||||
}
|
||||
|
||||
const node = await app.db.query.nodes.findFirst({
|
||||
where: eq(nodes.daemonToken, token),
|
||||
columns: { id: true },
|
||||
});
|
||||
|
||||
if (!node) {
|
||||
throw AppError.unauthorized('Invalid daemon token', 'DAEMON_AUTH_INVALID');
|
||||
}
|
||||
}
|
||||
|
||||
export default async function internalRoutes(app: FastifyInstance) {
|
||||
app.get('/schedules/due', async (request) => {
|
||||
await requireDaemonToken(app, request);
|
||||
return { tasks: [] };
|
||||
});
|
||||
|
||||
app.post(
|
||||
'/schedules/:taskId/ack',
|
||||
{
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
taskId: Type.String(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (request) => {
|
||||
await requireDaemonToken(app, request);
|
||||
const { taskId } = request.params as { taskId: string };
|
||||
return { success: true, taskId };
|
||||
},
|
||||
);
|
||||
|
||||
app.post(
|
||||
'/servers/:serverUuid/backup',
|
||||
{
|
||||
schema: {
|
||||
params: Type.Object({
|
||||
serverUuid: Type.String(),
|
||||
}),
|
||||
},
|
||||
},
|
||||
async (request) => {
|
||||
await requireDaemonToken(app, request);
|
||||
const { serverUuid } = request.params as { serverUuid: string };
|
||||
return { success: true, serverUuid };
|
||||
},
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user