refactor: migrate bot/ to a sensible logging solution

This commit is contained in:
zk
2026-03-12 20:19:27 +00:00
parent fc3e2bf8e1
commit d7bb9541f6
29 changed files with 175 additions and 221 deletions
+10 -10
View File
@@ -9,36 +9,36 @@
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
}
"source.fixAll.biome": "explicit"
}
},
"[typescriptreact]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
}
"source.fixAll.biome": "explicit"
}
},
"[javascript]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
}
"source.fixAll.biome": "explicit"
}
},
"[json]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
}
"source.fixAll.biome": "explicit"
}
},
"[jsonc]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "biomejs.biome",
"editor.codeActionsOnSave": {
"source.fixAll.biome": "explicit",
}
"source.fixAll.biome": "explicit"
}
},
"files.associations": {
"Justfile-*": "makefile"
+1
View File
@@ -19,6 +19,7 @@ fix: fmt
just gen
bun run --filter '*' lint-fix
.scripts/ts_autoinherit.js
# Automatically fix any issues we can in the codebase and then
# make a commit for them
+24
View File
@@ -95,6 +95,7 @@
"mei-logger": "catalog:",
"monk": "catalog:",
"node-fetch": "catalog:",
"pino": "^10.3.1",
"prudence": "catalog:",
"seq-logging": "catalog:",
"tachi-common": "workspace:*",
@@ -400,6 +401,7 @@
"node-html-parser": "catalog:",
"nodemailer": "catalog:",
"pg": "catalog:",
"pino": "^10.3.1",
"prudence": "catalog:",
"rate-limit-redis": "catalog:",
"redis": "catalog:",
@@ -1200,6 +1202,8 @@
"@paralleldrive/cuid2": ["@paralleldrive/cuid2@2.3.1", "", { "dependencies": { "@noble/hashes": "^1.1.5" } }, "sha512-XO7cAxhnTZl0Yggq6jOgjiOHhbgcO4NqFqwSmQpjK3b6TEE6Uj/jfSk6wzYyemh3+I0sHirKSetjQwn5cZktFw=="],
"@pinojs/redact": ["@pinojs/redact@0.4.0", "", {}, "sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg=="],
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
"@popperjs/core": ["@popperjs/core@2.11.8", "", {}, "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A=="],
@@ -1636,6 +1640,8 @@
"asynckit": ["asynckit@0.4.0", "", {}, "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="],
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
"auto-bind": ["auto-bind@4.0.0", "", {}, "sha512-Hdw8qdNiqdJ8LqT0iK0sVzkFbzg6fhnQqqfWhBDxcHZvU75+B+ayzTy8x+k5Ix0Y92XOhOUlx74ps+bA6BeYMQ=="],
"available-typed-arrays": ["available-typed-arrays@1.0.7", "", { "dependencies": { "possible-typed-array-names": "^1.0.0" } }, "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ=="],
@@ -2782,6 +2788,8 @@
"oblivious-set": ["oblivious-set@1.0.0", "", {}, "sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw=="],
"on-exit-leak-free": ["on-exit-leak-free@2.1.2", "", {}, "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA=="],
"on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="],
"on-headers": ["on-headers@1.0.2", "", {}, "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="],
@@ -2874,6 +2882,12 @@
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
"pino": ["pino@10.3.1", "", { "dependencies": { "@pinojs/redact": "^0.4.0", "atomic-sleep": "^1.0.0", "on-exit-leak-free": "^2.1.0", "pino-abstract-transport": "^3.0.0", "pino-std-serializers": "^7.0.0", "process-warning": "^5.0.0", "quick-format-unescaped": "^4.0.3", "real-require": "^0.2.0", "safe-stable-stringify": "^2.3.1", "sonic-boom": "^4.0.1", "thread-stream": "^4.0.0" }, "bin": { "pino": "bin.js" } }, "sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg=="],
"pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="],
"pino-std-serializers": ["pino-std-serializers@7.1.0", "", {}, "sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw=="],
"pirates": ["pirates@3.0.2", "", { "dependencies": { "node-modules-regexp": "^1.0.0" } }, "sha512-c5CgUJq6H2k6MJz72Ak1F5sN9n9wlSlJyEnwvpm9/y3WB4E3pHBDT2c6PEiS1vyJvq2bUxUAIu0EGf8Cx4Ic7Q=="],
"pkg-dir": ["pkg-dir@4.2.0", "", { "dependencies": { "find-up": "^4.0.0" } }, "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="],
@@ -2908,6 +2922,8 @@
"process-on-spawn": ["process-on-spawn@1.1.0", "", { "dependencies": { "fromentries": "^1.2.0" } }, "sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q=="],
"process-warning": ["process-warning@5.0.0", "", {}, "sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA=="],
"prom-client": ["prom-client@15.1.3", "", { "dependencies": { "@opentelemetry/api": "^1.4.0", "tdigest": "^0.1.1" } }, "sha512-6ZiOBfCywsD4k1BN9IX0uZhF+tJkV8q8llP64G5Hajs4JOeVLPCwpPVcpXy3BwYiUGgyJzsJJQeOIv7+hDSq8g=="],
"promise": ["promise@7.3.1", "", { "dependencies": { "asap": "~2.0.3" } }, "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg=="],
@@ -2940,6 +2956,8 @@
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
"quick-format-unescaped": ["quick-format-unescaped@4.0.4", "", {}, "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg=="],
"ramda": ["ramda@0.32.0", "", {}, "sha512-GQWAHhxhxWBWA8oIBr1XahFVjQ9Fic6MK9ikijfd4TZHfE2+urfk+irVlR5VOn48uwMgM+loRRBJd6Yjsbc0zQ=="],
"random-bytes": ["random-bytes@1.0.0", "", {}, "sha512-iv7LhNVO047HzYR3InF6pUcUsPQiHTM1Qal51DcGSuZFBil1aBBWG5eHPNek7bvILMaYJ/8RU1e8w1AMdHmLQQ=="],
@@ -2994,6 +3012,8 @@
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
"real-require": ["real-require@0.2.0", "", {}, "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg=="],
"rechoir": ["rechoir@0.8.0", "", { "dependencies": { "resolve": "^1.20.0" } }, "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ=="],
"redeyed": ["redeyed@2.1.1", "", { "dependencies": { "esprima": "~4.0.0" } }, "sha512-FNpGGo1DycYAdnrKFxCMmKYgo/mILAqtRYbkdQD8Ep/Hk2PQ5+aEAEx+IU713RTDmuBaH0c8P5ZozurNu5ObRQ=="],
@@ -3122,6 +3142,8 @@
"snappy": ["snappy@7.3.3", "", { "optionalDependencies": { "@napi-rs/snappy-android-arm-eabi": "7.3.3", "@napi-rs/snappy-android-arm64": "7.3.3", "@napi-rs/snappy-darwin-arm64": "7.3.3", "@napi-rs/snappy-darwin-x64": "7.3.3", "@napi-rs/snappy-freebsd-x64": "7.3.3", "@napi-rs/snappy-linux-arm-gnueabihf": "7.3.3", "@napi-rs/snappy-linux-arm64-gnu": "7.3.3", "@napi-rs/snappy-linux-arm64-musl": "7.3.3", "@napi-rs/snappy-linux-ppc64-gnu": "7.3.3", "@napi-rs/snappy-linux-riscv64-gnu": "7.3.3", "@napi-rs/snappy-linux-s390x-gnu": "7.3.3", "@napi-rs/snappy-linux-x64-gnu": "7.3.3", "@napi-rs/snappy-linux-x64-musl": "7.3.3", "@napi-rs/snappy-openharmony-arm64": "7.3.3", "@napi-rs/snappy-wasm32-wasi": "7.3.3", "@napi-rs/snappy-win32-arm64-msvc": "7.3.3", "@napi-rs/snappy-win32-ia32-msvc": "7.3.3", "@napi-rs/snappy-win32-x64-msvc": "7.3.3" } }, "sha512-UDJVCunvgblRpfTOjo/uT7pQzfrTsSICJ4yVS4aq7SsGBaUSpJwaVP15nF//jqinSLpN7boe/BqbUmtWMTQ5MQ=="],
"sonic-boom": ["sonic-boom@4.2.1", "", { "dependencies": { "atomic-sleep": "^1.0.0" } }, "sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q=="],
"source-map": ["source-map@0.5.7", "", {}, "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ=="],
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
@@ -3258,6 +3280,8 @@
"text-hex": ["text-hex@1.0.0", "", {}, "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg=="],
"thread-stream": ["thread-stream@4.0.0", "", { "dependencies": { "real-require": "^0.2.0" } }, "sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA=="],
"tildify": ["tildify@2.0.0", "", {}, "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw=="],
"tiny-invariant": ["tiny-invariant@1.3.3", "", {}, "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="],
+1 -1
View File
@@ -25,6 +25,6 @@ funcsave _tide_item_tachi > /dev/null
set -U tide_tachi_color cc527a
set -U tide_tachi_bg_color 131313
set -U tide_right_prompt_items status cmd_duration context jobs direnv bun node python rustc java php pulumi ruby go gcloud kubectl distrobox toolbox terraform aws nix_shell crystal elixir zig time tachi
set -U tide_right_prompt_items status cmd_duration context jobs direnv bun node python rustc java php pulumi ruby go gcloud kubectl distrobox toolbox terraform aws nix_shell crystal elixir zig tachi time
# rr
+14 -5
View File
@@ -28,10 +28,10 @@
},
"catalog": {
"@typescript/native-preview": "7.0.0-dev.20260309.1",
"@types/node": "18.11.18",
"@types/node": "*",
"@types/pg": "^8.11.11",
"ts-node": "^8.5.2",
"typescript": "^3.7.2",
"typescript": "^4.3.4",
"kysely": "^0.27.5",
"pg": "^8.13.3",
"@types/history": "4.7.11",
@@ -203,8 +203,8 @@
"which": "^2.0.2",
"@types/eslint__js": "8.42.3",
"@eslint/js": "^9.20.0",
"@typescript-eslint/eslint-plugin": "^8.23.0",
"@typescript-eslint/parser": "^8.23.0",
"@typescript-eslint/eslint-plugin": "^4.27.0",
"@typescript-eslint/parser": "^4.27.0",
"@typescript-eslint/utils": "^8.24.1",
"eslint-config-prettier": "^9.1.0",
"eslint-import-resolver-typescript": "^3.7.0",
@@ -218,7 +218,16 @@
"typescript-eslint": "^8.24.1",
"vitest": "~3.2.0",
"@vitest/coverage-v8": "~3.2.0",
"@vitest/coverage-istanbul": "~3.2.0"
"@vitest/coverage-istanbul": "~3.2.0",
"pino": "^10.3.1",
"@types/jest": "^26.0.23",
"eslint": "^7.29.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-jest": "^24.3.6",
"jest": "^27.0.4",
"standard": "^16.0.3",
"ts-jest": "^27.0.3",
"tsd": "^0.17.0"
},
"overrides": {
"@types/mongodb": "3.6.20",
-3
View File
@@ -8,8 +8,5 @@ export default [
},
{
files: ["**/*.{ts,tsx}"],
rules: {
"@typescript-eslint/no-unsafe-assignment": "warn",
},
},
];
+2 -1
View File
@@ -38,9 +38,10 @@
"json5": "catalog:",
"lodash": "catalog:",
"luxon": "catalog:",
"mei-logger": "catalog:",
"mei-log": "catalog:",
"monk": "catalog:",
"node-fetch": "catalog:",
"pino": "catalog:",
"prudence": "catalog:",
"seq-logging": "catalog:",
"tachi-common": "workspace:*",
+9 -15
View File
@@ -14,9 +14,9 @@ config();
// Reads the bots config file from $pwd/conf.json5.
// Validates it using prudence.
// the real logger tries to bind to discord, and is dependent on the options
// the real log tries to bind to discord, and is dependent on the options
// below.
const logger = console;
const log = console;
export interface BotConfig {
TACHI_SERVER_LOCATION: string;
@@ -43,10 +43,10 @@ function ParseBotConfig(fileLoc = "conf.json5"): BotConfig {
try {
const contents = fs.readFileSync(fileLoc, "utf-8");
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
data = JSON5.parse(contents);
} catch (err) {
logger.error("Failed to find/parse a valid conf.json5 file. Cannot boot.", { err });
log.error({ err }, "Failed to find/parse a valid conf.json5 file. Cannot boot.");
throw err;
}
@@ -93,7 +93,7 @@ function ParseBotConfig(fileLoc = "conf.json5"): BotConfig {
});
if (err) {
logger.error(FormatPrError(err, "Invalid conf.json5 file. Cannot safely boot."));
log.error(FormatPrError(err, "Invalid conf.json5 file. Cannot safely boot."));
throw err;
}
@@ -105,8 +105,6 @@ export interface ProcessEnvironment {
nodeEnv: "dev" | "production" | "staging" | "test";
mongoUrl: string;
port: integer;
seqUrl?: string;
seqApiKey?: string;
}
function ParseEnvVars() {
@@ -123,15 +121,13 @@ function ParseEnvVars() {
PORT: (self) =>
p.isPositiveInteger(Number(self)) === true ||
"Should be a string representing a whole integer port.",
SEQ_URL: "*string",
SEQ_API_KEY: "*string",
},
{},
{ allowExcessKeys: true },
);
if (err) {
logger.error(FormatPrError(err, "Invalid environment. Cannot safely boot."));
log.error(FormatPrError(err, "Invalid environment. Cannot safely boot."));
throw err;
}
@@ -140,8 +136,6 @@ function ParseEnvVars() {
nodeEnv: process.env.NODE_ENV,
mongoUrl: process.env.MONGO_URL,
port: Number(process.env.PORT),
seqUrl: process.env.SEQ_URL,
seqApiKey: process.env.SEQ_API_KEY,
} as ProcessEnvironment;
}
@@ -154,13 +148,13 @@ async function GetServerConfig() {
// this fetch is complete, and it saves us having to do a singleton pattern or worse.
// This *should* be solved with top-level-await, but good luck actually getting
// typescript to output the right stuff here.
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const res = await fetch(`${BotConfig.TACHI_SERVER_LOCATION}/api/v1/config`).then((res) =>
res.json(),
);
if (!res.success) {
logger.error(
log.error(
`Failed to fetch server info from ${BotConfig.TACHI_SERVER_LOCATION}. Can't run.`,
);
process.exit(1);
@@ -177,7 +171,7 @@ export const ProcessEnv = ParseEnvVars();
// This warns people if their parent server supports games that they aren't acknowledging.
for (const game of ServerConfig.GAMES) {
if (!Object.prototype.hasOwnProperty.call(BotConfig.DISCORD.GAME_CHANNELS, game)) {
logger.warn(
log.warn(
`${ServerConfig.NAME} declares support for ${game}, but no channel is mapped to it in your conf.json5.`,
);
}
-17
View File
@@ -1,17 +0,0 @@
export enum LoggerLayers {
apiRequests = "apiRequests",
botConfigSetup = "botConfigSetup",
buildChartEmbed = "buildChartEmbed",
buildProfileEmbed = "buildProfileEmbed",
chartSearch = "chartSearch",
client = "client",
database = "database",
databaseQuery = "databaseQuery",
profile = "profile",
selectInteractionHandler = "selectInteractionHandler",
server = "server",
serverAuth = "serverAuth",
slashCommands = "slashCommands",
tachiAuth = "tachiAuth",
tachiFetch = "tachiFetch",
}
+7 -10
View File
@@ -1,23 +1,20 @@
import { log } from "#utils/log";
import monk from "monk";
import type { DiscordUserMapDocument } from "./documents";
import { ProcessEnv } from "../config";
import { LoggerLayers } from "../data/data";
import { CreateLayeredLogger } from "../utils/logger";
const logger = CreateLayeredLogger(LoggerLayers.database);
logger.info(`Connecting to ${ProcessEnv.mongoUrl}...`);
log.info(`Connecting to ${ProcessEnv.mongoUrl}...`);
const monkDB = monk(ProcessEnv.mongoUrl);
monkDB
.then(() => {
logger.info(`Database connection successful.`);
log.info(`Database connection successful.`);
})
.catch((err) => {
logger.crit(err);
log.fatal(err);
process.exit(1);
});
@@ -26,16 +23,16 @@ const db = {
};
export async function SetIndexes(hardReset = false) {
logger.info(`Recieved request to set indexes.`);
log.info(`Recieved request to set indexes.`);
if (hardReset) {
logger.warn(`Hard resetting indexes!`);
log.warn(`Hard resetting indexes!`);
await db.discordUserMap.dropIndexes();
}
await db.discordUserMap.createIndex({ discordID: 1 }, { unique: true });
logger.info(`Indexes have been set.`);
log.info(`Indexes have been set.`);
}
export default db;
+4 -5
View File
@@ -1,23 +1,22 @@
import type { integer } from "tachi-common";
import { log } from "#utils/log.js";
import type { DiscordUserMapDocument } from "./documents";
import { LoggerLayers } from "../data/data";
import { CreateLayeredLogger } from "../utils/logger";
import db from "./mongo";
const logger = CreateLayeredLogger(LoggerLayers.databaseQuery);
export function GetUserAndTokenForDiscordID(
discordID: string,
): Promise<DiscordUserMapDocument | null> {
logger.verbose(`Fetching linked user & token with DiscordID: ${discordID}.`);
log.debug(`Fetching linked user & token with DiscordID: ${discordID}.`);
return db.discordUserMap.findOne({ discordID });
}
export async function GetUserIDForDiscordID(discordID: string): Promise<integer | null> {
logger.verbose(`Fetching linked user & token with DiscordID: ${discordID}.`);
log.debug(`Fetching linked user & token with DiscordID: ${discordID}.`);
const user = await db.discordUserMap.findOne({ discordID }, { projection: { userID: 1 } });
@@ -1,12 +1,9 @@
import { log } from "#utils/log";
import { type CommandInteraction, MessageEmbed } from "discord.js";
import type { DiscordUserMapDocument } from "../database/documents";
import { LoggerLayers } from "../data/data";
import { SLASH_COMMANDS } from "../slashCommands/commands";
import { CreateLayeredLogger } from "../utils/logger";
const logger = CreateLayeredLogger(LoggerLayers.slashCommands);
/**
* Handles incoming command requests by resolving the interaction to the command
@@ -29,7 +26,7 @@ export async function handleIsCommand(
await interaction.deferReply();
logger.verbose(`Running ${command.info.name} interaction.`);
log.debug(`Running ${command.info.name} interaction.`);
try {
const response = await command.exec(interaction, requestingUser);
@@ -43,13 +40,13 @@ export async function handleIsCommand(
});
}
} catch (err) {
logger.error(`An error occured while executing a command.`, { command, err });
log.error({ command, err }, `An error occured while executing a command.`);
void interaction.editReply(
`An error has occured while executing this command (${err}). This has been reported.`,
);
}
} catch (e) {
logger.error("Failed to handle isCommand interaction", { error: e });
log.error({ error: e }, "Failed to handle isCommand interaction");
}
}
+11 -16
View File
@@ -1,17 +1,16 @@
import { log } from "#utils/log.js";
import { GetLimboChannel } from "#utils/misc";
import { Client, type CommandInteraction, Intents, type SelectMenuInteraction } from "discord.js";
import { BotConfig, ProcessEnv, ServerConfig } from "./config";
import { LoggerLayers } from "./data/data";
import { GetUserAndTokenForDiscordID } from "./database/queries";
import { handleIsCommand } from "./interactionHandlers/handleIsCommand";
import { app } from "./server/server";
import { RegisterSlashCommands } from "./slashCommands/register";
import { CreateLayeredLogger } from "./utils/logger";
import { VERSION_PRETTY } from "./version";
// hack: DiscordJS's endpoints sometimes return bigints that end up in our logger.
// when our logger tries to format that content, JSON.stringify fails.
// hack: DiscordJS's endpoints sometimes return bigints that end up in our log.
// when our log tries to format that content, JSON.stringify fails.
//
// I personally cannot believe that the spec now made JSON.stringify fallible in such
// a common case. It's kind of absurdly ridiculous. But hey ho; monkey patch our way
@@ -21,8 +20,6 @@ BigInt.prototype.toJSON = function toJSON() {
return this.toString();
};
const logger = CreateLayeredLogger(LoggerLayers.client);
export const client = new Client({
intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.DIRECT_MESSAGES, Intents.FLAGS.GUILD_MESSAGES],
});
@@ -53,11 +50,11 @@ client.on("interactionCreate", async (interaction) => {
if (interaction.isCommand()) {
await handleIsCommand(interaction, requestingUser);
}
} catch (e) {
} catch (err) {
await interaction.channel?.send(
"We failed to handle this request. Are your DMs shut to non-friends?",
);
logger.error("Failed to run interaction.", { interaction, e });
log.error({ interaction, err }, "Failed to run interaction.");
}
});
@@ -79,25 +76,25 @@ We've sent you a DM with instructions on how to link your account.`,
void (async () => {
try {
logger.info(`Booting Tachi Bot ${VERSION_PRETTY}.`);
log.info(`Booting Tachi Bot ${VERSION_PRETTY}.`);
// Login to discord.
await client.login(BotConfig.DISCORD.TOKEN);
logger.info(`Logged in successfully to ${client.guilds.cache.size} guilds.`);
log.info(`Logged in successfully to ${client.guilds.cache.size} guilds.`);
// Mount our express server.
app.listen(ProcessEnv.port);
logger.info(
log.info(
`Invite URL: https://discord.com/api/oauth2/authorize?client_id=${
client.application!.id
}&permissions=8&scope=applications.commands%20bot`,
);
await RegisterSlashCommands(client);
} catch (err) {
logger.crit("Failed to properly boot.", err);
} catch (error) {
log.fatal({ error }, "Failed to properly boot.");
process.exit(1);
}
})();
@@ -105,7 +102,5 @@ void (async () => {
// taken from https://nodejs.org/api/process.html#process_event_unhandledrejection
// to avoid future deprecation.
process.on("unhandledRejection", (reason, promise) => {
// @ts-expect-error reason is an error, and the logger can handle errors
// it just refuses.
logger.error(reason, { promise });
log.error({ promise }, reason as string);
});
+6 -7
View File
@@ -1,10 +1,9 @@
import type { RequestHandler } from "express";
import { log } from "#utils/log";
import { BotConfig } from "../config";
import { LoggerLayers } from "../data/data";
import { CreateLayeredLogger } from "../utils/logger";
const logger = CreateLayeredLogger(LoggerLayers.serverAuth);
/**
* Middleware that checks that a webhook request has Authorization set to
@@ -17,7 +16,7 @@ export const ValidateWebhookRequest: RequestHandler = (req, res, next) => {
const auth = req.header("Authorization");
if (!auth) {
logger.info(`Received unauthed request from ${req.ip}.`);
log.info(`Received unauthed request from ${req.ip}.`);
return res.status(401).json({
success: false,
description: "No authorization provided.",
@@ -27,7 +26,7 @@ export const ValidateWebhookRequest: RequestHandler = (req, res, next) => {
const [type, value] = auth.split(" ", 2);
if (type !== "Bearer") {
logger.info(`Received invalid auth type request from ${req.ip}, got auth type ${type}.`);
log.info(`Received invalid auth type request from ${req.ip}, got auth type ${type}.`);
return res.status(400).json({
success: false,
description: "Invalid authorization type. Expected Bearer.",
@@ -35,7 +34,7 @@ export const ValidateWebhookRequest: RequestHandler = (req, res, next) => {
}
if (value !== BotConfig.OAUTH.CLIENT_SECRET) {
logger.warn(
log.warn(
`Recieved invalid auth value from ${req.ip}. Has the client secret been changed?`,
);
return res.status(403).json({
@@ -44,7 +43,7 @@ export const ValidateWebhookRequest: RequestHandler = (req, res, next) => {
});
}
logger.debug("Webhook authorisation successful.");
log.debug("Webhook authorisation successful.");
next();
};
+12 -16
View File
@@ -1,15 +1,13 @@
import type { APITokenDocument, UserDocument, WebhookEvents } from "tachi-common";
import { client } from "#main";
import { log } from "#utils/log.js";
import { HandleQuestAchievedV1 } from "#webhookHandlers/questAchieved";
import express, { type Express } from "express";
import path from "path";
import { BotConfig, ProcessEnv } from "../config";
import { LoggerLayers } from "../data/data";
import db from "../database/mongo";
import { RequestTypes, TachiServerV1Get, TachiServerV1Request } from "../utils/fetchTachi";
import { CreateLayeredLogger } from "../utils/logger";
import { VERSION_PRETTY } from "../version";
import { HandleClassUpdateV1 } from "../webhookHandlers/classUpdate";
import { HandleGoalAchievedV1 } from "../webhookHandlers/goalsAchieved";
@@ -17,7 +15,6 @@ import { ValidateWebhookRequest } from "./middleware";
export const app: Express = express();
const logger = CreateLayeredLogger(LoggerLayers.server);
app.use(express.json());
@@ -33,7 +30,7 @@ app.set("query parser", "simple");
*
* @name GET /
*/
app.get("/", (req, res) =>
app.get("/", (_req, res) =>
res.status(200).json({
success: true,
description: "Bot is online!",
@@ -76,7 +73,7 @@ app.get("/oauth/callback", async (req, res) => {
);
if (!tokenRes.success) {
logger.error(
log.error(
`Failed to convert code ${req.query.code} to a token. ${tokenRes.description} Cannot auth.`,
);
return res.status(401).json({
@@ -91,7 +88,8 @@ app.get("/oauth/callback", async (req, res) => {
const whoamiRes = await TachiServerV1Get<UserDocument>("/users/me", apiToken);
if (!whoamiRes.success) {
logger.severe("Failed to request user with token we just got?", { discordID });
log.error({ discordID }
, "Failed to request user with token we just got?");
return res
.status(500)
.send(
@@ -101,12 +99,12 @@ app.get("/oauth/callback", async (req, res) => {
const user = whoamiRes.body;
logger.info(`Saving user-discord-link for ${user.username} (id: ${user.id}).`);
log.info(`Saving user-discord-link for ${user.username} (id: ${user.id}).`);
const existingLink = await db.discordUserMap.findOne({ userID: user.id });
if (existingLink) {
logger.info(`Updating user-discord-link for ${user.username} (id: ${user.id})`);
log.info(`Updating user-discord-link for ${user.username} (id: ${user.id})`);
await db.discordUserMap.update(
{
@@ -163,7 +161,7 @@ app.post("/webhook", ValidateWebhookRequest, async (req, res) => {
// to define new webhooks, and the bot might not
// However, tachi-(server/common) may recieve an update
// According to the types, this should never happen.
logger.warn(
log.warn(
`Received unknown webhook event ${
(webhookEvent as WebhookEvents).type
}. Have we got support for this?`,
@@ -183,7 +181,7 @@ app.post("/webhook", ValidateWebhookRequest, async (req, res) => {
*
* @name ALL *
*/
app.all("*", (req, res) =>
app.all("*", (_req, res) =>
res.status(404).json({
success: false,
description: "Nothing found here.",
@@ -210,16 +208,14 @@ const MainExpressErrorHandler: express.ErrorRequestHandler = (err, req, res, _ne
const expErr: ExpressJSONErr = err as ExpressJSONErr;
if (expErr.status === 400 && "body" in expErr) {
logger.info(`Error in parsing JSON in request body from ${req.url}`, {
url: req.originalUrl,
});
log.info({ url: req.originalUrl, err: err }, `Error in parsing JSON in request body from ${req.url}`);
return res.status(400).send({ success: false, description: err.message });
}
// else, this isn't a JSON parsing error
}
logger.error(err, req.route);
log.error({ err, route: req.route }, "Fatal error propagated to server root?");
return res.status(500).json({
success: false,
@@ -229,4 +225,4 @@ const MainExpressErrorHandler: express.ErrorRequestHandler = (err, req, res, _ne
app.use(MainExpressErrorHandler);
logger.info(`Starting express server on port ${ProcessEnv.port}.`);
log.info(`Starting express server on port ${ProcessEnv.port}.`);
+9 -12
View File
@@ -1,15 +1,12 @@
import type { Client } from "discord.js";
import { log } from "#utils/log";
import { REST } from "@discordjs/rest";
import { Routes } from "discord-api-types/v9";
import { BotConfig, ProcessEnv } from "../config";
import { LoggerLayers } from "../data/data";
import { CreateLayeredLogger } from "../utils/logger";
import { SLASH_COMMANDS } from "./commands";
const logger = CreateLayeredLogger(LoggerLayers.slashCommands);
const rest = new REST({
version: "9",
}).setToken(BotConfig.DISCORD.TOKEN);
@@ -23,18 +20,18 @@ export async function RegisterSlashCommands(client: Client): Promise<void> {
const commandsArray = [...SLASH_COMMANDS.values()];
// always unregister guild slash commands, just in case.
logger.info(`Unregistering guild slash commands.`);
log.info(`Unregistering guild slash commands.`);
await UnregisterAllCommands(client);
if (ProcessEnv.nodeEnv === "production") {
logger.info(`Updating global commands.`);
log.info(`Updating global commands.`);
await rest.put(Routes.applicationCommands(client.application!.id), {
body: commandsArray.map((command) => command.info),
});
} else {
logger.info("Registering guild slash commands.");
log.info("Registering guild slash commands.");
await rest.put(
Routes.applicationGuildCommands(
@@ -47,9 +44,9 @@ export async function RegisterSlashCommands(client: Client): Promise<void> {
);
}
logger.info("Successfully registered guild slash commands.");
log.info("Successfully registered guild slash commands.");
} catch (err) {
logger.error("Failed to register guild slash commands.", err);
log.error({ err }, "Failed to register guild slash commands.");
throw err;
}
}
@@ -59,7 +56,7 @@ export async function RegisterSlashCommands(client: Client): Promise<void> {
*/
async function UnregisterAllCommands(client: Client): Promise<void> {
try {
logger.info("Tidying old guild slash commands.");
log.info("Tidying old guild slash commands.");
const guilds = client.guilds.cache;
// discord.js doesn't use arrays because those aren't cool anymore
@@ -77,9 +74,9 @@ async function UnregisterAllCommands(client: Client): Promise<void> {
// parallelise waiting for these to be deleted.
await Promise.all(promises);
logger.info(`Successfully tidied ${promises.length} old guild slash commands.`);
log.info(`Successfully tidied ${promises.length} old guild slash commands.`);
} catch (err) {
logger.error("Failed to tidy old guild slash commands.", err);
log.error({ err }, "Failed to tidy old guild slash commands.");
throw err;
}
+3 -6
View File
@@ -13,16 +13,13 @@ import type {
} from "tachi-common";
import { BotConfig } from "#config";
import { log } from "#utils/log";
import type { ImportDeferred, ImportPollStatus, UGPTStats } from "./returnTypes";
import { LoggerLayers } from "../data/data";
import { RequestTypes, TachiServerV1Get, TachiServerV1Request } from "./fetchTachi";
import { CreateLayeredLogger } from "./logger";
import { Sleep } from "./misc";
const logger = CreateLayeredLogger(LoggerLayers.apiRequests);
export async function GetUserInfo(userID: string | integer) {
const res = await TachiServerV1Get<UserDocument>(`/users/${userID}`, null);
@@ -116,7 +113,7 @@ export async function PerformScoreImport(
if (!initRes.success) {
if (initRes.statusCode >= 500) {
logger.error(`Failed to perform score import on ${url}.`, { body });
log.error({ body }, `Failed to perform score import on ${url}.`);
throw new Error(`Failed to perform import on ${url}.`);
} else {
return initRes.description;
@@ -172,7 +169,7 @@ Please go to ${BotConfig.TACHI_SERVER_LOCATION}/u/me/integrations/services to un
}
}
logger.error(`Unexpected status code ${initRes.statusCode} returned from ${url}.`, { body });
log.error({ body }, `Unexpected status code ${initRes.statusCode} returned from ${url}.`);
throw new Error(`Unexpected status code ${initRes.statusCode} returned from ${url}.`);
}
+11 -14
View File
@@ -1,14 +1,11 @@
import type { integer, SuccessfulAPIResponse, UnsuccessfulAPIResponse } from "tachi-common";
import { log } from "#utils/log";
import fetch from "node-fetch";
import { URLSearchParams } from "url";
import { BotConfig } from "../config";
import { LoggerLayers } from "../data/data";
import { VERSION_STR } from "../version";
import { CreateLayeredLogger } from "./logger";
const logger = CreateLayeredLogger(LoggerLayers.tachiFetch);
export type APIResponse<T> = (({ body: null } & UnsuccessfulAPIResponse) | SuccessfulAPIResponse<T>) & {
statusCode: integer;
@@ -41,9 +38,9 @@ export async function TachiServerV1Request<T>(
body: unknown = {},
): Promise<APIResponse<T>> {
const realUrl = PrependTachiUrl(url, "1");
const loggerUrl = `${method} ${realUrl}`;
const logUrl = `${method} ${realUrl}`;
logger.debug(`Making a request to ${loggerUrl}.`);
log.debug(`Making a request to ${logUrl}.`);
try {
const res = await fetch(realUrl, {
@@ -60,11 +57,11 @@ export async function TachiServerV1Request<T>(
const contents = { ...json, statusCode: res.status };
LogRequestResult(loggerUrl, contents);
LogRequestResult(logUrl, contents);
return contents;
} catch (err) {
logger.error(`Failed while requesting ${method} ${realUrl}.`, { err });
log.error({ err }, `Failed while requesting ${method} ${realUrl}.`);
// Throw the error upwards for it to be caught be a higher handler.
throw err;
@@ -94,7 +91,7 @@ export async function TachiServerV1Get<T = unknown>(
const realUrl = `${PrependTachiUrl(url, "1")}?${urlParams.toString()}`;
logger.verbose(`GET ${realUrl}`);
log.debug(`GET ${realUrl}`);
const res = await fetch(realUrl, {
method: RequestTypes.GET,
@@ -111,7 +108,7 @@ export async function TachiServerV1Get<T = unknown>(
return contents;
} catch (err) {
logger.error(`Failed while requesting GET ${url}.\n\n${err}\n`);
log.error(`Failed while requesting GET ${url}.\n\n${err}\n`);
throw err;
}
@@ -133,12 +130,12 @@ export function PrependTachiUrl(url: string, version: "1" = "1"): string {
* Logs the result of a request.
* Logs at WARN level if was unsuccessful, DEBUG otherwise.
*/
function LogRequestResult(loggerUrl: string, res: APIResponse<unknown>): void {
function LogRequestResult(logUrl: string, res: APIResponse<unknown>): void {
if (!res.success) {
logger.warn(
`Request ${loggerUrl} was unsuccessful: ${res.description} (${res.statusCode})`,
log.warn(
`Request ${logUrl} was unsuccessful: ${res.description} (${res.statusCode})`,
);
} else {
logger.debug(`Request ${loggerUrl} was successful: ${res.description} (${res.statusCode})`);
log.debug(`Request ${logUrl} was successful: ${res.description} (${res.statusCode})`);
}
}
+17
View File
@@ -0,0 +1,17 @@
import pino from "pino";
// Use JSON log lines when LOG_JSON=1 (dev/prod); otherwise pretty format for localdev.
// Deliberately process.env here instead of importing ENV to avoid a circular dep.
const useJson = process.env.LOG_JSON === "1" || process.env.LOG_JSON === "true";
export const log = pino({
level: process.env.LOG_LEVEL ?? "info",
...(useJson
? {}
: {
transport: {
options: { colorize: true },
target: "pino-pretty",
},
}),
});
-54
View File
@@ -1,54 +0,0 @@
import type { SeqLogLevel } from "seq-logging";
import { ProcessEnv } from "#config";
import { Transport as SeqTransport } from "@valuabletouch/winston-seq";
import { CreateLogger, type MeiLogger } from "mei-logger";
import { transports } from "winston";
import type { LoggerLayers } from "../data/data";
const tports: Array<any> = [new transports.Console({})];
if (ProcessEnv.seqUrl) {
// Turns winston log levels into seq format.
const levelMap: Record<string, SeqLogLevel> = {
crit: "Fatal",
severe: "Error",
error: "Error",
warn: "Warning",
info: "Information",
// Note that Seq interprets these in reverse,
// however, it's easier to read this code if I just
// use the same levels, instead of the right ones.
verbose: "Verbose",
debug: "Debug",
};
tports.push(
new SeqTransport({
apiKey: ProcessEnv.seqApiKey,
serverUrl: ProcessEnv.seqUrl,
onError: (err) => {
console.error(`Failed to send seq message: ${err.message}.`);
},
levelMapper(level = "") {
return levelMap[level] ?? "Information";
},
}),
);
}
const logger = CreateLogger(`tachi-bot`, undefined, tports);
export default logger;
export function CreateLayeredLogger(layerName: LoggerLayers) {
const lg = logger.child({
context: [layerName],
});
lg.defaultMeta = { ...(lg.defaultMeta ?? {}), context: [layerName] };
return lg as MeiLogger;
}
@@ -14,7 +14,7 @@ import { client } from "../main";
import { GetUGPTStats, GetUserInfo } from "../utils/apiRequests";
import { CreateEmbed } from "../utils/embeds";
import { PrependTachiUrl } from "../utils/fetchTachi";
import logger from "../utils/logger";
import { log } from "#utils/log"
import { FormatClass, GetGameChannel } from "../utils/misc";
export async function HandleClassUpdateV1(
@@ -29,12 +29,12 @@ export async function HandleClassUpdateV1(
} catch (e) {
const err = e as Error;
logger.error(`ClassUpdate handler failed: ${err.message}`);
log.error(`ClassUpdate handler failed: ${err.message}`);
return 500;
}
if (!ShouldRenderUpdate(game, playtype, event.set, event.new)) {
logger.info(
log.info(
`Not rendering class update ${event.set}: ${event.old} -> ${event.new} (not relevant).`,
);
return 204;
@@ -49,7 +49,7 @@ export async function HandleClassUpdateV1(
// Do not render if the user hasn't hit the score cap.
if (totalScores < minimumNecessaryScores) {
logger.info(
log.info(
`Not rendering class update ${event.set}: ${event.old} -> ${event.new} (not enough scores).`,
);
return 204;
@@ -91,7 +91,7 @@ function ShouldRenderUpdate(
const classSpec = config.classes[classSet];
if (classSpec === undefined) {
logger.error(`Invalid class ${classSet} for ${game} ${playtype}`);
log.error(`Invalid class ${classSet} for ${game} ${playtype}`);
return false;
}
@@ -105,12 +105,12 @@ function ShouldRenderUpdate(
const minimumId = ids.indexOf(classSpec.minimumRelevantValue);
if (currentId < 0) {
logger.error(`Invalid classValue ${classValue} for ${game} ${playtype}`);
log.error(`Invalid classValue ${classValue} for ${game} ${playtype}`);
return false;
}
if (minimumId < 0) {
logger.error(`Invalid minimum classValue ${classValue} for ${game} ${playtype}`);
log.error(`Invalid minimum classValue ${classValue} for ${game} ${playtype}`);
return false;
}
@@ -126,7 +126,7 @@ function GetMinimumScores(
const classSpec = config.classes[classSet];
if (classSpec === undefined) {
logger.error(`Invalid class ${classSet} for ${game} ${playtype}`);
log.error(`Invalid class ${classSet} for ${game} ${playtype}`);
return null;
}
@@ -1,5 +1,6 @@
import { BotConfig } from "#config";
import { PrependTachiUrl } from "#utils/fetchTachi";
import { log } from "#utils/log"
import {
GetGameGroupConfig,
type GoalDocument,
@@ -10,7 +11,6 @@ import {
import { client } from "../main";
import { GetGoalWithID, GetUserInfo } from "../utils/apiRequests";
import { CreateEmbed } from "../utils/embeds";
import logger from "../utils/logger";
import { GetGameChannel, Pluralise } from "../utils/misc";
export async function HandleGoalAchievedV1(
@@ -25,7 +25,7 @@ export async function HandleGoalAchievedV1(
} catch (e) {
const err = e as Error;
logger.error(`ClassUpdate handler failed: ${err.message}`);
log.error(`ClassUpdate handler failed: ${err.message}`);
return 500;
}
@@ -1,11 +1,11 @@
import { BotConfig } from "#config";
import { PrependTachiUrl } from "#utils/fetchTachi";
import { log } from "#utils/log";
import { GetGameGroupConfig, type integer, type WebhookEventQuestAchievedV1 } from "tachi-common";
import { client } from "../main";
import { GetQuestWithID, GetUserInfo } from "../utils/apiRequests";
import { CreateEmbed } from "../utils/embeds";
import logger from "../utils/logger";
import { GetGameChannel } from "../utils/misc";
export async function HandleQuestAchievedV1(
@@ -20,7 +20,7 @@ export async function HandleQuestAchievedV1(
} catch (e) {
const err = e as Error;
logger.error(`ClassUpdate handler failed: ${err.message}`);
log.error({ err }, "ClassUpdate handler failed.");
return 500;
}
+12
View File
@@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"module": "Preserve",
"moduleResolution": "bundler",
"noImplicitAny": false,
"strictNullChecks": true,
"allowJs": true,
"strict": false
},
"exclude": ["../seeds-scripts/node_modules"]
}
+3 -2
View File
@@ -95,6 +95,7 @@
"node-html-parser": "catalog:",
"nodemailer": "catalog:",
"pg": "catalog:",
"pino": "catalog:",
"prudence": "catalog:",
"rate-limit-redis": "catalog:",
"redis": "catalog:",
@@ -107,10 +108,10 @@
"ts-node": "catalog:",
"typescript": "catalog:",
"uuidv7": "catalog:",
"zod": "catalog:",
"winston": "catalog:",
"winston-loki": "catalog:",
"winston-transport": "catalog:"
"winston-transport": "catalog:",
"zod": "catalog:"
},
"nyc": {
"reporter": [
@@ -23,7 +23,7 @@ async function CloseEverythingElse() {
logger.info("Closing Mongo Database.", { shutdownInfo: true });
await monkDB.close();
logger.info("Closing database...", {shutdownInfo: true});
logger.info("Closing database...", { shutdownInfo: true });
await ClosePgConnection();
logger.info("Closing Redis Connection.", { shutdownInfo: true });
@@ -120,7 +120,6 @@ const tports: Array<winston.transport> = [
}),
];
export const rootLogger = winston.createLogger({
levels: {
// entire process termination is necessary
+1 -2
View File
@@ -1,5 +1,5 @@
import JSON5 from "json5";
import { allSupportedGameGroups, type GameGroup , type ImportTypes } from "tachi-common";
import { allSupportedGameGroups, type GameGroup, type ImportTypes } from "tachi-common";
import { allImportTypes } from "tachi-common/constants/import-types";
import { z } from "zod";
@@ -198,7 +198,6 @@ if (!["crit", "debug", "error", "info", "severe", "verbose", "warn"].includes(lo
process.exit(1);
}
const POSTGRES_URL = process.env.POSTGRES_URL ?? "";
if (!POSTGRES_URL) {
+1 -4
View File
@@ -51,10 +51,7 @@ const userSessionMiddleware = expressSession({
ServerConfig.ENABLE_SERVER_HTTPS,
// Very important. Without this, we're vulnerable to CSRF!
sameSite:
Env.NODE_ENV === "production" || Env.NODE_ENV === "staging"
? "strict"
: "none",
sameSite: Env.NODE_ENV === "production" || Env.NODE_ENV === "staging" ? "strict" : "none",
},
});