feat: cache#testAdapter

This commit is contained in:
MARCROCK22 2024-06-24 21:01:14 +00:00
parent ef5370462b
commit 1ee3edfc5b
20 changed files with 385 additions and 68 deletions

294
src/cache/index.ts vendored
View File

@ -1,4 +1,4 @@
import type { If } from '../common'; import { Logger, type If } from '../common';
import type { Adapter } from './adapters'; import type { Adapter } from './adapters';
@ -16,7 +16,20 @@ import { Threads } from './resources/threads';
import { VoiceStates } from './resources/voice-states'; import { VoiceStates } from './resources/voice-states';
import { Bans } from './resources/bans'; import { Bans } from './resources/bans';
import { ChannelType, GatewayIntentBits, type GatewayDispatchPayload } from 'discord-api-types/v10'; import {
type APIChannel,
type APIEmoji,
type APIGuildMember,
type APIOverwrite,
type APISticker,
type APITextChannel,
type APIUser,
ChannelType,
GatewayIntentBits,
GuildMemberFlags,
OverwriteType,
type GatewayDispatchPayload,
} from 'discord-api-types/v10';
import type { InternalOptions, UsingClient } from '../commands'; import type { InternalOptions, UsingClient } from '../commands';
import { Overwrites } from './resources/overwrites'; import { Overwrites } from './resources/overwrites';
import { Messages } from './resources/messages'; import { Messages } from './resources/messages';
@ -99,6 +112,8 @@ export class Cache {
messages?: Messages; messages?: Messages;
bans?: Bans; bans?: Bans;
__logger__?: Logger;
constructor( constructor(
public intents: number, public intents: number,
public adapter: Adapter, public adapter: Adapter,
@ -419,7 +434,6 @@ export class Cache {
case 'stageInstances': case 'stageInstances':
case 'emojis': case 'emojis':
case 'overwrites': case 'overwrites':
case 'bans':
case 'messages': case 'messages':
{ {
if (!this[type]?.filter(data, id, guildId)) continue; if (!this[type]?.filter(data, id, guildId)) continue;
@ -437,6 +451,7 @@ export class Cache {
allData.push([this[type]!.hashId(id), this[type]!.parse(data, id, guildId!)]); allData.push([this[type]!.hashId(id), this[type]!.parse(data, id, guildId!)]);
} }
break; break;
case 'bans':
case 'voiceStates': case 'voiceStates':
case 'members': case 'members':
{ {
@ -525,14 +540,14 @@ export class Cache {
case 'GUILD_EMOJIS_UPDATE': case 'GUILD_EMOJIS_UPDATE':
await this.emojis?.remove(await this.emojis?.keys(event.d.guild_id), event.d.guild_id); await this.emojis?.remove(await this.emojis?.keys(event.d.guild_id), event.d.guild_id);
await this.emojis?.set( await this.emojis?.set(
event.d.emojis.map(x => [x.id!, x]), event.d.emojis.map(x => [x.id!, x] as [string, APIEmoji]),
event.d.guild_id, event.d.guild_id,
); );
break; break;
case 'GUILD_STICKERS_UPDATE': case 'GUILD_STICKERS_UPDATE':
await this.stickers?.remove(await this.stickers?.keys(event.d.guild_id), event.d.guild_id); await this.stickers?.remove(await this.stickers?.keys(event.d.guild_id), event.d.guild_id);
await this.stickers?.set( await this.stickers?.set(
event.d.stickers.map(x => [x.id, x] as const), event.d.stickers.map(x => [x.id, x] as [string, APISticker]),
event.d.guild_id, event.d.guild_id,
); );
break; break;
@ -594,4 +609,273 @@ export class Cache {
break; break;
} }
} }
async testAdapter() {
this.__logger__ ??= new Logger({
name: '[CACHE]',
});
await this.adapter.flush();
// this method will only check the cache for `users`, `members` y `channels`
// likewise these have the three types of resources (GuildRelatedResource, GuildBasedResource, BaseResource)
// will also check `overwrites`, since the latter stores an array not as an object but as data.
await this.testUsersAndMembers();
await this.testChannelsAndOverwrites();
this.__logger__.info('The adapter seems to work properly');
this.__logger__.debug('Flushing adapter');
delete this.__logger__;
await this.adapter.flush();
}
private async testUsersAndMembers() {
if (!this.users) throw new Error('Users cache disabled, you should enable it for this.');
if (!this.members) throw new Error('Members cache disabled, you should enable it for this.');
function createUser(name: string): APIUser {
return {
avatar: 'xdxd',
discriminator: '0',
global_name: name,
id: `${Math.random()}`.slice(2),
username: `@seyfert/${name}`,
};
}
function createMember(name: string): APIGuildMember {
return {
avatar: 'xdxd',
deaf: !false,
flags: GuildMemberFlags.StartedHomeActions,
joined_at: new Date().toISOString(),
mute: !true,
roles: ['111111111111'],
user: createUser(name),
};
}
const users: APIUser[] = [
createUser('witherking_'),
createUser('vanecia'),
createUser('socram'),
createUser('free'),
createUser('justevil'),
createUser('nobody'),
createUser('aaron'),
createUser('simxnet'),
createUser('yuzu'),
createUser('vyrek'),
createUser('marcrock'),
];
for (const user of users) {
await this.users.set(user.id, user);
}
if ((await this.users.values()).length !== users.length)
throw new Error('users.values() is not of the expected size.');
if ((await this.users.count()) !== users.length) throw new Error('users.count() is not of the expected amount');
for (const user of users) {
const cache = await this.users.raw(user.id);
if (!cache) throw new Error(`users.raw(${user.id}) has returned undefined!!!!!!`);
if (cache.username !== user.username)
throw new Error(
`users.raw(${user.id}).username is not of the expected value!!!!! (cache (${cache.username})) (expected value: (${user.username}))`,
);
if (cache.id !== user.id)
throw new Error(
`users.raw(${user.id}).id is not of the expected value!!!!!! (cache (${cache.id})) (expected value: (${user.id}))`,
);
}
this.__logger__!.info('the user cache seems to be alright.');
this.__logger__!.debug('Flushing adapter to clear users cache.');
await this.adapter.flush();
const guildMembers: Record<string, APIGuildMember[]> = {
'852531635252494346': [
createMember("witherking_'s member"),
createMember("vanecia's member"),
createMember("nobody's member"),
],
'1003825077969764412': [
createMember("free's member"),
createMember("socram's member"),
createMember("marcrock's member"),
createMember("justevil's member"),
createMember("vyrek's member"),
],
'876711213126520882': [
createMember("aaron's member"),
createMember("simxnet's member"),
createMember("yuzu's member"),
],
};
for (const guildId in guildMembers) {
const members = guildMembers[guildId];
for (const member of members) {
await this.members.set(member.user.id, guildId, member);
}
if ((await this.members.values(guildId)).length !== members.length)
throw new Error('members.values(guildId) is not of the expected size.');
if ((await this.members.count(guildId)) !== members.length)
throw new Error('members.count(guildId) is not of the expected amount');
for (const member of members) {
const cache = await this.members.raw(member.user.id, guildId);
if (!cache) throw new Error(`members.raw(${member.user.id}, ${guildId}) has returned undefined.`);
if (cache.roles[0] !== member.roles[0])
throw new Error(
`members.raw(${member.user.id}, ${guildId}).roles[0] is not the expected value: ${member.roles[0]} (cache: ${cache.roles[0]})`,
);
if (cache.user.username !== member.user.username)
throw new Error(
`members.raw(${member.user.id}, ${guildId}).user.username is not the expected value!!!!!! (cache (${cache.user.username})) (expected value: (${member.user.username}))`,
);
if (cache.user.id !== member.user.id)
throw new Error(
`members.raw(${member.user.id}, ${guildId}).user.id is not the expected value!!!!!! (cache (${cache.user.id})) (expected value: (${member.user.id}))`,
);
}
}
if ((await this.members.values('*')).length !== Object.values(guildMembers).flat().length)
throw new Error('members.values(*) is not of the expected size');
if ((await this.members.count('*')) !== Object.values(guildMembers).flat().length)
throw new Error('the global amount of members.count(*) is not the expected amount');
this.__logger__!.info('the member cache seems to be alright.');
}
private async testChannelsAndOverwrites() {
if (!this.channels) throw new Error('Channels cache disabled, you should enable it for this.');
if (!this.overwrites) throw new Error('Overwrites cache disabled, you should enable it for this.');
function createChannel(name: string): APITextChannel {
return {
id: `${Math.random()}`.slice(2),
name,
type: ChannelType.GuildText,
position: Math.random() > 0.5 ? 1 : 0,
};
}
function createOverwrites(name: string): (APIOverwrite & { channel_id: string })[] {
const channel_id = `${Math.random()}`.slice(2);
return [
{
id: name,
allow: '8',
deny: '2',
type: OverwriteType.Role,
channel_id,
},
{
id: `${name}-2`,
allow: '8',
deny: '2',
type: OverwriteType.Role,
channel_id,
},
];
}
const guildChannels: Record<string, APIChannel[]> = {
'852531635252494346': [
createChannel("witherking_'s channel"),
createChannel("vanecia's channel"),
createChannel("nobody's channel"),
],
'1003825077969764412': [
createChannel("free's channel"),
createChannel("socram's channel"),
createChannel("marcrock's channel"),
createChannel("justevil's channel"),
createChannel("vyrek's channel"),
],
'876711213126520882': [
createChannel("aaron's channel"),
createChannel("simxnet's channel"),
createChannel("yuzu's channel"),
],
};
for (const guildId in guildChannels) {
const channels = guildChannels[guildId];
for (const channel of channels) {
await this.channels.set(channel.id, guildId, channel);
}
if ((await this.channels.values(guildId)).length !== channels.length)
throw new Error('channels.values(guildId) is not of the expected size');
if ((await this.channels.count(guildId)) !== channels.length)
throw new Error('channels.count(guildId) is not of the expected amount');
for (const channel of channels) {
const cache = await this.channels.raw(channel.id);
if (!cache) throw new Error(`channels.raw(${channel.id}) has returned undefined!!!!!!`);
if (cache.type !== ChannelType.GuildText)
throw new Error(
`channels.raw(${channel.id}).type is not of the expected type: ${channel.type}!!!!!!!! (mismatched type: ${cache.type})`,
);
if (cache.name !== channel.name)
throw new Error(
`channels.raw(${channel.id}).name is not the expected value!!!!!! (cache (${cache.name})) (expected value: (${channel.name}))`,
);
if (cache.id !== channel.id)
throw new Error(
`channels.raw(${channel.id}).id is not the expected value!!!!!! (cache (${cache.id})) (expected value: (${channel.id}))`,
);
}
}
if ((await this.channels.values('*')).length !== Object.values(guildChannels).flat().length)
throw new Error('channels.values(*) is not of the expected size');
if ((await this.channels.count('*')) !== Object.values(guildChannels).flat().length)
throw new Error('channels.count(*) is not of the expected amount');
this.__logger__!.info('the channel cache seems to be alright');
const guildOverwrites: Record<string, ReturnType<typeof createOverwrites>[]> = {
'852531635252494346': [
createOverwrites("witherking_'s channel"),
createOverwrites("vanecia's channel"),
createOverwrites("nobody's channel"),
],
'1003825077969764412': [
createOverwrites("free's channel"),
createOverwrites("socram's channel"),
createOverwrites("marcrock's channel"),
createOverwrites("justevil's channel"),
createOverwrites("vyrek's channel"),
],
'876711213126520882': [
createOverwrites("aaron's channel"),
createOverwrites("simxnet's channel"),
createOverwrites("yuzu's channel"),
],
};
for (const guildId in guildOverwrites) {
const bulkOverwrites = guildOverwrites[guildId];
for (const overwrites of bulkOverwrites) {
await this.overwrites.set(overwrites[0].channel_id, guildId, overwrites);
}
if ((await this.overwrites.values(guildId)).length !== bulkOverwrites.length)
throw new Error('overwrites.values(channelId) is not of the expected size');
if ((await this.overwrites.count(guildId)) !== bulkOverwrites.length)
throw new Error('overwrites.count(channelId) is not of the expected amount');
for (const overwrites of bulkOverwrites) {
const cache = await this.overwrites.raw(overwrites[0].channel_id);
if (!cache) throw new Error(`overwrites.raw(${overwrites[0].channel_id}) has returned undefined!!!!!!`);
if (cache.length !== overwrites.length)
throw new Error(
`overwrites.raw(${overwrites[0].channel_id}).length is not of the expected length!!!!!! (cache (${cache.length})) (expected value: (${overwrites.length}))`,
);
for (const overwrite of overwrites) {
if (
!cache.some(x => {
return (
x.allow === overwrite.allow &&
x.deny === overwrite.deny &&
x.guild_id === guildId &&
x.id === overwrite.id &&
x.type === overwrite.type
);
})
)
throw new Error("cache wasn't found in the overwrites cache");
}
}
}
this.__logger__!.info('the overwrites cache seems to be alright.');
}
} }

View File

@ -1,9 +1,9 @@
import type { APIBan } from 'discord-api-types/v10'; import type { APIBan, GatewayGuildBanModifyDispatchData } from 'discord-api-types/v10';
import type { ReturnCache } from '../..'; import type { ReturnCache } from '../..';
import { fakePromise } from '../../common'; import { fakePromise } from '../../common';
import { GuildBasedResource } from './default/guild-based'; import { GuildBasedResource } from './default/guild-based';
import { type GuildBanStructure, Transformers } from '../../client/transformers'; import { type GuildBanStructure, Transformers } from '../../client/transformers';
export class Bans extends GuildBasedResource { export class Bans extends GuildBasedResource<any, GatewayGuildBanModifyDispatchData | APIBan> {
namespace = 'ban'; namespace = 'ban';
//@ts-expect-error //@ts-expect-error

View File

@ -5,7 +5,7 @@ import channelFrom from '../../structures/channels';
import type { ReturnCache } from '../index'; import type { ReturnCache } from '../index';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
export class Channels extends GuildRelatedResource { export class Channels extends GuildRelatedResource<any, APIChannel> {
namespace = 'channel'; namespace = 'channel';
parse(data: APIChannel, id: string, guild_id: string) { parse(data: APIChannel, id: string, guild_id: string) {

View File

@ -3,7 +3,7 @@ import type { UsingClient } from '../../../commands';
import { fakePromise } from '../../../common'; import { fakePromise } from '../../../common';
import type { Cache, ReturnCache } from '../../index'; import type { Cache, ReturnCache } from '../../index';
export class BaseResource<T = any> { export class BaseResource<T = any, S = any> {
client!: UsingClient; client!: UsingClient;
namespace = 'base'; namespace = 'base';
@ -37,7 +37,7 @@ export class BaseResource<T = any> {
return; return;
} }
setIfNI(intent: keyof typeof GatewayIntentBits, id: string, data: any) { setIfNI(intent: keyof typeof GatewayIntentBits, id: string, data: S) {
if (!this.cache.hasIntent(intent)) { if (!this.cache.hasIntent(intent)) {
return this.set(id, data); return this.set(id, data);
} }
@ -51,12 +51,12 @@ export class BaseResource<T = any> {
return fakePromise(this.adapter.bulkGet(ids.map(id => this.hashId(id)))).then(x => x.filter(y => y)); return fakePromise(this.adapter.bulkGet(ids.map(id => this.hashId(id)))).then(x => x.filter(y => y));
} }
set(id: string, data: any) { set(id: string, data: S) {
if (!this.filter(data, id)) return; if (!this.filter(data, id)) return;
return fakePromise(this.addToRelationship(id)).then(() => this.adapter.set(this.hashId(id), data)); return fakePromise(this.addToRelationship(id)).then(() => this.adapter.set(this.hashId(id), data));
} }
patch(id: string, data: any) { patch(id: string, data: S) {
if (!this.filter(data, id)) return; if (!this.filter(data, id)) return;
return fakePromise(this.addToRelationship(id)).then(() => this.adapter.patch(false, this.hashId(id), data)); return fakePromise(this.addToRelationship(id)).then(() => this.adapter.patch(false, this.hashId(id), data));
} }
@ -73,12 +73,12 @@ export class BaseResource<T = any> {
return this.adapter.values(this.namespace) as T[]; return this.adapter.values(this.namespace) as T[];
} }
count() { count(): ReturnCache<number> {
return this.adapter.count(this.namespace); return this.adapter.count(this.namespace) as number;
} }
contains(id: string) { contains(id: string): ReturnCache<boolean> {
return this.adapter.contains(this.namespace, id); return this.adapter.contains(this.namespace, id) as boolean;
} }
getToRelationship() { getToRelationship() {
@ -94,6 +94,6 @@ export class BaseResource<T = any> {
} }
hashId(id: string) { hashId(id: string) {
return `${this.namespace}.${id}`; return id.startsWith(this.namespace) ? id : `${this.namespace}.${id}`;
} }
} }

View File

@ -3,7 +3,7 @@ import type { UsingClient } from '../../../commands';
import { fakePromise } from '../../../common'; import { fakePromise } from '../../../common';
import type { Cache, ReturnCache } from '../../index'; import type { Cache, ReturnCache } from '../../index';
export class GuildBasedResource<T = any> { export class GuildBasedResource<T = any, S = any> {
client!: UsingClient; client!: UsingClient;
namespace = 'base'; namespace = 'base';
@ -43,7 +43,7 @@ export class GuildBasedResource<T = any> {
return; return;
} }
setIfNI(intent: keyof typeof GatewayIntentBits, id: string, guildId: string, data: any) { setIfNI(intent: keyof typeof GatewayIntentBits, id: string, guildId: string, data: S) {
if (!this.cache.hasIntent(intent)) { if (!this.cache.hasIntent(intent)) {
return this.set(id, guildId, data); return this.set(id, guildId, data);
} }
@ -57,13 +57,12 @@ export class GuildBasedResource<T = any> {
return fakePromise(this.adapter.bulkGet(ids.map(id => this.hashGuildId(guild, id)))).then(x => x.filter(y => y)); return fakePromise(this.adapter.bulkGet(ids.map(id => this.hashGuildId(guild, id)))).then(x => x.filter(y => y));
} }
set(__keys: string, guild: string, data: any): ReturnCache<void>; set(__keys: string, guild: string, data: S): ReturnCache<void>;
set(__keys: [string, any][], guild: string): ReturnCache<void>; set(__keys: [string, S][], guild: string): ReturnCache<void>;
set(__keys: string | [string, any][], guild: string, data?: any): ReturnCache<void> { set(__keys: string | [string, S][], guild: string, data?: S): ReturnCache<void> {
const keys = (Array.isArray(__keys) ? __keys : [[__keys, data]]).filter(x => this.filter(x[1], x[0], guild)) as [ const keys = (Array.isArray(__keys) ? __keys : [[__keys, data]]).filter(x =>
string, this.filter(x[1], x[0] as string, guild),
any, ) as [string, any][];
][];
return fakePromise( return fakePromise(
this.addToRelationship( this.addToRelationship(
@ -79,7 +78,7 @@ export class GuildBasedResource<T = any> {
) as void; ) as void;
} }
patch(__keys: string, guild: string, data: any): ReturnCache<void>; patch(__keys: string, guild: string, data: S): ReturnCache<void>;
patch(__keys: [string, any][], guild: string): ReturnCache<void>; patch(__keys: [string, any][], guild: string): ReturnCache<void>;
patch(__keys: string | [string, any][], guild: string, data?: any): ReturnCache<void> { patch(__keys: string | [string, any][], guild: string, data?: any): ReturnCache<void> {
const keys = (Array.isArray(__keys) ? __keys : [[__keys, data]]).filter(x => this.filter(x[1], x[0], guild)) as [ const keys = (Array.isArray(__keys) ? __keys : [[__keys, data]]).filter(x => this.filter(x[1], x[0], guild)) as [
@ -144,10 +143,10 @@ export class GuildBasedResource<T = any> {
} }
hashId(id: string) { hashId(id: string) {
return `${this.namespace}.${id}`; return id.startsWith(this.namespace) ? id : `${this.namespace}.${id}`;
} }
hashGuildId(guild: string, id: string) { hashGuildId(guild: string, id: string) {
return `${this.namespace}.${guild}.${id}`; return id.startsWith(this.namespace) ? id : `${this.namespace}.${guild}.${id}`;
} }
} }

View File

@ -4,7 +4,7 @@ import type { UsingClient } from '../../../commands';
import { fakePromise } from '../../../common'; import { fakePromise } from '../../../common';
import type { Cache, ReturnCache } from '../../index'; import type { Cache, ReturnCache } from '../../index';
export class GuildRelatedResource<T = any> { export class GuildRelatedResource<T = any, S = any> {
client!: BaseClient; client!: BaseClient;
namespace = 'base'; namespace = 'base';
@ -43,7 +43,7 @@ export class GuildRelatedResource<T = any> {
} }
} }
setIfNI(intent: keyof typeof GatewayIntentBits, id: string, guildId: string, data: any) { setIfNI(intent: keyof typeof GatewayIntentBits, id: string, guildId: string, data: S) {
if (!this.cache.hasIntent(intent)) { if (!this.cache.hasIntent(intent)) {
return this.set(id, guildId, data); return this.set(id, guildId, data);
} }
@ -57,13 +57,12 @@ export class GuildRelatedResource<T = any> {
return fakePromise(this.adapter.bulkGet(ids.map(x => this.hashId(x)))).then(x => x.filter(y => y)); return fakePromise(this.adapter.bulkGet(ids.map(x => this.hashId(x)))).then(x => x.filter(y => y));
} }
set(__keys: string, guild: string, data: any): ReturnCache<void>; set(__keys: string, guild: string, data: S): ReturnCache<void>;
set(__keys: [string, any][], guild: string): ReturnCache<void>; set(__keys: [string, S][], guild: string): ReturnCache<void>;
set(__keys: string | [string, any][], guild: string, data?: any): ReturnCache<void> { set(__keys: string | [string, S][], guild: string, data?: S): ReturnCache<void> {
const keys = (Array.isArray(__keys) ? __keys : [[__keys, data]]).filter(x => this.filter(x[1], x[0], guild)) as [ const keys = (Array.isArray(__keys) ? __keys : [[__keys, data]]).filter(x =>
string, this.filter(x[1], x[0] as string, guild),
any, ) as [string, any][];
][];
return fakePromise( return fakePromise(
this.addToRelationship( this.addToRelationship(
@ -137,12 +136,14 @@ export class GuildRelatedResource<T = any> {
) as (T & { guild_id: string })[]); ) as (T & { guild_id: string })[]);
} }
count(to: string) { count(to: string): ReturnCache<number> {
return to === '*' ? fakePromise(this.keys(to)).then(x => x.length) : this.adapter.count(this.hashId(to)); return to === '*'
? fakePromise(this.keys(to)).then(x => x.length)
: (this.adapter.count(this.hashId(to)) as number);
} }
contains(id: string, guild: string) { contains(id: string, guild: string): ReturnCache<boolean> {
return this.adapter.contains(this.hashId(guild), id); return this.adapter.contains(this.hashId(guild), id) as boolean;
} }
getToRelationship(guild: string) { getToRelationship(guild: string) {
@ -162,6 +163,6 @@ export class GuildRelatedResource<T = any> {
} }
hashId(id: string) { hashId(id: string) {
return `${this.namespace}.${id}`; return id.startsWith(this.namespace) ? id : `${this.namespace}.${id}`;
} }
} }

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
import { type GuildEmojiStructure, Transformers } from '../../client/transformers'; import { type GuildEmojiStructure, Transformers } from '../../client/transformers';
export class Emojis extends GuildRelatedResource { export class Emojis extends GuildRelatedResource<any, APIEmoji> {
namespace = 'emoji'; namespace = 'emoji';
//@ts-expect-error //@ts-expect-error

View File

@ -1,10 +1,10 @@
import type { APIGuild } from 'discord-api-types/v10'; import type { APIGuild, GatewayGuildCreateDispatchData } from 'discord-api-types/v10';
import type { Cache, ReturnCache } from '..'; import type { Cache, ReturnCache } from '..';
import { fakePromise } from '../../common'; import { fakePromise } from '../../common';
import { BaseResource } from './default/base'; import { BaseResource } from './default/base';
import { type GuildStructure, Transformers } from '../../client/transformers'; import { type GuildStructure, Transformers } from '../../client/transformers';
export class Guilds extends BaseResource { export class Guilds extends BaseResource<any, APIGuild | GatewayGuildCreateDispatchData> {
namespace = 'guild'; namespace = 'guild';
//@ts-expect-error //@ts-expect-error
@ -35,22 +35,34 @@ export class Guilds extends BaseResource {
} }
override async remove(id: string) { override async remove(id: string) {
const keysChannels = this.cache.channels?.keys(id) ?? [];
await this.cache.adapter.bulkRemove( await this.cache.adapter.bulkRemove(
( (
await Promise.all([ await Promise.all([
this.cache.members?.keys(id) ?? [], this.cache.members?.keys(id) ?? [],
this.cache.roles?.keys(id) ?? [], this.cache.roles?.keys(id) ?? [],
this.cache.channels?.keys(id) ?? [], keysChannels,
this.cache.emojis?.keys(id) ?? [], this.cache.emojis?.keys(id) ?? [],
this.cache.stickers?.keys(id) ?? [], this.cache.stickers?.keys(id) ?? [],
this.cache.voiceStates?.keys(id) ?? [], this.cache.voiceStates?.keys(id) ?? [],
this.cache.presences?.keys(id) ?? [], this.cache.presences?.keys(id) ?? [],
this.cache.threads?.keys(id) ?? [], this.cache.threads?.keys(id) ?? [],
this.cache.stageInstances?.keys(id) ?? [], this.cache.stageInstances?.keys(id) ?? [],
this.cache.bans?.keys(id) ?? [],
]) ])
).flat(), ).flat(),
); );
if (this.cache.messages && this.cache.channels) {
const keysMessages: string[] = [];
for (const i of keysChannels) {
const channelId = i.slice(this.cache.channels.namespace.length + 1);
const messages = await this.cache.messages.keys(channelId);
keysMessages.push(...messages);
}
if (keysMessages.length) await this.cache.adapter.bulkRemove(keysMessages);
}
await this.cache.adapter.removeRelationship( await this.cache.adapter.removeRelationship(
[ [
this.cache.members?.hashId(id), this.cache.members?.hashId(id),

View File

@ -3,7 +3,7 @@ import type { ReturnCache } from '../..';
import { fakePromise } from '../../common'; import { fakePromise } from '../../common';
import { GuildBasedResource } from './default/guild-based'; import { GuildBasedResource } from './default/guild-based';
import { type GuildMemberStructure, Transformers } from '../../client/transformers'; import { type GuildMemberStructure, Transformers } from '../../client/transformers';
export class Members extends GuildBasedResource { export class Members extends GuildBasedResource<any, APIGuildMember> {
namespace = 'member'; namespace = 'member';
//@ts-expect-error //@ts-expect-error

View File

@ -4,7 +4,7 @@ import type { MessageData, ReturnCache } from '../..';
import { fakePromise } from '../../common'; import { fakePromise } from '../../common';
import { type MessageStructure, Transformers } from '../../client/transformers'; import { type MessageStructure, Transformers } from '../../client/transformers';
export class Messages extends GuildRelatedResource { export class Messages extends GuildRelatedResource<any, APIMessage> {
namespace = 'message'; namespace = 'message';
//@ts-expect-error //@ts-expect-error
@ -48,8 +48,8 @@ export class Messages extends GuildRelatedResource {
); );
} }
override values(guild: string): ReturnCache<MessageStructure[]> { override values(channel: string): ReturnCache<MessageStructure[]> {
return fakePromise(super.values(guild) as APIMessageResource[]).then(messages => { return fakePromise(super.values(channel) as APIMessageResource[]).then(messages => {
const hashes: (string | undefined)[] = this.cache.users const hashes: (string | undefined)[] = this.cache.users
? messages.map(x => (x.user_id ? this.cache.users!.hashId(x.user_id) : undefined)) ? messages.map(x => (x.user_id ? this.cache.users!.hashId(x.user_id) : undefined))
: []; : [];
@ -63,6 +63,10 @@ export class Messages extends GuildRelatedResource {
}); });
}); });
} }
keys(channel: string) {
return super.keys(channel);
}
} }
export type APIMessageResource = Omit<APIMessage, 'author'> & { user_id?: string }; export type APIMessageResource = Omit<APIMessage, 'author'> & { user_id?: string };

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common/it/utils';
import { PermissionsBitField } from '../../structures/extra/Permissions'; import { PermissionsBitField } from '../../structures/extra/Permissions';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
export class Overwrites extends GuildRelatedResource { export class Overwrites extends GuildRelatedResource<any, APIOverwrite[]> {
namespace = 'overwrite'; namespace = 'overwrite';
//@ts-expect-error //@ts-expect-error
@ -19,6 +19,10 @@ export class Overwrites extends GuildRelatedResource {
return data; return data;
} }
raw(id: string): ReturnCache<(APIOverwrite & { guild_id: string })[]> {
return super.get(id);
}
override get( override get(
id: string, id: string,
): ReturnCache< ): ReturnCache<

View File

@ -1,7 +1,7 @@
import type { GatewayPresenceUpdate } from 'discord-api-types/v10'; import type { GatewayPresenceUpdate } from 'discord-api-types/v10';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
export class Presences extends GuildRelatedResource<PresenceResource> { export class Presences extends GuildRelatedResource<PresenceResource, GatewayPresenceUpdate> {
namespace = 'presence'; namespace = 'presence';
//@ts-expect-error //@ts-expect-error
@ -17,4 +17,4 @@ export class Presences extends GuildRelatedResource<PresenceResource> {
} }
} }
export type PresenceResource = Omit<GatewayPresenceUpdate, 'user'> & { id: string }; export type PresenceResource = Omit<GatewayPresenceUpdate, 'user'> & { id: string; user_id: string };

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
import { type GuildRoleStructure, Transformers } from '../../client/transformers'; import { type GuildRoleStructure, Transformers } from '../../client/transformers';
export class Roles extends GuildRelatedResource { export class Roles extends GuildRelatedResource<any, APIRole> {
namespace = 'role'; namespace = 'role';
//@ts-expect-error //@ts-expect-error

View File

@ -1,7 +1,7 @@
import type { APIStageInstance } from 'discord-api-types/v10'; import type { APIStageInstance } from 'discord-api-types/v10';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
export class StageInstances extends GuildRelatedResource<APIStageInstance> { export class StageInstances extends GuildRelatedResource<APIStageInstance, APIStageInstance> {
namespace = 'stage_instance'; namespace = 'stage_instance';
//@ts-expect-error //@ts-expect-error

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
import { type StickerStructure, Transformers } from '../../client/transformers'; import { type StickerStructure, Transformers } from '../../client/transformers';
export class Stickers extends GuildRelatedResource { export class Stickers extends GuildRelatedResource<any, APISticker> {
namespace = 'sticker'; namespace = 'sticker';
//@ts-expect-error //@ts-expect-error

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common';
import { GuildRelatedResource } from './default/guild-related'; import { GuildRelatedResource } from './default/guild-related';
import { type ThreadChannelStructure, Transformers } from '../../client/transformers'; import { type ThreadChannelStructure, Transformers } from '../../client/transformers';
export class Threads extends GuildRelatedResource { export class Threads extends GuildRelatedResource<any, APIThreadChannel> {
namespace = 'thread'; namespace = 'thread';
//@ts-expect-error //@ts-expect-error

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common';
import { BaseResource } from './default/base'; import { BaseResource } from './default/base';
import { Transformers, type UserStructure } from '../../client/transformers'; import { Transformers, type UserStructure } from '../../client/transformers';
export class Users extends BaseResource { export class Users extends BaseResource<any, APIUser> {
namespace = 'user'; namespace = 'user';
//@ts-expect-error //@ts-expect-error

View File

@ -4,7 +4,7 @@ import { fakePromise } from '../../common';
import { GuildBasedResource } from './default/guild-based'; import { GuildBasedResource } from './default/guild-based';
import { Transformers, type VoiceStateStructure } from '../../client/transformers'; import { Transformers, type VoiceStateStructure } from '../../client/transformers';
export class VoiceStates extends GuildBasedResource { export class VoiceStates extends GuildBasedResource<any, GatewayVoiceState> {
namespace = 'voice_state'; namespace = 'voice_state';
//@ts-expect-error //@ts-expect-error

View File

@ -2,9 +2,9 @@ import type { GatewayDispatchPayload, GatewaySendPayload } from 'discord-api-typ
import { execSync } from 'node:child_process'; import { execSync } from 'node:child_process';
import { ApiHandler, Router } from '../../api'; import { ApiHandler, Router } from '../../api';
import { BaseClient, type InternalRuntimeConfig } from '../../client/base'; import { BaseClient, type InternalRuntimeConfig } from '../../client/base';
import { ShardManager, type ShardManagerOptions } from '../../websocket'; import { ShardManager, type ShardManagerDefaults, type ShardManagerOptions } from '../../websocket';
import { Logger } from '../it/logger'; import { Logger } from '../it/logger';
import type { MakeRequired } from '../types/util'; import type { MakePartial, MakeRequired } from '../types/util';
import { lazyLoadPackage } from '../it/utils'; import { lazyLoadPackage } from '../it/utils';
/** /**
@ -17,7 +17,7 @@ export class Watcher extends ShardManager {
}); });
rest?: ApiHandler; rest?: ApiHandler;
declare options: MakeRequired<WatcherOptions, 'intents' | 'token' | 'handlePayload' | 'info'>; declare options: MakeRequired<WatcherOptions, 'token' | 'info' | keyof typeof ShardManagerDefaults>;
/** /**
* Initializes a new instance of the Watcher class. * Initializes a new instance of the Watcher class.
@ -119,7 +119,19 @@ export class Watcher extends ShardManager {
} }
} }
export interface WatcherOptions extends Omit<ShardManager['options'], 'handlePayload' | 'info' | 'token' | 'intents'> { export interface WatcherOptions
extends MakePartial<
Omit<ShardManager['options'], 'handlePayload' | 'info' | 'token' | 'intents'>,
| 'compress'
| 'presence'
| 'properties'
| 'shardEnd'
| 'shardStart'
| 'spawnShardDelay'
| 'totalShards'
| 'url'
| 'version'
> {
filePath: string; filePath: string;
transpileCommand: string; transpileCommand: string;
srcPath: string; srcPath: string;

View File

@ -12,6 +12,7 @@ import { PermissionsBitField } from '../../structures/extra/Permissions';
import { BaseShorter } from './base'; import { BaseShorter } from './base';
import { MergeOptions } from '../it/utils'; import { MergeOptions } from '../it/utils';
import { type MessageStructure, Transformers } from '../../client/transformers'; import { type MessageStructure, Transformers } from '../../client/transformers';
import type { MakeRequired } from '../types/util';
export class ChannelShorter extends BaseShorter { export class ChannelShorter extends BaseShorter {
/** /**
@ -61,14 +62,14 @@ export class ChannelShorter extends BaseShorter {
body: RESTPatchAPIChannelJSONBody, body: RESTPatchAPIChannelJSONBody,
optional: ChannelShorterOptionalParams = { guildId: '@me' }, optional: ChannelShorterOptionalParams = { guildId: '@me' },
): Promise<AllChannels> { ): Promise<AllChannels> {
const options = MergeOptions<ChannelShorterOptionalParams>({ guildId: '@me' }, optional); const options = MergeOptions<MakeRequired<ChannelShorterOptionalParams, 'guildId'>>({ guildId: '@me' }, optional);
const res = await this.client.proxy.channels(id).patch({ body, reason: options.reason }); const res = await this.client.proxy.channels(id).patch({ body, reason: options.reason });
await this.client.cache.channels?.setIfNI(BaseChannel.__intent__(options.guildId!), res.id, options.guildId!, res); await this.client.cache.channels?.setIfNI(BaseChannel.__intent__(options.guildId!), res.id, options.guildId!, res);
if (body.permission_overwrites && 'permission_overwrites' in res) if (body.permission_overwrites && 'permission_overwrites' in res && res.permission_overwrites)
await this.client.cache.overwrites?.setIfNI( await this.client.cache.overwrites?.setIfNI(
BaseChannel.__intent__(options.guildId!), BaseChannel.__intent__(options.guildId),
res.id, res.id,
options.guildId!, options.guildId,
res.permission_overwrites, res.permission_overwrites,
); );
return channelFrom(res, this.client); return channelFrom(res, this.client);