Nubis, ein Open-Source-Framework von Eytak
Nubis ist ein TypeScript-Framework für Discord-Bots. Schreib eine Datei und du hast einen Slash-Befehl, typisiert aus dem, was du geschrieben hast, mit Tests, die ohne Discord laufen.
$ npx create-nubis my-botimport { command, hasPermission, option } from "nubis";
import { PermissionFlagsBits } from "discord-api-types/v10";
import { confirmBan } from "../../components/confirm-ban";
export default command({
description: "Ban a member",
ephemeral: true,
options: {
user: option.user({ required: true }),
days: option.integer({
choices: [
{ name: "One day", value: 1 },
{ name: "A week", value: 7 },
],
}),
},
guards: [hasPermission(PermissionFlagsBits.BanMembers)],
run: ({ options, reply }) =>
reply({
content: `Ban ${options.user.username}?`,
components: [confirmBan({ userId: options.user.id })],
}),
});
adahat /mod ban verwendet
my-botApp
Ban alice?
Nur du kannst das sehen
commands/mod/ban.ts/mod ban
Wähl eine Datei. Der Pfad ist der Befehl.Typen
Optionswerte, Auswahl-Unions, Komponenten-Status und Modal-Felder werden aus ihren Definitionen abgeleitet. Nachschlagen per String gibt es nicht.
days: option.integer({
choices: [
{ name: "One day", value: 1 },
{ name: "A week", value: 7 },
],
}),abgeleitet
options.days: 1 | 7 | undefined
export const confirmBan = button({
id: "confirm-ban",
label: "Confirm",
state: z.object({ userId: z.string() }),
onClick: ({ state }) => …abgeleitet
state.userId: string
fields: {
reason: textInput({
label: "Reason",
required: true,
}),
contact: textInput({ label: "Contact" }),
},abgeleitet
values.contact: string | undefined
Discords Regeln
Befehlsnamen mit bis zu 32 Zeichen, höchstens 25 Optionen und 25 Auswahlen, custom_ids mit 100 Zeichen, 5 Reihen Komponenten. Eine Definition, die Discord ablehnen würde, schlägt fehl, sobald sie geladen wird – und der Fehler sagt, wo.
days: option.integer({
choices: [
{ name: "One day", value: 1 },
{ name: "A week and a half", value: 7.5 },
],
}),$ nubis dev
[nubis] Synced commands:
+ ping
+ mod
[nubis] commands/mod/ban.ts changed, restarting.
[nubis] /mod ban option "days": integer choices must be whole numbers.
[nubis] Fix the error and save; I'll try again.
Testen
nubis/testing führt Befehle, Buttons, Auswahlmenüs, Modals und Menüs so aus, wie Discord es tun würde. Kein Token, kein Netzwerk, kein Testserver.
import { PermissionFlagsBits } from "discord-api-types/v10";
import { fake, testCommand } from "nubis/testing";
import ban from "../commands/mod/ban";
test("asks for confirmation", async () => {
const result = await testCommand(ban)
.as({ permissions: PermissionFlagsBits.BanMembers })
.run({ user: fake.user("alice") });
expect(result.replies).toEqual(["Ban alice?"]);
expect(result.ephemeral).toBe(true);
});
test("members without the permission are turned away", async () => {
const result = await testCommand(ban).run({ user: fake.user("alice") });
expect(result.status).toBe("denied");
});$ bun test
tests/ban.test.ts:
✓ asks for confirmation
✓ members without the permission are turned away
2 pass
0 fail
Antworten
Discord gibt einem Bot 3 Sekunden für die Antwort. Ruf reply() auf, den Rest erledigt Nubis: die Wartenachricht, die Bearbeitung und die Folgenachrichten.
0 s
Dein Handler beginnt, den Bericht zu erstellen.
2 s
Nach 2 Sekunden ohne Antwort, bevor Discords Frist von 3 Sekunden abläuft.
Wenn es fertig ist
Die erste Antwort ersetzt „denkt nach…“.
Innerhalb von 15 Min.
Spätere Antworten sind neue Nachrichten, in der Reihenfolge, in der du sie sendest.
Discords Frist · 3 s