Commit Graph
158 Commits
Author SHA1 Message Date
Fleny 8a66a76b2a fix!: Accept only raw data uri schemes in rest (#5317)
Some endpoints allowed for URLs to be passed in and converted to base64 data uri schemes.
Now the user should call urlToBase64 if they were using this
2026-08-15 18:43:33 +05:30
74f93eda6d feat(rest): add signal to makeRequest and stop re-sending proxied requests by default (#5158)
* fix(rest): don't resend timed out requests when proxied

When a request to a rest proxy hits requestTimeout, only our side of the
connection gets aborted - the proxy keeps processing the request (often
it's just queued behind a rate limit) and it can still reach Discord.
Resending it executes non-idempotent requests twice. We hit this in
production: a single ticket action created several empty channels because
the channel create kept being resent while the original was waiting out a
rate limit on the proxy.

Timeouts now fail immediately in proxy mode. Only attempts that never
reached the proxy at all (connection refused/reset) are retried, with a
small backoff so a proxy that's restarting isn't hammered in a tight
loop. Direct-to-Discord behavior is unchanged.

Follow-up to #5085.

* feat(rest): support aborting requests that are still queued

* fix(rest): let fetch handle the abort signal

Combine the caller signal with the timeout via AbortSignal.any like
review suggested, so aborting also cancels an attempt already in
flight. Same as nirn - the discord request inherits the incoming
request context, so a disconnect cancels it mid flight too. Dropped
the dispatched flag, not needed anymore. Also wired the signal into
the bigbot rest example off the close event.

* fix(rest): drop redundant abort check, fetch already does it

* tests: Fix broken tests due to sinon fake timers and Node.js v22 microtask behavior

* feat(rest): let users opt into retrying timed out proxied requests

* fix(rest): cap proxy connection retries and reuse the error format

Retrying a request that never reached the proxy was bound by maxRetryCount,
which is Infinity by default, so a proxy that stays down kept every request
alive forever. Cap it at 3 attempts instead.

The proxied path also threw the raw fetch error, so proxy users got a
different error shape than everyone else. Both paths now build the error
through the same helper.

* fix(rest): make the proxy connection retry count configurable

Re-sending a request that never reached the proxy is now bound by
rest.maxProxyConnectionRetryCount (3 by default, and by maxRetryCount when
that one is lower) instead of a hardcoded limit.

Also moves the error builder and the error prototype out of
createRestManager since neither depends on anything in it.

* fix(rest): don't re-send proxied requests that already reached the proxy

A timed out attempt only aborts our side of the connection, the proxy
keeps processing the request and it can still reach Discord, so re-sending
it executes non-idempotent requests twice. proxy.retryOnTimeout opts back
in for setups that deduplicate requests. Connection failures reject right
away, same as a failed fetch does when talking to Discord directly.

Moves the error building into rest.createRequestError so a proxied request
fails with the same message and cause as a direct one.

* fix(rest): re-send proxied requests that never reached the proxy

A failed fetch is only safe to send again when it failed while connecting,
the proxy restarting being the usual case. A socket that dies once the
request is on the wire may have been forwarded to Discord already, so those
keep rejecting right away.

Bound by maxProxyConnectionRetryCount, 3 by default, since maxRetryCount is
Infinity and a proxy that stays down would keep every request alive.

* fix(rest): recognize connect failures on Deno too

Deno puts no code on the errors fetch throws, the only place the phase the
request failed in shows up is the message, so match on that as well.

* fix(rest): go off the phase a request failed in, not the error code

Node.js names the syscall that failed, so matching on that covers every
reason a connection could not be established (refused, host or network
unreachable, dns) instead of the few codes that were listed, and it is
read or write once the request is on the wire. Bun reports a code of its
own and Deno only says it in the message, so those two keep their own
check.

* fix(rest): never re-send once an error says the request went out

A connection that dies while it is carrying the request is reported in
terms of that request, and a runtime can wrap that in the wording for a
failure to connect, which used to read as never having sent anything.
Looking for it first, and over the whole chain, settles those.

Also drops the codes and wordings that were guesses. What is left is what
node, bun and deno were seen to report, with the node ones kept as a
fallback for a runtime that borrows the code without the syscall.

* fix(rest): release cancelled requests and gate proxy re-sends behind one option

Cancelling a request only settled the caller. The entry stayed in the queue,
spent a rate limit slot and reached fetch with an aborted signal. The waiter is
spliced out of `waiting` now, `Queue.makeRequest` stops before pushing to
`pending` when the signal fired while it waited for a slot, and `processPending`
drops an entry whose caller gave up before anything is spent on it.
`processWaiting` cleans up when its loop ends, otherwise a queue whose waiters
were all cancelled never schedules its own deletion.

In proxy mode an abort landing while the response body was being read was
swallowed by the `null` fallback and came back as a successful empty response. A
read the abort killed rejects now, one that finished is still returned, the same
way the queued path keeps a result that arrived before the signal fired.

`proxy.retryOnTimeout` becomes `proxy.retryRequests` and covers every attempt
that failed without producing a response. Telling a failure to connect apart
from a connection that died carrying the request meant reading syscalls, error
codes and error text from three runtimes, and it could never be more than a
guess: fetch does not say which phase a failure happened in, and a wrong guess
re-sends a request the proxy already has. So that block is gone and the caller
decides, the same way it already did for timeouts. One `retryCount` bounded by
`maxRetryCount` and `maxProxyRetryCount`, so alternating failures can no longer
hand out more re-sends than the cap allows.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(rest): give a proxy that is restarting time to come back

Three re-sends 250ms apart is 750ms of patience, which is sized for a blip
rather than for the case it was added for. A container being restarted or
redeployed is not back in that time, so the budget ran out before the proxy was
reachable again.

Each further attempt now waits 250ms longer than the one before it, and the
default count is 15, so the ladder spans about 30 seconds. Stepping up rather
than doubling keeps the gaps small enough to notice the proxy coming back
instead of sleeping well past it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* refactor(rest): move the proxy re-send delay onto the manager

It was a module level constant sitting next to maxProxyRetryCount's own limit, so it is a manager field now like the counts it goes with, and the tests set it to 0 instead of really waiting out the backoff.

* Update packages/rest/tests/unit/manager.spec.ts

Co-authored-by: Fleny <Fleny113@outlook.com>

* Run biome

---------

Co-authored-by: Fleny <fleny113@outlook.com>
Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-04 20:44:22 +05:30
a6b940677e feat(rest): add guild message search support (#5233)
* feat(rest): add guild message search support

* fix(types): address guild message search review feedback

* Update packages/rest/src/routes.ts

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>

* Update packages/types/src/discord/message.ts

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>

* Update packages/rest/src/routes.ts

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>

* apply requested changes

---------

Co-authored-by: Fleny <Fleny113@outlook.com>
Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>
2026-08-02 10:25:05 +02:00
FlenyandAwesome Stickz ce2272e359 feat: Add lobby messages and lobby invites (#5232)
* feat: Add lobby messages and lobby invites

* Update packages/bot/src/transformers/lobby.ts

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>
2026-07-29 17:13:11 +05:30
Fleny ec8852740d feat: Add bulk update lobby members endpoint (#5231) 2026-07-29 11:36:23 +05:30
Fleny fa338e6447 feat: Add deleteCurrentUserApplicationRoleConnection endpoint (#5230) 2026-07-29 11:30:08 +05:30
Fleny 3bdc792c25 feat: server-side lobby message moderation metadata API (#5191) 2026-07-29 11:24:17 +05:30
FlenyandAwesome Stickz ad26db8c98 feat: document modify guild channel positions parent_id and permissions restrictions (#5184)
* feat: document modify guild channel positions parent_id and permissions restrictions

* Update opcode name

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>
2026-07-26 22:03:18 +05:30
Fleny 00ac3989c6 fix: Add missing type in route channels.reactions.message (#5228) 2026-07-26 05:18:11 +05:30
Fleny dd18449ce6 fix: Document required permissions for get voice state (#5176) 2026-07-24 17:57:48 +05:30
Awesome Stickz f334bb8f6c refactor(rest)!: rename rest.editBotMember() to rest.editCurrentMember() to be consistent with rest.getCurrentMember() (#5104)
* refactor(rest)!: rename rest.editBotMember() to rest.editCurrentMember() to be consistent with rest.getCurrentMember()

* refactor(type)!: rename ModifyCurrentMemberOptions to ModifyCurrentMember to be consistent with other types
2026-06-24 16:18:13 +05:30
NoahandAwesome Stickz b878b3cb43 feat(rest): strip trailing slash from proxy baseUrl if present in createRestManager() (#5101)
* support docker swarm urls

* Update packages/rest/tests/unit/manager.spec.ts

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>

* Update packages/rest/tests/unit/manager.spec.ts

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>

* Apply suggestion from @AwesomeStickz

* remove property

* Update packages/rest/src/types.ts

---------

Co-authored-by: Awesome Stickz <38146668+AwesomeStickz@users.noreply.github.com>
2026-06-24 16:10:42 +05:30
NotDemonix 9102fc4ecc feat(rest): add request timeout to manage stalled requests (#5085)
* feat(rest): add request timeout feature to manage request retries

* fix(rest): avoid calling Node-only Timeout.unref() on non-Node runtimes

* fix(rest): use try/catch for fetch to guarantee a Response on the success path

* refactor(rest): use AbortSignal.timeout and retry proxy requests on timeout

* refactor(rest): simplify timeout detection and use .catch() in proxy path

* refactor(rest): move isTimeoutError helper to bottom of file
2026-06-16 19:25:40 +02:00
Awesome Stickz ff1a349e1a docs(types): fix typos and duplicate words across docs (#4981) 2026-04-22 19:49:22 +02:00
Fleny 8939cc8492 fix!: Community invites updates (#4724)
* Update permissions for community invites

Use payload_json for invite creation with file upload

The TODO in INVITE_CREATE is to be done after #4436 gets merged as it splits the transformer logic between gateway and the normal invite object, placing the event transformation code in the event itself

* Community invites breaking changes
2026-02-16 23:20:42 +05:30
Fleny a4a5f172d4 feat: update documentation links to new domain (#4767)
* feat: update documentation links to new domain

* fix some links in the docs
2026-02-16 07:46:51 +05:30
FlenyandAwesome Stickz a88aa33341 fix(rest): Use Retry-After header for retrying requests (#4739)
* fix(rest): Use Retry-After header for retrying requests

According to discord docs: Your application should rely on the Retry-After header [...] to determine when to retry the request.

* also use in processHeaders()

---------

Co-authored-by: Awesome Stickz <kiran121102@gmail.com>
2026-02-10 17:48:19 +01:00
Fleny bd01ded6bf feat: Community Invites (#4685)
* api-docs: Community Invites

Add support for invites that gives roles to users.
Add support for target users on invites.

Sort-of unrleated change required: `restManager.makeRequest` `resolve` function had to changed or else the `getTargetUsers` would hang forever due to a JSON parsing issue.

* fix type error & add bot helpers
2026-01-27 19:08:08 +01:00
Fleny 4eccbea89f fix(rest)!: Remove calculateBits from changeToDiscordFormat (#4557)
* fix(rest)!: Remove calculateBits from changeToDiscordFormat

The rest manager currently has to assume that request bodies that have "permissions", "allow", "deny", "defaultMemberPermissions" fields are always meant as a permissions.
If these are not, for user error or future discord changes, this will break.

Also Discord expects these as strings, and discordeno does not abstract too much from the discord api, so it doesn't really makes sense for us to accept PermissionStrings[], the user should call calculateBits themselves, there is an argument to be made about accepting bigints since these are bitfields but that's another discussion.

* Channel.permissionOverwrites use PermissionStrings

For the transformed type we can keep the fact that it uses PermissionStrings

* Fix e2e test

* remove comment
2026-01-27 18:46:19 +01:00
Fleny 9085f4a454 fix(rest): Make sure to not suppress non-api errors (#4691)
Queues currenly suppress errors, making it very hard to figure out if there is a parse error for example
This fixes it as it add debug logs and passes the error object along with the rejection in sendRequest and does reject the promise in the queue instead of silently ignoring it
2026-01-27 18:41:37 +01:00
Fleny 6a5c346546 feat(rest): unref queue timers to prevent process hang (#4693)
Currently if a queue is pending deletion or waiting to refill its ratelimit will keep the process alive, this is not ideal for scripts like command deployment ones
This does not impact the functionality of the queues in any way, just allows the process to exit if nothing else is pending in which case you would be loosing the ratelimit information anyway
2026-01-20 12:00:21 +05:30
Fleny 27c261fee2 formatter: Use semicolons (#4686)
I prefer semicolors, they also help avoiding certain pitfalls in JavaScript/TypeScript, such as the following code sample:
```js
const xyz = "test"
(something.else as string) = "another"
```
This results in a TypeError: "test" is not a function, this is because js thinks we are trying to call the string "test" as a function.
To fix this it requires a `;` somewhere before the `(`, such as `;(something ... ` which in my opinion is ugly and less clean overall.
2026-01-17 21:54:15 +01:00
Fleny c1445e4600 fix(rest): Always encode URI component in routes (#4609)
* fix(rest): Always encode URI component in routes

Instead of using the implicit behavior of `fetch` and `Request` we do it explicitly in the routes.

* Add checks for numbers and digits-only strings

* Add option to disable uri encode
2026-01-12 12:12:54 -05:00
Fleny 1b9394244b api-docs: Guild Role Member Counts endpoint (#4628) 2026-01-07 13:55:42 -06:00
Fleny 0832500f01 docs(rest): Update documentation for get invites endpoint (#4427) 2025-09-04 08:47:45 +02:00
Fleny ae650a04d9 refactor(typedoc): update typedoc configuration and mark internal APIs as private (#4405)
The typedoc config is now only in the top-level config file instead of also being one per package
and all internal APIs are now marked as private so typedoc won't generate documentation for them, however we still need to export them to avoid typedoc warnings

The new internal APIs that are exported, since are marked as `@private` can have breaking changes without notices
2025-09-02 08:17:59 +02:00
Fleny 33ea279714 feat(types): Add PIN_MESSAGES permission (#4390) 2025-08-24 14:01:40 -07:00
FlenyandLink 27e53b801a fix(types)!: Fix discordeno/user.ts (#4365)
Co-authored-by: Link <link20050703@gmail.com>
2025-08-20 11:11:14 -07:00
Fleny 0b073a151d chore(rest): Remove todo about GET bodies (#4375)
We do not need to do anythng with GET bodies, fetch() will even throw if a body is passed to a GET
2025-08-17 09:10:46 +02:00
Link 8b41c9fe24 feat(bot,rest,types)!: Remove Discord JSON Params (#4351)
- Remove `createApplicationCommand` reverse transformer (Unused - `createGuildApplicationCommand` and `createGlobalApplicationCommand` use `snakelize`)
- Remove `DiscordModifyChannel`, `DiscordFollowAnnouncementChannel`, `DiscordCreateForumPostWithMessage`, `DiscordCreateGuildEmoji`, `DiscordModifyGuildEmoji`, `DiscordCreateGuildChannel`, `DiscordModifyGuildChannelPositions`, `DiscordCreateApplicationCommand`, `DiscordCreateMessage`, and `DiscordCreateWebhook` (unused)
- Remove `DiscordModifyGuildWelcomeScreen` (and replace it with `ModifyGuildWelcomeScreen`)

Fixes: https://github.com/discordeno/discordeno/issues/4308
2025-08-15 13:35:25 -04:00
Link 8baea8c771 feat(bot,rest,types): Add withLocalization (#4350)
- Add `withLocalization` to `getGlobalApplicationCommands` and `getGuildApplicationCommands`

fixes: https://github.com/discordeno/discordeno/issues/4340
2025-08-15 08:20:29 +02:00
Link af2b0cca2e fix(types)!: Rename CreateEntitlement to CreateTestEntitlement (#4346) 2025-08-14 21:12:16 +02:00
Fleny 6679f2c0e4 chore(bot,utils): Move snowflake utils to @discordeno/utils (#4345) 2025-08-14 12:08:19 -07:00
FlenyandLink 247fd4b348 fix(rest): Rewrite rest.simplifyUrl (#4305)
* fix(rest): Rewrite rest.simplifyUrl

* Update packages/rest/src/manager.ts

Co-authored-by: Link <lts20050703@gmail.com>

---------

Co-authored-by: Link <lts20050703@gmail.com>
2025-08-14 20:38:03 +02:00
FlenyandLink 65cbe5d1e6 fix(types)!: Split and fix discordeno.ts (#4301)
* fix(types)!: Split and fix discordeno.ts

* fix some mistakes

* remove now not needed @ts-expect-error

* Apply code review suggestions

* Fix test type errors

* Revert "Apply code review suggestions"

This reverts commit 7a0cea84b3.

* Restore some of the changes from the revert

---------

Co-authored-by: Link <lts20050703@gmail.com>
2025-08-14 18:37:52 +02:00
Fleny 51158071ad api-docs!: remove GetInvite.withExpiration, remove optional from DiscordInvite.expires_at (#4321) 2025-08-13 11:09:39 +02:00
Fleny 09d2697d37 api-docs: Update comment on getMessages (#4306) 2025-08-11 18:55:41 +02:00
FlenyandLink f199bbf71c build(dev-deps): Update biome to v2 (#4246)
* update biome to v2

* Run biome check --write

* Update biome.jsonc

Co-authored-by: Link <lts20050703@gmail.com>

* Fix config error

* Bump biome version

* Update website/yarn.lock

* Update biome to 2.1.3

---------

Co-authored-by: Link <lts20050703@gmail.com>
2025-08-09 12:45:04 -05:00
4792ad2721 feat(rest): Add events (#4245)
* feat(rest): Add events

* Apply suggestions from code review

Co-authored-by: Awesome Stickz <awesome@stickz.dev>

* Remove timeTook, consolidate event types

* Update packages/rest/src/manager.ts

Co-authored-by: Awesome Stickz <awesome@stickz.dev>

* Fix type error

* Apply suggestions from code review

Co-authored-by: Link <lts20050703@gmail.com>

---------

Co-authored-by: Awesome Stickz <awesome@stickz.dev>
Co-authored-by: Link <lts20050703@gmail.com>
2025-08-04 19:49:44 +02:00
Fleny 068ecf897b api-docs!: Remove deleteGuild & EditGuild.ownerId (#4269)
* Remove deleteGuild & EditGuild.ownerId

* Change E2E test
2025-07-31 21:05:31 +02:00
Fleny 5983af8c9b api-docs!: remove editGuildMFA (#4270) 2025-07-30 17:47:51 +02:00
Fleny 979f1a248c api-docs!: Remove createGuild and createGuildFromTemplate (#4268) 2025-07-30 17:45:01 +02:00
Fleny 936a09ec6c fix(rest): Use .startsWith on the Content-Type check (#4244)
* fix(rest): Use `.startsWith` on the Content-Type check

* Fix type error
2025-07-13 09:02:20 +02:00
FlenyandLink 612ac26ea7 feat(types,rest,bot): Updated message pin endpoints (#4228)
* feat: Updated message pin endpoints

* Apply suggestions from code review

Co-authored-by: Link <lts20050703@gmail.com>

---------

Co-authored-by: Link <lts20050703@gmail.com>
2025-07-12 09:30:35 +02:00
Fleny 8e637731e8 feat(rest): use a custom inspect for errors 2025-07-12 11:38:08 +05:30
LTS (Link) 4b96d9fe02 fix(bot,types)!: Remove editOriginalWebhookMessage (#4175)
(and fix editWebhookMessage options type as well)

Fixes: https://github.com/discordeno/discordeno/issues/4174
2025-05-04 09:23:11 +02:00
Fleny 80509a1420 Update manager.ts (#4176) 2025-04-28 18:28:55 +02:00
Fleny b3de175f13 feat(types,rest,bot): Add with_components to webhooks (#4152)
* Add with_components to webhook execute and edit

* Fix query param building

* update comments
2025-04-27 09:42:51 +02:00
FlenyandLTS 24703f13dd fix(types)!: Remove incorrect, reorder and fixes in channel (#4151)
* Remove incorrect, reorder and fixes in channel

- Updated comments to be more clear
- Remove `Channel.newly_created`, doesn't seem to exist in the api docs
- Fix nullability for some fields
- Remove DiscordActiveThreads, DiscordArchivedThreads and DiscordListActiveThreads as they don't seem to match anything in the api

* Add back DiscordListActiveThreads but under Guild
and fix type errors

* Update packages/types/src/discord/channel.ts

Co-authored-by: LTS (Link) <lts20050703@gmail.com>

* Revert newly_created removal

* Apply suggestions from code review

Co-authored-by: LTS (Link) <lts20050703@gmail.com>

---------

Co-authored-by: LTS (Link) <lts20050703@gmail.com>
2025-04-26 08:31:01 +02:00
Fleny 22012fc288 feat(types, rest, bot): Add lobby support (#4158)
* Add lobby support

* Fix CI
Apparently for extends a bot was a LobbyMember since both had
a required id property and even if LobbyMember had other properties
as well that did not matter

* update LobbyMember flags to use ToggleBitfield
2025-04-25 21:15:42 +02:00