Chore(deps): Update and remove dependencies (#3819)

## Description:

Only mentioning removals/major updates/notable changes below, not all
minor upgrades.

### Removed:
- "@aws-sdk/client-s3": not used anywhere (was used in Archive.ts
previously)
- chai, "@types/chai", sinon-chai: not used anywhere, probably leftover.
Vitest uses a bundled version of Chai for its expect asserations under
the hood too.
- protobufjs, "@types/google-protobuf": not used anywhere, probably left
from evan's experiment with it? Removed from vite.config.ts too.
- "@types/jquery": not used anywhere, probably leftover
- sinon, "@types/sinon": not used anywhere just like chai, probably
leftover. And Vitest provides us with the same functionality.
- "@types/systeminformation": dependency systeminformation was removed
last year, this is an unneeded, deprecated and unmaintained remainder.
- vite-tsconfig-paths: removed, and removed the import and usage in
vite.config.ts and replaced it by adding `tsconfigPaths: true` to the
`resolve` block. Because of this message displayed on running the tests:
"The plugin "vite-tsconfig-paths" is detected. Vite now supports
tsconfig paths resolution natively via the resolve.tsconfigPaths option.
You can remove the plugin and set resolve.tsconfigPaths: true in your
Vite config instead."
- vite-plugin-static-copy: removed, we don't use it anymore (was used in
our vite.config.ts once,, probably before Vite natively supported
copying static assets via its publicDir configuration)

