@stoatx/client 0.6.4 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -8,6 +8,7 @@ import util__default from 'node:util';
8
8
  declare class GatewayManager {
9
9
  private client;
10
10
  private ws;
11
+ private wsURL;
11
12
  private pingInterval;
12
13
  private token;
13
14
  private reconnectAttempts;
@@ -15,6 +16,7 @@ declare class GatewayManager {
15
16
  private isIntentionalClose;
16
17
  constructor(client: Client);
17
18
  connect(token: string): Promise<void>;
19
+ setGatewayUrl(url: string): void;
18
20
  private handleMessage;
19
21
  private startPingLoop;
20
22
  private send;
@@ -71,10 +73,13 @@ declare class StoatAPIError extends Error {
71
73
  declare class RESTManager {
72
74
  private client;
73
75
  private baseURL;
76
+ private cdnURL;
74
77
  private token;
75
78
  private buckets;
76
79
  constructor(client: Client);
77
80
  setToken(token: string): void;
81
+ setBaseURL(baseURL: string): void;
82
+ setCDNURL(cdnURL: string): void;
78
83
  /**
79
84
  * Generates a local identifier for the bucket based on method and path.
80
85
  */
@@ -1652,20 +1657,109 @@ declare class Emoji extends Base {
1652
1657
  nsfw: boolean;
1653
1658
  constructor(client: Client, data: Emoji$1);
1654
1659
  _patch(data: Emoji$1): void;
1660
+ /**
1661
+ * Fetch this emoji from the API or resolves it from the local cache.
1662
+ * @param force Whether to skip the cache check and force a direct API request. Defaults to false.
1663
+ * @returns A promise that resolves to the fetched {@link Emoji} object.
1664
+ * @throws {Error} If the API request fails or if the emoji is detached.
1665
+ * @example
1666
+ * // Force fetch emoji to update its data
1667
+ * await emoji.fetch(true);
1668
+ */
1669
+ fetch(force?: boolean): Promise<Emoji>;
1670
+ /**
1671
+ * Deletes this emoji from the server.
1672
+ * @returns A promise that resolves when the emoji has been deleted.
1673
+ * @throws {Error} If the API request fails or if the emoji is detached.
1674
+ * @example
1675
+ * // Delete an emoji from the server
1676
+ * await emoji.delete();
1677
+ */
1678
+ delete(): Promise<void>;
1679
+ /**
1680
+ * Edits this emoji's properties.
1681
+ * @param options The options to edit the emoji with.
1682
+ * @returns A promise that resolves to the edited {@link Emoji} object.
1683
+ * @throws {Error} If the API request fails or if the emoji is detached.
1684
+ * @example
1685
+ * // Edit an emoji's name
1686
+ * await emoji.edit({ name: "new_name" });
1687
+ */
1688
+ edit(options: EmojiEditOptions): Promise<Emoji>;
1655
1689
  }
1656
1690
 
1691
+ interface EmojiCreateOptions {
1692
+ emoji: string | AttachmentBuilder;
1693
+ name: string;
1694
+ nsfw?: boolean;
1695
+ }
1696
+ interface EmojiEditOptions {
1697
+ name: string;
1698
+ }
1699
+ type EmojiResolvable = string | Emoji;
1657
1700
  declare class EmojiManager extends BaseManager<string, Emoji> {
1658
1701
  server?: Server | undefined;
1659
1702
  constructor(client: Client, server?: Server | undefined, limit?: number);
1660
1703
  /**
1661
1704
  * Tell BaseManager how to find the ID for Emojis
1662
1705
  */
1663
- protected extractId(data: any): string;
1706
+ protected extractId(data: Emoji$1): string;
1664
1707
  /**
1665
1708
  * Tell BaseManager how to build an Emoji
1666
1709
  */
1667
- protected construct(data: any): Emoji;
1668
- fetch(id: string): Promise<Emoji>;
1710
+ protected construct(data: Emoji$1): Emoji;
1711
+ /**
1712
+ * Fetch an Emoji from the API or resolves it from the local cache.
1713
+ * @param emoji The ID, mention, or {@link Emoji} object to fetch
1714
+ * @param force Whether to skip the cache check and force a direct API request. Defaults to false.
1715
+ * @returns A promise that resolves to the fetched {@link Emoji} object.
1716
+ * @throws {TypeError} If an invalid {@link EmojiResolvable} is provided.
1717
+ * @throws {Error} If the API request fails.
1718
+ * @example
1719
+ * // Fetch a channel, bypassing cache
1720
+ * const channel = await client.channels.fetch("01H...", true);
1721
+ */
1722
+ fetch(emoji: EmojiResolvable, force?: boolean): Promise<Emoji>;
1723
+ /**
1724
+ * Resolves a {@link EmojiResolvable} to a {@link Emoji} object from the cache.
1725
+ * @param emoji The {@link EmojiResolvable} to resolve.
1726
+ * @returns The resolved {@link Emoji} object, or undefined if not found.
1727
+ */
1728
+ resolve(emoji: EmojiResolvable): Emoji | undefined;
1729
+ /**
1730
+ * Extracts ID from a {@link EmojiResolvable}.
1731
+ * @param emoji The {@link EmojiResolvable} to extract the ID from.
1732
+ * @returns The extracted {@link Emoji} ID.
1733
+ * @throws {TypeError} If an invalid type is provided.
1734
+ */
1735
+ resolveId(emoji: EmojiResolvable): string;
1736
+ /**
1737
+ * Create a new emoji
1738
+ * @param options The options for creating the emoji
1739
+ * @returns A promise that resolves to the created {@link Emoji} object.
1740
+ * @throws {Error} If no server is registered in the {@link EmojiManager} or if the emoji attachment cannot be resolved.
1741
+ * @example
1742
+ * const emoji = await client.emojis.create(server, { emoji: "path/to/emoji.png", name: "myEmoji" });
1743
+ */
1744
+ crate(options: EmojiCreateOptions): Promise<Emoji>;
1745
+ /**
1746
+ * Delete an emoji
1747
+ * @param emoji The {@link EmojiResolvable} to delete
1748
+ * @throws {Error} If no server is registered in the {@link EmojiManager}.
1749
+ * @example
1750
+ * await client.emojis.delete(emoji);
1751
+ */
1752
+ delete(emoji: EmojiResolvable): Promise<void>;
1753
+ /**
1754
+ * Edit an emoji
1755
+ * @param emoji The {@link EmojiResolvable} to edit
1756
+ * @param options The options to edit the emoji with
1757
+ * @returns A promise that resolves to the edited {@link Emoji} object.
1758
+ * @throws {Error} If no server is registered in the {@link EmojiManager}.
1759
+ * @example
1760
+ * const editedEmoji = await client.emojis.edit(emoji, { name: "newName" });
1761
+ */
1762
+ edit(emoji: EmojiResolvable, options: EmojiEditOptions): Promise<Emoji>;
1669
1763
  [util.inspect.custom](): Collection<string, Emoji>;
1670
1764
  }
1671
1765
 
@@ -2131,9 +2225,13 @@ interface ClientOptions {
2131
2225
  channels?: number;
2132
2226
  emojis?: number;
2133
2227
  };
2228
+ apiURL?: string;
2229
+ overrides?: {
2230
+ wsURL?: string;
2231
+ cdnURL?: string;
2232
+ };
2134
2233
  }
2135
2234
  declare class Client extends EventEmitter {
2136
- options: ClientOptions;
2137
2235
  rest: RESTManager;
2138
2236
  gateway: GatewayManager;
2139
2237
  channels: ChannelManager;
@@ -2142,11 +2240,13 @@ declare class Client extends EventEmitter {
2142
2240
  sweepers: SweeperManager;
2143
2241
  emojis: EmojiManager;
2144
2242
  user: ClientUser | null;
2243
+ options: ClientOptions;
2145
2244
  constructor(options?: ClientOptions);
2146
2245
  /**
2147
2246
  * Connects the bot to the Stoat Gateway
2148
2247
  */
2149
2248
  login(token: string): Promise<any>;
2249
+ private fetchConfig;
2150
2250
  on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
2151
2251
  once<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
2152
2252
  emit<K extends keyof ClientEvents>(event: K, ...args: ClientEvents[K]): boolean;
@@ -2159,4 +2259,4 @@ declare class UnknownChannel extends BaseChannel {
2159
2259
  constructor(client: Client, data: Channel);
2160
2260
  }
2161
2261
 
2162
- export { Attachment, AttachmentBuilder, type AttachmentMetadata, Base, BaseChannel, BitField, type BitFieldResolvable, type BotInformation, type CDNTag, type ChannelCreateOptions, type ChannelEditOptions, ChannelManager, type ChannelResolvable, type ChannelRolePermissionOptions, type ChannelType, Client, type ClientEvents, type ClientOptions, ClientUser, Collection, Collector, type CollectorOptions, DMChannel, EmbedBuilder, Emoji, EmojiManager, type EmojiParent, type FetchMembersOptions, GatewayManager, GroupChannel, type Interaction, type Masquerade, Member, type MemberBanOptions, type MemberEditOptions, MemberManager, type MemberResolvable, Message, MessageCollector, type MessageCollectorOptions, type MessageFetchOptions, MessageManager, type MessageOptions, MessageReaction, type MessageResolvable, PermissionFlags, type PermissionResolvable, type PermissionString, Permissions, RESTManager, type RawDMChannel, type RawGroupChannel, type RawTextChannel, ReactionCollector, type ReactionCollectorOptions, type ReplyIntent, Role, type RoleCreateOptions, type RoleEditOptions, RoleManager, type RolePermissionOptions, type RoleResolvable, Server, ServerChannelManager, type ServerEditOptions, ServerManager, StoatAPIError, SweeperManager, type SweeperOptions, TextChannel, type TextEmbedData, UnknownChannel, User, type UserEditOptions, UserManager, type UserPresence, type UserProfile, type UserRelationShip, type UserResolvable, type UserStatus };
2262
+ export { Attachment, AttachmentBuilder, type AttachmentMetadata, Base, BaseChannel, BitField, type BitFieldResolvable, type BotInformation, type CDNTag, type ChannelCreateOptions, type ChannelEditOptions, ChannelManager, type ChannelResolvable, type ChannelRolePermissionOptions, type ChannelType, Client, type ClientEvents, type ClientOptions, ClientUser, Collection, Collector, type CollectorOptions, DMChannel, EmbedBuilder, Emoji, type EmojiCreateOptions, type EmojiEditOptions, EmojiManager, type EmojiParent, type EmojiResolvable, type FetchMembersOptions, GatewayManager, GroupChannel, type Interaction, type Masquerade, Member, type MemberBanOptions, type MemberEditOptions, MemberManager, type MemberResolvable, Message, MessageCollector, type MessageCollectorOptions, type MessageFetchOptions, MessageManager, type MessageOptions, MessageReaction, type MessageResolvable, PermissionFlags, type PermissionResolvable, type PermissionString, Permissions, RESTManager, type RawDMChannel, type RawGroupChannel, type RawTextChannel, ReactionCollector, type ReactionCollectorOptions, type ReplyIntent, Role, type RoleCreateOptions, type RoleEditOptions, RoleManager, type RolePermissionOptions, type RoleResolvable, Server, ServerChannelManager, type ServerEditOptions, ServerManager, StoatAPIError, SweeperManager, type SweeperOptions, TextChannel, type TextEmbedData, UnknownChannel, User, type UserEditOptions, UserManager, type UserPresence, type UserProfile, type UserRelationShip, type UserResolvable, type UserStatus };
package/dist/index.d.ts CHANGED
@@ -8,6 +8,7 @@ import util__default from 'node:util';
8
8
  declare class GatewayManager {
9
9
  private client;
10
10
  private ws;
11
+ private wsURL;
11
12
  private pingInterval;
12
13
  private token;
13
14
  private reconnectAttempts;
@@ -15,6 +16,7 @@ declare class GatewayManager {
15
16
  private isIntentionalClose;
16
17
  constructor(client: Client);
17
18
  connect(token: string): Promise<void>;
19
+ setGatewayUrl(url: string): void;
18
20
  private handleMessage;
19
21
  private startPingLoop;
20
22
  private send;
@@ -71,10 +73,13 @@ declare class StoatAPIError extends Error {
71
73
  declare class RESTManager {
72
74
  private client;
73
75
  private baseURL;
76
+ private cdnURL;
74
77
  private token;
75
78
  private buckets;
76
79
  constructor(client: Client);
77
80
  setToken(token: string): void;
81
+ setBaseURL(baseURL: string): void;
82
+ setCDNURL(cdnURL: string): void;
78
83
  /**
79
84
  * Generates a local identifier for the bucket based on method and path.
80
85
  */
@@ -1652,20 +1657,109 @@ declare class Emoji extends Base {
1652
1657
  nsfw: boolean;
1653
1658
  constructor(client: Client, data: Emoji$1);
1654
1659
  _patch(data: Emoji$1): void;
1660
+ /**
1661
+ * Fetch this emoji from the API or resolves it from the local cache.
1662
+ * @param force Whether to skip the cache check and force a direct API request. Defaults to false.
1663
+ * @returns A promise that resolves to the fetched {@link Emoji} object.
1664
+ * @throws {Error} If the API request fails or if the emoji is detached.
1665
+ * @example
1666
+ * // Force fetch emoji to update its data
1667
+ * await emoji.fetch(true);
1668
+ */
1669
+ fetch(force?: boolean): Promise<Emoji>;
1670
+ /**
1671
+ * Deletes this emoji from the server.
1672
+ * @returns A promise that resolves when the emoji has been deleted.
1673
+ * @throws {Error} If the API request fails or if the emoji is detached.
1674
+ * @example
1675
+ * // Delete an emoji from the server
1676
+ * await emoji.delete();
1677
+ */
1678
+ delete(): Promise<void>;
1679
+ /**
1680
+ * Edits this emoji's properties.
1681
+ * @param options The options to edit the emoji with.
1682
+ * @returns A promise that resolves to the edited {@link Emoji} object.
1683
+ * @throws {Error} If the API request fails or if the emoji is detached.
1684
+ * @example
1685
+ * // Edit an emoji's name
1686
+ * await emoji.edit({ name: "new_name" });
1687
+ */
1688
+ edit(options: EmojiEditOptions): Promise<Emoji>;
1655
1689
  }
1656
1690
 
1691
+ interface EmojiCreateOptions {
1692
+ emoji: string | AttachmentBuilder;
1693
+ name: string;
1694
+ nsfw?: boolean;
1695
+ }
1696
+ interface EmojiEditOptions {
1697
+ name: string;
1698
+ }
1699
+ type EmojiResolvable = string | Emoji;
1657
1700
  declare class EmojiManager extends BaseManager<string, Emoji> {
1658
1701
  server?: Server | undefined;
1659
1702
  constructor(client: Client, server?: Server | undefined, limit?: number);
1660
1703
  /**
1661
1704
  * Tell BaseManager how to find the ID for Emojis
1662
1705
  */
1663
- protected extractId(data: any): string;
1706
+ protected extractId(data: Emoji$1): string;
1664
1707
  /**
1665
1708
  * Tell BaseManager how to build an Emoji
1666
1709
  */
1667
- protected construct(data: any): Emoji;
1668
- fetch(id: string): Promise<Emoji>;
1710
+ protected construct(data: Emoji$1): Emoji;
1711
+ /**
1712
+ * Fetch an Emoji from the API or resolves it from the local cache.
1713
+ * @param emoji The ID, mention, or {@link Emoji} object to fetch
1714
+ * @param force Whether to skip the cache check and force a direct API request. Defaults to false.
1715
+ * @returns A promise that resolves to the fetched {@link Emoji} object.
1716
+ * @throws {TypeError} If an invalid {@link EmojiResolvable} is provided.
1717
+ * @throws {Error} If the API request fails.
1718
+ * @example
1719
+ * // Fetch a channel, bypassing cache
1720
+ * const channel = await client.channels.fetch("01H...", true);
1721
+ */
1722
+ fetch(emoji: EmojiResolvable, force?: boolean): Promise<Emoji>;
1723
+ /**
1724
+ * Resolves a {@link EmojiResolvable} to a {@link Emoji} object from the cache.
1725
+ * @param emoji The {@link EmojiResolvable} to resolve.
1726
+ * @returns The resolved {@link Emoji} object, or undefined if not found.
1727
+ */
1728
+ resolve(emoji: EmojiResolvable): Emoji | undefined;
1729
+ /**
1730
+ * Extracts ID from a {@link EmojiResolvable}.
1731
+ * @param emoji The {@link EmojiResolvable} to extract the ID from.
1732
+ * @returns The extracted {@link Emoji} ID.
1733
+ * @throws {TypeError} If an invalid type is provided.
1734
+ */
1735
+ resolveId(emoji: EmojiResolvable): string;
1736
+ /**
1737
+ * Create a new emoji
1738
+ * @param options The options for creating the emoji
1739
+ * @returns A promise that resolves to the created {@link Emoji} object.
1740
+ * @throws {Error} If no server is registered in the {@link EmojiManager} or if the emoji attachment cannot be resolved.
1741
+ * @example
1742
+ * const emoji = await client.emojis.create(server, { emoji: "path/to/emoji.png", name: "myEmoji" });
1743
+ */
1744
+ crate(options: EmojiCreateOptions): Promise<Emoji>;
1745
+ /**
1746
+ * Delete an emoji
1747
+ * @param emoji The {@link EmojiResolvable} to delete
1748
+ * @throws {Error} If no server is registered in the {@link EmojiManager}.
1749
+ * @example
1750
+ * await client.emojis.delete(emoji);
1751
+ */
1752
+ delete(emoji: EmojiResolvable): Promise<void>;
1753
+ /**
1754
+ * Edit an emoji
1755
+ * @param emoji The {@link EmojiResolvable} to edit
1756
+ * @param options The options to edit the emoji with
1757
+ * @returns A promise that resolves to the edited {@link Emoji} object.
1758
+ * @throws {Error} If no server is registered in the {@link EmojiManager}.
1759
+ * @example
1760
+ * const editedEmoji = await client.emojis.edit(emoji, { name: "newName" });
1761
+ */
1762
+ edit(emoji: EmojiResolvable, options: EmojiEditOptions): Promise<Emoji>;
1669
1763
  [util.inspect.custom](): Collection<string, Emoji>;
1670
1764
  }
1671
1765
 
@@ -2131,9 +2225,13 @@ interface ClientOptions {
2131
2225
  channels?: number;
2132
2226
  emojis?: number;
2133
2227
  };
2228
+ apiURL?: string;
2229
+ overrides?: {
2230
+ wsURL?: string;
2231
+ cdnURL?: string;
2232
+ };
2134
2233
  }
2135
2234
  declare class Client extends EventEmitter {
2136
- options: ClientOptions;
2137
2235
  rest: RESTManager;
2138
2236
  gateway: GatewayManager;
2139
2237
  channels: ChannelManager;
@@ -2142,11 +2240,13 @@ declare class Client extends EventEmitter {
2142
2240
  sweepers: SweeperManager;
2143
2241
  emojis: EmojiManager;
2144
2242
  user: ClientUser | null;
2243
+ options: ClientOptions;
2145
2244
  constructor(options?: ClientOptions);
2146
2245
  /**
2147
2246
  * Connects the bot to the Stoat Gateway
2148
2247
  */
2149
2248
  login(token: string): Promise<any>;
2249
+ private fetchConfig;
2150
2250
  on<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
2151
2251
  once<K extends keyof ClientEvents>(event: K, listener: (...args: ClientEvents[K]) => void): this;
2152
2252
  emit<K extends keyof ClientEvents>(event: K, ...args: ClientEvents[K]): boolean;
@@ -2159,4 +2259,4 @@ declare class UnknownChannel extends BaseChannel {
2159
2259
  constructor(client: Client, data: Channel);
2160
2260
  }
2161
2261
 
2162
- export { Attachment, AttachmentBuilder, type AttachmentMetadata, Base, BaseChannel, BitField, type BitFieldResolvable, type BotInformation, type CDNTag, type ChannelCreateOptions, type ChannelEditOptions, ChannelManager, type ChannelResolvable, type ChannelRolePermissionOptions, type ChannelType, Client, type ClientEvents, type ClientOptions, ClientUser, Collection, Collector, type CollectorOptions, DMChannel, EmbedBuilder, Emoji, EmojiManager, type EmojiParent, type FetchMembersOptions, GatewayManager, GroupChannel, type Interaction, type Masquerade, Member, type MemberBanOptions, type MemberEditOptions, MemberManager, type MemberResolvable, Message, MessageCollector, type MessageCollectorOptions, type MessageFetchOptions, MessageManager, type MessageOptions, MessageReaction, type MessageResolvable, PermissionFlags, type PermissionResolvable, type PermissionString, Permissions, RESTManager, type RawDMChannel, type RawGroupChannel, type RawTextChannel, ReactionCollector, type ReactionCollectorOptions, type ReplyIntent, Role, type RoleCreateOptions, type RoleEditOptions, RoleManager, type RolePermissionOptions, type RoleResolvable, Server, ServerChannelManager, type ServerEditOptions, ServerManager, StoatAPIError, SweeperManager, type SweeperOptions, TextChannel, type TextEmbedData, UnknownChannel, User, type UserEditOptions, UserManager, type UserPresence, type UserProfile, type UserRelationShip, type UserResolvable, type UserStatus };
2262
+ export { Attachment, AttachmentBuilder, type AttachmentMetadata, Base, BaseChannel, BitField, type BitFieldResolvable, type BotInformation, type CDNTag, type ChannelCreateOptions, type ChannelEditOptions, ChannelManager, type ChannelResolvable, type ChannelRolePermissionOptions, type ChannelType, Client, type ClientEvents, type ClientOptions, ClientUser, Collection, Collector, type CollectorOptions, DMChannel, EmbedBuilder, Emoji, type EmojiCreateOptions, type EmojiEditOptions, EmojiManager, type EmojiParent, type EmojiResolvable, type FetchMembersOptions, GatewayManager, GroupChannel, type Interaction, type Masquerade, Member, type MemberBanOptions, type MemberEditOptions, MemberManager, type MemberResolvable, Message, MessageCollector, type MessageCollectorOptions, type MessageFetchOptions, MessageManager, type MessageOptions, MessageReaction, type MessageResolvable, PermissionFlags, type PermissionResolvable, type PermissionString, Permissions, RESTManager, type RawDMChannel, type RawGroupChannel, type RawTextChannel, ReactionCollector, type ReactionCollectorOptions, type ReplyIntent, Role, type RoleCreateOptions, type RoleEditOptions, RoleManager, type RolePermissionOptions, type RoleResolvable, Server, ServerChannelManager, type ServerEditOptions, ServerManager, StoatAPIError, SweeperManager, type SweeperOptions, TextChannel, type TextEmbedData, UnknownChannel, User, type UserEditOptions, UserManager, type UserPresence, type UserProfile, type UserRelationShip, type UserResolvable, type UserStatus };
package/dist/index.js CHANGED
@@ -756,6 +756,7 @@ var GatewayManager = class {
756
756
  this.client = client;
757
757
  }
758
758
  ws = null;
759
+ wsURL = "";
759
760
  pingInterval = null;
760
761
  token = null;
761
762
  reconnectAttempts = 0;
@@ -770,7 +771,7 @@ var GatewayManager = class {
770
771
  this.ws.removeAllListeners();
771
772
  this.ws = null;
772
773
  }
773
- const baseUrl = "wss://stoat.chat/events";
774
+ const baseUrl = this.wsURL ?? "wss://events.stoat.chat";
774
775
  const url = `${baseUrl}?version=1&format=json&token=${this.token}`;
775
776
  this.ws = new WebSocket(url);
776
777
  this.ws.on("open", () => {
@@ -790,6 +791,9 @@ var GatewayManager = class {
790
791
  this.client.emit("error", error);
791
792
  });
792
793
  }
794
+ setGatewayUrl(url) {
795
+ this.wsURL = url;
796
+ }
793
797
  handleMessage(rawData) {
794
798
  const payload = JSON.parse(rawData.toString());
795
799
  const eventType = payload.type;
@@ -1286,12 +1290,19 @@ var RESTManager = class {
1286
1290
  }
1287
1291
  }, 3e5).unref();
1288
1292
  }
1289
- baseURL = "https://stoat.chat/api";
1293
+ baseURL = "";
1294
+ cdnURL = "";
1290
1295
  token = null;
1291
1296
  buckets = /* @__PURE__ */ new Map();
1292
1297
  setToken(token) {
1293
1298
  this.token = token;
1294
1299
  }
1300
+ setBaseURL(baseURL) {
1301
+ this.baseURL = baseURL.replace(/\/+$/, "");
1302
+ }
1303
+ setCDNURL(cdnURL) {
1304
+ this.cdnURL = cdnURL.replace(/\/+$/, "");
1305
+ }
1295
1306
  /**
1296
1307
  * Generates a local identifier for the bucket based on method and path.
1297
1308
  */
@@ -1383,7 +1394,7 @@ var RESTManager = class {
1383
1394
  */
1384
1395
  async uploadFile(tag, fileBuffer, filename) {
1385
1396
  if (!this.token) throw new Error("REST_NOT_READY: No token available.");
1386
- const url = `https://cdn.stoatusercontent.com/${tag}`;
1397
+ const url = `${this.cdnURL}/${tag}`;
1387
1398
  const formData = new FormData();
1388
1399
  formData.append("file", new Blob([fileBuffer]), filename);
1389
1400
  const response = await fetch(url, {
@@ -3779,6 +3790,50 @@ var Emoji = class extends Base {
3779
3790
  if (data.animated !== void 0) this.animated = data.animated;
3780
3791
  if (data.nsfw !== void 0) this.nsfw = data.nsfw;
3781
3792
  }
3793
+ /**
3794
+ * Fetch this emoji from the API or resolves it from the local cache.
3795
+ * @param force Whether to skip the cache check and force a direct API request. Defaults to false.
3796
+ * @returns A promise that resolves to the fetched {@link Emoji} object.
3797
+ * @throws {Error} If the API request fails or if the emoji is detached.
3798
+ * @example
3799
+ * // Force fetch emoji to update its data
3800
+ * await emoji.fetch(true);
3801
+ */
3802
+ async fetch(force) {
3803
+ const server = this.client.servers.cache.get(this.parent.type === "Server" ? this.parent.id : "");
3804
+ if (!server) throw new Error("No server registered in EmojiManager");
3805
+ if (this.parent.type === "Detached") throw new Error("Cannot fetch a detached emoji");
3806
+ return await server.emojis.fetch(this, force);
3807
+ }
3808
+ /**
3809
+ * Deletes this emoji from the server.
3810
+ * @returns A promise that resolves when the emoji has been deleted.
3811
+ * @throws {Error} If the API request fails or if the emoji is detached.
3812
+ * @example
3813
+ * // Delete an emoji from the server
3814
+ * await emoji.delete();
3815
+ */
3816
+ async delete() {
3817
+ const server = this.client.servers.cache.get(this.parent.type === "Server" ? this.parent.id : "");
3818
+ if (!server) throw new Error("No server registered in EmojiManager");
3819
+ if (this.parent.type === "Detached") throw new Error("Emoji is already detached");
3820
+ await server.emojis.delete(this);
3821
+ }
3822
+ /**
3823
+ * Edits this emoji's properties.
3824
+ * @param options The options to edit the emoji with.
3825
+ * @returns A promise that resolves to the edited {@link Emoji} object.
3826
+ * @throws {Error} If the API request fails or if the emoji is detached.
3827
+ * @example
3828
+ * // Edit an emoji's name
3829
+ * await emoji.edit({ name: "new_name" });
3830
+ */
3831
+ async edit(options) {
3832
+ const server = this.client.servers.cache.get(this.parent.type === "Server" ? this.parent.id : "");
3833
+ if (!server) throw new Error("No server registered in EmojiManager");
3834
+ if (this.parent.type === "Detached") throw new Error("Cannot edit a detached emoji");
3835
+ return await server.emojis.edit(this, options);
3836
+ }
3782
3837
  };
3783
3838
 
3784
3839
  // src/managers/EmojiManager.ts
@@ -3792,7 +3847,7 @@ var EmojiManager = class extends BaseManager {
3792
3847
  * Tell BaseManager how to find the ID for Emojis
3793
3848
  */
3794
3849
  extractId(data) {
3795
- return data._id ?? data.id;
3850
+ return data._id;
3796
3851
  }
3797
3852
  /**
3798
3853
  * Tell BaseManager how to build an Emoji
@@ -3800,10 +3855,104 @@ var EmojiManager = class extends BaseManager {
3800
3855
  construct(data) {
3801
3856
  return new Emoji(this.client, data);
3802
3857
  }
3803
- async fetch(id) {
3858
+ /**
3859
+ * Fetch an Emoji from the API or resolves it from the local cache.
3860
+ * @param emoji The ID, mention, or {@link Emoji} object to fetch
3861
+ * @param force Whether to skip the cache check and force a direct API request. Defaults to false.
3862
+ * @returns A promise that resolves to the fetched {@link Emoji} object.
3863
+ * @throws {TypeError} If an invalid {@link EmojiResolvable} is provided.
3864
+ * @throws {Error} If the API request fails.
3865
+ * @example
3866
+ * // Fetch a channel, bypassing cache
3867
+ * const channel = await client.channels.fetch("01H...", true);
3868
+ */
3869
+ async fetch(emoji, force = false) {
3870
+ if (!force) {
3871
+ const cached = this.resolve(emoji);
3872
+ if (cached) return cached;
3873
+ }
3874
+ const id = this.resolveId(emoji);
3804
3875
  const data = await this.client.rest.get(`/custom/emoji/${id}`);
3805
3876
  return this._add(data);
3806
3877
  }
3878
+ /**
3879
+ * Resolves a {@link EmojiResolvable} to a {@link Emoji} object from the cache.
3880
+ * @param emoji The {@link EmojiResolvable} to resolve.
3881
+ * @returns The resolved {@link Emoji} object, or undefined if not found.
3882
+ */
3883
+ resolve(emoji) {
3884
+ if (emoji instanceof Emoji) return emoji;
3885
+ if (typeof emoji === "string") {
3886
+ const id = emoji.replace(/[<:>]/g, "");
3887
+ return this.cache.get(id);
3888
+ }
3889
+ return void 0;
3890
+ }
3891
+ /**
3892
+ * Extracts ID from a {@link EmojiResolvable}.
3893
+ * @param emoji The {@link EmojiResolvable} to extract the ID from.
3894
+ * @returns The extracted {@link Emoji} ID.
3895
+ * @throws {TypeError} If an invalid type is provided.
3896
+ */
3897
+ resolveId(emoji) {
3898
+ if (emoji instanceof Emoji) return emoji.id;
3899
+ if (typeof emoji === "string") {
3900
+ return emoji.replace(/:/g, "");
3901
+ }
3902
+ throw new Error("Invalid EmojiResolvable");
3903
+ }
3904
+ /**
3905
+ * Create a new emoji
3906
+ * @param options The options for creating the emoji
3907
+ * @returns A promise that resolves to the created {@link Emoji} object.
3908
+ * @throws {Error} If no server is registered in the {@link EmojiManager} or if the emoji attachment cannot be resolved.
3909
+ * @example
3910
+ * const emoji = await client.emojis.create(server, { emoji: "path/to/emoji.png", name: "myEmoji" });
3911
+ */
3912
+ async crate(options) {
3913
+ if (!this.server) throw new Error("No server registered in EmojiManager");
3914
+ const resolvedId = await resolveAttachment(this.client.rest, options.emoji, "emojis");
3915
+ if (!resolvedId) throw new Error("Failed to resolve emoji attachment");
3916
+ const payload = {
3917
+ name: options.name,
3918
+ parent: {
3919
+ type: "Server",
3920
+ id: this.server.id
3921
+ }
3922
+ };
3923
+ if (options.nsfw) payload.nsfw = options.nsfw;
3924
+ const data = await this.client.rest.put(`/custom/emoji/${resolvedId}`, payload);
3925
+ return this._add(data);
3926
+ }
3927
+ /**
3928
+ * Delete an emoji
3929
+ * @param emoji The {@link EmojiResolvable} to delete
3930
+ * @throws {Error} If no server is registered in the {@link EmojiManager}.
3931
+ * @example
3932
+ * await client.emojis.delete(emoji);
3933
+ */
3934
+ async delete(emoji) {
3935
+ const id = this.resolveId(emoji);
3936
+ await this.client.rest.delete(`/custom/emoji/${id}`);
3937
+ this.cache.delete(id);
3938
+ }
3939
+ /**
3940
+ * Edit an emoji
3941
+ * @param emoji The {@link EmojiResolvable} to edit
3942
+ * @param options The options to edit the emoji with
3943
+ * @returns A promise that resolves to the edited {@link Emoji} object.
3944
+ * @throws {Error} If no server is registered in the {@link EmojiManager}.
3945
+ * @example
3946
+ * const editedEmoji = await client.emojis.edit(emoji, { name: "newName" });
3947
+ */
3948
+ async edit(emoji, options) {
3949
+ const id = this.resolveId(emoji);
3950
+ const payload = {
3951
+ name: options.name
3952
+ };
3953
+ const data = await this.client.rest.patch(`/custom/emoji/${id}`, payload);
3954
+ return this._add(data);
3955
+ }
3807
3956
  [util11.inspect.custom]() {
3808
3957
  return this.cache;
3809
3958
  }
@@ -4209,6 +4358,15 @@ var SweeperManager = class {
4209
4358
 
4210
4359
  // src/client/Client.ts
4211
4360
  var Client = class extends EventEmitter2 {
4361
+ rest;
4362
+ gateway;
4363
+ channels;
4364
+ servers;
4365
+ users;
4366
+ sweepers;
4367
+ emojis;
4368
+ user = null;
4369
+ options;
4212
4370
  constructor(options = {}) {
4213
4371
  super({ captureRejections: true });
4214
4372
  this.options = options;
@@ -4220,23 +4378,40 @@ var Client = class extends EventEmitter2 {
4220
4378
  this.emojis = new EmojiManager(this, void 0, options.cacheLimits?.emojis);
4221
4379
  this.sweepers = new SweeperManager(this, options.sweepers ?? {});
4222
4380
  }
4223
- rest;
4224
- gateway;
4225
- channels;
4226
- servers;
4227
- users;
4228
- sweepers;
4229
- emojis;
4230
- user = null;
4231
4381
  /**
4232
4382
  * Connects the bot to the Stoat Gateway
4233
4383
  */
4234
4384
  async login(token) {
4235
4385
  if (!token) throw new Error("A valid token must be provided.");
4236
- this.sweepers.start();
4386
+ const rootApiUrl = this.options.apiURL ?? "https://api.stoat.chat";
4387
+ this.rest.setBaseURL(rootApiUrl);
4237
4388
  this.rest.setToken(token);
4389
+ const configData = await this.fetchConfig(rootApiUrl);
4390
+ const finalWsUrl = this.options.overrides?.wsURL ?? configData.ws;
4391
+ if (!finalWsUrl) {
4392
+ throw new Error(
4393
+ `[Stoat Misconfiguration] The server at '${rootApiUrl}' is running, but it has no WebSocket URL configured. The server administrator needs to set their gateway config, or you must bypass it using 'options.overrides.wsURL'.`
4394
+ );
4395
+ }
4396
+ this.gateway.setGatewayUrl(finalWsUrl);
4397
+ const finalCdnUrl = this.options.overrides?.cdnURL ?? configData.features.autumn.url;
4398
+ if (!finalCdnUrl) {
4399
+ throw new Error(
4400
+ `[Stoat Misconfiguration] The server at '${rootApiUrl}' is running, but it has no CDN URL configured. The server administrator needs to set their cdn config, or you must bypass it using 'options.overrides.cdnURL'.`
4401
+ );
4402
+ }
4403
+ this.rest.setCDNURL(finalCdnUrl);
4404
+ this.sweepers.start();
4238
4405
  return this.gateway.connect(token);
4239
4406
  }
4407
+ async fetchConfig(baseURL) {
4408
+ try {
4409
+ const response = await fetch(baseURL);
4410
+ return await response.json();
4411
+ } catch (error) {
4412
+ throw new Error(`Failed to fetch ${baseURL}, make sure the instance is running.`);
4413
+ }
4414
+ }
4240
4415
  [/* @__PURE__ */ Symbol.for("nodejs.rejection")](error) {
4241
4416
  this.emit("error", error);
4242
4417
  }