Merged in chore/eslint9 (pull request #2029)

chore: Update to ESLint 9

* wip: apply codemod and upgrade swc plugin

* Update eslint to 9 in scandic-web

apply code mod to config
fix existing lint issues

* Remove uneccessary fixupConfigRules

* Update eslint to 9 in design-system

* Add lint turbo dependency

* Move redis-api to eslint and prettier instead of biome

* Simplify eslint configs

* Clean up

* Apply linting


Approved-by: Linus Flood
This commit is contained in:
Anton Gunnarsson
2025-06-03 14:26:44 +00:00
parent 91278feb40
commit dd4ef527df
37 changed files with 858 additions and 497 deletions

View File

@@ -1,17 +1,17 @@
import "@/server/sentry.server.config";
import serverTiming from "@elysiajs/server-timing";
import { swagger } from "@elysiajs/swagger";
import * as Sentry from "@sentry/bun";
import { Elysia } from "elysia";
import { swagger } from "@elysiajs/swagger";
import { apiRoutes } from "@/routes/api";
import { healthRoutes } from "@/routes/health";
import { baseLogger } from "@/utils/logger";
import { env } from "@/env";
import serverTiming from "@elysiajs/server-timing";
import { AuthenticationError } from "@/errors/AuthenticationError";
import { ModelValidationError } from "@/errors/ModelValidationError";
import { apiRoutes } from "@/routes/api";
import { healthRoutes } from "@/routes/health";
import { setupShutdown } from "@/shutdown";
import { baseLogger } from "@/utils/logger";
setupShutdown();
@@ -48,7 +48,7 @@ if (env.IS_DEV) {
version: "1.0.0",
},
},
})
}),
);
}

View File

@@ -1,6 +1,7 @@
import { AuthenticationError } from "@/errors/AuthenticationError";
import type { Context } from "elysia";
import { env } from "@/env";
import { AuthenticationError } from "@/errors/AuthenticationError";
const API_KEY_HEADER = "x-api-key";

View File

@@ -1,11 +1,11 @@
import * as Sentry from "@sentry/bun";
import { Elysia, t } from "elysia";
import { redis } from "@/services/redis";
import { ModelValidationError } from "@/errors/ModelValidationError";
import { redis } from "@/services/redis";
import { loggerModule } from "@/utils/logger";
import { truncate } from "@/utils/truncate";
import { timeout } from "@/utils/timeout";
import { truncate } from "@/utils/truncate";
const MIN_LENGTH = 1;
@@ -42,7 +42,7 @@ export const cacheRoutes = new Elysia({ prefix: "/cache" })
{
query: QUERY_TYPE,
response: { 200: t.Object({ data: t.Any() }), 404: t.String() },
}
},
)
.put(
"/",
@@ -52,7 +52,7 @@ export const cacheRoutes = new Elysia({ prefix: "/cache" })
if (!body.ttl || body.ttl < 0) {
cacheRouteLogger.warn(
`PUT /cache ${key} with ttl=${body.ttl}, will not cache the data`
`PUT /cache ${key} with ttl=${body.ttl}, will not cache the data`,
);
return status("Bad Request", "ttl is required");
}
@@ -66,14 +66,14 @@ export const cacheRoutes = new Elysia({ prefix: "/cache" })
body: t.Object({ data: t.Any(), ttl: t.Number() }),
query: QUERY_TYPE,
response: { 204: t.Undefined(), 400: t.String() },
}
},
)
.delete(
"/",
async ({ query: { key, fuzzy } }) => {
key = validateKey(key);
cacheRouteLogger.debug(
`DELETE /cache ${key} ${fuzzy ? "fuzzy" : ""}`
`DELETE /cache ${key} ${fuzzy ? "fuzzy" : ""}`,
);
const deletedKeys: number = fuzzy
? await deleteWithPattern(`*${key}*`)
@@ -91,7 +91,7 @@ export const cacheRoutes = new Elysia({ prefix: "/cache" })
200: t.Object({ deletedKeys: t.Number() }),
400: t.String(),
},
}
},
);
function validateKey(key: string) {
@@ -99,7 +99,7 @@ function validateKey(key: string) {
if (parsedKey.length < MIN_LENGTH) {
throw new ModelValidationError(
"Key has to be at least 1 character long"
"Key has to be at least 1 character long",
);
}
@@ -122,7 +122,7 @@ async function deleteWithPattern(pattern: string) {
"MATCH",
pattern,
"COUNT",
SCAN_SIZE
SCAN_SIZE,
);
cursor = newCursor;

View File

@@ -1,7 +1,9 @@
import { Elysia } from "elysia";
import { cacheRoutes } from "./cache";
import { apiKeyMiddleware } from "@/middleware/apiKeyMiddleware";
import { cacheRoutes } from "./cache";
export const apiRoutes = new Elysia({ prefix: "/api" })
.guard({ beforeHandle: apiKeyMiddleware })
.use(cacheRoutes);

View File

@@ -1,8 +1,8 @@
import Elysia, { t } from "elysia";
import { redis } from "@/services/redis";
import { baseLogger, loggerModule } from "@/utils/logger";
import { env } from "@/env";
import { redis } from "@/services/redis";
import { baseLogger } from "@/utils/logger";
const healthLogger = baseLogger.child({
module: "health",
@@ -52,5 +52,5 @@ export const healthRoutes = new Elysia().get(
duration: t.String(),
}),
},
}
},
);

