mirror of
https://github.com/jaronpate/unicord.git
synced 2026-10-18 21:47:40 +00:00
Messages service, ceched promises, adding 'hydration' models
This commit is contained in:
+2
-1
@@ -3,7 +3,8 @@
|
|||||||
"module": "src/index.ts",
|
"module": "src/index.ts",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "dotenvx run -f .env -- bun run testing/demo.test.ts"
|
"test": "dotenvx run -f .env -- bun run testing/demo.test.ts",
|
||||||
|
"test:inspect": "dotenvx run -f .env -- bun --inspect testing/demo.test.ts"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/bun": "latest"
|
"@types/bun": "latest"
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
|
// Base classes
|
||||||
export { Client } from './services/client';
|
export { Client } from './services/client';
|
||||||
export { Intent } from './types/common';
|
export { Intent } from './types/common';
|
||||||
export { BaseHandler, type Handler } from './types/hander';
|
export { BaseHandler, type Handler } from './types/hander';
|
||||||
|
// Consumable types
|
||||||
export type { ClientConfig } from './types/common';
|
export type { ClientConfig } from './types/common';
|
||||||
export type { Context } from './types/context';
|
export type { Context } from './types/context';
|
||||||
|
// Consumable util classes
|
||||||
|
export { Guild } from './types/guild';
|
||||||
|
export { Role } from './types/role';
|
||||||
|
export { Member } from './types/member';
|
||||||
|
export { User } from './types/user';
|
||||||
|
export { Message } from './types/message';
|
||||||
|
export { Embed } from './types/embed';
|
||||||
|
export { Emoji } from './types/emoji';
|
||||||
+2
-2
@@ -6,7 +6,7 @@ export class API {
|
|||||||
constructor(private client: Client) {}
|
constructor(private client: Client) {}
|
||||||
|
|
||||||
async request<T = any>(method: string, path: string, data?: any): Promise<T> {
|
async request<T = any>(method: string, path: string, data?: any): Promise<T> {
|
||||||
const url = `${this.base_url}${path}`;
|
const url = new URL(path, this.base_url).toString();
|
||||||
const headers = {
|
const headers = {
|
||||||
Authorization: `Bot ${this.client.token}`,
|
Authorization: `Bot ${this.client.token}`,
|
||||||
'Accept': 'application/json',
|
'Accept': 'application/json',
|
||||||
@@ -29,7 +29,7 @@ export class API {
|
|||||||
|
|
||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
|
|
||||||
console.log('API Response:', JSON.stringify(body, null, 4));
|
// console.log('API Response:', JSON.stringify(body, null, 4));
|
||||||
|
|
||||||
return body;
|
return body;
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-15
@@ -3,15 +3,14 @@ import { exists } from "../utils";
|
|||||||
import type { API } from "./api";
|
import type { API } from "./api";
|
||||||
import type { Processor } from "./processor";
|
import type { Processor } from "./processor";
|
||||||
|
|
||||||
|
|
||||||
export class ObjectCache<T> {
|
export class ObjectCache<T> {
|
||||||
cache = new Map<string, T>();
|
cache = new Map<string, Promise<T> | T>();
|
||||||
private readonly type: string;
|
readonly type: string;
|
||||||
|
|
||||||
constructor(private api: API, processor: Processor, type: string, events: string[]) {
|
constructor(protected api: API, processor: Processor, type: string, private readonly factory: (...args: any[]) => Promise<T>, events: string[]) {
|
||||||
this.type = type;
|
this.type = type;
|
||||||
processor.events.register(events, (_context: Context, e: Record<string, any>) => {
|
processor.events.register(events, async (_context: Context, e: Record<string, any>) => {
|
||||||
this.cache.set(e.id, e as T);
|
this.cache.set(e.id, factory(e));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,23 +29,22 @@ export class ObjectCache<T> {
|
|||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
async fetch(object_id: string): Promise<T> {
|
async fetch(object_id: string, ..._args: any[]): Promise<T> {
|
||||||
return this.api.get(`${this.type}/${object_id}`).then((res) => {
|
const req = this.api.get(`/${this.type}/${object_id}`).then((data) => this.factory(data));
|
||||||
const object: T & { id: string } = res.data;
|
this.cache.set(object_id, req);
|
||||||
this.cache.set(object.id, object);
|
req.catch(() => this.cache.delete(object_id));
|
||||||
return object;
|
return await req;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
get(object_id: string): T | Promise<T> {
|
async get(object_id: string, ..._args: any[]): Promise<T> {
|
||||||
if (this.cache.has(object_id)) {
|
if (this.cache.has(object_id)) {
|
||||||
return Promise.resolve(this.cache.get(object_id)!);
|
return await Promise.resolve(this.cache.get(object_id)!);
|
||||||
} else {
|
} else {
|
||||||
return this.fetch(object_id);
|
return this.fetch(object_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
list(): Map<string, T> {
|
list(): Map<string, Promise<T> | T> {
|
||||||
return this.cache;
|
return this.cache;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-23
@@ -4,9 +4,10 @@ import { Processor } from './processor';
|
|||||||
import { Intent, type ClientConfig } from '../types/common';
|
import { Intent, type ClientConfig } from '../types/common';
|
||||||
import { exists, isNil } from '../utils/index';
|
import { exists, isNil } from '../utils/index';
|
||||||
import type { Handler } from '../types/hander';
|
import type { Handler } from '../types/hander';
|
||||||
import { Message } from '../types/message';
|
import { DiscordMessage, Message } from '../types/message';
|
||||||
import { Guilds } from './guilds';
|
import { Guilds } from './guilds';
|
||||||
import { Users } from './users';
|
import { Users } from './users';
|
||||||
|
import { Messages } from './messages';
|
||||||
|
|
||||||
export class Client {
|
export class Client {
|
||||||
readonly token: string;
|
readonly token: string;
|
||||||
@@ -14,11 +15,12 @@ export class Client {
|
|||||||
readonly intents: Intent[] = [Intent.DEFAULT];
|
readonly intents: Intent[] = [Intent.DEFAULT];
|
||||||
prefix: string;
|
prefix: string;
|
||||||
// Internal services
|
// Internal services
|
||||||
protected _api: API;
|
protected api: API;
|
||||||
protected _processor: Processor;
|
protected processor: Processor;
|
||||||
protected _gateway: Gateway;
|
protected gateway: Gateway;
|
||||||
guilds: Guilds;
|
guilds: Guilds;
|
||||||
users: Users;
|
users: Users;
|
||||||
|
messages: Messages
|
||||||
|
|
||||||
constructor(config: ClientConfig) {
|
constructor(config: ClientConfig) {
|
||||||
// Validate the configuration
|
// Validate the configuration
|
||||||
@@ -29,23 +31,12 @@ export class Client {
|
|||||||
this.intents = config.intents ?? this.intents;
|
this.intents = config.intents ?? this.intents;
|
||||||
this.prefix = config.prefix ?? '!';
|
this.prefix = config.prefix ?? '!';
|
||||||
// Initialize internal services
|
// Initialize internal services
|
||||||
this._api = new API(this);
|
this.api = new API(this);
|
||||||
this._processor = new Processor(this);
|
this.processor = new Processor(this, this.api);
|
||||||
this._gateway = new Gateway(this, this.processor, this.api);
|
this.gateway = new Gateway(this, this.processor, this.api);
|
||||||
this.guilds = new Guilds(this.api, this.processor);
|
this.guilds = new Guilds(this.api, this.processor);
|
||||||
this.users = new Users(this.api, this.processor);
|
this.users = new Users(this.api, this.processor);
|
||||||
}
|
this.messages = new Messages(this, this.api, this.processor);
|
||||||
|
|
||||||
private get api() {
|
|
||||||
return this._api;
|
|
||||||
}
|
|
||||||
|
|
||||||
private get gateway() {
|
|
||||||
return this._gateway;
|
|
||||||
}
|
|
||||||
|
|
||||||
private get processor() {
|
|
||||||
return this._processor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static validateConfig(config: ClientConfig) {
|
private static validateConfig(config: ClientConfig) {
|
||||||
@@ -79,13 +70,19 @@ export class Client {
|
|||||||
message = new Message().setContent(message);
|
message = new Message().setContent(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
return Message.fromAPIResponse(await this.api.post(`/channels/${channel_id}/messages`, message.toJSON()));
|
return Message.hydrate(DiscordMessage.fromAPIResponse(await this.api.post(`/channels/${channel_id}/messages`, message.toJSON())), this, this.api);
|
||||||
}
|
}
|
||||||
|
|
||||||
chatCommands = {
|
chatCommands = {
|
||||||
register: (name: string | string[], handler: Handler) => this.processor.commands.register(name, handler),
|
register: (name: string | string[], handler: Handler) => this.processor.chat_commands.register(name, handler),
|
||||||
unregister: (name: string | string[]) => this.processor.commands.unregister(name),
|
unregister: (name: string | string[]) => this.processor.chat_commands.unregister(name),
|
||||||
has: (name: string) => this.processor.commands.has(name)
|
has: (name: string) => this.processor.chat_commands.has(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
slashCommands = {
|
||||||
|
register: (name: string, handler: Handler) => this.processor.slash_commands.register(name, handler),
|
||||||
|
unregister: (name: string) => this.processor.slash_commands.unregister(name),
|
||||||
|
has: (name: string) => this.processor.slash_commands.has(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
connect = () => this.gateway.connect();
|
connect = () => this.gateway.connect();
|
||||||
|
|||||||
+13
-11
@@ -5,8 +5,8 @@ import { exists, isNil, isObject, log } from "../utils";
|
|||||||
import type { API } from "./api";
|
import type { API } from "./api";
|
||||||
import type { Processor } from './processor';
|
import type { Processor } from './processor';
|
||||||
import { Context } from '../types/context';
|
import { Context } from '../types/context';
|
||||||
import { Message } from '../types/message';
|
import { DiscordMessage, Message } from '../types/message';
|
||||||
import { User } from '../types/user';
|
import { DiscordUser, User } from '../types/user';
|
||||||
|
|
||||||
export class Gateway {
|
export class Gateway {
|
||||||
private socket: WebSocket | null = null;
|
private socket: WebSocket | null = null;
|
||||||
@@ -22,7 +22,7 @@ export class Gateway {
|
|||||||
log('Connected to gateway');
|
log('Connected to gateway');
|
||||||
}
|
}
|
||||||
|
|
||||||
private onMessage = (packet: Data) => {
|
private onMessage = async (packet: Data) => {
|
||||||
// console.log(packet);
|
// console.log(packet);
|
||||||
// Allocate a variable to store the parsed payload
|
// Allocate a variable to store the parsed payload
|
||||||
let data: Payload | null = null;
|
let data: Payload | null = null;
|
||||||
@@ -44,7 +44,7 @@ export class Gateway {
|
|||||||
const code = data.op;
|
const code = data.op;
|
||||||
if (code === 0) {
|
if (code === 0) {
|
||||||
// Event received
|
// Event received
|
||||||
this.parseEvent(data);
|
await this.parseEvent(data);
|
||||||
} else if (code === 1) {
|
} else if (code === 1) {
|
||||||
// Heartbeat requested
|
// Heartbeat requested
|
||||||
this.send({ op: 1, d: this.sequence });
|
this.send({ op: 1, d: this.sequence });
|
||||||
@@ -111,7 +111,7 @@ export class Gateway {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
private parseEvent(payload: Payload) {
|
private async parseEvent(payload: Payload) {
|
||||||
if (isNil(payload.t)) {
|
if (isNil(payload.t)) {
|
||||||
throw new Error('Event name is required');
|
throw new Error('Event name is required');
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ export class Gateway {
|
|||||||
} else if (event_name === 'INTERACTION_CREATE') {
|
} else if (event_name === 'INTERACTION_CREATE') {
|
||||||
// this.handleInteractionCreate(payload);
|
// this.handleInteractionCreate(payload);
|
||||||
} else if (event_name === 'MESSAGE_CREATE') {
|
} else if (event_name === 'MESSAGE_CREATE') {
|
||||||
this.handleMessageCreate(payload as Payload);
|
await this.handleMessageCreate(payload as Payload);
|
||||||
} else if (event_name === 'MESSAGE_UPDATE') {
|
} else if (event_name === 'MESSAGE_UPDATE') {
|
||||||
// this.handleMessageCreate(payload);
|
// this.handleMessageCreate(payload);
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,8 @@ export class Gateway {
|
|||||||
|
|
||||||
if (['MESSAGE_CREATE', 'MESSAGE_UPDATE'].includes(event_name)) {
|
if (['MESSAGE_CREATE', 'MESSAGE_UPDATE'].includes(event_name)) {
|
||||||
// If the event is a message event, create a message object
|
// If the event is a message event, create a message object
|
||||||
const message = Message.fromAPIResponse(event_data);
|
const discord_message = DiscordMessage.fromAPIResponse(event_data);
|
||||||
|
const message = await Message.hydrate(discord_message, this.client, this.api);
|
||||||
// And then generate the context
|
// And then generate the context
|
||||||
context = new Context(this.client, this.api, message);
|
context = new Context(this.client, this.api, message);
|
||||||
}
|
}
|
||||||
@@ -164,7 +165,7 @@ export class Gateway {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Extract the author
|
// Extract the author
|
||||||
const author = User.fromAPIResponse(payload.d.author);
|
const author = User.hydrate(DiscordUser.fromAPIResponse(payload.d.author));
|
||||||
// Store the author in the cache
|
// Store the author in the cache
|
||||||
this.client.users.set(author.id, author);
|
this.client.users.set(author.id, author);
|
||||||
// Extract the content
|
// Extract the content
|
||||||
@@ -185,14 +186,15 @@ export class Gateway {
|
|||||||
// Extract the command name
|
// Extract the command name
|
||||||
// TODO: Case insensitive config?
|
// TODO: Case insensitive config?
|
||||||
const command = args.shift()!;
|
const command = args.shift()!;
|
||||||
|
console.log('payload.d', payload.d)
|
||||||
// Create a new message object from the payload
|
// Create a new message object from the payload
|
||||||
const message = Message.fromAPIResponse(payload.d);
|
const message = await Message.hydrate(DiscordMessage.fromAPIResponse(payload.d), this.client, this.api);
|
||||||
// Generate context
|
// Generate context
|
||||||
const context = new Context(this.client, this.api, message);
|
const context = new Context(this.client, this.api, message);
|
||||||
// Check if command exists
|
// Check if command exists
|
||||||
if (this.processor.commands.has(command)) {
|
if (this.processor.chat_commands.has(command)) {
|
||||||
// Execute the handler
|
// Execute the handler
|
||||||
this.processor.commands.execute(command, context, args);
|
this.processor.chat_commands.execute(command, context, args);
|
||||||
} else {
|
} else {
|
||||||
// TODO: Custom unknown command handler
|
// TODO: Custom unknown command handler
|
||||||
context.reply(`Unknown command: ${command}`);
|
context.reply(`Unknown command: ${command}`);
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import type { Guild } from "../types/guild";
|
import { Guild } from "../types/guild";
|
||||||
import type { API } from "./api";
|
import type { API } from "./api";
|
||||||
import { ObjectCache } from "./cache";
|
import { ObjectCache } from "./cache";
|
||||||
import type { Processor } from "./processor";
|
import type { Processor } from "./processor";
|
||||||
|
|
||||||
export class Guilds extends ObjectCache<Guild> {
|
export class Guilds extends ObjectCache<Guild> {
|
||||||
constructor (api: API, processor: Processor) {
|
constructor (api: API, processor: Processor) {
|
||||||
super(api, processor, 'guilds', ['GUILD_CREATE', 'GUILD_UPDATE']);
|
super(api, processor, 'guilds', Guild.factory, ['GUILD_CREATE', 'GUILD_UPDATE']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { Message } from "../types/message";
|
||||||
|
import type { API } from "./api";
|
||||||
|
import { ObjectCache } from "./cache";
|
||||||
|
import type { Client } from "./client";
|
||||||
|
import type { Processor } from "./processor";
|
||||||
|
|
||||||
|
export class Messages extends ObjectCache<Message> {
|
||||||
|
constructor (protected client: Client, api: API, processor: Processor) {
|
||||||
|
super(api, processor, 'message', (data) => Message.factory(data, client, api), ['MESSAGE_CREATE', 'MESSAGE_UPDATE']);
|
||||||
|
}
|
||||||
|
|
||||||
|
async fetch(channel_id: string, message_id: string, resolveReference: boolean = true): Promise<Message> {
|
||||||
|
const req = this.api.get(`/channels/${channel_id}/messages/${message_id}`).then((data) => Message.factory(data, this.client, this.api, undefined, resolveReference));
|
||||||
|
this.cache.set(message_id, req);
|
||||||
|
req.catch(() => this.cache.delete(message_id));
|
||||||
|
return await req;
|
||||||
|
}
|
||||||
|
|
||||||
|
async get(channel_id: string, message_id: string, resolveReference: boolean = true): Promise<Message> {
|
||||||
|
if (this.cache.has(message_id)) {
|
||||||
|
return await Promise.resolve(this.cache.get(message_id)!);
|
||||||
|
} else {
|
||||||
|
return this.fetch(channel_id, message_id, resolveReference);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
-14
@@ -2,15 +2,17 @@ import type { Client } from "./client";
|
|||||||
import type { Context } from "../types/context";
|
import type { Context } from "../types/context";
|
||||||
import { HandlerType, type EventPayload, type Payload } from "../types/common";
|
import { HandlerType, type EventPayload, type Payload } from "../types/common";
|
||||||
import { BaseHandler, type Handler } from "../types/hander";
|
import { BaseHandler, type Handler } from "../types/hander";
|
||||||
|
import type { API } from "./api";
|
||||||
|
|
||||||
export class Processor {
|
export class Processor {
|
||||||
private handlers = {
|
private handlers = {
|
||||||
[HandlerType.Events]: new Map<string, Handler[]>(),
|
[HandlerType.Events]: new Map<string, Handler[]>(),
|
||||||
[HandlerType.Commands]: new Map<string, Handler[]>(),
|
[HandlerType.ChatCommands]: new Map<string, Handler[]>(),
|
||||||
|
[HandlerType.SlashCommands]: new Map<string, Handler[]>(),
|
||||||
[HandlerType.Interactions]: new Map<string, Handler[]>()
|
[HandlerType.Interactions]: new Map<string, Handler[]>()
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(private client: Client) {};
|
constructor(private client: Client, private api: API) {};
|
||||||
|
|
||||||
public register(type: HandlerType, event: string | string[], handler: Handler) {
|
public register(type: HandlerType, event: string | string[], handler: Handler) {
|
||||||
// Normalize events into an array
|
// Normalize events into an array
|
||||||
@@ -46,18 +48,18 @@ export class Processor {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
public execute(type: HandlerType.Events, event: string, context: Context | null, payload: EventPayload): void
|
public async execute(type: HandlerType.Events, event: string, context: Context | null, payload: EventPayload): Promise<void>
|
||||||
public execute(type: Omit<HandlerType, HandlerType.Events>, event: string, context: Context, args: any[]): void
|
public async execute(type: Omit<HandlerType, HandlerType.Events>, event: string, context: Context, args: any[]): Promise<void>
|
||||||
public execute(type: HandlerType, event: string, context: Context | null, argsOrPayload: any[] | EventPayload) {
|
public async execute(type: HandlerType, event: string, context: Context | null, argsOrPayload: any[] | EventPayload) {
|
||||||
const handlers = this.handlers[type].get(event);
|
const handlers = this.handlers[type].get(event);
|
||||||
|
|
||||||
if (handlers) {
|
if (handlers) {
|
||||||
for (const handler of handlers) {
|
for (const handler of handlers) {
|
||||||
if (handler instanceof BaseHandler) {
|
if (handler instanceof BaseHandler) {
|
||||||
handler.execute(context, argsOrPayload);
|
await Promise.resolve(handler.execute(context, argsOrPayload));
|
||||||
} else {
|
} else {
|
||||||
// TODO: Fix ts error
|
// TODO: Fix ts error
|
||||||
handler(context, argsOrPayload);
|
await Promise.resolve(handler(context, argsOrPayload))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,21 +68,28 @@ export class Processor {
|
|||||||
[HandlerType.Events] = {
|
[HandlerType.Events] = {
|
||||||
register: (event: string | string[], handler: Handler) => this.register(HandlerType.Events, event, handler),
|
register: (event: string | string[], handler: Handler) => this.register(HandlerType.Events, event, handler),
|
||||||
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.Events, event, handler),
|
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.Events, event, handler),
|
||||||
execute: (event: string, context: Context | null, payload: EventPayload) => this.execute(HandlerType.Events, event, context, payload),
|
execute: async (event: string, context: Context | null, payload: EventPayload) => this.execute(HandlerType.Events, event, context, payload),
|
||||||
has: (event: string) => this.handlers[HandlerType.Events].has(event) && this.handlers[HandlerType.Events].get(event)?.length! > 0
|
has: (event: string) => this.handlers[HandlerType.Events].has(event) && this.handlers[HandlerType.Events].get(event)?.length! > 0
|
||||||
};
|
};
|
||||||
|
|
||||||
[HandlerType.Commands] = {
|
[HandlerType.ChatCommands] = {
|
||||||
register: (event: string | string[], handler: Handler) => this.register(HandlerType.Commands, event, handler),
|
register: (event: string | string[], handler: Handler) => this.register(HandlerType.ChatCommands, event, handler),
|
||||||
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.Commands, event, handler),
|
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.ChatCommands, event, handler),
|
||||||
execute: (event: string, context: Context, args: any[]) => this.execute(HandlerType.Commands, event, context, args),
|
execute: async (event: string, context: Context, args: any[]) => this.execute(HandlerType.ChatCommands, event, context, args),
|
||||||
has: (event: string) => this.handlers[HandlerType.Commands].has(event) ?? this.handlers[HandlerType.Commands].get(event)?.length! > 0
|
has: (event: string) => this.handlers[HandlerType.ChatCommands].has(event) ?? this.handlers[HandlerType.ChatCommands].get(event)?.length! > 0
|
||||||
|
};
|
||||||
|
|
||||||
|
[HandlerType.SlashCommands] = {
|
||||||
|
register: (event: string | string[], handler: Handler) => this.register(HandlerType.SlashCommands, event, handler),
|
||||||
|
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.SlashCommands, event, handler),
|
||||||
|
execute: async (event: string, context: Context, args: any[]) => this.execute(HandlerType.SlashCommands, event, context, args),
|
||||||
|
has: (event: string) => this.handlers[HandlerType.SlashCommands].has(event) ?? this.handlers[HandlerType.SlashCommands].get(event)?.length! > 0
|
||||||
};
|
};
|
||||||
|
|
||||||
[HandlerType.Interactions] = {
|
[HandlerType.Interactions] = {
|
||||||
register: (event: string | string[], handler: Handler) => this.register(HandlerType.Interactions, event, handler),
|
register: (event: string | string[], handler: Handler) => this.register(HandlerType.Interactions, event, handler),
|
||||||
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.Interactions, event, handler),
|
unregister: (event: string | string[], handler?: Handler) => this.unregister(HandlerType.Interactions, event, handler),
|
||||||
execute: (event: string, context: Context, args: any[]) => this.execute(HandlerType.Interactions, event, context, args),
|
execute: async (event: string, context: Context, args: any[]) => this.execute(HandlerType.Interactions, event, context, args),
|
||||||
has: (event: string) => this.handlers[HandlerType.Interactions].has(event) ?? this.handlers[HandlerType.Interactions].get(event)?.length! > 0
|
has: (event: string) => this.handlers[HandlerType.Interactions].has(event) ?? this.handlers[HandlerType.Interactions].get(event)?.length! > 0
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -10,7 +10,8 @@ export type ClientConfig = {
|
|||||||
}
|
}
|
||||||
export enum HandlerType {
|
export enum HandlerType {
|
||||||
Events = 'events',
|
Events = 'events',
|
||||||
Commands = 'commands',
|
ChatCommands = 'chat_commands',
|
||||||
|
SlashCommands = 'slash_commands',
|
||||||
Interactions = 'interactions'
|
Interactions = 'interactions'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+16
-31
@@ -1,7 +1,7 @@
|
|||||||
import type { API } from "../services/api";
|
import type { API } from "../services/api";
|
||||||
import type { Client } from "../services/client";
|
import type { Client } from "../services/client";
|
||||||
import { isNil } from "../utils";
|
import { isNil } from "../utils";
|
||||||
import { Message } from "./message";
|
import { DiscordMessage, Message } from "./message";
|
||||||
/**
|
/**
|
||||||
* Represents the context of a message in a Discord channel.
|
* Represents the context of a message in a Discord channel.
|
||||||
* Provides methods to interact with the message and the channel it was sent in.
|
* Provides methods to interact with the message and the channel it was sent in.
|
||||||
@@ -26,39 +26,27 @@ export class Context {
|
|||||||
channel_id: string;
|
channel_id: string;
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
|
|
||||||
constructor(private client: Client, private api: API, private _message: Message) {
|
constructor(private client: Client, private api: API, public message: Message) {
|
||||||
if (isNil(_message.id)) {
|
console.log('Context created: ', );
|
||||||
|
if (isNil(message.id)) {
|
||||||
throw new Error('Message ID is required to create a context');
|
throw new Error('Message ID is required to create a context');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isNil(_message.channel_id)) {
|
if (isNil(message.channel_id)) {
|
||||||
throw new Error('Channel ID is required to create a context');
|
throw new Error('Channel ID is required to create a context');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.client = client;
|
this.client = client;
|
||||||
this.message_id = _message.id;
|
this.message_id = message.id;
|
||||||
this.channel_id = _message.channel_id;
|
this.channel_id = message.channel_id;
|
||||||
this.guild_id = _message.guild_id;
|
this.guild_id = message.guild_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get author() {
|
// get author() {
|
||||||
// return this.client.users.get(this.author_id);
|
// return this.client.users.get(this.author_id);
|
||||||
// };
|
// };
|
||||||
|
|
||||||
get message(): Message & { getReference: () => Promise<Message | null> } {
|
async fetchGuild() {
|
||||||
return Object.assign(this._message, {
|
|
||||||
getReference: async () => {
|
|
||||||
const reference = this._message.message_reference;
|
|
||||||
if (isNil(reference)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Message.fromAPIResponse(await this.api.get(`/channels/${reference.channel_id}/messages/${reference.message_id}`));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fetchGuild() {
|
|
||||||
if (isNil(this.guild_id)) {
|
if (isNil(this.guild_id)) {
|
||||||
return Promise.resolve(null);
|
return Promise.resolve(null);
|
||||||
}
|
}
|
||||||
@@ -78,11 +66,7 @@ export class Context {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (reference) {
|
if (reference) {
|
||||||
message.message_reference = {
|
message.setReference(this.message)
|
||||||
message_id: this.message_id,
|
|
||||||
channel_id: this.channel_id,
|
|
||||||
guild_id: this.guild_id
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.client.sendMessage(this.channel_id, message);
|
return this.client.sendMessage(this.channel_id, message);
|
||||||
@@ -108,7 +92,7 @@ export class Context {
|
|||||||
* @param {string} [message_id] - The ID of the message to delete. If not provided, the message ID of this context will be used.
|
* @param {string} [message_id] - The ID of the message to delete. If not provided, the message ID of this context will be used.
|
||||||
* @returns {Promise<void>} A promise that resolves when the message is deleted.
|
* @returns {Promise<void>} A promise that resolves when the message is deleted.
|
||||||
*/
|
*/
|
||||||
public delete = (message_id?: string) => {
|
public deleteMessage = (message_id: string) => {
|
||||||
return this.api.delete(`/channels/${this.channel_id}/messages/${message_id ?? this.message_id}`);
|
return this.api.delete(`/channels/${this.channel_id}/messages/${message_id ?? this.message_id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -119,10 +103,11 @@ export class Context {
|
|||||||
* @param {Message | string} message - The updated message content.
|
* @param {Message | string} message - The updated message content.
|
||||||
* @returns {Promise<Message>} The updated message.
|
* @returns {Promise<Message>} The updated message.
|
||||||
*/
|
*/
|
||||||
public edit = async (message: Message | string) => {
|
public async editMessage (message: Message, content?: string) {
|
||||||
if (typeof message === 'string') {
|
const clone = new Message(message);
|
||||||
message = new Message().setContent(message);
|
if (content) {
|
||||||
|
clone.setContent(content);
|
||||||
}
|
}
|
||||||
return Message.fromAPIResponse(await this.api.patch(`/channels/${this.channel_id}/messages/${this.message_id}`, message));
|
return Message.hydrate(DiscordMessage.fromAPIResponse(await this.api.patch(`/channels/${clone.channel_id}/messages/${clone.id}`, clone)), this.client, this.api);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
+43
-2
@@ -4,6 +4,47 @@ import { Member } from "./member";
|
|||||||
import { Role } from "./role";
|
import { Role } from "./role";
|
||||||
|
|
||||||
export class Guild {
|
export class Guild {
|
||||||
|
id: string;
|
||||||
|
name: string;
|
||||||
|
description: string | null;
|
||||||
|
icon: string | null;
|
||||||
|
banner: string | null;
|
||||||
|
owner_id: string;
|
||||||
|
// emojis: Emoji[];
|
||||||
|
// roles: Role[];
|
||||||
|
|
||||||
|
constructor(data: Guild) {
|
||||||
|
this.id = data.id;
|
||||||
|
this.name = data.name;
|
||||||
|
this.description = data.description;
|
||||||
|
this.icon = data.icon;
|
||||||
|
this.banner = data.banner;
|
||||||
|
this.owner_id = data.owner_id;
|
||||||
|
// this.emojis = data.emojis;
|
||||||
|
// this.roles = data.roles;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async factory(data: any) {
|
||||||
|
return await Guild.hydrate(DiscordGuild.fromAPIResponse(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async hydrate(data: DiscordGuild) {
|
||||||
|
return new Guild({
|
||||||
|
id: data.id,
|
||||||
|
name: data.name,
|
||||||
|
description: data.description,
|
||||||
|
icon: data.icon,
|
||||||
|
banner: data.banner,
|
||||||
|
owner_id: data.owner_id,
|
||||||
|
// emojis: data.emojis,
|
||||||
|
// roles: data.roles,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DiscordGuild {
|
||||||
system_channel_id: string | null;
|
system_channel_id: string | null;
|
||||||
premium_progress_bar_enabled: boolean;
|
premium_progress_bar_enabled: boolean;
|
||||||
region: string;
|
region: string;
|
||||||
@@ -124,7 +165,7 @@ export class Guild {
|
|||||||
this.explicit_content_filter = data.explicit_content_filter;
|
this.explicit_content_filter = data.explicit_content_filter;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromAPIResponse(data: any): Guild {
|
static fromAPIResponse(data: any): DiscordGuild {
|
||||||
return new Guild(data);
|
return new DiscordGuild(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+3
-3
@@ -4,11 +4,11 @@ import type { Context } from "./context";
|
|||||||
export class BaseHandler {
|
export class BaseHandler {
|
||||||
constructor() {};
|
constructor() {};
|
||||||
|
|
||||||
public execute(context: Context | null, args: any[]) {};
|
public async execute(context: Context | null, args: any[]) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CommandHandlerFunction = (context: Context, args: any[]) => void;
|
export type CommandHandlerFunction = (context: Context, args: any[]) => Promise<void> | void;
|
||||||
export type EventHandlerFunction = (context: Context | null, payload: EventPayload) => void;
|
export type EventHandlerFunction = (context: Context | null, payload: EventPayload) => Promise<void> | void;
|
||||||
|
|
||||||
export type HandlerFunction = CommandHandlerFunction | EventHandlerFunction;
|
export type HandlerFunction = CommandHandlerFunction | EventHandlerFunction;
|
||||||
export type Handler = CommandHandlerFunction | EventHandlerFunction | BaseHandler;
|
export type Handler = CommandHandlerFunction | EventHandlerFunction | BaseHandler;
|
||||||
|
|||||||
+163
-32
@@ -1,6 +1,8 @@
|
|||||||
|
import type { API } from '../services/api';
|
||||||
|
import type { Client } from '../services/client';
|
||||||
import { isNil } from '../utils';
|
import { isNil } from '../utils';
|
||||||
import { Embed } from './embed';
|
import { Embed } from './embed';
|
||||||
import { User } from './user';
|
import { DiscordUser, User } from './user';
|
||||||
|
|
||||||
export type Component = Partial<Button | SelectMenu> & {
|
export type Component = Partial<Button | SelectMenu> & {
|
||||||
type: ComponentType;
|
type: ComponentType;
|
||||||
@@ -84,36 +86,42 @@ export class Message {
|
|||||||
author?: User;
|
author?: User;
|
||||||
channel_id?: string;
|
channel_id?: string;
|
||||||
guild_id?: string;
|
guild_id?: string;
|
||||||
public content?: string;
|
public content: string;
|
||||||
public embeds: Embed[] = [];
|
public embeds: Embed[] = [];
|
||||||
public components: Component[] = [];
|
public components: Component[] = [];
|
||||||
public message_reference?: {
|
public reference?: Message;
|
||||||
type?: number;
|
timestamp: Date;
|
||||||
message_id: string;
|
|
||||||
channel_id: string;
|
|
||||||
guild_id?: string;
|
|
||||||
fail_if_not_exists?: boolean;
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor(data?: Partial<Message>) {
|
constructor(data?: Partial<Message>) {
|
||||||
if (data) {
|
this.id = data?.id;
|
||||||
this.id = data.id;
|
this.author = data?.author;
|
||||||
this.author = User.fromAPIResponse(data.author);
|
this.channel_id = data?.channel_id;
|
||||||
this.channel_id = data.channel_id;
|
this.guild_id = data?.guild_id;
|
||||||
this.guild_id = data.guild_id;
|
this.content = data?.content ?? '';
|
||||||
this.content = data.content;
|
this.reference = data?.reference;
|
||||||
this.message_reference = data.message_reference;
|
this.timestamp = data?.timestamp ?? new Date();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static fromAPIResponse = (data: any) => {
|
public static factory = async (data: any, client: Client, api: API, resolveReference: boolean = true): Promise<Message> => {
|
||||||
|
return Message.hydrate(DiscordMessage.fromAPIResponse(data), client, api, resolveReference);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static hydrate = async (discord_message: DiscordMessage, client: Client, api: API, resolveReference: boolean = true): Promise<Message> => {
|
||||||
|
let reference: Message | undefined;
|
||||||
|
|
||||||
|
if (discord_message.message_reference && resolveReference) {
|
||||||
|
const { channel_id, message_id } = discord_message.message_reference;
|
||||||
|
reference = await client.messages.get(channel_id, message_id, false);
|
||||||
|
}
|
||||||
|
|
||||||
return new Message({
|
return new Message({
|
||||||
id: data.id,
|
id: discord_message.id,
|
||||||
author: data.author,
|
author: User.hydrate(discord_message.author),
|
||||||
channel_id: data.channel_id,
|
channel_id: discord_message.channel_id,
|
||||||
guild_id: data.guild_id,
|
guild_id: discord_message?.guild_id,
|
||||||
content: data.content,
|
content: discord_message.content,
|
||||||
message_reference: data.message_reference
|
reference,
|
||||||
|
timestamp: new Date(discord_message.timestamp)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -157,17 +165,20 @@ export class Message {
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
public setReference = (message: Partial<Message>) => {
|
public setReference = (message: Message | Partial<Message>) => {
|
||||||
if (isNil(message.id) || isNil(message.channel_id)) {
|
if (isNil(message.id) || isNil(message.channel_id)) {
|
||||||
throw new Error('Message ID and Channel ID are required');
|
throw new Error('Message ID and Channel ID are required');
|
||||||
}
|
}
|
||||||
|
|
||||||
this.message_reference = {
|
let ref: Message;
|
||||||
message_id: message.id,
|
|
||||||
channel_id: message.channel_id,
|
if (!(message instanceof Message)) {
|
||||||
guild_id: message.guild_id,
|
ref = new Message(message);
|
||||||
fail_if_not_exists: false
|
} else {
|
||||||
};
|
ref = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.reference = ref;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -176,7 +187,127 @@ export class Message {
|
|||||||
content: this.content,
|
content: this.content,
|
||||||
embeds: this.embeds,
|
embeds: this.embeds,
|
||||||
components: this.components,
|
components: this.components,
|
||||||
message_reference: this.message_reference
|
message_reference: {
|
||||||
|
message_id: this.reference?.id,
|
||||||
|
channel_id: this.reference?.channel_id,
|
||||||
|
guild_id: this.reference?.guild_id,
|
||||||
|
fail_if_not_exists: false
|
||||||
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Raw API Class
|
||||||
|
export class DiscordMessage {
|
||||||
|
id: string;
|
||||||
|
channel_id: string;
|
||||||
|
guild_id?: string;
|
||||||
|
author: DiscordUser;
|
||||||
|
// member?: DiscordGuildMember;
|
||||||
|
content: string;
|
||||||
|
// ISO8601 timestamp
|
||||||
|
timestamp: string;
|
||||||
|
edited_timestamp: string | null;
|
||||||
|
tts: boolean;
|
||||||
|
mention_everyone: boolean;
|
||||||
|
mentions: DiscordUser[];
|
||||||
|
mention_roles: string[];
|
||||||
|
mention_channels?: { id: string; guild_id: string; type: number; name: string }[];
|
||||||
|
attachments: { id: string; filename: string; url: string; proxy_url: string; size: number }[];
|
||||||
|
// embeds: DiscordEmbed[];
|
||||||
|
reactions?: { count: number; me: boolean; emoji: Emoji }[];
|
||||||
|
nonce?: string | number;
|
||||||
|
pinned: boolean;
|
||||||
|
webhook_id?: string;
|
||||||
|
type: number;
|
||||||
|
activity?: { type: number; party_id?: string };
|
||||||
|
application?: { id: string; cover_image?: string; description: string; icon?: string; name: string };
|
||||||
|
application_id?: string;
|
||||||
|
message_reference?: { message_id: string; channel_id: string; guild_id?: string; fail_if_not_exists?: boolean };
|
||||||
|
flags?: number;
|
||||||
|
referenced_message?: DiscordMessage | null;
|
||||||
|
interaction?: { id: string; type: number; name: string; user: DiscordUser };
|
||||||
|
thread?: { id: string; name: string; type: number };
|
||||||
|
components?: any[];
|
||||||
|
sticker_items?: { id: string; name: string; format_type: number }[];
|
||||||
|
stickers?: {
|
||||||
|
id: string;
|
||||||
|
pack_id?: string;
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
tags: string;
|
||||||
|
asset: string;
|
||||||
|
preview_asset?: string;
|
||||||
|
format_type: number;
|
||||||
|
}[];
|
||||||
|
|
||||||
|
constructor(data: DiscordMessage) {
|
||||||
|
this.id = data.id;
|
||||||
|
this.channel_id = data.channel_id;
|
||||||
|
this.guild_id = data.guild_id;
|
||||||
|
this.author = data.author;
|
||||||
|
// this.member = data.member;
|
||||||
|
this.content = data.content;
|
||||||
|
this.timestamp = data.timestamp;
|
||||||
|
this.edited_timestamp = data.edited_timestamp;
|
||||||
|
this.tts = data.tts;
|
||||||
|
this.mention_everyone = data.mention_everyone;
|
||||||
|
this.mentions = data.mentions;
|
||||||
|
this.mention_roles = data.mention_roles;
|
||||||
|
this.mention_channels = data.mention_channels;
|
||||||
|
this.attachments = data.attachments;
|
||||||
|
// this.embeds = data.embeds;
|
||||||
|
this.reactions = data.reactions;
|
||||||
|
this.nonce = data.nonce;
|
||||||
|
this.pinned = data.pinned;
|
||||||
|
this.webhook_id = data.webhook_id;
|
||||||
|
this.type = data.type;
|
||||||
|
this.activity = data.activity;
|
||||||
|
this.application = data.application;
|
||||||
|
this.application_id = data.application_id;
|
||||||
|
this.message_reference = data.message_reference;
|
||||||
|
this.flags = data.flags;
|
||||||
|
this.referenced_message = data.referenced_message;
|
||||||
|
this.interaction = data.interaction;
|
||||||
|
this.thread = data.thread;
|
||||||
|
this.components = data.components;
|
||||||
|
this.sticker_items = data.sticker_items;
|
||||||
|
this.stickers = data.stickers;
|
||||||
|
}
|
||||||
|
|
||||||
|
static fromAPIResponse(data: any): DiscordMessage {
|
||||||
|
return new DiscordMessage({
|
||||||
|
id: data.id,
|
||||||
|
channel_id: data.channel_id,
|
||||||
|
guild_id: data.guild_id,
|
||||||
|
author: data.author,
|
||||||
|
// member: data.member,
|
||||||
|
content: data.content,
|
||||||
|
timestamp: data.timestamp,
|
||||||
|
edited_timestamp: data.edited_timestamp,
|
||||||
|
tts: data.tts,
|
||||||
|
mention_everyone: data.mention_everyone,
|
||||||
|
mentions: data.mentions,
|
||||||
|
mention_roles: data.mention_roles,
|
||||||
|
mention_channels: data.mention_channels,
|
||||||
|
attachments: data.attachments,
|
||||||
|
// embeds: data.embeds,
|
||||||
|
reactions: data.reactions,
|
||||||
|
nonce: data.nonce,
|
||||||
|
pinned: data.pinned,
|
||||||
|
webhook_id: data.webhook_id,
|
||||||
|
type: data.type,
|
||||||
|
activity: data.activity,
|
||||||
|
application: data.application,
|
||||||
|
application_id: data.application_id,
|
||||||
|
message_reference: data.message_reference,
|
||||||
|
flags: data.flags,
|
||||||
|
referenced_message: data.referenced_message,
|
||||||
|
interaction: data.interaction,
|
||||||
|
thread: data.thread,
|
||||||
|
components: data.components,
|
||||||
|
sticker_items: data.sticker_items,
|
||||||
|
stickers: data.stickers
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
+59
-4
@@ -1,3 +1,58 @@
|
|||||||
|
export class User {
|
||||||
|
id: string;
|
||||||
|
username: string;
|
||||||
|
discriminator: string;
|
||||||
|
display_name: string;
|
||||||
|
avatar: string;
|
||||||
|
bot?: boolean;
|
||||||
|
system?: boolean;
|
||||||
|
mfa_enabled?: boolean;
|
||||||
|
banner?: string;
|
||||||
|
accent_color?: number;
|
||||||
|
locale?: string;
|
||||||
|
verified?: boolean;
|
||||||
|
email?: string;
|
||||||
|
// TODO: Add the rest of the properties
|
||||||
|
|
||||||
|
constructor(data: Partial<User> & { id: string; username: string; discriminator: string; display_name: string; avatar: string }) {
|
||||||
|
this.id = data.id;
|
||||||
|
this.username = data.username;
|
||||||
|
this.discriminator = data.discriminator;
|
||||||
|
this.display_name = data.display_name;
|
||||||
|
this.avatar = data.avatar;
|
||||||
|
this.bot = data.bot;
|
||||||
|
this.system = data.system;
|
||||||
|
this.mfa_enabled = data.mfa_enabled;
|
||||||
|
this.banner = data.banner;
|
||||||
|
this.accent_color = data.accent_color;
|
||||||
|
this.locale = data.locale;
|
||||||
|
this.verified = data.verified;
|
||||||
|
this.email = data.email;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async factory(data: DiscordUser) {
|
||||||
|
return User.hydrate(DiscordUser.fromAPIResponse(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static hydrate(data: DiscordUser) {
|
||||||
|
return new User({
|
||||||
|
id: data.id,
|
||||||
|
username: data.username,
|
||||||
|
discriminator: data.discriminator,
|
||||||
|
display_name: data.global_name,
|
||||||
|
avatar: data.avatar,
|
||||||
|
bot: data.bot,
|
||||||
|
system: data.system,
|
||||||
|
mfa_enabled: data.mfa_enabled,
|
||||||
|
banner: data.banner,
|
||||||
|
accent_color: data.accent_color,
|
||||||
|
locale: data.locale,
|
||||||
|
verified: data.verified,
|
||||||
|
email: data.email
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// id snowflake the user's id identify
|
// id snowflake the user's id identify
|
||||||
// username string the user's username, not unique across the platform identify
|
// username string the user's username, not unique across the platform identify
|
||||||
// discriminator string the user's Discord-tag identify
|
// discriminator string the user's Discord-tag identify
|
||||||
@@ -16,7 +71,7 @@
|
|||||||
// public_flags? integer the public flags on a user's account identify
|
// public_flags? integer the public flags on a user's account identify
|
||||||
// avatar_decoration_data?
|
// avatar_decoration_data?
|
||||||
|
|
||||||
export class User {
|
export class DiscordUser {
|
||||||
id: string;
|
id: string;
|
||||||
username: string;
|
username: string;
|
||||||
discriminator: string;
|
discriminator: string;
|
||||||
@@ -35,7 +90,7 @@ export class User {
|
|||||||
public_flags?: number;
|
public_flags?: number;
|
||||||
avatar_decoration_data?: Record<string, any>;
|
avatar_decoration_data?: Record<string, any>;
|
||||||
|
|
||||||
constructor(data: User) {
|
constructor(data: DiscordUser) {
|
||||||
this.id = data.id;
|
this.id = data.id;
|
||||||
this.username = data.username;
|
this.username = data.username;
|
||||||
this.discriminator = data.discriminator;
|
this.discriminator = data.discriminator;
|
||||||
@@ -55,8 +110,8 @@ export class User {
|
|||||||
this.avatar_decoration_data = data.avatar_decoration_data;
|
this.avatar_decoration_data = data.avatar_decoration_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
static fromAPIResponse(data: any): User {
|
static fromAPIResponse(data: any): DiscordUser {
|
||||||
return new User({
|
return new DiscordUser({
|
||||||
id: data.id,
|
id: data.id,
|
||||||
username: data.username,
|
username: data.username,
|
||||||
discriminator: data.discriminator,
|
discriminator: data.discriminator,
|
||||||
|
|||||||
+23
-8
@@ -13,25 +13,40 @@ const client = new Client({
|
|||||||
});
|
});
|
||||||
|
|
||||||
client.chatCommands.register('ping', async (context: Context, args: any[]) => {
|
client.chatCommands.register('ping', async (context: Context, args: any[]) => {
|
||||||
await context.reply(`Pong!: got ${args.join(', ')}`, true)
|
const message = await context.reply(`Pong!: got ${args.join(', ')}`, true);
|
||||||
|
// Calculate the time it took to send the message
|
||||||
|
const time = message.timestamp.getTime() - context.message.timestamp.getTime();
|
||||||
|
// Edit the message to include the time
|
||||||
|
await context.editMessage(message, `Pong! Latency: ${time}ms`);
|
||||||
});
|
});
|
||||||
|
|
||||||
client.chatCommands.register('here', async (context: Context, _args: any[]) => {
|
client.chatCommands.register('here', async (context: Context, _args: any[]) => {
|
||||||
const guild = await context.fetchGuild();
|
const guild = await context.fetchGuild();
|
||||||
if (guild !== null) {
|
if (guild !== null) {
|
||||||
await context.reply(`You are in ${guild?.name}`, true);
|
await context.reply(`You are in ${guild.name}`, true);
|
||||||
} else {
|
} else {
|
||||||
await context.reply('You are not in a guild', true);
|
await context.reply('This is not a server!', true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
client.chatCommands.register('quote', async (context: Context, args: any[]) => {
|
client.chatCommands.register('quote', async (context: Context, _args: any[]) => {
|
||||||
const referenced = await context.message.getReference();
|
const referenced = context.message.reference;
|
||||||
if (referenced === null) {
|
|
||||||
await context.reply('No message to quote', true);
|
let reply = null;
|
||||||
|
if (referenced === null || referenced === undefined) {
|
||||||
|
reply = await context.reply('No message to quote', true);
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
await context.reply(`> "${referenced.content}"\n> — ${referenced.author?.global_name}`, true);
|
reply = await context.reply(`> "${referenced.content}"\n> — ${referenced.author?.display_name ?? referenced.author?.username}`, true);
|
||||||
|
// Save to quote database
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reply?.id) {
|
||||||
|
const message_id = reply.id;
|
||||||
|
setTimeout(() => {
|
||||||
|
context.deleteMessage(message_id);
|
||||||
|
}, 3000);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user