mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-07-01 15:03:29 +00:00
Enable the sort-keys eslint rule (#1746)
## Description: Enable the `sort-keys` eslint rule. Fixes #1629 ## Please complete the following: - [x] I have added screenshots for all UI updates - [x] I process any text displayed to the user through translateText() and I've added it to the en.json file - [x] I have added relevant tests to the test directory - [x] I confirm I have thoroughly tested these changes and take full responsibility for any bugs introduced - [ ] I have read and accepted the CLA agreement (only required once).
This commit is contained in:
@@ -11,11 +11,13 @@ const log = logger.child({ component: "Archive" });
|
||||
// R2 client configuration
|
||||
const r2 = new S3({
|
||||
region: "auto", // R2 ignores region, but it's required by the SDK
|
||||
/* eslint-disable sort-keys */
|
||||
endpoint: config.r2Endpoint(),
|
||||
credentials: {
|
||||
accessKeyId: config.r2AccessKey(),
|
||||
secretAccessKey: config.r2SecretKey(),
|
||||
},
|
||||
/* eslint-disable sort-keys */
|
||||
});
|
||||
|
||||
const bucket = config.r2Bucket();
|
||||
|
||||
@@ -60,12 +60,12 @@ export class Cloudflare {
|
||||
data?: any,
|
||||
): Promise<T> {
|
||||
const response = await fetch(url, {
|
||||
method,
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
headers: {
|
||||
Authorization: `Bearer ${this.apiToken}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: data ? JSON.stringify(data) : undefined,
|
||||
method,
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
@@ -178,7 +178,6 @@ export class Cloudflare {
|
||||
log.info(`Created credentials file at: ${this.credsPath}`);
|
||||
|
||||
const tunnelConfig: CloudflaredConfig = {
|
||||
tunnel: tunnelId,
|
||||
"credentials-file": this.credsPath,
|
||||
ingress: [
|
||||
...Array.from(subdomainToService.entries()).map(
|
||||
@@ -191,6 +190,7 @@ export class Cloudflare {
|
||||
service: "http_status:404",
|
||||
},
|
||||
],
|
||||
tunnel: tunnelId,
|
||||
};
|
||||
|
||||
// Write config file
|
||||
@@ -210,11 +210,11 @@ export class Cloudflare {
|
||||
|
||||
const recordId = existingRecords.result[0]?.id;
|
||||
const dnsData = {
|
||||
type: "CNAME",
|
||||
name: subdomain,
|
||||
content: `${tunnelId}.cfargotunnel.com`,
|
||||
ttl: 1,
|
||||
name: subdomain,
|
||||
proxied: true,
|
||||
ttl: 1,
|
||||
type: "CNAME",
|
||||
};
|
||||
|
||||
if (recordId) {
|
||||
@@ -240,12 +240,12 @@ export class Cloudflare {
|
||||
["tunnel", "--config", this.configPath, "--loglevel", "error", "run"],
|
||||
{
|
||||
detached: true,
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
env: {
|
||||
...process.env,
|
||||
// Set this to bypass origin cert requirement for named tunnels
|
||||
TUNNEL_ORIGIN_CERT: "/dev/null",
|
||||
},
|
||||
stdio: ["ignore", "pipe", "pipe"],
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -39,16 +39,16 @@ export class GameManager {
|
||||
Date.now(),
|
||||
this.config,
|
||||
{
|
||||
gameMap: GameMapType.World,
|
||||
gameType: GameType.Private,
|
||||
bots: 400,
|
||||
difficulty: Difficulty.Medium,
|
||||
disableNPCs: false,
|
||||
disabledUnits: [],
|
||||
gameMap: GameMapType.World,
|
||||
gameMode: GameMode.FFA,
|
||||
gameType: GameType.Private,
|
||||
infiniteGold: false,
|
||||
infiniteTroops: false,
|
||||
instantBuild: false,
|
||||
gameMode: GameMode.FFA,
|
||||
bots: 400,
|
||||
disabledUnits: [],
|
||||
...gameConfig,
|
||||
},
|
||||
creatorClientID,
|
||||
|
||||
+26
-26
@@ -123,15 +123,15 @@ export class GameServer {
|
||||
// Log when lobby creator joins private game
|
||||
if (client.clientID === this.LobbyCreatorID) {
|
||||
this.log.info("Lobby creator joined", {
|
||||
gameID: this.id,
|
||||
creatorID: this.LobbyCreatorID,
|
||||
gameID: this.id,
|
||||
});
|
||||
}
|
||||
this.log.info("client (re)joining game", {
|
||||
clientID: client.clientID,
|
||||
persistentID: client.persistentID,
|
||||
clientIP: ipAnonymize(client.ip),
|
||||
isRejoin: lastTurn > 0,
|
||||
persistentID: client.persistentID,
|
||||
});
|
||||
|
||||
if (
|
||||
@@ -210,9 +210,9 @@ export class GameServer {
|
||||
});
|
||||
client.ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error,
|
||||
message,
|
||||
type: "error",
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
client.ws.close(1002, "ClientMessageSchema");
|
||||
@@ -244,8 +244,8 @@ export class GameServer {
|
||||
this.log.warn(`Only lobby creator can kick players`, {
|
||||
clientID: authenticatedClientID,
|
||||
creatorID: this.LobbyCreatorID,
|
||||
target: clientMsg.intent.target,
|
||||
gameID: this.id,
|
||||
target: clientMsg.intent.target,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -261,9 +261,9 @@ export class GameServer {
|
||||
// Log and execute the kick
|
||||
this.log.info(`Lobby creator initiated kick of player`, {
|
||||
creatorID: authenticatedClientID,
|
||||
target: clientMsg.intent.target,
|
||||
gameID: this.id,
|
||||
kickMethod: "websocket",
|
||||
target: clientMsg.intent.target,
|
||||
});
|
||||
|
||||
this.kickClient(clientMsg.intent.target);
|
||||
@@ -358,8 +358,8 @@ export class GameServer {
|
||||
this._hasPrestarted = true;
|
||||
|
||||
const prestartMsg = ServerPrestartMessageSchema.safeParse({
|
||||
type: "prestart",
|
||||
gameMap: this.gameConfig.gameMap,
|
||||
type: "prestart",
|
||||
});
|
||||
|
||||
if (!prestartMsg.success) {
|
||||
@@ -393,13 +393,13 @@ export class GameServer {
|
||||
this.lastPingUpdate = Date.now();
|
||||
|
||||
const result = GameStartInfoSchema.safeParse({
|
||||
gameID: this.id,
|
||||
config: this.gameConfig,
|
||||
gameID: this.id,
|
||||
players: this.activeClients.map((c) => ({
|
||||
username: c.username,
|
||||
clientID: c.clientID,
|
||||
pattern: c.pattern,
|
||||
flag: c.flag,
|
||||
pattern: c.pattern,
|
||||
username: c.username,
|
||||
})),
|
||||
});
|
||||
if (!result.success) {
|
||||
@@ -430,9 +430,9 @@ export class GameServer {
|
||||
try {
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "start",
|
||||
turns: this.turns.slice(lastTurn),
|
||||
gameStartInfo: this.gameStartInfo,
|
||||
turns: this.turns.slice(lastTurn),
|
||||
type: "start",
|
||||
} satisfies ServerStartGameMessage),
|
||||
);
|
||||
} catch (error) {
|
||||
@@ -447,8 +447,8 @@ export class GameServer {
|
||||
|
||||
private endTurn() {
|
||||
const pastTurn: Turn = {
|
||||
turnNumber: this.turns.length,
|
||||
intents: this.intents,
|
||||
turnNumber: this.turns.length,
|
||||
};
|
||||
this.turns.push(pastTurn);
|
||||
this.intents = [];
|
||||
@@ -457,8 +457,8 @@ export class GameServer {
|
||||
this.checkDisconnectedStatus();
|
||||
|
||||
const msg = JSON.stringify({
|
||||
type: "turn",
|
||||
turn: pastTurn,
|
||||
type: "turn",
|
||||
} satisfies ServerTurnMessage);
|
||||
this.activeClients.forEach((c) => {
|
||||
c.ws.send(msg);
|
||||
@@ -510,9 +510,9 @@ export class GameServer {
|
||||
}
|
||||
|
||||
this.log.error("Error archiving game record details:", {
|
||||
gameId: this.id,
|
||||
errorType: typeof error,
|
||||
error: errorDetails,
|
||||
errorType: typeof error,
|
||||
gameId: this.id,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -587,12 +587,12 @@ export class GameServer {
|
||||
|
||||
public gameInfo(): GameInfo {
|
||||
return {
|
||||
gameID: this.id,
|
||||
clients: this.activeClients.map((c) => ({
|
||||
username: c.username,
|
||||
clientID: c.clientID,
|
||||
username: c.username,
|
||||
})),
|
||||
gameConfig: this.gameConfig,
|
||||
gameID: this.id,
|
||||
msUntilStart: this.isPublic()
|
||||
? this.createdAt + this.config.gameCreationRate()
|
||||
: undefined,
|
||||
@@ -618,8 +618,8 @@ export class GameServer {
|
||||
});
|
||||
client.ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error: "Kicked from game (you may have been playing on another tab)",
|
||||
type: "error",
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
client.ws.close(1000, "Kicked from game");
|
||||
@@ -660,9 +660,9 @@ export class GameServer {
|
||||
private markClientDisconnected(clientID: string, isDisconnected: boolean) {
|
||||
this.clientsDisconnectedStatus.set(clientID, isDisconnected);
|
||||
this.addIntent({
|
||||
type: "mark_disconnected",
|
||||
clientID: clientID,
|
||||
clientID,
|
||||
isDisconnected: isDisconnected,
|
||||
type: "mark_disconnected",
|
||||
});
|
||||
}
|
||||
|
||||
@@ -681,10 +681,10 @@ export class GameServer {
|
||||
}
|
||||
return {
|
||||
clientID: player.clientID,
|
||||
username: player.username,
|
||||
persistentID:
|
||||
this.allClients.get(player.clientID)?.persistentID ?? "",
|
||||
stats,
|
||||
username: player.username,
|
||||
} satisfies PlayerRecord;
|
||||
},
|
||||
);
|
||||
@@ -722,17 +722,17 @@ export class GameServer {
|
||||
}
|
||||
|
||||
const serverDesync = ServerDesyncSchema.safeParse({
|
||||
type: "desync",
|
||||
turn: lastHashTurn,
|
||||
correctHash: mostCommonHash,
|
||||
clientsWithCorrectHash:
|
||||
this.activeClients.length - outOfSyncClients.length,
|
||||
correctHash: mostCommonHash,
|
||||
totalActiveClients: this.activeClients.length,
|
||||
turn: lastHashTurn,
|
||||
type: "desync",
|
||||
});
|
||||
if (!serverDesync.success) {
|
||||
this.log.warn("failed to create desync message", {
|
||||
gameID: this.id,
|
||||
error: serverDesync.error,
|
||||
gameID: this.id,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -745,8 +745,8 @@ export class GameServer {
|
||||
}
|
||||
this.sentDesyncMessageClients.add(c.clientID);
|
||||
this.log.info("sending desync to client", {
|
||||
gameID: this.id,
|
||||
clientID: c.clientID,
|
||||
gameID: this.id,
|
||||
persistentID: c.persistentID,
|
||||
});
|
||||
c.ws.send(desyncMsg);
|
||||
|
||||
@@ -29,6 +29,7 @@ if (config.otelEnabled()) {
|
||||
// Add OTLP exporter for logs
|
||||
const logExporter = new OTLPLogExporter({
|
||||
url: `${config.otelEndpoint()}/v1/logs`,
|
||||
// eslint-disable-next-line sort-keys
|
||||
headers,
|
||||
});
|
||||
|
||||
@@ -56,6 +57,7 @@ const addSeverityFormat = winston.format((info) => {
|
||||
// Define your base/parent logger
|
||||
const logger = winston.createLogger({
|
||||
level: "info",
|
||||
/* eslint-disable sort-keys */
|
||||
format: winston.format.combine(
|
||||
winston.format.timestamp(),
|
||||
addSeverityFormat(),
|
||||
@@ -65,6 +67,7 @@ const logger = winston.createLogger({
|
||||
service: "openfront",
|
||||
environment: process.env.GAME_ENV ?? "prod",
|
||||
},
|
||||
/* eslint-enable sort-keys */
|
||||
transports: [
|
||||
new winston.transports.Console(),
|
||||
new OpenTelemetryTransportV3(),
|
||||
|
||||
+29
-29
@@ -20,33 +20,33 @@ const config = getServerConfigFromServer();
|
||||
// How many times each map should appear in the playlist.
|
||||
// Note: The Partial should eventually be removed for better type safety.
|
||||
const frequency: Partial<Record<GameMapName, number>> = {
|
||||
World: 3,
|
||||
Europe: 2,
|
||||
Africa: 2,
|
||||
Baikal: 2,
|
||||
Australia: 1,
|
||||
NorthAmerica: 1,
|
||||
Britannia: 1,
|
||||
GatewayToTheAtlantic: 1,
|
||||
Iceland: 1,
|
||||
SouthAmerica: 1,
|
||||
DeglaciatedAntarctica: 1,
|
||||
EuropeClassic: 1,
|
||||
Mena: 1,
|
||||
Pangaea: 1,
|
||||
Asia: 1,
|
||||
Australia: 1,
|
||||
Baikal: 2,
|
||||
BetweenTwoSeas: 1,
|
||||
BlackSea: 1,
|
||||
Britannia: 1,
|
||||
DeglaciatedAntarctica: 1,
|
||||
EastAsia: 1,
|
||||
Europe: 2,
|
||||
EuropeClassic: 1,
|
||||
FalklandIslands: 1,
|
||||
FaroeIslands: 1,
|
||||
GatewayToTheAtlantic: 1,
|
||||
Halkidiki: 1,
|
||||
Iceland: 1,
|
||||
Italia: 1,
|
||||
Mars: 1,
|
||||
MarsRevised: 1,
|
||||
BetweenTwoSeas: 1,
|
||||
EastAsia: 1,
|
||||
BlackSea: 1,
|
||||
FaroeIslands: 1,
|
||||
FalklandIslands: 1,
|
||||
Halkidiki: 1,
|
||||
StraitOfGibraltar: 1,
|
||||
Italia: 1,
|
||||
Yenisei: 1,
|
||||
Mena: 1,
|
||||
NorthAmerica: 1,
|
||||
Pangaea: 1,
|
||||
Pluto: 1,
|
||||
SouthAmerica: 1,
|
||||
StraitOfGibraltar: 1,
|
||||
World: 3,
|
||||
Yenisei: 1,
|
||||
};
|
||||
|
||||
interface MapWithMode {
|
||||
@@ -77,18 +77,18 @@ export class MapPlaylist {
|
||||
|
||||
// Create the default public game config (from your GameManager)
|
||||
return {
|
||||
gameMap: map,
|
||||
maxPlayers: config.lobbyMaxPlayers(map, mode, playerTeams),
|
||||
gameType: GameType.Public,
|
||||
bots: 400,
|
||||
difficulty: Difficulty.Medium,
|
||||
disableNPCs: mode === GameMode.Team,
|
||||
disabledUnits: [],
|
||||
gameMap: map,
|
||||
gameMode: mode,
|
||||
gameType: GameType.Public,
|
||||
infiniteGold: false,
|
||||
infiniteTroops: false,
|
||||
instantBuild: false,
|
||||
disableNPCs: mode === GameMode.Team,
|
||||
gameMode: mode,
|
||||
maxPlayers: config.lobbyMaxPlayers(map, mode, playerTeams),
|
||||
playerTeams,
|
||||
bots: 400,
|
||||
disabledUnits: [],
|
||||
} satisfies GameConfig;
|
||||
}
|
||||
|
||||
|
||||
@@ -54,8 +54,8 @@ app.use(express.json());
|
||||
app.set("trust proxy", 3);
|
||||
app.use(
|
||||
rateLimit({
|
||||
windowMs: 1000, // 1 second
|
||||
max: 20, // 20 requests per IP per second
|
||||
windowMs: 1000, // 1 second
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -180,10 +180,10 @@ app.post(
|
||||
const response = await fetch(
|
||||
`http://localhost:${config.workerPort(gameID)}/api/kick_player/${gameID}/${clientID}`,
|
||||
{
|
||||
method: "POST",
|
||||
headers: {
|
||||
[config.adminHeader()]: config.adminToken(),
|
||||
},
|
||||
method: "POST",
|
||||
},
|
||||
);
|
||||
|
||||
@@ -232,10 +232,10 @@ async function fetchLobbies(): Promise<number> {
|
||||
.filter((result) => result !== null)
|
||||
.map((gi: GameInfo) => {
|
||||
return {
|
||||
gameID: gi.gameID,
|
||||
numClients: gi?.clients?.length ?? 0,
|
||||
gameConfig: gi.gameConfig,
|
||||
gameID: gi.gameID,
|
||||
msUntilStart: (gi.msUntilStart ?? Date.now()) - Date.now(),
|
||||
numClients: gi?.clients?.length ?? 0,
|
||||
} as GameInfo;
|
||||
});
|
||||
|
||||
@@ -283,12 +283,12 @@ async function schedulePublicGame(playlist: MapPlaylist) {
|
||||
const response = await fetch(
|
||||
`http://localhost:${config.workerPort(gameID)}/api/create_game/${gameID}`,
|
||||
{
|
||||
method: "POST",
|
||||
body: JSON.stringify(playlist.gameConfig()),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
[config.adminHeader()]: config.adminToken(),
|
||||
},
|
||||
body: JSON.stringify(playlist.gameConfig()),
|
||||
method: "POST",
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ export function getOtelResource() {
|
||||
export function getPromLabels() {
|
||||
return {
|
||||
"service.instance.id": process.env.HOSTNAME,
|
||||
/* eslint-disable sort-keys */
|
||||
"openfront.environment": config.env(),
|
||||
"openfront.host": process.env.HOST,
|
||||
"openfront.domain": process.env.DOMAIN,
|
||||
@@ -25,5 +26,6 @@ export function getPromLabels() {
|
||||
"openfront.component": process.env.WORKER_ID
|
||||
? "Worker " + process.env.WORKER_ID
|
||||
: "Master",
|
||||
/* eslint-enable sort-keys */
|
||||
};
|
||||
}
|
||||
|
||||
@@ -55,8 +55,8 @@ async function setupTunnels() {
|
||||
|
||||
if (!(await cloudflare.configAlreadyExists())) {
|
||||
await cloudflare.createTunnel({
|
||||
subdomain: config.subdomain(),
|
||||
domain: config.domain(),
|
||||
subdomain: config.subdomain(),
|
||||
subdomainToService: domainToService,
|
||||
} as TunnelConfig);
|
||||
} else {
|
||||
|
||||
@@ -85,8 +85,8 @@ export async function startWorker() {
|
||||
app.use(express.static(path.join(__dirname, "../../out")));
|
||||
app.use(
|
||||
rateLimit({
|
||||
windowMs: 1000, // 1 second
|
||||
max: 20, // 20 requests per IP per second
|
||||
windowMs: 1000, // 1 second
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -232,9 +232,9 @@ export async function startWorker() {
|
||||
|
||||
if (!gameRecord) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Game not found",
|
||||
exists: false,
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -246,20 +246,20 @@ export async function startWorker() {
|
||||
`git commit mismatch for game ${req.params.id}, expected ${config.gitCommit()}, got ${gameRecord.gitCommit}`,
|
||||
);
|
||||
return res.status(409).json({
|
||||
success: false,
|
||||
details: {
|
||||
actualCommit: gameRecord.gitCommit,
|
||||
expectedCommit: config.gitCommit(),
|
||||
},
|
||||
error: "Version mismatch",
|
||||
exists: true,
|
||||
details: {
|
||||
expectedCommit: config.gitCommit(),
|
||||
actualCommit: gameRecord.gitCommit,
|
||||
},
|
||||
success: false,
|
||||
});
|
||||
}
|
||||
|
||||
return res.status(200).json({
|
||||
success: true,
|
||||
exists: true,
|
||||
gameRecord: gameRecord,
|
||||
success: true,
|
||||
});
|
||||
}),
|
||||
);
|
||||
@@ -324,8 +324,8 @@ export async function startWorker() {
|
||||
log.warn("Error parsing client message", error);
|
||||
ws.send(
|
||||
JSON.stringify({
|
||||
type: "error",
|
||||
error: error.toString(),
|
||||
type: "error",
|
||||
} satisfies ServerErrorMessage),
|
||||
);
|
||||
ws.close(1002, "ClientJoinMessageSchema");
|
||||
|
||||
@@ -25,20 +25,20 @@ export function initWorkerMetrics(gameManager: GameManager): void {
|
||||
|
||||
// Create metrics exporter
|
||||
const metricExporter = new OTLPMetricExporter({
|
||||
url: `${config.otelEndpoint()}/v1/metrics`,
|
||||
headers,
|
||||
url: `${config.otelEndpoint()}/v1/metrics`,
|
||||
});
|
||||
|
||||
// Configure the metric reader
|
||||
const metricReader = new PeriodicExportingMetricReader({
|
||||
exporter: metricExporter,
|
||||
exportIntervalMillis: 15000, // Export metrics every 15 seconds
|
||||
exporter: metricExporter,
|
||||
});
|
||||
|
||||
// Create a meter provider
|
||||
const meterProvider = new MeterProvider({
|
||||
resource,
|
||||
readers: [metricReader],
|
||||
resource,
|
||||
});
|
||||
|
||||
// Get meter for creating metrics
|
||||
|
||||
+3
-2
@@ -21,6 +21,7 @@ export async function verifyClientToken(
|
||||
config: ServerConfig,
|
||||
): Promise<TokenVerificationResult> {
|
||||
if (PersistentIdSchema.safeParse(token).success) {
|
||||
// eslint-disable-next-line sort-keys
|
||||
return { persistentId: token, claims: null };
|
||||
}
|
||||
try {
|
||||
@@ -29,8 +30,8 @@ export async function verifyClientToken(
|
||||
const key = await config.jwkPublicKey();
|
||||
const { payload, protectedHeader } = await jwtVerify(token, key, {
|
||||
algorithms: ["EdDSA"],
|
||||
issuer,
|
||||
audience,
|
||||
issuer,
|
||||
});
|
||||
const result = TokenPayloadSchema.safeParse(payload);
|
||||
if (!result.success) {
|
||||
@@ -40,7 +41,7 @@ export async function verifyClientToken(
|
||||
}
|
||||
const claims = result.data;
|
||||
const persistentId = claims.sub;
|
||||
return { persistentId, claims };
|
||||
return { claims, persistentId };
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user