View File

@@ -1,7 +1,9 @@
import "@sentry/tracing";
import { env } from "@/env";
import * as Sentry from "@sentry/bun";
import { env } from "@/env";
Sentry.init({
dsn: env.SENTRY_DSN,
enabled: env.SENTRY_ENABLED,

View File

@@ -1,6 +1,7 @@
import { redisConfig, env } from "@/env";
import ioredis from "ioredis";
import { env, redisConfig } from "@/env";
const redis = new ioredis({
host: redisConfig.host,
port: redisConfig.port,

View File

@@ -1,5 +1,5 @@
import { loggerModule } from "@/utils/logger";
import { redis } from "@/services/redis";
import { loggerModule } from "@/utils/logger";
const shutdownLogger = loggerModule("shutdown");

View File

@@ -1,34 +1,36 @@
import pino from "pino";
import { mask } from "./mask";
import { env } from "@/env";
const serializers: { [key: string]: pino.SerializerFn } = {
password: (payload) => {
if (payload) {
return env.IS_DEV
? mask(payload)
: mask(payload, {
visibleStart: 0,
visibleEnd: 0,
});
}
import { mask } from "./mask";
return payload;
},
email: (payload) => {
if (payload) {
return env.IS_DEV ? payload : mask(payload);
}
return payload;
},
const serializers: { [key: string]: pino.SerializerFn } = {
password: (payload) => {
if (payload) {
return env.IS_DEV
? mask(payload)
: mask(payload, {
visibleStart: 0,
visibleEnd: 0,
});
}
return payload;
},
email: (payload) => {
if (payload) {
return env.IS_DEV ? payload : mask(payload);
}
return payload;
},
};
export const baseLogger = pino({
level: process.env.LOG_LEVEL || "info",
timestamp: pino.stdTimeFunctions.isoTime,
serializers,
level: process.env.LOG_LEVEL || "info",
timestamp: pino.stdTimeFunctions.isoTime,
serializers,
});
export const loggerModule = (loggerName: string) => {
return baseLogger.child({ module: loggerName });
return baseLogger.child({ module: loggerName });
};

View File

@@ -1,42 +1,43 @@
import { describe, it, expect } from "bun:test";
import { describe, expect, it } from "bun:test";
import { mask } from "./mask";
describe("mask", () => {
it("should return empty string for empty input", () => {
expect(mask("")).toBe("");
});
it("should return empty string for empty input", () => {
expect(mask("")).toBe("");
});
it("should mask string with default parameters", () => {
expect(mask("1234567890")).toBe("12******90");
});
it("should mask string with default parameters", () => {
expect(mask("1234567890")).toBe("12******90");
});
it("should show custom number of characters at start", () => {
expect(mask("1234567890", { visibleStart: 3 })).toBe("123*****90");
});
it("should show custom number of characters at start", () => {
expect(mask("1234567890", { visibleStart: 3 })).toBe("123*****90");
});
it("should show custom number of characters at end", () => {
expect(mask("1234567890", { visibleStart: 2, visibleEnd: 3 })).toBe(
"12*****890",
);
});
it("should show custom number of characters at end", () => {
expect(mask("1234567890", { visibleStart: 2, visibleEnd: 3 })).toBe(
"12*****890",
);
});
it("should mask entire string when visible parts exceed length", () => {
expect(mask("123", { visibleStart: 2, visibleEnd: 2 })).toBe("***");
});
it("should mask entire string when visible parts exceed length", () => {
expect(mask("123", { visibleStart: 2, visibleEnd: 2 })).toBe("***");
});
it("should handle undefined end part", () => {
expect(mask("1234567890", { visibleStart: 2, visibleEnd: 0 })).toBe(
"12********",
);
});
it("should handle undefined end part", () => {
expect(mask("1234567890", { visibleStart: 2, visibleEnd: 0 })).toBe(
"12********",
);
});
it("should handle long strings", () => {
expect(mask("12345678901234567890")).toBe("12**********90");
});
it("should handle long strings", () => {
expect(mask("12345678901234567890")).toBe("12**********90");
});
it("should handle emails", () => {
expect(mask("test.testsson@scandichotels.com")).toBe(
"te*********on@sc*********ls.com",
);
});
it("should handle emails", () => {
expect(mask("test.testsson@scandichotels.com")).toBe(
"te*********on@sc*********ls.com",
);
});
});