Compare commits
No commits in common. "b6e24c517bb6f62c0635920bef903d5c29952750" and "5cfcb3ba0caff7565cd1fbade08634482a125737" have entirely different histories.
b6e24c517b
...
5cfcb3ba0c
13 changed files with 45 additions and 243 deletions
14
bun.lock
14
bun.lock
|
@ -6,11 +6,9 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^14.21.0",
|
"discord.js": "^14.21.0",
|
||||||
"ky": "^1.8.2",
|
"ky": "^1.8.2",
|
||||||
"msgpack-lite": "^0.1.26",
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest",
|
||||||
"@types/msgpack-lite": "^0.1.11",
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5",
|
"typescript": "^5",
|
||||||
|
@ -38,8 +36,6 @@
|
||||||
|
|
||||||
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
||||||
|
|
||||||
"@types/msgpack-lite": ["@types/msgpack-lite@0.1.11", "", { "dependencies": { "@types/node": "*" } }, "sha512-cdCZS/gw+jIN22I4SUZUFf1ZZfVv5JM1//Br/MuZcI373sxiy3eSSoiyLu0oz+BPatTbGGGBO5jrcvd0siCdTQ=="],
|
|
||||||
|
|
||||||
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
|
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
|
||||||
|
|
||||||
"@types/react": ["@types/react@19.1.9", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA=="],
|
"@types/react": ["@types/react@19.1.9", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA=="],
|
||||||
|
@ -56,16 +52,8 @@
|
||||||
|
|
||||||
"discord.js": ["discord.js@14.21.0", "", { "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.1", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-U5w41cEmcnSfwKYlLv5RJjB8Joa+QJyRwIJz5i/eg+v2Qvv6EYpCRhN9I2Rlf0900LuqSDg8edakUATrDZQncQ=="],
|
"discord.js": ["discord.js@14.21.0", "", { "dependencies": { "@discordjs/builders": "^1.11.2", "@discordjs/collection": "1.5.3", "@discordjs/formatters": "^0.6.1", "@discordjs/rest": "^2.5.1", "@discordjs/util": "^1.1.1", "@discordjs/ws": "^1.2.3", "@sapphire/snowflake": "3.5.3", "discord-api-types": "^0.38.1", "fast-deep-equal": "3.1.3", "lodash.snakecase": "4.1.1", "magic-bytes.js": "^1.10.0", "tslib": "^2.6.3", "undici": "6.21.3" } }, "sha512-U5w41cEmcnSfwKYlLv5RJjB8Joa+QJyRwIJz5i/eg+v2Qvv6EYpCRhN9I2Rlf0900LuqSDg8edakUATrDZQncQ=="],
|
||||||
|
|
||||||
"event-lite": ["event-lite@0.1.3", "", {}, "sha512-8qz9nOz5VeD2z96elrEKD2U433+L3DWdUdDkOINLGOJvx1GsMBbMn0aCeu28y8/e85A6mCigBiFlYMnTBEGlSw=="],
|
|
||||||
|
|
||||||
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
||||||
|
|
||||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
|
||||||
|
|
||||||
"int64-buffer": ["int64-buffer@0.1.10", "", {}, "sha512-v7cSY1J8ydZ0GyjUHqF+1bshJ6cnEVLo9EnjB8p+4HDRPZc9N5jjmvUV7NvEsqQOKyH0pmIBFWXVQbiS0+OBbA=="],
|
|
||||||
|
|
||||||
"isarray": ["isarray@1.0.0", "", {}, "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ=="],
|
|
||||||
|
|
||||||
"ky": ["ky@1.8.2", "", {}, "sha512-XybQJ3d4Ea1kI27DoelE5ZCT3bSJlibYTtQuMsyzKox3TMyayw1asgQdl54WroAm+fIA3ZCr8zXW2RpR7qWVpA=="],
|
"ky": ["ky@1.8.2", "", {}, "sha512-XybQJ3d4Ea1kI27DoelE5ZCT3bSJlibYTtQuMsyzKox3TMyayw1asgQdl54WroAm+fIA3ZCr8zXW2RpR7qWVpA=="],
|
||||||
|
|
||||||
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
"lodash": ["lodash@4.17.21", "", {}, "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="],
|
||||||
|
@ -74,8 +62,6 @@
|
||||||
|
|
||||||
"magic-bytes.js": ["magic-bytes.js@1.12.1", "", {}, "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="],
|
"magic-bytes.js": ["magic-bytes.js@1.12.1", "", {}, "sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA=="],
|
||||||
|
|
||||||
"msgpack-lite": ["msgpack-lite@0.1.26", "", { "dependencies": { "event-lite": "^0.1.1", "ieee754": "^1.1.8", "int64-buffer": "^0.1.9", "isarray": "^1.0.0" }, "bin": { "msgpack": "./bin/msgpack" } }, "sha512-SZ2IxeqZ1oRFGo0xFGbvBJWMp3yLIY9rlIJyxy8CGrwZn1f0ZK4r6jV/AM1r0FZMDUkWkglOk/eeKIL9g77Nxw=="],
|
|
||||||
|
|
||||||
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
|
"ts-mixer": ["ts-mixer@6.0.4", "", {}, "sha512-ufKpbmrugz5Aou4wcr5Wc1UUFWOLhq+Fm6qa6P0w0K5Qw2yhaUoiWszhCVuNQyNwrlGiscHOmqYoAox1PtvgjA=="],
|
||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
import list from "./list";
|
|
||||||
import register from "./register";
|
|
||||||
import user from "./user";
|
|
||||||
|
|
||||||
export default [
|
|
||||||
user,
|
|
||||||
register,
|
|
||||||
list
|
|
||||||
]
|
|
107
cmd/list.ts
107
cmd/list.ts
|
@ -1,107 +0,0 @@
|
||||||
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, CacheType, ChatInputCommandInteraction, Events, Interaction, InteractionReplyOptions, MessageFlags, SlashCommandBuilder, User } from "discord.js";
|
|
||||||
import { db } from "../db/db";
|
|
||||||
import { b64decode, b64encode } from "../lib/b64";
|
|
||||||
import { createEmbed } from "../lib/embed";
|
|
||||||
import { formatSize } from "../lib/files";
|
|
||||||
import { StereoFile } from "../types/files";
|
|
||||||
|
|
||||||
export const data = new SlashCommandBuilder()
|
|
||||||
.setName("list")
|
|
||||||
.setDescription("list all of your files")
|
|
||||||
.addIntegerOption(option =>
|
|
||||||
option.setName("page")
|
|
||||||
.setDescription("page number to view")
|
|
||||||
.setRequired(false)
|
|
||||||
.setMinValue(1)
|
|
||||||
);
|
|
||||||
|
|
||||||
export async function renderList(user: User, userId: string, page: number): Promise<InteractionReplyOptions> {
|
|
||||||
const amount = 2;
|
|
||||||
|
|
||||||
const { count } = await db.get<{ count: number }>`
|
|
||||||
SELECT COUNT(*) as count FROM files WHERE owner = ${userId}
|
|
||||||
`;
|
|
||||||
const totalPages = Math.max(1, Math.ceil(count / amount));
|
|
||||||
const pages = Math.max(1, Math.min(page, totalPages));
|
|
||||||
|
|
||||||
const files = await db.all<StereoFile[]>`
|
|
||||||
SELECT * FROM files WHERE owner = ${userId}
|
|
||||||
ORDER BY created_at DESC
|
|
||||||
LIMIT ${amount} OFFSET ${(pages - 1) * amount}
|
|
||||||
`;
|
|
||||||
|
|
||||||
if (files.length === 0) {
|
|
||||||
return { content: "you havn't uploaded any files yet, visit the website to get started!", flags: MessageFlags.Ephemeral };
|
|
||||||
}
|
|
||||||
|
|
||||||
const embed = createEmbed(user)
|
|
||||||
.setTitle("your files")
|
|
||||||
.addFields(...files.map(file => ({
|
|
||||||
name: file.name,
|
|
||||||
value: `${formatSize(file.size)}\n${new Date(file.created_at).toLocaleString()}\n[open in browser](${process.env.API}/${file.id})`,
|
|
||||||
inline: true
|
|
||||||
})))
|
|
||||||
.setFooter({ text: `page ${pages} of ${totalPages}` });
|
|
||||||
|
|
||||||
const row = new ActionRowBuilder<ButtonBuilder>()
|
|
||||||
.addComponents(
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(b64encode({ direction: -1, user: userId, pages: pages }))
|
|
||||||
.setLabel('<')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
.setDisabled(pages === 1),
|
|
||||||
new ButtonBuilder()
|
|
||||||
.setCustomId(b64encode({ direction: 1, user: userId, pages: pages }))
|
|
||||||
.setLabel('>')
|
|
||||||
.setStyle(ButtonStyle.Danger)
|
|
||||||
.setDisabled(pages === totalPages)
|
|
||||||
);
|
|
||||||
|
|
||||||
return { embeds: [embed], components: [row] };
|
|
||||||
}
|
|
||||||
|
|
||||||
export const execute = async (interaction: ChatInputCommandInteraction) => {
|
|
||||||
const page = interaction.options.getInteger("page") || 1;
|
|
||||||
const userId = interaction.user.id;
|
|
||||||
const reply = await renderList(interaction.user, userId, page);
|
|
||||||
await interaction.reply(reply);
|
|
||||||
};
|
|
||||||
|
|
||||||
export const on: {
|
|
||||||
[event in Events]?: (interaction: Interaction<CacheType>) => Promise<void>;
|
|
||||||
} = {
|
|
||||||
[Events.InteractionCreate]: async (interaction: Interaction<CacheType>) => {
|
|
||||||
if (!interaction.isButton()) return;
|
|
||||||
// old, cursed code :vomit:
|
|
||||||
|
|
||||||
// const match = interaction.customId.match(/^s\.list\.(prev|next)\.(\d+)$/);
|
|
||||||
// if (!match) return;
|
|
||||||
|
|
||||||
// let page = parseInt(match[2] || "1", 10);
|
|
||||||
// page = match[1] === "next" ? page + 1 : page - 1;
|
|
||||||
|
|
||||||
// const dirtyReply = await renderList(interaction.user, interaction.user.id, page);
|
|
||||||
// const { flags, ...reply } = dirtyReply;
|
|
||||||
// await interaction.update({ ...reply });
|
|
||||||
|
|
||||||
// new, clean code :sunglasses: (minified since discord limits ids to 100 chars)
|
|
||||||
|
|
||||||
const data = b64decode<{
|
|
||||||
direction: -1 | 1;
|
|
||||||
user: string;
|
|
||||||
pages: number;
|
|
||||||
}>(interaction.customId);
|
|
||||||
|
|
||||||
if (interaction.user.id !== data.user) {
|
|
||||||
await interaction.reply({ content: "hey, stop that!!!", flags: MessageFlags.Ephemeral });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const page = data.pages + data.direction;
|
|
||||||
const dirty = await renderList(interaction.user, interaction.user.id, page);
|
|
||||||
const { flags, ...r } = dirty;
|
|
||||||
await interaction.update({ ...r });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default [data, execute, on] as const;
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { ChatInputCommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js";
|
|
||||||
import { db } from "../db/db";
|
|
||||||
|
|
||||||
export const data = new SlashCommandBuilder()
|
|
||||||
.setName("register")
|
|
||||||
.setDescription("create your stereo account");
|
|
||||||
|
|
||||||
export const execute = async (interaction: ChatInputCommandInteraction) => {
|
|
||||||
const existingUser = await db.get<{ id: string }>`SELECT id FROM users WHERE id = ${interaction.user.id}`;
|
|
||||||
if (existingUser) {
|
|
||||||
await interaction.reply({ content: "you already have a stereo account", flags: MessageFlags.Ephemeral });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await interaction.reply({
|
|
||||||
content: `visit [this link](${process.env.API + "/auth/login"}) to create your stereo account`,
|
|
||||||
flags: MessageFlags.Ephemeral
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
export default [data, execute] as const;
|
|
33
cmd/user.ts
33
cmd/user.ts
|
@ -1,9 +1,8 @@
|
||||||
// commands/overview.ts
|
// commands/overview.ts
|
||||||
import { ChatInputCommandInteraction, MessageFlags, SlashCommandBuilder } from "discord.js";
|
import { ChatInputCommandInteraction, EmbedBuilder, MessageFlags, SlashCommandBuilder } from "discord.js";
|
||||||
import { db } from "../db/db";
|
import { db } from "../db";
|
||||||
import { createEmbed } from "../lib/embed";
|
import { formatSize } from "../lib";
|
||||||
import { formatSize } from "../lib/files";
|
import { StereoFile } from "../types";
|
||||||
import { StereoFile } from "../types/files";
|
|
||||||
|
|
||||||
export const data = new SlashCommandBuilder()
|
export const data = new SlashCommandBuilder()
|
||||||
.setName("user")
|
.setName("user")
|
||||||
|
@ -12,16 +11,6 @@ export const data = new SlashCommandBuilder()
|
||||||
|
|
||||||
export const execute = async (interaction: ChatInputCommandInteraction) => {
|
export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
const user = interaction.options.getUser("user") || interaction.user;
|
const user = interaction.options.getUser("user") || interaction.user;
|
||||||
if (user.id === interaction.client.user?.id) {
|
|
||||||
await interaction.reply({ content: "hey! stop that!!!!", flags: MessageFlags.Ephemeral });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (user.bot) {
|
|
||||||
await interaction.reply({ content: "bots can't have stereo accounts...", flags: MessageFlags.Ephemeral });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!user) {
|
if (!user) {
|
||||||
await interaction.reply({ content: "couldn't find user", flags: MessageFlags.Ephemeral });
|
await interaction.reply({ content: "couldn't find user", flags: MessageFlags.Ephemeral });
|
||||||
return;
|
return;
|
||||||
|
@ -29,11 +18,6 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
|
|
||||||
const id = await db.get<{ id: string }>`SELECT id FROM users WHERE id = ${user.id}`;
|
const id = await db.get<{ id: string }>`SELECT id FROM users WHERE id = ${user.id}`;
|
||||||
if (!id) {
|
if (!id) {
|
||||||
if (user.id === interaction.user.id) {
|
|
||||||
await interaction.reply({ content: "you don't have a stereo account yet, use the `/register` command to make one", flags: MessageFlags.Ephemeral });
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await interaction.reply({ content: "this user doesn't have a stereo account", flags: MessageFlags.Ephemeral });
|
await interaction.reply({ content: "this user doesn't have a stereo account", flags: MessageFlags.Ephemeral });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -41,13 +25,20 @@ export const execute = async (interaction: ChatInputCommandInteraction) => {
|
||||||
const files = await db.all<StereoFile[]>`SELECT * FROM files WHERE owner = ${user.id}`;
|
const files = await db.all<StereoFile[]>`SELECT * FROM files WHERE owner = ${user.id}`;
|
||||||
const totalSize = files.reduce((a, b) => a + b.size, 0);
|
const totalSize = files.reduce((a, b) => a + b.size, 0);
|
||||||
|
|
||||||
const embed = createEmbed(user)
|
const embed = new EmbedBuilder()
|
||||||
|
.setColor(0xff264e)
|
||||||
|
.setAuthor({
|
||||||
|
name: `${user.globalName || "user"} on stereo`,
|
||||||
|
iconURL: user.avatarURL({ size: 512 }) || ""
|
||||||
|
})
|
||||||
.setDescription("Here's your overview:")
|
.setDescription("Here's your overview:")
|
||||||
.addFields(
|
.addFields(
|
||||||
{ name: "Uploads", value: `${files.length} files`, inline: true },
|
{ name: "Uploads", value: `${files.length} files`, inline: true },
|
||||||
{ name: "Uploaded", value: `${formatSize(totalSize)} / 15 GB`, inline: true },
|
{ name: "Uploaded", value: `${formatSize(totalSize)} / 15 GB`, inline: true },
|
||||||
{ name: "Plan", value: `Free`, inline: true }
|
{ name: "Plan", value: `Free`, inline: true }
|
||||||
)
|
)
|
||||||
|
.setFooter({ text: "powered by stereo" })
|
||||||
|
.setTimestamp();
|
||||||
|
|
||||||
await interaction.reply({ embeds: [embed] });
|
await interaction.reply({ embeds: [embed] });
|
||||||
}
|
}
|
||||||
|
|
5
globals.d.ts
vendored
5
globals.d.ts
vendored
|
@ -4,11 +4,8 @@ declare module "bun" {
|
||||||
TOKEN: string;
|
TOKEN: string;
|
||||||
CLIENT_ID: string;
|
CLIENT_ID: string;
|
||||||
|
|
||||||
// db
|
// stereo
|
||||||
DB_URL: string;
|
DB_URL: string;
|
||||||
DB_TYPE: "sqlite" | "postgres";
|
DB_TYPE: "sqlite" | "postgres";
|
||||||
|
|
||||||
// web
|
|
||||||
API: string;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
37
index.ts
37
index.ts
|
@ -1,23 +1,22 @@
|
||||||
import { ActivityType, Client, Events, GatewayIntentBits, REST, Routes } from "discord.js";
|
import { ActivityType, Client, Events, GatewayIntentBits, REST, Routes } from "discord.js";
|
||||||
import commands from "./cmd";
|
import user from "./cmd/user";
|
||||||
import { db } from "./db/db";
|
import { db } from "./db";
|
||||||
import { StereoFile } from "./types/files";
|
import { StereoFile } from "./types";
|
||||||
|
|
||||||
const bot = new Client({
|
const client = new Client({
|
||||||
intents: [
|
intents: [
|
||||||
GatewayIntentBits.Guilds,
|
GatewayIntentBits.Guilds,
|
||||||
GatewayIntentBits.GuildMessages,
|
GatewayIntentBits.GuildMessages,
|
||||||
GatewayIntentBits.MessageContent,
|
GatewayIntentBits.MessageContent,
|
||||||
|
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
const rest = new REST({ version: "10" }).setToken(process.env.TOKEN);
|
||||||
|
|
||||||
const rest = new REST({ version: "10" })
|
client.once(Events.ClientReady, async (c) => {
|
||||||
.setToken(process.env.TOKEN);
|
|
||||||
|
|
||||||
bot.once(Events.ClientReady, async (c) => {
|
|
||||||
await rest.put(
|
await rest.put(
|
||||||
Routes.applicationCommands(process.env.CLIENT_ID),
|
Routes.applicationCommands(process.env.CLIENT_ID),
|
||||||
{ body: commands.map(([data, _]) => data) }
|
{ body: commands.map(([data]) => data) }
|
||||||
);
|
);
|
||||||
|
|
||||||
const files = (await db.all<StereoFile[]>`SELECT * FROM files`).length
|
const files = (await db.all<StereoFile[]>`SELECT * FROM files`).length
|
||||||
|
@ -29,11 +28,14 @@ bot.once(Events.ClientReady, async (c) => {
|
||||||
console.log(c.user.tag);
|
console.log(c.user.tag);
|
||||||
});
|
});
|
||||||
|
|
||||||
bot.on(Events.InteractionCreate, async interaction => {
|
const commands = [
|
||||||
|
user
|
||||||
|
]
|
||||||
|
|
||||||
|
client.on(Events.InteractionCreate, async interaction => {
|
||||||
if (!interaction.isChatInputCommand()) return;
|
if (!interaction.isChatInputCommand()) return;
|
||||||
const cmd = commands.find(([data]) => data.name === interaction.commandName);
|
const cmd = commands.find(([data]) => data.name === interaction.commandName);
|
||||||
if (!cmd) return;
|
if (!cmd) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await cmd[1](interaction);
|
await cmd[1](interaction);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
@ -42,16 +44,7 @@ bot.on(Events.InteractionCreate, async interaction => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const [_, __, on] of commands) {
|
client.login(process.env.TOKEN).catch((err) => {
|
||||||
if (!on) continue;
|
|
||||||
|
|
||||||
for (const [event, handler] of Object.entries(on)) {
|
|
||||||
if (!Object.values(Events).includes(event as Events)) { console.warn(`Unknown event: ${event}`); continue; }
|
|
||||||
bot.on(event, handler);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bot.login(process.env.TOKEN).catch((err) => {
|
|
||||||
console.error("Failed to login:", err)
|
console.error("Failed to login:", err)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
});
|
});
|
14
lib/b64.ts
14
lib/b64.ts
|
@ -1,14 +0,0 @@
|
||||||
import m from "msgpack-lite";
|
|
||||||
|
|
||||||
// i actually love this
|
|
||||||
export const b64encode = (obj: object): string => {
|
|
||||||
return Buffer.from(m.encode(obj)).toString("base64url");
|
|
||||||
}
|
|
||||||
|
|
||||||
export const b64decode = <T>(str: string): T => {
|
|
||||||
try {
|
|
||||||
return m.decode(Buffer.from(str, "base64url"));
|
|
||||||
} catch {
|
|
||||||
throw new Error("invalid base64-encoded object string: " + str);
|
|
||||||
}
|
|
||||||
}
|
|
12
lib/embed.ts
12
lib/embed.ts
|
@ -1,12 +0,0 @@
|
||||||
import { EmbedBuilder, User } from "discord.js";
|
|
||||||
|
|
||||||
export const createEmbed = (user: User) => {
|
|
||||||
return new EmbedBuilder()
|
|
||||||
.setColor(0xff264e)
|
|
||||||
.setAuthor({
|
|
||||||
name: `${user.globalName || "user"} on stereo`,
|
|
||||||
iconURL: user.avatarURL({ size: 512 }) || ""
|
|
||||||
})
|
|
||||||
.setFooter({ text: "powered by stereo" })
|
|
||||||
.setTimestamp()
|
|
||||||
}
|
|
|
@ -4,15 +4,13 @@
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"private": true,
|
"private": true,
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest",
|
"@types/bun": "latest"
|
||||||
"@types/msgpack-lite": "^0.1.11"
|
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"typescript": "^5"
|
"typescript": "^5"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"discord.js": "^14.21.0",
|
"discord.js": "^14.21.0",
|
||||||
"ky": "^1.8.2",
|
"ky": "^1.8.2"
|
||||||
"msgpack-lite": "^0.1.26"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue