mirror of
https://github.com/openfrontio/OpenFrontIO.git
synced 2026-06-21 09:10:42 +00:00
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:
@@ -101,7 +101,6 @@ All new features and bug fixes should include relevant tests. We use **Vitest**.
|
||||
## Submitting a Pull Request
|
||||
|
||||
1. **Commit your changes**:
|
||||
|
||||
- Write clear, concise commit messages.
|
||||
- Use the present tense ("Add feature" not "Added feature").
|
||||
|
||||
|
||||
@@ -181,7 +181,6 @@ Feel free to ask questions in the translation Discord server!
|
||||
To ensure code quality and project stability, we use a progressive contribution system:
|
||||
|
||||
1. **New Contributors**: Limited to UI improvements and small bug fixes only
|
||||
|
||||
- This helps you become familiar with the codebase
|
||||
- UI changes are easier to review and less likely to break core functionality
|
||||
- Small, focused PRs have a higher chance of being accepted
|
||||
@@ -193,20 +192,17 @@ To ensure code quality and project stability, we use a progressive contribution
|
||||
### How to Contribute Successfully
|
||||
|
||||
1. **Before Starting Work**:
|
||||
|
||||
- Open an issue describing what you want to contribute
|
||||
- Wait for maintainer feedback before investing significant time
|
||||
- Small improvements can proceed directly to PR stage
|
||||
|
||||
2. **Code Quality Requirements**:
|
||||
|
||||
- All code must be well-commented and follow existing style patterns
|
||||
- New features should not break existing functionality
|
||||
- Code should be thoroughly tested before submission
|
||||
- All code changes in src/core _MUST_ be tested.
|
||||
|
||||
3. **Pull Request Process**:
|
||||
|
||||
- Keep PRs focused on a single feature or bug fix
|
||||
- Include screenshots for UI changes
|
||||
- Describe what testing you've performed
|
||||
|
||||
Generated
+1799
-4872
File diff suppressed because it is too large
Load Diff
+52
-64
@@ -29,103 +29,91 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@datastructures-js/priority-queue": "^6.3.3",
|
||||
"@eslint/compat": "^1.2.7",
|
||||
"@eslint/js": "^9.21.0",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@datastructures-js/priority-queue": "^6.3.5",
|
||||
"@eslint/compat": "^2.0.5",
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@tailwindcss/vite": "^4.2.4",
|
||||
"@types/benchmark": "^2.1.5",
|
||||
"@types/chai": "^4.3.17",
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/ejs": "^3.1.5",
|
||||
"@types/express": "^5.0.6",
|
||||
"@types/google-protobuf": "^3.15.12",
|
||||
"@types/hammerjs": "^2.0.46",
|
||||
"@types/howler": "^2.2.12",
|
||||
"@types/jquery": "^3.5.31",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/msgpack5": "^3.4.6",
|
||||
"@types/node": "^22.10.2",
|
||||
"@types/pg": "^8.11.11",
|
||||
"@types/node": "^24.12.0",
|
||||
"@types/pg": "^8.20.0",
|
||||
"@types/seedrandom": "^3.0.8",
|
||||
"@types/sinon": "^17.0.3",
|
||||
"@types/systeminformation": "^3.23.1",
|
||||
"@types/ws": "^8.5.11",
|
||||
"@vitest/coverage-v8": "^4.0.16",
|
||||
"@vitest/ui": "^4.0.16",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"@types/ws": "^8.18.1",
|
||||
"@vitest/coverage-v8": "^4.1.5",
|
||||
"@vitest/ui": "^4.1.5",
|
||||
"autoprefixer": "^10.5.0",
|
||||
"benchmark": "^2.1.4",
|
||||
"canvas": "^3.2.1",
|
||||
"chai": "^5.1.1",
|
||||
"canvas": "^3.2.3",
|
||||
"concurrently": "^9.2.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"cross-env": "^10.1.0",
|
||||
"d3": "^7.9.0",
|
||||
"eslint": "^9.21.0",
|
||||
"eslint-config-prettier": "^10.1.1",
|
||||
"eslint-formatter-gha": "^1.5.2",
|
||||
"glob": "^13.0.0",
|
||||
"globals": "^16.0.0",
|
||||
"eslint": "^10.3.0",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"eslint-formatter-gha": "^2.0.1",
|
||||
"glob": "^13.0.6",
|
||||
"globals": "^17.6.0",
|
||||
"husky": "^9.1.7",
|
||||
"jsdom": "^27.4.0",
|
||||
"lint-staged": "^16.1.2",
|
||||
"lit": "^3.3.1",
|
||||
"jsdom": "^29.1.1",
|
||||
"lint-staged": "^16.4.0",
|
||||
"lit": "^3.3.2",
|
||||
"lit-markdown": "^1.3.2",
|
||||
"mrmime": "^2.0.0",
|
||||
"mrmime": "^2.0.1",
|
||||
"pixi-filters": "^6.1.5",
|
||||
"pixi.js": "^8.18.1",
|
||||
"prettier": "^3.5.3",
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"prettier-plugin-sh": "^0.17.4",
|
||||
"protobufjs": "^7.5.5",
|
||||
"sinon": "^21.0.1",
|
||||
"sinon-chai": "^4.0.0",
|
||||
"tailwindcss": "^4.1.18",
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-organize-imports": "^4.3.0",
|
||||
"prettier-plugin-sh": "^0.18.1",
|
||||
"tailwindcss": "^4.2.4",
|
||||
"tsconfig-paths": "^4.2.0",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.59.1",
|
||||
"vite": "^7.3.2",
|
||||
"vite": "^8.0.10",
|
||||
"vite-plugin-html": "^3.2.2",
|
||||
"vite-plugin-static-copy": "^3.1.4",
|
||||
"vite-tsconfig-paths": "^6.0.3",
|
||||
"vitest": "^4.0.16",
|
||||
"vitest-canvas-mock": "^1.1.3"
|
||||
"vitest": "^4.1.5",
|
||||
"vitest-canvas-mock": "^1.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.758.0",
|
||||
"@lit-labs/virtualizer": "^2.1.1",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@opentelemetry/api-logs": "^0.200.0",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "^0.200.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "^0.200.0",
|
||||
"@opentelemetry/resources": "^2.0.0",
|
||||
"@opentelemetry/sdk-logs": "^0.200.0",
|
||||
"@opentelemetry/sdk-metrics": "^2.0.0",
|
||||
"@opentelemetry/semantic-conventions": "^1.32.0",
|
||||
"@opentelemetry/winston-transport": "^0.11.0",
|
||||
"@opentelemetry/api": "^1.9.1",
|
||||
"@opentelemetry/api-logs": "^0.216.0",
|
||||
"@opentelemetry/exporter-logs-otlp-http": "^0.216.0",
|
||||
"@opentelemetry/exporter-metrics-otlp-http": "^0.216.0",
|
||||
"@opentelemetry/resources": "^2.7.1",
|
||||
"@opentelemetry/sdk-logs": "^0.216.0",
|
||||
"@opentelemetry/sdk-metrics": "^2.7.1",
|
||||
"@opentelemetry/semantic-conventions": "^1.40.0",
|
||||
"@opentelemetry/winston-transport": "^0.26.0",
|
||||
"@types/compression": "^1.8.1",
|
||||
"colord": "^2.9.3",
|
||||
"colorjs.io": "^0.5.2",
|
||||
"colorjs.io": "^0.6.1",
|
||||
"compression": "^1.8.1",
|
||||
"dompurify": "^3.4.0",
|
||||
"dotenv": "^16.5.0",
|
||||
"ejs": "^3.1.10",
|
||||
"dompurify": "^3.4.2",
|
||||
"dotenv": "^17.4.2",
|
||||
"ejs": "^5.0.2",
|
||||
"express": "^5.2.1",
|
||||
"express-rate-limit": "^8.3.2",
|
||||
"fastpriorityqueue": "^0.7.5",
|
||||
"express-rate-limit": "^8.4.1",
|
||||
"fastpriorityqueue": "^0.8.0",
|
||||
"howler": "^2.2.4",
|
||||
"intl-messageformat": "^10.7.16",
|
||||
"intl-messageformat": "^11.2.3",
|
||||
"ip-anonymize": "^0.1.0",
|
||||
"jose": "^6.0.10",
|
||||
"jose": "^6.2.3",
|
||||
"js-yaml": "^4.1.1",
|
||||
"limiter": "^3.0.0",
|
||||
"nanoid": "^3.3.6",
|
||||
"node-html-parser": "^7.0.2",
|
||||
"obscenity": "^0.4.3",
|
||||
"nanoid": "^5.1.11",
|
||||
"node-html-parser": "^7.1.0",
|
||||
"obscenity": "^0.4.6",
|
||||
"seedrandom": "^3.0.5",
|
||||
"ts-node": "^10.9.2",
|
||||
"tsx": "^4.17.0",
|
||||
"winston": "^3.17.0",
|
||||
"ws": "^8.18.0",
|
||||
"zod": "^4.0.5"
|
||||
"tsx": "^4.21.0",
|
||||
"winston": "^3.19.0",
|
||||
"ws": "^8.20.0",
|
||||
"zod": "^4.4.2"
|
||||
},
|
||||
"type": "module"
|
||||
}
|
||||
|
||||
@@ -237,7 +237,7 @@ async function createClientGame(
|
||||
userSettings,
|
||||
lobbyConfig.gameRecord !== undefined,
|
||||
);
|
||||
let gameMap: TerrainMapData | null = null;
|
||||
let gameMap: TerrainMapData;
|
||||
|
||||
if (terrainLoad) {
|
||||
gameMap = await terrainLoad;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -131,7 +131,7 @@ export class GameRunner {
|
||||
this.currTurn++;
|
||||
|
||||
let updates: GameUpdates;
|
||||
let tickExecutionDuration: number = 0;
|
||||
let tickExecutionDuration: number;
|
||||
|
||||
try {
|
||||
const startTime = performance.now();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 }[] }[];
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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}`);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,9 +53,8 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
describe("handleApprove increments selectedClan.memberCount", () => {
|
||||
it("increments memberCount by 1 after successful approveClanRequest", async () => {
|
||||
const { approveClanRequest, fetchClanRequests } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { approveClanRequest, fetchClanRequests } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(approveClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanRequests as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
@@ -90,9 +89,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("does not increment memberCount when approveClanRequest fails", async () => {
|
||||
const { approveClanRequest, fetchClanRequests } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { approveClanRequest, fetchClanRequests } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(approveClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -125,9 +123,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("treats undefined memberCount as 0 and increments to 1", async () => {
|
||||
const { approveClanRequest, fetchClanRequests } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { approveClanRequest, fetchClanRequests } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(approveClanRequest as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanRequests as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
@@ -271,9 +268,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("handleBan syncs memberCount via clan-updated event on success", async () => {
|
||||
const { banClanMember, fetchClanMembers } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { banClanMember, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(banClanMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
// Server returns the post-ban member total (was 5, now 4).
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
@@ -310,9 +306,8 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
describe("handleUnban", () => {
|
||||
it("removes ban from list and decrements total on success", async () => {
|
||||
const { unbanClanMember, fetchClanBans } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { unbanClanMember, fetchClanBans } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(unbanClanMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanBans as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [
|
||||
@@ -377,9 +372,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("calls kickMember and syncs memberCount on success", async () => {
|
||||
const { kickMember, fetchClanMembers } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { kickMember, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(kickMember as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
(fetchClanMembers as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
results: [],
|
||||
@@ -411,9 +405,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("does not mutate state when kickMember fails", async () => {
|
||||
const { kickMember, fetchClanMembers } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { kickMember, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(kickMember as ReturnType<typeof vi.fn>).mockResolvedValue({
|
||||
error: "clan_modal.error_generic",
|
||||
});
|
||||
@@ -600,9 +593,8 @@ describe("ClanModal — handlers", () => {
|
||||
|
||||
describe("handleJoin", () => {
|
||||
beforeEach(async () => {
|
||||
const { fetchClanDetail, fetchClanStats } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { fetchClanDetail, fetchClanStats } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(fetchClanDetail as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
makeClan({ isOpen: true, memberCount: 5 }),
|
||||
);
|
||||
@@ -615,9 +607,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("switches detail view into member mode immediately after open-clan join", async () => {
|
||||
const { joinClan, fetchClanMembers } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { joinClan, fetchClanMembers } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(joinClan as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
|
||||
status: "joined",
|
||||
});
|
||||
@@ -781,9 +772,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("clears confirmAction and removes the dialog after confirming", async () => {
|
||||
const { transferLeadership } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { transferLeadership } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(transferLeadership as ReturnType<typeof vi.fn>).mockResolvedValue(true);
|
||||
|
||||
const dialog = modal.querySelector("confirm-dialog");
|
||||
@@ -802,9 +792,8 @@ describe("ClanModal — handlers", () => {
|
||||
});
|
||||
|
||||
it("clears confirmAction when cancel is clicked, without calling the API", async () => {
|
||||
const { transferLeadership } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { transferLeadership } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
|
||||
const dialog = modal.querySelector("confirm-dialog");
|
||||
expect(dialog).toBeTruthy();
|
||||
|
||||
@@ -241,9 +241,8 @@ describe("ClanModal — rendering", () => {
|
||||
});
|
||||
|
||||
it("shows 0 in the stats row of the detail view when memberCount is undefined", async () => {
|
||||
const { fetchClanDetail, fetchClanStats } = await import(
|
||||
"../../../src/client/ClanApi"
|
||||
);
|
||||
const { fetchClanDetail, fetchClanStats } =
|
||||
await import("../../../src/client/ClanApi");
|
||||
(fetchClanDetail as ReturnType<typeof vi.fn>).mockResolvedValueOnce(
|
||||
makeClan({ memberCount: undefined }),
|
||||
);
|
||||
|
||||
+6
-8
@@ -5,7 +5,6 @@ import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { defineConfig, loadEnv, type Plugin } from "vite";
|
||||
import { createHtmlPlugin } from "vite-plugin-html";
|
||||
import tsconfigPaths from "vite-tsconfig-paths";
|
||||
import {
|
||||
type AssetManifest,
|
||||
buildAssetUrl,
|
||||
@@ -155,17 +154,13 @@ export default defineConfig(({ mode }) => {
|
||||
publicDir: isProduction ? false : "resources",
|
||||
|
||||
resolve: {
|
||||
tsconfigPaths: true,
|
||||
alias: {
|
||||
"protobufjs/minimal": path.resolve(
|
||||
__dirname,
|
||||
"node_modules/protobufjs/minimal.js",
|
||||
),
|
||||
resources: path.resolve(__dirname, "resources"),
|
||||
},
|
||||
},
|
||||
|
||||
plugins: [
|
||||
tsconfigPaths(),
|
||||
...(!isProduction
|
||||
? [serveProprietaryDir(proprietaryDir, resourcesDir)]
|
||||
: []),
|
||||
@@ -209,8 +204,11 @@ export default defineConfig(({ mode }) => {
|
||||
assetsDir: "assets", // Sub-directory for assets
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
vendor: ["pixi.js", "howler", "zod", "protobufjs"],
|
||||
manualChunks: (id) => {
|
||||
const vendorModules = ["pixi.js", "howler", "zod"];
|
||||
if (vendorModules.some((module) => id.includes(module))) {
|
||||
return "vendor";
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user