mirror of
https://github.com/xHyroM/roles-bot.git
synced 2024-12-21 21:31:05 +01:00
feat: add contexts
This commit is contained in:
parent
05aa790303
commit
6cf73a07a5
12 changed files with 131 additions and 57 deletions
|
@ -5,6 +5,7 @@
|
|||
"scripts": {
|
||||
"build": "node scripts/build.mjs",
|
||||
"dev": "miniflare --watch --debug --port 8787",
|
||||
"dev:tunnel": "cloudflared tunnel --url localhost:8787/",
|
||||
"deploy": "cross-env NODE_ENV=production wrangler publish"
|
||||
},
|
||||
"keywords": [],
|
||||
|
|
|
@ -1,15 +1,10 @@
|
|||
import { InteractionResponseType } from "discord-api-types/v10";
|
||||
import { Command } from "../structs/Command";
|
||||
import respond from "../utils/respond";
|
||||
|
||||
new Command({
|
||||
name: "setup",
|
||||
run: async () => {
|
||||
return respond({
|
||||
type: InteractionResponseType.ChannelMessageWithSource,
|
||||
data: {
|
||||
content: "Setup",
|
||||
},
|
||||
run: async (ctx) => {
|
||||
await ctx.editReply({
|
||||
content: "Setup",
|
||||
});
|
||||
},
|
||||
});
|
||||
|
|
|
@ -9,17 +9,19 @@ import {
|
|||
import { COMMANDS, COMPONENTS } from "./registers";
|
||||
import { verify } from "./utils/verify";
|
||||
import respond from "./utils/respond";
|
||||
import { CommandContext } from "./structs/contexts/CommandContext";
|
||||
import { ComponentContext } from "./structs/contexts/ComponentContext";
|
||||
|
||||
console.log(COMMANDS);
|
||||
|
||||
export default {
|
||||
fetch: async (request: Request) => {
|
||||
fetch: async (request: Request, env: Env) => {
|
||||
if (
|
||||
!request.headers.get("X-Signature-Ed25519") ||
|
||||
!request.headers.get("X-Signature-Timestamp")
|
||||
)
|
||||
return Response.redirect("https://xhyrom.dev");
|
||||
if (!(await verify(request)))
|
||||
if (!(await verify(request, env)))
|
||||
return new Response("Invalid request signature", { status: 401 });
|
||||
|
||||
const interaction = (await request.json()) as
|
||||
|
@ -38,7 +40,14 @@ export default {
|
|||
);
|
||||
|
||||
if (!command) return new Response("Unknown command", { status: 404 });
|
||||
return command.run(interaction);
|
||||
|
||||
try {
|
||||
return respond({
|
||||
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
||||
});
|
||||
} finally {
|
||||
command.run(new CommandContext(interaction, env));
|
||||
}
|
||||
}
|
||||
|
||||
const component = COMPONENTS.find(
|
||||
|
@ -46,6 +55,13 @@ export default {
|
|||
);
|
||||
|
||||
if (!component) return new Response("Unknown component", { status: 404 });
|
||||
return component.run(interaction);
|
||||
|
||||
try {
|
||||
return respond({
|
||||
type: InteractionResponseType.DeferredChannelMessageWithSource,
|
||||
});
|
||||
} finally {
|
||||
component.run(new ComponentContext(interaction, env));
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import { APIApplicationCommandInteraction } from "discord-api-types/v10";
|
||||
import { registerCommand } from "../registers";
|
||||
import { CommandContext } from "./contexts/CommandContext";
|
||||
|
||||
interface CommandOptions {
|
||||
name: string;
|
||||
run: (interaction: APIApplicationCommandInteraction) => Promise<Response>;
|
||||
run: (interaction: CommandContext) => void;
|
||||
}
|
||||
|
||||
export class Command {
|
||||
public name: string;
|
||||
public run: (
|
||||
interaction: APIApplicationCommandInteraction,
|
||||
) => Promise<Response>;
|
||||
public run: (interaction: CommandContext) => void;
|
||||
|
||||
constructor(options: CommandOptions) {
|
||||
this.name = options.name;
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
import { APIMessageComponentInteraction } from "discord-api-types/v10";
|
||||
import { registerComponent } from "../registers";
|
||||
import { ComponentContext } from "./contexts/ComponentContext";
|
||||
|
||||
interface ComponentOptions {
|
||||
id: string;
|
||||
run: (interaction: APIMessageComponentInteraction) => Promise<Response>;
|
||||
run: (interaction: ComponentContext) => void;
|
||||
}
|
||||
|
||||
export class Component {
|
||||
public id: string;
|
||||
public run: (
|
||||
interaction: APIMessageComponentInteraction,
|
||||
) => Promise<Response>;
|
||||
public run: (interaction: ComponentContext) => void;
|
||||
|
||||
constructor(options: ComponentOptions) {
|
||||
this.id = options.id;
|
||||
|
|
12
packages/bot/src/structs/contexts/CommandContext.ts
Normal file
12
packages/bot/src/structs/contexts/CommandContext.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { APIApplicationCommandInteraction } from "discord-api-types/v10";
|
||||
import { Context } from "./Context";
|
||||
|
||||
export class CommandContext extends Context {
|
||||
public interaction: APIApplicationCommandInteraction;
|
||||
|
||||
constructor(interaction: APIApplicationCommandInteraction, env: Env) {
|
||||
super(interaction, env);
|
||||
|
||||
this.interaction = interaction;
|
||||
}
|
||||
}
|
12
packages/bot/src/structs/contexts/ComponentContext.ts
Normal file
12
packages/bot/src/structs/contexts/ComponentContext.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { APIMessageComponentInteraction } from "discord-api-types/v10";
|
||||
import { Context } from "./Context";
|
||||
|
||||
export class ComponentContext extends Context {
|
||||
public interaction: APIMessageComponentInteraction;
|
||||
|
||||
constructor(interaction: APIMessageComponentInteraction, env: Env) {
|
||||
super(interaction, env);
|
||||
|
||||
this.interaction = interaction;
|
||||
}
|
||||
}
|
33
packages/bot/src/structs/contexts/Context.ts
Normal file
33
packages/bot/src/structs/contexts/Context.ts
Normal file
|
@ -0,0 +1,33 @@
|
|||
import {
|
||||
APIInteraction,
|
||||
APIInteractionResponseCallbackData,
|
||||
RouteBases,
|
||||
Routes,
|
||||
} from "discord-api-types/v10";
|
||||
|
||||
export class Context {
|
||||
public interaction: APIInteraction;
|
||||
public env: Env;
|
||||
|
||||
constructor(interaction: APIInteraction, env: Env) {
|
||||
this.interaction = interaction;
|
||||
this.env = env;
|
||||
}
|
||||
|
||||
public async editReply(content: APIInteractionResponseCallbackData) {
|
||||
return await fetch(
|
||||
`${RouteBases.api}${Routes.webhookMessage(
|
||||
this.interaction.application_id,
|
||||
this.interaction.token,
|
||||
)}`,
|
||||
{
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(content),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `Bot ${this.env.token}`,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
8
packages/bot/src/types.d.ts
vendored
8
packages/bot/src/types.d.ts
vendored
|
@ -1,3 +1,7 @@
|
|||
// secrets: wrangler secret put <name>
|
||||
declare const publicKey: string;
|
||||
declare const token: string;
|
||||
declare let MINIFLARE; // just check because algorithm is different
|
||||
|
||||
declare interface Env {
|
||||
publicKey: string;
|
||||
token: string;
|
||||
}
|
||||
|
|
|
@ -10,28 +10,28 @@ function hex2bin(hex: string) {
|
|||
return buf;
|
||||
}
|
||||
|
||||
const PUBLIC_KEY = crypto.subtle.importKey(
|
||||
"raw",
|
||||
hex2bin(publicKey),
|
||||
{
|
||||
name: "NODE-ED25519",
|
||||
namedCurve: "NODE-ED25519",
|
||||
},
|
||||
true,
|
||||
["verify"],
|
||||
);
|
||||
|
||||
const encoder = new TextEncoder();
|
||||
|
||||
export async function verify(request: Request) {
|
||||
export async function verify(request: Request, env: Env) {
|
||||
const subtle = await crypto.subtle.importKey(
|
||||
"raw",
|
||||
hex2bin(env.publicKey),
|
||||
{
|
||||
name: typeof MINIFLARE !== "undefined" ? "Ed25519" : "NODE-ED25519",
|
||||
namedCurve: typeof MINIFLARE !== "undefined" ? "Ed25519" : "NODE-ED25519",
|
||||
},
|
||||
true,
|
||||
["verify"],
|
||||
);
|
||||
|
||||
// rome-ignore lint/style/noNonNullAssertion: its fine
|
||||
const signature = hex2bin(request.headers.get("X-Signature-Ed25519")!);
|
||||
const timestamp = request.headers.get("X-Signature-Timestamp");
|
||||
const unknown = await request.clone().text();
|
||||
|
||||
return await crypto.subtle.verify(
|
||||
"NODE-ED25519",
|
||||
await PUBLIC_KEY,
|
||||
typeof MINIFLARE !== "undefined" ? "Ed25519" : "NODE-ED25519",
|
||||
subtle,
|
||||
signature,
|
||||
encoder.encode(timestamp + unknown),
|
||||
);
|
||||
|
|
|
@ -3,6 +3,8 @@ type = "javascript"
|
|||
account_id = "294bee38d448e390dab3757215c63f03"
|
||||
compatibility_date = "2022-07-12"
|
||||
|
||||
main = "dist/worker.mjs"
|
||||
|
||||
[build]
|
||||
command = "pnpm build"
|
||||
[build.upload]
|
||||
|
|
41
turbo.json
41
turbo.json
|
@ -1,21 +1,24 @@
|
|||
{
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"dev": {
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"preview": {
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"deploy": {
|
||||
"dependsOn": ["build", "test", "lint"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
}
|
||||
"$schema": "https://turbo.build/schema.json",
|
||||
"pipeline": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"dev": {
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"dev:tunnel": {
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"preview": {
|
||||
"outputs": ["dist"]
|
||||
},
|
||||
"deploy": {
|
||||
"dependsOn": ["build", "test", "lint"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue