@stoatx/client 0.1.1 → 0.2.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/README.md CHANGED
@@ -1,11 +1,11 @@
1
1
  # @stoatx/client
2
2
 
3
- A high-performance, fully-typed, and memory-efficient client library for the Revolt API. Built from the ground up for the Stoatx ecosystem.
3
+ A high-performance, fully-typed, and memory-efficient client library for the Stoat API. Built from the ground up for the Stoatx ecosystem.
4
4
 
5
5
  [![npm version](https://img.shields.io/npm/v/@stoatx/client.svg?style=flat-square)](https://www.npmjs.com/package/@stoatx/client)
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-Strict-blue.svg?style=flat-square)](https://www.typescriptlang.org/)
7
7
 
8
- `@stoatx/client` provides a robust object-oriented wrapper around Revolt's REST and WebSocket APIs. It features an intelligent caching system, automatic memory sweeping, and strict event typings to make building bots as frictionless as possible.
8
+ `@stoatx/client` provides a robust object-oriented wrapper around Stoat's REST and WebSocket APIs. It features an intelligent caching system, automatic memory sweeping, and strict event typings to make building bots as frictionless as possible.
9
9
 
10
10
  ## Features
11
11
 
@@ -102,7 +102,7 @@ if (channel && channel.isText()) {
102
102
  ## Building Command Handlers
103
103
 
104
104
  While you can use `@stoatx/client` directly, it truly shines when paired with a command handler. Because the events are strictly typed using generics, you can easily build type-safe event registries.
105
- We recommend using the Stoatx Handler for a seamless experience, but you can also create your own custom command handler leveraging the client's event system.
105
+ We recommend using the `Stoatx` for a seamless experience, but you can also create your own custom command handler leveraging the client's event system.
106
106
 
107
107
  ```typescript
108
108
  // Example of event listening
package/dist/index.cjs CHANGED
@@ -450,7 +450,7 @@ var GatewayManager = class {
450
450
  if (payload.users) {
451
451
  for (const rawUser of payload.users) {
452
452
  this.client.users._add(rawUser);
453
- if (rawUser.relation === "User" && !this.client.user) {
453
+ if (rawUser.relationship === "User" && !this.client.user) {
454
454
  this.client.user = new ClientUser(this.client, rawUser);
455
455
  }
456
456
  }
@@ -617,7 +617,8 @@ var GatewayManager = class {
617
617
  }
618
618
  reconnect() {
619
619
  if (!this.token) {
620
- return this.client.emit("error", new Error("RECONNECT_FAILED: No token available."));
620
+ this.client.emit("error", new Error("RECONNECT_FAILED: No token available."));
621
+ return;
621
622
  }
622
623
  let waitTime = Math.pow(2, this.reconnectAttempts) * 1e3;
623
624
  const jitter = waitTime * 0.2 * Math.random();
@@ -893,11 +894,17 @@ var util2 = __toESM(require("util"), 1);
893
894
 
894
895
  // src/managers/BaseManager.ts
895
896
  var BaseManager = class {
897
+ cache;
898
+ client;
896
899
  constructor(client, limit = Infinity) {
897
900
  this.client = client;
898
901
  this.cache = new Collection(limit);
902
+ Object.defineProperty(this, "client", {
903
+ value: client,
904
+ enumerable: false,
905
+ writable: false
906
+ });
899
907
  }
900
- cache;
901
908
  /**
902
909
  * Transforms raw data into a Structure, patches if existing, and saves to cache.
903
910
  * @internal
@@ -1606,16 +1613,28 @@ var MemberRoleManager = class {
1606
1613
  }
1607
1614
  };
1608
1615
 
1616
+ // src/utils/Constants.ts
1617
+ var StoatCDN = "https://cdn.stoatusercontent.com";
1618
+
1609
1619
  // src/structures/Member.ts
1610
1620
  var Member = class extends Base {
1621
+ // The server ID the member is in
1611
1622
  serverId;
1623
+ // The nickname the member has in the server, if any.
1612
1624
  nickname = null;
1625
+ // The avatar the member has in the server, if any.
1613
1626
  avatar = null;
1614
- roleIds = [];
1627
+ /** @internal */
1628
+ _roles = [];
1629
+ // The date the member joined the server
1615
1630
  joinedAt;
1631
+ // The date the member's timeout expires, or null if not timed out
1616
1632
  timeout = null;
1633
+ // Whatever the user can talk in Voice Chat
1617
1634
  canPublish = false;
1635
+ // Whatever the user can hear in Voice Chat
1618
1636
  canRecieve = false;
1637
+ // Member roles manager
1619
1638
  roles;
1620
1639
  constructor(client, data) {
1621
1640
  super(client, { _id: data.user._id });
@@ -1627,11 +1646,17 @@ var Member = class extends Base {
1627
1646
  _patch(data) {
1628
1647
  if (data.nickname !== void 0) this.nickname = data.nickname;
1629
1648
  if (data.avatar !== void 0) this.avatar = data.avatar;
1630
- if (data.roles !== void 0) this.roleIds = data.roles;
1649
+ if (data.roles !== void 0) this._roles = data.roles;
1631
1650
  if (data.timeout !== void 0) this.timeout = data.timeout ? new Date(data.timeout) : null;
1632
1651
  if (data.can_publish !== void 0) this.canPublish = data.canPublish;
1633
1652
  if (data.can_recieve !== void 0) this.canRecieve = data.canRecieve;
1634
1653
  }
1654
+ /**
1655
+ * Get member role IDs
1656
+ */
1657
+ get roleIds() {
1658
+ return this._roles;
1659
+ }
1635
1660
  /** Gets the global User object for this member */
1636
1661
  get user() {
1637
1662
  return this.client.users.cache.get(this.id);
@@ -1640,18 +1665,12 @@ var Member = class extends Base {
1640
1665
  get server() {
1641
1666
  return this.client.servers.cache.get(this.serverId);
1642
1667
  }
1643
- /** Resolves the array of role strings into actual Role objects */
1644
- get roleObjects() {
1645
- const server = this.server;
1646
- if (!server) return [];
1647
- return this.roleIds.map((id) => server.roles.cache.get(id)).filter((role) => role !== void 0);
1648
- }
1649
1668
  /** Calculates the member's total permissions using BigInt */
1650
1669
  get permissions() {
1651
1670
  const server = this.server;
1652
1671
  if (!server) return 0n;
1653
1672
  let totalPerms = server.defaultPermissions ?? 0n;
1654
- for (const role of this.roleObjects) {
1673
+ for (const role of this.roles.cache.values()) {
1655
1674
  totalPerms |= BigInt(role.permissions);
1656
1675
  }
1657
1676
  if (server.ownerId === this.id) {
@@ -1659,40 +1678,76 @@ var Member = class extends Base {
1659
1678
  }
1660
1679
  return totalPerms;
1661
1680
  }
1662
- /** Checks if the member has a specific permission */
1663
- hasPermission(permission) {
1664
- return Permissions.has(this.permissions, permission);
1681
+ /** Get avatar URL for this member, or null if they don't have one.
1682
+ * @example
1683
+ * // Get a member's avatar URL
1684
+ * const avatarURL = member.avatarURL;
1685
+ * console.log(avatarURL); // https://cdn.stoat.chat/attachments/avatars/1234567890/avatar.png
1686
+ */
1687
+ get avatarURL() {
1688
+ if (!this.avatar) return null;
1689
+ return `${StoatCDN}/attachments/avatars/${this.avatar.id}/${this.avatar.filename}`;
1665
1690
  }
1666
1691
  /**
1667
- * Edits this member's nickname, avatar, roles, or timeout.
1692
+ * Ban this member from the server.
1693
+ * @param options The options for this ban
1694
+ * @example
1695
+ * // Ban a member with a reason and delete their messages from the last hour
1696
+ * await member.ban({ reason: "Spamming", deleteMessageSeconds: 3600 });
1668
1697
  */
1669
- async edit(options) {
1698
+ async ban(options) {
1670
1699
  let server = this.server;
1671
1700
  if (!server) server = await this.client.servers.fetch(this.serverId);
1672
- return await server.members.edit(this.id, options);
1701
+ await server.members.ban(this.id, options);
1673
1702
  }
1674
1703
  /**
1675
- * Kicks this member from the server.
1704
+ * Creates a DM channel between the client's user and this member.
1705
+ * @param force If true, forces the creation of a new DM channel even if one already exists.
1706
+ * @returns A promise that resolves to the created DMChannel object.
1707
+ * @throws {Error} If the API request fails.
1708
+ * @example
1709
+ * // Create a DM with this member
1710
+ * const dm = await member.createDM();
1711
+ * console.log(`DM channel ID: ${dm.id}`);
1676
1712
  */
1677
- async kick() {
1713
+ async createDM(force = false) {
1714
+ await this.client.users.createDM(this.id, { force });
1715
+ }
1716
+ /**
1717
+ * Timeout this member for a specified duration.
1718
+ * @param duration The duration of the timeout in milliseconds.
1719
+ * @example
1720
+ * // Timeout a member for 10 minutes (600,000 milliseconds)
1721
+ * await member.setTimeout(600000);
1722
+ */
1723
+ async setTimeout(duration) {
1678
1724
  let server = this.server;
1679
1725
  if (!server) server = await this.client.servers.fetch(this.serverId);
1680
- await server.members.kick(this.id);
1726
+ await server.members.setTimeout(this.id, duration);
1727
+ }
1728
+ /** Checks if the member has a specific permission */
1729
+ hasPermission(permission) {
1730
+ return Permissions.has(this.permissions, permission);
1681
1731
  }
1682
1732
  /**
1683
- * Bans this member from the server.
1684
- * @param options The options for this ban
1733
+ * Edit this member.
1734
+ * @param options The options to edit the member with (nickname, roles, timeout, etc.)
1735
+ * @returns A promise that resolves to the updated Member.
1685
1736
  */
1686
- async ban(options) {
1737
+ async edit(options) {
1687
1738
  let server = this.server;
1688
1739
  if (!server) server = await this.client.servers.fetch(this.serverId);
1689
- await server.members.ban(this.id, options);
1740
+ return await server.members.edit(this.id, options);
1690
1741
  }
1691
- async unban() {
1692
- let server = this.client.servers.cache.get(this.serverId);
1742
+ /**
1743
+ * Kick this member from the server.
1744
+ */
1745
+ async kick() {
1746
+ let server = this.server;
1693
1747
  if (!server) server = await this.client.servers.fetch(this.serverId);
1694
- await server.members.unban(this.id);
1748
+ await server.members.kick(this.id);
1695
1749
  }
1750
+ /** @internal */
1696
1751
  [util4.inspect.custom](depth, options, inspect10) {
1697
1752
  const { client, serverId, ...props } = this;
1698
1753
  return `${this.constructor.name} ${inspect10(
@@ -1730,17 +1785,41 @@ var MemberManager = class extends BaseManager {
1730
1785
  }
1731
1786
  return new Member(this.client, data);
1732
1787
  }
1788
+ /**
1789
+ * Resolve a string or mention to Member
1790
+ * @param member The MemberResolvable to resolve
1791
+ * @returns The resolved Member or undefined if not found
1792
+ */
1733
1793
  resolve(member) {
1734
1794
  if (member instanceof Member) return member;
1735
1795
  if (member instanceof User) return this.cache.get(member.id);
1736
1796
  if (typeof member === "string") return this.cache.get(member.replace(/[<@>]/g, ""));
1737
1797
  return void 0;
1738
1798
  }
1799
+ /**
1800
+ * Resolve a Member to their ID string.
1801
+ * @param member The MemberResolvable to resolve
1802
+ * @returns The resolved ID string
1803
+ * @throws {TypeError} If the provided resolvable is invalid
1804
+ */
1739
1805
  resolveId(member) {
1740
1806
  if (typeof member === "string") return member.replace(/[<@>]/g, "");
1741
1807
  if ("id" in member) return member.id;
1742
1808
  throw new TypeError("Invalid MemberResolvable provided.");
1743
1809
  }
1810
+ /**
1811
+ * Fetches a member from the server, or returns the cached version if available and not forced.
1812
+ * @param member The MemberResolvable to fetch
1813
+ * @param force Whether to bypass the cache and fetch fresh data from the API
1814
+ * @returns A promise that resolves to the fetched Member
1815
+ * @throws {Error} If the API request fails or the member is not found
1816
+ * @example
1817
+ * // Fetch a member by ID, using cache if available
1818
+ * const member = await server.members.fetch("1234567890");
1819
+ *
1820
+ * // Fetch a member by mention, bypassing cache
1821
+ * const member = await server.members.fetch("<@1234567890>", true);
1822
+ */
1744
1823
  async fetch(member, force = false) {
1745
1824
  if (!force) {
1746
1825
  const cached = this.resolve(member);
@@ -1787,6 +1866,14 @@ var MemberManager = class extends BaseManager {
1787
1866
  * Edits a member in the server.
1788
1867
  * @param member The MemberResolvable to edit.
1789
1868
  * @param options The fields to update (nickname, roles, timeout, etc.).
1869
+ * @returns A promise that resolves to the updated Member.
1870
+ * @throws {Error} If the API request fails or the member is not found.
1871
+ * @example
1872
+ * // Change a member's nickname and add a role
1873
+ * const updatedMember = await server.members.edit("1234567890", {
1874
+ * nickname: "New Nickname",
1875
+ * roles: ["roleId1", "roleId2"],
1876
+ * });
1790
1877
  */
1791
1878
  async edit(member, options) {
1792
1879
  const id = this.resolveId(member);
@@ -1813,6 +1900,9 @@ var MemberManager = class extends BaseManager {
1813
1900
  /**
1814
1901
  * Kicks a member from the server.
1815
1902
  * @param member The MemberResolvable to kick.
1903
+ * @example
1904
+ * // Kick a member by ID
1905
+ * await server.members.kick("1234567890");
1816
1906
  */
1817
1907
  async kick(member) {
1818
1908
  const id = this.resolveId(member);
@@ -1823,6 +1913,9 @@ var MemberManager = class extends BaseManager {
1823
1913
  * Bans a member from the server.
1824
1914
  * @param member The MemberResolvable to ban.
1825
1915
  * @param options The ban options
1916
+ * @example
1917
+ * // Ban a member by ID
1918
+ * await server.members.ban("1234567890", { reason: "Spamming", deleteMessageSeconds: 3600 });
1826
1919
  */
1827
1920
  async ban(member, options) {
1828
1921
  const id = this.resolveId(member);
@@ -1835,11 +1928,26 @@ var MemberManager = class extends BaseManager {
1835
1928
  /**
1836
1929
  * Unbans a user from the server
1837
1930
  * @param member The MemberResolvable to unban
1931
+ * @example
1932
+ * // Unban a member by ID
1933
+ * await server.members.unban("1234567890");
1838
1934
  */
1839
1935
  async unban(member) {
1840
1936
  const id = this.resolveId(member);
1841
1937
  await this.client.rest.delete(`/servers/${this.server.id}/bans/${id}`);
1842
1938
  }
1939
+ /**
1940
+ * Timeouts a member in the server for a specified duration.
1941
+ * @param member The MemberResolvable to timeout
1942
+ * @param duration The duration of the timeout in milliseconds
1943
+ * @example
1944
+ * // Timeout a member for 10 minutes
1945
+ * await server.members.setTimeout("1234567890", 10 * 60 * 1000);
1946
+ */
1947
+ async setTimeout(member, duration) {
1948
+ const id = this.resolveId(member);
1949
+ await this.edit(id, { timeout: new Date(Date.now() + duration).toISOString() });
1950
+ }
1843
1951
  [util5.inspect.custom]() {
1844
1952
  return this.cache;
1845
1953
  }
@@ -2204,7 +2312,7 @@ var RoleManager = class extends BaseManager {
2204
2312
  * console.log("Role deleted successfully.");
2205
2313
  *
2206
2314
  * // Delete a role using a Role object
2207
- * const role = await server.roles.fetch("01JE2MM759J5D7CHJF084R7MJ2");
2315
+ * const role = await server.roles.fetch("01JE2MM759J5D7CHJF084R7");
2208
2316
  * await server.roles.delete(role);
2209
2317
  * console.log("Role deleted successfully.");
2210
2318
  *
@@ -2692,6 +2800,38 @@ var UserManager = class extends BaseManager {
2692
2800
  const data = await this.client.rest.patch(`/users/@me`, payload);
2693
2801
  return this._add(data);
2694
2802
  }
2803
+ /**
2804
+ * The DM between the client's user and a user
2805
+ *
2806
+ * @param {string} userId The user id
2807
+ * @returns {?DMChannel}
2808
+ * @private
2809
+ */
2810
+ dmChannel(userId) {
2811
+ return this.client.channels.cache.find((channel) => channel.isDM() && channel.recipients.includes(userId)) ?? null;
2812
+ }
2813
+ /**
2814
+ * Creates a DM channel between the client's user and another user.
2815
+ * @param user The UserResolvable to create a DM with.
2816
+ * @param options Additional options for DM creation.
2817
+ * @param options.force If true, forces the creation of a new DM channel even if one already exists.
2818
+ * @returns A promise that resolves to the created DMChannel object.
2819
+ * @throws {TypeError} If an invalid UserResolvable is provided.
2820
+ * @throws {Error} If the API request fails.
2821
+ * @example
2822
+ * // Create a DM with a user by ID
2823
+ * const dm = await client.users.createDM("1234567890");
2824
+ * console.log(`DM channel ID: ${dm.id}`);
2825
+ */
2826
+ async createDM(user, { force = false } = {}) {
2827
+ const id = this.resolveId(user);
2828
+ if (!force) {
2829
+ const dmChannel = this.dmChannel(id);
2830
+ if (dmChannel) return dmChannel;
2831
+ }
2832
+ const data = await this.client.rest.get(`/users/${id}/dm`);
2833
+ return this.client.channels._add(data);
2834
+ }
2695
2835
  };
2696
2836
 
2697
2837
  // src/managers/SweepManager.ts
@@ -2847,3 +2987,4 @@ var EmbedBuilder = class {
2847
2987
  UserPresence,
2848
2988
  UserRelationship
2849
2989
  });
2990
+ //# sourceMappingURL=index.cjs.map