mirror of
https://github.com/stoatchat/javascript-client-sdk.git
synced 2026-07-19 17:13:31 -04:00
feat: further auxiliary method implementations
This commit is contained in:
@@ -265,6 +265,19 @@ export class Client {
|
||||
|
||||
return `${autumn.url}/${tag}/${_id}${query}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Proxy a file through January.
|
||||
* @param url URL to proxy
|
||||
* @returns Proxied media URL
|
||||
*/
|
||||
proxyFile(url: string): string | undefined {
|
||||
if (this.configuration?.features.january.enabled) {
|
||||
return `${
|
||||
this.configuration.features.january.url
|
||||
}/proxy?url=${encodeURIComponent(url)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type FileArgs = [
|
||||
|
||||
@@ -6,6 +6,8 @@ import type {
|
||||
DataMessageSend,
|
||||
Member,
|
||||
Message,
|
||||
OptionsMessageSearch,
|
||||
Override,
|
||||
User,
|
||||
} from "revolt-api";
|
||||
import { APIRoutes } from "revolt-api/dist/routes";
|
||||
@@ -95,6 +97,24 @@ export default (
|
||||
return Channel.#get(this.id).channelType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute pathname to this channel in the client
|
||||
*/
|
||||
get path() {
|
||||
if (this.serverId) {
|
||||
return `/server/${this.serverId}/channel/${this.id}`;
|
||||
} else {
|
||||
return `/channel/${this.id}`;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to this channel
|
||||
*/
|
||||
get url() {
|
||||
return client.configuration?.app + this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Channel name
|
||||
*/
|
||||
@@ -457,4 +477,116 @@ export default (
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for messages
|
||||
* @param params Message searching route data
|
||||
* @returns The messages
|
||||
*/
|
||||
async search(params: Omit<OptionsMessageSearch, "include_users">) {
|
||||
const messages = (await client.api.post(
|
||||
`/channels/${this.id as ""}/search`,
|
||||
params
|
||||
)) as Message[];
|
||||
|
||||
return messages.map((message) =>
|
||||
client.Message.new(message._id, message)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search for messages including the users that sent them
|
||||
* @param params Message searching route data
|
||||
* @returns The messages
|
||||
*/
|
||||
async searchWithUsers(params: Omit<OptionsMessageSearch, "include_users">) {
|
||||
const data = (await client.api.post(`/channels/${this.id as ""}/search`, {
|
||||
...params,
|
||||
include_users: true,
|
||||
})) as { messages: Message[]; users: User[]; members?: Member[] };
|
||||
|
||||
return {
|
||||
messages: data.messages.map((message) =>
|
||||
client.Message.new(message._id, message)
|
||||
),
|
||||
users: data.users.map((user) => client.User.new(user._id, user)),
|
||||
members: data.members?.map((member) =>
|
||||
client.ServerMember.new(member._id, member)
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
async deleteMessages(ids: string[]) {
|
||||
await client.api.delete(`/channels/${this.id as ""}/messages/bulk`, {
|
||||
data: { ids },
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an invite to the channel
|
||||
* @returns Newly created invite code
|
||||
*/
|
||||
async createInvite() {
|
||||
return await client.api.post(`/channels/${this.id as ""}/invites`);
|
||||
}
|
||||
|
||||
#ackTimeout?: number;
|
||||
#ackLimit?: number;
|
||||
|
||||
/**
|
||||
* Mark a channel as read
|
||||
* @param message Last read message or its ID
|
||||
* @param skipRateLimiter Whether to skip the internal rate limiter
|
||||
*/
|
||||
async ack(message?: Message | string, skipRateLimiter?: boolean) {
|
||||
const id =
|
||||
(typeof message === "string" ? message : message?._id) ??
|
||||
this.lastMessageId ??
|
||||
ulid();
|
||||
const performAck = () => {
|
||||
this.#ackLimit = undefined;
|
||||
client.api.put(`/channels/${this.id}/ack/${id as ""}`);
|
||||
};
|
||||
|
||||
/* TODO: if (!client.options.ackRateLimiter || skipRateLimiter)
|
||||
return performAck();*/
|
||||
|
||||
clearTimeout(this.#ackTimeout);
|
||||
if (this.#ackLimit && +new Date() > this.#ackLimit) {
|
||||
performAck();
|
||||
}
|
||||
|
||||
// We need to use setTimeout here for both Node.js and browser.
|
||||
this.#ackTimeout = setTimeout(performAck, 5000) as unknown as number;
|
||||
|
||||
if (!this.#ackLimit) {
|
||||
this.#ackLimit = +new Date() + 15e3;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set role permissions
|
||||
* @param role_id Role Id, set to 'default' to affect all users
|
||||
* @param permissions Permission value
|
||||
*/
|
||||
async setPermissions(role_id = "default", permissions: Override) {
|
||||
return await client.api.put(
|
||||
`/channels/${this.id as ""}/permissions/${role_id as ""}`,
|
||||
{ permissions }
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Start typing in this channel
|
||||
*/
|
||||
startTyping() {
|
||||
client.events.send({ type: "BeginTyping", channel: this.id });
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop typing in this channel
|
||||
*/
|
||||
stopTyping() {
|
||||
client.events.send({ type: "EndTyping", channel: this.id });
|
||||
}
|
||||
};
|
||||
|
||||
@@ -74,6 +74,20 @@ export default (
|
||||
return new Date(decodeTime(this.id));
|
||||
}
|
||||
|
||||
/**
|
||||
* Absolute pathname to this message in the client
|
||||
*/
|
||||
get path() {
|
||||
return `${this.channel!.path}/${this.id}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to this message
|
||||
*/
|
||||
get url() {
|
||||
return client.configuration?.app + this.path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Nonce value
|
||||
*/
|
||||
@@ -95,6 +109,23 @@ export default (
|
||||
return client.channels.get(Message.#get(this.id).channelId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Server this message was sent in
|
||||
*/
|
||||
get server() {
|
||||
return this.channel!.server;
|
||||
}
|
||||
|
||||
/**
|
||||
* Member this message was sent by
|
||||
*/
|
||||
get member() {
|
||||
return client.serverMembers.getByKey({
|
||||
server: this.channel!.serverId,
|
||||
user: this.authorId!,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Id of user this message was sent by
|
||||
*/
|
||||
@@ -178,4 +209,86 @@ export default (
|
||||
get masquerade() {
|
||||
return Message.#get(this.id).masquerade;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the username for this message
|
||||
*/
|
||||
get username() {
|
||||
return (
|
||||
this.masquerade?.name ?? this.member?.nickname ?? this.author?.username
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the role colour for this message
|
||||
*/
|
||||
get roleColour() {
|
||||
return this.masquerade?.colour ?? this.member?.roleColour;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the avatar URL for this message
|
||||
*/
|
||||
get avatarURL() {
|
||||
return (
|
||||
this.masqueradeAvatarURL ??
|
||||
this.member?.avatarURL ??
|
||||
this.author?.avatarURL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the animated avatar URL for this message
|
||||
*/
|
||||
get animatedAvatarURL() {
|
||||
return (
|
||||
this.masqueradeAvatarURL ??
|
||||
(this.member
|
||||
? this.member?.animatedAvatarURL
|
||||
: this.author?.animatedAvatarURL)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Avatar URL from the masquerade
|
||||
*/
|
||||
get masqueradeAvatarURL() {
|
||||
const avatar = this.masquerade?.avatar;
|
||||
return avatar ? client.proxyFile(avatar) : undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populated system message
|
||||
*/
|
||||
get populatedSystemMessage() {
|
||||
const system = this.systemMessage;
|
||||
if (!system) return { type: "none" };
|
||||
|
||||
const { type } = system;
|
||||
const get = (id: string) => client.users.get(id);
|
||||
switch (system.type) {
|
||||
case "text":
|
||||
return system;
|
||||
case "user_added":
|
||||
return { type, user: get(system.id), by: get(system.by) };
|
||||
case "user_remove":
|
||||
return { type, user: get(system.id), by: get(system.by) };
|
||||
case "user_joined":
|
||||
return { type, user: get(system.id) };
|
||||
case "user_left":
|
||||
return { type, user: get(system.id) };
|
||||
case "user_kicked":
|
||||
return { type, user: get(system.id) };
|
||||
case "user_banned":
|
||||
return { type, user: get(system.id) };
|
||||
case "channel_renamed":
|
||||
return { type, name: system.name, by: get(system.by) };
|
||||
case "channel_description_changed":
|
||||
return { type, by: get(system.by) };
|
||||
case "channel_icon_changed":
|
||||
return { type, by: get(system.by) };
|
||||
case "channel_ownership_changed":
|
||||
return { type, from: get(system.from), to: get(system.to) };
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import { SetStoreFunction } from "solid-js/store";
|
||||
|
||||
import type { Member as ApiMember, MemberCompositeKey } from "revolt-api";
|
||||
|
||||
import { Channel, Client, Server } from "../Client";
|
||||
import { Channel, Client, FileArgs, Server } from "../Client";
|
||||
import { StoreCollection } from "../collections/Collection";
|
||||
import { HydratedServerMember } from "../hydration/serverMember";
|
||||
import { bitwiseAndEq, calculatePermission } from "../permissions/calculator";
|
||||
@@ -214,4 +214,24 @@ export default (
|
||||
inferiorTo(target: ServerMember) {
|
||||
return target.ranking < this.ranking;
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the member's avatar
|
||||
*/
|
||||
get avatarURL() {
|
||||
return (
|
||||
client.generateFileURL(this.avatar, { max_side: 256 }) ??
|
||||
this.user?.avatarURL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the member's animated avatar
|
||||
*/
|
||||
get animatedAvatarURL() {
|
||||
return (
|
||||
client.generateFileURL(this.avatar, { max_side: 256 }, true) ??
|
||||
this.user?.animatedAvatarURL
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
+6
-11
@@ -144,24 +144,19 @@ export default (
|
||||
* URL to the user's avatar
|
||||
*/
|
||||
get avatarURL() {
|
||||
return this.#generateAvatarURL({ max_side: 256 });
|
||||
return (
|
||||
client.generateFileURL(this.avatar, { max_side: 256 }) ??
|
||||
this.defaultAvatarURL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* URL to the user's animated avatar
|
||||
*/
|
||||
get animatedAvatarURL() {
|
||||
return this.#generateAvatarURL({ max_side: 256 }, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate avatar URL
|
||||
* @param args File args
|
||||
* @returns URL
|
||||
*/
|
||||
#generateAvatarURL(...args: FileArgs) {
|
||||
return (
|
||||
client.generateFileURL(this.avatar, ...args) ?? this.defaultAvatarURL
|
||||
client.generateFileURL(this.avatar, { max_side: 256 }, true) ??
|
||||
this.defaultAvatarURL
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user