feat: eslint 적용 및 관련 코드 일괄 수정

This commit is contained in:
2026-01-05 15:46:47 +00:00
parent cb312f02b3
commit c965b1120f
387 changed files with 39808 additions and 38800 deletions
@@ -5,11 +5,7 @@ import { createGamePostgresConnector, resolvePostgresConfigFromEnv } from '@samm
import type { BuildRunner } from './buildRunner.js';
import type { ProcessManager } from './processManager.js';
import type {
GatewayProfileRecord,
GatewayProfileRepository,
GatewayProfileStatus,
} from './profileRepository.js';
import type { GatewayProfileRecord, GatewayProfileRepository, GatewayProfileStatus } from './profileRepository.js';
import type { GitWorkspaceManager } from './workspaceManager.js';
export interface GatewayProcessConfig {
@@ -58,12 +54,7 @@ export const planProfileReconcile = (
status: GatewayProfileStatus,
runtime: ProfileRuntimeState
): { shouldStart: boolean; shouldStop: boolean } => {
if (
status === 'RUNNING' ||
status === 'PREOPEN' ||
status === 'PAUSED' ||
status === 'COMPLETED'
) {
if (status === 'RUNNING' || status === 'PREOPEN' || status === 'PAUSED' || status === 'COMPLETED') {
return {
shouldStart: !(runtime.apiRunning && runtime.daemonRunning),
shouldStop: false,
@@ -97,8 +88,7 @@ interface GatewayAdminActionResult {
const isRecord = (value: unknown): value is Record<string, unknown> =>
Boolean(value) && typeof value === 'object' && !Array.isArray(value);
const normalizeMeta = (value: unknown): Record<string, unknown> =>
isRecord(value) ? value : {};
const normalizeMeta = (value: unknown): Record<string, unknown> => (isRecord(value) ? value : {});
const normalizeStatus = (value: unknown): GatewayAdminActionStatus | null => {
if (typeof value === 'string') {
@@ -108,16 +98,9 @@ const normalizeStatus = (value: unknown): GatewayAdminActionStatus | null => {
};
const buildActionKey = (action: GatewayAdminActionRecord): string =>
[
action.action ?? '',
action.requestedAt ?? '',
action.scheduledAt ?? '',
action.reason ?? '',
].join('|');
[action.action ?? '', action.requestedAt ?? '', action.scheduledAt ?? '', action.reason ?? ''].join('|');
const parseScenarioId = (
value: string | number | null | undefined
): number | null => {
const parseScenarioId = (value: string | number | null | undefined): number | null => {
if (typeof value === 'number' && Number.isFinite(value)) {
return Math.floor(value);
}
@@ -136,8 +119,10 @@ const buildProcessName = (profileName: string, role: 'api' | 'daemon'): string =
const buildProcessDefinitions = (
profile: GatewayProfileRecord,
config: GatewayProcessConfig
): { api: { name: string; script: string; cwd: string; env: Record<string, string> };
daemon: { name: string; script: string; cwd: string; env: Record<string, string> } } => {
): {
api: { name: string; script: string; cwd: string; env: Record<string, string> };
daemon: { name: string; script: string; cwd: string; env: Record<string, string> };
} => {
const baseEnv = { ...(config.baseEnv ?? {}) };
const apiName = buildProcessName(profile.profileName, 'api');
const daemonName = buildProcessName(profile.profileName, 'daemon');
@@ -176,10 +161,7 @@ const buildProcessDefinitions = (
};
};
const mapRuntimeStates = (
profileNames: string[],
processNames: Map<string, boolean>
): ProfileRuntimeSnapshot[] =>
const mapRuntimeStates = (profileNames: string[], processNames: Map<string, boolean>): ProfileRuntimeSnapshot[] =>
profileNames.map((profileName) => {
const apiName = buildProcessName(profileName, 'api');
const daemonName = buildProcessName(profileName, 'daemon');
@@ -227,22 +209,10 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
start(): void {
void this.reconcileNow();
void this.runAdminActionsNow();
this.reconcileTimer = setInterval(
() => void this.reconcileNow(),
this.reconcileIntervalMs
);
this.scheduleTimer = setInterval(
() => void this.runScheduleNow(),
this.scheduleIntervalMs
);
this.buildTimer = setInterval(
() => void this.runBuildQueueNow(),
this.buildIntervalMs
);
this.adminActionTimer = setInterval(
() => void this.runAdminActionsNow(),
this.adminActionIntervalMs
);
this.reconcileTimer = setInterval(() => void this.reconcileNow(), this.reconcileIntervalMs);
this.scheduleTimer = setInterval(() => void this.runScheduleNow(), this.scheduleIntervalMs);
this.buildTimer = setInterval(() => void this.runBuildQueueNow(), this.buildIntervalMs);
this.adminActionTimer = setInterval(() => void this.runAdminActionsNow(), this.adminActionIntervalMs);
}
async stop(): Promise<void> {
@@ -313,8 +283,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
);
continue;
}
const queued =
profile.buildStatus === 'QUEUED' || profile.buildStatus === 'RUNNING';
const queued = profile.buildStatus === 'QUEUED' || profile.buildStatus === 'RUNNING';
if (!queued) {
await this.repository.updateBuildStatus(profile.profileName, 'QUEUED', {
requestedAt: now.toISOString(),
@@ -325,11 +294,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
}
const profiles = await this.repository.listProfiles();
for (const profile of profiles) {
if (
profile.status === 'PREOPEN' &&
profile.openAt &&
new Date(profile.openAt) <= now
) {
if (profile.status === 'PREOPEN' && profile.openAt && new Date(profile.openAt) <= now) {
await this.repository.updateStatus(profile.profileName, 'RUNNING', {
preopenAt: profile.preopenAt ?? null,
openAt: profile.openAt ?? null,
@@ -363,10 +328,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
startedAt,
error: null,
});
const result = await this.runBuildCommands(
queued.profileName,
queued.buildCommitSha
);
const result = await this.runBuildCommands(queued.profileName, queued.buildCommitSha);
const completedAt = this.now().toISOString();
if (result.ok) {
await this.repository.updateBuildStatus(queued.profileName, 'SUCCEEDED', {
@@ -376,9 +338,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
if (queued.status === 'RESERVED') {
await this.repository.updateStatus(
queued.profileName,
queued.openAt && new Date(queued.openAt) <= this.now()
? 'RUNNING'
: 'PREOPEN',
queued.openAt && new Date(queued.openAt) <= this.now() ? 'RUNNING' : 'PREOPEN',
{
preopenAt: queued.preopenAt ?? null,
openAt: queued.openAt ?? null,
@@ -418,13 +378,9 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
}
}
private async handleProfileAdminActions(
profile: GatewayProfileRecord
): Promise<void> {
private async handleProfileAdminActions(profile: GatewayProfileRecord): Promise<void> {
const meta = normalizeMeta(profile.meta);
const rawActions = Array.isArray(meta.adminActions)
? meta.adminActions
: [];
const rawActions = Array.isArray(meta.adminActions) ? meta.adminActions : [];
if (!rawActions.length) {
return;
}
@@ -442,10 +398,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
return;
}
const updates = new Map<
string,
{ status: GatewayAdminActionStatus; detail?: string; handledAt: string }
>();
const updates = new Map<string, { status: GatewayAdminActionStatus; detail?: string; handledAt: string }>();
for (const action of pending) {
if (action.action !== 'RESET_NOW' && action.action !== 'RESET_SCHEDULED') {
@@ -528,9 +481,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
return { status: 'FAILED', detail: 'scenarioId is missing' };
}
const seedTime =
action.scheduledAt && action.action === 'RESET_SCHEDULED'
? new Date(action.scheduledAt)
: this.now();
action.scheduledAt && action.action === 'RESET_SCHEDULED' ? new Date(action.scheduledAt) : this.now();
const startedAt = this.now().toISOString();
await this.repository.updateStatus(profile.profileName, 'STOPPED');
await this.stopProfile(profile);
@@ -646,10 +597,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
async cleanupStaleWorkspaces(): Promise<{ removed: string[]; skipped: string[] }> {
const profiles = await this.repository.listProfiles();
const cutoff = this.computeCutoffDate(6);
const workspaceMap = new Map<
string,
{ profileNames: string[]; lastUsedAt?: Date; hasActiveBuild: boolean }
>();
const workspaceMap = new Map<string, { profileNames: string[]; lastUsedAt?: Date; hasActiveBuild: boolean }>();
for (const profile of profiles) {
const workspace = profile.buildWorkspace;
if (!workspace) {
@@ -733,8 +681,7 @@ export class GatewayOrchestrator implements GatewayOrchestratorHandle {
const statusMap = new Map<string, boolean>();
for (const process of processes) {
const status = process.status.toLowerCase();
const running =
status === 'online' || status === 'launching' || status === 'stopping';
const running = status === 'online' || status === 'launching' || status === 'stopping';
statusMap.set(process.name, running);
}
return statusMap;
@@ -9,9 +9,7 @@ import { resolveWorkspaceRoot } from './workspaceRoot.js';
import { GitWorkspaceManager } from './workspaceManager.js';
export const buildEnvMap = (env: NodeJS.ProcessEnv): Record<string, string> => {
const entries = Object.entries(env).filter(
(entry): entry is [string, string] => typeof entry[1] === 'string'
);
const entries = Object.entries(env).filter((entry): entry is [string, string] => typeof entry[1] === 'string');
return Object.fromEntries(entries);
};
@@ -9,16 +9,10 @@ import { createGatewayOrchestrator } from './orchestratorFactory.js';
export const runGatewayOrchestrator = async (): Promise<void> => {
const config = resolveGatewayOrchestratorConfigFromEnv();
const postgres = createGatewayPostgresConnector(
resolvePostgresConfigFromEnv({ schema: config.dbSchema })
);
const postgres = createGatewayPostgresConnector(resolvePostgresConfigFromEnv({ schema: config.dbSchema }));
await postgres.connect();
const { orchestrator } = createGatewayOrchestrator(
postgres.prisma as GatewayPrismaClient,
config,
process.env
);
const { orchestrator } = createGatewayOrchestrator(postgres.prisma as GatewayPrismaClient, config, process.env);
const stop = async (reason: string): Promise<void> => {
console.info(`[gateway-orchestrator] stopping: ${reason}`);
@@ -11,13 +11,7 @@ export const GATEWAY_PROFILE_STATUSES = [
] as const;
export type GatewayProfileStatus = (typeof GATEWAY_PROFILE_STATUSES)[number];
export const GATEWAY_BUILD_STATUSES = [
'IDLE',
'QUEUED',
'RUNNING',
'FAILED',
'SUCCEEDED',
] as const;
export const GATEWAY_BUILD_STATUSES = ['IDLE', 'QUEUED', 'RUNNING', 'FAILED', 'SUCCEEDED'] as const;
export type GatewayBuildStatus = (typeof GATEWAY_BUILD_STATUSES)[number];
export interface GatewayProfileRecord {
@@ -81,23 +75,15 @@ export interface GatewayProfileRepository {
lastUsedAt?: string | null;
}
): Promise<GatewayProfileRecord | null>;
updateMeta(
profileName: string,
meta: Record<string, unknown>
): Promise<GatewayProfileRecord | null>;
updateMeta(profileName: string, meta: Record<string, unknown>): Promise<GatewayProfileRecord | null>;
listReservedToStart(now: Date): Promise<GatewayProfileRecord[]>;
findQueuedBuild(): Promise<GatewayProfileRecord | null>;
updateLastError(profileName: string, lastError: string | null): Promise<void>;
updateWorkspaceUsage(
profileName: string,
workspace: string,
lastUsedAt: string
): Promise<void>;
updateWorkspaceUsage(profileName: string, workspace: string, lastUsedAt: string): Promise<void>;
clearWorkspaceUsage(profileNames: string[]): Promise<void>;
}
const toIso = (value: Date | null): string | undefined =>
value ? value.toISOString() : undefined;
const toIso = (value: Date | null): string | undefined => (value ? value.toISOString() : undefined);
type GatewayProfileRow = {
profileName: string;
@@ -145,12 +131,9 @@ const mapProfile = (row: GatewayProfileRow): GatewayProfileRecord => ({
updatedAt: row.updatedAt.toISOString(),
});
const buildProfileName = (profile: string, scenario: string): string =>
`${profile}:${scenario}`;
const buildProfileName = (profile: string, scenario: string): string => `${profile}:${scenario}`;
export const createGatewayProfileRepository = (
prisma: GatewayPrismaClient
): GatewayProfileRepository => ({
export const createGatewayProfileRepository = (prisma: GatewayPrismaClient): GatewayProfileRepository => ({
async listProfiles(): Promise<GatewayProfileRecord[]> {
const rows = await prisma.gatewayProfile.findMany({
orderBy: [{ profile: 'asc' }, { scenario: 'asc' }],
@@ -175,34 +158,21 @@ export const createGatewayProfileRepository = (
status: input.status ?? 'STOPPED',
preopenAt: input.preopenAt ? new Date(input.preopenAt) : null,
openAt: input.openAt ? new Date(input.openAt) : null,
scheduledStartAt: input.scheduledStartAt
? new Date(input.scheduledStartAt)
: null,
scheduledStartAt: input.scheduledStartAt ? new Date(input.scheduledStartAt) : null,
buildCommitSha: input.buildCommitSha ?? null,
meta: (input.meta ?? {}) as GatewayPrisma.JsonObject,
},
update: {
apiPort: input.apiPort,
status: input.status,
preopenAt: input.preopenAt
? new Date(input.preopenAt)
: input.preopenAt === null
? null
: undefined,
openAt: input.openAt
? new Date(input.openAt)
: input.openAt === null
? null
: undefined,
preopenAt: input.preopenAt ? new Date(input.preopenAt) : input.preopenAt === null ? null : undefined,
openAt: input.openAt ? new Date(input.openAt) : input.openAt === null ? null : undefined,
scheduledStartAt: input.scheduledStartAt
? new Date(input.scheduledStartAt)
: input.scheduledStartAt === null
? null
: undefined,
buildCommitSha:
input.buildCommitSha === undefined
? undefined
: input.buildCommitSha,
buildCommitSha: input.buildCommitSha === undefined ? undefined : input.buildCommitSha,
meta: input.meta ? (input.meta as GatewayPrisma.JsonObject) : undefined,
},
});
@@ -229,11 +199,7 @@ export const createGatewayProfileRepository = (
? new Date(schedule.preopenAt)
: null,
openAt:
schedule?.openAt === undefined
? undefined
: schedule?.openAt
? new Date(schedule.openAt)
: null,
schedule?.openAt === undefined ? undefined : schedule?.openAt ? new Date(schedule.openAt) : null,
scheduledStartAt:
schedule?.scheduledStartAt === undefined
? undefined
@@ -262,10 +228,8 @@ export const createGatewayProfileRepository = (
where: { profileName },
data: {
buildStatus: status,
buildCommitSha:
fields?.commitSha === undefined ? undefined : fields.commitSha,
buildWorkspace:
fields?.workspace === undefined ? undefined : fields.workspace,
buildCommitSha: fields?.commitSha === undefined ? undefined : fields.commitSha,
buildWorkspace: fields?.workspace === undefined ? undefined : fields.workspace,
buildLastUsedAt:
fields?.lastUsedAt === undefined
? undefined
@@ -279,11 +243,7 @@ export const createGatewayProfileRepository = (
? new Date(fields.requestedAt)
: null,
buildStartedAt:
fields?.startedAt === undefined
? undefined
: fields?.startedAt
? new Date(fields.startedAt)
: null,
fields?.startedAt === undefined ? undefined : fields?.startedAt ? new Date(fields.startedAt) : null,
buildCompletedAt:
fields?.completedAt === undefined
? undefined
@@ -295,10 +255,7 @@ export const createGatewayProfileRepository = (
});
return row ? mapProfile(row) : null;
},
async updateMeta(
profileName: string,
meta: Record<string, unknown>
): Promise<GatewayProfileRecord | null> {
async updateMeta(profileName: string, meta: Record<string, unknown>): Promise<GatewayProfileRecord | null> {
const gatewayProfile = prisma.gatewayProfile;
const row = await gatewayProfile.update({
where: { profileName },
@@ -335,11 +292,7 @@ export const createGatewayProfileRepository = (
data: { lastError },
});
},
async updateWorkspaceUsage(
profileName: string,
workspace: string,
lastUsedAt: string
): Promise<void> {
async updateWorkspaceUsage(profileName: string, workspace: string, lastUsedAt: string): Promise<void> {
const gatewayProfile = prisma.gatewayProfile;
await gatewayProfile.update({
where: { profileName },
@@ -14,11 +14,7 @@ export interface WorkspaceInfo {
needsInstall: boolean;
}
const runGit = (
args: string[],
cwd: string,
env?: Record<string, string>
): Promise<{ ok: boolean; output: string }> =>
const runGit = (args: string[], cwd: string, env?: Record<string, string>): Promise<{ ok: boolean; output: string }> =>
new Promise((resolve) => {
const child = spawn('git', args, {
cwd,
@@ -43,8 +39,7 @@ const ensureDir = (dir: string): void => {
}
};
const hasInstallMarker = (dir: string): boolean =>
fs.existsSync(path.join(dir, 'node_modules', '.pnpm'));
const hasInstallMarker = (dir: string): boolean => fs.existsSync(path.join(dir, 'node_modules', '.pnpm'));
export class GitWorkspaceManager {
private readonly repoRoot: string;
@@ -63,11 +58,7 @@ export class GitWorkspaceManager {
const exists = fs.existsSync(workspacePath);
if (!exists) {
const hasCommit = await runGit(
['cat-file', '-e', `${commitSha}^{commit}`],
this.repoRoot,
this.baseEnv
);
const hasCommit = await runGit(['cat-file', '-e', `${commitSha}^{commit}`], this.repoRoot, this.baseEnv);
if (!hasCommit.ok) {
await runGit(['fetch', '--all', '--tags'], this.repoRoot, this.baseEnv);
}
@@ -97,11 +88,7 @@ export class GitWorkspaceManager {
if (!fs.existsSync(resolved)) {
return false;
}
const result = await runGit(
['worktree', 'remove', '--force', resolved],
this.repoRoot,
this.baseEnv
);
const result = await runGit(['worktree', 'remove', '--force', resolved], this.repoRoot, this.baseEnv);
if (!result.ok) {
fs.rmSync(resolved, { recursive: true, force: true });
}
@@ -6,10 +6,7 @@ const WORKSPACE_MARKERS = ['pnpm-workspace.yaml', 'package.json'];
const hasWorkspaceMarker = (dir: string): boolean =>
WORKSPACE_MARKERS.some((marker) => fs.existsSync(path.join(dir, marker)));
export const resolveWorkspaceRoot = (
startDir: string,
maxDepth = 5
): string => {
export const resolveWorkspaceRoot = (startDir: string, maxDepth = 5): string => {
let current = path.resolve(startDir);
for (let depth = 0; depth <= maxDepth; depth += 1) {
if (hasWorkspaceMarker(current)) {