#archive-library-discussion
1 messages · Page 6 of 1
okay
uh, ok that doesn't load apparently 
can anybody explain to me how they made the VoiceState class bc i wanna make one for slashcmds myself
it did
#archive-offtopic for things not related to the development of discord.js
- the source code is public, you can look at the class implementation
makes sense
@vernal atlas another minor thing on the v8 refactor, in https://github.com/NotSugden/yeetcord.js/blob/refactor-v8/typings/index.d.ts#L2954
the typings give activity whereas it should actually be activities
so I've been looking into v8 PR by @vernal atlas and ran into an issue... message create is not emitted by the library for DM messages (https://github.com/discordjs/discord.js/blob/master/src/client/actions/MessageCreate.js#L10)
which makes sense since discord stopped sending channel create for DMs in v8
my question is, how should this be approached, should/will there be a new event just for direct messages that doesn't have channels?
oh interesting
or maybe fetch the channel and then emit message create?
I guess another option could be to just create a DMChannel with id (the only data discord provides) and go with it 
no auto fetching of incomplete structures
could also add recipients: [data.author] to the partial channel
could make use of Action#getChannel() (https://github.com/discordjs/discord.js/blob/master/src/client/actions/Action.js#L34-L49) here which does ^ but this would require the 'CHANNEL' partial to be included within the client options for it to end up calling Chanel.create(), ig an exception for the partials check could be bypassed for this case but thats a bit hacky
message.channelID and get channel()
Ref: Latest pin in this channel now deleted
overwritePermissions completely replaces all overwrites on the channel
createOverwrite and updateOverwrite are fundamentally very similar, however I think createOverwrite is supposed to completely replace a single overwrite if it exists, which updateOverwrite is supposed to merge with a single one that exists, or create if it doesnt
overwritePermissions is the most un-similar to the other two
At a low level createOverwrite and updateOverwrite are the same thing. However, because the overwrites are cached, they do both need to exist (and it makes it slightly clearer for users).
Further: the API endpoint those are calling updates based on the overwrite id, which will only ever be one overwrite at a time. Discord expects us to use the edit endpoint if we need to edit all overwrites (which is what overwritePermissions does)
Perhaps an updateOverwrites method would be better
Yeah, if you want to build a method which will analyse and diff the existing permissions rather than completely overwrite them, that should be updateOverwrites
Imo the play method should give a few more options to specify the type of the input and throw more errors if it doesn't know what to do with it/invalid input
80% of the questions in #archive-djs-v12-voice-deprecated are caused by d.js (or prism? Idk) swallowing errors and not throwing errors when something is wrong
Is there a reason why a lot of the structs exposed by the library aren't frozen? E.g Permissions.FLAGS?
I doubt it
Hey guys, I'm not sure if this is a good idea or not, so that's why im like putting it here instead of making a pr for it
Alright so basically, you guys know how the message object has a url property right? to keep it consistent wouldnt it be better to also make it so that the channel property also had a url property as well? imo it doesnt make much sense to have one url formed for you, and be forced to form the other one manually.
(I searched the docs for a channel.url property but couldn't find one, sorry if i missed it)
(Same thing for guilds as well)
eh
with channels you'd usually use a mention
which mirrors the client
the client only provides message urls and you can use mentions for channels
I don't actually see why you would want a channel url, it's pretty much only useful for exploiting client quirks like the old video chat stuff lol
idk abt any client quirks, the only reason this came to mind was cos someone was asking for it in support for an embed, and tbh it was more of a like consistency thing, but ig ur right and it would be kinda useless
ty!!
yw
would probably be a better idea to just generate an invite link for that channel, so users who aren't already in the server can still gain access to it
even if, that's definitely not something that library would do on it's own
wait r you talking abt the forming a url? Or making an invite link
Invite
ohh okey gotchu
I noticed during some debugging today that any method in a manager that deals with a Collection or Array of items will throw an error if even just one of those items is invalid.
This is fine, however the error it gives back suggests that the whole passed Collectoin or Array is invalid, not just a single item, which makes it difficult to debug.
I could see two solutions to this:
- Reject the Promise (currently behavior is throw, but I believe this is changing) with a newly defined TypeError that indicates that one or more of the internal items is invalid
- Silently throw out invalid objects / snowflakes and continue execution as long as there is at least 1 valid item left (obviously less desireable)
For reference, I found out about this by removing roles using an array of snowflakes. It threw a type error because one of the snowflakes was associated with a newly deleted role, but the error message made me think my database structure was messed up (I have handled this error before it gets to the method now)
Any thoughts?
@vernal atlas what if you made all BitFields use BigInts in v13 for consistency?
should not really matter (except for memory usage increase) if you use them with the flags, and you could convert numbers to bigints in the methods
well the only thing with that is its just useless conversion between bigint and number all the time
we can always break it altogether and not accept numbers
Honestly my only actual problem with keeping some as numbers is this line
const defaultBit = this.name === 'Permissions' ? 0n : 0;
thats the best way i found of solving it
maybe an additional param to resolve?
it seems silly to convert between bigints and numbers when you don't have to
it is
so then why suggest changing it all to bigints?
you can do that without converting
what
just bigint or it fucks
the api sends numbers for things like userflags
equality of what
for a start, why is this being done on the base Bitfield class
wasn't there gonna be a separate BigIntBitField? were they merged into one or can we just not tell the difference in this situation
given this.constructor.resolve is being used all across the board
the Permisisons class could just... overwrite static resolve
but then it would just be entirely duplicated code except for replacing 0 with 0n
default resolve can default to 0, extended resolve can behave like:
if (typeof bit === 'undefined') return 0n;
return super.resolve(bit);```
and it'd probs not be a huge deal
https://discord.js.org/#/docs/main/stable/class/Client?scrollTo=generateInvite should be updated to support the slash commands scope
Or maybe just add an option to give specifics scopes https://discord.com/developers/docs/topics/oauth2#shared-resources-oauth2-scopes
I much prefer the option to provide additional scopes
rather than forcing all invites to request application.commands
I would prefer it to
[...] forcing all invites to request application.commands
yeah, that's not gonna happen. array of scopes is probably what i'd go for
reminder though that interactions are still only in public beta
although we could definitely add that array of copes now and add application.commands once its finalized as I imagine there are already some use cases where more than the bot scope is necessary
sure, v13
I'l go ahead andl work on a PR for that
The slash commands PR has been merged, even if the slash commands itselves are in beta it is not a reason to not integrate it
Does Discord.js not support import {} from '' syntax? And if so why? If so what benefit is require() allowing?
That's more a node thing not supporting it in js yet, ts does support it though, and d.js does support ts
oh ok so what is the default export i assume just "Discord"
ah wait nvm sorry am a bit tired 😅
node 14 supports it
but you'll have to use .mjs or put "type": "module" in package.json
(and its unfinished so wont work for everything)
Well fair yeah, but as you said, it's still not 100% working, so no need to be pushing it until it is (just like interactions
)
Is there any plans for a Deno Package 👀
lol
I'd go out on a limb and say no, considering Discord.js is meant for Node.js. However, https://github.com/discordjs/discord-api-types does have support for deno
Supporting Deno is a headache with JavaScript, maybe once we go to TypeScript (discord.js-next), we'll have an easier way to support it. Regardless of that, we use a lot of things Node.js has that Deno doesn't.
deno does have a node compat layer tho
👋
User.presence.clientStatus returns an object, and this has got a major flaw:
For example, if someone logs in on mobile and logs in on mobile on another device, clientStatus would be mobile: 'status'
There is only one mobile object, meaning, the 2nd one wouldn't be displayed
This'd therefore be incorrect, would a PR changing this to something like an array of objects, with device as a string and status as a string be an idea people like?
Ping me if you have a question.
discord doesn't expose if there's more than one mobile device logged in
so that's impossible
oh there it is, i just wasted 3 minutes trying to find it on User or Guild
also i have to ask.. like what?
It'd be nice if there was an option to broadcastEval on all available shards when not all of them have finished spawning instead of just erroring, should I PR one?
I'd personally be against adding something like that, given you can broadcastEval to a specific shard. I think it'd be better to leave that to each user to write their own util to broadcastEval to all shards individually and handle the error. Having a util in the library that does that might lead to folks missing issues, like a shard not starting etc.
The error is still thrown even if it's to a specific shard
Yes, but you can then catch that error and handle it yourself
I meant even if the shard has spawned already
there's no way to b-eval on any shard until all of them have spawned
the error is thrown on the third line here - your added code is after that
Oh i forgot sharding in progress was a thing
maybe we just drop that err, cause each shard will throw a no process error iirc
if you dropped that line - from my understanding it would then just run for each available shard
and ignore the ones that are yet to spawn
(which would be the option I was suggesting)
Oh, this is when everything first starts
Yes
Personally, I'd be in favour of pulling out the SHARDING_IN_PROGRESS error, but then iterating over all expected shards and throwing an error further down if a shard hasn't yet spawned
I'm very against the idea of silently just ignoring shards that haven't spawned, but agree on ensuring its possible to exec on a specific shard before everything has spawned
I could work with that
Ig the for loop at the bottom would iterate over this.shardList instead, trying to find the shard in this.shards, and throwing something like SHARDING_SHARD_NOT_SPAWNED if its not there?
I'd just move the 3rd line under your addition for specific shards
it would be a lot simpler
Actually tbh yeah that achieves the same outcome
So should I PR that or will you?
Why is Guild.owner nullable but Guild.ownerID isn't?
because the owner member may or may not be cached
I got that part, but if it's not cached, how can ownerID be guaranteed?
Hmmm ok. Thanks
Guild.owner is a getter on guild.member.cache with the guild.ownerID
Go for it 🙂
Cool, will do
@vernal atlas re https://github.com/discordjs/discord.js/issues/5227#issuecomment-762727900
Yeah I can def see this being an inconsistently reproduced issue depending on bot size and other factors.
If you check MessageManager#delete all it does is make the HTTP call - at which point d.js waits for the gateway MESSAGE_DELETE packet to actually mark the message as deleted
yeah
Yeah, it does depend on size, I can replicate with all code samples myself
It's an error due to eventual consistency
Cheers for bringing it up in here!
I don't particularly know how to even go about "fixing" this.
Most things in the library work this way, since Discord flat out doesn't really give this data properly in the http response
Yeah, in my case I'm thinking I'll just have to queue up my own collected events and process them FIFO
You could theoretically set it to true if Discord replies with a code 2xx (promise resolves)
but then that creates inconsistency
and lots of head scratching in other areas of the library
Yeah, we'd have to rely on the response code being 204 (in this case)
But even if I queue up what I'm doing, there's still race conditions around it
:p for now you could just do something like
const deleted = await message.delete().then(() => true).catch(() => false);```
the catch part varying on your scenario
which would rely purely on the HTTP request
The issue is, the message is deleted in one collect event, then the error is thrown in the next collect event - if I react between the fist event firing and the delete finishing.
ah, message collectors - that's a headache
mhm
i'm not even sure if this can be considered a bug to begin with - neither do i understand in which use case this would be an issue
afaik the user client works the same way, messages are considered deleted and evicted from view and cache once the respective event arrives
so, wait, are you deleting the message yourself or are you concerned about someone deleting it?
My case is:
A message embed with paginated reactions. One reaction is assigned to call await message.delete() on the message the reactions are being collected on.
If you react with one of the other reactions prior to the delete finishing, the collect event fires again.
I have:
await reaction.users.remove(user.id at the top of my collect event, and this hits an error as it tries to get the message, which is deleted half way through the call
Yeah, I would agree with that, the message is not instantly deleted with the response, we could speculate on the order that discord processes things, but that wouldn't get us anywhere
ah
in that case you could just end the collector along with the mesasge.delete() call, though
That's true.
so that next reaction never comes through
Good point
But then if the delete fails, the collector is lost pre-emptively, state wise it can still end up inconsistent
and if the end user deletes the message... well... I guess there is the off-chance for the reaction to come in before the MESSAGE_DELETE, but that's so incredibly unlikely I'd just dismiss that edge case
but that is definitely a preferred option
well, it's your bot's message
the delete would only fail due to a sudden permission change or just Discord failing the request due to a 5xx or something similar
either case gets a shrug from me ¯_(ツ)_/¯
either case gets thrown into a rejected promise too IIRC
On a completely separate note, is integrating HTTP fetches for getters of user / member etc not in the cache planned for v13 or was that something that is happening later?
i don't yet see the necessity to introduce library side handling for this (message/other deletion)
pardon? you mean auto-fetching uncached partial data? has been discussed but been decided against for what it's worth
Ah, i must have missed the resolution to that conversation then
for larger use cases auto fetching uncached data could result in massive amounts of api fetches behind the scenes, with intents now being in the picture the whole ordeal becomes arguably worse (seeing that you might need to go with different approaches based on the data you receive)
abstracting that away into auto-fetches might even result in the developer never realising how spammy their bot even is. fetching data should be a conscious decision
yeah, I definitely see why it wouldn't be desirable, especially considering intents, just remembered seeing something about it and noticed there wasn't a PR
Again, going to a slightly different subject (but indirectly related) when passing a snowflake to something like Channel#createOverwrite(), the user has to be cached, even theough the API only needs the snowflake of the role or user.
This is actually due to attempting to type the data.
This is only one example, but I assume there are others that fall under the same category.
Since v13 will include improved type safety for Snowflakes, would it be feasible to pass Snowflakes directly if no cached object is available?
i was blissfully unaware that that's the case - with intents happening that's rather bad 
but i do for this one understand where it's coming from, since the type seems to be required, but can't really be determined based on the snowflake passed, might need to require that to be passed explicitly
@ruby terrace should prob. create an issue so that's on the radar (if you can find other places where similar things are happening do include those)
I’d be happy to (even to make a PR once the decision has been made) I’m just headed off to bed though, so will do in the morning
any idea why djs destroys sessions w 4000 instead of 1000 or 1012 https://github.com/discordjs/discord.js/blob/2583ad5da7db5ab92dfa357909f9c713db0a2981/src/client/websocket/WebSocketShard.js#L417
^
1000 means "all good, im out"
discord wont let you reconnect off of it
i... found that out the hard way.
it closes with 4000 so its able to resume its session because the session doesnt close immediately
I know v13 should be Soon™️, but do we have any documentation of the changelog or an update guide in the works? (I'd like my framework to be ready and don't see an in-dev branch on the doc site.)
Wonderful - thank you!
is there a reason it’s User.send instead of User.dmChannel.send?
or is it just for convenience?
User#send exists only because User implements TextBasedChannel which has the send method. However, in the code for TextBasedChannel#send you can see that if the object you're calling send on is a user or a member, it will just wrap around createDM and send to the returned dmChannel
ah I see
so basically dmChannel.send wouldn’t work if createDM hasn’t been called, and .send does that for you
so dmChannel would be undefined
Not necessarily? createDM will return the DMChannel if it's in the cache, otherwise it will fetch it
null, but pretty much, yes
oh i should probably move my discussion here
i didnt see this chat earlier
why Guild#addMember instead of GuildMemberManager#add ?
BaseManager#add already has specific functionality which that would clash with
But your point is still valid, it could be on the manager with a non-clashing name
yeah i opened up a fork and looked around to try and do a PR for it and I found that
so my question now is why is there a BaseManager class that 2-3 managers decide not to implement
Those are fake managers lol
Probably not no
what's a fake manager then
and why the need for it
just looks very off to me at a first glance to have one manager reimplement part of the base without extending it or something like that
by fake managers are you talking about things like ActionManager?
no
nvm I got a little mixed up
But Im not sure why this is a concern for you?
This manager does have custom a custom add method
well its a concern to me because i was going to go in and move the code on over from addMember to members.add
and then i see that, so I'm like, "okay lets look at the base manager to see what this does"
those managers are pseudo-managers, meaning that they don't have their own cache but instead get/filter it from another cache
so i look at it and i see it doing the cache, and I say "oh cool, but wait, you can do member.roles.add, so maybe I'll look at that and see how that's implemented"
so i go there
and it's completely different
fake managers are needed for the getters correct? like GuildMember#roles
ah okay
yeah ok I see how this works now
So they dont extend BaseManager because you cant override a real property with a getter
so how are we going to fix the addMember issue then
best way would probably be a non-clashing name right?
that seems fine but I don't agree with naming it anything other than "add" though, seeing as the discord API call is literally named "Add Guild Member"
you could use GuildMemberManager#join maybe?
that doesn't make semantic sense either
I was thinking of like
User#join
or joinGuild
joinGuild probably works better
if we have methods available such as member.ban() and member.kick(), I dont see why user.joinGuild() is inconsistent
having it be a method on User requires the user to be currently cached, no?
The current method accepts a UserResolvable which includes ID only as an option
^
well to stay in line with consistency as well as fulfilling the requirement of it being a userresolvable, the only option is GuildMemberManager.add
for my use case at least, the user is cached beforehand
...which still isn't a valid option though
in most cases it won't be though
yeah i agree
you can add both, seeing as you have member.ban() and guildmembermanager.ban(userresolvable)
why is it not a valid option @frank turret
like, semantics and design wise
pretttyyy sure member.ban is just a wrapper over guildmembermanager.ban
yeah that's my point
i mean sure, a convenience method is fine
at the end of the day i just see a massive inconsistency here
everything was migrated to use a manager system in v12 then out of nowhere we get a .addMember
lol
which brings us back to the option of guildmembermanager#join lol
Here's two possible thoughts:
- add a parameter to the add method in that indicates the user is not already in the guild (I strongly dislike this)
- add a new function named something descriptive, perhaps like forceAdd
forceadd also semantically doesn't make sense
it might be inconsistent, but we have no choice, we can't override a basemanager method that would literally break it's functionality
the only way I see design wise to be consistent (if we exclude the issue with implementation for now), is if we add guildmembermanager.add and user.joinGuild to wrap around it
pls dont mind my lazy typing for those methods
mmmmm then what do you propose we do about the existing basemanager method then?
cause if we override it, there's tons of places in the lib that are gonna be broken
@ruby terrace my thought is that having add and forceAdd both exist is a bad idea because that implies that:
- add is an action that may fail
- forceAdd does the same thing as add except in some way forces it to not fail
@frank turret the issue here is with the fundamentals of the manager system at this point
i also disagree with .join because the API method is named add
and, read this: guild.members.join(user)
oh, addUser might work, since you are adding a user to the guild, not necessarily a member
the guild's members aren't joining the user
🤔
maybe rename manager.add to manager._add?
@ruby terrace no that's also bad, because again, the API method is named "Add Guild Member"
dunno if its considered private
you are not adding a user, you are adding a member, therefore you don't use addUser
users aren't supposed to exist within the context of guilds, only members
you cannot add a member though, since that member doesn't exist yet, you are adding a user, which creates that member
well in dAPI, it's referred to as adding a member https://discord.com/developers/docs/resources/guild#add-guild-member
well at that point that's a gripe with the discord api docs
doesn't guild.addMember require oauth
it does
i'd assume d.js to follow the docs , and not opinionate them
it does
so why are we trying to force it so hard into base d.js
because oauth is apart of base d.js? The method already exists on guild so you can't argue that it isn't already in base djs
you want to have proper api coverage right?
like, on the homepage of djs website?
almost 100% coverage?
the only thing this convo is talking about is moving said method to the more consistent placing
i mean the coverage is there but the implementation is flawed
read above
i did
"inconsistent naming"
there is a lot of words above, which don't mean much
to my knowledge, Guild.addMember is the only use case of similar methods not being in <manager>.add
the ONLY case
and it's an inconsistency
only because of the clashing base method
yup
so the problem at the core here is the fact that internal manager method naming clashes with potential API naming
that was something that shouldn't have happened to start with
so then i like Jan's suggestion of moving basemanager#add to basemanager#_add
since it is only used internally either way
I think that's a step in the right direction, but I feel it might still be confusing and there might be a better solution
maybe something where internal manager code is abstracted from api calls
well so far you haven't really provided any other alternative, you've only said to replace the add method, no solution as to where we are gonna move the existing method
the issue doesn't disappear if I don't have an alternative
and I was typing something
how has API coverage even come up as argument in this discussion... adding members through oauth2 is covered.
because someone above asked "why are we trying so hard to force X discord API method into discord.js"
that was not what i said
could you rephrase then because I may have misinterpreted you then, mb
so the real argument is Guild#addMember should be Guild#members#add?
okay. yeah, sure
so can that be the actual point in the discussion please?
not... whatever else what discussed up there
well that's what i brought up initially but it got trailed off
well that's what i'm trying to discuss
@frank turret if you want my idea for an actual implementation that prevents the name clashing, i suggest an abstraction between core manager code (managing caches, etc.) and 1:1 wrappers around API methods
for example, one could use the guild.members to not return the entire basemanager, but rather a scoped proxy or something on the basemanager that maps calls to manager._api.X or something like that for example
that way you could have manager.add, manager.cache, etc. all that stuff, and have all 1:1 discord API mappings outside of that layer
that way there would be no possibilities of a name clash
the point of managers is to separate cache and api 
well, then we have an issue, because that's exactly what DOESN'T happen when an api method named .add can't be implemented on a manager because it's cache needs it to have an .add method
that's exactly what we are discussing
in this case, they seem to be implemented incorrectly
whats blocking you from just doing guild.members.add
where is that api method named add again
why are you bringing a 1:1 mapping djs <-> discord API up? that's not a design goal
basemanager#add, that's what
@oak quail https://www.threebow.com/i/681dc8942dbf.png
we got this
and basemanager.add yeah
oh is there an undocumented basemanager#add
yeah its undocumented
it doesnt show in docs even with private on
yeah i just tried it, it's weird
i think these comments need to be fixed
i dont know how this jsdoc and that method are related
not at all
tbh i'm confused as to why add is a thing, isn't that blurring the line between separation of cache and manager?
so there isn't anything to fix either, if anything there is docs to add - to add

@frank turret yes, that is my entire point

that's what i've been trying to say
Then i guess i've finally understood you, mb
though your solution is going a lot farther than what i'd think the solution would be, which would be to just remove .add
you're thinking of the next managers revolution type stuff
well thats what you get when you find a fundamental violation of separation of concerns
my point: if the goal is to have an abstraction layer between an internal cache mechanism and API consumption, the very fact that there is a possibility for a name clash to occur on the same class between the two proves that the implementation is fundamentally flawed
looks like BaseManager.add is a left-over from DataStore
manager.add was added as "create a new instance of this.holds, and add to this.cache if it doesnt exist yet"
@frank turret the solution may also very well be to just remove add, if it is a leftover from something. however, i dont know what impact that would have as I'm not too familiar with the inner workings of the lib, so that would need to be checked by like everyone
the very fact that there is a possibility for a name clash to occur on the same class between the two proves that the implementation is fundamentally flawed
not exactly? this would mean that a manager has to have exactly 0 properties on it, as virtually anything could clash
the manager doesn't have to have exactly 0 properties, the object given to the user when requesting the manager should
abstract the api away from the caching
tbh that just feels like a layer of abstraction too far for the end user to have to learn
so how would you manage cache of a manager again
I explained above
no
you have all caching mechanism-related methods on the manager, using the existing add/set/remove/whatever it needs. then, in the API that the end user uses, for example guild.members, you return a wrapper around the manager that exposes only dAPI methods instead of the manager itself, using a proxy or something
It's just discussion, overly drawn out discussion at that
that wrapper then would control the interaction between the two
so from the user's side of things, they would ideally only get access to API methods
Yeah but this is now so far removed from what the discussion was supposed to be about
I dont see how that is, I was answering the question of how I'd implement a solution to the problem personally
the discussion's still about the core problem
and how do you access actual members via this propertyless manager proxy?
yeah
that's the whole issue
but seeing as it's used internally and causes a name clash with a real api method, here we are
We can call our stuff whatever we like though
yeah im not denying that, i just figure in the name of consistency that it wouldnt make sense to have Guild.addMember
just renaming it to _add should resolve the problem
or if we dont want to break too much
ya that too
making it _add in guildmembermanager specifically
guildmembermanager already has a ```js
add(data, cache = true) {
return super.add(data, cache, { id: data.user.id, extras: [this.guild] });
}
then comes in the question about consistency
How would that work?
but this argument is about a fundamental flaw in the method existing in the first place - which it really isn't. the manager manages the data saved in the cache.
meaning half of this way too long thread is void.
two options IMO, you either feign the API's "get user" method to return a cached user if they already exist, or just let them have the cache method
so we could just make that _add and overwrite add to be addMember and be done with it
but cache where
on the manager
but how do you access that
the manager will still manage the cache
for example guild.members, you return a wrapper around the manager that exposes only dAPI methods instead of the manager itself, using a proxy or something
yes
most fetch methods already try to get from cache first iirc
why?
does anyone have any objections to this
I can word that better, what I meant wasn't directly allowing certain methods of the manager to be exposed and others not
I'm not a fan of having both add and _add
addToCache?
since it's going to be a lot easier for me to explain it that way
Please no
Sorry wrong reply
addToCache bad because you have .cache prop
only objection i have is on the basis of consistency with the other managers, why not do the same change for all the managers in the event dAPI ever makes another endpoint that clashes. Why not make all manager specific methods have that _ notation
@frank turret the future proof-ness of "in case they ever make a new one that clashes" was also a core factor in my solution
This is supposed to be a channel for raising suggestions / issues to the actual maintainers and developers of the library. Arguing over the naming of a property is exhausting
well it's not just about the naming anymore at this point
What you're now proposing belongs in the -next lib imo
the naming is a problem due to another underlying issue and that's what i'm talking about
I'll take my leave from the discussion, as my last message is probably my final stance that i've got on it
not too familiar with -next personally
is that where you do like
v20 or something
I do agree that it would definitely be a change big enough to the point of it probably belonging in a repo like that
Its a typescript rewrite
its a planned ts rewrite, pretty empty rn
yes? it adds it to the .cache
So you'd be able to properly flag properties as private
so .cache.add()
No
but that clashes, because .cache is collection
I didn't suggest that, I'm bringing up the issue of what @oak quail is saying
I agree with you lol
but this argument is about a fundamental flaw in the method existing in the first place - which it really isn't. the manager manages the data saved in the cache.
meaning half of this way too long thread is void
again.
ok I want to reply to like 4 different people but it's so difficult to keep track of this
Yeah, GuildMemberManager#add is the edge case here, not BaseManager#add
@unique axle i was going to type a reply to that when you sent it but I got caught off guard by everything else
me calling it a fundamental flaw was based on my assumption that there was a goal of separating caching from apis
then do me a favour, stop writing, read
and then decide if a response is still needed.
this entire chat at this point reads more like a rant than like a legitimate suggestion, which i am very much not a fan of.
Is there a reason that method exists in the first place? I mean, it’s the only OAuth method that exists in the library afaik
i have had "give me like 5 mins, I'll write something up" pasted in my clipboard for the past three minutes
requires a bot token and the bot's permissions matter, so its basically a bot endpoint
but i have to keep overwriting myself because everyone's bringing up like 5 different things
It requires an oauth token from the user to use, but its a bot API method
that has been discussed before, it stays, it's part of the bot API, not the oauth2 api - despite requiring an oauth2 flow to receive the required token
@unique axle so the core thing that I based my argument on originally was me hearing somewhere that managers existed as a way to abstract api methods from caching
if that's the case, then I believe what I say to be valid
but if it isn't then i'm wrong
and I remember reading something like that in this chat before I made that point, and that was my reasoning
I can try and find it rq
yeah this one
I know less about the intended design of the stuff than you guys do so if you say that this isn't the point then that's fine, but that was the presumption that I made my points with
again, cache is a data structure, nothing more
the manager acts as... manager, to manage said cache, add and evict data - however complicated that might be
which also makes Basemanager#add completely valid to be on the manager
it allows the adding of data to the underlying cache without having a ton of code duplication when the api is called from various places
yeah, I understand that, I never proposed we get rid of caching from the manager
but my question now is that if the manager acts to manage the cache, then why is it also responsible for wrapping API calls
you argue that #add should not be on the manager - for whatever reason
Because thats what API calls do
Manage cache
fetch? into cache
kick? remove from cache too
edit? update cache
I dont think you guys are fully understanding the solution that I was proposing to the issue
There's a rather big nuance here
a rather big nuance is as well that you are proposing a solution to a problem that doesn't exist
We're allowed to understand but not agree
I didnt say that method shouldn't be on the manager itself entirely, I said it shouldnt be on whatever the end user gets to work with
the only thing that actually should be discussed is moving Guild#addMember to GuildMemberManager#add and renaming the Basemanager#add which conflicts
You're proposing yet another level of abstraction between cache/manager/wrapper of that and I fundamentally disagree that its necessary
@unique axle well if you find a way to do that that would be good, but assume later down the line for example discord somehow adds an API method to whatever you rename BaseManager#add to (assuming you dont call it _add or something, which tbh I disagree with because then you'll have .add and ._add on the same class and that'll get a bit weird)
considering there's e.g. Base#_clone and GuildChannel#clone too, i dont think _add would be a problem
since it's calmed down a bit here, an example of my solution would be to still have the manager handle all the cache-related stuff retaining the problematic BaseManager#add, etc. - the difference is that the implementations of all the API methods would be on <IndividualManager>#api or something, and when somebody requests for example guild.members it returns a proxy who's entire job is to facilitate cooperation between the api and the manager's cache itself
But the proxy would only actually return methods defined in the api child, not any of the internal manager methods involving cache manipulation
and maybe a .cache object as well that acts the same way as it does now
That way it would be effectively impossible for there to be any name clash
keep in mind that idea is overkill for this little thing, and would definitely be better suited in a rewrite. if renaming and moving around a method or two is all it takes to fix the .addMember inconsistency then I'm all for it
but just something to consider for the future
if it's consistent then sure, but then my question becomes whether or not those two methods existing in the first place is the best way to do that task
I disagree that's necessary. The manager is already facilitating the cooperation between the API methods and the cache itself. I don't see the perceived issue with the user being presented with methods that operate on the cache also.
The only demonstrable example of this is add which can be addressed by renaming it to _add
my idea comes more from my POV that code that may need to be fixed in this exact same way if another example of this happens at some point is not maintainable
I dont think a major refactor is the answer to that
i understand that it's not the most efficient way to deal with that in respect to time constraints and whatnot, and if you can get away with renaming a method because you got a name clash and it'll save time then by all means do it, but there's no guarantee that this kind of thing won't pop up again even if rarely
in my eyes I don't consider patching this one instance out as a true fix to the underlying issue, that's all
that's also why I said it's definitely much better suited to a rewrite if you're already doing that
I really disagree with the pattern of adding underscores to a conflicting method to fix the conflict, because that becomes a huge pain in the ass really quickly from my experience
but it's your library - as you said, you don't have to agree with anything, I'm just bringing my input to the table
The underscore is normally used to denote that a property is only intended for internal use, since Javascript has no private typings for class methods (or didnt until a very recent TC proposal)
I'd say its more that a naming clash has flagged that this method should have been underscored, because BaseManager#add is intended for internal use
well what classifies internal use vs non internal use in this case
like, exact same thing as private keyword in other langs?
Roughly
i'm also not too sure how you rely on a system like that
javascript doesn't have actual classes
Exactly
it's not real OO
Exactly
so i dont know why you're trying to feign private accessors with _'s in the first place
Because it communicates to users that its not intended for use
This is no longer library discussion, really more about general practices. This isnt a uniquely djs thing
seeing as you use these practices in the library i'd say it's discussion related to the library though
Tbh if that's the only inconsistency then there's no issue besides fixing it
Respectfully I dont really care what you say it is or isnt and I, as staff, am trying to move tangents out of this channel and stop this circular discussion from covering the same points all the time
.referencedMessage
READ-ONLY
The Message this crosspost/reply/pin-add references, if cached
seems weird to say "if cached" when its provided by the api?
it's only provided for replies, not crossposts etc
is it weird? Cause looking at dAPI docs on the you only get the message id, channel id, and guild id, so wouldn't we not be able to provide that prop if it isn't cached?
api provides referenced_message on replies (usually) and pins (in some cases)
not always though
can't believe i overlooked that
Does it when you fetch
Its also possible to have a reference deleted
tl;dr there are valid cases where it wont exist in cache
Also a really obvious callout - messages that are not replies
I have no idea if message cache sweeping would clear them out at the same time or not
@pearl basin i pushed a fix to send the message event - but for the moment it requires having the channels partial, is the best route just removing the channels partial and then dm channels can just always be partial?
yeah
tbh, would probably be a good idea to just allow anything to be partial and to stop dropping events by default
what is the use of the channels partial even? I mean... When is the channel not in cache except for DMs?
you just answered your own question - reactions on uncached messages in DMs
so only DMs 
idk I'd remove the partial and just put "events that happen in DMs might have an incomplete channel object" in the changelog
TYPING_START on an uncached DM channel is also probably a partial (?)
I think long term that may be a good idea. Furthermore, slash commands might affect decisions around this, if the bot isn't it the guild, can't fetch the channel, so almost guaranteed partial unless they decide to send the channel object with interactions
how would removing functionality be a good idea?
if you don't need the partial, don't use it - i don't see any reason for it to be removed, it covers an edge case that exists in various use cases
Having to enable a partial to be able to receive a DM 
gUys heLp mY bOt nO reCeIve dMs
{200 lines of shit code here}
Oh, I don't mean removing partial functionality, I mean having partials be expected (since that's how the API handles it) especially with interactions where there is no bot user
it's a small change but it's still gonna cause a lot of confusion for those who... Uh... want to make a bot but don't want to learn programming
i have no idea what you are trying to get at...
you don't have to enable partials to receive dms, you have to enable partials to receive events which depend on dm channels
Still no idea what you want or are saying
Oh I'm just agreeing with this
Sum up: DM channels will always be partial unless manually fetched with v8 gateway, meaning users won't get DM messages unless they have channel partials enabled
@vernal atlas about your comments at https://github.com/discordjs/discord.js/pull/5130#pullrequestreview-555106805, do you suggest they should all be required?
@wild flax having strings for bitfields still usable is defeating the entire purpose of the pr
well yeah thats what the type is for isnt it? (referring to ping above, forgot to reply mmmmm)
like:
GuildAuditLogs.Actions.BAN_ADD should be a number not number | undefined
nah, I think the PR is still great for what it is, not promoting strings anymore.
I think we can evaluate completely eliminating strings with the typescript rewrite
but this is def a step in the right direction
so do I add a deprecation warning?
will do
We can always add it later when we have a good path for the rewrite
@vernal atlas whats the point of this commit https://github.com/discordjs/discord.js/pull/4879/commits/8532201e5c204429f6a3e5263c3ac9bed35b8525
new permissions and all are just pure strings now because of big ints
why should we accept a number?
it was to accept compatibility when extending the class
so that for instance UserFlags still uses numbers but Permissions uses bigints
would you say discordjs/collection#31 warrants a version bump/new release?
@ruby terrace I converted your issue to a discussion btw, just in case you wonder why its closed https://github.com/discordjs/discord.js/discussions/5242
Ah, thank you, forgot those were a thing
any thoughts on making Collection#array() and Collection#keyArray() getters?
any thoughts on removing them altogether? No..? just me? ok
they're used internally for some other methods 
and they're more less a cached [...coll.values/keys()]
Personally against. In my mind having it be a getter gives some impression that it can be used to mutate the collection, whereas as a method mentally there is a clearer distinction that its generating a copy.
at what size does that caching mechanism actually become noticeable?
I mean you'll probably notice it at any size if you really monitor each byte of ram used, however, I'd expect a bunch of ram used if you, say, call members.array() on a 100k members guild (assuming you have all members cached)
Yeah... there are cases where the caches bring more bad than good, members.array() is a good example
So what about a potential bool to indicate whether a cache is warranted or not
what's a use case for caching this anyways?
But it's mostly useless, because:
- When the collection is small, the values are barely added/removed, but creating arrays on the fly are so fast it's negligible.
- When the collection is big, the values are added/removed very often, which voids the array almost instantly, forcing re-arrays anyways.
Having this cache layer also adds overhead in the set/delete calls, even for those who don't use the array caching
so is it better to remove just the cache or the whole methods 
Both
I believe .array() was originally done because we didn't have [...iterator] back in 2017
we need a major for this anyways, so might as well do it now
Hi, i have a question about ratelimit/api on this function .remove(arrayofroleids) when using an array of role ID's.
Does this count as 1 request? (see gif)
if (roleOrRoles instanceof Collection || Array.isArray(roleOrRoles)) { ... return this.set(newRoles, reason);, single API request
ahh like that thank you so much! ❤️
If you pass a single, the lib sends a delete request to remove the role from the user. If you pass multiple to remove, the lib sends a single request to set the users roles to what remains
oh wow, thats interesting. thanks for clarifying!
but does it still on the api side use one rate limit request?
so if youre just adding/removing one role at a time you can technically use both endpoints to do 2x the amount without getting ratelimited
im surprised how detailed of an answer you both gave me fjdiosaj thanks again! it was definitely helpful
have a nice day : D
oh just wondering, is it also possible to remove/add an array of roles to an array of members with only one request?
nvm probably not
nop
no
haha thanks :p
questions regarding library usage go into the GET HELP HERE category as well
got it! sorry
collection exports are still kinda broken btw 
exports.Collection = Collection;
Collection.default = Collection;
module.exports = Collection;
exports.default = Collection;
should probably just remove the module.exports = part
module.exports = messes up the exports referencing module.exports
And this is after @warped crater already "fixed" it 
looking back - yeah, it was obvious that would've never fixed it
module.exports is being used here since export = (the proper syntax for this) would throw an error
since TS does not like that along with any other exports in the file
me and I think Vlad(?) also suggested removing module.exports =, but we were shut down by Crawl due to it being a breaking change.
they can be removed now
how do you wanna go about versioning?
per semver since we're on 0.y.z we can just bump y for breaking changes
things are getting deleted literally now
we cant remove the default export
so doing export class X wont work
except TS does some magic that you can do export class X and then still do export { Collection }
not sure if it allows that
it allows you to do both export class X and export default X
export class x = export { x }, we can export default it too I suppose
uhuh..
but does export class X do the same
so you can have export class X {} and then later do export default X
let AttachmentArchive = class AttachmentArchive {
ticketID;
originalURL;
archiveURL;
};
// decorators here l o l
exports.AttachmentArchive = AttachmentArchive;```
short answer, yes
so TS itself, before compilation doesnt complain?
it doesn't
aight then, sure
ah, so we're doing that? sure.
wait so is v13 gonna be a ts-rewrite? or naw
no
d.js-next will be a ts rewrite. v13 is planned for the api v8 release, which is coming out sometime in the near future
ohhh kk gotchu
Is there a specific reason why some api-route crafting functions use foo[id] instead of foo(id)
For example:
https://github.com/discordjs/discord.js/blob/8a7abc9f06d44bf693e35a615bb6ba2c3eb1d6e7/src/managers/MessageManager.js#L84 is ```js
this.client.api.channels[this.channel.id].pins.get()`
<https://github.com/discordjs/discord.js/blob/8a7abc9f06d44bf693e35a615bb6ba2c3eb1d6e7/src/managers/MessageManager.js#L126> is ```js
this.client.api.channels(this.channel.id).messages(message).delete({ reason })
there really is no convention
i honestly believe that we should remove the possibility of () for those
keep calling the function to the request itself
I've just PR'd a change to enforce brackets
why?
@unique axle you commented on #5256 referencing #5256?
i've updated what you pointed out, though

i'm smart.
can you please wait for feedback though, before you apply reviews regarding a change you propose on other prs?
this is far from decided and suggesting that as required changes on the api v8 PR is not a good thing to do yet
Why Message#member does not return a partial member (if partial enabled) if the message is coming from a guild (and not a system message or any other necessary check I guess) ? https://github.com/discordjs/discord.js/blob/master/src/structures/Message.js#L278, same for https://github.com/discordjs/discord.js/blob/master/src/structures/Message.js#L413
because API sends member object with the message
true, https://discord.com/developers/docs/resources/channel#message-object lists member as "partial", but what API consideres partial is irrelevant to what discord.js partials are
See
** The member object exists in
MESSAGE_CREATEandMESSAGE_UPDATEevents from text-based guild channels. This allows bots to obtain real-time member data without requiring bots to store member state in memory.
under link above, and
The fielduserwon't be included in the member object attached toMESSAGE_CREATEandMESSAGE_UPDATEgateway events.
under https://discord.com/developers/docs/resources/guild#guild-member-object
I see, thank you!
is there a reason why PermissionOverwrites doesn't extend Base? assuming they do have IDs
Represents a data model that is identifiable by a Snowflake (i.e. Discord API data models).
PermissionOverwrite is not. The ID you refer to is the ID of the target of the overwrite (user or role)
this ID does not uniquely identify an overwrite (you also require information about the channel)
what about e.g. voicestates? same thing should apply there
going by the description of Base, yes
unless i'm misunderstanding the description and whoever wrote that does mean a snowflake to be used as key for a map containing the structure, which then would also make scoped unique valiable
i think you're right about the description but it's not really consistent there
there can even be some Bases without any id, like reactionemojis representing unicode emojis
indeed 
consistency is noticeable by lack thereof
so would the decision be to change the description of Base or go forward to make the class extend Base?
considering that's (almost) the same case with voicestates. or rather, the description seems quite misleading at this point unless your first guess was correct that it holds "structures mapped by IDs"
Just a little bit of curiosity, why is it that the client events don't pass some sort of indication of who did the said action, rather than just giving the old and new object? Is this subject to change, am I missing something? Or is currently the only way of getting the user that did an action just fetching from audit logs for it?
we can only provide information we get from the WS, discord does not give that information without requesting the audit logs
Ah, alright thanks
What if we removed Util methods from the default export?
I really can't find a case where I preferred to use them over importing Util
i'm not saying remove util
but you can currently call Discord.mergeDefault like Discord.Util.mergeDefault
why make -next a monorepo?
Developer convenience, theres no reason for it not to be right now I think was the general sentiment
I mean I'm down.. idk about others tho
What else would it be
separate repos?
but why
monorepos are so much easier to work in
its the common approach nowdays for large projects
apart from the fact that you can't install a single package from the branch like npm i discordjs/discord.js
so you can only work with the repo itself / the releases
so you have to update 4 different repos, then go to the main repo, change all the deps to latest and push another update?
essentially switching 4 repos for 1 change?
well not every repo would need to be updated for every change, I assume most changes wouldn't need that
We would, @oak quail
For example, most of the monorepo's packages will depend on @discordjs/core, however, there are dependencies between them, e.g. @discordjs/rest depends on @discordjs/core and @discordjs/collection, similarly, @discordjs/ws depends on all the previous (including rest)
are we going to rewrite collection too?
It's already rewritten? Unless I'm missing something
@mystic meadow what if you had to import a version for discord-api-types and just import 'discord-api-types' would not be possible?
yeah, i was wondering because i saw a collection directory in the -next repo
?
you currently can import any of:
import ... from 'discord-api-types';
import ... from 'discord-api-types/v6';
import ... from 'discord-api-types/v8';
i am sort of suggesting to remove the first option
so no api version confusion ever
To remove the default version export? while doable, you need to specify SOMETHING on the main/types properties of the package.json
you don't
I'm still against dropping it as there are still exported properties that aren't versioned (JSON errors for one)
then you could have disocrd-api-types/common or discord-api-types/errors or any other thing
just eliminate the default version
when the ts recode comes eventually, how will the typings look? will there be one typings file or several?
and I’m assuming they’re still being exported
the purpose of writing source code in typescript is that you wont have to create declaration files at all, the compiler does that for you
oh so everything is just gonna be defined on its respective class
How will they be exported?
Yeah but how is that gonna work on like a Message structure
I assume that'll exist within the core
Structures that are meant to be extended will be exported possibly the same way as they are right now, CC @solemn oyster
Extending structures in -next is gonna be completely different to how it works right now
There is no way this will be comparable
do you have any plans you could share to me? 👀
I'd assume just a DI approach such with something like tsyringe
I wrote this like a month ago, mind you, Im sure I can come up with something better, but youll get the gist
import "reflect-metadata";
import { injectable, inject, container } from 'tsyringe';
@injectable()
class CustomChannels {
public test = 'test2';
}
container.register('CUSTOM_CHANNELS', CustomChannels);
@injectable()
class Channels {
public test = 'test';
}
@injectable()
class Client {
channels = container.resolve(this.customStructures.CHANNELS ? this.customStructures.CHANNELS : Channels);
public constructor(public customStructures: any) {}
}
const client = new Client({ CHANNELS: 'CUSTOM_CHANNELS' });
console.log(client);
but it goes into that direction
👍 from me
That would only work with TS tho
Nah, tsyringe also works with javascript
mmm, I remember reading something about that
but what are the approaches as an alternative to the decorators?
You could use babel (https://babeljs.io/docs/en/babel-plugin-proposal-decorators) or something unholy like that, but I'd assume there's a clean programmatic method to get the same effect, right
you can just register them to the container I guess
Not that I care about pure JS users
not... certain I share that sentiment given djs was always known as being very user friendly and easy to get into, compared to other libraries
then again, extensions are not easy to get into
as much as I also hate vanilla js
as long as its doable in raw JS, i'm down
discord.js that doesn't fully work on js 🤔
Inversify comes with their own helpers for JS, like a decorate method: https://github.com/inversify/InversifyJS/blob/master/wiki/basic_js_example.md
so we could either use inversify, or just write our own decorate helper
Its not nice, but i mean thats what you get when you write JS
If we stick with tsyringe we could prolly just straight up copy this: https://github.com/inversify/InversifyJS/blob/6ef0ddf76093e97fd3d302c16905daa5c418db9c/src/annotation/decorator_utils.ts
nvm we dont even have to
we can just use Reflect lmao
I mean, you dont really need the decorators
require("reflect-metadata");
const { injectable, inject, container } = require('tsyringe');
class CustomChannels {
test = 'test2';
}
container.register('CUSTOM_CHANNELS', CustomChannels);
class Channels {
test = 'test';
}
class Client {
constructor(customStructures) {
this.customStructures = customStructures;
// kinda fucky wucky idk
this.channels = container.resolve(this.customStructures.CHANNELS ? this.customStructures.CHANNELS : Channels);
}
}
const client = new Client({ CHANNELS: 'CUSTOM_CHANNELS' });
console.log(client);
you do, by using register
only if they actually need to.. inject something
oh, am I misunderstanding the decorator too?
oh, and since we need users to register it anyway... I guess that makes sense
I thought @injectable did implicit resolving so you didn't have to do @inject on every parameter 
yeah nevermind, it makes sense now
uhhh yeah dd is right, but I guess as long as we dont do that?
either way you can just fall back to container.resolve in the constructor
we need to always resolve anyway for all custom structures
Class decorator factory that allows the class' dependencies to be injected at runtime. TSyringe relies on several decorators in order to collect metadata about classes to be instantiated.
buut, if I'm not mistaken, you can just do
injectable(CustomChannels)
and get the same result
@wild flax whatever we use, we'll need something to auto-inject or something
is there a reason to use DI over Structures.get/extend?
Yes, Structres.get/extend is budget DI
Yeah, the current structures are ass
Client for example is something that needs to be able to resolve in all structures
what are the advantages of using "complete DI" over "budget DI"
Structures arent DI
thats why i said budget DI
We just hack together JS to make what they are right now
yeah.. it may look "clean" on the outside, but internally the current structures system is very difficult to navigate and understand
whatever they are, they seem to work fine rn. are there any major shortcomings with them?
hmm
this is similar to a lot of things in the package, for that matter
such as actions
nobody has any idea how they work anymore
Yeah, it won't be achievable like this in TypeScript without a lot of Type-hacking
And its certainly just a pain in the ass
We still need to augment modules, regardless of whether we use DI or not
what I dont get rn tho, what about the types?
lets say you extended Channels, message.channel would still have the old type, no?
thats why you have to augment
do you have to augment even with tsyringe
yes
Logically, yes
TypeScript doesn't have anything to do that automatically, types are static, not dynamic
To be honest, I hope we go for resolving the client in all structures on demand, rather than storing a reference to it as a field in all of them
that only works well in TS
We can always make our own solution if you want
So it works well for both JS and TS
You make it sounds so easy
I mean... nothing stops us from doing```ts
import { container } from 'tsyringe';
import { Tokens } from '#lib/util';
export class Base {
public get client() {
return container.resolve(Tokens.CLIENT);
}
}```
was looking at the Rest impl and have you considered making it an interface so people can use custom rest instances? https://github.com/discordjs/discord.js-next/blob/8a0f8cc547927dc5e6699c8fd9cda341b980a4a0/packages/rest/src/lib/RequestManager.ts#L126
Why would you?
big bots who microservice parts of their code would find it very useful, and i don't see a reason not to make that an option
?
You dont seem to understand -next very well
You can already use the rest package independent
It's not REST what you want to edit, Stitch, it's RequestHandler, which implements IHandler (see https://github.com/discordjs/discord.js-next/blob/8a0f8cc547927dc5e6699c8fd9cda341b980a4a0/packages/rest/src/lib/RequestManager.ts#L124)
that's not what im talking about at all...
And that
okay yeah that's a better answer
REST is just a controller, but the hard work is done in IHandler
Yeah its just that your explanation why you want it modifiable didnt make much sense
the tsyringe container would be global tho?
wouldnt we need a new container per client instance? (or what is the "defining" instance in -next)
well handler is just a request handling strategy right? as-in burst or sequential?
Generally, DI containers are global
And... what even is your use case for more than one client per process?
thats not what im talking about kyra, im talking about REST being an interface so people can use their own controllers (maybe one could proxy requests to a server that does ratelimit handling, like spectacles' proxy)
I'm talking to CHY, sorry
i was replying to this
so as soon as I use tsyringe for my own stuff I would mess with the container that d.js uses.
anyway, you probably just wrote this down quick, just wanted to notice that we need own containers for d.js (or "defining" instances? idk)
If you want to make your own REST, just do so, Stitch
Well we would generally use Symbols when registering stuff in our container, so its impossible to overwrite our stuff
If you make a class extending REST, e.g. StitchREST, RequestManager#rest would be an instance of it, per: https://github.com/discordjs/discord.js-next/blob/8a0f8cc547927dc5e6699c8fd9cda341b980a4a0/packages/rest/src/lib/REST.ts#L74
Except you use the exact same symbols
okay cool, that works
LGTM on the usage of symbols for this
SequentialHandler
I'd rather not allow that, because ratelimits are the number 1 thing that WILL get you banned temporarily or permanently from Discord if done wrong
IF we want to truly make REST extendable, the interface needs to be VERY strict
technically i can already do that extending REST, can't i?
Unless you overwrite the RequestManager's function that returns a different handler, no
that would mean going down the chain
even then
what you need is to just change api endpoint
to your proxy
and leave the rest to us

the point of the proxy is it handles ratelimits, not whatever process that is using it
yeah and?
You forward all requests to the proxy
and return some form of headers that just tell us we can keep requesting (limit 5, remaining 5, boom done)
okay fair enough i guess
const proxiedRest = new REST({ api: 'http://localhost:1234' });
proxiedRest.get('/gateway/bot');
the one proxy that im referring to returns no ratelimit info
so it wouldn't work with your proposal
we have defaults anyways
are they set to zero for everything? XD
// Update the total number of requests that can be made before the rate limit resets
this.limit = limit ? Number(limit) : Infinity;
// Update the number of remaining requests that can be made before the rate limit resets
this.remaining = remaining ? Number(remaining) : 1;
// Update the time when this rate limit resets (reset-after is in seconds)
this.reset = reset ? Number(reset) * 1000 + Date.now() + this.manager.rest.options.offset : Date.now();
Infinite limit, 1 remaining, if no headers are present
so basically
handling ratelimits in the rest manager would defeat the purpose of a proxy
it'll work just fine
Thanks
If Stitch is talking about a proxy proxy, and not a cheap "proxy", we currently don't support them if you think about it
I don't recall any place in our code taking an https.Agent instance (which iirc is required for proxies to work)
I mean there is no point
its not even how spectacles works
you dont use spectacles REST with spectacles proxy
you use only spectacles proxy and write your own quick rest handler
yes
and if i wanted my d.js bot with it, that wouldn't be possible if the d.js rest-handler is enforcing ratelimits itself
...?
Stitch
Why would you do that?
you do understand that, if no headers are present, it'll just...not..deal..with ratelimits right
A limit of Infinity and remaining of always 1 means it'll just pass through
ah is that so? nice
Thats like me saying, I have the same bot on an eris music bot, but all the other functionality on a d.js bot
Why cant I use the same proxy?
Thats such a weird request
it's not as weird as you make it out to be. kyra, for example, wants to microservice everything Moderation-related from skyra. if the new service is doing anything REST related, it's gonna need a proxy for both applications to keep track of ratelimits
Yes, but he uses libraries that are meant to work that way
You can't shoehorn this solution
Its the reason I use spectacles, and not a mix of spectacles and djs and eris
I just have a single message broker for example that makes sure all things go into the correct proxy
If we'd support every use case for this, this would mean our "unknown error" ratio would go through the roof because we can not guarantee someone doesnt mess with something we have no control over and suddenly want support for it
but wouldn't -next's rest handler being customizable be a good solution to this? it uses the proxy, and we can still use all the convenience methods d.js provides. and if vlad is right, we can do that already
I don't think you understand how this works
If you want multiple bots to proxy into a single ratelimit, you would build a server that WRAPS -next' rest handler
And then make requests to that wrapper
Not the other way around
yes, and making REST an interface would solve that?
Thats exactly how spectacles works
No?
How?
You wouldnt need any of the rest handlers logic
The proxy handles that
You just blindly fire request to the proxy, doesnt matter what it is
lets assume REST is an interface with get(), post() and put(). i implement it to send http requests to my proxy server, which then does the actual ratelimit handling.
No, crawl, what Stitch wants is to forward all requests done through -next's rest to some local endpoint, to a global "proxy" (in go or otherwise) that handles the rest
I understand that
which, as I said, is already doable
But thats unneeded
that way i can use message.channel.send() and it works with my proxy 😉
...
Yeaaaaah, thats exactly what I meant with shoehorning a solution
Y'all ignoring me intentionally? Stitch, just override the api endpoint. That's all. If your proxy runs and it catches all requests and works PROPERLY (do note its your responsibility if you fuck ratelimits up and get banned), d.js will just pass requests on
or rather, not d.js but -next's rest
IN FACT, the EXACT SAME is possible right now in v12
Same logic
yes vlad i gotcha, i did mention you said it was already possible
override the api base
You talk about microservices but say stuff like message.channel.send when you wouldnt even theoretically have a cache like that in mutliple services because its not feasible
that wasn't the point, the point is i can continue using discord.js' REST functions with my own proxy and handler
yes vlad i get it, don't worry
If it wasn't the point don't bring up the points of microservices
now you're just taking whatever i say out of context, im not continuing this, especially since the "issue" is already resolved anyway
If you continue to dismiss the claims that proper microservices do not rely on a monolithic library like d.js to properly function and just try to have it your way, go ahead.
You brought examples into this with skyra that have no foundation because its simply not how you would even design such a system
My opinion on this is that we shouldn't go too much overboard, -next is still very young and while many things are in the design stage, most aren't even in that step, naturally, -next will evolve with time just like any other OSS project
I personally think that having a functional REST package that works for the typical case, is priority
We can enhance it later with things we might need in the future, but as for now, we aren't very sure about everything
I'd say give the new REST a shot once it's released, and if you can find a solution (Crawl and Vlad proposed some) that works for you, then you don't have anything else to worry about
Kinda like what I want, a handler that spreads out requests evenly in the reset window (so if we can do 4 requests a second it'd spread them out as evenly as possible), but thats offtopic
doing some personal testing, exporting a class also exports the built in interface for the class
^ conversation relating to the ts recode and exporting interfaces
There are chances that we might keep Structures, mostly because it's the polar opposite of DI
The only feasible alternative a friend of mine (who's well versed in DI and many other programming patterns) was the transformer pattern, which is basically the same as Structures but less optimised and bulkier
@tacit crypt @unique axle my point with the PR is to e n f o r c e the consistency, not just change all cases into using the same bracket type (have no idea how to word this).
With the PR in place it means: route building is property access, requests are function calls, no way for it to be confusing like that.
Currently (even with the PR), you can still use .guilds(id), so if the PR gets merged and turns out I missed some changes, the library won't break.
When we're sure that all places use the correct way, we can make it error - e n f o r c ing the new style.
To be honest, I'm unsure if we'll go for that path, we can very well replace REST with -next's once Smugen's PR lands (since we need the other changes)
^
I'm more in favor of x.y.z.post(), x.y(id).z.post() or x.y(id).z(member).post() than any other variation
unenforced consistency
I think thats a pretty consistent pattern
Would it be a good idea to add some sort of error throw on GuildMemberManager#fetch if the correct intent isn't enabled?
wouldn't that be done on api side already
it'll just timeout
Could Message#authorID be added for partial messages?
hmm .. i mentioned something similar yesterday to be used with Guild#owner, suggesting it should be GuildMember | PartialGuildMember. the only 'valid' property of PartialGuildMember is id and it has a fetch function similar to GuildMember#fetch
perhaps the same thing could be applied here? PartialUser where only id is valid with a fetch function?
what's the reasoning for Message? seeing that both user and member data are included in the message payload?
does running .fetch add to its respective cache?
@unique axle author.id is known in MESSAGE_UPDATE, so I can save an api call by using it on the partial structure and not fetch it.
all i need there is message.id, message.authorID, message.content
which I should not have to fetch
discord always sends an author object, not just an author id
so whenever djs has a message it should have an author object
so authorID would never be present if author.id isnt
It doesnt use the API, it uses the ws opcode
@oak quail but it is not
when message.partial is true, message.author.id throws cannot access id of undefined
well that means that djs is constructing a message object from just an id
why though
Try enabling user partials, @snow crypt
Still (node:7640) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'id' of null when message.partial
The docs says otherwise
Unlike [message] creates, message updates may contain only a subset of the full message object payload (but will always contain an id and channel_id)
https://discord.com/developers/docs/topics/gateway#message-update
yes, no
I have edited the literally oldest message I could find in a server (which is only 1.5 years ago, but still not very new), and MESSAGE_UPDATE (using client.ws) emitted with author
Was it a webhook message?
no
Can you show the data object?
well i can redo it in a moment

well in that case you... still wouldn't have the author id
nothing djs can do about that
yeah fml
see above the raw event with author.id and then messageUpdate where newMessage.author is non-existent
@copper garden
Apparently the author prop was left out in the client.actions.getMessage function
Looks like the method assumes that it'll either get a message object like { message: Message {...} } or just { id: "...", channel_id: "...", guild_id: "..." } (partial message)
We looked into this the other day, getMessage doesnt pass the author to getPayload
and.. is that intentional?
Probably not 😄
@ruby terrace I don’t see how that our job to maintain lol
And as I read that, several other libs decided against too
It's not something that the library should handle automatically, it should be a developer choice, but the developer currently can't make that choice
Huh
I would argue it’s discord’s fault and that’s it
We do exactly as it should work
It just so happens that discord fucks up
I can't think of one of the top of my head, but there is a point to be made for a use case where you do want to change solely allowed_mentions.
I know this is a stretch, but maybe mentioning a user, but disabling the highlight afterwards.
Editing with allowed_mentions is always going to be cosmetic, even with content come to think of it
I’m not against a fix, but I sure wouldnt put any high priority on it
I wonder if it affects the inbox