### Updated:
- color.js: v0.5 > v0.6, no breaking change affecting us
- cross-env: v7 > v10. It's a publicly archived repo since Nov 2025. But
before that he got it up-to-date from June 2025, porting to TS, dropping
old Node versions, dependencies etc. Seems still good to use for some
amount of time to come.
- dotenv: v16 > v17, now logs an informational message by default when
it loads an environment file. Can be disabled by using
dotenv.config({quite: true}) if needed.
- ejs: v3 > v5: security patches mostly. Vite still uses v3 btw.
- eslint: v9 > v10. Newly enabled rules by default:
'no-unassigned-vars', 'no-useless-assignment' and
'preserve-caught-error'. Mostly faster and minimum support moved to
higher node versions, which shouldn't be a problem.
- "@eslint/compat": v1 > v2. Minimum supported Node versions, which
should not be a problem.
- intl-messageformat: v10 > v11 no breaking changes that affect us
- jdom: v27 > v29. Faster. Most notably minimum support moved to higher
node v22 version, which should not be a problem. Also, see types/node,
kind of expecting v24 to be installed now.
- nanoid: from v3 to v5, no breaking changes that affect us
- "@opentelemetry/sdk-logs": now that addLogRecordProcessor is removed,
changed Logger.ts to pass an (empty) provider array directly to the
LoggerProvider constructor. Follows the changes in
https://github.com/open-telemetry/opentelemetry-js/pull/5588
- "@tailwindcss/vite": supports vite v8 from 4.2.2, and a fix for it in
4.2.4
- tailwindcss: supports vite v8 from 4.2.2
-- in 4.1.15 (we were already above this version) break-words was
deprecated in favor of wrap-break-word. But break-words, which we use in
15 places, will still work as expected
(https://github.com/tailwindlabs/tailwindcss/pull/19157). Same goes for
also deprecated "order-none".
- "@types/node": from v22 to v24, assuming most now use node 24
- vite v7 > v8: 
-- is now on 8.0.10 so first bugs are out of it, while v8 itself also
fixed a big number of bugs.
-- in vite.config.ts, fixed Ts error/compilation issue by changing the
manualChunks option in build.rollupOptions.output to use the function
syntax, which is required by the updated types instead of the object
syntax.
- zod: no changes that affect us

### Prettier:
Updated only because of (new because of update?) Prettier errors for
files untouched in this PR originally:
- PathFinder.Parabola.ts
- WorkerMessages.ts
- ClanModal.handlers.test.ts
- ClanModal.rendering.test.ts‎
- CONTRIBUTING.md
- README.md

### ESLint:
Fixes needed to silence errors coming from newly enabled recommended
rules 'no-useless-assignment' and 'preserve-caught-error':

For 'no-useless-assignment' (default assignment never used because of
unreachable code or they are guaranteed to get a value, so they can be
undefinedat the start. Exception was AttackExecution, so made the
default value of 0 the default case in the switch statement):
- ClientGameRunner
- GameModeSelector
- NameBoxCalculator
- StructureDrawingUtils
- TerritoryLayer
- Diagnostics
- GameRunner
- ColorAllocator
- DefaultConfig
- AttackExecution
- AiAttackBehavior
- Worker.worker
- GamePreviewBuilder

For 'preserve-caught-error', disabled the rule here because the possible
fix `{cause: error}` was introduced in ES2022 while we're still on
target ES2020 currently:
- GameServer
- Privilege

_Error: The value assigned to 'gameMap' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'timeDisplay' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'scalingFactor' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'radius' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'teamColor' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'gl' is not used in subsequent statements.
(no-useless-assignment)
Error: The value assigned to 'power' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'tickExecutionDuration' is not used in
subsequent statements. (no-useless-assignment)
Error: The value assigned to 'selectedIndex' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'mag' is not used in subsequent statements.
(no-useless-assignment)
Error: The value assigned to 'speed' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'matchesCriteria' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'shouldContinue' is not used in subsequent
statements. (no-useless-assignment)
Error: The value assigned to 'description' is not used in subsequent
statements. (no-useless-assignment)
Error: There is no `cause` attached to the symptom error being thrown.
(preserve-caught-error)
Error: There is no `cause` attached to the symptom error being thrown.
(preserve-caught-error)_

All tests pass. TypeScript and ESLint errors resolved.

## 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

## Please put your Discord username so you can be contacted if a bug or
regression is found:

tryout33

---------

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
VariableVince
2026-05-06 17:12:27 +02:00
committed by GitHub
parent c0b976448b
commit eca5794ebb
25 changed files with 1910 additions and 5015 deletions
+1 -1
View File
@@ -237,7 +237,7 @@ async function createClientGame(
userSettings,
lobbyConfig.gameRecord !== undefined,
);
let gameMap: TerrainMapData | null = null;
let gameMap: TerrainMapData;
if (terrainLoad) {
gameMap = await terrainLoad;
+1 -1
View File
@@ -275,7 +275,7 @@ export class GameModeSelector extends LitElement {
? getSecondsUntilServerTimestamp(lobby.startsAt, this.serverTimeOffset)
: undefined;
let timeDisplay: string = "";
let timeDisplay: string;
let timeDisplayUppercase = false;
if (timeRemaining === undefined) {
timeDisplay = renderDuration(this.defaultLobbyTime);
+1 -1
View File
@@ -18,7 +18,7 @@ export function placeName(game: Game, player: Player): NameViewData {
player.largestClusterBoundingBox ??
calculateBoundingBox(game, player.borderTiles());
let scalingFactor = 1;
let scalingFactor: number;
const width = boundingBox.max.x - boundingBox.min.x;
const height = boundingBox.max.y - boundingBox.min.y;
const size = Math.min(width, height);
@@ -489,7 +489,7 @@ export class SpriteFactory {
if (stage === undefined) throw new Error("Not initialized");
const parentContainer = new PIXI.Container();
const circle = new PIXI.Graphics();
let radius = 0;
let radius: number;
switch (type) {
case UnitType.SAMLauncher:
radius = this.game.config().samRange(level ?? 1);
+1 -1
View File
@@ -244,7 +244,7 @@ export class TerritoryLayer implements Layer {
minRad + (maxRad - minRad) * (0.5 + 0.5 * Math.sin(this.borderAnimTime));
const baseColor = this.theme.spawnHighlightSelfColor(); //white
let teamColor: Colord | null = null;
let teamColor: Colord;
const team: Team | null = focusedPlayer.team();
if (team !== null && Object.values(ColoredTeams).includes(team)) {
+2 -3
View File
@@ -63,10 +63,9 @@ export async function collectGraphicsDiagnostics(
/* ---------- Rendering ---------- */
let gl: WebGLRenderingContext | WebGL2RenderingContext | null = null;
let type: RendererType = "Canvas2D";
gl =
const gl =
canvas.getContext("webgl2", { antialias: true }) ??
canvas.getContext("webgl", { antialias: true });
@@ -111,7 +110,7 @@ export async function collectGraphicsDiagnostics(
/* ---------- Power ---------- */
let power: PowerInfo = {};
let power: PowerInfo;
if ("getBattery" in navigator) {
try {
+1 -1
View File
@@ -131,7 +131,7 @@ export class GameRunner {
this.currTurn++;
let updates: GameUpdates;
let tickExecutionDuration: number = 0;
let tickExecutionDuration: number;
try {
const startTime = performance.now();
+1 -1
View File
@@ -65,7 +65,7 @@ export class ColorAllocator {
this.availableColors = [...this.fallbackColors];
}
let selectedIndex = 0;
let selectedIndex: number;
if (this.assigned.size === 0 || this.assigned.size > 50) {
// Randomly pick the first color if no colors have been assigned yet.
+2 -2
View File
@@ -635,8 +635,8 @@ export class DefaultConfig implements Config {
defenderTroopLoss: number;
tilesPerTickUsed: number;
} {
let mag = 0;
let speed = 0;
let mag: number;
let speed: number;
const type = gm.terrainType(tileToConquer);
switch (type) {
case TerrainType.Plains:
+4 -1
View File
@@ -338,7 +338,7 @@ export class AttackExecution implements Execution {
}
}
let mag = 0;
let mag: number;
switch (this.mg.terrainType(neighbor)) {
case TerrainType.Plains:
mag = 1;
@@ -349,6 +349,9 @@ export class AttackExecution implements Execution {
case TerrainType.Mountain:
mag = 2;
break;
default:
mag = 0;
break;
}
const priority =
+1 -1
View File
@@ -183,7 +183,7 @@ export class AiAttackBehavior {
continue;
}
let matchesCriteria = false;
let matchesCriteria: boolean;
if (highInterestOnly) {
// High-interest targeting: prioritize unowned tiles or tiles owned by bots
matchesCriteria = !owner.isPlayer() || owner.type() === PlayerType.Bot;
+1 -3
View File
@@ -11,9 +11,7 @@ export interface ParabolaOptions {
const PARABOLA_MIN_HEIGHT = 50;
export class ParabolaUniversalPathFinder
implements SteppingPathFinder<TileRef>
{
export class ParabolaUniversalPathFinder implements SteppingPathFinder<TileRef> {
private curve: DistanceBasedBezierCurve | null = null;
private lastTo: TileRef | null = null;
+1 -1
View File
@@ -50,7 +50,7 @@ async function drain(): Promise<void> {
draining = true;
drainRequested = false;
let shouldContinue = false;
let shouldContinue: boolean;
try {
const gr = await gameRunner;
if (!gr) {
+1 -2
View File
@@ -122,8 +122,7 @@ export interface AttackClusteredPositionsMessage extends BaseWorkerMessage {
attackID?: string;
}
export interface AttackClusteredPositionsResultMessage
extends BaseWorkerMessage {
export interface AttackClusteredPositionsResultMessage extends BaseWorkerMessage {
type: "attack_clustered_positions_result";
attacks: { id: string; positions: { x: number; y: number }[] }[];
}
+1 -1
View File
@@ -210,7 +210,7 @@ export async function buildPreview(
? `${mode} on ${map}${gameTypeLabel}`
: "OpenFront Game";
let description = "";
let description: string;
if (isFinished) {
const parts: string[] = [];
if (winner) {
+2
View File
@@ -794,6 +794,8 @@ export class GameServer {
} satisfies ServerStartGameMessage),
);
} catch (error) {
// can be enabled once we can use {cause: error} in Error constructor starting with ES2022
// eslint-disable-next-line preserve-caught-error
throw new Error(
`error sending start message for game ${this.id}, ${error}`.substring(
0,
+5 -9
View File
@@ -15,11 +15,6 @@ const config = getServerConfigFromServer();
const resource = getOtelResource();
// Initialize the OpenTelemetry Logger Provider
const loggerProvider = new LoggerProvider({
resource,
});
if (config.otelEnabled()) {
console.log("OTEL enabled");
// Configure OpenTelemetry endpoint with basic auth (if provided)
@@ -31,10 +26,11 @@ if (config.otelEnabled()) {
headers,
});
// Add a log processor with the exporter
loggerProvider.addLogRecordProcessor(
new SimpleLogRecordProcessor(logExporter),
);
// Initialize the OpenTelemetry Logger Provider
const loggerProvider = new LoggerProvider({
resource,
processors: [new SimpleLogRecordProcessor(logExporter)],
});
// Set as the global logger provider
logsAPI.logs.setGlobalLoggerProvider(loggerProvider);
+2
View File
@@ -212,6 +212,8 @@ export class PrivilegeCheckerImpl implements PrivilegeChecker {
try {
decodePatternData(found.pattern, this.b64urlDecode);
} catch (e) {
// can be enabled once we can use {cause: error} in Error constructor starting with ES2022
// eslint-disable-next-line preserve-caught-error
throw new Error(`Invalid pattern ${name}`);
}