mirror of
https://github.com/zkldi/Tachi.git
synced 2026-10-07 14:28:09 +03:00
refactor: apply cadence to bot and make it compile
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unsafe-assignment": "warn"
|
||||
}
|
||||
}
|
||||
+4
-6
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "tachi-bot",
|
||||
"version": "1.0.0",
|
||||
"main": "src/index.ts",
|
||||
"version": "0.0.0",
|
||||
"main": "js/bot/src/main.js",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
"start": "pnpm build && node js/main.js",
|
||||
"start": "pnpm build && node -r ts-node/register -r tsconfig-paths/register js/bot/src/main.js",
|
||||
"lint": "eslint . --fix"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -34,8 +34,6 @@
|
||||
"monk": "7.3.4",
|
||||
"node-fetch": "2.6.7",
|
||||
"prudence": "0.9.6",
|
||||
"sync-fetch": "^0.3.1",
|
||||
"tachi-common": "0.7.2",
|
||||
"ts-node": "10.2.0"
|
||||
"sync-fetch": "^0.3.1"
|
||||
}
|
||||
}
|
||||
+14
-10
@@ -1,15 +1,16 @@
|
||||
import fs from "fs";
|
||||
import { config } from "dotenv";
|
||||
import JSON5 from "json5";
|
||||
import p from "prudence";
|
||||
// @ts-expect-error No types available...
|
||||
import fetchSync from "sync-fetch";
|
||||
import { Game, integer } from "tachi-common";
|
||||
import { LoggerLayers } from "./data/data";
|
||||
import { CreateLayeredLogger } from "./utils/logger";
|
||||
import { IsRecord } from "./utils/predicates";
|
||||
import { FormatPrError } from "./utils/prudence";
|
||||
import { ServerConfig as ServerConfigType } from "./utils/returnTypes";
|
||||
import { config } from "dotenv";
|
||||
import JSON5 from "json5";
|
||||
import p from "prudence";
|
||||
|
||||
// @ts-expect-error No types available...
|
||||
import fetchSync from "sync-fetch";
|
||||
import fs from "fs";
|
||||
import type { ServerConfig as ServerConfigType } from "./utils/returnTypes";
|
||||
import type { Game, integer } from "tachi-common";
|
||||
|
||||
// Initialise .env.
|
||||
config();
|
||||
@@ -32,7 +33,7 @@ export interface BotConfig {
|
||||
TOKEN: string;
|
||||
SERVER_ID: string;
|
||||
GAME_CHANNELS: Partial<Record<Game, string>>;
|
||||
ADMIN_USERS: string[];
|
||||
ADMIN_USERS: Array<string>;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -41,6 +42,7 @@ function ParseBotConfig(fileLoc = "conf.json5"): BotConfig {
|
||||
|
||||
try {
|
||||
const contents = fs.readFileSync(fileLoc, "utf-8");
|
||||
|
||||
data = JSON5.parse(contents);
|
||||
} catch (err) {
|
||||
logger.error("Failed to find/parse a valid conf.json5 file. Cannot boot.", { err });
|
||||
@@ -76,6 +78,7 @@ function ParseBotConfig(fileLoc = "conf.json5"): BotConfig {
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
// A list of users that are allowed to do powerful stuff.
|
||||
ADMIN_USERS: ["string"],
|
||||
},
|
||||
@@ -91,7 +94,7 @@ function ParseBotConfig(fileLoc = "conf.json5"): BotConfig {
|
||||
}
|
||||
|
||||
export interface ProcessEnvironment {
|
||||
nodeEnv: "production" | "dev" | "staging" | "test";
|
||||
nodeEnv: "dev" | "production" | "staging" | "test";
|
||||
mongoUrl: string;
|
||||
port: integer;
|
||||
}
|
||||
@@ -101,6 +104,7 @@ function ParseEnvVars() {
|
||||
process.env,
|
||||
{
|
||||
NODE_ENV: p.isIn("production", "dev", "staging", "test"),
|
||||
|
||||
// mei implicitly reads this.
|
||||
LOG_LEVEL: p.optional(
|
||||
p.isIn("debug", "verbose", "info", "warn", "error", "severe", "crit")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Snowflake } from "discord.js";
|
||||
import { integer } from "tachi-common";
|
||||
import type { Snowflake } from "discord.js";
|
||||
import type { integer } from "tachi-common";
|
||||
|
||||
export interface DiscordUserMapDocument {
|
||||
userID: integer;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import monk from "monk";
|
||||
import { ProcessEnv } from "../config";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { CreateLayeredLogger } from "../utils/logger";
|
||||
import { DiscordUserMapDocument, QuoteDocument } from "./documents";
|
||||
import monk from "monk";
|
||||
import type { DiscordUserMapDocument, QuoteDocument } from "./documents";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.database);
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { integer } from "tachi-common";
|
||||
import db from "./mongo";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { CreateLayeredLogger } from "../utils/logger";
|
||||
import { DiscordUserMapDocument, QuoteDocument } from "./documents";
|
||||
import db from "./mongo";
|
||||
import type { DiscordUserMapDocument, QuoteDocument } from "./documents";
|
||||
import type { integer } from "tachi-common";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.databaseQuery);
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { CommandInteraction, MessageEmbed } from "discord.js";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { DiscordUserMapDocument } from "../database/documents";
|
||||
import { SLASH_COMMANDS } from "../slashCommands/commands";
|
||||
import { CreateLayeredLogger } from "../utils/logger";
|
||||
import { MessageEmbed } from "discord.js";
|
||||
import type { DiscordUserMapDocument } from "../database/documents";
|
||||
import type { CommandInteraction } from "discord.js";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.slashCommands);
|
||||
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
import { SelectMenuInteraction } from "discord.js";
|
||||
import { Game, Playtype } from "tachi-common";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { DiscordUserMapDocument } from "../database/documents";
|
||||
import { GetUserInfo } from "../utils/apiRequests";
|
||||
import {
|
||||
CreateChartScoresEmbed,
|
||||
@@ -9,6 +6,9 @@ import {
|
||||
CreateFolderTimelineEmbed,
|
||||
} from "../utils/embeds";
|
||||
import { CreateLayeredLogger } from "../utils/logger";
|
||||
import type { DiscordUserMapDocument } from "../database/documents";
|
||||
import type { SelectMenuInteraction } from "discord.js";
|
||||
import type { Game, Playtype } from "tachi-common";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.slashCommands);
|
||||
|
||||
@@ -34,8 +34,8 @@ export async function handleIsSelectMenu(
|
||||
|
||||
if (interaction.customId.startsWith("chart!")) {
|
||||
// horrendous hackery, but we only have 100 chars to store selector metadata.
|
||||
const [, game, playtype, userID] = interaction.customId.match(
|
||||
/!(.*):(.*):(.*)$/u
|
||||
const [, game, playtype, userID] = /!(.*):(.*):(.*)$/u.exec(
|
||||
interaction.customId
|
||||
) as unknown as [string, Game, Playtype, string];
|
||||
|
||||
const userDoc = await GetUserInfo(userID);
|
||||
@@ -44,32 +44,32 @@ export async function handleIsSelectMenu(
|
||||
userDoc,
|
||||
game,
|
||||
playtype,
|
||||
interaction.values[0],
|
||||
interaction.values[0]!,
|
||||
null
|
||||
);
|
||||
|
||||
await interaction.update({ embeds: [embed] });
|
||||
} else if (interaction.customId.startsWith("folder!")) {
|
||||
const [, game, playtype, username] = interaction.customId.match(
|
||||
/!(.*):(.*):(.*)$/u
|
||||
const [, game, playtype, username] = /!(.*):(.*):(.*)$/u.exec(
|
||||
interaction.customId
|
||||
) as unknown as [string, Game, Playtype, string];
|
||||
|
||||
const embed = await CreateFolderStatsEmbed(
|
||||
game,
|
||||
playtype,
|
||||
username,
|
||||
interaction.values[0]
|
||||
interaction.values[0]!
|
||||
);
|
||||
|
||||
await interaction.update({ embeds: [embed] });
|
||||
} else if (interaction.customId.startsWith("ftl!")) {
|
||||
const [, game, playtype, username, formatMethod, rawTarget] =
|
||||
interaction.customId.match(/!(.*):(.*):(.*):(.*):(.*)$/u) as unknown as [
|
||||
/!(.*):(.*):(.*):(.*):(.*)$/u.exec(interaction.customId) as unknown as [
|
||||
string,
|
||||
Game,
|
||||
Playtype,
|
||||
string,
|
||||
"recent" | "first",
|
||||
"first" | "recent",
|
||||
string
|
||||
];
|
||||
|
||||
@@ -77,7 +77,7 @@ export async function handleIsSelectMenu(
|
||||
game,
|
||||
playtype,
|
||||
username,
|
||||
interaction.values[0],
|
||||
interaction.values[0]!,
|
||||
formatMethod,
|
||||
rawTarget
|
||||
);
|
||||
|
||||
+4
-1
@@ -1,15 +1,17 @@
|
||||
import { Client, CommandInteraction, Intents, SelectMenuInteraction } from "discord.js";
|
||||
import { BotConfig, ProcessEnv, ServerConfig } from "./config";
|
||||
import { LoggerLayers, METALLIC_MIND_SPLASHES } from "./data/data";
|
||||
import { GetUserAndTokenForDiscordID } from "./database/queries";
|
||||
import { handleIsCommand } from "./interactionHandlers/handleIsCommand";
|
||||
import { handleIsSelectMenu } from "./interactionHandlers/handleIsSelectMenu";
|
||||
|
||||
// import { handleIsSelectMenu } from "./interactionHandlers/handleIsSelectMenu";
|
||||
import { app } from "./server/server";
|
||||
import { RegisterSlashCommands } from "./slashCommands/register";
|
||||
import { CreateLayeredLogger } from "./utils/logger";
|
||||
import { RFA, TruncateString } from "./utils/misc";
|
||||
import { VERSION_PRETTY } from "./version";
|
||||
import { Client, Intents } from "discord.js";
|
||||
import type { CommandInteraction, SelectMenuInteraction } from "discord.js";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.client);
|
||||
|
||||
@@ -57,6 +59,7 @@ async function RequireUserAuth(interaction: CommandInteraction | SelectMenuInter
|
||||
const oAuthLink = `${BotConfig.TACHI_SERVER_LOCATION}/oauth/request-auth?clientID=${BotConfig.OAUTH.CLIENT_ID}&context=${interaction.user.id}`;
|
||||
|
||||
const dmChannel = await interaction.user.createDM();
|
||||
|
||||
await dmChannel.send(`Click this link to authenticate with ${ServerConfig.name}: ${oAuthLink}`);
|
||||
return interaction.reply({
|
||||
content: `To use the bot, your discord account must be linked to ${ServerConfig.name}.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { RequestHandler } from "express";
|
||||
import { BotConfig } from "../config";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { CreateLayeredLogger } from "../utils/logger";
|
||||
import type { RequestHandler } from "express";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.serverAuth);
|
||||
|
||||
@@ -45,5 +45,5 @@ export const ValidateWebhookRequest: RequestHandler = (req, res, next) => {
|
||||
|
||||
logger.debug("Webhook authorisation successful.");
|
||||
|
||||
return next();
|
||||
next();
|
||||
};
|
||||
|
||||
+18
-11
@@ -1,6 +1,4 @@
|
||||
import path from "path";
|
||||
import express, { Express } from "express";
|
||||
import { APITokenDocument, PublicUserDocument, WebhookEvents } from "tachi-common";
|
||||
import { ValidateWebhookRequest } from "./middleware";
|
||||
import { BotConfig, ProcessEnv } from "../config";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import db from "../database/mongo";
|
||||
@@ -9,7 +7,10 @@ import { CreateLayeredLogger } from "../utils/logger";
|
||||
import { VERSION_PRETTY } from "../version";
|
||||
import { HandleClassUpdateV1 } from "../webhookHandlers/classUpdate";
|
||||
import { HandleGoalAchievedV1 } from "../webhookHandlers/goalAchieved";
|
||||
import { ValidateWebhookRequest } from "./middleware";
|
||||
import express from "express";
|
||||
import path from "path";
|
||||
import type { Express } from "express";
|
||||
import type { APITokenDocument, PublicUserDocument, WebhookEvents } from "tachi-common";
|
||||
|
||||
export const app: Express = express();
|
||||
|
||||
@@ -123,7 +124,7 @@ app.get("/oauth/callback", async (req, res) => {
|
||||
});
|
||||
}
|
||||
|
||||
return res.sendFile(path.join(__dirname, "../../pages/account-linked.html"));
|
||||
res.sendFile(path.join(__dirname, "../../pages/account-linked.html"));
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -139,18 +140,22 @@ app.post("/webhook", ValidateWebhookRequest, async (req, res) => {
|
||||
let statusCode = 200;
|
||||
|
||||
switch (webhookEvent.type) {
|
||||
case "class-update/v1":
|
||||
case "class-update/v1": {
|
||||
statusCode = await HandleClassUpdateV1(webhookEvent.content);
|
||||
break;
|
||||
case "goals-achieved/v1":
|
||||
}
|
||||
|
||||
case "goals-achieved/v1": {
|
||||
statusCode = await HandleGoalAchievedV1(webhookEvent.content);
|
||||
break;
|
||||
}
|
||||
|
||||
case "milestone-achieved/v1":
|
||||
default:
|
||||
// According to the types, this should never happen.
|
||||
// However, tachi-(server/common) may recieve an update
|
||||
// to define new webhooks, and the bot might not
|
||||
default: {
|
||||
// get around to updating in time.
|
||||
// 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(
|
||||
`Received unknown webhook event ${
|
||||
(webhookEvent as WebhookEvents).type
|
||||
@@ -160,6 +165,7 @@ app.post("/webhook", ValidateWebhookRequest, async (req, res) => {
|
||||
success: false,
|
||||
description: `The type ${(webhookEvent as WebhookEvents).type} is unsupported.`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return res.sendStatus(statusCode);
|
||||
@@ -195,6 +201,7 @@ interface ExpressJSONErr extends SyntaxError {
|
||||
const MainExpressErrorHandler: express.ErrorRequestHandler = (err, req, res, _next) => {
|
||||
if (err instanceof SyntaxError) {
|
||||
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,
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import { ServerConfig } from "../config";
|
||||
import chart from "./commands/chart";
|
||||
import faq from "./commands/faq";
|
||||
import folder from "./commands/folder";
|
||||
import invite from "./commands/invite";
|
||||
import last_score from "./commands/last_score";
|
||||
import last_session from "./commands/last_session";
|
||||
import ping from "./commands/ping";
|
||||
import profile from "./commands/profile";
|
||||
import quote from "./commands/quote";
|
||||
import sync from "./commands/sync";
|
||||
import whois from "./commands/whois";
|
||||
import invite from "./commands/invite";
|
||||
import last_score from "./commands/last_score";
|
||||
import last_session from "./commands/last_session";
|
||||
import { SlashCommand } from "./types";
|
||||
import { ServerConfig } from "../config";
|
||||
import type { SlashCommand } from "./types";
|
||||
|
||||
export const SLASH_COMMANDS: Map<string, SlashCommand> = new Map(
|
||||
Object.entries({
|
||||
@@ -34,5 +34,6 @@ if (ServerConfig.type !== "btchi") {
|
||||
// btchi or omni specific commands
|
||||
if (ServerConfig.type !== "ktchi") {
|
||||
SLASH_COMMANDS.set("invite", invite);
|
||||
|
||||
// None. Yet!
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { MessageActionRow, MessageSelectMenu, Util } from "discord.js";
|
||||
import { Difficulties, FormatChart, IDStrings, integer, SongDocument } from "tachi-common";
|
||||
import { GetGPTAndUser, ParseDifficulty } from "../../utils/argParsers";
|
||||
import { CreateChartScoresEmbed } from "../../utils/embeds";
|
||||
import { TachiServerV1Get } from "../../utils/fetchTachi";
|
||||
import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options";
|
||||
import { ChartQueryReturns } from "../../utils/returnTypes";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { MessageActionRow, MessageSelectMenu, Util } from "discord.js";
|
||||
import { FormatChart } from "tachi-common";
|
||||
import type { ChartQueryReturns } from "../../utils/returnTypes";
|
||||
import type { SlashCommand } from "../types";
|
||||
import type { Difficulties, IDStrings, integer, SongDocument } from "tachi-common";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
@@ -52,7 +53,7 @@ const command: SlashCommand = {
|
||||
// As such, we just treat a difficulty (if it exists) as being part of the
|
||||
// song title.
|
||||
if ((game === "bms" || game === "pms") && difficulty) {
|
||||
search += ` ${difficulty}`;
|
||||
search = `${search} ${difficulty}`;
|
||||
}
|
||||
|
||||
const chartsRes = await TachiServerV1Get<ChartQueryReturns>(
|
||||
@@ -80,7 +81,7 @@ const command: SlashCommand = {
|
||||
chartsRes.body.charts = chartsRes.body.charts.slice(0, 25);
|
||||
}
|
||||
|
||||
const firstChart = chartsRes.body.charts[0];
|
||||
const firstChart = chartsRes.body.charts[0]!; // length is asserted as non-zero
|
||||
|
||||
const songMap = new Map<integer, SongDocument>();
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import deepmerge from "deepmerge";
|
||||
import { BotConfig, ServerConfig } from "../../config";
|
||||
import { CreateEmbed } from "../../utils/embeds";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import deepmerge from "deepmerge";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const NEUTRAL_FAQ_ENTRIES: Record<string, string> = {
|
||||
duplicates: `Scores on ${ServerConfig.name} are deduplicated based on your score and lamp (and some other things).
|
||||
@@ -111,8 +111,7 @@ Since I don't play a lot of the the games that ${ServerConfig.name} supports, we
|
||||
const KTCHI_FAQ_ENTRIES: Record<string, string> = {
|
||||
kai_support: `Support for KAI based networks (FLO, EAG, MIN) is available, but we are waiting on APIs for more games on their end. At the moment, only IIDX and SDVX are supported.`,
|
||||
bokutachi: `Bokutachi is our public sister website for home games and simulators. Feel free to check out [the discord](${
|
||||
// Note: obfuscating this for obvious reasons so we don't get garbage bot spam.
|
||||
Buffer.from("aHR0cHM6Ly9kaXNjb3JkLmdnL3N3VkJUanhtUFk=", "base64")
|
||||
Buffer.from("aHR0cHM6Ly9kaXNjb3JkLmdnL3N3VkJUanhtUFk=", "base64") // Note: obfuscating this for obvious reasons so we don't get garbage bot spam.
|
||||
})`,
|
||||
sdvx_1259: `Automation Paradise is song ID 1259. It is not a real song, and it is not supported by ${ServerConfig.name}. Related autopara-only songs are not supported, either.`,
|
||||
invites: `To invite your friends, go to your profile and select 'Invites'. From there, you can create an invite code.
|
||||
@@ -125,7 +124,7 @@ const BTCHI_FAQ_ENTRIES: Record<string, string> = {
|
||||
(This is because putting your real password in there is a security nightmare.)`,
|
||||
lr2: `Support for LR2 (the LR2Hook) are **not officially maintained** and therefore **not managed by bokutachi developers**.
|
||||
We urge you to use a more modern BMS client like lr2oraja, unless you have very good reason to stay on LR2.
|
||||
Beatoraja is actively developed and integrates properly with the Bokutachi IR, it is also significantly more stable and works on modern hardware without encoding hacks.`
|
||||
Beatoraja is actively developed and integrates properly with the Bokutachi IR, it is also significantly more stable and works on modern hardware without encoding hacks.`,
|
||||
};
|
||||
|
||||
let faqEntries = NEUTRAL_FAQ_ENTRIES;
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { SlashCommandBuilder, SlashCommandSubcommandBuilder } from "@discordjs/builders";
|
||||
import { MessageActionRow, MessageSelectMenu, Util } from "discord.js";
|
||||
import { FindFolders } from "../../utils/apiRequests";
|
||||
import { GetGPTAndUser } from "../../utils/argParsers";
|
||||
import { CreateFolderStatsEmbed, CreateFolderTimelineEmbed } from "../../utils/embeds";
|
||||
import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { MessageActionRow, MessageSelectMenu, Util } from "discord.js";
|
||||
import type { SlashCommand } from "../types";
|
||||
import type { SlashCommandSubcommandBuilder } from "@discordjs/builders";
|
||||
|
||||
function ApplyCommonOptions(sub: SlashCommandSubcommandBuilder) {
|
||||
return sub
|
||||
@@ -82,7 +83,7 @@ const command: SlashCommand = {
|
||||
}
|
||||
|
||||
// pick an initial folder
|
||||
const folder = folders[0];
|
||||
const folder = folders[0]!; // length is asserted as non-zero
|
||||
|
||||
// with all of the common info, we now need to chalk up what to actually do.
|
||||
|
||||
@@ -117,7 +118,7 @@ const command: SlashCommand = {
|
||||
|
||||
const rawTarget = interaction.options.getString("target", true);
|
||||
|
||||
const formatMethod = interaction.options.getString("method", true) as "recent" | "first";
|
||||
const formatMethod = interaction.options.getString("method", true) as "first" | "recent";
|
||||
|
||||
const select = new MessageActionRow().addComponents(
|
||||
new MessageSelectMenu()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { client } from "../../main";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import { GetUGPTStats } from "../../utils/apiRequests";
|
||||
import { GetGPTAndUser } from "../../utils/argParsers";
|
||||
import { CreateChartScoresEmbed } from "../../utils/embeds";
|
||||
import logger from "../../utils/logger";
|
||||
import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
@@ -24,6 +24,7 @@ const command: SlashCommand = {
|
||||
const { userDoc, game, playtype } = gptUserInfo.content;
|
||||
|
||||
let mostRecentScore;
|
||||
|
||||
try {
|
||||
({ mostRecentScore } = await GetUGPTStats(userDoc.id, game, playtype));
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import { GetMostRecentSession } from "../../utils/apiRequests";
|
||||
import { GetGPTAndUser } from "../../utils/argParsers";
|
||||
import { CreateSessionEmbed } from "../../utils/embeds";
|
||||
import logger from "../../utils/logger";
|
||||
import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
@@ -24,6 +24,7 @@ const command: SlashCommand = {
|
||||
const { userDoc, game, playtype } = gptUserInfo.content;
|
||||
|
||||
let session;
|
||||
|
||||
try {
|
||||
session = await GetMostRecentSession(userDoc.id, game, playtype);
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { ServerConfig } from "../../config";
|
||||
import { TachiServerV1Get } from "../../utils/fetchTachi";
|
||||
import { ServerStatus } from "../../utils/returnTypes";
|
||||
import { VERSION_PRETTY } from "../../version";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import type { ServerStatus } from "../../utils/returnTypes";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import { GetUGPTStats } from "../../utils/apiRequests";
|
||||
import { GetGPTAndUser } from "../../utils/argParsers";
|
||||
import { CreateGameProfileEmbed } from "../../utils/embeds";
|
||||
import { GPTOptions, MakeRequired, OtherUserOption } from "../../utils/options";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
@@ -23,6 +23,7 @@ const command: SlashCommand = {
|
||||
const { userDoc, game, playtype } = gptUserInfo.content;
|
||||
|
||||
let ugptStats;
|
||||
|
||||
try {
|
||||
ugptStats = await GetUGPTStats(userDoc.id, game, playtype);
|
||||
} catch (err) {
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { Util } from "discord.js";
|
||||
import { escapeRegExp } from "lodash";
|
||||
import db from "../../database/mongo";
|
||||
import { GetQuoteWithID } from "../../database/queries";
|
||||
import { GetUserInfo } from "../../utils/apiRequests";
|
||||
import { CreateEmbed } from "../../utils/embeds";
|
||||
import { FormatDate, IsAdmin, Pluralise, TruncateString } from "../../utils/misc";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { Util } from "discord.js";
|
||||
import { escapeRegExp } from "lodash";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
@@ -61,11 +61,11 @@ const command: SlashCommand = {
|
||||
.toJSON(),
|
||||
exec: async (interaction, requestingUser) => {
|
||||
const subCommand = interaction.options.getSubcommand() as
|
||||
| "read"
|
||||
| "write"
|
||||
| "delete"
|
||||
| "read"
|
||||
| "search_id"
|
||||
| "search_text"
|
||||
| "search_id";
|
||||
| "write";
|
||||
|
||||
if (subCommand === "search_id" || subCommand === "search_text") {
|
||||
const query = interaction.options.getString("query", true).trim();
|
||||
@@ -121,58 +121,65 @@ const command: SlashCommand = {
|
||||
|
||||
const quote = await GetQuoteWithID(quoteID);
|
||||
|
||||
if (subCommand === "read") {
|
||||
if (!quote) {
|
||||
return `No quote exists for '${Util.escapeMarkdown(quoteID)}'.`;
|
||||
switch (subCommand) {
|
||||
case "read": {
|
||||
if (!quote) {
|
||||
return `No quote exists for '${Util.escapeMarkdown(quoteID)}'.`;
|
||||
}
|
||||
|
||||
await db.quotes.update({ quoteID }, { $inc: { hits: 1 } });
|
||||
|
||||
const authorInfo = await GetUserInfo(quote.quotedBy);
|
||||
|
||||
return CreateEmbed()
|
||||
.setTitle(`Quote: ${quoteID}`)
|
||||
.setDescription(`\`\`\`${Util.escapeMarkdown(quote.text)}\`\`\``)
|
||||
.setFooter({
|
||||
text: `Quoted by ${authorInfo.username} on ${FormatDate(
|
||||
quote.quotedAt
|
||||
)}. This quote has been read ${quote.hits + 1} times.`,
|
||||
});
|
||||
}
|
||||
|
||||
await db.quotes.update({ quoteID }, { $inc: { hits: 1 } });
|
||||
case "write": {
|
||||
const text = interaction.options.getString("text", true);
|
||||
|
||||
const authorInfo = await GetUserInfo(quote.quotedBy);
|
||||
if (quote) {
|
||||
return `A quote exists for '${Util.escapeMarkdown(quoteID)}' already.`;
|
||||
}
|
||||
|
||||
return CreateEmbed()
|
||||
.setTitle(`Quote: ${quoteID}`)
|
||||
.setDescription(`\`\`\`${Util.escapeMarkdown(quote.text)}\`\`\``)
|
||||
.setFooter({
|
||||
text: `Quoted by ${authorInfo.username} on ${FormatDate(
|
||||
quote.quotedAt
|
||||
)}. This quote has been read ${quote.hits + 1} times.`,
|
||||
if (text.length > 480) {
|
||||
return `Quotes are capped at 480 characters. Not quoting this.`;
|
||||
}
|
||||
|
||||
await db.quotes.insert({
|
||||
quoteID,
|
||||
text,
|
||||
hits: 0,
|
||||
quotedAt: Date.now(),
|
||||
quotedBy: requestingUser.userID,
|
||||
});
|
||||
} else if (subCommand === "write") {
|
||||
const text = interaction.options.getString("text", true);
|
||||
|
||||
if (quote) {
|
||||
return `A quote exists for '${Util.escapeMarkdown(quoteID)}' already.`;
|
||||
return `Quote '${Util.escapeMarkdown(quoteID)}' has been saved.`;
|
||||
}
|
||||
|
||||
if (text.length > 480) {
|
||||
return `Quotes are capped at 480 characters. Not quoting this.`;
|
||||
case "delete": {
|
||||
if (!IsAdmin(requestingUser.discordID)) {
|
||||
return `You are not authorised to delete quotes.`;
|
||||
}
|
||||
|
||||
if (!quote) {
|
||||
return `No quote exists for '${Util.escapeMarkdown(quoteID)}'.`;
|
||||
}
|
||||
|
||||
await db.quotes.remove({ quoteID: quote.quoteID });
|
||||
|
||||
return `Quote '${Util.escapeMarkdown(quoteID)}' has been deleted.`;
|
||||
}
|
||||
|
||||
await db.quotes.insert({
|
||||
quoteID,
|
||||
text,
|
||||
hits: 0,
|
||||
quotedAt: Date.now(),
|
||||
quotedBy: requestingUser.userID,
|
||||
});
|
||||
|
||||
return `Quote '${Util.escapeMarkdown(quoteID)}' has been saved.`;
|
||||
} else if (subCommand === "delete") {
|
||||
if (!IsAdmin(requestingUser.discordID)) {
|
||||
return `You are not authorised to delete quotes.`;
|
||||
}
|
||||
|
||||
if (!quote) {
|
||||
return `No quote exists for '${Util.escapeMarkdown(quoteID)}'.`;
|
||||
}
|
||||
|
||||
await db.quotes.remove({ quoteID: quote.quoteID });
|
||||
|
||||
return `Quote '${Util.escapeMarkdown(quoteID)}' has been deleted.`;
|
||||
default:
|
||||
throw new Error(`Unknown subcommand '${subCommand}'. How did this happen?`);
|
||||
}
|
||||
|
||||
throw new Error(`Unknown subcommand '${subCommand}'. How did this happen?`);
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { PerformScoreImport } from "../../utils/apiRequests";
|
||||
import { CreateImportEmbed } from "../../utils/embeds";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import { ServerConfig } from "../../config";
|
||||
import { GetUserIDForDiscordID } from "../../database/queries";
|
||||
import { GetUserInfo } from "../../utils/apiRequests";
|
||||
import { CreateUserEmbed } from "../../utils/embeds";
|
||||
import { SlashCommand } from "../types";
|
||||
import { SlashCommandBuilder } from "@discordjs/builders";
|
||||
import type { SlashCommand } from "../types";
|
||||
|
||||
const command: SlashCommand = {
|
||||
info: new SlashCommandBuilder()
|
||||
@@ -18,7 +18,7 @@ const command: SlashCommand = {
|
||||
|
||||
const userID = await GetUserIDForDiscordID(discordUser.id);
|
||||
|
||||
if (!userID) {
|
||||
if (userID === null) {
|
||||
return `This user is not linked with the bot.`;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { REST } from "@discordjs/rest";
|
||||
import { Routes } from "discord-api-types/v9";
|
||||
import { Client } from "discord.js";
|
||||
import { SLASH_COMMANDS } from "./commands";
|
||||
import { BotConfig, ProcessEnv } from "../config";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { CreateLayeredLogger } from "../utils/logger";
|
||||
import { SLASH_COMMANDS } from "./commands";
|
||||
import { REST } from "@discordjs/rest";
|
||||
import { Routes } from "discord-api-types/v9";
|
||||
import type { Client } from "discord.js";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.slashCommands);
|
||||
|
||||
@@ -65,6 +65,7 @@ export async function UnregisterAllCommands(client: Client): Promise<void> {
|
||||
// They use collections, which inherit from ES6's Map. Ah well.
|
||||
|
||||
const promises = [];
|
||||
|
||||
for (const [, guild] of guilds) {
|
||||
promises.push(guild.commands.set([]));
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
import { APIApplicationCommandOption } from "discord-api-types";
|
||||
import {
|
||||
import type { DiscordUserMapDocument } from "../database/documents";
|
||||
import type { APIApplicationCommandOption } from "discord-api-types";
|
||||
import type {
|
||||
CommandInteraction,
|
||||
InteractionReplyOptions,
|
||||
MessageEmbed,
|
||||
MessagePayload,
|
||||
} from "discord.js";
|
||||
import { DiscordUserMapDocument } from "../database/documents";
|
||||
|
||||
export type Emittable = MessagePayload | string | MessageEmbed | InteractionReplyOptions;
|
||||
export type Emittable = InteractionReplyOptions | MessageEmbed | MessagePayload | string;
|
||||
|
||||
export type Command = (
|
||||
interaction: CommandInteraction,
|
||||
requestingUser: DiscordUserMapDocument
|
||||
) => Promise<Emittable> | Emittable;
|
||||
) => Emittable | Promise<Emittable>;
|
||||
|
||||
export interface SlashCommand {
|
||||
info: {
|
||||
name: string;
|
||||
description: string;
|
||||
options: APIApplicationCommandOption[];
|
||||
options: Array<APIApplicationCommandOption>;
|
||||
};
|
||||
exec: Command;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
import { CommandInteraction } from "discord.js";
|
||||
import {
|
||||
import { RequestTypes, TachiServerV1Get, TachiServerV1Request } from "./fetchTachi";
|
||||
import { CreateLayeredLogger } from "./logger";
|
||||
import { Sleep } from "./misc";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { ScoreDocument } from "tachi-common";
|
||||
import type { ImportDeferred, ImportPollStatus, SessionInfo, UGPTStats } from "./returnTypes";
|
||||
import type { CommandInteraction } from "discord.js";
|
||||
import type {
|
||||
ChartDocument,
|
||||
FolderDocument,
|
||||
Game,
|
||||
@@ -9,15 +15,9 @@ import {
|
||||
PBScoreDocument,
|
||||
Playtype,
|
||||
PublicUserDocument,
|
||||
ScoreDocument,
|
||||
SessionDocument,
|
||||
SongDocument,
|
||||
} from "tachi-common";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { RequestTypes, TachiServerV1Get, TachiServerV1Request } from "./fetchTachi";
|
||||
import { CreateLayeredLogger } from "./logger";
|
||||
import { Sleep } from "./misc";
|
||||
import { ImportDeferred, ImportPollStatus, SessionInfo, UGPTStats } from "./returnTypes";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.apiRequests);
|
||||
|
||||
@@ -92,7 +92,7 @@ export async function PerformScoreImport(
|
||||
body: Record<string, unknown>,
|
||||
interaction?: CommandInteraction
|
||||
) {
|
||||
const initRes = await TachiServerV1Request<ImportDocument | ImportDeferred>(
|
||||
const initRes = await TachiServerV1Request<ImportDeferred | ImportDocument>(
|
||||
RequestTypes.POST,
|
||||
url,
|
||||
authToken,
|
||||
@@ -122,23 +122,24 @@ export async function PerformScoreImport(
|
||||
|
||||
if (pollRes.success) {
|
||||
if (pollRes.body.importStatus === "completed") {
|
||||
// is there even a nice way around this --
|
||||
// why *are* we nested so deeply?
|
||||
// eslint-disable-next-line max-depth
|
||||
if (interaction) {
|
||||
interaction.editReply(`Import finished!`);
|
||||
void interaction.editReply(`Import finished!`);
|
||||
}
|
||||
|
||||
return pollRes.body.import;
|
||||
} else {
|
||||
if (interaction) {
|
||||
interaction.editReply(
|
||||
`Importing Scores: ${
|
||||
pollRes.body.progress.description ?? "Importing."
|
||||
}..`
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Sleep(1000);
|
||||
}
|
||||
|
||||
if (interaction) {
|
||||
void interaction.editReply(
|
||||
`Importing Scores: ${pollRes.body.progress.description}..`
|
||||
);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-await-in-loop
|
||||
await Sleep(1000);
|
||||
} else {
|
||||
throw new Error(`Failed to import scores. ${pollRes.description}.`);
|
||||
}
|
||||
@@ -151,7 +152,7 @@ export async function PerformScoreImport(
|
||||
}
|
||||
|
||||
export async function FindFolders(game: Game, playtype: Playtype, folderName: string) {
|
||||
const res = await TachiServerV1Get<FolderDocument[]>(
|
||||
const res = await TachiServerV1Get<Array<FolderDocument>>(
|
||||
`/games/${game}/${playtype}/folders`,
|
||||
null,
|
||||
{
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
import { CommandInteraction } from "discord.js";
|
||||
import {
|
||||
Difficulties,
|
||||
Game,
|
||||
GetGamePTConfig,
|
||||
IDStrings,
|
||||
Playtype,
|
||||
PublicUserDocument,
|
||||
} from "tachi-common";
|
||||
import { DiscordUserMapDocument } from "../database/documents";
|
||||
import { Emittable } from "../slashCommands/types";
|
||||
import { GetUserInfo } from "./apiRequests";
|
||||
import { ConvertInputIntoGenerousRegex, ParseGPT } from "./misc";
|
||||
import { GetGamePTConfig } from "tachi-common";
|
||||
import type { DiscordUserMapDocument } from "../database/documents";
|
||||
import type { Emittable } from "../slashCommands/types";
|
||||
import type { CommandInteraction } from "discord.js";
|
||||
import type { Difficulties, Game, IDStrings, Playtype, PublicUserDocument } from "tachi-common";
|
||||
|
||||
/**
|
||||
* Utility parser for getting the game, playtype and requesting user, since this is
|
||||
@@ -20,8 +14,8 @@ export async function GetGPTAndUser(
|
||||
interaction: CommandInteraction,
|
||||
requestingUser: DiscordUserMapDocument
|
||||
): Promise<
|
||||
| { error: null; content: { userDoc: PublicUserDocument; game: Game; playtype: Playtype } }
|
||||
| { error: Emittable }
|
||||
| { error: null; content: { userDoc: PublicUserDocument; game: Game; playtype: Playtype } }
|
||||
> {
|
||||
const userID = interaction.options.getString("other_user") ?? requestingUser.userID.toString();
|
||||
|
||||
@@ -30,6 +24,7 @@ export async function GetGPTAndUser(
|
||||
}
|
||||
|
||||
let userDoc;
|
||||
|
||||
try {
|
||||
userDoc = await GetUserInfo(userID);
|
||||
} catch (err) {
|
||||
|
||||
@@ -50,4 +50,4 @@ export enum POPN_CLASSES {
|
||||
GENERAL,
|
||||
HERMIT,
|
||||
GOD,
|
||||
}
|
||||
}
|
||||
|
||||
+36
-32
@@ -1,21 +1,3 @@
|
||||
import { EmbedFieldData, MessageEmbed, Util } from "discord.js";
|
||||
import {
|
||||
ChartDocument,
|
||||
FolderDocument,
|
||||
FormatChart,
|
||||
FormatGame,
|
||||
Game,
|
||||
GetGamePTConfig,
|
||||
ImportDocument,
|
||||
integer,
|
||||
PBScoreDocument,
|
||||
Playtype,
|
||||
PublicUserDocument,
|
||||
ScoreDocument,
|
||||
SessionDocument,
|
||||
SongDocument,
|
||||
} from "tachi-common";
|
||||
import { BotConfig, ServerConfig } from "../config";
|
||||
import { GetChartInfoForUser, GetSessionInfo } from "./apiRequests";
|
||||
import { ParseTimelineTarget } from "./argParsers";
|
||||
import { PrependTachiUrl, TachiServerV1Get } from "./fetchTachi";
|
||||
@@ -37,7 +19,24 @@ import {
|
||||
UniqueOnKey,
|
||||
UppercaseFirst,
|
||||
} from "./misc";
|
||||
import { UGPTFolderStat, UGPTFolderTimeline, UGPTStats } from "./returnTypes";
|
||||
import { BotConfig, ServerConfig } from "../config";
|
||||
import { MessageEmbed, Util } from "discord.js";
|
||||
import { FormatChart, FormatGame, GetGamePTConfig } from "tachi-common";
|
||||
import type { UGPTFolderStat, UGPTFolderTimeline, UGPTStats } from "./returnTypes";
|
||||
import type { EmbedFieldData } from "discord.js";
|
||||
import type {
|
||||
ChartDocument,
|
||||
FolderDocument,
|
||||
Game,
|
||||
ImportDocument,
|
||||
integer,
|
||||
PBScoreDocument,
|
||||
Playtype,
|
||||
PublicUserDocument,
|
||||
ScoreDocument,
|
||||
SessionDocument,
|
||||
SongDocument,
|
||||
} from "tachi-common";
|
||||
|
||||
export function CreateEmbed() {
|
||||
return new MessageEmbed()
|
||||
@@ -99,7 +98,7 @@ export function CreateGameProfileEmbed(userDoc: PublicUserDocument, ugptStats: U
|
||||
Entries(ugptStats.gameStats.classes)
|
||||
.map(
|
||||
([k, v]) =>
|
||||
`**${UppercaseFirst(k)}**: ${gptConfig.classHumanisedFormat[k][v].display}`
|
||||
`**${UppercaseFirst(k)}**: ${gptConfig.classHumanisedFormat[k][v]?.display}`
|
||||
)
|
||||
.join("\n") || "No Classes",
|
||||
true
|
||||
@@ -107,7 +106,7 @@ export function CreateGameProfileEmbed(userDoc: PublicUserDocument, ugptStats: U
|
||||
.addField("Playcount", ugptStats.totalScores.toString())
|
||||
.addField(
|
||||
"First Play",
|
||||
ugptStats.firstScore.timeAchieved
|
||||
ugptStats.firstScore.timeAchieved !== null
|
||||
? `${FormatDate(ugptStats.firstScore.timeAchieved)}
|
||||
(${MillisToSince(ugptStats.firstScore.timeAchieved)})`
|
||||
: "N/A",
|
||||
@@ -115,7 +114,7 @@ export function CreateGameProfileEmbed(userDoc: PublicUserDocument, ugptStats: U
|
||||
)
|
||||
.addField(
|
||||
"Last Played",
|
||||
ugptStats.mostRecentScore.timeAchieved
|
||||
ugptStats.mostRecentScore.timeAchieved !== null
|
||||
? `${FormatDate(ugptStats.mostRecentScore.timeAchieved)}
|
||||
(${MillisToSince(ugptStats.mostRecentScore.timeAchieved)})`
|
||||
: "N/A",
|
||||
@@ -135,7 +134,7 @@ export async function CreateChartScoresEmbed(
|
||||
) {
|
||||
const { song, chart, pb } = await GetChartInfoForUser(userDoc.id, chartID, game, playtype);
|
||||
|
||||
let score: ScoreDocument | PBScoreDocument | null = renderThisScore;
|
||||
let score: PBScoreDocument | ScoreDocument | null = renderThisScore;
|
||||
|
||||
// if the user didn't pass a score to be rendered, render their PB.
|
||||
if (renderThisScore === null) {
|
||||
@@ -173,7 +172,7 @@ export async function CreateChartScoresEmbed(
|
||||
)
|
||||
.addField(
|
||||
"Last Raised",
|
||||
score.timeAchieved
|
||||
score.timeAchieved !== null
|
||||
? `${FormatDate(score.timeAchieved)} (${MillisToSince(score.timeAchieved)})`
|
||||
: "N/A",
|
||||
true
|
||||
@@ -182,7 +181,7 @@ export async function CreateChartScoresEmbed(
|
||||
// if score is a PB
|
||||
if ("rankingData" in score) {
|
||||
embed.addField("Ranking", `#**${score.rankingData.rank}**/${score.rankingData.outOf}`);
|
||||
} else if (pb) {
|
||||
} else {
|
||||
const { scoreStr, lampStr } = FormatScoreData(pb);
|
||||
|
||||
if (pb.scoreData.score !== score.scoreData.score) {
|
||||
@@ -260,7 +259,7 @@ export async function CreateFolderTimelineEmbed(
|
||||
playtype: Playtype,
|
||||
username: string,
|
||||
folderID: string,
|
||||
formatMethod: "recent" | "first",
|
||||
formatMethod: "first" | "recent",
|
||||
rawTarget: string
|
||||
) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
@@ -289,15 +288,17 @@ export async function CreateFolderTimelineEmbed(
|
||||
const songMap = CreateSongMap(songs);
|
||||
const chartMap = CreateChartMap(charts);
|
||||
|
||||
let fields: EmbedFieldData[] = [];
|
||||
let fields: Array<EmbedFieldData> = [];
|
||||
|
||||
fields = scores
|
||||
.filter((e) => e.timeAchieved !== null)
|
||||
.sort((a, b) =>
|
||||
formatMethod === "first"
|
||||
? a.timeAchieved! - b.timeAchieved!
|
||||
: b.timeAchieved! - a.timeAchieved!
|
||||
)
|
||||
.sort((a, b) => {
|
||||
if (formatMethod === "first") {
|
||||
return a.timeAchieved! - b.timeAchieved!;
|
||||
}
|
||||
|
||||
return b.timeAchieved! - a.timeAchieved!;
|
||||
})
|
||||
.slice(0, 5)
|
||||
.map((sc) => ScoreToEmbed(sc, songMap, chartMap));
|
||||
|
||||
@@ -353,8 +354,10 @@ export async function CreateSessionEmbed(session: SessionDocument) {
|
||||
|
||||
embed.addFields(
|
||||
scores
|
||||
|
||||
// don't mutate original array
|
||||
.slice(0)
|
||||
|
||||
// sort on default rating alg
|
||||
// @todo Honour the user's preferred rating alg?
|
||||
.sort(
|
||||
@@ -364,6 +367,7 @@ export async function CreateSessionEmbed(session: SessionDocument) {
|
||||
)
|
||||
)
|
||||
.filter(UniqueOnKey("chartID"))
|
||||
|
||||
// pick best 5
|
||||
.slice(0, 5)
|
||||
.map((sc) => ScoreToEmbed(sc, songMap, chartMap))
|
||||
|
||||
+11
-11
@@ -1,18 +1,16 @@
|
||||
import fetch from "node-fetch";
|
||||
import { integer, SuccessfulAPIResponse, UnsuccessfulAPIResponse } from "tachi-common";
|
||||
import { CreateLayeredLogger } from "./logger";
|
||||
import { BotConfig } from "../config";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { VERSION_STR } from "../version";
|
||||
import { CreateLayeredLogger } from "./logger";
|
||||
import fetch from "node-fetch";
|
||||
import { URLSearchParams } from "url";
|
||||
import type { integer, SuccessfulAPIResponse, UnsuccessfulAPIResponse } from "tachi-common";
|
||||
|
||||
const logger = CreateLayeredLogger(LoggerLayers.tachiFetch);
|
||||
|
||||
export type APIResponse<T> = (
|
||||
| SuccessfulAPIResponse<T>
|
||||
| (UnsuccessfulAPIResponse & { body: null })
|
||||
) & {
|
||||
export type APIResponse<T> = {
|
||||
statusCode: integer;
|
||||
};
|
||||
} & (SuccessfulAPIResponse<T> | (UnsuccessfulAPIResponse & { body: null }));
|
||||
|
||||
export enum RequestTypes {
|
||||
GET = "GET",
|
||||
@@ -20,6 +18,7 @@ export enum RequestTypes {
|
||||
PATCH = "PATCH",
|
||||
PUT = "PUT",
|
||||
DELETE = "DELETE",
|
||||
|
||||
// HEAD, OPTIONS not used by tachi-server anywhere.
|
||||
}
|
||||
|
||||
@@ -55,7 +54,7 @@ export async function TachiServerV1Request<T>(
|
||||
body: JSON.stringify(body),
|
||||
});
|
||||
|
||||
const json: APIResponse<T> = await res.json();
|
||||
const json: APIResponse<T> = (await res.json()) as unknown as APIResponse<T>;
|
||||
|
||||
const contents = { ...json, statusCode: res.status };
|
||||
|
||||
@@ -84,6 +83,7 @@ export async function TachiServerV1Get<T = unknown>(
|
||||
): Promise<APIResponse<T>> {
|
||||
try {
|
||||
let authHeader = "";
|
||||
|
||||
if (authToken) {
|
||||
authHeader = `Bearer ${authToken}`;
|
||||
}
|
||||
@@ -102,7 +102,7 @@ export async function TachiServerV1Get<T = unknown>(
|
||||
},
|
||||
});
|
||||
|
||||
const json: APIResponse<T> = await res.json();
|
||||
const json: APIResponse<T> = (await res.json()) as unknown as APIResponse<T>;
|
||||
const contents = { ...json, statusCode: res.status };
|
||||
|
||||
LogRequestResult(`GET ${realUrl}`, contents);
|
||||
@@ -119,7 +119,7 @@ export async function TachiServerV1Get<T = unknown>(
|
||||
* Takes a url like "/hello" or "bar" and converts it to "https://tachi-server.com/api/v1/hello" or "https://tachi-server.com/api/v1/bar".
|
||||
*/
|
||||
export function PrependTachiUrl(url: string, version: "1" = "1"): string {
|
||||
if (url[0] !== "/") {
|
||||
if (!url.startsWith("/")) {
|
||||
// eslint-disable-next-line no-param-reassign
|
||||
url = `/${url}`;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { CreateLogger, MeiLogger } from "mei-logger";
|
||||
import { LoggerLayers } from "../data/data";
|
||||
import { CreateLogger } from "mei-logger";
|
||||
import type { LoggerLayers } from "../data/data";
|
||||
import type { MeiLogger } from "mei-logger";
|
||||
|
||||
const logger = CreateLogger(`tachi-bot`);
|
||||
|
||||
@@ -10,9 +11,7 @@ export function CreateLayeredLogger(layerName: LoggerLayers) {
|
||||
context: [layerName],
|
||||
});
|
||||
|
||||
lg.defaultMeta = Object.assign({}, lg.defaultMeta ?? {}, {
|
||||
context: [layerName],
|
||||
});
|
||||
lg.defaultMeta = { ...(lg.defaultMeta ?? {}), context: [layerName] };
|
||||
|
||||
return lg as MeiLogger;
|
||||
}
|
||||
|
||||
+47
-26
@@ -1,13 +1,12 @@
|
||||
import { Client } from "discord.js";
|
||||
import { BotConfig } from "../config";
|
||||
import humaniseDuration from "humanize-duration";
|
||||
import _ from "lodash";
|
||||
import { DateTime } from "luxon";
|
||||
import {
|
||||
import { GenericFormatGradeDelta, GetGameConfig, GetGamePTConfig } from "tachi-common";
|
||||
import type { Client } from "discord.js";
|
||||
import type {
|
||||
ChartDocument,
|
||||
Game,
|
||||
GenericFormatGradeDelta,
|
||||
GetGameConfig,
|
||||
GetGamePTConfig,
|
||||
GoalDocument,
|
||||
Grades,
|
||||
IDStrings,
|
||||
@@ -20,15 +19,15 @@ import {
|
||||
ScoreDocument,
|
||||
SongDocument,
|
||||
UGSRatingsLookup,
|
||||
GameConfig,
|
||||
} from "tachi-common";
|
||||
import { GameClassSets } from "tachi-common/game-classes";
|
||||
import { BotConfig } from "../config";
|
||||
import type { GameClassSets } from "tachi-common/game-classes";
|
||||
|
||||
/**
|
||||
* Random From Array - Selects a random value from an array.
|
||||
*/
|
||||
export function RFA<T>(arr: T[]): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
export function RFA<T>(arr: Array<T>): T {
|
||||
return arr[Math.floor(Math.random() * arr.length)] as T;
|
||||
}
|
||||
|
||||
export function TruncateString(string: string, len = 30) {
|
||||
@@ -48,7 +47,11 @@ export function IsAdmin(discordID: string) {
|
||||
}
|
||||
|
||||
export function Sleep(ms: number) {
|
||||
return new Promise<void>((resolve) => setTimeout(() => resolve(), ms));
|
||||
return new Promise<void>((resolve) => {
|
||||
setTimeout(() => {
|
||||
resolve();
|
||||
}, ms);
|
||||
});
|
||||
}
|
||||
|
||||
export function Pluralise(int: integer, str: string) {
|
||||
@@ -100,8 +103,8 @@ export function FormatScoreRating(
|
||||
/**
|
||||
* Typesafe asserted version of Object.entries.
|
||||
*/
|
||||
export function Entries<K extends string, V>(rec: Partial<Record<K, V>>): [K, V][] {
|
||||
return Object.entries(rec) as [K, V][];
|
||||
export function Entries<K extends string, V>(rec: Partial<Record<K, V>>): Array<[K, V]> {
|
||||
return Object.entries(rec) as Array<[K, V]>;
|
||||
}
|
||||
|
||||
export function ParseGPT(str: string) {
|
||||
@@ -110,7 +113,8 @@ export function ParseGPT(str: string) {
|
||||
const game = spl[0] as Game;
|
||||
const playtype = spl[1] as Playtype;
|
||||
|
||||
const gameConfig = GetGameConfig(game);
|
||||
// this is an interesting way of game checking noah
|
||||
const gameConfig = GetGameConfig(game) as GameConfig | undefined;
|
||||
|
||||
if (!gameConfig || !gameConfig.validPlaytypes.includes(playtype)) {
|
||||
throw new Error(`Invalid GPT Combination '${str}'.`);
|
||||
@@ -120,6 +124,10 @@ export function ParseGPT(str: string) {
|
||||
}
|
||||
|
||||
export function UppercaseFirst(str: string) {
|
||||
if (!str[0]) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return str[0].toUpperCase() + str.substring(1);
|
||||
}
|
||||
|
||||
@@ -154,7 +162,15 @@ export function FormatClass(
|
||||
) {
|
||||
const gptConfig = GetGamePTConfig(game, playtype);
|
||||
|
||||
return gptConfig.classHumanisedFormat[classSet][classValue].display;
|
||||
const classInfo = gptConfig.classHumanisedFormat[classSet][classValue];
|
||||
|
||||
if (!classInfo) {
|
||||
throw new Error(
|
||||
`Couldn't find a class at index ${classValue} for ${game} ${playtype} ${classSet}?`
|
||||
);
|
||||
}
|
||||
|
||||
return classInfo.display;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +213,7 @@ export function CreateChartLink(chart: ChartDocument, game: Game) {
|
||||
return `${BotConfig.TACHI_SERVER_LOCATION}/dashboard/games/${game}/${chart.playtype}/songs/${chart.songID}/${chart.chartID}`;
|
||||
}
|
||||
|
||||
type ScOrPBDoc<I extends IDStrings> = ScoreDocument<I> | PBScoreDocument<I>;
|
||||
type ScOrPBDoc<I extends IDStrings> = PBScoreDocument<I> | ScoreDocument<I>;
|
||||
|
||||
export function FormatScoreData<I extends IDStrings = IDStrings>(score: ScOrPBDoc<I>) {
|
||||
const game = score.game;
|
||||
@@ -210,7 +226,7 @@ export function FormatScoreData<I extends IDStrings = IDStrings>(score: ScOrPBDo
|
||||
if (game === "iidx" || game === "bms" || game === "pms") {
|
||||
const bp = (
|
||||
score as ScOrPBDoc<
|
||||
"iidx:SP" | "iidx:DP" | "pms:Controller" | "pms:Keyboard" | "bms:14K" | "bms:7K"
|
||||
"bms:7K" | "bms:14K" | "iidx:DP" | "iidx:SP" | "pms:Controller" | "pms:Keyboard"
|
||||
>
|
||||
).scoreData.hitMeta.bp;
|
||||
|
||||
@@ -252,7 +268,7 @@ export function GetGradeFromPercent<I extends IDStrings = IDStrings>(
|
||||
|
||||
// (hey, this for loop is backwards!)
|
||||
for (let i = boundaries.length; i >= 0; i--) {
|
||||
if (percent + Number.EPSILON >= boundaries[i]) {
|
||||
if (percent + Number.EPSILON >= boundaries[i]!) {
|
||||
return grades[i] as Grades[I];
|
||||
}
|
||||
}
|
||||
@@ -282,7 +298,7 @@ export function GetChartPertinentInfo<I extends IDStrings>(game: Game, chart: Ch
|
||||
if (game === "iidx") {
|
||||
const ch = chart as ChartDocument<"iidx:DP" | "iidx:SP">;
|
||||
|
||||
if (!ch.data.kaidenAverage || !ch.data.worldRecord) {
|
||||
if (ch.data.kaidenAverage === null || ch.data.worldRecord === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -305,6 +321,7 @@ export function FormatChartTierlistInfo(game: Game, chart: ChartDocument) {
|
||||
}
|
||||
|
||||
const fmts = [];
|
||||
|
||||
for (const tierlist of gptConfig.tierlists) {
|
||||
const data = chart.tierlistInfo[tierlist];
|
||||
|
||||
@@ -313,7 +330,9 @@ export function FormatChartTierlistInfo(game: Game, chart: ChartDocument) {
|
||||
}
|
||||
|
||||
fmts.push(
|
||||
`${tierlist}: ${data.text} (${data.value}${data.individualDifference ? " ⚖️" : ""})`
|
||||
`${tierlist}: ${data.text} (${data.value}${
|
||||
data.individualDifference === true ? " ⚖️" : ""
|
||||
})`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -337,7 +356,7 @@ export function ConvertInputIntoGenerousRegex(input: string) {
|
||||
return regex;
|
||||
}
|
||||
|
||||
export function CreateSongMap<G extends Game = Game>(songs: SongDocument<G>[]) {
|
||||
export function CreateSongMap<G extends Game = Game>(songs: Array<SongDocument<G>>) {
|
||||
const songMap = new Map<integer, SongDocument<G>>();
|
||||
|
||||
for (const song of songs) {
|
||||
@@ -347,7 +366,7 @@ export function CreateSongMap<G extends Game = Game>(songs: SongDocument<G>[]) {
|
||||
return songMap;
|
||||
}
|
||||
|
||||
export function CreateUserMap(users: PublicUserDocument[]) {
|
||||
export function CreateUserMap(users: Array<PublicUserDocument>) {
|
||||
const userMap = new Map<integer, PublicUserDocument>();
|
||||
|
||||
for (const user of users) {
|
||||
@@ -357,7 +376,7 @@ export function CreateUserMap(users: PublicUserDocument[]) {
|
||||
return userMap;
|
||||
}
|
||||
|
||||
export function CreateGoalMap(goals: GoalDocument[]) {
|
||||
export function CreateGoalMap(goals: Array<GoalDocument>) {
|
||||
const goalMap = new Map<string, GoalDocument>();
|
||||
|
||||
for (const goal of goals) {
|
||||
@@ -367,8 +386,8 @@ export function CreateGoalMap(goals: GoalDocument[]) {
|
||||
return goalMap;
|
||||
}
|
||||
|
||||
export function CreateChartIDMap<T extends { chartID: string }>(arr: T[]): Map<string, T> {
|
||||
const map = new Map();
|
||||
export function CreateChartIDMap<T extends { chartID: string }>(arr: Array<T>): Map<string, T> {
|
||||
const map = new Map<string, T>();
|
||||
|
||||
for (const t of arr) {
|
||||
map.set(t.chartID, t);
|
||||
@@ -377,7 +396,7 @@ export function CreateChartIDMap<T extends { chartID: string }>(arr: T[]): Map<s
|
||||
return map;
|
||||
}
|
||||
|
||||
export function CreateChartMap<I extends IDStrings = IDStrings>(charts: ChartDocument<I>[]) {
|
||||
export function CreateChartMap<I extends IDStrings = IDStrings>(charts: Array<ChartDocument<I>>) {
|
||||
const chartMap = new Map<string, ChartDocument<I>>();
|
||||
|
||||
for (const chart of charts) {
|
||||
@@ -387,7 +406,7 @@ export function CreateChartMap<I extends IDStrings = IDStrings>(charts: ChartDoc
|
||||
return chartMap;
|
||||
}
|
||||
|
||||
export function CreateScoreIDMap<I extends IDStrings = IDStrings>(scores: ScoreDocument<I>[]) {
|
||||
export function CreateScoreIDMap<I extends IDStrings = IDStrings>(scores: Array<ScoreDocument<I>>) {
|
||||
const scoreMap = new Map<string, ScoreDocument<I>>();
|
||||
|
||||
for (const score of scores) {
|
||||
@@ -405,6 +424,7 @@ export function NumericSOV<T>(getValueFn: (data: T) => number, reverse = false)
|
||||
if (reverse) {
|
||||
return (a: T, b: T) => getValueFn(b) - getValueFn(a);
|
||||
}
|
||||
|
||||
return (a: T, b: T) => getValueFn(a) - getValueFn(b);
|
||||
}
|
||||
|
||||
@@ -423,6 +443,7 @@ export function UniqueOnKey<T>(prop: keyof T) {
|
||||
if (seenBefore.has(item[prop])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
seenBefore.add(item[prop]);
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { SlashCommandStringOption } from "@discordjs/builders";
|
||||
import { FormatGame, GetGameConfig } from "tachi-common";
|
||||
import { ServerConfig } from "../config";
|
||||
import { FormatGame, GetGameConfig } from "tachi-common";
|
||||
import type { SlashCommandStringOption } from "@discordjs/builders";
|
||||
|
||||
/**
|
||||
* Game Playtype options. Frequently used by things that might need
|
||||
* game specific listening.
|
||||
*/
|
||||
const GPTChoices: [string, string][] = [];
|
||||
const GPTChoices: Array<[string, string]> = [];
|
||||
|
||||
for (const game of ServerConfig.games) {
|
||||
const gameConfig = GetGameConfig(game);
|
||||
|
||||
@@ -2,5 +2,5 @@
|
||||
* Determines whether an input is a record or not.
|
||||
*/
|
||||
export function IsRecord<T = string>(v: unknown): v is Record<string, T> {
|
||||
return !!v && typeof v === "object" && !Array.isArray(v);
|
||||
return v !== null && typeof v === "object" && !Array.isArray(v);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { PrudenceError } from "prudence";
|
||||
import type { PrudenceError } from "prudence";
|
||||
|
||||
/**
|
||||
* Formats a PrudenceError into something a little more readable.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {
|
||||
import type {
|
||||
APIPermissions,
|
||||
ChartDocument,
|
||||
FolderDocument,
|
||||
@@ -19,10 +19,10 @@ import {
|
||||
} from "tachi-common";
|
||||
|
||||
export interface ServerConfig {
|
||||
games: Game[];
|
||||
importTypes: ImportTypes[];
|
||||
games: Array<Game>;
|
||||
importTypes: Array<ImportTypes>;
|
||||
name: string;
|
||||
type: "ktchi" | "btchi" | "omni";
|
||||
type: "btchi" | "ktchi" | "omni";
|
||||
}
|
||||
|
||||
export interface ServerStatus {
|
||||
@@ -30,7 +30,7 @@ export interface ServerStatus {
|
||||
startTime: number;
|
||||
version: string;
|
||||
whoami: integer | null;
|
||||
permissions: APIPermissions[];
|
||||
permissions: Array<APIPermissions>;
|
||||
}
|
||||
|
||||
export interface ImportDeferred {
|
||||
@@ -60,28 +60,28 @@ export interface UGPTStats<I extends IDStrings = IDStrings> {
|
||||
}
|
||||
|
||||
export interface ChartQueryReturns {
|
||||
charts: (ChartDocument & { __playcount: integer })[];
|
||||
songs: SongDocument[];
|
||||
charts: Array<ChartDocument & { __playcount: integer }>;
|
||||
songs: Array<SongDocument>;
|
||||
}
|
||||
|
||||
export interface UGPTFolderStat<I extends IDStrings = IDStrings> {
|
||||
folderID: string;
|
||||
grades: Record<Grades[I], integer>;
|
||||
lamps: Record<Lamps[I], integer>;
|
||||
grades: Partial<Record<Grades[I], integer>>;
|
||||
lamps: Partial<Record<Lamps[I], integer>>;
|
||||
chartCount: integer;
|
||||
}
|
||||
|
||||
export interface UGPTFolderTimeline<I extends IDStrings = IDStrings> {
|
||||
songs: SongDocument<IDStringToGame[I]>[];
|
||||
charts: ChartDocument<I>[];
|
||||
scores: ScoreDocument<I>[];
|
||||
songs: Array<SongDocument<IDStringToGame[I]>>;
|
||||
charts: Array<ChartDocument<I>>;
|
||||
scores: Array<ScoreDocument<I>>;
|
||||
folder: FolderDocument;
|
||||
}
|
||||
|
||||
export interface SessionInfo {
|
||||
session: SessionDocument;
|
||||
songs: SongDocument[];
|
||||
charts: ChartDocument[];
|
||||
scores: ScoreDocument[];
|
||||
songs: Array<SongDocument>;
|
||||
charts: Array<ChartDocument>;
|
||||
scores: Array<ScoreDocument>;
|
||||
user: PublicUserDocument;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { FormatGame, Game, integer, Playtype, WebhookEventClassUpdateV1 } from "tachi-common";
|
||||
import { AllClassSets } from "tachi-common/game-classes";
|
||||
import { BotConfig } from "../config";
|
||||
import { client } from "../main";
|
||||
import { GetUGPTStats, GetUserInfo } from "../utils/apiRequests";
|
||||
@@ -8,6 +6,9 @@ import { CreateEmbed } from "../utils/embeds";
|
||||
import { PrependTachiUrl } from "../utils/fetchTachi";
|
||||
import logger from "../utils/logger";
|
||||
import { FormatClass, GetGameChannel } from "../utils/misc";
|
||||
import { FormatGame } from "tachi-common";
|
||||
import type { Game, integer, Playtype, WebhookEventClassUpdateV1 } from "tachi-common";
|
||||
import type { AllClassSets } from "tachi-common/game-classes";
|
||||
|
||||
export async function HandleClassUpdateV1(
|
||||
event: WebhookEventClassUpdateV1["content"]
|
||||
@@ -15,10 +16,12 @@ export async function HandleClassUpdateV1(
|
||||
const { game, playtype } = event;
|
||||
|
||||
let channel;
|
||||
|
||||
try {
|
||||
channel = GetGameChannel(client, game);
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
|
||||
logger.error(`ClassUpdate handler failed: ${err.message}`);
|
||||
return 500;
|
||||
}
|
||||
@@ -35,7 +38,7 @@ export async function HandleClassUpdateV1(
|
||||
// atleast 10 of the volforce ranks, which will just result in channel spam.
|
||||
const minimumNecessaryScores = GetMinimumScores(game, playtype, event.set);
|
||||
|
||||
if (minimumNecessaryScores) {
|
||||
if (minimumNecessaryScores !== null) {
|
||||
const { totalScores } = await GetUGPTStats(userDoc.id, game, playtype);
|
||||
|
||||
// Do not render if the user hasn't hit the score cap.
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import { GetGameConfig, GoalDocument, integer, WebhookEventGoalAchievedV1 } from "tachi-common";
|
||||
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";
|
||||
import { GetGameConfig } from "tachi-common";
|
||||
import type { GoalDocument, integer, WebhookEventGoalAchievedV1 } from "tachi-common";
|
||||
|
||||
export async function HandleGoalAchievedV1(
|
||||
event: WebhookEventGoalAchievedV1["content"]
|
||||
@@ -11,10 +12,12 @@ export async function HandleGoalAchievedV1(
|
||||
const { game } = event;
|
||||
|
||||
let channel;
|
||||
|
||||
try {
|
||||
channel = GetGameChannel(client, game);
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
|
||||
logger.error(`ClassUpdate handler failed: ${err.message}`);
|
||||
return 500;
|
||||
}
|
||||
@@ -26,6 +29,7 @@ export async function HandleGoalAchievedV1(
|
||||
);
|
||||
|
||||
const goalMap = new Map<string, GoalDocument>();
|
||||
|
||||
for (const goalDoc of goalDocuments) {
|
||||
goalMap.set(goalDoc.goalID, goalDoc);
|
||||
}
|
||||
@@ -53,7 +57,7 @@ export async function HandleGoalAchievedV1(
|
||||
: `${e.old.progressHuman}/${e.old.outOfHuman} -> ${e.new.progressHuman}/${e.new.outOfHuman}`;
|
||||
|
||||
return {
|
||||
name: `${goal.title}${shouldShowPlaytype ? ` (${e.playtype})` : ""}`,
|
||||
name: `${goal.name}${shouldShowPlaytype ? ` (${e.playtype})` : ""}`,
|
||||
value,
|
||||
};
|
||||
})
|
||||
|
||||
+18
-8
@@ -1,21 +1,31 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"module": "CommonJS",
|
||||
"noImplicitAny": true,
|
||||
"strict": true,
|
||||
"target": "ES2020",
|
||||
"baseUrl": "src",
|
||||
"outDir": "./js",
|
||||
"lib": [
|
||||
"DOM" // hack workaround. URLSearchParams must be imported, yet
|
||||
// discordJS carelessly uses it without being imported
|
||||
// as if it were a DOM type.
|
||||
// Sad!
|
||||
],
|
||||
"types": [
|
||||
"node",
|
||||
"jest"
|
||||
],
|
||||
"outDir": "js/",
|
||||
"esModuleInterop": true, // lets us use module.exports stuff as if they were ES6 modules.
|
||||
"paths": {
|
||||
"tachi-common": [
|
||||
"../../common/src"
|
||||
],
|
||||
"tachi-common/*": [
|
||||
"../../common/src/*"
|
||||
]
|
||||
},
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules",
|
||||
"**/*.spec.ts"
|
||||
"**/*.test.ts"
|
||||
]
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {},
|
||||
"compilerOptions": {
|
||||
"outDir": "./js",
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts",
|
||||
"src/**/*.test.ts"
|
||||
|
||||
@@ -39,7 +39,6 @@
|
||||
"monk": "^7.3.4",
|
||||
"node-fetch": "2.6.7",
|
||||
"prudence": "^0.9.7",
|
||||
"ts-node": "^10.4.0",
|
||||
"xml2js": "^0.4.23"
|
||||
},
|
||||
"devDependencies": {}
|
||||
|
||||
+3
-2
@@ -20,12 +20,13 @@
|
||||
"@types/node": "17.0.8",
|
||||
"@types/tap": "15.0.3",
|
||||
"eslint": "8.18.0",
|
||||
"eslint-plugin-cadence": "0.0.3",
|
||||
"eslint-plugin-cadence": "0.0.4",
|
||||
"tap": "15.0.9",
|
||||
"ts-node": "10.0.0",
|
||||
"typescript": "4.6.3",
|
||||
"@typescript-eslint/eslint-plugin": "5.22.0",
|
||||
"@typescript-eslint/parser": "5.22.0"
|
||||
"@typescript-eslint/parser": "5.22.0",
|
||||
"tsconfig-paths": "3.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/mongodb": "3.6.18",
|
||||
|
||||
Generated
+19
-105
@@ -9,9 +9,10 @@ importers:
|
||||
'@typescript-eslint/eslint-plugin': 5.22.0
|
||||
'@typescript-eslint/parser': 5.22.0
|
||||
eslint: 8.18.0
|
||||
eslint-plugin-cadence: 0.0.3
|
||||
eslint-plugin-cadence: 0.0.4
|
||||
tap: 15.0.9
|
||||
ts-node: 10.0.0
|
||||
tsconfig-paths: 3.12.0
|
||||
typescript: 4.6.3
|
||||
devDependencies:
|
||||
'@types/node': 17.0.8
|
||||
@@ -19,9 +20,10 @@ importers:
|
||||
'@typescript-eslint/eslint-plugin': 5.22.0_3692bfa38c76dfb409a7f758aafdbd9d
|
||||
'@typescript-eslint/parser': 5.22.0_eslint@8.18.0+typescript@4.6.3
|
||||
eslint: 8.18.0
|
||||
eslint-plugin-cadence: 0.0.3_eslint@8.18.0+typescript@4.6.3
|
||||
eslint-plugin-cadence: 0.0.4_eslint@8.18.0+typescript@4.6.3
|
||||
tap: 15.0.9_ts-node@10.0.0+typescript@4.6.3
|
||||
ts-node: 10.0.0_22ec373cc6e5c139fea80a5e1bbc5c61
|
||||
tsconfig-paths: 3.12.0
|
||||
typescript: 4.6.3
|
||||
|
||||
bot:
|
||||
@@ -50,8 +52,6 @@ importers:
|
||||
node-fetch: 2.6.7
|
||||
prudence: 0.9.6
|
||||
sync-fetch: ^0.3.1
|
||||
tachi-common: 0.7.2
|
||||
ts-node: 10.2.0
|
||||
dependencies:
|
||||
'@discordjs/builders': 0.5.0
|
||||
'@discordjs/rest': 0.1.0-canary.0
|
||||
@@ -72,8 +72,6 @@ importers:
|
||||
node-fetch: 2.6.7
|
||||
prudence: 0.9.6
|
||||
sync-fetch: 0.3.1
|
||||
tachi-common: 0.7.2
|
||||
ts-node: 10.2.0_22ec373cc6e5c139fea80a5e1bbc5c61
|
||||
devDependencies:
|
||||
'@types/express': 4.17.13
|
||||
'@types/express-serve-static-core': 4.17.24
|
||||
@@ -340,7 +338,6 @@ importers:
|
||||
seq-logging: 1.1.1
|
||||
supertest: 6.2.2
|
||||
tap: 15.1.6
|
||||
ts-node: 10.4.0
|
||||
tsconfig-paths: 3.12.0
|
||||
typescript: 4.5.5
|
||||
why-is-node-running: 2.2.1
|
||||
@@ -386,7 +383,6 @@ importers:
|
||||
safe-json-stringify: 1.2.0
|
||||
semver: 7.3.7
|
||||
seq-logging: 1.1.1
|
||||
ts-node: 10.4.0_367793418afa917fddeb69e0b1aa8aae
|
||||
tsconfig-paths: 3.12.0
|
||||
typescript: 4.5.5
|
||||
winston: 3.5.1
|
||||
@@ -414,7 +410,7 @@ importers:
|
||||
node-mocks-http: 1.11.0
|
||||
prettier: 2.5.1
|
||||
supertest: 6.2.2
|
||||
tap: 15.1.6_ts-node@10.4.0+typescript@4.5.5
|
||||
tap: 15.1.6_ts-node@10.0.0+typescript@4.5.5
|
||||
why-is-node-running: 2.2.1
|
||||
|
||||
sieglinde:
|
||||
@@ -3373,25 +3369,6 @@ packages:
|
||||
engines: {node: '>=0.1.90'}
|
||||
dev: false
|
||||
|
||||
/@cspotcode/source-map-consumer/0.8.0:
|
||||
resolution: {integrity: sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==}
|
||||
engines: {node: '>= 12'}
|
||||
dev: false
|
||||
|
||||
/@cspotcode/source-map-support/0.6.1:
|
||||
resolution: {integrity: sha512-DX3Z+T5dt1ockmPdobJS/FAsQPW4V4SrWEhD2iYQT2Cb2tQsiMnYxrcUH9By/Z3B+v0S5LMBkQtV/XOBbpLEOg==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@cspotcode/source-map-consumer': 0.8.0
|
||||
dev: false
|
||||
|
||||
/@cspotcode/source-map-support/0.7.0:
|
||||
resolution: {integrity: sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==}
|
||||
engines: {node: '>=12'}
|
||||
dependencies:
|
||||
'@cspotcode/source-map-consumer': 0.8.0
|
||||
dev: false
|
||||
|
||||
/@csstools/convert-colors/1.4.0:
|
||||
resolution: {integrity: sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
@@ -4244,15 +4221,19 @@ packages:
|
||||
|
||||
/@tsconfig/node10/1.0.9:
|
||||
resolution: {integrity: sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node12/1.0.11:
|
||||
resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node14/1.0.3:
|
||||
resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==}
|
||||
dev: true
|
||||
|
||||
/@tsconfig/node16/1.0.3:
|
||||
resolution: {integrity: sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==}
|
||||
dev: true
|
||||
|
||||
/@types/aes-js/3.1.1:
|
||||
resolution: {integrity: sha512-SDSGgXT3LRCH6qMWk8OHT1vLSVNuHNvCpKCx2/TYtQMbMGGgxJC9fspwSkQjqzRagrWnCrxuLL3jMNXLXHHvSw==}
|
||||
@@ -4966,11 +4947,6 @@ packages:
|
||||
acorn: 8.7.1
|
||||
dev: true
|
||||
|
||||
/acorn-walk/8.2.0:
|
||||
resolution: {integrity: sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
dev: false
|
||||
|
||||
/acorn/6.4.2:
|
||||
resolution: {integrity: sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
@@ -4981,6 +4957,7 @@ packages:
|
||||
resolution: {integrity: sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==}
|
||||
engines: {node: '>=0.4.0'}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/address/1.1.2:
|
||||
resolution: {integrity: sha512-aT6camzM4xEA54YVJYSqxz1kv4IHnQZRtThJJHhUMRExaU5spC7jX5ugSwTaTgJliIgs4VhZOk7htClvQ/LmRA==}
|
||||
@@ -5168,6 +5145,7 @@ packages:
|
||||
|
||||
/arg/4.1.3:
|
||||
resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==}
|
||||
dev: true
|
||||
|
||||
/argparse/1.0.10:
|
||||
resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==}
|
||||
@@ -6711,6 +6689,7 @@ packages:
|
||||
|
||||
/create-require/1.1.1:
|
||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||
dev: true
|
||||
|
||||
/cron-parser/2.18.0:
|
||||
resolution: {integrity: sha512-s4odpheTyydAbTBQepsqd2rNWGa2iV3cyo8g7zbI2QQYGLVsfbhmwukayS1XHppe02Oy1fg7mg6xoaraVJeEcg==}
|
||||
@@ -7315,6 +7294,7 @@ packages:
|
||||
/diff/4.0.2:
|
||||
resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==}
|
||||
engines: {node: '>=0.3.1'}
|
||||
dev: true
|
||||
|
||||
/diff/5.1.0:
|
||||
resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==}
|
||||
@@ -7787,8 +7767,8 @@ packages:
|
||||
find-up: 2.1.0
|
||||
dev: true
|
||||
|
||||
/eslint-plugin-cadence/0.0.3_eslint@8.18.0+typescript@4.6.3:
|
||||
resolution: {integrity: sha512-RQz1d4wU2UZe3Ztt8UPCZffvxZFuL6WkleIxcR5yW3KTwilXOePjpmJR69989L2IIlN+JcKlPjtPPairUV1E9g==}
|
||||
/eslint-plugin-cadence/0.0.4_eslint@8.18.0+typescript@4.6.3:
|
||||
resolution: {integrity: sha512-uodA7IZ5KebQSx+r0DVz0j4hqBBpqq8GwW3kweiO7kDrNrDIkP/NL2T2bz7qQ6V4PpzJoi2PY6i1f5NTzZwQxQ==}
|
||||
engines: {node: 12.x || 14.x || >= 16}
|
||||
peerDependencies:
|
||||
eslint: '>=8'
|
||||
@@ -10606,6 +10586,7 @@ packages:
|
||||
|
||||
/make-error/1.3.6:
|
||||
resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==}
|
||||
dev: true
|
||||
|
||||
/mamacro/0.0.3:
|
||||
resolution: {integrity: sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==}
|
||||
@@ -14887,12 +14868,6 @@ packages:
|
||||
prudence: 0.9.8
|
||||
dev: false
|
||||
|
||||
/tachi-common/0.7.2:
|
||||
resolution: {integrity: sha512-VBCrWWtQRa2FcVEcc7JNKBS7g9ZX0+wYbcCJKGsuSsPGWrv9wRVLwxc5Oo4xKEs12Lm93t7e2ywEvLV7mmEfCQ==}
|
||||
dependencies:
|
||||
'@types/mongodb': 3.6.18
|
||||
dev: false
|
||||
|
||||
/tap-mocha-reporter/5.0.3:
|
||||
resolution: {integrity: sha512-6zlGkaV4J+XMRFkN0X+yuw6xHbE9jyCZ3WUKfw4KxMyRGOpYSRuuQTRJyWX88WWuLdVTuFbxzwXhXuS2XE6o0g==}
|
||||
engines: {node: '>= 8'}
|
||||
@@ -14986,7 +14961,7 @@ packages:
|
||||
- treport
|
||||
- '@types/react'
|
||||
|
||||
/tap/15.1.6_ts-node@10.4.0+typescript@4.5.5:
|
||||
/tap/15.1.6_ts-node@10.0.0+typescript@4.5.5:
|
||||
resolution: {integrity: sha512-TN7xH6Q2tUPTd6qwmkhuFJcx1vUR8e4dDUpBKc61G0krOzne7Ia6aKIFb8O/0kVazachSSuVME1V8nQ2xwWL8w==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
@@ -15023,7 +14998,7 @@ packages:
|
||||
tap-parser: 10.1.0
|
||||
tap-yaml: 1.0.0
|
||||
tcompare: 5.0.7
|
||||
ts-node: 10.4.0_367793418afa917fddeb69e0b1aa8aae
|
||||
ts-node: 10.0.0_22ec373cc6e5c139fea80a5e1bbc5c61
|
||||
typescript: 4.5.5
|
||||
which: 2.0.2
|
||||
transitivePeerDependencies:
|
||||
@@ -15278,67 +15253,6 @@ packages:
|
||||
yn: 3.1.1
|
||||
dev: true
|
||||
|
||||
/ts-node/10.2.0_22ec373cc6e5c139fea80a5e1bbc5c61:
|
||||
resolution: {integrity: sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg==}
|
||||
engines: {node: '>=12.0.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.6.1
|
||||
'@tsconfig/node10': 1.0.9
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.3
|
||||
'@types/node': 17.0.8
|
||||
acorn: 8.7.1
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 4.6.3
|
||||
yn: 3.1.1
|
||||
dev: false
|
||||
|
||||
/ts-node/10.4.0_367793418afa917fddeb69e0b1aa8aae:
|
||||
resolution: {integrity: sha512-g0FlPvvCXSIO1JDF6S232P5jPYqBkRL9qly81ZgAOSU7rwI0stphCgd2kLiCrU9DjQCrJMWEqcNSjQL02s6d8A==}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
'@swc/core': '>=1.2.50'
|
||||
'@swc/wasm': '>=1.2.50'
|
||||
'@types/node': '*'
|
||||
typescript: '>=2.7'
|
||||
peerDependenciesMeta:
|
||||
'@swc/core':
|
||||
optional: true
|
||||
'@swc/wasm':
|
||||
optional: true
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.7.0
|
||||
'@tsconfig/node10': 1.0.9
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.3
|
||||
'@types/node': 17.0.8
|
||||
acorn: 8.7.1
|
||||
acorn-walk: 8.2.0
|
||||
arg: 4.1.3
|
||||
create-require: 1.1.1
|
||||
diff: 4.0.2
|
||||
make-error: 1.3.6
|
||||
typescript: 4.5.5
|
||||
yn: 3.1.1
|
||||
dev: false
|
||||
|
||||
/ts-pnp/1.1.4_typescript@4.3.5:
|
||||
resolution: {integrity: sha512-1J/vefLC+BWSo+qe8OnJQfWTYRS6ingxjwqmHMqaMxXMj7kFtKLgAaYW3JeX3mktjgUL+etlU8/B4VUAUI9QGw==}
|
||||
engines: {node: '>=6'}
|
||||
@@ -15357,7 +15271,6 @@ packages:
|
||||
json5: 1.0.1
|
||||
minimist: 1.2.6
|
||||
strip-bom: 3.0.0
|
||||
dev: false
|
||||
|
||||
/tsconfig-paths/3.14.1:
|
||||
resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==}
|
||||
@@ -16484,6 +16397,7 @@ packages:
|
||||
/yn/3.1.1:
|
||||
resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/zod/3.17.3:
|
||||
resolution: {integrity: sha512-4oKP5zvG6GGbMlqBkI5FESOAweldEhSOZ6LI6cG+JzUT7ofj1ZOC0PJudpQOpT1iqOFpYYtX5Pw0+o403y4bcg==}
|
||||
|
||||
@@ -81,7 +81,6 @@
|
||||
"safe-json-stringify": "1.2.0",
|
||||
"semver": "^7.3.7",
|
||||
"seq-logging": "1.1.1",
|
||||
"ts-node": "10.4.0",
|
||||
"tsconfig-paths": "3.12.0",
|
||||
"typescript": "4.5.5",
|
||||
"winston": "3.5.1",
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": "src",
|
||||
"outDir": "./js",
|
||||
"lib": [
|
||||
"ES2019",
|
||||
// This is necessary because -- for some unknown reason -- the AWS SDK
|
||||
@@ -27,11 +28,6 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"ts-node": {
|
||||
"require": [
|
||||
"tsconfig-paths/register"
|
||||
]
|
||||
},
|
||||
"include": [
|
||||
"src/**/*.ts"
|
||||
],
|
||||
|
||||
+2
-4
@@ -3,15 +3,13 @@
|
||||
"target": "ES2020",
|
||||
"module": "CommonJS",
|
||||
"lib": [
|
||||
"ES2019"
|
||||
"ES2019",
|
||||
],
|
||||
"declaration": true,
|
||||
"strict": true,
|
||||
"allowJs": false,
|
||||
"esModuleInterop": true,
|
||||
"outDir": "./js",
|
||||
"noUncheckedIndexedAccess": true,
|
||||
"sourceMap": true,
|
||||
"noEmit": true
|
||||
"sourceMap": true
|
||||
},
|
||||
}
|
||||
Reference in New Issue
Block a user