chore: sync local workspace changes

This commit is contained in:
2026-05-07 11:03:47 +09:00
parent 2df0ba30cb
commit 82c0d8a197
217 changed files with 44873 additions and 1678 deletions

View File

@@ -2,16 +2,45 @@ import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify';
import { z } from 'zod';
import { env } from '../config/env.js';
import { listServerCommands, restartServerCommand, serverCommandKeys } from '../services/server-command-service.js';
import {
cancelServerRestartReservation,
confirmServerRestartReservation,
getRestartReservationWorkloadSummary,
getServerRestartReservation,
scheduleServerRestartReservation,
} from '../services/server-restart-reservation-service.js';
const serverCommandParamSchema = z.object({
key: z.enum(serverCommandKeys),
});
const restartReservationBodySchema = z.object({
autoExecuteDelaySeconds: z.number().int().min(1).max(300).optional(),
});
function getRequestAccessToken(request: FastifyRequest) {
const tokenHeader = request.headers['x-access-token'];
return Array.isArray(tokenHeader) ? tokenHeader[0]?.trim() ?? '' : String(tokenHeader ?? '').trim();
}
function getRequestClientId(request: FastifyRequest) {
const clientIdHeader = request.headers['x-client-id'];
return Array.isArray(clientIdHeader) ? clientIdHeader[0]?.trim() ?? '' : String(clientIdHeader ?? '').trim();
}
function getRequestAppOrigin(request: FastifyRequest) {
const appOriginHeader = request.headers['x-app-origin'];
const appOrigin = Array.isArray(appOriginHeader) ? appOriginHeader[0] : appOriginHeader;
if (appOrigin?.trim()) {
return appOrigin.trim();
}
const originHeader = request.headers.origin;
const origin = Array.isArray(originHeader) ? originHeader[0] : originHeader;
return origin?.trim() ?? '';
}
function ensureAuthorized(request: FastifyRequest, reply: FastifyReply) {
if (getRequestAccessToken(request) === env.SERVER_COMMAND_ACCESS_TOKEN) {
return true;
@@ -42,6 +71,25 @@ export async function registerServerCommandRoutes(app: FastifyInstance) {
}
const { key } = serverCommandParamSchema.parse(request.params);
if (key === 'test' || key === 'work-server') {
const workloadSummary = await getRestartReservationWorkloadSummary();
const pendingCount =
workloadSummary.codexRunningCount
+ workloadSummary.codexQueuedCount
+ workloadSummary.automationRunningCount
+ workloadSummary.automationQueuedCount;
if (pendingCount > 0) {
reply.status(409);
return {
ok: false,
message: `진행 중인 Codex Live/자동화 작업 ${pendingCount}건이 있어 즉시 재기동할 수 없습니다. 재기동 예약을 사용해 주세요.`,
workloadSummary,
};
}
}
const result = await restartServerCommand(key);
return {
@@ -51,4 +99,64 @@ export async function registerServerCommandRoutes(app: FastifyInstance) {
restartState: result.restartState,
};
});
app.get('/api/server-commands/restart-reservation', async (request, reply) => {
if (!ensureAuthorized(request, reply)) {
return;
}
return {
ok: true,
item: await getServerRestartReservation(),
};
});
app.put('/api/server-commands/restart-reservation', async (request, reply) => {
if (!ensureAuthorized(request, reply)) {
return;
}
let payload: unknown = request.body ?? {};
if (typeof payload === 'string') {
try {
payload = JSON.parse(payload);
} catch {
payload = {};
}
}
const parsed = restartReservationBodySchema.parse(payload ?? {});
return {
ok: true,
item: await scheduleServerRestartReservation({
clientId: getRequestClientId(request),
appOrigin: getRequestAppOrigin(request),
autoExecuteDelaySeconds: parsed.autoExecuteDelaySeconds,
}),
};
});
app.post('/api/server-commands/restart-reservation/confirm', async (request, reply) => {
if (!ensureAuthorized(request, reply)) {
return;
}
return {
ok: true,
item: await confirmServerRestartReservation(app.log),
};
});
app.delete('/api/server-commands/restart-reservation', async (request, reply) => {
if (!ensureAuthorized(request, reply)) {
return;
}
return {
ok: true,
item: await cancelServerRestartReservation(),
};
});
}