From e447f2a35517ca2b89a360c47e35fd4f8147da53 Mon Sep 17 00:00:00 2001 From: Hri7566 Date: Thu, 15 Feb 2024 03:47:35 -0500 Subject: [PATCH] stuff --- bun.lockb | Bin 7581 -> 8700 bytes package.json | 40 +++--- prisma/schema.prisma | 20 ++- src/api/{util/config.ts => api/auth.ts} | 0 src/api/api/server.ts | 5 + src/api/api/trpc.ts | 54 +++++++- src/api/commands/Command.ts | 12 ++ src/api/commands/groups/fishing/fish.ts | 12 ++ src/api/commands/groups/general/help.ts | 33 +++++ src/api/commands/groups/index.ts | 36 +++++ src/api/commands/groups/util/data.ts | 10 ++ src/api/commands/handler.ts | 42 ++++++ src/api/commands/prefixes.ts | 1 + src/api/data/token.ts | 27 ++++ src/api/index.ts | 1 - src/mpp/api/trpc.ts | 15 ++ src/mpp/bot/Bot.ts | 173 ++++++++++++++++++++++++ src/mpp/bot/index.ts | 30 ++++ src/mpp/index.ts | 3 + src/util/Logger.ts | 43 ++++++ src/util/config.ts | 25 ++++ src/util/tick.ts | 19 +++ src/util/time.ts | 22 +++ src/util/types.d.ts | 16 +++ test/api/data/token.test.ts | 28 ++++ tsconfig.json | 43 +++--- 26 files changed, 662 insertions(+), 48 deletions(-) rename src/api/{util/config.ts => api/auth.ts} (100%) create mode 100644 src/api/commands/Command.ts create mode 100644 src/api/commands/groups/fishing/fish.ts create mode 100644 src/api/commands/groups/general/help.ts create mode 100644 src/api/commands/groups/index.ts create mode 100644 src/api/commands/groups/util/data.ts create mode 100644 src/api/commands/handler.ts create mode 100644 src/api/commands/prefixes.ts create mode 100644 src/api/data/token.ts create mode 100644 src/mpp/api/trpc.ts create mode 100644 src/mpp/bot/Bot.ts create mode 100644 src/mpp/bot/index.ts create mode 100644 src/mpp/index.ts create mode 100644 src/util/Logger.ts create mode 100644 src/util/config.ts create mode 100644 src/util/tick.ts create mode 100644 src/util/time.ts create mode 100644 src/util/types.d.ts create mode 100644 test/api/data/token.test.ts diff --git a/bun.lockb b/bun.lockb index b79560f6c52714138d66e9ab2f009c74a2a84ffe..d76ce6a3ad559cb880fbe642305bfaf75469a7b9 100755 GIT binary patch delta 2087 zcmb^yYfzL`^xkiG*#|7_!tSz*JR(u>u^%k3%!0^6ASJXJ!djsuQ68>>Knt2S3QXys zV;Y`8)Tz-XYlM<~XOotKsiX*#GuD`?P0plfjfxFr2A#9)XZph#e{^T=ch0%zeZF(g zeSgY>tarr;DTAjrw5=P`jkRri-uP}9cEj<+`+i5At$T~% z8J?l@sqOE{>}%2}<+&>lZ%91@^LR5~05^ELeiQ1)p+1JdWVq$<0gr~OT*bR!f{-3F z8Dr1&`a$-?6@llJ!|vHHHVq7i%z=Jx=5Il}kghn1tTfmyOi?tU)fpbF2eA|nCPOct zGs{xMR-g&Yh*EsG@_@^u^|z6mja)RwXv?I)w25-YtjJN}sSZykQMfV7@$_i}Ra`~k zR0>B3RX~S4O(;^p0D^V}OjM-tpTMO^7smQPhayd=@qqzFN zpkr_xf(Fy*PN_ zO7kBH7Y-!E>u_6eZMh3UFplS9_nD>k@J1}Dm8y*>5lsk3NX)oVwg3iEcDRd?1Dp|a2DiyWY z7~Is9cw=e8&@}S2*$fjRxQ>zf_y)2_ED|A6>R~cLH0heM4E8w zPzfiO-hf9)hwRXu2*gcyfnX5s+oNH~*aHi6291Xwf^w9+*e)iEHi$ALnQ~Bu2BS2` z1PX+~%ZBjy0z}Yc+C%%%|G~OEh+J8EQpf_506-+W( z>`#_@vSp8E!;>|ohe4X-n36-ZQ?eykUaWlMLU-rL{eVwg240*f#)%m2V&qWm`t63< zg_rIr4Lofss)+F{8MCA(WOCo3%bOZfx9NBn%7#O?F)UPicHX>I(c2t&^I3soO~v>m z##$Bdz-SJY-lGrCY+1g2(RVI^ucA9DGDk@dl)5_gFT(vnJ7X-Qof_?sj54~BFI{{jls)6f6_ delta 1388 zcmcIkT}TvB6ux(6XWbuXUH{gd*-R@)jhx&y&9!Y6Maj0HB-ykKivA=*O9YKd0}HVv z_0WTY^pFV!g(V455D`UzR1ZP^P+$<0VA)GPWZF67jt~*`(t$hQ`R1N;@44rkd*_P# zHg;+mUnd@V@=r~|)i)oqTF%|8Yp@>{A05nIG56ZtQa*KitDMYqiR%idG;fJpB#U1= zV=X6Z59p)>zfRi8YDr``Zc0nP zgR}p*ucY8H0<^kNVS-*MD1ZsZ5#F0XH3zv1D$NDL9tnEQLE*Xt1`)u6%@`b6Zv?ne1z3RGG~;IuWwMR;xv z!!xT4nYIv@pve}7Mw<+8kwrmA++Bze7>5qd@Vxc;} zuqYH|ERI)^>4bO~NG#H@kM+b;kGgPB(y7<5@2S6-8%H5!7NwtDRyNZrG)-n?PPL#q zVQ1-eAZ|2O6zY_HGY-ESMzFFFq))UN6-?_+0q0tZpCBVR{yQy zVyAHNlE9y0F1R5eulV9Lxd|8^;t7VUwU{G-fe>Ye|xj@;D z>8FRwS{ryewWIewy5?xUTx~rYjO2611!lDfN>!iQ7cp+l%NgN~j`>u4!bqfK=vI${ U-BUGm*`tZD;4u%Cr`!;J0uxvBNB{r; diff --git a/package.json b/package.json index c005eeb..d0b6738 100644 --- a/package.json +++ b/package.json @@ -1,19 +1,25 @@ { - "name": "fishing-api", - "module": "src/api/index.ts", - "type": "module", - "devDependencies": { - "@types/bun": "latest" - }, - "peerDependencies": { - "typescript": "^5.0.0" - }, - "dependencies": { - "@prisma/client": "^5.9.1", - "@trpc/client": "next", - "@trpc/server": "next", - "prisma": "^5.9.1", - "trpc-bun-adapter": "^1.1.0", - "zod": "^3.22.4" - } + "name": "fishing-api", + "module": "src/api/index.ts", + "type": "module", + "scripts": { + "start": "bun .", + "start-bot": "bun src/mpp/index.ts" + }, + "devDependencies": { + "@types/bun": "latest" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@prisma/client": "^5.9.1", + "@trpc/client": "next", + "@trpc/server": "next", + "mpp-client-net": "^1.1.3", + "prisma": "^5.9.1", + "trpc-bun-adapter": "^1.1.0", + "yaml": "^2.3.4", + "zod": "^3.22.4" + } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma index db3cb68..dcaa515 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -11,7 +11,21 @@ datasource db { } model User { - id String @id - name String - color String + id String @id + name String + color String + inventory Inventory @relation(fields: [inventoryId], references: [id]) + inventoryId Int @unique +} + +model Inventory { + id Int @id @default(autoincrement()) + balance Int + items Json @default("[]") + User User? +} + +model AuthToken { + id Int @id @default(autoincrement()) + token String @unique } diff --git a/src/api/util/config.ts b/src/api/api/auth.ts similarity index 100% rename from src/api/util/config.ts rename to src/api/api/auth.ts diff --git a/src/api/api/server.ts b/src/api/api/server.ts index eca625a..d62617c 100644 --- a/src/api/api/server.ts +++ b/src/api/api/server.ts @@ -1,5 +1,8 @@ import { createBunServeHandler } from "trpc-bun-adapter"; import { appRouter } from "./trpc"; +import { Logger } from "@util/Logger"; + +const logger = new Logger("Server"); export const server = Bun.serve( createBunServeHandler({ @@ -7,4 +10,6 @@ export const server = Bun.serve( }) ); +logger.info("Started on port", (process.env.PORT as string) || 3000); + export default server; diff --git a/src/api/api/trpc.ts b/src/api/api/trpc.ts index 9e95876..a30004a 100644 --- a/src/api/api/trpc.ts +++ b/src/api/api/trpc.ts @@ -1,16 +1,58 @@ -import { initTRPC } from "@trpc/server"; +import { handleCommand } from "@server/commands/handler"; +import { prefixes } from "@server/commands/prefixes"; +import { TRPCError, initTRPC } from "@trpc/server"; +import { Logger } from "@util/Logger"; import { z } from "zod"; -const t = initTRPC.create(); +export interface Context { + isAuthed: boolean; +} + +const t = initTRPC.context().create(); export const router = t.router; export const publicProcedure = t.procedure; +export const privateProcedure = publicProcedure.use(async opts => { + const { ctx } = opts; + + if (!ctx.isAuthed) throw new TRPCError({ code: "UNAUTHORIZED" }); + + return opts.next({ + ctx: { + isAuthed: true + } + }); +}); + +const logger = new Logger("tRPC"); export const appRouter = router({ - cast: publicProcedure.input(z.string()).query(async opts => { - const { input } = opts; - const response = `${input} cast their rod`; - return { response }; + prefixes: publicProcedure.query(async opts => { + return prefixes; + }), + + command: publicProcedure + .input( + z.object({ + command: z.string(), + prefix: z.string(), + args: z.array(z.string()), + user: z.object({ + id: z.string(), + name: z.string(), + color: z.string() + }) + }) + ) + .query(async opts => { + const { command, args, prefix, user } = opts.input; + const out = await handleCommand(command, args, prefix, user); + + return out; + }), + + auth: publicProcedure.input(z.string()).query(async opts => { + const token = opts.input; }) }); diff --git a/src/api/commands/Command.ts b/src/api/commands/Command.ts new file mode 100644 index 0000000..c551c85 --- /dev/null +++ b/src/api/commands/Command.ts @@ -0,0 +1,12 @@ +export class Command { + constructor( + public id: string, + public aliases: string[], + public description: string, + public usage: string, + public permissionNode: string, + public callback: TCommandCallback + ) {} +} + +export default Command; diff --git a/src/api/commands/groups/fishing/fish.ts b/src/api/commands/groups/fishing/fish.ts new file mode 100644 index 0000000..2120d7e --- /dev/null +++ b/src/api/commands/groups/fishing/fish.ts @@ -0,0 +1,12 @@ +import Command from "@server/commands/Command"; + +export const fish = new Command( + "fish", + ["fish", "fosh", "cast"], + "Send your LURE into a water for catching fish", + "fish", + "command.fishing.fish", + async () => { + return "There is no fishing yet, please come back later when I write the code for it"; + } +); diff --git a/src/api/commands/groups/general/help.ts b/src/api/commands/groups/general/help.ts new file mode 100644 index 0000000..7e83e7a --- /dev/null +++ b/src/api/commands/groups/general/help.ts @@ -0,0 +1,33 @@ +import Command from "@server/commands/Command"; +import { commandGroups } from ".."; +import { logger } from "@server/commands/handler"; + +export const help = new Command( + "help", + [ + "help", + "h", + "holp", + "halp", + "hilp", + "hulp", + "commands", + "commonds", + "cmds", + "cimminds", + "cammands", + "cummunds" + ], + "Help command", + "help [command]", + "command.general.help", + async (command, args, prefix, user) => { + return `${commandGroups + .map(group => { + return `${group.displayName}: ${group.commands + .map(cmd => cmd.aliases[0]) + .join(", ")}`; + }) + .join("\n")}`; + } +); diff --git a/src/api/commands/groups/index.ts b/src/api/commands/groups/index.ts new file mode 100644 index 0000000..bfde77f --- /dev/null +++ b/src/api/commands/groups/index.ts @@ -0,0 +1,36 @@ +import type { Command } from "../Command"; +import { fish } from "./fishing/fish"; +import { help } from "./general/help"; +import { data } from "./util/data"; + +interface ICommandGroup { + id: string; + displayName: string; + commands: Command[]; +} + +export const commandGroups: ICommandGroup[] = []; + +const general: ICommandGroup = { + id: "general", + displayName: "General", + commands: [help] +}; + +commandGroups.push(general); + +const fishing: ICommandGroup = { + id: "fishing", + displayName: "Fishing", + commands: [fish] +}; + +commandGroups.push(fishing); + +const util: ICommandGroup = { + id: "util", + displayName: "Utility", + commands: [data] +}; + +commandGroups.push(util); diff --git a/src/api/commands/groups/util/data.ts b/src/api/commands/groups/util/data.ts new file mode 100644 index 0000000..bda72af --- /dev/null +++ b/src/api/commands/groups/util/data.ts @@ -0,0 +1,10 @@ +import Command from "@server/commands/Command"; + +export const data = new Command( + "data", + ["data"], + "Data command", + "data", + "command.util.data", + async () => {} +); diff --git a/src/api/commands/handler.ts b/src/api/commands/handler.ts new file mode 100644 index 0000000..56568b4 --- /dev/null +++ b/src/api/commands/handler.ts @@ -0,0 +1,42 @@ +import { Logger } from "@util/Logger"; +import type Command from "./Command"; +import { commandGroups } from "./groups"; + +export const logger = new Logger("Command Handler"); + +export async function handleCommand( + command: string, + args: string[], + prefix: string, + user: IUser +): Promise { + let foundCommand: Command | undefined; + + commandGroups.forEach(group => { + if (!foundCommand) { + foundCommand = group.commands.find(cmd => { + return cmd.aliases.includes(command); + }); + } + }); + + if (!foundCommand) return; + + // TODO Check user's (or their groups') permissions against command permission node + + try { + const response = await foundCommand.callback( + command, + args, + prefix, + user + ); + if (response) return { response }; + } catch (err) { + logger.error(err); + return { + response: + "An error has occurred, but no fish were lost. If you are the fishing bot owner, check the error logs for details." + }; + } +} diff --git a/src/api/commands/prefixes.ts b/src/api/commands/prefixes.ts new file mode 100644 index 0000000..04698cd --- /dev/null +++ b/src/api/commands/prefixes.ts @@ -0,0 +1 @@ +export const prefixes = ["/"]; diff --git a/src/api/data/token.ts b/src/api/data/token.ts new file mode 100644 index 0000000..a6a50c6 --- /dev/null +++ b/src/api/data/token.ts @@ -0,0 +1,27 @@ +import prisma from "./prisma"; + +export async function createToken() { + const randomToken = crypto.randomUUID(); + + await prisma.authToken.create({ + data: { + token: randomToken + } + }); + + return randomToken; +} + +export async function deleteToken(token: string) { + await prisma.authToken.delete({ + where: { token } + }); +} + +export async function checkToken(token: string) { + const existing = await prisma.authToken.findUnique({ + where: { token } + }); + + return !!existing; +} diff --git a/src/api/index.ts b/src/api/index.ts index 75462ab..fb0b736 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1,2 +1 @@ import "./api/server"; -import prisma from "S:/data/prisma"; diff --git a/src/mpp/api/trpc.ts b/src/mpp/api/trpc.ts new file mode 100644 index 0000000..7a85c1b --- /dev/null +++ b/src/mpp/api/trpc.ts @@ -0,0 +1,15 @@ +import { createTRPCClient, httpBatchLink } from "@trpc/client"; +import type { AppRouter } from "@server/api/trpc"; + +export const trpc = createTRPCClient({ + links: [ + httpBatchLink({ + url: "http://localhost:3000" + }), + httpBatchLink({ + url: "https://fishing.hri7566.info/api" + }) + ] +}); + +export default trpc; diff --git a/src/mpp/bot/Bot.ts b/src/mpp/bot/Bot.ts new file mode 100644 index 0000000..be6a913 --- /dev/null +++ b/src/mpp/bot/Bot.ts @@ -0,0 +1,173 @@ +import Client from "mpp-client-net"; +import { Logger } from "@util/Logger"; +import trpc from "@client/api/trpc"; + +export interface MPPNetBotConfig { + uri: string; + + channel: { + id: string; + allowColorChanging: boolean; + }; +} + +export class MPPNetBot { + public client: Client; + + public logger: Logger; + + constructor( + public config: MPPNetBotConfig, + token: string = process.env[`MPP_TOKEN_NET`] as string + ) { + this.logger = new Logger(config.channel.id); + this.client = new Client(config.uri, token); + + this.client.setChannel(config.channel.id); + + this.bindEventListeners(); + } + + public start() { + this.client.start(); + } + + public stop() { + this.client.stop(); + } + + public bindEventListeners() { + this.client.on("hi", msg => { + this.logger.info(`Connected to ${this.client.uri}`); + }); + + this.client.on("ch", msg => { + this.logger.info( + `Received channel update for channel ID "${msg.ch._id}"` + ); + }); + + this.client.on("a", async msg => { + let prefixes: string[]; + + try { + prefixes = await trpc.prefixes.query(); + } catch (err) { + this.logger.error(err); + this.logger.warn("Unable to contact server"); + return; + } + + let usedPrefix: string | undefined = prefixes.find(pr => + msg.a.startsWith(pr) + ); + + if (!usedPrefix) return; + + const args = msg.a.split(" "); + + const command = await trpc.command.query({ + args: args.slice(1, args.length), + command: args[0].substring(usedPrefix.length), + prefix: usedPrefix, + user: { + id: msg.p._id, + name: msg.p.name, + color: msg.p.color + } + }); + + if (!command) return; + if (command.response) this.sendChat(command.response); + }); + + (this.client as unknown as any).on( + "dm", + async (msg: { + m: "dm"; + id: string; + t: number; + a: string; + + sender: { + _id: string; + name: string; + color: string; + afk: boolean; + tag?: { + text: string; + color: string; + }; + id: string; + }; + + recipient: { + _id: string; + name: string; + color: string; + afk: boolean; + tag?: { + text: string; + color: string; + }; + id: string; + }; + }) => { + let prefixes: string[]; + + try { + prefixes = await trpc.prefixes.query(); + } catch (err) { + this.logger.error(err); + this.logger.warn("Unable to contact server"); + return; + } + + let usedPrefix: string | undefined = prefixes.find(pr => + msg.a.startsWith(pr) + ); + + if (!usedPrefix) return; + + const args = msg.a.split(" "); + + const command = await trpc.command.query({ + args: args.slice(1, args.length), + command: args[0].substring(usedPrefix.length), + prefix: usedPrefix, + user: { + id: msg.sender._id, + name: msg.sender.name, + color: msg.sender.color + } + }); + + if (!command) return; + if (command.response) this.sendChat(command.response); + } + ); + } + + public sendChat(text: string) { + let lines = text.split("\n"); + + for (const line of lines) { + if (line.length <= 510) { + this.client.sendArray([ + { + m: "a", + message: `\u034f${line + .split("\t") + .join("") + .split("\r") + .join("")}` + } + ]); + } else { + this.sendChat(line); + } + } + } +} + +export default MPPNetBot; diff --git a/src/mpp/bot/index.ts b/src/mpp/bot/index.ts new file mode 100644 index 0000000..63f9800 --- /dev/null +++ b/src/mpp/bot/index.ts @@ -0,0 +1,30 @@ +import { loadConfig } from "@util/config"; +import { MPPNetBot, type MPPNetBotConfig } from "./Bot"; + +const bots = []; + +const defaults = loadConfig("config/bots.yml", [ + { + uri: "wss://mppclone.com:8443", + channel: { + id: "βœ§π““π“”π“₯ π“‘π“Έπ“Έπ“Άβœ§", + allowColorChanging: true + } + } +] as MPPNetBotConfig[]); + +export function connectDefaultBots() { + defaults.forEach(conf => { + initBot(conf); + }); +} + +export function initBot(conf: MPPNetBotConfig) { + const bot = new MPPNetBot(conf); + bot.start(); + bots.push(bot); +} + +export { MPPNetBot as Bot }; + +export default MPPNetBot; diff --git a/src/mpp/index.ts b/src/mpp/index.ts new file mode 100644 index 0000000..b5476de --- /dev/null +++ b/src/mpp/index.ts @@ -0,0 +1,3 @@ +import { connectDefaultBots } from "./bot"; + +connectDefaultBots(); diff --git a/src/util/Logger.ts b/src/util/Logger.ts new file mode 100644 index 0000000..82353ec --- /dev/null +++ b/src/util/Logger.ts @@ -0,0 +1,43 @@ +import { getHHMMSS } from "./time"; + +export class Logger { + private static log(...args: any[]) { + const time = getHHMMSS(); + + console.log(`\x1b[30m${time}\x1b[0m`, ...args); + } + + constructor(public id: string) {} + + public info(...args: any[]) { + Logger.log( + `\x1b[34m[${this.id}]\x1b[0m`, + `\x1b[34m[INFO]\x1b[0m`, + ...args + ); + } + + public error(...args: any[]) { + Logger.log( + `\x1b[34m[${this.id}]\x1b[0m`, + `\x1b[31m[ERROR]\x1b[0m`, + ...args + ); + } + + public warn(...args: any[]) { + Logger.log( + `\x1b[34m[${this.id}]\x1b[0m`, + `\x1b[33m[WARNING]\x1b[0m`, + ...args + ); + } + + public debug(...args: any[]) { + Logger.log( + `\x1b[34m[${this.id}]\x1b[0m`, + `\x1b[32m[DEBUG]\x1b[0m`, + ...args + ); + } +} diff --git a/src/util/config.ts b/src/util/config.ts new file mode 100644 index 0000000..4e3de3a --- /dev/null +++ b/src/util/config.ts @@ -0,0 +1,25 @@ +import { existsSync, readFileSync, writeFileSync, mkdirSync } from "fs"; +import YAML from "yaml"; +import { parse } from "path/posix"; + +export function loadConfig(path: string, defaultConfig: T) { + const parsed = parse(path); + const dir = parsed.dir; + + if (!existsSync(dir)) { + mkdirSync(dir); + } + + if (existsSync(path)) { + const yaml = readFileSync(path).toString(); + const data = YAML.parse(yaml); + + return data as T; + } else { + return defaultConfig; + } +} + +export function saveConfig(path: string, config: T) { + writeFileSync(path, YAML.stringify(config)); +} diff --git a/src/util/tick.ts b/src/util/tick.ts new file mode 100644 index 0000000..25af37b --- /dev/null +++ b/src/util/tick.ts @@ -0,0 +1,19 @@ +type TickEvent = () => Promise | void; + +const ticks: TickEvent[] = []; + +(globalThis as unknown as Record).ticker = setInterval(() => { + for (const tick of ticks) tick(); +}, 1000 / 20); + +export function addTickEvent(event: TickEvent) { + ticks.push(event); +} + +export function removeTickEvent(event: TickEvent) { + const index = ticks.indexOf(event); + + if (index >= 0) { + ticks.splice(index, 1); + } +} diff --git a/src/util/time.ts b/src/util/time.ts new file mode 100644 index 0000000..7c7a907 --- /dev/null +++ b/src/util/time.ts @@ -0,0 +1,22 @@ +export function getHHMMSS() { + const now = Date.now(); + + const s = now / 1000; + const m = s / 60; + const h = m / 60; + + const hh = Math.floor(h % 12) + .toString() + .padStart(2, "0"); + const mm = Math.floor(m % 60) + .toString() + .padStart(2, "0"); + const ss = Math.floor(s % 60) + .toString() + .padStart(2, "0"); + const ms = Math.floor(now % 1000) + .toString() + .padStart(3, "0"); + + return `${hh}:${mm}:${ss}.${ms}`; +} diff --git a/src/util/types.d.ts b/src/util/types.d.ts new file mode 100644 index 0000000..736743b --- /dev/null +++ b/src/util/types.d.ts @@ -0,0 +1,16 @@ +interface IUser { + id: string; + name: string; + color: string; +} + +interface ICommandResponse { + response: string; +} + +type TCommandCallback = ( + command: string, + args: string[], + prefix: string, + user: IUser +) => Promise; diff --git a/test/api/data/token.test.ts b/test/api/data/token.test.ts new file mode 100644 index 0000000..7500b09 --- /dev/null +++ b/test/api/data/token.test.ts @@ -0,0 +1,28 @@ +import { checkToken, createToken, deleteToken } from "@server/data/token"; +import { test, expect } from "bun:test"; + +test("Token can be created and deleted", async () => { + const token = await createToken(); + expect(token).toBeString(); + await deleteToken(token); +}); + +test("Token can be validated", async () => { + const token = await createToken(); + expect(token).toBeString(); + + const checked = await checkToken(token); + expect(checked).toBeTruthy(); + + await deleteToken(token); +}); + +test("Token can be invalidated", async () => { + const token = await createToken(); + expect(token).toBeString(); + + await deleteToken(token); + + const checked = await checkToken(token); + expect(checked).toBeFalsy(); +}); diff --git a/tsconfig.json b/tsconfig.json index 8243fb1..7f0d096 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,27 +1,28 @@ { - "compilerOptions": { - "lib": ["ESNext"], - "target": "ESNext", - "module": "ESNext", - "moduleDetection": "force", - "jsx": "react-jsx", - "allowJs": true, + "compilerOptions": { + "lib": ["ESNext"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, - /* Bundler mode */ - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "verbatimModuleSyntax": true, - "noEmit": true, + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, - /* Linting */ - "skipLibCheck": true, - "strict": true, - "noFallthroughCasesInSwitch": true, - "forceConsistentCasingInFileNames": true, + /* Linting */ + "skipLibCheck": true, + "strict": true, + "noFallthroughCasesInSwitch": true, + "forceConsistentCasingInFileNames": true, - "paths": { - "S:/*": ["./src/api/*"], - "C:/*": ["./src/bot/*"], + "paths": { + "@server/*": ["./src/api/*"], + "@client/*": ["./src/mpp/*"], + "@util/*": ["./src/util/*"] + } } - } }