From e85083035ed8ec5fd962e8f23e3fee5358958c47 Mon Sep 17 00:00:00 2001 From: Jaron Date: Mon, 16 Dec 2024 12:48:18 -0600 Subject: [PATCH] Some build proccess stuff --- bun.lockb | Bin 3143 -> 13077 bytes package.json | 14 +++++++++++--- src/services/api.ts | 25 +++++++++++++++++++++++++ src/services/hydrator.ts | 9 ++++++--- src/types/context.ts | 2 -- src/types/message.ts | 19 ++++++++++++++++++- testing/demo.test.ts | 23 +---------------------- tsconfig.json | 7 ++++++- 8 files changed, 67 insertions(+), 32 deletions(-) diff --git a/bun.lockb b/bun.lockb index b2e680dbeeccb89dba2d47f7ee45f0f1137b5c9f..7fd744c4b21c2633f4bc547e6cb05ce8da200a89 100755 GIT binary patch literal 13077 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 TdjpJ*ft3Z)LhXS5AO8FsQSn}9 delta 622 zcmbQ5c3fhDo@S;EU+;`2Tg%&?=VP~ zy|URM90)1Iz|bHAWO4!N7$D6Fq*nrIppJ%jK$-_gFMx^z)q>UCz5ZfnlYxW$>WJ1i*^;+p@>enM$v=2`C;N(fGcr$}DIPv~1t0I^zd#=A zWKW6k$r1d#lh;aQPd1PYm@FabviXFxIwRKxsGUdHC#xvgOa1!~0YJ;auKEC#=HQs@ zrmUm{5(YUGwDSb!Mh84C^|0R$mnWm+I6%ugVtASE#6Ai4vp+>Udyl!_WiWU{@A zsSGS8s^6ra?GSpc#KdT*XQ*dv!oaYAVX~Ztgc&S~ChAA^s%^EkWMZr{GSD+L(zAd? z8fU)Eu~&h!b^~Qh^^DB)Oc+)&OwQ4e;OYQIF$kRCoZP43Fj+v;Kq?>T6Hr9ASeTw+ atl<0i1FB>__v9!|pUI3yN}Kr%*_i-{NO{=+ diff --git a/package.json b/package.json index b181d40..e7a1a27 100644 --- a/package.json +++ b/package.json @@ -1,15 +1,23 @@ { - "name": "discord.ts-rewrite", + "name": "discord.ts", "module": "src/index.ts", "type": "module", + "main": "out/index.js", "scripts": { "test": "bun run testing/demo.test.ts", - "test:inspect": "bun --inspect testing/demo.test.ts" + "test:inspect": "bun --inspect testing/demo.test.ts", + "build": "bun run build:types && bun build src/index.ts --outdir out", + "build:types": "tsc --emitDeclarationOnly --project tsconfig.json --noCheck", + "build:watch": "concurrently \"tsc --emitDeclarationOnly --project tsconfig.json --noCheck --watch\" \"bun build src/index.ts --outdir out --watch\"" }, "devDependencies": { - "@types/bun": "latest" + "@types/bun": "latest", + "concurrently": "^9.1.0" }, "peerDependencies": { "typescript": "^5.0.0" + }, + "dependencies": { + "ws": "^8.18.0" } } \ No newline at end of file diff --git a/src/services/api.ts b/src/services/api.ts index 58f5a70..e1ce067 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -1,3 +1,4 @@ +import { exists, log } from "../utils"; import type { Client } from "./client"; export class API { @@ -32,6 +33,30 @@ export class API { // console.log(`API Body: ${JSON.stringify(data, null, 4)}`); // console.log('API Response:', JSON.stringify(body, null, 4)); + // Extract rate limit headers + const remaining = response.headers.get('X-RateLimit-Remaining'); + const limit = response.headers.get('X-RateLimit-Limit'); + const reset = response.headers.get('X-RateLimit-Reset'); + const resetSeconds = response.headers.get('X-RateLimit-Reset-After'); + const limitBucket = response.headers.get('X-RateLimit-Bucket'); + + // Log rate limit info for debugging + log(`Rate Limit: ${remaining}/${limit} - Reset: ${reset} (${resetSeconds}s) - Bucket: ${limitBucket}`); + + // If status is 429, we are being rate limited + if (response.status === 429) { + // Look for the retry-after header + const retryAfter = response.headers.get('Retry-After'); + if (exists(retryAfter)) { + // Wait for the retry-after time + await new Promise(resolve => setTimeout(resolve, parseInt(retryAfter) * 1000)); + } else { + // TODO: Handle this case better + // Maybe wait some arbitrary time?? + throw new Error('Rate limited without Retry-After header'); + } + } + return body; } diff --git a/src/services/hydrator.ts b/src/services/hydrator.ts index 5971a22..479ef81 100644 --- a/src/services/hydrator.ts +++ b/src/services/hydrator.ts @@ -38,11 +38,14 @@ export async function hydrate, K exte if (data instanceof Context) { for (const expectation of expectations) { - if (expectation === Expectation.Guild && exists(data.guild_id)) { + if (expectation === Expectation.Message && exists(data.message_id)) { + let context = data as unknown as HydratedContext<[Expectation.Message, ...Expectation[]]>; + context.message = await client.messages.get(data.channel_id, data.message_id); + } else if (expectation === Expectation.Guild && exists(data.guild_id)) { let context = data as unknown as HydratedContext<[Expectation.Guild, ...Expectation[]]>; context.guild = await client.guilds.get(data.guild_id); } else { - throw new Error(`Could not resolve expectation: ${expectation}`); + throw new Error(`Invalid expectation requested for Context: ${expectation}`); } } } else if (data instanceof Message) { @@ -54,7 +57,7 @@ export async function hydrate, K exte let message = data as unknown as HydratedMessage<[Expectation.Guild, ...Expectation[]]>; message.guild = await client.guilds.get(data.guild_id); } else { - throw new Error(`Could not resolve expectation: ${expectation}`); + throw new Error(`Invalid expectation requested for Message: ${expectation}`); } } } diff --git a/src/types/context.ts b/src/types/context.ts index 4b30ded..651a68f 100644 --- a/src/types/context.ts +++ b/src/types/context.ts @@ -102,8 +102,6 @@ export class Context { * @returns The message that was sent */ public reply = async (message: Message | string, reference: boolean = true): Promise => { - console.log('this.interaction', this.interaction) - if (isNil(this.message)) { throw new Error('Cannot reply without a message'); } diff --git a/src/types/message.ts b/src/types/message.ts index acc1a96..5958890 100644 --- a/src/types/message.ts +++ b/src/types/message.ts @@ -1,4 +1,4 @@ -import { isNil } from '../utils'; +import { exists, isNil } from '../utils'; import { GatewayObject } from './base'; import { fromDiscord, Trait, type Expectation, type Expects } from './common'; import { Embed } from './embed'; @@ -125,9 +125,17 @@ export class Message extends GatewayObject { this.channel_id = data?.channel_id; this.guild_id = data?.guild_id; this.content = data?.content ?? ''; + this.message_reference = data?.message_reference; this.timestamp = data?.timestamp; }; + // NOTE: Overriden here because the `fromDiscord` method returns a `MessagePayload` object + // and the GatewayObject getter overrides the return type to `Message` + // TODO: Fix type in GatewayObject so this override is not needed + public static get fromDiscord() { + return this[Trait.fromDiscord]; + } + public static [Trait.fromDiscord](data: DiscordMessage): T { return new Message({ id: data.id, @@ -135,6 +143,15 @@ export class Message extends GatewayObject { channel_id: data.channel_id, guild_id: data.guild_id, content: data.content, + // TODO: Add embeds + // embeds: data.embeds.map(embed => Embed.fromDiscord(embed)), + // TODO: Add components + // components: data.components, + message_reference: exists(data.message_reference) ? { + id: data.message_reference.message_id, + channel_id: data.message_reference.channel_id, + guild_id: data.message_reference.guild_id + } : undefined, timestamp: new Date(data.timestamp) }) as T; }; diff --git a/testing/demo.test.ts b/testing/demo.test.ts index 7d485ab..6dc6af5 100644 --- a/testing/demo.test.ts +++ b/testing/demo.test.ts @@ -10,7 +10,7 @@ const client = new Client({ Intent.GUILD_MESSAGE_REACTIONS, Intent.MESSAGE_CONTENT ], - prefix: '??' + prefix: '!' }); // Register arbitrary event handler to the client bus @@ -105,25 +105,4 @@ client.chatCommands.register('here', async (context: Context, _args: any[]) => { } }); -// Quote command -client.chatCommands.register('quote', async (context: Context, _args: any[]) => { - const { message } = await context.hydrate(context, [Expectation.Message]); - const reference = (await context.hydrator(message, [Expectation.Message]))(message); - - let reply: MessagePayload; - - if (reference) { - reply = await context.reply(`> "${message.reference.content}"\n> — ${message.reference.author.display_name ?? message.reference.author.username}`, true); - // Save to quote database - // TODO - } else { - reply = await context.reply('No message to quote', true); - } - - // Wait 3 seconds then delete the quote - setTimeout(() => { - context.deleteMessage(reply.id); - }, 3000); -}); - client.connect(); \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 238655f..54f8459 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,6 @@ { + "files": ["src/index.ts"], + "include": ["src/**/*.ts", "src/**/*.tsx"], "compilerOptions": { // Enable latest features "lib": ["ESNext", "DOM"], @@ -8,11 +10,14 @@ "jsx": "react-jsx", "allowJs": true, + "declaration": true, + "outDir": "out", + // Bundler mode "moduleResolution": "bundler", "allowImportingTsExtensions": true, "verbatimModuleSyntax": true, - "noEmit": true, + "emitDeclarationOnly": true, // Best practices "strict": true,