├── .eslintignore ├── .eslintrc.js ├── .github ├── CODEOWNER ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── ci.yml │ └── docs.yml ├── .gitignore ├── .husky ├── .gitignore ├── commit-msg └── pre-commit ├── LICENSE ├── README.md ├── babel.config.js ├── commitlint.config.js ├── examples ├── README.md ├── command-handler │ ├── package-lock.json │ ├── package.json │ └── src │ │ ├── commands │ │ ├── embed.js │ │ └── ping.js │ │ └── index.js ├── getting-started │ ├── package-lock.json │ ├── package.json │ └── src │ │ └── index.js └── reactions │ ├── package-lock.json │ ├── package.json │ └── src │ └── index.js ├── jest.config.js ├── lerna.json ├── lint-staged.config.js ├── package-lock.json ├── package.json ├── packages ├── common │ ├── README.md │ ├── __tests__ │ │ ├── CacheCollection.test.ts │ │ ├── MessageUtil.test.data.json │ │ ├── MessageUtil.test.ts │ │ └── util.test.ts │ ├── lib │ │ ├── CacheCollection.ts │ │ ├── MessageUtil.ts │ │ ├── UUID.ts │ │ ├── index.ts │ │ └── util.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── embeds │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── embed.test.ts │ │ └── util.test.ts │ ├── lib │ │ ├── Embed.ts │ │ ├── consts.ts │ │ ├── index.ts │ │ └── util.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── guilded-api-typings │ ├── README.md │ ├── lib │ │ ├── common │ │ │ ├── Content.ts │ │ │ ├── Document.ts │ │ │ ├── Plant.ts │ │ │ ├── index.ts │ │ │ └── structures │ │ │ │ ├── Channel.ts │ │ │ │ ├── Emoji.ts │ │ │ │ ├── Team.ts │ │ │ │ ├── User.ts │ │ │ │ ├── Webhook.ts │ │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── rest │ │ │ ├── Channel.ts │ │ │ ├── Emoji.ts │ │ │ ├── Team.ts │ │ │ ├── User.ts │ │ │ ├── Webhook.ts │ │ │ └── index.ts │ │ └── ws │ │ │ ├── ChatMessageCreated.ts │ │ │ ├── ChatMessageReactionAdded.ts │ │ │ ├── ChatMessageReactionDeleted.ts │ │ │ ├── ChatMessageUpdated.ts │ │ │ ├── Ready.ts │ │ │ └── index.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── guilded.js │ ├── LICENSE │ ├── README.md │ ├── __tests__ │ │ ├── colors.js │ │ ├── index.js │ │ └── modules │ │ │ ├── connection.js │ │ │ ├── embed.js │ │ │ ├── invite.js │ │ │ ├── message.js │ │ │ ├── role.js │ │ │ └── ws.js │ ├── lib │ │ ├── index.ts │ │ ├── structures │ │ │ ├── Base.ts │ │ │ ├── Channel.ts │ │ │ ├── Client.ts │ │ │ ├── Group.ts │ │ │ ├── Member.ts │ │ │ ├── Message.ts │ │ │ ├── Role.ts │ │ │ ├── Team.ts │ │ │ ├── User.ts │ │ │ ├── Webhook.ts │ │ │ ├── index.ts │ │ │ └── managers │ │ │ │ ├── BaseManager.ts │ │ │ │ ├── ChannelManager.ts │ │ │ │ ├── MessageManager.ts │ │ │ │ ├── TeamGroupChannelManager.ts │ │ │ │ ├── TeamGroupManager.ts │ │ │ │ ├── TeamManager.ts │ │ │ │ ├── TeamMemberManager.ts │ │ │ │ ├── TeamMemberRoleManager.ts │ │ │ │ ├── TeamRoleManager.ts │ │ │ │ ├── TeamWebhookManager.ts │ │ │ │ ├── UserManager.ts │ │ │ │ └── index.ts │ │ ├── typings.ts │ │ ├── util.ts │ │ └── ws │ │ │ ├── ClientGatewayHandler.ts │ │ │ ├── GatewayHandler.ts │ │ │ ├── Heartbeater.ts │ │ │ └── events │ │ │ ├── ChatMessageCreated.ts │ │ │ ├── ChatMessageReactionAdded.ts │ │ │ ├── ChatMessageReactionDeleted.ts │ │ │ ├── ChatMessageUpdated.ts │ │ │ └── Event.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── rest │ ├── README.md │ ├── lib │ │ ├── GuildedAPIError.ts │ │ ├── RestManager.ts │ │ └── index.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json └── webhook-client │ ├── README.md │ ├── __tests__ │ └── Webhook.test.ts │ ├── lib │ ├── Webhook.ts │ └── index.ts │ ├── package-lock.json │ ├── package.json │ └── tsconfig.json ├── prettier.config.js ├── scripts ├── jest.js ├── post-docs.js ├── refresh.js ├── reset.js └── setup.js ├── static ├── guilded-icon.png ├── itami-transparent.png └── readme-header.png ├── testing.env.example ├── tsconfig.base.json ├── typedoc.config.js └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | types/ 4 | *.d.ts 5 | packages/**/*.js -------------------------------------------------------------------------------- /.github/CODEOWNER: -------------------------------------------------------------------------------- 1 | / @zaida04 -------------------------------------------------------------------------------- /.github/CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | https://discord.gg/jf66UUN. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | The issue tracker for bug reports and enhancement suggestions. If you have a question, please ask away! 3 | 4 | If you wish to contribute to the codebase or documentation, feel free to fork the repository and submit a pull request. We use ESLint to enforce a consistent coding style, so having that set up in your editor of choice is a great boon to your development process. 5 | 6 | # Setup 7 | To get ready to work on the codebase, please do the following: 8 | 9 | Fork & clone the repository, and make sure you're on the main branch 10 | Run npm install 11 | Code your heart out! 12 | Run npm run test to run ESLint and ensure any JSDoc changes are valid 13 | Submit a pull request (Make sure you follow the conventional commit format) 14 | 15 | > Adapted from https://github.com/discordjs/discord.js/blob/master/.github/CONTRIBUTING.md 16 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report something not working at expected. 4 | title: '' 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Please complete the following information** 27 | - NodeJS version (`node -v`) 28 | - NPM version (`npm -v`) 29 | - Package version (`npm ls @guildedjs/guilded.js`) 30 | 31 | **Additional context** 32 | Add any other context about the problem here. 33 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: zaida04 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Please describe the changes this PR makes and why it should be merged: 2 | 3 | Status 4 | [] Code changes have been tested. 5 | 6 | Semantic versioning classification: 7 | [] This PR changes the library's interface (methods or parameters added) 8 | [] This PR includes breaking changes (methods removed or renamed, parameters moved or removed) 9 | [] This PR only includes non-code changes, like changes to documentation, README, etc. -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI workflows 2 | on: [push, pull_request] 3 | jobs: 4 | lint: 5 | name: ESLint 6 | runs-on: ubuntu-latest 7 | steps: 8 | - name: Checkout repository 9 | uses: actions/checkout@v2 10 | 11 | - name: Install Node v14 12 | uses: actions/setup-node@v1 13 | with: 14 | node-version: 14 15 | 16 | - name: Use node_modules cache 17 | uses: actions/cache@v2 18 | with: 19 | path: '**/node_modules' 20 | key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }} 21 | 22 | - name: Install Main Dependencies 23 | if: ${{ !steps.cache-restore.outputs.cache-hit }} 24 | run: npm i 25 | 26 | - name: Install Sub Dependencies 27 | run: npm run bootstrap 28 | 29 | - name: Run ESLint 30 | run: npm run lint 31 | 32 | typescript: 33 | name: TypeScript Build 34 | runs-on: ubuntu-latest 35 | steps: 36 | - name: Checkout repository 37 | uses: actions/checkout@v2 38 | 39 | - name: Install Node v14 40 | uses: actions/setup-node@v1 41 | with: 42 | node-version: 14 43 | 44 | - name: Use node_modules cache 45 | uses: actions/cache@v2 46 | with: 47 | path: '**/node_modules' 48 | key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }} 49 | 50 | - name: Install Main Dependencies 51 | if: ${{ !steps.cache-restore.outputs.cache-hit }} 52 | run: npm i 53 | 54 | - name: Install Sub Dependencies 55 | run: npm run bootstrap 56 | 57 | - name: Run TSC 58 | run: npm run build 59 | 60 | tests: 61 | name: Jest tests 62 | runs-on: ubuntu-latest 63 | steps: 64 | - name: Checkout repository 65 | uses: actions/checkout@v2 66 | 67 | - name: Install Node v14 68 | uses: actions/setup-node@v1 69 | with: 70 | node-version: 14 71 | 72 | - name: Use node_modules cache 73 | uses: actions/cache@v2 74 | with: 75 | path: '**/node_modules' 76 | key: ${{ runner.os }}-node-modules-${{ hashFiles('**/package-lock.json') }} 77 | 78 | - name: Install Main Dependencies 79 | if: ${{ !steps.cache-restore.outputs.cache-hit }} 80 | run: npm i 81 | 82 | - name: Install Sub Dependencies 83 | run: npm run bootstrap 84 | 85 | - name: Run TSC 86 | run: npm run build 87 | 88 | - name: Run Jest 89 | run: npm run test -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Docs 2 | on: 3 | push: 4 | branches: 5 | - main 6 | jobs: 7 | docs: 8 | name: Deploy Docs 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout repository 12 | uses: actions/checkout@v2 13 | 14 | - name: Install Node v14 15 | uses: actions/setup-node@v1 16 | with: 17 | node-version: 14 18 | 19 | - name: Install Main Dependencies 20 | run: npm i 21 | 22 | - name: Install Sub Dependencies 23 | run: npm run bootstrap 24 | 25 | - name: Run TypeScript compiler 26 | run: npm run build 27 | 28 | - name: Build the docs 29 | run: npm run docs 30 | 31 | - name: Commit the Docs 32 | uses: cpina/github-action-push-to-another-repository@main 33 | env: 34 | API_TOKEN_GITHUB: ${{ secrets.API_TOKEN_GITHUB }} 35 | with: 36 | source-directory: "docs" 37 | destination-github-username: "github-actions[bot]" 38 | destination-repository-username: "zaida04" 39 | destination-repository-name: "guildedjs-selfbot-docs" 40 | target-branch: "master" 41 | user-email: 41898282+github-actions[bot]@users.noreply.github.com 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | types/ 4 | coverage/ 5 | 6 | .npmrc 7 | *.tsbuildinfo 8 | *.log 9 | 10 | *.config.json 11 | .vscode/ 12 | .idea/ 13 | *.env 14 | docs/ -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx --no-install commitlint --edit "$1" 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run build && npx lint-staged 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Zaid - Nico 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > # 🚨 This library has been discontinued in favor of the bot API version, which can be found [here](https://github.com/guildedjs/guilded.js-next) 2 | 3 |
4 | guildedjs 5 |

Tools for interacting with the Guilded.gg API.

6 |
7 |

8 | 9 | CI 10 | License: MIT
11 |

12 |
13 | 14 | ## 📝 About 15 | 16 | > ### ⚠️ This library only works with selfbots, which are a gray zone in Guilded. Use at your own risk. 17 | 18 | This repo serves as a monorepo that houses several packages, mainly the `@guildedjs/guilded.js` package, which is a library for the Guilded API. Inspired heavily by [discord.js](https://github.com/discordjs/discord.js) 19 | 20 | ## 📦 Packages 21 | 22 | - `@guildedjs/guilded.js` (**[GitHub](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/guilded.js#readme), [NPM](https://www.npmjs.com/package/@guildedjs/guilded.js)**) - main package that provides a lib for the guilded.gg API. Comes with built in caching, structures, etc. 23 | - `@guildedjs/guilded-api-types` (**[GitHub](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/guilded-api-typings#readme), [NPM](https://www.npmjs.com/package/@guildedjs/guilded-api-typings)**) - thinking of making your own guilded lib/wrapper? This package consists of typings for the guilded.gg API compiled together by the community. No need to write your own typings and reinvent the wheel. 24 | - `@guildedjs/rest` (**[GitHub](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/rest#readme), [NPM](https://www.npmjs.com/package/@guildedjs/rest)**) - Utility for making REST requests. 25 | - `@guildedjs/webhook-client` (**[GitHub](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/webhook-client#readme), [NPM](https://www.npmjs.com/package/@guildedjs/webhook-client)**) - Library-agnostic webhook client for interaction with guilded.gg API webhooks. 26 | - `@guildedjs/embeds` (**[GitHub](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/embeds#readme), [NPM](https://www.npmjs.com/package/@guildedjs/embeds)**) - Library-agnostic embed builder for sending messages with rich content through the guilded.gg API. 27 | - `@guildedjs/common` (**[GitHub](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/common#readme), [NPM](https://www.npmjs.com/package/@guildedjs/common)**) - Utilities and structures shared across various @guildedjs packages. 28 | 29 | ## 📥 Installation 30 | 31 | NPM 32 | 33 | **Recommended that you use node v12+** 34 | 35 | - `npm install @guildedjs/guilded.js` 36 | - `yarn add @guildedjs/guilded.js` 37 | 38 | ## ⚡ Usage 39 | 40 | You can find extra examples [here](https://github.com/zaida04/guilded.js-selfbot/tree/main/examples) 41 | 42 | ```ts 43 | const { Client } = require("@guildedjs/guilded.js"); 44 | 45 | /* 46 | * ES6: 47 | * import { Client } from "@guildedjs/guilded.js"; 48 | */ 49 | 50 | const client = new Client(); 51 | 52 | client.on("ready", () => console.log(`Bot is successfully logged in`)); 53 | 54 | client.on("messageCreate", (message) => { 55 | if (message.content === "poggers") { 56 | return message.channel.send("poggers indeed"); 57 | } 58 | }); 59 | 60 | client.login({ 61 | email: "email", 62 | password: "password", 63 | }); 64 | ``` 65 | 66 | ## 📃 Documentation 67 | 68 | Documentation is viewable here: https://zaida04.github.io/guildedjs-selfbot-docs 69 | 70 | 71 | 72 | ## ✋ Contributing 73 | 74 | Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**. 75 | 76 | **Please run `npm run bootstrap` after running npm install in your local environment.** 77 | **Please ensure your commits pass the test, lint, and build scripts.** 78 | 79 | **We make use of [lerna](https://lerna.js.org/) to manage our monorepo. The main commands used are below** 80 | 81 | - `lerna add [--scope=package-name]` - add npm module dependency to all/specific package(s) 82 | - `lerna create ` - create a new package 83 | - `npm run bootstrap` = `lerna bootstrap` - recursively install dependencies in all packages and symlink local packages 84 | - `lerna run ` - recursively execute command in all packages (must exist in each packages package.json) 85 | 86 | ## 🤝 Acknowledgements 87 | 88 | [Discord.js](https://github.com/discordjs/discord.js) - Main inspiration & lots of derived work. 89 | 90 | ## ⚖️ LICENSING 91 | 92 | > **Guilded.JS** © [zaida04](https://github.com/zaida04). All packages released under [MIT](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE). 93 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | comments: true, 3 | parserOpts: { strictMode: true }, 4 | plugins: ['babel-plugin-replace-ts-export-assignment', 'babel-plugin-const-enum'], 5 | presets: [ 6 | [ 7 | '@babel/preset-env', 8 | { 9 | modules: 'commonjs', 10 | targets: { node: 'current' }, 11 | }, 12 | ], 13 | '@babel/preset-typescript', 14 | ], 15 | sourceMaps: 'inline', 16 | }; 17 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: ['@commitlint/config-angular'], 3 | rules: { 4 | 'scope-case': [2, 'always', 'pascal-case'], 5 | 'type-enum': [ 6 | 2, 7 | 'always', 8 | ['chore', 'build', 'ci', 'docs', 'feat', 'fix', 'perf', 'refactor', 'revert', 'style', 'test'], 9 | ], 10 | }, 11 | }; 12 | -------------------------------------------------------------------------------- /examples/README.md: -------------------------------------------------------------------------------- 1 | # Examples 2 | Examples for some common functionalities of this lib. 3 | These examples are tested to work on latest before being updated. 4 | 5 | **If you are using this as a drop in starting point for your project, please change the lib require from "../../../packages/guilded.js" to "@guildedjs/guilded.js" and run `npm install @guildedjs/guilded.js`** 6 | 7 | ## Support 8 | If you encounter a legitimate error, please open an issue. 9 | If you have a question, please use the [Discord Server](https://discord.gg/jf66UUN). -------------------------------------------------------------------------------- /examples/command-handler/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/command-handler-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@discordjs/collection": { 8 | "version": "0.1.6", 9 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 10 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /examples/command-handler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/command-handler-example", 3 | "version": "1.0.0", 4 | "description": "Example of a command handler using @guildedjs", 5 | "main": "src/index.js", 6 | "private": true, 7 | "dependencies": { 8 | "@discordjs/collection": "^0.1.6" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 13 | }, 14 | "author": "Zaid \"Nico\"", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 18 | }, 19 | "homepage": "https://github.com/zaida04/guilded.js-selfbot#readme" 20 | } 21 | -------------------------------------------------------------------------------- /examples/command-handler/src/commands/embed.js: -------------------------------------------------------------------------------- 1 | const { Embed } = require('@guildedjs/guilded.js'); 2 | 3 | module.exports = { 4 | execute: (msg, args) => 5 | msg.channel.send(new Embed().setTitle('Test Embed!').setDescription(`Here are your args: ${args.join(', ')}`)), 6 | name: 'embed', 7 | }; 8 | -------------------------------------------------------------------------------- /examples/command-handler/src/commands/ping.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | aliases: ['ding'], 3 | execute: msg => msg.channel.send('pong!'), 4 | name: 'ping', 5 | }; 6 | -------------------------------------------------------------------------------- /examples/command-handler/src/index.js: -------------------------------------------------------------------------------- 1 | const Guilded = require('../../../packages/guilded.js'); 2 | const Collection = require('@discordjs/collection'); 3 | // function to construct paths to files 4 | const { join } = require('path'); 5 | // we use fs/promises here for the promisifed versions of fs functions 6 | const { readdir } = require('fs/promises'); 7 | const client = new Guilded.Client(); 8 | const context = { 9 | commands: new Collection(), 10 | }; 11 | const prefix = '!'; 12 | 13 | client.on('ready', () => { 14 | console.log('Guilded Bot is ready!'); 15 | }); 16 | 17 | client.on('messageCreate', async msg => { 18 | if (!msg.content.startsWith(prefix)) return; 19 | let [commandName, ...args] = msg.content.slice(prefix.length).trim().split(/ +/); 20 | commandName = commandName.toLowerCase(); 21 | 22 | const command = context.commands.get(commandName) ?? context.commands.find(x => x.aliases?.includes(commandName)); 23 | if (!command) return; 24 | 25 | try { 26 | await command.execute(msg, args); 27 | } catch (e) { 28 | msg.channel.send('There was an error executing that command!'); 29 | void console.error(e); 30 | } 31 | }); 32 | 33 | (async () => { 34 | // read the commands dir and have the file extensions. 35 | const commandDir = await readdir(join(__dirname, 'commands'), { withFileTypes: true }); 36 | 37 | // go through all the files/dirs scanned from the readdir, and make sure we only have js files 38 | for (const file of commandDir.filter(x => x.name.endsWith('.js'))) { 39 | const command = require(join(__dirname, 'commands', file.name)); 40 | context.commands.set(command.name, command); 41 | } 42 | 43 | client.login({ 44 | email: process.env.EMAIL, 45 | password: process.env.PASSWORD, 46 | }); 47 | })(); 48 | -------------------------------------------------------------------------------- /examples/getting-started/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/getting-started-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /examples/getting-started/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/getting-started-example", 3 | "version": "1.0.0", 4 | "description": "Getting started example for the @guildedjs/guilded.js", 5 | "main": "src/index.js", 6 | "private": true, 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 10 | }, 11 | "author": "Zaid \"Nico\"", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 15 | }, 16 | "homepage": "https://github.com/zaida04/guilded.js-selfbot#readme" 17 | } 18 | -------------------------------------------------------------------------------- /examples/getting-started/src/index.js: -------------------------------------------------------------------------------- 1 | // if you are not running this code in the examples directory, please run npm install @guildedjs/guilded.js and swap below. 2 | const Guilded = require('../../../packages/guilded.js'); 3 | const client = new Guilded.Client(); 4 | const prefix = '!'; 5 | 6 | // log to the console when the bot is "ready" 7 | client.on('ready', () => { 8 | console.log('Guilded Bot is ready!'); 9 | }); 10 | 11 | // on every message sent that your account can see in guilded (including your own), run the callback function provided. 12 | client.on('messageCreate', msg => { 13 | // if the message doesn't start with our prefix, we want to discard this message 14 | if (!msg.content.startsWith(prefix)) return; 15 | // we first slice off the prefix from the message content, get rid of spaces at the beginning and end of the message 16 | // and then split the string into an array based on every space in the message 17 | // we then destructure the returned array because we know the first element will always be the command name, and the rest are args 18 | const [commandName, ...args] = msg.content.slice(botConfig.GLOBAL_PREFIX.length).trim().split(/ +/); 19 | 20 | switch (commandName) { 21 | case 'hi': { 22 | return msg.channel.send('Hello!'); 23 | } 24 | case 'ping': { 25 | return msg.channel.send('Pong'); 26 | } 27 | case 'say': { 28 | return msg.channel.send(args.join(' ')); 29 | } 30 | case 'embed': { 31 | return msg.channel.send( 32 | new Guilded.Embed() 33 | .setTitle('Test Embed') 34 | .setDescription('Test Description') 35 | .setTimestamp() 36 | .setURL('https://google.com') 37 | .setFooter('Test Footer'), 38 | ); 39 | } 40 | } 41 | }); 42 | 43 | client.login({ 44 | email: process.env.EMAIL, 45 | password: process.env.PASSWORD, 46 | }); 47 | -------------------------------------------------------------------------------- /examples/reactions/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/getting-started-example", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1 5 | } 6 | -------------------------------------------------------------------------------- /examples/reactions/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/reactions-example", 3 | "version": "1.0.0", 4 | "description": "Getting started example for the @guildedjs/guilded.js", 5 | "main": "src/index.js", 6 | "private": true, 7 | "repository": { 8 | "type": "git", 9 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 10 | }, 11 | "author": "Zaid \"Nico\"", 12 | "license": "MIT", 13 | "bugs": { 14 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 15 | }, 16 | "homepage": "https://github.com/zaida04/guilded.js-selfbot#readme" 17 | } 18 | -------------------------------------------------------------------------------- /examples/reactions/src/index.js: -------------------------------------------------------------------------------- 1 | const Guilded = require('../../../packages/guilded.js'); 2 | const client = new Guilded.Client({ 3 | // without this, we would only receive events involving cached messages, so reactions on messages that were sent 4 | // before the bot was logged in would not be counted. 5 | partials: ['MESSAGE', 'CHANNEL'], 6 | }); 7 | 8 | // log to the console when the bot is "ready" 9 | client.on('ready', () => { 10 | console.log('Guilded Bot is ready!'); 11 | }); 12 | 13 | client.on('messageReactionAdd', (reaction, userOrId) => 14 | console.log(`${userOrId?.name ?? userOrId} just reacted with ${reaction.id}`), 15 | ); 16 | client.on('messageReactionDelete', (reactionOrId, userOrId) => 17 | // we use optional chaining here to tell whether it's a user object or an user ID 18 | // we also use optional chaining here to tell whether it's a reaction object or a reaction ID. 19 | console.log(`${userOrId?.name ?? userOrId} just removed their reaction ${reactionOrId?.id ?? reactionOrId}`), 20 | ); 21 | 22 | client.login({ 23 | email: process.env.EMAIL, 24 | password: process.env.PASSWORD, 25 | }); 26 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@jest/types').Config.InitialOptions} */ 2 | module.exports = { 3 | collectCoverage: true, 4 | coverageDirectory: 'coverage', 5 | coveragePathIgnorePatterns: ['dist/'], 6 | coveragePathIgnorePatterns: ['/node_modules/', '/packages/rest'], 7 | coverageReporters: ['text', 'lcov', 'clover'], 8 | coverageThreshold: { 9 | global: { 10 | branches: 80, 11 | functions: 80, 12 | lines: 80, 13 | statements: 80, 14 | }, 15 | }, 16 | roots: ['/packages'], 17 | setupFilesAfterEnv: ['/scripts/jest.js', 'dotenv/config'], 18 | testEnvironment: 'node', 19 | testMatch: ['**/__tests__/**/*.test.ts'], 20 | }; 21 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "command": { 3 | "publish": { 4 | "message": "chore: release" 5 | } 6 | }, 7 | "publishConfig": { 8 | "access": "public" 9 | }, 10 | "packages": [ 11 | "packages/*" 12 | ], 13 | "version": "independent" 14 | } -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{js,ts}': 'eslint --fix --ext ts,js', 3 | }; 4 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/main", 3 | "version": "0.0.0", 4 | "description": "Main overarching package utilizing lerna to manage all the @guildedjs packages", 5 | "private": true, 6 | "author": "Zaid \"Nico\"", 7 | "license": "MIT", 8 | "scripts": { 9 | "build": "npx lerna run build", 10 | "bootstrap": "npx lerna bootstrap", 11 | "lint": "npx eslint packages/ scripts/ --ext .ts,.js", 12 | "lint:fix": "npm run lint -- --fix", 13 | "docs": "npx rimraf docs && npx typedoc --options typedoc.config.js packages && node scripts/post-docs.js", 14 | "test": "npx jest", 15 | "test:build": "npm run build && npx jest", 16 | "prepublishOnly": "npm run lint && npx lerna run prepublishOnly", 17 | "prepare": "husky install", 18 | "changelog": "npx conventional-changelog -p angular -i CHANGELOG.md -s", 19 | "reset": "cd scripts && node refresh.js" 20 | }, 21 | "devDependencies": { 22 | "@babel/core": "^7.12.17", 23 | "@babel/generator": "^7.13.0", 24 | "@babel/preset-env": "^7.12.17", 25 | "@babel/preset-typescript": "^7.12.17", 26 | "@commitlint/cli": "^11.0.0", 27 | "@commitlint/config-angular": "^11.0.0", 28 | "@strictsoftware/typedoc-plugin-monorepo": "^0.3.1", 29 | "@types/jest": "^26.0.24", 30 | "@typescript-eslint/eslint-plugin": "^3.9.0", 31 | "@typescript-eslint/parser": "^3.9.0", 32 | "babel-jest": "^26.6.3", 33 | "babel-plugin-const-enum": "^1.0.1", 34 | "babel-plugin-replace-ts-export-assignment": "^0.0.2", 35 | "conventional-changelog-cli": "^2.1.1", 36 | "dotenv": "^8.2.0", 37 | "eslint": "^7.6.0", 38 | "eslint-config-prettier": "^6.11.0", 39 | "eslint-plugin-prettier": "^3.1.4", 40 | "eslint-plugin-simple-import-sort": "^5.0.3", 41 | "eslint-plugin-sort-keys-fix": "^1.1.1", 42 | "husky": "^6.0.0", 43 | "jest": "^27.0.6", 44 | "lerna": "^3.22.1", 45 | "lint-staged": "^10.4.2", 46 | "prettier": "^2.0.5", 47 | "rimraf": "^3.0.2", 48 | "typedoc": "^0.19.2", 49 | "typedoc-plugin-remove-references": "0.0.5", 50 | "typescript": "^4.0.5" 51 | }, 52 | "repository": { 53 | "type": "git", 54 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 55 | }, 56 | "bugs": { 57 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 58 | }, 59 | "homepage": "https://github.com/zaida04/guilded.js-selfbot#readme" 60 | } 61 | -------------------------------------------------------------------------------- /packages/common/README.md: -------------------------------------------------------------------------------- 1 | # `@guildedjs/common` 2 | 3 | [![GitHub](https://img.shields.io/github/license/zaida04/guilded.js-selfbot)](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 4 | [![npm](https://img.shields.io/npm/v/@guildedjs/common?color=crimson&logo=npm)](https://www.npmjs.com/package/@guildedjs/common) 5 | [![CI workflows](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml/badge.svg)](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml) 6 | 7 | Common structures and utilities used in various @guildedjs packages 8 | 9 | > ⚠️ If you intend to use `@guildedjs/guilded.js` you won't need to install this, as it's already a dependency of that package. 10 | 11 | ## Installation 12 | 13 | You can install this package from [NPM](https://www.npmjs.com/package/@guildedjs/common) 14 | 15 | - `npm install @guildedjs/common` 16 | - `yarn add @guildedjs/common` 17 | 18 | ## Contributing 19 | 20 | Please see the main [README.md](https://github.com/zaida04/guilded.js-selfbot) for info on how to contribute to this package or the other `@guildedjs` packages. 21 | 22 | ## Credits 23 | 24 | Concept and structure dervied from https://github.com/discordjs/discord.js/blob/stable/src/structures/MessageEmbed.js#L9 - [Discord.js](https://github.com/discordjs/discord.js) ([License](https://github.com/discordjs/discord.js/blob/stable/LICENSE)) 25 | 26 | ## LICENSE 27 | 28 | Licensed under the [MIT License](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 29 | -------------------------------------------------------------------------------- /packages/common/__tests__/CacheCollection.test.ts: -------------------------------------------------------------------------------- 1 | import { CacheCollection } from '..'; 2 | const zeroOrNegativeErrorMessage = 'Cannot pass 0 or negative value as maxSize.'; 3 | 4 | test('Successful construction with default cache maxSize', () => { 5 | expect(new CacheCollection().maxSize).toStrictEqual(Infinity); 6 | expect(() => new CacheCollection({ maxSize: undefined })).not.toThrow(); 7 | }); 8 | 9 | test('Abiding by cache maxSize', () => { 10 | const cache = new CacheCollection({ maxSize: 500 }); 11 | for (let i = 0; i < 505; i++) { 12 | cache.set(`test-${i}`, i); 13 | } 14 | expect(cache.size).toStrictEqual(500); 15 | }); 16 | 17 | test('Properly error on invalid maxSize being passed', () => { 18 | expect(() => new CacheCollection({ maxSize: 0 })).toThrow(new TypeError(zeroOrNegativeErrorMessage)); 19 | expect(() => new CacheCollection({ maxSize: -1 })).toThrow(new TypeError(zeroOrNegativeErrorMessage)); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/common/__tests__/MessageUtil.test.ts: -------------------------------------------------------------------------------- 1 | import { generateMessage, parseMessage, parseToMessage } from '..'; 2 | import { Embed } from '../../embeds'; 3 | import data from './MessageUtil.test.data.json'; 4 | 5 | const testingMessage1 = 'TESTING MESSAGE' as const; 6 | const testingMessage2 = 'TESTING MESSAGE 2' as const; 7 | const testingMessage3 = 'TESTING MESSAGE 3' as const; 8 | 9 | // taken from https://stackoverflow.com/a/13653180, show them some love. 10 | const UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-5][0-9a-f]{3}-[089ab][0-9a-f]{3}-[0-9a-f]{12}$/i; 11 | 12 | test('convert plain-text content to proper message format', () => { 13 | expect(parseToMessage(testingMessage1)).toStrictEqual(data['plain-message']); 14 | }); 15 | test('convert embed content to proper message format', () => { 16 | expect(parseToMessage(new Embed().setTitle(testingMessage1))).toEqual(data['embed-message']); 17 | }); 18 | test('convert both plain-text and embed content to proper message format', () => { 19 | expect(parseToMessage(testingMessage2, new Embed().setTitle(testingMessage3))).toEqual(data['mixed-message']); 20 | }); 21 | test('generate valid sendable plain-text message structure', () => { 22 | const [id, message] = generateMessage(testingMessage1); 23 | expect(id).toMatch(UUID_REGEX); 24 | expect(message.content).toStrictEqual(data['plain-message']); 25 | }); 26 | test('generate valid sendable embed message structure', () => { 27 | const [id, message] = generateMessage(new Embed().setTitle(testingMessage1)); 28 | expect(id).toMatch(UUID_REGEX); 29 | expect(message.content).toEqual(data['embed-message']); 30 | }); 31 | test('generate valid sendable embed and plain-text message structure', () => { 32 | const [id, message] = generateMessage(testingMessage2, new Embed().setTitle(testingMessage3)); 33 | expect(id).toMatch(UUID_REGEX); 34 | expect(message.content).toEqual(data['mixed-message']); 35 | }); 36 | 37 | test('parse regular message', () => { 38 | expect(parseMessage(data['plain-message'])).toStrictEqual({ 39 | embeds: [], 40 | mentions: { 41 | channels: [], 42 | reactions: [], 43 | roles: [], 44 | users: [], 45 | }, 46 | parsedArr: [{ content: 'TESTING MESSAGE', type: 'text' }], 47 | parsedText: 'TESTING MESSAGE', 48 | }); 49 | }); 50 | 51 | test('parse embed message', () => { 52 | expect(parseMessage(data['embed-message'])).toStrictEqual({ 53 | embeds: [ 54 | { 55 | fields: [], 56 | title: 'TESTING MESSAGE', 57 | }, 58 | ], 59 | mentions: { 60 | channels: [], 61 | reactions: [], 62 | roles: [], 63 | users: [], 64 | }, 65 | parsedArr: [], 66 | parsedText: '', 67 | }); 68 | }); 69 | 70 | test('parse multi-line message', () => { 71 | expect(parseMessage(data['multi-line'])).toStrictEqual({ 72 | embeds: [], 73 | mentions: { 74 | channels: [], 75 | reactions: [], 76 | roles: [], 77 | users: [], 78 | }, 79 | parsedArr: [ 80 | { content: 'MULTILINE', type: 'text' }, 81 | { content: 'STRING', type: 'text' }, 82 | { content: 'TEST', type: 'text' }, 83 | ], 84 | parsedText: 'MULTILINE\nSTRING\nTEST', 85 | }); 86 | }); 87 | 88 | test('parse message with user mentions', () => { 89 | expect(parseMessage(data['user-mention'])).toStrictEqual({ 90 | embeds: [], 91 | mentions: { 92 | channels: [], 93 | reactions: [], 94 | roles: [], 95 | users: ['user-id'], 96 | }, 97 | parsedArr: [ 98 | { 99 | content: '@nico', 100 | mention: { 101 | avatar: data.avatarURL, 102 | color: '#ececee', 103 | id: 'user-id', 104 | matcher: '@nico', 105 | name: 'nico', 106 | nickname: false, 107 | type: 'person', 108 | }, 109 | type: 'user', 110 | }, 111 | { content: ' testing testing!', type: 'text' }, 112 | ], 113 | parsedText: '@nico testing testing!', 114 | }); 115 | }); 116 | test('parse message with role mentions', () => { 117 | expect(parseMessage(data['role-mention'])).toStrictEqual({ 118 | embeds: [], 119 | mentions: { 120 | channels: [], 121 | reactions: [], 122 | roles: ['10000000'], 123 | users: [], 124 | }, 125 | parsedArr: [ 126 | { 127 | content: '@Captain', 128 | mention: { 129 | color: '#d9acff', 130 | id: 10000000, 131 | matcher: '@captain', 132 | name: 'Captain', 133 | type: 'role', 134 | }, 135 | type: 'role', 136 | }, 137 | { content: ' testing testing 3!', type: 'text' }, 138 | ], 139 | parsedText: '@Captain testing testing 3!', 140 | }); 141 | }); 142 | test('parse message with channel mentions', () => { 143 | expect(parseMessage(data['channel-mention'])).toStrictEqual({ 144 | embeds: [], 145 | mentions: { 146 | channels: ['channel-id'], 147 | reactions: [], 148 | roles: [], 149 | users: [], 150 | }, 151 | parsedArr: [ 152 | { 153 | channel: { 154 | id: 'channel-id', 155 | matcher: '#testing', 156 | name: 'testing', 157 | }, 158 | content: '#testing', 159 | type: 'channel', 160 | }, 161 | { content: ' testing testing!', type: 'text' }, 162 | ], 163 | parsedText: '#testing testing testing!', 164 | }); 165 | }); 166 | test('parse message with mixed mentions', () => {}); 167 | -------------------------------------------------------------------------------- /packages/common/lib/CacheCollection.ts: -------------------------------------------------------------------------------- 1 | import Collection from '@discordjs/collection'; 2 | 3 | /** 4 | * A collection with a max cap size, which will remove a random element 5 | */ 6 | export class CacheCollection extends Collection { 7 | public maxSize: number; 8 | 9 | public constructor(options?: CacheCollectionOptions, entries?: readonly (readonly [K, V])[] | null | undefined) { 10 | super(entries); 11 | if (options?.maxSize !== undefined && options.maxSize < 1) { 12 | throw new TypeError('Cannot pass 0 or negative value as maxSize.'); 13 | } 14 | this.maxSize = options?.maxSize ?? Infinity; 15 | } 16 | 17 | public set(...args: Parameters): this { 18 | if (this.size >= this.maxSize) this.delete(this.firstKey()!); 19 | return super.set(...args); 20 | } 21 | } 22 | 23 | export interface CacheCollectionOptions { 24 | maxSize?: number; 25 | } 26 | -------------------------------------------------------------------------------- /packages/common/lib/UUID.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | export { v4 as generateUUID } from 'uuid'; 3 | -------------------------------------------------------------------------------- /packages/common/lib/index.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | export * from './MessageUtil'; 3 | export * from './util'; 4 | export * from './CacheCollection'; 5 | export * from './UUID'; 6 | -------------------------------------------------------------------------------- /packages/common/lib/util.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | 3 | export enum IMG_EXTENSION { 4 | PNG = 'png', 5 | GIF = 'gif', 6 | WEBP = 'webp', 7 | } 8 | 9 | export type IMG_SIZE = 'Small' | 'Medium' | 'Large'; 10 | 11 | const formAssetURL = ( 12 | route: string, 13 | hash: string, 14 | extension: string, 15 | width?: number, 16 | height?: number, 17 | size?: string, 18 | ) => { 19 | const url = new URL(`https://${ROUTES.IMAGE_CDN_DOMAIN}/${route}/${hash}-${size}.${extension.toLowerCase()}`); 20 | if (width) url.searchParams.append('w', width.toString()); 21 | if (height) url.searchParams.append('h', height.toString()); 22 | return url.toString(); 23 | }; 24 | 25 | export const ROUTES = { 26 | ASSETS: { 27 | AVATAR_URL: (hash: string, size: IMG_SIZE = 'Medium'): string => 28 | formAssetURL('UserAvatar', hash, IMG_EXTENSION.PNG, undefined, undefined, size), 29 | IMAGE_IN_CHAT: (hash: string, size = 'Full', width?: number, height?: number): string => 30 | formAssetURL('ContentMedia', hash, IMG_EXTENSION.WEBP, width, height, size), 31 | PROFILE_BANNER: (hash: string, size = 'Hero', width?: number, height?: number): string => 32 | formAssetURL('UserBanner', hash, IMG_EXTENSION.PNG, width, height, size), 33 | TEAM_BANNER: (hash: string, size = 'Hero', width?: number, height?: number): string => 34 | formAssetURL('TeamBanner', hash, IMG_EXTENSION.PNG, width, height, size), 35 | TEAM_EMOJI: ( 36 | hash: string, 37 | size = 'Full', 38 | extension: 'WEBP' | 'APNG' = 'WEBP', 39 | width?: number, 40 | height?: number, 41 | ): string => formAssetURL('CustomReaction', hash, extension.toLowerCase(), width, height, size), 42 | TEAM_ICON: (hash: string, size: 'Small' | 'Medium' | 'Large' = 'Medium'): string => 43 | formAssetURL('TeamAvatar', hash, IMG_EXTENSION.PNG, undefined, undefined, size), 44 | }, 45 | AWS_CDN: 'https://s3-us-west-2.amazonaws.com/www.guilded.gg/' as const, 46 | BASE_DOMAIN: 'api.guilded.gg' as const, 47 | CDN: 'img.guildedcdn.com' as const, 48 | IMAGE_CDN_DOMAIN: 'img.guildedcdn.com' as const, 49 | MEDIA_DOMAIN: 'media.guilded.gg' as const, 50 | }; 51 | -------------------------------------------------------------------------------- /packages/common/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/common", 3 | "version": "1.0.5-selfbot", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@guildedjs/common", 9 | "version": "1.0.3-selfbot", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@discordjs/collection": "^0.1.6", 13 | "uuid": "^8.3.2" 14 | }, 15 | "devDependencies": { 16 | "@guildedjs/guilded-api-typings": "^1.3.1", 17 | "@types/uuid": "^8.3.0", 18 | "typescript": "^4.4.2" 19 | } 20 | }, 21 | "node_modules/@discordjs/collection": { 22 | "version": "0.1.6", 23 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 24 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 25 | }, 26 | "node_modules/@guildedjs/guilded-api-typings": { 27 | "version": "1.3.1", 28 | "resolved": "https://registry.npmjs.org/@guildedjs/guilded-api-typings/-/guilded-api-typings-1.3.1.tgz", 29 | "integrity": "sha512-deoCfmBpnltL3G5nwxFKKdn+tyq7YfB/0VKoXE8vx3XrjrRWuipXnlXsDs4CtrwVdhmrflQCXQG3TtQf0Bv5LQ==", 30 | "dev": true 31 | }, 32 | "node_modules/@types/uuid": { 33 | "version": "8.3.0", 34 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", 35 | "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", 36 | "dev": true 37 | }, 38 | "node_modules/typescript": { 39 | "version": "4.4.2", 40 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 41 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 42 | "dev": true, 43 | "bin": { 44 | "tsc": "bin/tsc", 45 | "tsserver": "bin/tsserver" 46 | }, 47 | "engines": { 48 | "node": ">=4.2.0" 49 | } 50 | }, 51 | "node_modules/uuid": { 52 | "version": "8.3.2", 53 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 54 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 55 | "bin": { 56 | "uuid": "dist/bin/uuid" 57 | } 58 | } 59 | }, 60 | "dependencies": { 61 | "@discordjs/collection": { 62 | "version": "0.1.6", 63 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 64 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 65 | }, 66 | "@guildedjs/guilded-api-typings": { 67 | "version": "1.3.1", 68 | "resolved": "https://registry.npmjs.org/@guildedjs/guilded-api-typings/-/guilded-api-typings-1.3.1.tgz", 69 | "integrity": "sha512-deoCfmBpnltL3G5nwxFKKdn+tyq7YfB/0VKoXE8vx3XrjrRWuipXnlXsDs4CtrwVdhmrflQCXQG3TtQf0Bv5LQ==", 70 | "dev": true 71 | }, 72 | "@types/uuid": { 73 | "version": "8.3.0", 74 | "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.0.tgz", 75 | "integrity": "sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ==", 76 | "dev": true 77 | }, 78 | "typescript": { 79 | "version": "4.4.2", 80 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 81 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 82 | "dev": true 83 | }, 84 | "uuid": { 85 | "version": "8.3.2", 86 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 87 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/common/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/common", 3 | "version": "1.0.5-selfbot", 4 | "description": "Common structures and utilities used in various @guildedjs packages", 5 | "author": "Zaid \"Nico\" ", 6 | "homepage": "https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/common#readme", 7 | "license": "MIT", 8 | "types": "types/index.d.ts", 9 | "main": "dist/index.js", 10 | "scripts": { 11 | "test": "npm run build && node ./__tests__/index.js", 12 | "build": "tsc", 13 | "prepublishOnly": "npx rimraf dist/ && npx rimraf types/ && npm run build" 14 | }, 15 | "devDependencies": { 16 | "@guildedjs/guilded-api-typings": "^1.3.1", 17 | "@types/uuid": "^8.3.0", 18 | "typescript": "^4.4.2" 19 | }, 20 | "dependencies": { 21 | "@discordjs/collection": "^0.1.6", 22 | "@guildedjs/embeds": "^1.0.5-selfbot", 23 | "uuid": "^8.3.2" 24 | }, 25 | "keywords": [ 26 | "guilded-gg", 27 | "guilded-api", 28 | "guilded-webhook" 29 | ], 30 | "directories": { 31 | "lib": "lib", 32 | "test": "__tests__" 33 | }, 34 | "files": [ 35 | "dist", 36 | "types" 37 | ], 38 | "publishConfig": { 39 | "access": "public" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 44 | }, 45 | "bugs": { 46 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 47 | }, 48 | "gitHead": "0719b880becce0aa4bccaf5eb5b210ecb08b0547" 49 | } 50 | -------------------------------------------------------------------------------- /packages/common/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "declarationDir": "./types" 6 | }, 7 | "include": [ "./lib/**/*.ts" ], 8 | "exclude": [ "*.test.ts"] 9 | } -------------------------------------------------------------------------------- /packages/embeds/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Zaid - Nico 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /packages/embeds/README.md: -------------------------------------------------------------------------------- 1 | # `@guildedjs/embeds` 2 | 3 | [![GitHub](https://img.shields.io/github/license/zaida04/guilded.js-selfbot)](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 4 | [![npm](https://img.shields.io/npm/v/@guildedjs/embeds?color=crimson&logo=npm)](https://www.npmjs.com/package/@guildedjs/embeds) 5 | [![CI workflows](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml/badge.svg)](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml) 6 | 7 | Library-agnostic embed builder utility for the guilded.gg API 8 | 9 | > ⚠️ If you intend to use `@guildedjs/guilded.js` you won't need to install this, as it's already a dependency of that package. 10 | 11 | ## Installation 12 | 13 | You can install this package from [NPM](https://www.npmjs.com/package/@guildedjs/embeds) 14 | 15 | - `npm install @guildedjs/embeds` 16 | - `yarn add @guildedjs/embeds` 17 | 18 | ## Contributing 19 | 20 | Please see the main [README.md](https://github.com/zaida04/guilded.js-selfbot) for info on how to contribute to this package or the other `@guildedjs` packages. 21 | 22 | ## Credits 23 | 24 | Concept and structure dervied from https://github.com/discordjs/discord.js/blob/stable/src/structures/MessageEmbed.js#L9 - [Discord.js](https://github.com/discordjs/discord.js) ([License](https://github.com/discordjs/discord.js/blob/stable/LICENSE)) 25 | 26 | ## LICENSE 27 | 28 | Licensed under the [MIT License](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 29 | -------------------------------------------------------------------------------- /packages/embeds/__tests__/util.test.ts: -------------------------------------------------------------------------------- 1 | import { resolveColor } from '..'; 2 | 3 | test('parse Hexadecimal string', () => { 4 | expect(resolveColor('#f5c400')).toStrictEqual(0xf5c400); 5 | }); 6 | test('parse Color string', () => { 7 | expect(resolveColor('GUILDED')).toStrictEqual(0xf5c400); 8 | }); 9 | test('parse RGB value', () => { 10 | expect(resolveColor([245, 196, 0])).toStrictEqual(0xf5c400); 11 | }); 12 | test('test RANDOM value', () => { 13 | expect(typeof resolveColor('RANDOM')).toEqual('number'); 14 | }); 15 | test('Get error on out of range number', () => { 16 | expect(() => resolveColor(0xfffffff)).toThrow(new RangeError('COLOR_RANGE')); 17 | }); 18 | test('Get error on bad string input', () => { 19 | expect(() => resolveColor('SIUDFHUISDHFIUHSDUDIFHIUSDHFUISDI')).toThrow(new TypeError('COLOR_CONVERT')); 20 | }); 21 | -------------------------------------------------------------------------------- /packages/embeds/lib/consts.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2015 - 2021 Amish Shah 3 | * Copyrights licensed under the Apache License 2.0, https://github.com/discordjs/discord.js/blob/master/LICENSE 4 | * Taken from https://github.com/discordjs/discord.js/blob/stable/src/util/Constants.js 5 | */ 6 | export const COLORS: { [key: string]: number } = { 7 | AQUA: 0x1abc9c, 8 | BLUE: 0x3498db, 9 | DARKER_GREY: 0x7f8c8d, 10 | DARK_AQUA: 0x11806a, 11 | DARK_BLUE: 0x206694, 12 | DARK_BUT_NOT_BLACK: 0x2c2f33, 13 | DARK_GOLD: 0xc27c0e, 14 | DARK_GREEN: 0x1f8b4c, 15 | DARK_GREY: 0x979c9f, 16 | DARK_NAVY: 0x2c3e50, 17 | DARK_ORANGE: 0xa84300, 18 | DARK_PURPLE: 0x71368a, 19 | DARK_RED: 0x992d22, 20 | DARK_VIVID_PINK: 0xad1457, 21 | DEFAULT: 0x000000, 22 | GOLD: 0xf1c40f, 23 | GREEN: 0x2ecc71, 24 | GREY: 0x95a5a6, 25 | GREYPLE: 0x99aab5, 26 | GUILDED: 0xf5c400, 27 | LIGHT_GREY: 0xbcc0c0, 28 | LUMINOUS_VIVID_PINK: 0xe91e63, 29 | NAVY: 0x34495e, 30 | NOT_QUITE_BLACK: 0x23272a, 31 | ORANGE: 0xe67e22, 32 | PURPLE: 0x9b59b6, 33 | RED: 0xe74c3c, 34 | WHITE: 0xffffff, 35 | YELLOW: 0xffff00, 36 | } as const; 37 | -------------------------------------------------------------------------------- /packages/embeds/lib/index.ts: -------------------------------------------------------------------------------- 1 | import { Embed } from './Embed'; 2 | export * from './util'; 3 | export { Embed }; 4 | export default Embed; 5 | -------------------------------------------------------------------------------- /packages/embeds/lib/util.ts: -------------------------------------------------------------------------------- 1 | import { COLORS } from './consts'; 2 | 3 | /** 4 | * Copyright 2015 - 2021 Amish Shah 5 | * Copyrights licensed under the Apache License 2.0, https://github.com/discordjs/discord.js/blob/master/LICENSE 6 | * Taken from https://github.com/discordjs/discord.js/blob/stable/src/util/Util.js#L436 7 | */ 8 | export function resolveColor(color: string | number | [number, number, number]): number { 9 | if (typeof color === 'string') { 10 | if (color === 'RANDOM') return Math.floor(Math.random() * (0xffffff + 1)); 11 | color = COLORS[color.toUpperCase()] ?? parseInt(color.replace('#', ''), 16); 12 | } else if (Array.isArray(color)) { 13 | color = (color[0] << 16) + (color[1] << 8) + color[2]; 14 | } 15 | 16 | if (color < 0 || color > 0xffffff) throw new RangeError('COLOR_RANGE'); 17 | else if (isNaN(color)) throw new TypeError('COLOR_CONVERT'); 18 | 19 | return color; 20 | } 21 | -------------------------------------------------------------------------------- /packages/embeds/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/embeds", 3 | "version": "1.0.5-selfbot", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@guildedjs/embeds", 9 | "version": "1.0.3-selfbot", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "typescript": "^4.4.2" 13 | } 14 | }, 15 | "node_modules/typescript": { 16 | "version": "4.4.2", 17 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 18 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 19 | "dev": true, 20 | "bin": { 21 | "tsc": "bin/tsc", 22 | "tsserver": "bin/tsserver" 23 | }, 24 | "engines": { 25 | "node": ">=4.2.0" 26 | } 27 | } 28 | }, 29 | "dependencies": { 30 | "typescript": { 31 | "version": "4.4.2", 32 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 33 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 34 | "dev": true 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/embeds/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/embeds", 3 | "version": "1.0.5-selfbot", 4 | "description": "Library-agnostic guilded embed builder utility for the guilded.gg API", 5 | "author": "Zaid \"Nico\" ", 6 | "homepage": "https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/embeds#readme", 7 | "license": "MIT", 8 | "types": "types/index.d.ts", 9 | "main": "dist/index.js", 10 | "scripts": { 11 | "test": "npm run build && node ./__tests__/index.js", 12 | "build": "tsc", 13 | "prepublishOnly": "npx rimraf dist/ && npx rimraf types/ && npm run build" 14 | }, 15 | "devDependencies": { 16 | "@guildedjs/guilded-api-typings": "^1.4.1-selfbot", 17 | "typescript": "^4.4.2" 18 | }, 19 | "keywords": [ 20 | "guilded-gg", 21 | "guilded-api", 22 | "guilded-embed", 23 | "embed" 24 | ], 25 | "directories": { 26 | "lib": "lib", 27 | "test": "__tests__" 28 | }, 29 | "files": [ 30 | "dist", 31 | "types" 32 | ], 33 | "publishConfig": { 34 | "access": "public" 35 | }, 36 | "repository": { 37 | "type": "git", 38 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 39 | }, 40 | "bugs": { 41 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 42 | }, 43 | "gitHead": "0719b880becce0aa4bccaf5eb5b210ecb08b0547" 44 | } 45 | -------------------------------------------------------------------------------- /packages/embeds/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "declarationDir": "./types" 6 | }, 7 | "include": [ "./lib/**/*.ts" ], 8 | "exclude": [ "*.test.ts"] 9 | } -------------------------------------------------------------------------------- /packages/guilded-api-typings/README.md: -------------------------------------------------------------------------------- 1 | # `@guildedjs/guilded-api-typings` 2 | 3 | [![GitHub](https://img.shields.io/github/license/zaida04/guilded.js-selfbot)](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 4 | [![npm](https://img.shields.io/npm/v/@guildedjs/guilded-api-typings?color=crimson&logo=npm)](https://www.npmjs.com/package/@guildedjs/guilded-api-typings) 5 | [![CI workflows](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml/badge.svg)](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml) 6 | 7 | TypeScript Typings for the Guilded.gg API. 8 | 9 | > ⚠️ If you intend to use `@guildedjs/guilded.js` you won't need to install this, as it's already a dependency of that package. 10 | 11 | ## Installation 12 | 13 | You can install this package from [NPM](https://www.npmjs.com/package/@guildedjs/guilded-api-typings) 14 | 15 | - `npm install @guildedjs/guilded-api-typings` 16 | - `yarn add @guildedjs/guilded-api-typings` 17 | 18 | ## Structure 19 | 20 | - `lib/rest` - Response from REST reqs to the API. Typings here are prefixed with `API`, then the `HTTP METHOD` that the request uses, then the request title. So for example `APIGetAPIChannels`, `APIGetChannelMessage`. If the request contains a body or query, the typings will have either `Result`, `Body`, or `Query` appended to the end of the typing name. E.x. `APIPostChannelMessagesBody`, `APIPostChannelMessagesResult`. `Body` is the body of the request you send, while `Result` is the response you get back from the API, and `Query` is the URL queries that you will put into the URL. 21 | - `lib/ws` - Payloads from the WS Gateway. Typings here are prefixed with `WS`. 22 | - `lib/common` - Common structures that may be sent by either WS or REST. Typings here are prefixed with `API`. 23 | 24 | ## Contributing 25 | 26 | Please see the main [README.md](https://github.com/zaida04/guilded.js-selfbot) for info on how to contribute to this package or the other `@guildedjs` packages. 27 | 28 | ## Credits 29 | 30 | Huge thank you to [Shay](https://github.com/shayypy) and the rest of the [Unofficial GuildedAPI Team](https://github.com/GuildedAPI). The third rewrite of these API typings were based entirely on https://guildedapi.com/, which they built. 31 | 32 | Thank you to [Vlad](https://github.com/vladfrangu) and the rest of the contributors at https://github.com/discordjs/discord-api-types for the structure in which I based my typings structure on. 33 | 34 | ## LICENSE 35 | 36 | Licensed under the [MIT License](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 37 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/Content.ts: -------------------------------------------------------------------------------- 1 | import { APIDocument } from './Document'; 2 | 3 | export interface APIContent { 4 | object: string; 5 | document: APIDocument; 6 | } 7 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/Document.ts: -------------------------------------------------------------------------------- 1 | import { APILeaf } from './Plant'; 2 | 3 | export interface APIDocument { 4 | data: unknown; 5 | nodes: APIDocumentNode[]; 6 | object: string; 7 | } 8 | 9 | export interface APIDocumentNode { 10 | data: unknown; 11 | type: string; 12 | nodes: APINestedNode[]; 13 | object: string; 14 | } 15 | 16 | export interface APINestedNode { 17 | leaves?: APILeaf[]; 18 | object: string; 19 | data?: unknown; 20 | type?: string; 21 | nodes?: APINestedNode[]; 22 | } 23 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/Plant.ts: -------------------------------------------------------------------------------- 1 | export interface APILeaf { 2 | text: string; 3 | marks: APIMark[]; 4 | object: 'leaf' | string; 5 | } 6 | 7 | export interface APIMark { 8 | data: unknown; 9 | type: string; 10 | object: string; 11 | } 12 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/index.ts: -------------------------------------------------------------------------------- 1 | // API Structures 2 | export * from './structures'; 3 | 4 | // Weird API Structures 5 | export * from './Content'; 6 | export * from './Document'; 7 | export * from './Plant'; 8 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/structures/Channel.ts: -------------------------------------------------------------------------------- 1 | import { APIContent } from '../Content'; 2 | import { APICustomReaction } from './Emoji'; 3 | import { RolePermissions } from './Team'; 4 | import { APIUser } from './User'; 5 | 6 | export interface APIDMChannel { 7 | id: string; 8 | type: CHANNEL_TYPES; 9 | name: string | null; 10 | description: string | null; 11 | users: APIUser[]; 12 | createdAt: string; 13 | createdBy: string; 14 | updatedAt: string | null; 15 | contentType: CHANNEL_CONTENT_TYPES; 16 | archivedAt: string | null; 17 | autoArchiveAt: string | null; 18 | archivedBy: string | null; 19 | parentChannelId: string | null; 20 | deletedAt: string | null; 21 | createdByWebhookId: string | null; 22 | archivedByWebhookId: string | null; 23 | dmType: 'Default' | string; 24 | ownerId: string; 25 | voiceParticipants: APIUser[]; 26 | } 27 | 28 | export interface APITeamChannel { 29 | id: string; 30 | type: CHANNEL_TYPES; 31 | createdAt: string; 32 | createdBy: string; 33 | updatedAt: string | null; 34 | name: string; 35 | contentType: CHANNEL_CONTENT_TYPES; 36 | archivedAt: string | null; 37 | parentChannelId: string | null; 38 | autoArchiveAt: string | null; 39 | deletedAt: string | null; 40 | archivedBy: string | null; 41 | description: string | null; 42 | createdByWebhookId: string | null; 43 | archivedByWebhookId: string | null; 44 | teamId: string; 45 | channelCategoryId: string | null; 46 | addedAt: string | null; 47 | channelId: string | null; 48 | isRoleSynced: boolean | null; 49 | roles: string[] | null; 50 | userPermissions: string[] | null; 51 | tournamentRoles: string[] | null; 52 | isPublic: boolean; 53 | priority: number; 54 | groupId: number; 55 | settings: unknown; 56 | groupType: string; 57 | rolesById: { 58 | [key: string]: APITeamChannelRolePermissionOverwrite; 59 | }; 60 | tournamentRolesById: { 61 | [key: string]: APITeamChannelRolePermissionOverwrite; 62 | }; 63 | createdByInfo: { 64 | id: string; 65 | name: string; 66 | profilePicture: string; 67 | profilePictureSm: string; 68 | }; 69 | } 70 | 71 | export type CHANNEL_TYPES = 'Team' | 'DM'; 72 | export type CHANNEL_CONTENT_TYPES = 'chat' | 'voice' | 'forum' | 'doc'; 73 | 74 | export interface APIMessageReaction { 75 | customReactionId: number; 76 | createdAt: string; 77 | users: { 78 | id: string; 79 | webhookId: string | null; 80 | botId: string | null; 81 | }[]; 82 | customReaction: APICustomReaction; 83 | } 84 | 85 | export interface APIReactionUsage { 86 | id: number; 87 | total: number; 88 | } 89 | 90 | export interface DenyPermissions { 91 | [key: string]: number; 92 | } 93 | 94 | export interface AllowPermissions { 95 | [key: string]: number; 96 | } 97 | 98 | export interface APIRoleOverwrite { 99 | teamId: string; 100 | createdAt: string; 101 | updatedAt: string | null; 102 | teamRoleId: number; 103 | denyPermissions: DenyPermissions; 104 | allowPermissions: AllowPermissions; 105 | channelId?: string; 106 | channelCategoryId?: number; 107 | } 108 | 109 | export type APIUserOverwrite = APIRoleOverwrite; 110 | 111 | export type APICategoryChannelRoleOverwrite = APIRoleOverwrite; 112 | 113 | export type APITeamChannelRoleOverwrite = APIRoleOverwrite; 114 | 115 | export interface APIMessage { 116 | id: string; 117 | content: APIContent; 118 | type: APIContentMessageType; 119 | reactions?: APIMessageReaction[]; 120 | createdBy: string; 121 | createdAt: string; 122 | editedAt?: string | null; 123 | deletedAt?: string | null; 124 | channelId: string; 125 | repliesToIds: string[]; 126 | repliesTo: string | null; 127 | webhookId?: string | null; 128 | botId?: string | null; 129 | isPinned?: boolean; 130 | pinnedBy?: string | null; 131 | } 132 | 133 | export interface APIMessageMention { 134 | id: string; 135 | name: string; 136 | type: string; 137 | color: string; 138 | avatar: string; 139 | matcher: string; 140 | nickname: boolean; 141 | description: string; 142 | } 143 | 144 | export type APIPartialMessage = Pick; 145 | 146 | export interface APIEmbed { 147 | title?: string; 148 | description?: string; 149 | url?: string; 150 | timestamp?: string; 151 | color?: number; 152 | footer?: APIEmbedFooter; 153 | image?: APIEmbedImage; 154 | thumbnail?: APIEmbedThumbnail; 155 | video?: APIEmbedVideo; 156 | provider?: APIEmbedProvider; 157 | author?: APIEmbedAuthor; 158 | fields?: APIEmbedField[]; 159 | } 160 | 161 | export interface APIEmbedFooter { 162 | text: string; 163 | icon_url?: string; 164 | proxy_icon_url?: string; 165 | } 166 | export interface APIEmbedImage { 167 | url: string; 168 | proxy_url?: string; 169 | height?: string; 170 | width?: string; 171 | } 172 | export type APIEmbedThumbnail = APIEmbedImage; 173 | 174 | export type APIEmbedVideo = APIEmbedImage; 175 | 176 | export interface APIEmbedProvider { 177 | name?: string; 178 | url?: string; 179 | } 180 | 181 | export interface APIEmbedAuthor { 182 | name: string; 183 | icon_url?: string; 184 | url?: string; 185 | proxy_icon_url?: string; 186 | } 187 | export interface APIEmbedField { 188 | inline?: boolean; 189 | name: string; 190 | value: string; 191 | } 192 | 193 | export type APIContentMessageType = 'block' | 'text' | string; 194 | export type DocumentNodeMessageType = 'code-container' | 'paragraph' | string; 195 | 196 | export interface APITeamChannelRolePermissionOverwrite { 197 | teamId: string; 198 | channelId: string; 199 | createdAt: string; 200 | updatedAt: string | null; 201 | teamRoleId: number; 202 | denyPermissions: RolePermissions; 203 | allowPermissions: RolePermissions; 204 | } 205 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/structures/Emoji.ts: -------------------------------------------------------------------------------- 1 | export interface APICustomReaction { 2 | id: number; 3 | name: string; 4 | png: string | null; 5 | webp: string | null; 6 | apng: string | null; 7 | } 8 | 9 | export interface APIEmoji { 10 | id: number; 11 | name: string; 12 | createdBy: string; 13 | createdAt: string; 14 | png: string; 15 | webp: string; 16 | apng: string; 17 | aliases: string[]; 18 | teamId: string; 19 | isDeleted: boolean; 20 | discordEmojiId: string | null; 21 | discordSyncedAt: string | null; 22 | } 23 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/structures/Team.ts: -------------------------------------------------------------------------------- 1 | import { APITeamChannelRoleOverwrite } from './Channel'; 2 | import { APIAboutInfo, APIAlias, APISocialLink, APIUserStatus } from './User'; 3 | import { APIWebhook } from './Webhook'; 4 | 5 | export interface APITeam { 6 | additionalGameInfo: unknown; 7 | additionalInfo: { 8 | platform: string; 9 | }; 10 | alphaInfo: unknown; 11 | alwaysShowTeamHome: boolean; 12 | autoSyncDiscordRoles: boolean; 13 | bannerImages: unknown; 14 | baseGroup: APIGroup; 15 | bio: string | null; 16 | bots: unknown[]; 17 | canInviteMembers?: boolean; 18 | canManageTournaments?: boolean; 19 | canUpdateTeam?: boolean; 20 | characteristics: string | null; 21 | createdAt: string; 22 | customizationInfo: unknown; 23 | deafenedMembers?: unknown[]; 24 | description: string; 25 | discordGuildId: string | null; 26 | discordServerName: string | null; 27 | flair: unknown[]; 28 | followerCount: number; 29 | followingGroups: string[] | null; 30 | games: unknown[]; 31 | homeBannerImageLg: string | null; 32 | homeBannerImageMd: string | null; 33 | homeBannerImageSm: string | null; 34 | id: string; 35 | insightsInfo: unknown; 36 | isAdmin?: boolean; 37 | isFavorite?: boolean; 38 | isPro: boolean; 39 | isPublic: boolean; 40 | isRecruiting: boolean; 41 | isUserApplicant: boolean; 42 | isUserBannedFromTeam: boolean; 43 | isUserInvited: boolean; 44 | isVerified: boolean; 45 | lfmStatusByGameId: unknown; 46 | measurements: APIMeasurements; 47 | members: APIMember[]; 48 | mutedMembers: string[]; 49 | memberCount?: string; 50 | membershipRole: string; 51 | name: string; 52 | notificationPreference: string | null; 53 | ownerId: string; 54 | profilePicture: string; 55 | rankNames: string | null; 56 | roleIds?: number[] | null; 57 | rolesById: { 58 | [key: string]: APITeamRole; 59 | }; 60 | rolesVersion: number; 61 | socialInfo: unknown; 62 | status: string | null; 63 | subdomain: string; 64 | subscriptionInfo: string | null; 65 | teamDashImage: string | null; 66 | teamPreferences: string | null; 67 | timezone: string | null; 68 | type: string | null; 69 | upsell: null; 70 | userFollowsTeam: boolean; 71 | webhooks: APIWebhook[]; 72 | } 73 | 74 | export interface APIPartialTeam { 75 | id: string; 76 | name: string; 77 | subdomain: string; 78 | activity: unknown[]; 79 | games: string[] | null[]; 80 | profilePicture: string; 81 | teamDashImage: string; 82 | homeBannerImageSm: string; 83 | homeBannerImageMd: string; 84 | homeBannerImageLg: string; 85 | gameIds: string[] | null; 86 | bannerImages: string[] | null[]; 87 | memberCount: number; 88 | } 89 | 90 | export interface APITeamBan { 91 | reason: string; 92 | userId: string; 93 | bannedBy: string; 94 | createdAt: string; 95 | } 96 | 97 | export interface APITeamRole { 98 | id: string; 99 | name: string; 100 | color: string; 101 | priority: number; 102 | permissions: RolePermissions; 103 | isBase: boolean; 104 | teamId: string; 105 | createdAt: string; 106 | updatedAt: string | null; 107 | isMentionable: boolean; 108 | discordRoleId: string | null; 109 | discordSyncedAt: string | null; 110 | isSelfAssignable: boolean; 111 | isDisplayedSeparately: boolean; 112 | } 113 | 114 | export interface APIGroup { 115 | id: string; 116 | name: string; 117 | description: string | null; 118 | priority: string | null; 119 | type: string; 120 | avatar: string | null; 121 | banner: string | null; 122 | teamId: string; 123 | gameId: string | null; 124 | visibilityTeamRoleId: number; 125 | membershipTeamRoleId: number; 126 | isBase: boolean; 127 | additionalGameInfo: unknown; 128 | createdBy: string | null; 129 | createdAt: string; 130 | updatedBy: string | null; 131 | updatedAt: string | null; 132 | deletedAt: string | null; 133 | customReactionId: string | null; 134 | isPublic: boolean; 135 | archivedAt: string | null; 136 | archivedBy: string | null; 137 | } 138 | 139 | export interface APIMeasurements { 140 | numMembers: number; 141 | numFollowers: number; 142 | numRecentMatches: number; 143 | numRecentMatchWins: number; 144 | matchmakingGameRanks: unknown[]; 145 | numFollowersAndMembers: number; 146 | numMembersAddedInLastDay: number; 147 | numMembersAddedInLastWeek: number; 148 | mostRecentMemberLastOnline: number; 149 | numMembersAddedInLastMonth: number; 150 | subscriptionMonthsRemaining: number | null; 151 | } 152 | 153 | export interface RoleOverwriteById { 154 | [key: string]: APITeamChannelRoleOverwrite; 155 | } 156 | 157 | /* 158 | Taken from: https://github.com/Skillz4Killz/gapi/blob/master/src/lib/Team.ts#L181 159 | GAPI created by https://github.com/Skillz4Killz, LICENSED under Apache License 2.0 160 | */ 161 | export interface RolePermissions extends Record { 162 | chat: 119; 163 | docs: 15; 164 | forms: 18; 165 | lists: 63; 166 | media: 15; 167 | voice: 8179; 168 | forums: 123; 169 | general: 15412; 170 | calendar: 31; 171 | scheduling: 11; 172 | matchmaking: 1; 173 | recruitment: 55; 174 | announcements: 7; 175 | customization: 49; 176 | } 177 | 178 | export interface APIMember { 179 | id: string; 180 | name: string; 181 | nickname: string | null; 182 | badges: string[] | null; 183 | joinDate: string; 184 | membershipRole: MembershipRole; 185 | lastOnline: string | null; 186 | profilePicture: null | string; 187 | profileBannerBlur: null | string; 188 | aboutInfo: APIAboutInfo | null; 189 | userStatus: APIUserStatus; 190 | socialLinks: APISocialLink[] | null; 191 | roleIds: number[] | null; 192 | subscriptionType: string | null; 193 | aliases: APIAlias[]; 194 | userPresenceStatus: number; 195 | teamXp: number; 196 | } 197 | 198 | export type MembershipRole = 'member' | 'admin' | 'formerMember'; 199 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/structures/User.ts: -------------------------------------------------------------------------------- 1 | import { APIContent } from '../Content'; 2 | import { APICustomReaction } from './Emoji'; 3 | 4 | export interface APIUserStatus { 5 | content: APIContent | null; 6 | customReactionId: number | null; 7 | customReaction?: APICustomReaction; 8 | } 9 | 10 | export interface APIAboutInfo { 11 | bio?: string; 12 | tagLine?: string; 13 | } 14 | 15 | export interface APISocialLink { 16 | type: SocialLinkSource; 17 | handle: null | string; 18 | additionalInfo: APISocialLinkAdditionalInfo; 19 | } 20 | 21 | export interface APISocialLinkAdditionalInfo { 22 | channelName?: string; 23 | } 24 | 25 | export enum USER_PRESENCE { 26 | ONLINE = 1, 27 | IDLE = 2, 28 | DND = 3, 29 | INVISIBLE = 4, 30 | } 31 | 32 | export interface APIAlias { 33 | alias?: string; 34 | discriminator: null | string; 35 | name: string; 36 | createdAt?: string; 37 | userId?: string; 38 | gameId: number; 39 | socialLinkSource: SocialLinkSource | null; 40 | additionalInfo: unknown; 41 | editedAt?: string; 42 | playerInfo: unknown; 43 | } 44 | 45 | export type SocialLinkSource = 46 | | 'bnet' 47 | | 'discord' 48 | | 'psn' 49 | | 'steam' 50 | | 'switch' 51 | | 'twitch' 52 | | 'twitter' 53 | | 'xbox' 54 | | 'youtube'; 55 | 56 | export interface APIDevice { 57 | type: string; 58 | id: string; 59 | lastOnline: string; 60 | isActive: boolean; 61 | } 62 | 63 | export interface APIUser { 64 | aboutInfo: APIAboutInfo | null; 65 | aliases: APIAlias[]; 66 | email: string | null; 67 | id: string; 68 | joinDate: string; 69 | lastOnline: string; 70 | moderationStatus: string | null; 71 | name: string; 72 | profileBannerBlur: string | null; 73 | profileBannerLg: string | null; 74 | profileBannerSm: string | null; 75 | profilePicture: string | null; 76 | profilePictureBlur: string | null; 77 | profilePictureLg: string | null; 78 | profilePictureSm: string | null; 79 | serviceEmail: string | null; 80 | steamId: string | null; 81 | subdomain: string; 82 | userStatus: APIUserStatus; 83 | } 84 | 85 | export interface APIClientUser extends APIUser { 86 | useMinimalNav: boolean; 87 | blockedUsers: unknown[]; 88 | socialLinks: APIUserSocialLinks[]; 89 | userPresenceStatus: number; 90 | badges: string[]; 91 | canRedeemGold: boolean; 92 | isUnrecoverable: boolean; 93 | devices: APIDevice[]; 94 | userChannelNotificationSettings: unknown[]; 95 | upsell: null; 96 | } 97 | 98 | export interface APIUserSocialLinks { 99 | type: string; 100 | handle: string; 101 | additionalInfo: unknown; 102 | } 103 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/structures/Webhook.ts: -------------------------------------------------------------------------------- 1 | export interface APIWebhook { 2 | id: string; 3 | name: string; 4 | channelId: string; 5 | teamId: string; 6 | iconUrl: string | null; 7 | createdBy: string; 8 | createdAt: string; 9 | deletedAt: string | null; 10 | token?: string; 11 | } 12 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/common/structures/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Channel'; 2 | export * from './Emoji'; 3 | export * from './Team'; 4 | export * from './User'; 5 | export * from './Webhook'; 6 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './rest'; 2 | export * from './common'; 3 | export * from './ws'; 4 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/rest/Channel.ts: -------------------------------------------------------------------------------- 1 | import { APIContent, APIEmbed, APIMessage, APITeamChannel, CHANNEL_TYPES } from '../common'; 2 | 3 | /** 4 | * Get Channel Result 5 | * @destination /channels/:channelID 6 | */ 7 | export type APIGetChannel = APITeamChannel; 8 | 9 | /** 10 | * Modify Channel 11 | * @destination /channels/:id 12 | */ 13 | export interface APIPatchChannelBody { 14 | name?: string; 15 | type?: CHANNEL_TYPES; 16 | position?: number | null; 17 | topic?: string | null; 18 | nsfw?: boolean | null; 19 | rate_limit_per_user?: number | null; 20 | bitrate?: number | null; 21 | user_limit?: number | null; 22 | parent_id?: string | null; 23 | } 24 | 25 | /** 26 | * Modify Channel Result 27 | * @destination /channels/:id 28 | */ 29 | export type APIPatchChannelResult = APITeamChannel; 30 | 31 | /** 32 | * Delete/Close Channel 33 | * @destination /channels/:id 34 | */ 35 | export type APIDeleteChannel = never; 36 | 37 | /** 38 | * Get Channel Messages 39 | * @destination /channels/:id/messages?limit=:amt 40 | */ 41 | export interface APIGetChannelMessages { 42 | messages: APIMessage[]; 43 | hasPastMessages: boolean; 44 | } 45 | 46 | /** 47 | * Get Channel Message 48 | * @destination /content/route/metadata?route=//channels/:channelID/chat&messageId=:messageID 49 | */ 50 | export interface APIGetChannelMessageQuery { 51 | route: string; 52 | messageId: string; 53 | } 54 | 55 | /** 56 | * Get Channel Message Result 57 | * @destination /content/route/metadata?route=//channels/:channelID/chat&messageId=:messageID 58 | */ 59 | export type APIGetChannelMessageResult = APIMessage; 60 | 61 | /** 62 | * Get Channel Messages 63 | * @destination /channels/:id/messages?limit=:amt 64 | * Tested upto 50k messages 65 | */ 66 | export interface APIGetChannelMessagesQuery { 67 | limit?: number; 68 | } 69 | 70 | /** 71 | * Send Message 72 | * @destination /channels/:id/messages 73 | */ 74 | export interface APIPostChannelMessagesBody { 75 | messageId: string; 76 | content: APIContent; 77 | embed: APIEmbed; 78 | } 79 | 80 | /** 81 | * Send Message 82 | * @destination /channels/:id/messages 83 | */ 84 | export type APIPostChannelMessagesResult = APIMessage; 85 | 86 | /** 87 | * Edit Message 88 | * @destination /channels/:id/messages/:messageID 89 | */ 90 | export interface APIPatchChannelMessageBody { 91 | content: string; 92 | embed: APIEmbed; 93 | } 94 | 95 | /** 96 | * Edit Message Result 97 | * @destination /channels/:id/messages/:messageID 98 | */ 99 | export type APIPatchChannelMessageResult = APIMessage; 100 | 101 | /** 102 | * Delete Message 103 | * @destination /channels/:channelID/messages/:messageID 104 | */ 105 | export type APIDeleteChannelMessage = never; 106 | 107 | /** 108 | * Add Reaction 109 | * @destination /channels/:channelID/messages/:messageID/reactions/:reactionID 110 | */ 111 | export type APIPostMessageReactions = never; 112 | 113 | /** 114 | * Delete Own Reactioon 115 | * @destination /channels/:channelID/messages/:messageID/reactions/:reactionID 116 | */ 117 | export type APIDeleteMessageReactionsOwn = never; 118 | 119 | /** 120 | * Get Pinned Messages 121 | * @destination /channels/:id/pins 122 | */ 123 | export interface APIGetChannelPinnedMessages { 124 | message: APIMessage[]; 125 | } 126 | 127 | /** 128 | * Pin Message 129 | * @destination /channels/:id/pins 130 | */ 131 | export interface APIPostChannelPinnedMessagesBody { 132 | messageId: string; 133 | } 134 | 135 | /** 136 | * Unpin Message 137 | * @destination /channels/:id/pins/messageID 138 | */ 139 | export type APIDeleteChannelPinnedMessage = never; 140 | 141 | /** 142 | * Create Thread 143 | * @destination /channels/:id/threads 144 | */ 145 | export interface APIPostChannelCreateThread { 146 | name: string; 147 | message: APIMessage; 148 | channelId: string; 149 | threadMessageId: string; 150 | initialThreadMessage: APIMessage; 151 | contentType: string; 152 | confirmed: boolean; 153 | } 154 | 155 | /** 156 | * Delete Thread 157 | * @destination /teams/:teamID/groups/:groupID/channels/threadID 158 | */ 159 | export type APIDeleteChannelThread = never; 160 | 161 | /** 162 | * Post Team Announcements 163 | * @destination /teams/:teamID/announcements 164 | */ 165 | export interface APIPostTeamAnnouncement { 166 | title: string; 167 | content: APIMessage; 168 | } 169 | 170 | /** 171 | * Post Announcement 172 | * @destination /channels/:id/announcements 173 | */ 174 | export interface APIPostChannelAnnouncementsBody { 175 | title: string; 176 | content: APIMessage; 177 | dontSendNotifications: boolean; 178 | } 179 | 180 | /** 181 | * @destination /teams/:id/channels 182 | */ 183 | export interface APIGetTeamChannels { 184 | channels: APITeamChannel[]; 185 | badgedChannelContentByChannelId: unknown; 186 | temporalChannels: unknown[]; 187 | categories: APITeamChannel[]; 188 | } 189 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/rest/Emoji.ts: -------------------------------------------------------------------------------- 1 | import { APIEmoji } from '../common/structures/Emoji'; 2 | 3 | /** 4 | * Get Team Emojis 5 | * @destination 6 | */ 7 | export interface APIGetTeamEmojisResult { 8 | emojis: APIEmoji[]; 9 | } 10 | 11 | /** 12 | * Get Team Emojis 13 | * @destination 14 | */ 15 | export interface APIGetTeamEmojisQuery { 16 | maxItems: number; 17 | when: { 18 | upperValue: string; 19 | lowerValue: string; 20 | }; 21 | createdBy: string; 22 | searchTerm: string; 23 | beforeId: string; 24 | } 25 | 26 | /** 27 | * Create Team Emoji 28 | * @destination 29 | */ 30 | export interface APIPostTeamEmojisBody { 31 | name: string; 32 | png?: string; 33 | webp?: string; 34 | apng?: string; 35 | } 36 | 37 | /** 38 | * Create Team Emoji 39 | * @destination 40 | */ 41 | export type APIPostTeamEmojisResult = APIEmoji; 42 | 43 | /** 44 | * Modify Team Emoji 45 | * @destination 46 | */ 47 | export interface APIPatchTeamEmojiBody { 48 | name: string; 49 | } 50 | 51 | /** 52 | * Modify Team Emoji 53 | * @destination 54 | */ 55 | export type APIPatchTeamEmojisResult = never; 56 | 57 | /** 58 | * Delete Team Emoji 59 | * @destination 60 | */ 61 | export type APIDeleteTeamEmojiResult = never; 62 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/rest/Team.ts: -------------------------------------------------------------------------------- 1 | import { APITeam } from '../common'; 2 | 3 | /** 4 | * @destination /teams/:id 5 | */ 6 | export interface APIGetTeam { 7 | team: APITeam; 8 | } 9 | /** 10 | * @destination /teams/:id/invites 11 | */ 12 | export interface APIPostCreateInviteResult { 13 | id: string; 14 | } 15 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/rest/User.ts: -------------------------------------------------------------------------------- 1 | import { 2 | APIAboutInfo, 3 | APIClientUser, 4 | APICustomReaction, 5 | APIDMChannel, 6 | APIReactionUsage, 7 | APITeam, 8 | APIUser, 9 | } from '../common'; 10 | 11 | /** 12 | * Get User 13 | * @destination /users/:id 14 | */ 15 | export interface APIGetUser { 16 | user: APIUser; 17 | } 18 | 19 | /** 20 | * Get Current User 21 | * @destination /me 22 | */ 23 | export interface APIGetCurrentUser { 24 | updateMessage: string | null; 25 | user: APIClientUser; 26 | teams: APITeam[]; 27 | customReactions: APICustomReaction[]; 28 | reactionUsages: APIReactionUsage[]; 29 | landingUrl: boolean; 30 | } 31 | 32 | /** 33 | * Modify Current User 34 | * @destination /users/:userID/profilev2 35 | */ 36 | export interface APIPutCurrentUserBody { 37 | name: string; 38 | avatar: string; 39 | subdomain: string; 40 | aboutInfo: APIAboutInfo; 41 | } 42 | 43 | /** 44 | * Modify Current User 45 | * @destination /users/:userID/profilev2 46 | */ 47 | export type APIPutCurrentUserResult = APIUser; 48 | 49 | /** 50 | * Leave Team 51 | * @destination /teams/:teamID/members/:userID 52 | */ 53 | export type APIDeleteUserTeam = never; 54 | 55 | /** 56 | * Login the Client 57 | * @destination /login 58 | */ 59 | export interface APIPostLoginResponse { 60 | user: Omit; 61 | } 62 | 63 | /** 64 | * Get all of a user's DM Channel 65 | * @destination /users/:id/channels 66 | */ 67 | export interface APIGetUserDMChannels { 68 | channels: APIDMChannel[]; 69 | unreadInfoByChannelId: unknown; 70 | users: APIUser[]; 71 | } 72 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/rest/Webhook.ts: -------------------------------------------------------------------------------- 1 | import { APIContent, APIEmbed, APIWebhook } from '../common'; 2 | 3 | /** 4 | * Create Webhook 5 | * @destination /webhooks 6 | */ 7 | export interface APIPostCreateWebhookBody { 8 | name: string; 9 | channelId: string; 10 | } 11 | 12 | /** 13 | * Create Webhook Result 14 | * @destination /webhooks 15 | */ 16 | export type APIPostCreateWebhookResult = APIWebhook; 17 | 18 | /** 19 | * Get Channel Webhooks 20 | * @destination /teams/:teamID/channels/:channelID/webhooks 21 | */ 22 | export interface APIGetTeamChannelWebhooks { 23 | webhooks: APIWebhook[]; 24 | } 25 | 26 | /** 27 | * Modify Webhook 28 | * @destination /webhooks/:webhookID 29 | */ 30 | export interface APIPutWebhookBody { 31 | name: string; 32 | iconUrl: string; 33 | channelId: string; 34 | } 35 | 36 | /** 37 | * Modify Webhook Result 38 | * @destination /webhooks/:webhookID 39 | */ 40 | export type APIPutWebhookResult = APIWebhook; 41 | 42 | /** 43 | * Delete Webhook Result 44 | * @destination /webhooks/:webhookID 45 | */ 46 | export type APIDeleteWebhookResult = Pick; 47 | 48 | /** 49 | * Execute Webhook 50 | * @destination /webhooks/:webhookID/:webhookToken 51 | */ 52 | export interface APIPostWebhookBody { 53 | content: string; 54 | embeds: APIEmbed[]; 55 | } 56 | 57 | export interface APIPostWebhookResult { 58 | id: string; 59 | channelId: string; 60 | content: APIContent; 61 | type: string; 62 | createdBy: string; 63 | createdAt: string; 64 | webhookId: string; 65 | botId: string | null; 66 | } 67 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/rest/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Channel'; 2 | export * from './Emoji'; 3 | export * from './Team'; 4 | export * from './User'; 5 | export * from './Webhook'; 6 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/ws/ChatMessageCreated.ts: -------------------------------------------------------------------------------- 1 | import { APIMessage, CHANNEL_CONTENT_TYPES, CHANNEL_TYPES } from '../common'; 2 | export interface WSChatMessageCreated { 3 | channelCategoryId?: string | null; 4 | channelId: string; 5 | channelType: CHANNEL_TYPES; 6 | contentId: string; 7 | contentType: CHANNEL_CONTENT_TYPES; 8 | createdAt: string; 9 | createdBy: string; 10 | guildedClientId: string; 11 | id: string; 12 | message: Pick< 13 | APIMessage, 14 | 'id' | 'createdBy' | 'content' | 'type' | 'createdAt' | 'webhookId' | 'botId' | 'repliesTo' | 'repliesToIds' 15 | >; 16 | repliedToMessage?: APIMessage[]; 17 | silenceNotification: boolean; 18 | teamId?: string; 19 | type: 'ChatMessageCreated'; 20 | } 21 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/ws/ChatMessageReactionAdded.ts: -------------------------------------------------------------------------------- 1 | import { APICustomReaction, CHANNEL_CONTENT_TYPES, CHANNEL_TYPES } from '../common'; 2 | 3 | export interface WSChatMessageReactionAdded { 4 | type: 'ChatMessageReactionAdded'; 5 | guildedClientId: string; 6 | channelId: string; 7 | channelCategoryId: string | null; 8 | channelType: CHANNEL_TYPES; 9 | teamId: string | null; 10 | contentType: CHANNEL_CONTENT_TYPES; 11 | reaction: { 12 | customReactionId: number; 13 | customReaction: APICustomReaction; 14 | createdBy: string; 15 | }; 16 | message: { 17 | id: string; 18 | }; 19 | silenceNotification: boolean; 20 | } 21 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/ws/ChatMessageReactionDeleted.ts: -------------------------------------------------------------------------------- 1 | import { CHANNEL_CONTENT_TYPES, CHANNEL_TYPES } from '../common'; 2 | 3 | export interface WSChatMessageReactionDeleted { 4 | type: 'ChatMessageReactionDeleted'; 5 | guildedClientId: string; 6 | channelId: string; 7 | channelCategoryId: string | null; 8 | channelType: CHANNEL_TYPES; 9 | teamId: string | null; 10 | contentType: CHANNEL_CONTENT_TYPES; 11 | reaction: { 12 | customReactionId: number; 13 | createdBy: string; 14 | }; 15 | message: { 16 | id: string; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/ws/ChatMessageUpdated.ts: -------------------------------------------------------------------------------- 1 | import { APIPartialMessage } from '../common'; 2 | 3 | export interface WSChatMessageUpdated { 4 | channelCategoryId: string | null; 5 | channelId: string; 6 | channelType: string; 7 | contentId: string; 8 | contentType: string; 9 | guildedClientId: string; 10 | message: APIPartialMessage; 11 | silenceNotification: boolean; 12 | teamId: string; 13 | type: string; 14 | updatedBy: string; 15 | } 16 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/ws/Ready.ts: -------------------------------------------------------------------------------- 1 | export interface WSGatewayReady { 2 | sid: string; 3 | upgrades: unknown[]; 4 | pingInterval: number; 5 | pingTimeout: number; 6 | } 7 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/lib/ws/index.ts: -------------------------------------------------------------------------------- 1 | export * from './ChatMessageCreated'; 2 | export * from './ChatMessageReactionAdded'; 3 | export * from './ChatMessageReactionDeleted'; 4 | export * from './ChatMessageUpdated'; 5 | export * from './Ready'; 6 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/guilded-api-typings", 3 | "version": "1.4.1-selfbot", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@guildedjs/guilded-api-typings", 9 | "version": "1.3.1-selfbot", 10 | "license": "MIT", 11 | "devDependencies": { 12 | "@types/node": "^14.14.9", 13 | "typescript": "^4.4.2" 14 | } 15 | }, 16 | "node_modules/@types/node": { 17 | "version": "14.14.16", 18 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.16.tgz", 19 | "integrity": "sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw==", 20 | "dev": true 21 | }, 22 | "node_modules/typescript": { 23 | "version": "4.4.2", 24 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 25 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 26 | "dev": true, 27 | "bin": { 28 | "tsc": "bin/tsc", 29 | "tsserver": "bin/tsserver" 30 | }, 31 | "engines": { 32 | "node": ">=4.2.0" 33 | } 34 | } 35 | }, 36 | "dependencies": { 37 | "@types/node": { 38 | "version": "14.14.16", 39 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.16.tgz", 40 | "integrity": "sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw==", 41 | "dev": true 42 | }, 43 | "typescript": { 44 | "version": "4.4.2", 45 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 46 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 47 | "dev": true 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/guilded-api-typings", 3 | "version": "1.4.1-selfbot", 4 | "description": "Typings for the guilded API", 5 | "author": "zaid450 ", 6 | "homepage": "https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/guilded-api-typings#readme", 7 | "license": "MIT", 8 | "types": "dist/index.d.ts", 9 | "main": "dist/index.js", 10 | "scripts": { 11 | "build": "tsc", 12 | "prepublishOnly": "npx rimraf dist/ && npm run build" 13 | }, 14 | "devDependencies": { 15 | "@types/node": "^14.14.9", 16 | "typescript": "^4.4.2" 17 | }, 18 | "directories": { 19 | "lib": "lib", 20 | "test": "__tests__" 21 | }, 22 | "keywords": [ 23 | "guilded", 24 | "guildedjs", 25 | "guilded.js", 26 | "guilded-api", 27 | "guilded-api-wrapper", 28 | "guilded-wrapper", 29 | "guilded-api-typings" 30 | ], 31 | "files": [ 32 | "dist" 33 | ], 34 | "repository": { 35 | "type": "git", 36 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 37 | }, 38 | "bugs": { 39 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 40 | }, 41 | "gitHead": "0719b880becce0aa4bccaf5eb5b210ecb08b0547" 42 | } 43 | -------------------------------------------------------------------------------- /packages/guilded-api-typings/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "target": "ES2020", 6 | "removeComments": false 7 | }, 8 | "include": [ 9 | "./lib/**/*.ts" 10 | ] 11 | } -------------------------------------------------------------------------------- /packages/guilded.js/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Zaid - Nico 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | Includes other software related under the Apache License 2.0: 24 | - discord.js, Copyright 2015-2020, For licensing see https://github.com/discordjs/discord.js/blob/stable/LICENSE -------------------------------------------------------------------------------- /packages/guilded.js/README.md: -------------------------------------------------------------------------------- 1 |
2 |

Guilded.js

3 |

A Node.js library for the Guilded.gg API.

4 |

5 | 6 | CI 7 | License: MIT
8 |

9 |
10 | 11 | ```ts 12 | const { Client } = require("@guildedjs/guilded.js"); 13 | // import { Client } from "@guildedjs/guilded.js"; 14 | 15 | const client = new Client(); 16 | 17 | client.on("ready", () => console.log(`Bot is successfully logged in`)); 18 | 19 | client.on("messageCreate", (message) => { 20 | if (message.content === "poggers") { 21 | return message.channel.send("poggers indeed"); 22 | } 23 | }); 24 | 25 | client.login({ 26 | email: "email", 27 | password: "password", 28 | }); 29 | ``` 30 | 31 | ## 📝 About 32 | 33 | `@guildedjs/guilded.js` is a library written in TypeScript usable in either TypeScript or JavaScript projects. It provides structures, abstraction, and utilities for interaction between the guilded API and your userbot. 34 | 35 | Off the bat there are very noticable similarities between this package and [`discord.js`](https://discord.js.org) structure-wise. This is intentional in order to make the migration or copying of your codebase to a Guilded bot smooth and predictable. We've adopted the same managers/cache structure that they've implemented because we find that it's what works well without complications. While our structure is **influenced** by them, there are underlying differences with how we handle things like websockets, events, and utilities. In addition to that, the library is split up into multiple packages (this being the main one) and written in TypeScript over JavaScript. 36 | 37 | ## 📥 Installation 38 | 39 | NPM 40 | 41 | **Recommended that you use node v12+** 42 | 43 | - `npm install @guildedjs/guilded.js` 44 | - `yarn add @guildedjs/guilded.js` 45 | 46 | ## 📃 Documentation 47 | 48 | Documentation is located [here](https://zaida04.github.io/guildedjs-selfbot-docs) 49 | 50 | ## 📦 Dependencies 51 | 52 | - [`@guildedjs/guilded-api-typings`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/guilded-api-typings) (dev dep): used for typing the REST and WS payloads 53 | - [`@guildedjs/common`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/common): Utilities between `@guildedjs` packages 54 | - [`@guildedjs/rest`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/rest): Rest structure for `@guildedjs` packages 55 | - [`@guildedjs/embeds`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/embeds): Embed builder/utility 56 | - [`@guildedjs/webhook-client`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/webhook-client): Webhook Client 57 | - `@discordjs/collection`: Map utility 58 | - `ws`: WebSocket interaction 59 | 60 | ## ✋ Contributing 61 | 62 | Please see the main [README.md](https://github.com/zaida04/guilded.js-selfbot) for info on how to contribute to this package or the other `@guildedjs` packages. 63 | 64 | ## 🤝 Acknowledgements 65 | 66 | - [`Discord.js`](https://discord.js.org/#/) - Inspiration and caching strategy 67 | 68 | ## ⚖️ LICENSING 69 | 70 | Licensed under the [MIT License](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 71 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/colors.js: -------------------------------------------------------------------------------- 1 | exports.COLORS = { 2 | CYAN: '\u001B[36m', 3 | GREEN: '\u001B[32m', 4 | RED: '\u001B[31m', 5 | RESET: '\u001B[0m', 6 | UNDERSCORE: '\u001B[4m', 7 | WHITE: '\u001B[37m', 8 | YELLOW: '\u001B[33m', 9 | }; 10 | 11 | exports.testText = str => console.log(`\n${exports.COLORS.YELLOW} ---${str}--- ${exports.COLORS.RESET}`); 12 | exports.successText = str => console.log(`${exports.COLORS.GREEN} ${str} ${exports.COLORS.RESET}`); 13 | exports.errorText = str => console.log(`\n${exports.COLORS.RED} ${str} ${exports.COLORS.RESET}\n`); 14 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | const { config } = require('dotenv'); 3 | const { join } = require('path'); 4 | const { COLORS, testText, errorText, successText } = require('./colors.js'); 5 | const Guilded = require('..'); 6 | 7 | config({ 8 | path: join(__dirname, '..', '..', '..', '.env'), 9 | }); 10 | 11 | if (!process.env.EMAIL) throw new Error('Must supply email for testing'); 12 | if (!process.env.PASSWORD) throw new Error('Must supply password for testing'); 13 | if (!process.env.TEAM_ID) throw new Error('Must provide a testing team ID'); 14 | if (!process.env.ROLE_ID) throw new Error('Must provide a testing role ID'); 15 | if (!process.env.GUINEAPIG_ID) throw new Error('Must provide a testing user ID'); 16 | if (!process.env.GROUP_ID) throw new Error('Must provide a testing group ID'); 17 | if (!process.env.CHANNEL_ID) throw new Error('Must provide a testing channel ID'); 18 | 19 | const client = new Guilded.Client({ 20 | ws: { 21 | heartbeatInterval: 15000, 22 | }, 23 | }); 24 | const prefix = 'gg!'; 25 | 26 | // client.on('raw', console.log); 27 | // client.on('debug', console.log); 28 | 29 | client.on(Guilded.events.MESSAGE_REACTION_ADD, a => console.log(`REACTION ADDED: ${a.id}`)); 30 | client.on(Guilded.events.MESSAGE_REACTION_DELETE, a => console.log(`REACTION REMOVED: ${a.id}`)); 31 | 32 | /** 33 | * Testing login 34 | */ 35 | client.once(Guilded.events.READY, async () => { 36 | let passed = 0; 37 | let failed = 0; 38 | 39 | console.log( 40 | `Successfully logged in as ${client.user.id}. Currently in ${client.teams.cache.size} Teams and serving ${client.users.cache.size} users with ${client.channels.cache.size} channels.`, 41 | ); 42 | 43 | testText('Role adding/Removal'); 44 | await require('./modules/role')(client, passed, failed, successText, errorText) 45 | .then(() => passed++) 46 | .catch(() => failed++); 47 | 48 | testText('Client Disconnection/Reconnection'); 49 | try { 50 | require('./modules/connection')(client, passed, failed, successText, errorText); 51 | passed++; 52 | } catch { 53 | failed++; 54 | } 55 | 56 | testText('Message Sending/Editing/Deletion/Fetching'); 57 | await require('./modules/message')(client, passed, failed, successText, errorText) 58 | .then(() => passed++) 59 | .catch(() => failed++); 60 | 61 | testText('Active WS connection'); 62 | try { 63 | require('./modules/ws')(client, passed, failed, successText, errorText); 64 | passed++; 65 | } catch { 66 | failed++; 67 | } 68 | 69 | testText('Invite Creation/Deletion'); 70 | await require('./modules/invite')(client, passed, failed, successText, errorText) 71 | .then(() => passed++) 72 | .catch(() => failed++); 73 | 74 | testText('Embed sending'); 75 | await require('./modules/embed')(client, passed, failed, successText, errorText) 76 | .then(() => passed++) 77 | .catch(() => failed++); 78 | 79 | console.log(`\n\n${COLORS.GREEN} ${passed} tests passed.${COLORS.RED} ${failed} tests failed. ${COLORS.RESET}`); 80 | }); 81 | 82 | client.on(Guilded.events.MESSAGE_CREATE, message => { 83 | if (message.teamID !== process.env.TEAM_ID) return; 84 | if (!message.content.startsWith(prefix)) return; 85 | const args = message.content.split(/ /g); 86 | const command = args.shift().slice(prefix.length); 87 | 88 | switch (command) { 89 | case 'eval': { 90 | if (message.authorID !== client.user.id) return message.channel.send('**NICE TRY**'); 91 | const code = args.join(' '); 92 | const evaled = eval(`(async () => {${code}})()`); 93 | message.channel.send(` 94 | 📥 **Input** 95 | \`\`\`${code}\`\`\` 96 | 📤 **Output** 97 | \`\`\`${evaled}\`\`\` 98 | `); 99 | break; 100 | } 101 | case 'ping': { 102 | return message.channel.send('HI!'); 103 | } 104 | } 105 | }); 106 | 107 | client.login({ 108 | email: process.env.EMAIL, 109 | password: process.env.PASSWORD, 110 | }); 111 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/modules/connection.js: -------------------------------------------------------------------------------- 1 | module.exports = (client, passed, failed, testText, errorText) => { 2 | try { 3 | client.destroy(true); 4 | testText('Successfully disconnected!'); 5 | } catch (e) { 6 | errorText(`Client disconnected failed! ${e}`); 7 | throw e; 8 | } 9 | }; 10 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/modules/embed.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const { Embed } = require('@guildedjs/embeds'); 3 | const iconURL = 'https://cdn.discordapp.com/avatars/500765481788112916/0c12c135aeeae527f46e9f737e6ca937.png'; 4 | 5 | module.exports = async (client, passed, failed, testText, errorText) => { 6 | try { 7 | console.log('...sending embed'); 8 | message = await client.channels.sendMessage( 9 | process.env.CHANNEL_ID, 10 | new Embed() 11 | .setTitle('TESTING EMBED!') 12 | .setAuthor('Joe Mama', iconURL, 'https://google.com') 13 | .setDescription('This is a test description') 14 | .setFooter('This is a footer', iconURL) 15 | .setTimestamp(new Date().getTime()) 16 | .setURL('https://google.com') 17 | .setImage(iconURL), 18 | ); 19 | testText(`Successfully sent embed message with ID: ${message}!`); 20 | } catch (e) { 21 | errorText(`Message sending failed! ${e}`); 22 | throw e; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/modules/invite.js: -------------------------------------------------------------------------------- 1 | module.exports = async (client, passed, failed, testText, errorText) => { 2 | let invite; 3 | try { 4 | console.log('...creating Invite'); 5 | invite = await client.teams.createInvite(process.env.TEAM_ID); 6 | testText(`Successfully created invite! id: ${invite.id}`); 7 | } catch (e) { 8 | errorText(`Creating invite failed! ${e}`); 9 | console.log(e); 10 | throw e; 11 | } 12 | 13 | try { 14 | console.log('...deleting Invite'); 15 | const responseID = await client.teams.deleteInvite(process.env.TEAM_ID, invite.id); 16 | testText(`Successfully deleted invite! response-id ${responseID}`); 17 | } catch (e) { 18 | errorText(`Deleting invite failed! ${e}`); 19 | console.log(e); 20 | throw e; 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/modules/message.js: -------------------------------------------------------------------------------- 1 | module.exports = async (client, passed, failed, testText, errorText) => { 2 | let message; 3 | const content = 'TESTING MESSAGE'; 4 | 5 | try { 6 | console.log('...sending message'); 7 | message = await client.channels.sendMessage(process.env.CHANNEL_ID, content); 8 | testText(`Successfully sent message with ID: ${message}!`); 9 | } catch (e) { 10 | errorText(`Message sending failed! ${e}`); 11 | throw e; 12 | } 13 | 14 | try { 15 | console.log('...editing message'); 16 | const newMessage = await client.channels.editMessage( 17 | process.env.CHANNEL_ID, 18 | message, 19 | 'THIS IS AN EDITED TEST MESSAGE', 20 | ); 21 | if (content === newMessage.content) throw new Error('Content is unchanged!'); 22 | testText(`Successfully edited message ${message} with new content ${newMessage.content}`); 23 | } catch (e) { 24 | errorText(`Message editing failed! ${e}`); 25 | throw e; 26 | } 27 | 28 | try { 29 | console.log('...deleting message'); 30 | await client.channels.deleteMessage(process.env.CHANNEL_ID, message); 31 | testText('Successfully deleted message!'); 32 | } catch (e) { 33 | errorText(`Message deletion failed! ${e}`); 34 | throw e; 35 | } 36 | 37 | try { 38 | console.log('...fetching 5 messages'); 39 | const messages = await client.channels.cache.random().messages.fetch(5); 40 | testText(`Successfully fetched messages!`); 41 | } catch (e) { 42 | errorText(`Message fetching failed! ${e}`); 43 | throw e; 44 | } 45 | }; 46 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/modules/role.js: -------------------------------------------------------------------------------- 1 | module.exports = async (client, passed, failed, testText, errorText) => { 2 | try { 3 | console.log('...adding role'); 4 | await client.teams.addRoleToMember(process.env.TEAM_ID, process.env.GUINEAPIG_ID, process.env.ROLE_ID); 5 | testText('Role successfully added.'); 6 | } catch (e) { 7 | errorText(`Role adding failed! ${e}`); 8 | throw e; 9 | } 10 | 11 | try { 12 | console.log('...removing role'); 13 | await client.teams.removeRoleFromMember(process.env.TEAM_ID, process.env.GUINEAPIG_ID, process.env.ROLE_ID); 14 | testText('Role successfully removed.'); 15 | } catch (e) { 16 | errorText(`Role removal failed! ${e}`); 17 | throw e; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /packages/guilded.js/__tests__/modules/ws.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-var-requires 2 | const webSocket = require('ws'); 3 | 4 | module.exports = (client, passed, failed, testText, errorText) => { 5 | try { 6 | console.log('...testing connection'); 7 | if (client.gateway.ws.readyState !== webSocket.OPEN) throw new Error('WS NOT OPEN!'); 8 | client.gateway.ws.send('2'); 9 | testText('WS message sent!'); 10 | } catch (e) { 11 | errorText(`WS connection failed! ${e}`); 12 | throw e; 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/index.ts: -------------------------------------------------------------------------------- 1 | export { Client } from './structures/Client'; 2 | export * from './structures'; 3 | export * from './typings'; 4 | export * from '@guildedjs/common'; 5 | export * from '@guildedjs/rest'; 6 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/Base.ts: -------------------------------------------------------------------------------- 1 | import type { BaseData } from '../typings'; 2 | import type { Client } from './Client'; 3 | 4 | /** 5 | * The base of all structures 6 | * 7 | * @param T The minimum amount of data required to construct this structure 8 | */ 9 | export abstract class Base { 10 | /** 11 | * The ID of this structure 12 | */ 13 | public readonly id: string; 14 | 15 | /** 16 | * The raw API data of this structure 17 | */ 18 | public readonly raw: Partial; 19 | 20 | public constructor(public readonly client: Client, data: T) { 21 | this.id = data.id.toString(); 22 | this.raw = data; 23 | } 24 | 25 | /** 26 | * Update the data in this structure 27 | * @internal 28 | */ 29 | public abstract patch(data: T | Partial): this; 30 | 31 | /** 32 | * Taken from https://github.com/discordjs/discord.js/blob/8e8d9b490a71de6cabe6f16375d7549a7c5c3737/src/structures/Base.js#L20 33 | * Licensed under the Apache License 2.0 34 | */ 35 | public _clone(): this { 36 | return Object.assign(Object.create(this), this); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/Group.ts: -------------------------------------------------------------------------------- 1 | import type { APIGroup } from '@guildedjs/guilded-api-typings'; 2 | 3 | import { Base } from './Base'; 4 | import type { Client } from './Client'; 5 | import { TeamGroupChannelManager } from './managers/TeamGroupChannelManager'; 6 | import type { Team } from './Team'; 7 | 8 | /** 9 | * A group residing within a Team that contains channels. 10 | */ 11 | export class Group extends Base { 12 | /** 13 | * The channels that belong to this group. 14 | */ 15 | public readonly channels: TeamGroupChannelManager; 16 | 17 | /** 18 | * The name of this group. 19 | */ 20 | public name!: string; 21 | 22 | /** 23 | * The description of this group. 24 | */ 25 | public description: string | null; 26 | 27 | /** 28 | * The position of this group. 29 | */ 30 | public priority: string | null; 31 | 32 | /** 33 | * The type of this group. 34 | */ 35 | public type: string; 36 | 37 | /** 38 | * The avatar hash of this group. 39 | */ 40 | public avatar: string | null; 41 | 42 | /** 43 | * The banner hash of this group. 44 | */ 45 | public banner: string | null; 46 | 47 | /** 48 | * The ID of the team this group belongs to. 49 | * @readonly 50 | */ 51 | public teamID: string; 52 | 53 | /** 54 | * The ID of the game this group belongs to. 55 | */ 56 | public gameID: string | null; 57 | 58 | /** 59 | * The role required to see this group. 60 | */ 61 | public visibilityTeamRoleID: number; 62 | 63 | /** 64 | * The role required to be considered a member of this group. 65 | */ 66 | public membershipTeamRoleID: number; 67 | 68 | /** 69 | * If this is the base group of the team this group belongs to. 70 | */ 71 | public isBase!: boolean; 72 | 73 | /** 74 | * The ID of the user that created this group. 75 | */ 76 | public readonly createdByID: string | null; 77 | 78 | /** 79 | * Date this group was created on. 80 | */ 81 | public readonly createdAt: Date; 82 | 83 | /** 84 | * The ID of the user that last updated this group. 85 | */ 86 | public updatedBy: string | null; 87 | 88 | /** 89 | * Date this group was last updated. 90 | */ 91 | public updatedAt: Date | null; 92 | 93 | /** 94 | * Date this group was deleted at. 95 | */ 96 | public deletedAt: Date | null; 97 | 98 | /** 99 | * ID of the custom reaction tied to this group. 100 | */ 101 | public customReactionID: string | null; 102 | 103 | /** 104 | * Whether this group is public or not (can be seen without being a member). 105 | */ 106 | public public!: boolean; 107 | 108 | /** 109 | * Date this group was archived at. 110 | */ 111 | public archivedAt: Date | null; 112 | 113 | /** 114 | * The ID of the user that archived this group. 115 | */ 116 | public archivedBy: string | null; 117 | 118 | public constructor(client: Client, data: APIGroup, public team: Team | null) { 119 | super(client, data); 120 | this.channels = new TeamGroupChannelManager(this.client, this); 121 | this.description = null; 122 | this.priority = null; 123 | this.type = data.type; 124 | this.avatar = null; 125 | this.banner = null; 126 | this.teamID = data.teamId; 127 | this.gameID = null; 128 | this.visibilityTeamRoleID = data.visibilityTeamRoleId; 129 | this.membershipTeamRoleID = data.membershipTeamRoleId; 130 | this.createdByID = data.createdBy; 131 | this.createdAt = new Date(data.createdAt); 132 | this.updatedAt = null; 133 | this.updatedBy = null; 134 | this.deletedAt = null; 135 | this.customReactionID = null; 136 | this.archivedAt = null; 137 | this.archivedBy = null; 138 | 139 | this.patch(data); 140 | } 141 | 142 | /** 143 | * Update the data in this structure 144 | * @internal 145 | */ 146 | public patch(data: APIGroup | Partial): this { 147 | if ('name' in data && data.name !== undefined) this.name = data.name; 148 | if ('description' in data && data.description !== undefined) this.description = data.description; 149 | if ('priority' in data && data.priority !== undefined) this.priority = data.priority; 150 | if ('type' in data && data.type !== undefined) this.type = data.type; 151 | if ('avatar' in data && data.avatar !== undefined) this.avatar = data.avatar; 152 | if ('banner' in data && data.banner !== undefined) this.banner = data.banner; 153 | if ('updatedBy' in data && data.updatedBy !== undefined) this.updatedBy = data.updatedBy ?? null; 154 | if ('updatedAt' in data && data.updatedAt !== undefined) { 155 | this.updatedAt = data.updatedAt ? new Date(data.updatedAt) : null; 156 | } 157 | if ('deletedAt' in data && data.deletedAt !== undefined) { 158 | this.deletedAt = data.deletedAt ? new Date(data.deletedAt) : null; 159 | } 160 | if ('customReactionId' in data && data.customReactionId !== undefined) { 161 | this.customReactionID = data.customReactionId; 162 | } 163 | if ('isPublic' in data && data.isPublic !== undefined) this.public = data.isPublic; 164 | if ('archivedAt' in data && data.archivedAt !== undefined) { 165 | this.archivedAt = data.archivedAt ? new Date(data.archivedAt) : null; 166 | } 167 | if ('archivedBy' in data && data.archivedBy !== undefined) this.archivedBy = data.archivedBy ?? null; 168 | return this; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/Member.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | APIAboutInfo, 3 | APIAlias, 4 | APIMember, 5 | APISocialLink, 6 | APIUserStatus, 7 | MembershipRole, 8 | } from '@guildedjs/guilded-api-typings'; 9 | 10 | import { Base } from './Base'; 11 | import type { Client } from './Client'; 12 | import { TeamMemberRoleManager } from './managers/TeamMemberRoleManager'; 13 | import type { Team } from './Team'; 14 | 15 | /** 16 | * A member of a team 17 | */ 18 | export class Member extends Base { 19 | /** 20 | * The current username of this member 21 | */ 22 | public name!: string; 23 | 24 | /** 25 | * The current nickname of this member in this team 26 | */ 27 | public nickname: string | null; 28 | 29 | /** 30 | * Badges belonging to this member 31 | */ 32 | public badges: string[] | null; 33 | 34 | /** 35 | * The date in which this member joined 36 | */ 37 | public joinDate: Date; 38 | 39 | /** 40 | * Unknown purpose 41 | */ 42 | public membershipRole!: MembershipRole; 43 | 44 | /** 45 | * The last date in which this member was detected to be online 46 | */ 47 | public lastOnline: Date | null; 48 | 49 | /** 50 | * The profile picture belonging to this member 51 | */ 52 | public profilePicture: string | null; 53 | 54 | /** 55 | * The blurred out banner belonging to this member 56 | */ 57 | public profileBannerBlur: string | null; 58 | 59 | /** 60 | * Additional info regarding this member 61 | */ 62 | public aboutInfo: APIAboutInfo | null; 63 | 64 | /** 65 | * This members current detected status 66 | */ 67 | public userStatus!: APIUserStatus; 68 | 69 | /** 70 | * Connections that this member has to other social media platforms 71 | */ 72 | public socialLinks: APISocialLink[] | null; 73 | 74 | /** 75 | * The IDs of the roles that this member has 76 | */ 77 | public roleIDs: number[] | null; 78 | 79 | /** 80 | * Unknown purpose 81 | */ 82 | public subscriptionType: string | null; 83 | 84 | /** 85 | * Aliases this member may have on games 86 | */ 87 | public aliases: APIAlias[]; 88 | 89 | /** 90 | * Unknown purpose 91 | */ 92 | public userPresenceStatus!: number; 93 | 94 | /** 95 | * The amount of XP this member has in this team 96 | */ 97 | public teamXp!: number; 98 | 99 | /** 100 | * The manager in charge of managing the roles this member has 101 | */ 102 | public roles: TeamMemberRoleManager; 103 | public constructor(client: Client, data: APIMember, public team: Team | null) { 104 | super(client, data); 105 | this.roles = new TeamMemberRoleManager(client, this); 106 | this.joinDate = new Date(data.joinDate); 107 | this.badges = []; 108 | this.nickname = null; 109 | this.lastOnline = null; 110 | this.profilePicture = null; 111 | this.profileBannerBlur = null; 112 | this.aboutInfo = null; 113 | this.socialLinks = []; 114 | this.roleIDs = []; 115 | this.subscriptionType = null; 116 | this.aliases = []; 117 | 118 | this.patch(data); 119 | } 120 | 121 | /** 122 | * Update the data in this structure 123 | * @internal 124 | */ 125 | public patch(data: APIMember | Partial): this { 126 | if ('name' in data && data.name !== undefined) this.name = data.name; 127 | if ('nickname' in data && data.nickname !== undefined) this.nickname = data.nickname; 128 | if ('badges' in data && data.badges !== undefined) this.badges = data.badges; 129 | if ('membershipRole' in data && data.membershipRole !== undefined) this.membershipRole = data.membershipRole; 130 | if ('lastOnline' in data && data.lastOnline !== undefined) { 131 | this.lastOnline = data.lastOnline ? new Date(data.lastOnline) : null; 132 | } 133 | if ('profilePicture' in data && data.profilePicture !== undefined) this.profilePicture = data.profilePicture; 134 | if ('profileBannerBlur' in data && data.profileBannerBlur !== undefined) { 135 | this.profileBannerBlur = data.profileBannerBlur; 136 | } 137 | if ('aboutInfo' in data && data.aboutInfo !== undefined) this.aboutInfo = data.aboutInfo; 138 | if ('userStatus' in data && data.userStatus !== undefined) this.userStatus = data.userStatus; 139 | if ('socialLinks' in data && data.socialLinks !== undefined) this.socialLinks = data.socialLinks; 140 | if ('roleIds' in data && data.roleIds !== undefined) this.roleIDs = data.roleIds; 141 | if ('subscriptionType' in data && data.subscriptionType !== undefined) { 142 | this.subscriptionType = data.subscriptionType; 143 | } 144 | if ('aliases' in data && data.aliases !== undefined) this.aliases = data.aliases; 145 | if ('userPresenceStatus' in data && data.userPresenceStatus !== undefined) { 146 | this.userPresenceStatus = Number(data.userPresenceStatus); 147 | } 148 | if ('teamXp' in data && data.teamXp !== undefined) this.teamXp = data.teamXp; 149 | 150 | return this; 151 | } 152 | 153 | public kick(): Promise { 154 | return this.client.teams.kickMember(this.team!, this); 155 | } 156 | 157 | public setNickname(newNickname: string): Promise { 158 | return this.client.teams.setMemberNickname(this.team!, this, newNickname); 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/Role.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | APITeamChannelRolePermissionOverwrite, 3 | APITeamRole, 4 | RolePermissions, 5 | } from '@guildedjs/guilded-api-typings'; 6 | 7 | import { retrieveTeamFromStructureCache } from '../util'; 8 | import { Base } from './Base'; 9 | import type { TeamChannel } from './Channel'; 10 | import type { Client } from './Client'; 11 | import type { Team } from './Team'; 12 | 13 | /** 14 | * A role belonging to a team 15 | */ 16 | export class Role extends Base { 17 | /** 18 | * Whether this role is mentionable. 19 | */ 20 | public mentionable!: boolean; 21 | 22 | /** 23 | * The base permissions this role has. 24 | */ 25 | public permissions!: RolePermissions; 26 | 27 | /** 28 | * Whether this role is hoisted or not. 29 | */ 30 | public hoisted!: boolean; 31 | 32 | /** 33 | * Discord sync'ed role info. 34 | */ 35 | public discord: { roleID: string | null; syncedAt: Date | null }; 36 | 37 | /** 38 | * Whether this role is self assignable by others. 39 | */ 40 | public selfAssignable!: boolean; 41 | 42 | /** 43 | * Date this role was created on. 44 | * @readonly 45 | */ 46 | public readonly createdAt: Date; 47 | 48 | /** 49 | * ID of the team this role belongs to. 50 | */ 51 | public readonly teamID: string; 52 | 53 | /** 54 | * Date this role was last updated on. 55 | */ 56 | public updatedAt: Date | null; 57 | 58 | /** 59 | * The position of this role. 60 | */ 61 | public priority!: number; 62 | 63 | /** 64 | * The color of this role. 65 | */ 66 | public color!: string; 67 | 68 | /** 69 | * The name of this role. 70 | */ 71 | public name!: string; 72 | 73 | public constructor(client: Client, data: APITeamRole, private _team: Team | null) { 74 | super(client, data); 75 | this.discord = { roleID: null, syncedAt: null }; 76 | this.createdAt = new Date(data.createdAt); 77 | this.updatedAt = null; 78 | this.teamID = data.teamId; 79 | this.patch(data); 80 | } 81 | 82 | public get team(): Team | null { 83 | return retrieveTeamFromStructureCache({ 84 | _team: this._team, 85 | client: this.client, 86 | teamID: this.teamID, 87 | }); 88 | } 89 | 90 | /** 91 | * Update the data in this structure 92 | * @internal 93 | */ 94 | public patch(data: APITeamRole | Partial): this { 95 | if ('permissions' in data && data.permissions) this.permissions = data.permissions; 96 | if ('isMentionable' in data && data.isMentionable) this.mentionable = data.isMentionable; 97 | if ('isDisplayedSeparately' in data && data.isDisplayedSeparately) this.hoisted = data.isDisplayedSeparately; 98 | if ('discordRoleId' in data && data.discordRoleId !== undefined) this.discord.roleID = data.discordRoleId; 99 | if ('discordSyncedAt' in data && data.discordSyncedAt !== undefined) { 100 | this.discord.syncedAt = data.discordSyncedAt ? new Date(data.discordSyncedAt) : null; 101 | } 102 | if ('isSelfAssignable' in data && data.isSelfAssignable) this.selfAssignable = data.isSelfAssignable; 103 | if ('updatedAt' in data && data.updatedAt !== undefined) { 104 | this.updatedAt = data.updatedAt ? new Date(data.updatedAt) : null; 105 | } 106 | if ('priority' in data && data.priority) this.priority = data.priority; 107 | if ('color' in data && data.color) this.color = data.color; 108 | if ('name' in data && data.name) this.name = data.name; 109 | 110 | return this; 111 | } 112 | } 113 | 114 | /** 115 | * Object representing permission overwrites for a role on a team channel. 116 | */ 117 | export class RolePermissionOverwrite { 118 | /** 119 | * The ID of the team this overwrite belongs to. 120 | */ 121 | public readonly teamID: string; 122 | 123 | /** 124 | * The ID of the channel this overwrite belongs to. 125 | */ 126 | public readonly channelID: string; 127 | 128 | /** 129 | * Date this overwrite was created on. 130 | */ 131 | public readonly createdAt: Date; 132 | 133 | /** 134 | * Date this overwrite was last updated on. 135 | */ 136 | public readonly updatedAt: Date | null; 137 | 138 | /** 139 | * The ID of the role this overwrite belongs to. 140 | */ 141 | public readonly teamRoleID: string; 142 | 143 | /** 144 | * The permissions this overwrite currently has denied. 145 | */ 146 | public readonly denyPermissions: RolePermissions; 147 | 148 | /** 149 | * The permissions this overwrite currently has allowed. 150 | */ 151 | public readonly allowPermissions: RolePermissions; 152 | 153 | public constructor( 154 | public client: Client, 155 | data: APITeamChannelRolePermissionOverwrite, 156 | public channel: TeamChannel, 157 | ) { 158 | this.teamID = data.teamId; 159 | this.channelID = data.channelId; 160 | this.createdAt = new Date(data.createdAt); 161 | this.updatedAt = data.updatedAt ? new Date(data.updatedAt) : null; 162 | this.teamRoleID = data.teamRoleId.toString(); 163 | this.denyPermissions = data.denyPermissions; 164 | this.allowPermissions = data.allowPermissions; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/Webhook.ts: -------------------------------------------------------------------------------- 1 | import type { APIWebhook } from '@guildedjs/guilded-api-typings'; 2 | 3 | import { 4 | retrieveChannelFromStructureCache, 5 | retrieveCreatorFromStructureCache, 6 | retrieveTeamFromStructureCache, 7 | } from '../util'; 8 | import { Base } from './Base'; 9 | import type { TeamChannel } from './Channel'; 10 | import type { Client } from './Client'; 11 | import type { Team } from './Team'; 12 | import type { User } from './User'; 13 | 14 | /** 15 | * Object representing received webhook data. This object is NOT to be used to send data to webhooks. That will be WebhookClient 16 | */ 17 | export class Webhook extends Base { 18 | /** 19 | * The username belonging to this webhook 20 | */ 21 | public name!: string; 22 | 23 | /** 24 | * The ID of the channel this webhook belongs to 25 | */ 26 | public channelID: string; 27 | 28 | /** 29 | * The ID of the team this webhook belongs to 30 | */ 31 | public teamID: string; 32 | 33 | /** 34 | * The URL of the avatar belonging to this webhook 35 | */ 36 | public iconURL: string | null; 37 | 38 | /** 39 | * The ID of the user who created this webhook 40 | */ 41 | public createdByID: string; 42 | 43 | /** 44 | * The date in which this webhook was created 45 | */ 46 | public createdAt: Date; 47 | 48 | /** 49 | * The date this webhook was deleted if it was deleted 50 | */ 51 | public deletedAt: Date | null; 52 | 53 | private _team: Team | null; 54 | private _createdBy: User | null; 55 | 56 | public constructor(client: Client, data: APIWebhook, private _channel: TeamChannel | null) { 57 | super(client, data); 58 | this.createdAt = new Date(data.createdAt); 59 | this.deletedAt = null; 60 | this.iconURL = null; 61 | this.createdByID = data.createdBy; 62 | this.channelID = data.channelId; 63 | this.teamID = data.teamId; 64 | this._team = _channel?.team ?? null; 65 | this._createdBy = null; 66 | this.patch(data); 67 | } 68 | 69 | /** 70 | * The channel object this webhook belongs to if cached 71 | */ 72 | public get channel(): TeamChannel | null { 73 | return retrieveChannelFromStructureCache({ 74 | _channel: this._channel, 75 | channelID: this.channelID, 76 | client: this.client, 77 | }) as TeamChannel | null; 78 | } 79 | 80 | /** 81 | * The User object of the user that created this webhook if cached 82 | */ 83 | public get createdBy(): User | null { 84 | return retrieveCreatorFromStructureCache({ 85 | _createdBy: this._createdBy, 86 | client: this.client, 87 | createdByID: this.createdByID, 88 | }); 89 | } 90 | 91 | /** 92 | * The team object this webhook belongs to if cached 93 | */ 94 | public get team(): Team | null { 95 | return retrieveTeamFromStructureCache({ 96 | _team: this._team, 97 | client: this.client, 98 | teamID: this.teamID, 99 | }); 100 | } 101 | 102 | /** 103 | * Update the data in this structure 104 | * @internal 105 | */ 106 | public patch(data: APIWebhook | Partial): this { 107 | if ('name' in data && data.name !== undefined) this.name = data.name; 108 | if ('iconUrl' in data && data.iconUrl !== undefined) this.iconURL = data.iconUrl; 109 | if ('deletedAt' in data && data.deletedAt !== undefined) { 110 | this.deletedAt = data.deletedAt ? new Date(data.deletedAt) : null; 111 | } 112 | 113 | return this; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/index.ts: -------------------------------------------------------------------------------- 1 | export * from '@guildedjs/embeds'; 2 | export * from '@guildedjs/webhook-client'; 3 | export * from './Channel'; 4 | export * from './Client'; 5 | export * from './Group'; 6 | export * from './Member'; 7 | export * from './Message'; 8 | export * from './Role'; 9 | export * from './Team'; 10 | export * from './User'; 11 | export * from './Webhook'; 12 | export * from './managers'; 13 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/BaseManager.ts: -------------------------------------------------------------------------------- 1 | import { CacheCollection, CacheCollectionOptions } from '@guildedjs/common'; 2 | 3 | import type { BaseData, constructable } from '../../typings'; 4 | import { Base } from '../Base'; 5 | import type { Client } from '../Client'; 6 | 7 | /** 8 | * The manager in charge of cached objects and potential api endpoints 9 | * @param K The base amount of data required to construct object T 10 | * @param T The object that will be held in this manager 11 | */ 12 | export class BaseManager> { 13 | public cache: CacheCollection = new CacheCollection(this.cacheOptions ?? {}); 14 | public constructor( 15 | public readonly client: Client, 16 | public readonly holds: constructable, 17 | public readonly cacheOptions?: CacheCollectionOptions, 18 | ) {} 19 | 20 | /** 21 | * Add an object, potential data, or constructor params into this managers cache 22 | * @private 23 | */ 24 | public add(data: T | K | Partial | ConstructorParameters>): T | null { 25 | if (this.isConstructorParamsOfHolds(data)) { 26 | const addition = new this.holds(...data); 27 | this.cache.set(addition.id.toString(), addition); 28 | return addition; 29 | } else if (this.isInstanceOfHolds(data)) { 30 | this.cache.set(data.id.toString(), data); 31 | return data; 32 | } else { 33 | const existing = data.id ? this.cache.get(data.id.toString()) : null; 34 | if (existing) { 35 | existing.patch(data as K | Partial); 36 | } 37 | return existing ?? null; 38 | } 39 | } 40 | 41 | private isConstructorParamsOfHolds( 42 | data: ConstructorParameters> | unknown, 43 | ): data is ConstructorParameters> { 44 | return Array.isArray(data); 45 | } 46 | 47 | private isInstanceOfHolds(data: T | K | Partial): data is T { 48 | return data instanceof this.holds; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/ChannelManager.ts: -------------------------------------------------------------------------------- 1 | import { generateMessage, parseToMessage } from '@guildedjs/common'; 2 | import Embed from '@guildedjs/embeds'; 3 | import type { 4 | APIGetChannelMessageResult, 5 | APIMessage, 6 | APIPostChannelMessagesResult, 7 | APITeamChannel, 8 | } from '@guildedjs/guilded-api-typings'; 9 | 10 | import { DMChannel, PartialChannel, TeamChannel } from '../Channel'; 11 | import type { Client } from '../Client'; 12 | import { Message, PartialMessage } from '../Message'; 13 | import { BaseManager } from './BaseManager'; 14 | import { MessageManager } from './MessageManager'; 15 | 16 | export class ChannelManager extends BaseManager { 17 | public constructor(client: Client) { 18 | super(client, PartialChannel, { maxSize: client.options?.cache?.cacheMaxSize?.channelsCache }); 19 | } 20 | 21 | public static resolve(channel: string | PartialChannel): string { 22 | return channel instanceof PartialChannel ? channel.id : channel; 23 | } 24 | 25 | /** 26 | * Send a message to a channel, using either the object or channel ID. 27 | * @param channel The ID or channel object of the target channel to send this message to 28 | */ 29 | public sendMessage( 30 | channel: string | PartialChannel, 31 | content: string | Embed, 32 | embed?: Embed, 33 | ): Promise { 34 | const channelID = ChannelManager.resolve(channel); 35 | const [messageID, formattedContent] = generateMessage(content, embed); 36 | return this.client.rest 37 | .post(`/channels/${channelID}/messages`, { ...formattedContent, messageId: messageID }) 38 | .then(x => 39 | 'id' in x 40 | ? new Message( 41 | this.client, 42 | x, 43 | channel instanceof PartialChannel ? channel : this.client.channels.add({ id: channel })!, 44 | ) 45 | : messageID, 46 | ); 47 | } 48 | 49 | /** 50 | * Fetch a message from a channel from the API 51 | * @param channel The ID or channel object of the taret channel to fetch the message from. 52 | * @param message The ID, message object, or partial message object of the message to fetch. 53 | * @param cache Whether to cache the fetched message or not. 54 | */ 55 | public fetchMessage( 56 | channel: string | PartialChannel, 57 | message: string | Message | PartialMessage, 58 | ): Promise { 59 | const channelID = ChannelManager.resolve(channel); 60 | const messageID = MessageManager.resolve(message); 61 | return this.client.rest 62 | .get(`/channels/${channelID}/chat?messageId=${messageID}`) 63 | .then(x => { 64 | let targetChannel = 65 | channel instanceof PartialChannel ? channel : this.client.channels.cache.get(channelID); 66 | if (!channel) { 67 | targetChannel = new PartialChannel(this.client, { id: x.channelId }, null); 68 | this.client.channels.add(targetChannel); 69 | } 70 | const newMessage = new Message(this.client, x, targetChannel!); 71 | targetChannel!.messages!.cache.set(newMessage.id, newMessage); 72 | return newMessage; 73 | }); 74 | } 75 | 76 | /** 77 | * Delete a message from a channel. 78 | * @param channel The ID or channel object of the channel to delete the message from. 79 | * @param msg The ID or message object of the message to delete. 80 | */ 81 | public deleteMessage(channel: string | PartialChannel, msg: string | Message): Promise { 82 | if (!msg) throw new TypeError('Expected a string or message object for message deletion.'); 83 | const channelID = ChannelManager.resolve(channel); 84 | const messageID = MessageManager.resolve(msg); 85 | return this.client.rest.delete(`/channels/${channelID}/messages/${messageID}`).then(() => { 86 | const existingChannel = this.cache.get(channelID); 87 | const existingMessage = existingChannel?.messages?.cache.get(messageID); 88 | 89 | if (existingMessage) existingMessage.deleted = true; 90 | return existingMessage ?? messageID; 91 | }); 92 | } 93 | 94 | /** 95 | * Edit a message 96 | * @hidden 97 | */ 98 | public editMessage(channel: string | PartialChannel, msg: string | Message, newContent: string): Promise { 99 | const channelID = ChannelManager.resolve(channel); 100 | const messageID = MessageManager.resolve(msg); 101 | return this.client.rest 102 | .put(`/channels/${channelID}/messages/${messageID}`, { content: parseToMessage(newContent) }) 103 | .then(x => { 104 | const existingChannel = this.client.channels.cache.get(x.channelId); 105 | if (!existingChannel) return new Message(this.client, x, null); 106 | const existingMessage = existingChannel.messages!.cache.get(x.id); 107 | if (existingMessage) return existingMessage.patch(x); 108 | return existingChannel.messages!.add(x)!; 109 | }); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/MessageManager.ts: -------------------------------------------------------------------------------- 1 | import Collection from '@discordjs/collection'; 2 | import type { APIGetChannelMessages, APIMessage } from '@guildedjs/guilded-api-typings'; 3 | 4 | import { UpgradedMessageData } from '../../typings'; 5 | import type { DMChannel, PartialChannel, TeamChannel } from '../Channel'; 6 | import type { Client } from '../Client'; 7 | import { Message, PartialMessage } from '../Message'; 8 | import { BaseManager } from './BaseManager'; 9 | import { ChannelManager } from './ChannelManager'; 10 | 11 | export class MessageManager extends BaseManager { 12 | public constructor(client: Client, public readonly channel: TeamChannel | DMChannel | PartialChannel) { 13 | super(client, Message, { maxSize: client.options?.cache?.cacheMaxSize?.messagesCache }); 14 | } 15 | 16 | public static resolve(message: string | Message | PartialMessage): string { 17 | return message instanceof Message || message instanceof PartialMessage ? message.id : message; 18 | } 19 | 20 | /** 21 | * Edit a message 22 | */ 23 | public edit(msg: string | Message, newContent: string): Promise { 24 | return this.client.channels.editMessage(this.channel.id, msg, newContent); 25 | } 26 | 27 | /** 28 | * Delete a message 29 | */ 30 | public delete(msg: string | Message): Promise { 31 | return this.client.channels.deleteMessage(this.channel.id, msg); 32 | } 33 | 34 | /** 35 | * Add a reaction to this message 36 | */ 37 | public react(message: string | Message, channel: string | PartialChannel, emoji: string): unknown { 38 | const messageID = MessageManager.resolve(message); 39 | const channelID = ChannelManager.resolve(channel); 40 | return this.client.rest.post(`/channels/${channelID}/messages/${messageID}/reactions/${emoji}`, {}); 41 | } 42 | 43 | /** 44 | * Remove a reaction from this message 45 | */ 46 | public unreact(message: string | Message, channel: string | PartialChannel, emoji: string): unknown { 47 | const messageID = MessageManager.resolve(message); 48 | const channelID = ChannelManager.resolve(channel); 49 | return this.client.rest.delete(`/channels/${channelID}/messages/${messageID}/reactions/${emoji}`, {}); 50 | } 51 | 52 | /** 53 | * Fetch multiple messages from the channel this manager belongs to 54 | * @param amnt The amount of messages to fetch. 55 | * @param cache Whether to cache the fetched messages or not. 56 | */ 57 | public fetch(amnt: number, cache = true): Promise> { 58 | if (Number.isNaN(amnt)) throw new TypeError('Expected a number for message fetching amount!'); 59 | if (amnt > 100) amnt = 100; 60 | if (amnt < 0) amnt = 1; 61 | const messages: Collection = new Collection(); 62 | return this.client.rest 63 | .get(`/channels/${this.channel.id}/messages?limit=${amnt}`) 64 | .then(x => { 65 | for (const message of x.messages) { 66 | const tempMessage = this.add([this.client, message, this.channel]); 67 | messages.set(message.id, tempMessage!); 68 | if (cache) this.add(tempMessage!); 69 | } 70 | return messages; 71 | }); 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamGroupChannelManager.ts: -------------------------------------------------------------------------------- 1 | import type { APITeamChannel, CHANNEL_TYPES } from '@guildedjs/guilded-api-typings'; 2 | 3 | import { TeamChannel } from '../Channel'; 4 | import type { Client } from '../Client'; 5 | import type { Group } from '../Group'; 6 | import { BaseManager } from './BaseManager'; 7 | 8 | export class TeamGroupChannelManager extends BaseManager { 9 | public constructor(client: Client, public group: Group) { 10 | super(client, TeamChannel, { maxSize: client.options?.cache?.cacheMaxSize?.channelsCache }); 11 | } 12 | 13 | /** 14 | * Create a channel in the group this manager belongs to. 15 | */ 16 | public create({ 17 | name, 18 | parent, 19 | type, 20 | isPublic = true, 21 | }: { 22 | name: string; 23 | parent?: string; 24 | type: CHANNEL_TYPES; 25 | isPublic: boolean; 26 | }): Promise { 27 | return this.client.rest.post(`/teams/${this.group.team?.id}/groups/${this.group.id}/channels`, { 28 | channelCategoryId: parent, 29 | contentType: type, 30 | isPublic: isPublic, 31 | name, 32 | }); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamGroupManager.ts: -------------------------------------------------------------------------------- 1 | import type { APIGroup } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../Client'; 4 | import { Group } from '../Group'; 5 | import type { Team } from '../Team'; 6 | import { BaseManager } from './BaseManager'; 7 | 8 | export class TeamGroupManager extends BaseManager { 9 | public constructor(client: Client, public readonly team: Team) { 10 | super(client, Group, { maxSize: client.options?.cache?.cacheMaxSize?.groupsCache }); 11 | } 12 | 13 | public static resolve(group: string | Group): string { 14 | return group instanceof Group ? group.id : group; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamManager.ts: -------------------------------------------------------------------------------- 1 | import type { 2 | APIGetTeam, 3 | APIPartialTeam, 4 | APIPostCreateInviteResult, 5 | APITeam, 6 | CHANNEL_CONTENT_TYPES, 7 | } from '@guildedjs/guilded-api-typings'; 8 | 9 | import { TeamChannel } from '../Channel'; 10 | import type { Client } from '../Client'; 11 | import { Group } from '../Group'; 12 | import { Member } from '../Member'; 13 | import { Role } from '../Role'; 14 | import { Team } from '../Team'; 15 | import { BaseManager } from './BaseManager'; 16 | import { TeamGroupManager } from './TeamGroupManager'; 17 | import { TeamMemberManager } from './TeamMemberManager'; 18 | 19 | export class TeamManager extends BaseManager { 20 | public constructor(client: Client) { 21 | super(client, Team, { maxSize: client.options?.cache?.cacheMaxSize?.teamsCache }); 22 | } 23 | 24 | public static resolve(team: string | Team): string { 25 | return team instanceof Team ? team.id : team; 26 | } 27 | 28 | /** 29 | * Add a role to a TeamMember 30 | * @param team The ID or team object of the Team the target member is in. 31 | * @param member The ID or member object of the Member that will have the role added to them. 32 | * @param role The ID or role object of the Role to add to the member. 33 | */ 34 | public addRoleToMember(team: string | Team, member: string | Member, role: string | Role): Promise { 35 | const roleID = role instanceof Role ? role.id : role; 36 | const memberID = TeamMemberManager.resolve(member); 37 | const teamID = TeamManager.resolve(team); 38 | return this.client.rest.put(`/teams/${teamID}/roles/${roleID}/users/${memberID}`).then(() => void 0); 39 | } 40 | 41 | /** 42 | * Remove a role from a TeamMember 43 | * @param team The ID or team object of the Team the target member is in. 44 | * @param member The ID or member object of the Member that will have the role removed from them. 45 | * @param role The ID or role object of the Role to remove from the member. 46 | */ 47 | public removeRoleFromMember(team: string | Team, member: string | Member, role: string | Role): Promise { 48 | const roleID = role instanceof Role ? role.id : role; 49 | const memberID = TeamMemberManager.resolve(member); 50 | const teamID = TeamManager.resolve(team); 51 | return this.client.rest.delete(`/teams/${teamID}/roles/${roleID}/users/${memberID}`).then(() => void 0); 52 | } 53 | 54 | /** 55 | * Kick a TeamMember 56 | * @param team The ID or team object of the Team the target member is in. 57 | * @param member The ID or member object of the Member that will be kicked 58 | */ 59 | public kickMember(team: string | Team, member: string | Member): Promise { 60 | const memberID = TeamMemberManager.resolve(member); 61 | const teamID = TeamManager.resolve(team); 62 | return this.client.rest.delete(`/teams/${teamID}/members/${memberID}`).then(() => void 0); 63 | } 64 | 65 | /** 66 | * Set a TeamMember's name 67 | * @param team The ID or team object of the Team the target member is in. 68 | * @param member The ID or member object of the Member that will be renamed. 69 | * @param newNickname The new nickname to give to the Member. 70 | */ 71 | public setMemberNickname(team: string | Team, member: string | Member, newNickname: string): Promise { 72 | if (typeof newNickname !== 'string') throw new TypeError('Nickname must be a string!'); 73 | const memberID = TeamMemberManager.resolve(member); 74 | const teamID = TeamManager.resolve(team); 75 | return this.client.rest 76 | .put(`/teams/${teamID}/members/${memberID}/nickname`, { nickname: newNickname }) 77 | .then(() => void 0); 78 | } 79 | 80 | /** 81 | * Creates an Invite for the Team 82 | * @param team The ID or team object of the Team. 83 | * @returns The ID of the created Invite 84 | */ 85 | public createInvite(team: string | Team): Promise { 86 | const teamID = TeamManager.resolve(team); 87 | return this.client.rest.post(`/teams/${teamID}/invites`, { teamId: teamID }).then(x => x.invite); 88 | } 89 | 90 | public deleteInvite(team: string | Team, inviteID: string): Promise { 91 | if (typeof inviteID !== 'string') throw new TypeError('InviteID must be a string!'); 92 | const teamID = TeamManager.resolve(team); 93 | return this.client.rest.delete(`/teams/${teamID}/invites/${inviteID}`).then(x => x.id); 94 | } 95 | 96 | /** 97 | * Creates a Teamchannel 98 | * @param team 99 | * @param group 100 | * @param name 101 | * @param contentType 102 | * @param channelCategoryId 103 | * @param isPublic 104 | * @returns 105 | */ 106 | 107 | public createChannel( 108 | team: string | Team, 109 | group: string | Group, 110 | name: string, 111 | contentType: CHANNEL_CONTENT_TYPES, 112 | channelCategoryId: number | null = null, 113 | isPublic = false, 114 | ): Promise { 115 | if (typeof name !== 'string') { 116 | throw new TypeError('Name must be a string!'); 117 | } 118 | const teamID = TeamManager.resolve(team); 119 | const groupID = TeamGroupManager.resolve(group); 120 | return this.client.rest.post(`/teams/${teamID}/groups/${groupID}`, { 121 | channelCategoryId, 122 | contentType, 123 | isPublic, 124 | name, 125 | }); 126 | // .then(x => new TeamChannel(this.client, x, null, null)); 127 | } 128 | 129 | /** 130 | * Fetch a team, will retrieve from cache if exists 131 | * @param id the ID of the team to fetch. 132 | * @param cache Whether to cache the fetched Team or not. 133 | */ 134 | public fetch(id: string, cache = true): Promise { 135 | return this.client.rest.get(`/teams/${id}`).then(data => { 136 | const cachedTeam = this.client.teams.cache.get(id); 137 | 138 | if (cache && cachedTeam) { 139 | cachedTeam.patch(data.team); 140 | for (const member of data.team.members) { 141 | const existingMember = cachedTeam.members.cache.get(member.id); 142 | if (existingMember) existingMember.patch(member); 143 | else cachedTeam.members.cache.set(member.id, new Member(this.client, member, cachedTeam)); 144 | } 145 | } 146 | 147 | return cachedTeam ?? new Team(this.client, data.team); 148 | }); 149 | } 150 | } 151 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamMemberManager.ts: -------------------------------------------------------------------------------- 1 | import type { APIMember } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../Client'; 4 | import { Member } from '../Member'; 5 | import type { Team } from '../Team'; 6 | import { BaseManager } from './BaseManager'; 7 | 8 | export class TeamMemberManager extends BaseManager { 9 | public constructor(client: Client, public readonly team: Team) { 10 | super(client, Member, { maxSize: client.options?.cache?.cacheMaxSize?.membersCache }); 11 | } 12 | 13 | public static resolve(member: string | Member): string { 14 | return member instanceof Member ? member.id : member; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamMemberRoleManager.ts: -------------------------------------------------------------------------------- 1 | import type { APITeamRole } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../Client'; 4 | import type { Member } from '../Member'; 5 | import { Role } from '../Role'; 6 | import { BaseManager } from './BaseManager'; 7 | 8 | export class TeamMemberRoleManager extends BaseManager { 9 | public constructor(client: Client, public readonly member: Member) { 10 | super(client, Role, { maxSize: client.options?.cache?.cacheMaxSize?.memberRolesCache }); 11 | } 12 | 13 | /** 14 | * Shortcut for adding a role to a member. 15 | * @param role The ID or Role object of the role to add to the member. 16 | * @see {@link https://zaida04.github.io/guildedjs-selfbot-docs/classes/guilded_js.teammanager.html#addroletomember} 17 | */ 18 | public append(role: string | Role): Promise { 19 | return this.client.teams.addRoleToMember(this.member.team!.id, this.member, role); 20 | } 21 | 22 | /** 23 | * Shortcut for removing a role from a member. 24 | * @param role The ID or Role object of the role to add to the member. 25 | * @see {@link https://zaida04.github.io/guildedjs-selfbot-docs/classes/guilded_js.teammanager.html#removerolefrommember} 26 | */ 27 | public remove(role: string | Role): Promise { 28 | return this.client.teams.removeRoleFromMember(this.member.team!.id, this.member, role); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamRoleManager.ts: -------------------------------------------------------------------------------- 1 | import type { APITeamRole } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../Client'; 4 | import { Role } from '../Role'; 5 | import { Team } from '../Team'; 6 | import { BaseManager } from './BaseManager'; 7 | 8 | export class TeamRoleManager extends BaseManager { 9 | public constructor(client: Client, public readonly team: Team) { 10 | super(client, Role, { maxSize: client.options?.cache?.cacheMaxSize?.memberRolesCache }); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/TeamWebhookManager.ts: -------------------------------------------------------------------------------- 1 | import type { APIWebhook } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../Client'; 4 | import type { Team } from '../Team'; 5 | import { Webhook } from '../Webhook'; 6 | import { BaseManager } from './BaseManager'; 7 | 8 | export class TeamWebhookManager extends BaseManager { 9 | public constructor(client: Client, public readonly team: Team) { 10 | super(client, Webhook, { maxSize: client.options?.cache?.cacheMaxSize?.teamWebhooksCache }); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/UserManager.ts: -------------------------------------------------------------------------------- 1 | import type { APIGetUser, APIUser } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../Client'; 4 | import { User } from '../User'; 5 | import { BaseManager } from './BaseManager'; 6 | 7 | export class UserManager extends BaseManager { 8 | public constructor(client: Client) { 9 | super(client, User, { maxSize: client.options?.cache?.cacheMaxSize?.usersCache }); 10 | } 11 | 12 | /** 13 | * Fetch a user, retrieves from the cache if exists 14 | */ 15 | public fetch(id: string, cache = true, force = false): Promise { 16 | const existing = force ? null : this.cache.get(id); 17 | if (existing) return Promise.resolve(existing); 18 | 19 | return this.client.rest.get(`/users/${id}`).then(x => { 20 | const tempUser = new User(this.client, x.user); 21 | if (cache) this.client.users.cache.set(tempUser.id, tempUser); 22 | return tempUser; 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/structures/managers/index.ts: -------------------------------------------------------------------------------- 1 | export * from './BaseManager'; 2 | export * from './ChannelManager'; 3 | export * from './MessageManager'; 4 | export * from './TeamGroupChannelManager'; 5 | export * from './TeamGroupManager'; 6 | export * from './TeamManager'; 7 | export * from './TeamMemberManager'; 8 | export * from './TeamMemberRoleManager'; 9 | export * from './TeamWebhookManager'; 10 | export * from './UserManager'; 11 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/typings.ts: -------------------------------------------------------------------------------- 1 | import { APIMessage, APIPartialMessage } from '@guildedjs/guilded-api-typings'; 2 | 3 | /** 4 | * The minimum amount of data that is needed to construct any structure 5 | * @internal 6 | */ 7 | export interface BaseData { 8 | readonly id: string; 9 | } 10 | 11 | /** 12 | * Adapted from https://github.com/discordjs/discord.js/blob/master/typings/index.d.ts#L2051 13 | * @internal 14 | */ 15 | // eslint-disable-next-line @typescript-eslint/no-explicit-any 16 | export type constructable = new (...args: any[]) => T; 17 | 18 | export interface PartialMessageData extends APIPartialMessage { 19 | channelId: string; 20 | } 21 | 22 | export interface UpgradedMessageData extends APIMessage { 23 | teamId?: string | null; 24 | } 25 | 26 | /* eslint-disable @typescript-eslint/naming-convention */ 27 | export enum websocket_events { 28 | CHAT_MESSAGE_CREATED = 'ChatMessageCreated', 29 | CHAT_MESSAGE_UPDATED = 'ChatMessageUpdated', 30 | CHAT_MESSAGE_REACTION_ADDED = 'ChatMessageReactionAdded', 31 | CHAT_MESSAGE_REACTION_DELETED = 'ChatMessageReactionDeleted', 32 | } 33 | 34 | export enum events { 35 | MESSAGE_CREATE = 'messageCreate', 36 | MESSAGE_UPDATE = 'messageUpdate', 37 | MESSAGE_REACTION_ADD = 'messageReactionAdd', 38 | MESSAGE_REACTION_DELETE = 'messageReactionDelete', 39 | READY = 'ready', 40 | } 41 | 42 | export type clientPartial = 'MEMBER' | 'MESSAGE' | 'USER' | 'CHANNEL'; 43 | 44 | /** 45 | * Options you can instantiate the client with. 46 | */ 47 | export interface ClientOptions { 48 | partials?: clientPartial[]; 49 | cache?: { 50 | startupRestrictions?: { 51 | dropDMs?: boolean; 52 | dropTeams?: boolean; 53 | dropChannels?: boolean; 54 | }; 55 | cacheMaxSize?: { 56 | teamsCache?: number; 57 | channelsCache?: number; 58 | usersCache?: number; 59 | membersCache?: number; 60 | memberRolesCache?: number; 61 | teamRolesCache?: number; 62 | teamWebhooksCache?: number; 63 | groupsCache?: number; 64 | messagesCache?: number; 65 | }; 66 | disableTeam?: boolean; 67 | disableChannels?: boolean; 68 | disableUsers?: boolean; 69 | disableMembers?: boolean; 70 | disableMembersRoles?: boolean; 71 | disableTeamRoles?: boolean; 72 | disableWebhooks?: boolean; 73 | disableGroups?: boolean; 74 | disableMessages?: boolean; 75 | }; 76 | ws?: { 77 | heartbeatInterval?: number; 78 | disabledEvents?: events[]; 79 | disallowReconnect?: boolean; 80 | reconnectLimit?: number; 81 | blockTeamWSConnection?: boolean; 82 | }; 83 | rest?: { 84 | apiURL?: string; 85 | cdnURL?: string; 86 | }; 87 | } 88 | 89 | /** 90 | * Options to log the client in with 91 | */ 92 | export interface LoginOptions { 93 | email: string; 94 | password: string; 95 | } 96 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/util.ts: -------------------------------------------------------------------------------- 1 | import type { Client, PartialChannel, Team, User } from './structures'; 2 | 3 | export function retrieveTeamFromStructureCache({ 4 | client, 5 | _team, 6 | teamID, 7 | }: { 8 | client: Client; 9 | _team: Team | null; 10 | teamID: string | null; 11 | }): Team | null { 12 | if (_team) return _team; 13 | if (!teamID) return null; 14 | const cachedTeam = client.teams.cache.get(teamID); 15 | return cachedTeam ?? null; 16 | } 17 | 18 | export function retrieveChannelFromStructureCache({ 19 | client, 20 | _channel, 21 | channelID, 22 | }: { 23 | client: Client; 24 | _channel: PartialChannel | null; 25 | channelID: string | null; 26 | }): PartialChannel | null { 27 | if (_channel) return _channel; 28 | if (!channelID) return null; 29 | const cachedChannel = client.channels.cache.get(channelID); 30 | return cachedChannel ?? null; 31 | } 32 | 33 | export function retrieveCreatorFromStructureCache({ 34 | client, 35 | _createdBy, 36 | createdByID, 37 | }: { 38 | client: Client; 39 | _createdBy: User | null; 40 | createdByID: string | null; 41 | }): User | null { 42 | if (_createdBy) return _createdBy; 43 | if (!createdByID) return null; 44 | const cachedUser = client.users.cache.get(createdByID); 45 | return cachedUser ?? null; 46 | } 47 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/ClientGatewayHandler.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | import { ROUTES } from '@guildedjs/common'; 3 | import type { 4 | WSChatMessageCreated, 5 | WSChatMessageReactionAdded, 6 | WSChatMessageReactionDeleted, 7 | WSChatMessageUpdated, 8 | WSGatewayReady, 9 | } from '@guildedjs/guilded-api-typings'; 10 | import WebSocket from 'ws'; 11 | 12 | import type { Client } from '../structures/Client'; 13 | import { events, websocket_events } from '../typings'; 14 | import ChatMessageCreatedEvent from './events/ChatMessageCreated'; 15 | import ChatMessageReactionAddedEvent from './events/ChatMessageReactionAdded'; 16 | import ChatMessageReactionDeletedEvent from './events/ChatMessageReactionDeleted'; 17 | import ChatMessageUpdatedEvent from './events/ChatMessageUpdated'; 18 | import GatewayHandler from './GatewayHandler'; 19 | 20 | export class ClientGatewayHandler extends GatewayHandler { 21 | public lastPing: number | null = null; 22 | private reconnectionAmnt = 0; 23 | 24 | public events = { 25 | chatMessageCreated: new ChatMessageCreatedEvent(this.client), 26 | chatMessageReactionAdded: new ChatMessageReactionAddedEvent(this.client), 27 | chatMessageReactionDeleted: new ChatMessageReactionDeletedEvent(this.client), 28 | chatMessageUpdated: new ChatMessageUpdatedEvent(this.client), 29 | }; 30 | public constructor(client: Client) { 31 | super(client); 32 | } 33 | 34 | public init(): this | null { 35 | if (this.ws) return this; 36 | // eslint-disable-next-line max-len 37 | const socketURL = `wss://${ROUTES.BASE_DOMAIN}/socket.io/?jwt=undefined&guildedClientId=${this.client.rest.guildedMID}&EIO=3&transport=websocket`; 38 | this.ws = new WebSocket(socketURL, { 39 | headers: { 40 | cookie: `hmac_signed_session=${this.client.rest.token};`, 41 | }, 42 | }); 43 | this.ws 44 | .on('open', () => (this.connectedAt = new Date())) 45 | .on('message', (incomingData: string) => { 46 | this.client.debug('Gateway message recieved', incomingData); 47 | this.dataRecieved(incomingData); 48 | }) 49 | .on('close', (...closeData: unknown[]) => { 50 | this.client.debug(`Gateway connection terminated. Related data: ${closeData}`); 51 | const shouldntReconnect = 52 | this.client.options?.ws?.disallowReconnect || 53 | this.reconnectionAmnt >= (this.client.options?.ws?.reconnectLimit ?? Infinity); 54 | this.client.destroy(!shouldntReconnect); 55 | 56 | if (shouldntReconnect) return this.client.emit('disconnected', closeData); 57 | this.reconnectionAmnt++; 58 | this.client.emit('reconnecting', closeData); 59 | }); 60 | return this; 61 | } 62 | 63 | public dataRecieved(incomingData: string): void { 64 | let data: string = incomingData; 65 | let opCode = ''; 66 | for (const char of data) { 67 | if (!Number.isInteger(Number(char))) break; 68 | data = data.substring(1); 69 | opCode += char; 70 | } 71 | 72 | try { 73 | switch (Number(opCode)) { 74 | case 0: { 75 | this.client.debug('Heartbeat started...'); 76 | 77 | let packet; 78 | try { 79 | packet = JSON.parse(data) as WSGatewayReady; 80 | } catch (e) { 81 | throw new Error(`malformed payload! ${data}`); 82 | } 83 | 84 | this.sessionID = packet.sid; 85 | this.heartbeater.start(packet.pingInterval); 86 | break; 87 | } 88 | 89 | case 3: { 90 | this.lastPing = Date.now(); 91 | this.ping = this.lastPing - this.heartbeater.lastPingSentAt; 92 | this.client.debug('Ping returned. '); 93 | break; 94 | } 95 | 96 | case 40: { 97 | this.client.debug('Ready event recieved.'); 98 | this.client.emit(events.READY); 99 | break; 100 | } 101 | 102 | case 42: { 103 | let EVENT_NAME, EVENT_DATA; 104 | 105 | try { 106 | [EVENT_NAME, EVENT_DATA] = JSON.parse(data); 107 | } catch (e) { 108 | throw new Error(`malformed payload! ${data}`); 109 | } 110 | 111 | if (this.client.options?.ws?.disabledEvents?.includes(EVENT_NAME)) return; 112 | this.client.emit('raw', EVENT_NAME, EVENT_DATA); 113 | 114 | let result: (boolean | (string | undefined))[] | undefined; 115 | switch (EVENT_NAME) { 116 | case websocket_events.CHAT_MESSAGE_CREATED: { 117 | result = this.events.chatMessageCreated.ingest(EVENT_DATA as WSChatMessageCreated); 118 | break; 119 | } 120 | case websocket_events.CHAT_MESSAGE_UPDATED: { 121 | result = this.events.chatMessageUpdated.ingest(EVENT_DATA as WSChatMessageUpdated); 122 | break; 123 | } 124 | case websocket_events.CHAT_MESSAGE_REACTION_ADDED: { 125 | result = this.events.chatMessageReactionAdded.ingest( 126 | EVENT_DATA as WSChatMessageReactionAdded, 127 | ); 128 | break; 129 | } 130 | case websocket_events.CHAT_MESSAGE_REACTION_DELETED: { 131 | result = this.events.chatMessageReactionDeleted.ingest( 132 | EVENT_DATA as WSChatMessageReactionDeleted, 133 | ); 134 | break; 135 | } 136 | } 137 | if (!result?.[0]) { 138 | this.client.debug( 139 | `Event ${EVENT_NAME} dropped because of ${result?.[1] ?? 'unknown reason or not handled'}`, 140 | ); 141 | } 142 | break; 143 | } 144 | } 145 | } catch (e) { 146 | this.client.debug('Error parsing WS event', e); 147 | } 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/GatewayHandler.ts: -------------------------------------------------------------------------------- 1 | import WebSocket from 'ws'; 2 | 3 | import type { Client } from '../structures/Client'; 4 | import Heartbeater from './Heartbeater'; 5 | 6 | export default abstract class GatewayHandler { 7 | public ws!: WebSocket | null; 8 | public heartbeater = new Heartbeater(this); 9 | public ping = 0; 10 | public connectedAt: Date | null = null; 11 | public sessionID: string | null = null; 12 | 13 | public constructor(public readonly client: Client) {} 14 | public abstract init(): void; 15 | public destroy(intentionToReconnect: boolean): void { 16 | if (!this.ws) { 17 | throw Error("Attempting to destroy WS connection that doesn't exist!"); 18 | } 19 | 20 | /** 21 | * Credits to: https://github.com/Skillz4Killz/gapi/blob/master/src/websocket/Shard.ts#L186 22 | * AUTHOR: https://github.com/Skillz4Killz 23 | * LICENSE: APACHE LICENSE 2.0 (https://github.com/Skillz4Killz/gapi/blob/master/LICENSE) 24 | */ 25 | if (intentionToReconnect && this.sessionID) { 26 | if (this.ws.readyState === WebSocket.OPEN) this.ws?.close(4901, 'Reconnect with session id please'); 27 | else this.ws?.terminate(); 28 | } else { 29 | this.ws?.close(1000, 'Clean close with no reconnection.'); 30 | } 31 | 32 | this.ws.removeAllListeners(); 33 | this.ws = null; 34 | this.heartbeater.destroy(); 35 | 36 | if (intentionToReconnect) this.init(); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/Heartbeater.ts: -------------------------------------------------------------------------------- 1 | import GatewayHandler from './GatewayHandler'; 2 | 3 | export default class Heartbeater { 4 | public interval!: NodeJS.Timeout; 5 | public lastPingSentAt = 0; 6 | public active = false; 7 | 8 | public constructor(public gateway: GatewayHandler) {} 9 | public start(interval?: number): void { 10 | this.gateway.client.debug('Heartbeating...'); 11 | this.active = true; 12 | this.interval = setInterval( 13 | this.sendHB.bind(this), 14 | interval ?? this.gateway.client.options?.ws?.heartbeatInterval ?? 15000, 15 | ); 16 | } 17 | 18 | public destroy(): void { 19 | clearInterval(this.interval); 20 | this.active = false; 21 | } 22 | 23 | public sendHB(): void { 24 | if (!this.gateway.ws) return; 25 | if (this.gateway.ws.readyState !== 1) return; 26 | this.lastPingSentAt = Date.now(); 27 | this.gateway.ws.send('2'); 28 | this.gateway.client.rest.put('/users/me/ping'); 29 | this.gateway.client.debug('heartbeat sent'); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/events/ChatMessageCreated.ts: -------------------------------------------------------------------------------- 1 | import { WSChatMessageCreated } from '@guildedjs/guilded-api-typings'; 2 | 3 | import { PartialChannel } from '../../structures'; 4 | import type { Client } from '../../structures/Client'; 5 | import { Message } from '../../structures/Message'; 6 | import { events } from '../../typings'; 7 | import Event from './Event'; 8 | 9 | export default class ChatMessageCreatedEvent extends Event { 10 | public constructor(client: Client) { 11 | super(client); 12 | } 13 | public ingest(data: WSChatMessageCreated): (boolean | (string | undefined))[] { 14 | if (data) { 15 | let channel = this.client.channels.cache.get(data.channelId); 16 | const team = (data.teamId ? this.client.teams.cache.get(data.teamId) : null) ?? null; 17 | 18 | if (!channel) { 19 | channel = new PartialChannel( 20 | this.client, 21 | { 22 | contentType: data.contentType, 23 | createdAt: data.createdAt, 24 | createdBy: data.createdBy, 25 | id: data.channelId, 26 | type: data.channelType, 27 | }, 28 | team, 29 | ); 30 | this.client.channels.cache.set(channel.id, channel); 31 | } 32 | 33 | const newMessage = new Message( 34 | this.client, 35 | { channelId: data.channelId, teamId: data.teamId, ...data.message }, 36 | channel, 37 | )!; 38 | channel.messages!.cache.set(newMessage.id, newMessage); 39 | this.client.emit(events.MESSAGE_CREATE, newMessage); 40 | return [true]; 41 | } 42 | return [false, 'passthrough']; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/events/ChatMessageReactionAdded.ts: -------------------------------------------------------------------------------- 1 | import { WSChatMessageReactionAdded } from '@guildedjs/guilded-api-typings'; 2 | 3 | import { MessageReaction } from '../../structures'; 4 | import type { Client } from '../../structures/Client'; 5 | import { events } from '../../typings'; 6 | import Event from './Event'; 7 | 8 | export default class ChatMessageReactionAddedEvent extends Event { 9 | public constructor(client: Client) { 10 | super(client); 11 | } 12 | public ingest(data: WSChatMessageReactionAdded): (boolean | (string | undefined))[] { 13 | if (data) { 14 | const reacter = this.client.users.cache.get(data.reaction.createdBy); 15 | 16 | let channel = this.client.channels.cache.get(data.channelId); 17 | if (!channel) { 18 | if (!this.client.options?.partials?.includes('CHANNEL')) return [false, 'Uncached channel']; 19 | channel = this.client.channels.add({ 20 | contentType: data.contentType, 21 | id: data.channelId, 22 | teamId: data.teamId ?? undefined, 23 | type: data.channelType, 24 | })!; 25 | } 26 | 27 | const message = channel?.messages?.cache.get(data.message.id); 28 | if (!message && !this.client.options?.partials?.includes('MESSAGE')) return [false, 'Uncached message']; 29 | 30 | let messageReaction = message?.reactions.get(data.reaction.customReactionId.toString()); 31 | if (!messageReaction) { 32 | const newMessageReaction = new MessageReaction(this.client, { 33 | ...data.reaction, 34 | createdAt: new Date().toISOString(), 35 | users: [{ botId: null, id: data.reaction.createdBy, webhookId: null }], 36 | }); 37 | message?.reactions.set(newMessageReaction.id, newMessageReaction); 38 | messageReaction = newMessageReaction; 39 | } 40 | messageReaction.users.set( 41 | data.reaction.createdBy, 42 | this.client.users.cache.get(data.reaction.createdBy) ?? { id: data.reaction.createdBy }, 43 | ); 44 | 45 | this.client.emit(events.MESSAGE_REACTION_ADD, messageReaction, reacter ?? data.reaction.createdBy); 46 | return [true]; 47 | } 48 | 49 | return [false, 'passthrough']; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/events/ChatMessageReactionDeleted.ts: -------------------------------------------------------------------------------- 1 | import { WSChatMessageReactionDeleted } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../../structures/Client'; 4 | import { events } from '../../typings'; 5 | import Event from './Event'; 6 | 7 | export default class ChatMessageReactionDeletedEvent extends Event { 8 | public constructor(client: Client) { 9 | super(client); 10 | } 11 | public ingest(data: WSChatMessageReactionDeleted): (boolean | (string | undefined))[] { 12 | if (data) { 13 | const reactionID = data.reaction.customReactionId.toString(); 14 | const reacter = this.client.users.cache.get(data.reaction.createdBy); 15 | 16 | let channel = this.client.channels.cache.get(data.channelId); 17 | if (!channel) { 18 | if (!this.client.options?.partials?.includes('CHANNEL')) return [false, 'Uncached channel']; 19 | channel = this.client.channels.add({ 20 | contentType: data.contentType, 21 | id: data.channelId, 22 | teamId: data.teamId ?? undefined, 23 | type: data.channelType, 24 | })!; 25 | } 26 | 27 | const message = channel?.messages?.cache.get(data.message.id); 28 | if (!message && !this.client.options?.partials?.includes('MESSAGE')) return [false, 'Uncached message']; 29 | 30 | const messageReaction = message?.reactions.get(reactionID); 31 | messageReaction?.users.delete(data.reaction.createdBy); 32 | if (!messageReaction?.users.size) message?.reactions.delete(reactionID); 33 | 34 | this.client.emit( 35 | events.MESSAGE_REACTION_DELETE, 36 | messageReaction ?? reactionID, 37 | reacter ?? data.reaction.createdBy, 38 | ); 39 | return [true]; 40 | } 41 | 42 | return [false, 'passthrough']; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/events/ChatMessageUpdated.ts: -------------------------------------------------------------------------------- 1 | import { WSChatMessageUpdated } from '@guildedjs/guilded-api-typings'; 2 | 3 | import type { Client } from '../../structures/Client'; 4 | import { PartialMessage } from '../../structures/Message'; 5 | import { events } from '../../typings'; 6 | import Event from './Event'; 7 | 8 | export default class ChatMessageUpdatedEvent extends Event { 9 | public constructor(client: Client) { 10 | super(client); 11 | } 12 | public ingest(data: WSChatMessageUpdated): (boolean | (string | undefined))[] { 13 | if (data) { 14 | const channel = this.client.channels.cache.get(data.channelId); 15 | const oldMessage = channel?.messages?.cache.get(data.message.id); 16 | if (!oldMessage && !this.client.options?.partials?.includes('MESSAGE')) { 17 | return [false, 'Old message not cached!']; 18 | } 19 | const newMessage = 20 | oldMessage?._clone().patch(data.message) ?? 21 | new PartialMessage(this.client, { ...data.message, channelId: data.channelId }); 22 | this.client.emit(events.MESSAGE_UPDATE, oldMessage, newMessage); 23 | } 24 | 25 | return [false, 'passthrough']; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/guilded.js/lib/ws/events/Event.ts: -------------------------------------------------------------------------------- 1 | import type { Client } from '../../structures/Client'; 2 | 3 | export default abstract class Event { 4 | public constructor(public client: Client) {} 5 | public abstract ingest(data: unknown): (boolean | (string | undefined))[]; 6 | public partialEnabled(): boolean { 7 | return !!this.client.options?.partials?.length; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/guilded.js/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/guilded.js", 3 | "version": "2.3.1-selfbot", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@guildedjs/guilded.js", 9 | "version": "2.2.1-selfbot", 10 | "license": "MIT", 11 | "dependencies": { 12 | "@discordjs/collection": "^0.1.6", 13 | "ws": "^7.4.0" 14 | }, 15 | "devDependencies": { 16 | "@types/node": "^14.14.9", 17 | "@types/ws": "^7.4.0", 18 | "typescript": "^4.4.2" 19 | } 20 | }, 21 | "node_modules/@discordjs/collection": { 22 | "version": "0.1.6", 23 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 24 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 25 | }, 26 | "node_modules/@types/node": { 27 | "version": "14.14.16", 28 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.16.tgz", 29 | "integrity": "sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw==", 30 | "dev": true 31 | }, 32 | "node_modules/@types/ws": { 33 | "version": "7.4.0", 34 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz", 35 | "integrity": "sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==", 36 | "dev": true, 37 | "dependencies": { 38 | "@types/node": "*" 39 | } 40 | }, 41 | "node_modules/typescript": { 42 | "version": "4.4.2", 43 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 44 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 45 | "dev": true, 46 | "bin": { 47 | "tsc": "bin/tsc", 48 | "tsserver": "bin/tsserver" 49 | }, 50 | "engines": { 51 | "node": ">=4.2.0" 52 | } 53 | }, 54 | "node_modules/ws": { 55 | "version": "7.4.6", 56 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", 57 | "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", 58 | "engines": { 59 | "node": ">=8.3.0" 60 | }, 61 | "peerDependencies": { 62 | "bufferutil": "^4.0.1", 63 | "utf-8-validate": "^5.0.2" 64 | }, 65 | "peerDependenciesMeta": { 66 | "bufferutil": { 67 | "optional": true 68 | }, 69 | "utf-8-validate": { 70 | "optional": true 71 | } 72 | } 73 | } 74 | }, 75 | "dependencies": { 76 | "@discordjs/collection": { 77 | "version": "0.1.6", 78 | "resolved": "https://registry.npmjs.org/@discordjs/collection/-/collection-0.1.6.tgz", 79 | "integrity": "sha512-utRNxnd9kSS2qhyivo9lMlt5qgAUasH2gb7BEOn6p0efFh24gjGomHzWKMAPn2hEReOPQZCJaRKoURwRotKucQ==" 80 | }, 81 | "@types/node": { 82 | "version": "14.14.16", 83 | "resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.16.tgz", 84 | "integrity": "sha512-naXYePhweTi+BMv11TgioE2/FXU4fSl29HAH1ffxVciNsH3rYXjNP2yM8wqmSm7jS20gM8TIklKiTen+1iVncw==", 85 | "dev": true 86 | }, 87 | "@types/ws": { 88 | "version": "7.4.0", 89 | "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz", 90 | "integrity": "sha512-Y29uQ3Uy+58bZrFLhX36hcI3Np37nqWE7ky5tjiDoy1GDZnIwVxS0CgF+s+1bXMzjKBFy+fqaRfb708iNzdinw==", 91 | "dev": true, 92 | "requires": { 93 | "@types/node": "*" 94 | } 95 | }, 96 | "typescript": { 97 | "version": "4.4.2", 98 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz", 99 | "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==", 100 | "dev": true 101 | }, 102 | "ws": { 103 | "version": "7.4.6", 104 | "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", 105 | "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", 106 | "requires": {} 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /packages/guilded.js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/guilded.js", 3 | "version": "2.3.1-selfbot", 4 | "description": "A Node.js library for the Guilded.gg (https://www.guilded.gg/) API written in TypeScript, usable in either JavaScript or TypeScript projects.", 5 | "types": "types/index.d.ts", 6 | "main": "dist/index.js", 7 | "author": "zaid450 ", 8 | "homepage": "https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/guilded.js#readme", 9 | "license": "MIT", 10 | "scripts": { 11 | "test": "cd ../../ && npm run build && cd packages/guilded.js && node ./__tests__/index.js", 12 | "test:local": "npm run build && cd __tests__ && node index.js", 13 | "build": "tsc", 14 | "prepublishOnly": "npx rimraf dist/ && npx rimraf types/ && npm run build" 15 | }, 16 | "devDependencies": { 17 | "@guildedjs/guilded-api-typings": "^1.4.1-selfbot", 18 | "@types/node": "^14.14.9", 19 | "@types/ws": "^7.4.0", 20 | "typescript": "^4.4.2" 21 | }, 22 | "dependencies": { 23 | "@discordjs/collection": "^0.1.6", 24 | "@guildedjs/common": "^1.0.5-selfbot", 25 | "@guildedjs/embeds": "^1.0.5-selfbot", 26 | "@guildedjs/rest": "^1.0.6-selfbot", 27 | "@guildedjs/webhook-client": "^1.0.6-selfbot", 28 | "ws": "^7.4.0" 29 | }, 30 | "files": [ 31 | "dist", 32 | "types" 33 | ], 34 | "keywords": [ 35 | "guildedjs", 36 | "guilded.js", 37 | "guilded.gg", 38 | "guilded-api", 39 | "guilded" 40 | ], 41 | "directories": { 42 | "lib": "lib", 43 | "test": "__tests__" 44 | }, 45 | "repository": { 46 | "type": "git", 47 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 51 | }, 52 | "gitHead": "0719b880becce0aa4bccaf5eb5b210ecb08b0547" 53 | } 54 | -------------------------------------------------------------------------------- /packages/guilded.js/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "declarationDir": "./types" 6 | }, 7 | "include": [ "./lib/**/*.ts" ], 8 | "exclude": [ "*.test.ts"] 9 | } -------------------------------------------------------------------------------- /packages/rest/README.md: -------------------------------------------------------------------------------- 1 | # `@guildedjs/rest` 2 | 3 | [![GitHub](https://img.shields.io/github/license/zaida04/guilded.js-selfbot)](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 4 | [![npm](https://img.shields.io/npm/v/@guildedjs/rest?color=crimson&logo=npm)](https://www.npmjs.com/package/@guildedjs/rest) 5 | [![CI workflows](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml/badge.svg)](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml) 6 | 7 | Rest utility for [`@guildedjs/guilded.js`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/guilded.js) and [`@guildedjs/webhook-client`](https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/webhook-client). 8 | 9 | > ⚠️ If you intend to use `@guildedjs/guilded.js` you won't need to install this, as it's already a dependency of that package. 10 | 11 | ## Installation 12 | 13 | You can install this package from [NPM](https://www.npmjs.com/package/@guildedjs/rest) 14 | 15 | - `npm install @guildedjs/rest` 16 | - `yarn add @guildedjs/rest` 17 | 18 | ## Contributing 19 | 20 | Please see the main [README.md](https://github.com/zaida04/guilded.js-selfbot) for info on how to contribute to this package or the other `@guildedjs` packages. 21 | 22 | ## LICENSE 23 | 24 | Licensed under the [MIT License](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 25 | -------------------------------------------------------------------------------- /packages/rest/lib/GuildedAPIError.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | 3 | export class GuildedAPIError extends Error { 4 | public constructor(msg: string, method: string, path: string, code: number | string) { 5 | super(`[GuildedAPIError:${code}:${method.toUpperCase()}] ${path} - ${msg}`); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/rest/lib/RestManager.ts: -------------------------------------------------------------------------------- 1 | /* istanbul ignore file */ 2 | 3 | import fetch, { Response } from 'node-fetch'; 4 | 5 | import { GuildedAPIError } from './GuildedAPIError'; 6 | 7 | export class RestManager { 8 | public apiURL: string; 9 | public token?: string; 10 | public cookieJar?: string; 11 | public guildedMID?: string; 12 | 13 | public constructor(public config?: RestManagerOptions) { 14 | this.apiURL = `https://${config?.apiURL ?? 'www.guilded.gg/api'}`; 15 | } 16 | 17 | public async make( 18 | data: MakeOptions, 19 | authenticated = true, 20 | retryCount = 0, 21 | ): Promise<[Response, Promise]> { 22 | const headers: HeadersInit = {}; 23 | if (authenticated) headers.cookie = `hmac_signed_session=${this.token};`; 24 | const requestOptions = { 25 | body: data.body ? JSON.stringify(data.body) : undefined, 26 | headers: { 27 | 'content-type': 'application/json', 28 | ...headers, 29 | }, 30 | method: data.method, 31 | }; 32 | 33 | let request; 34 | try { 35 | request = await fetch(this.apiURL + data.path, requestOptions); 36 | } catch (e: any) { 37 | throw new Error(`Error while making API call, ${e.message.toString()}`); 38 | } 39 | 40 | if (!request.ok) { 41 | if (request.status === 429) { 42 | if (retryCount >= (this.config?.maxRatelimitRetryLimit ?? 3)) { 43 | throw new Error('MAX REQUEST RATELIMIT RETRY LIMIT REACHED.'); 44 | } 45 | await sleep(this.config?.restOffset ?? 3500); 46 | return this.make(data, authenticated, retryCount++); 47 | } 48 | 49 | const parsedRequest = await request.json().catch(() => ({ message: 'Cannot parse JSON Error Response.' })); 50 | throw new GuildedAPIError(parsedRequest.message, data.method, data.path, request.status); 51 | } 52 | 53 | return [request, request.json().catch(() => ({})) as Promise]; 54 | } 55 | 56 | public get(path: string, authenticated = true): Promise { 57 | return this.make( 58 | { 59 | method: 'GET', 60 | path, 61 | }, 62 | authenticated, 63 | ).then(x => x[1]); 64 | } 65 | 66 | public post(path: string, body?: B, authenticated = true): Promise { 67 | return this.make( 68 | { 69 | body, 70 | method: 'POST', 71 | path, 72 | }, 73 | authenticated, 74 | ).then(x => x[1]); 75 | } 76 | 77 | public delete(path: string, body?: B, authenticated = true): Promise { 78 | return this.make( 79 | { 80 | body, 81 | method: 'DELETE', 82 | path, 83 | }, 84 | authenticated, 85 | ).then(x => x[1]); 86 | } 87 | 88 | public patch(path: string, body: B, authenticated = true): Promise { 89 | return this.make( 90 | { 91 | body, 92 | method: 'PATCH', 93 | path, 94 | }, 95 | authenticated, 96 | ).then(x => x[1]); 97 | } 98 | 99 | public put(path: string, body?: B, authenticated = true): Promise { 100 | return this.make( 101 | { 102 | body, 103 | method: 'PUT', 104 | path, 105 | }, 106 | authenticated, 107 | ).then(x => x[1]); 108 | } 109 | 110 | public setAuth(cookieJar: string): void { 111 | this.cookieJar = cookieJar; 112 | const setCookies = cookieJar.split(' '); 113 | this.token = extractFromCookieJar(setCookies, 0); 114 | this.guildedMID = extractFromCookieJar(setCookies, 11); 115 | } 116 | 117 | public destroy(): void { 118 | this.cookieJar = undefined; 119 | this.token = undefined; 120 | } 121 | } 122 | 123 | export interface RestManagerOptions { 124 | apiURL?: string; 125 | restOffset?: number; 126 | maxRatelimitRetryLimit?: number; 127 | } 128 | export interface MakeOptions { 129 | method: string; 130 | path: string; 131 | body?: Record; 132 | } 133 | export type JSONB = Record; 134 | export type RequestBodyObject = JSONB | undefined; 135 | export interface LoginData { 136 | email: string; 137 | password: string; 138 | } 139 | 140 | const extractFromCookieJar = (decodedCookieJar: string[], i: number) => decodedCookieJar[i].split('=')[1].split(';')[0]; 141 | const sleep = (ms: number): Promise => new Promise(r => setTimeout(r, ms)); 142 | -------------------------------------------------------------------------------- /packages/rest/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './GuildedAPIError'; 2 | export * from './RestManager'; 3 | -------------------------------------------------------------------------------- /packages/rest/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/rest", 3 | "version": "1.0.6-selfbot", 4 | "description": "Rest structure for @guildedjs/guilded.js", 5 | "author": "Zaid \"Nico\" ", 6 | "license": "MIT", 7 | "main": "dist/index.js", 8 | "types": "types/index.d.ts", 9 | "scripts": { 10 | "test": "npm run build && node ./__tests__/index.js", 11 | "build": "tsc", 12 | "prepublishOnly": "npx rimraf dist/ && npx rimraf types/ && npm run build" 13 | }, 14 | "devDependencies": { 15 | "@types/node": "^14.14.9", 16 | "@types/node-fetch": "^2.5.8", 17 | "typescript": "^4.4.2" 18 | }, 19 | "dependencies": { 20 | "node-fetch": "^2.6.1" 21 | }, 22 | "homepage": "https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/rest#readme", 23 | "files": [ 24 | "dist", 25 | "types" 26 | ], 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/guildedjs/guilded.js.git" 30 | }, 31 | "bugs": { 32 | "url": "https://github.com/guildedjs/guilded.js/issues" 33 | }, 34 | "gitHead": "0719b880becce0aa4bccaf5eb5b210ecb08b0547" 35 | } 36 | -------------------------------------------------------------------------------- /packages/rest/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "declarationDir": "./types" 6 | }, 7 | "include": [ "./lib/**/*.ts" ], 8 | "exclude": [ "*.test.ts"] 9 | } -------------------------------------------------------------------------------- /packages/webhook-client/README.md: -------------------------------------------------------------------------------- 1 | # `@guildedjs/webhook-client` 2 | 3 | [![GitHub](https://img.shields.io/github/license/zaida04/guilded.js-selfbot)](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 4 | [![npm](https://img.shields.io/npm/v/@guildedjs/webhook-client?color=crimson&logo=npm)](https://www.npmjs.com/package/@guildedjs/webhook-client) 5 | [![CI workflows](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml/badge.svg)](https://github.com/zaida04/guilded.js-selfbot/actions/workflows/ci.yml) 6 | 7 | Library-agnostic webhook client and utility 8 | 9 | > ⚠️ If you intend to use `@guildedjs/guilded.js` you won't need to install this, as it's already a dependency of that package. 10 | 11 | ## Installation 12 | 13 | You can install this package from [NPM](https://www.npmjs.com/package/@guildedjs/webhook-client) 14 | 15 | - `npm install @guildedjs/webhook-client` 16 | - `yarn add @guildedjs/webhook-client` 17 | 18 | ## Contributing 19 | 20 | Please see the main [README.md](https://github.com/zaida04/guilded.js-selfbot) for info on how to contribute to this package or the other `@guildedjs` packages. 21 | 22 | ## LICENSE 23 | 24 | Licensed under the [MIT License](https://github.com/zaida04/guilded.js-selfbot/blob/main/LICENSE) 25 | -------------------------------------------------------------------------------- /packages/webhook-client/__tests__/Webhook.test.ts: -------------------------------------------------------------------------------- 1 | import { WebhookClient } from '..'; 2 | const id = 'THISISARANDOMID'; 3 | const token = 'THISISARANDOMTOKEN'; 4 | const url = `https://media.guilded.gg/webhooks/${id}/${token}`; 5 | 6 | test('Pass URL as connection string', () => { 7 | const webhook = new WebhookClient(url); 8 | expect(webhook.id).toStrictEqual(id); 9 | expect(webhook.token).toStrictEqual(token); 10 | expect(webhook.URL).toStrictEqual(url); 11 | }); 12 | 13 | test('Pass id and token as connection string', () => { 14 | const webhook = new WebhookClient({ id, token }); 15 | expect(webhook.id).toStrictEqual(id); 16 | expect(webhook.token).toStrictEqual(token); 17 | expect(webhook.URL).toStrictEqual(url); 18 | }); 19 | 20 | test('Get error when passing bad url', () => { 21 | expect(() => new WebhookClient('thisisnotagoodurl')).toThrow( 22 | new Error('Not a proper guilded webhook URL! Alternatively, you can provide an ID/token'), 23 | ); 24 | }); 25 | 26 | test('Get error when not passing anything in constructor', () => { 27 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 28 | // @ts-expect-error 29 | expect(() => new WebhookClient()).toThrow( 30 | new Error('Must provide Webhook connection info in either string or object. Received undefined.'), 31 | ); 32 | }); 33 | 34 | test('Pass only partial constructable info', () => { 35 | // eslint-disable-next-line @typescript-eslint/ban-ts-comment 36 | // @ts-expect-error 37 | expect(() => new WebhookClient({ id: 'aiuhdfius' })).toThrow( 38 | new Error( 39 | 'You must provide either a webhook URL or a webhook ID & token in an object when constructing the Webhook Client', 40 | ), 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /packages/webhook-client/lib/Webhook.ts: -------------------------------------------------------------------------------- 1 | import { parsedMessage, parseMessage, ROUTES } from '@guildedjs/common'; 2 | import Embed from '@guildedjs/embeds'; 3 | import { APIContent, APIPostWebhookResult } from '@guildedjs/guilded-api-typings'; 4 | import { RestManager } from '@guildedjs/rest'; 5 | 6 | export class WebhookClient { 7 | private api = new RestManager({ apiURL: ROUTES.MEDIA_DOMAIN }); 8 | public URL: string; 9 | public id: string; 10 | public token: string; 11 | 12 | public constructor(webhookConnection: string | { id: string; token: string }) { 13 | if (!webhookConnection) { 14 | throw new TypeError( 15 | `Must provide Webhook connection info in either string or object. Received ${webhookConnection}.`, 16 | ); 17 | } 18 | if (typeof webhookConnection === 'string') { 19 | const destructuredWebhookURL = webhookConnection.match(/guilded.gg\/webhooks\/([^/]+)\/([^/]+)/); 20 | if (!destructuredWebhookURL?.length) { 21 | throw new Error('Not a proper guilded webhook URL! Alternatively, you can provide an ID/token'); 22 | } 23 | this.id = destructuredWebhookURL[1]; 24 | this.token = destructuredWebhookURL[2]; 25 | } else if (webhookConnection.id && webhookConnection.token) { 26 | this.id = webhookConnection.id; 27 | this.token = webhookConnection.token; 28 | } else { 29 | throw new TypeError( 30 | 'You must provide either a webhook URL or a webhook ID & token in an object when constructing the Webhook Client', 31 | ); 32 | } 33 | this.URL = `https://${ROUTES.MEDIA_DOMAIN}/webhooks/${this.id}/${this.token}`; 34 | } 35 | 36 | /* istanbul ignore next */ 37 | public send(content: string, embeds?: Embed[]): Promise { 38 | return this.api 39 | .post(`/webhooks/${this.id}/${this.token}`, { 40 | content, 41 | embeds, 42 | }) 43 | .then(data => { 44 | const parsedContent = parseMessage(data.content); 45 | return { 46 | ...data, 47 | content: parsedContent.parsedText, 48 | parsedContent, 49 | rawContent: data.content, 50 | } as WebhookExecuteResponse; 51 | }); 52 | } 53 | } 54 | 55 | export interface WebhookExecuteResponse extends Omit { 56 | content: string; 57 | parsedContent: parsedMessage; 58 | rawContent: APIContent; 59 | } 60 | 61 | export default WebhookClient; 62 | -------------------------------------------------------------------------------- /packages/webhook-client/lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './Webhook'; 2 | export * from '@guildedjs/common'; 3 | -------------------------------------------------------------------------------- /packages/webhook-client/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/webhook-client", 3 | "version": "1.0.6-selfbot", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "@guildedjs/webhook-client", 9 | "version": "1.0.4-selfbot", 10 | "license": "MIT", 11 | "dependencies": { 12 | "node-fetch": "^2.6.1" 13 | }, 14 | "devDependencies": { 15 | "@types/node-fetch": "^2.5.10" 16 | } 17 | }, 18 | "node_modules/@types/node": { 19 | "version": "15.12.2", 20 | "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", 21 | "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", 22 | "dev": true 23 | }, 24 | "node_modules/@types/node-fetch": { 25 | "version": "2.5.10", 26 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz", 27 | "integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==", 28 | "dev": true, 29 | "dependencies": { 30 | "@types/node": "*", 31 | "form-data": "^3.0.0" 32 | } 33 | }, 34 | "node_modules/asynckit": { 35 | "version": "0.4.0", 36 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 37 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 38 | "dev": true 39 | }, 40 | "node_modules/combined-stream": { 41 | "version": "1.0.8", 42 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 43 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 44 | "dev": true, 45 | "dependencies": { 46 | "delayed-stream": "~1.0.0" 47 | }, 48 | "engines": { 49 | "node": ">= 0.8" 50 | } 51 | }, 52 | "node_modules/delayed-stream": { 53 | "version": "1.0.0", 54 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 55 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 56 | "dev": true, 57 | "engines": { 58 | "node": ">=0.4.0" 59 | } 60 | }, 61 | "node_modules/form-data": { 62 | "version": "3.0.1", 63 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", 64 | "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", 65 | "dev": true, 66 | "dependencies": { 67 | "asynckit": "^0.4.0", 68 | "combined-stream": "^1.0.8", 69 | "mime-types": "^2.1.12" 70 | }, 71 | "engines": { 72 | "node": ">= 6" 73 | } 74 | }, 75 | "node_modules/mime-db": { 76 | "version": "1.48.0", 77 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", 78 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", 79 | "dev": true, 80 | "engines": { 81 | "node": ">= 0.6" 82 | } 83 | }, 84 | "node_modules/mime-types": { 85 | "version": "2.1.31", 86 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", 87 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", 88 | "dev": true, 89 | "dependencies": { 90 | "mime-db": "1.48.0" 91 | }, 92 | "engines": { 93 | "node": ">= 0.6" 94 | } 95 | }, 96 | "node_modules/node-fetch": { 97 | "version": "2.6.1", 98 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 99 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", 100 | "engines": { 101 | "node": "4.x || >=6.0.0" 102 | } 103 | } 104 | }, 105 | "dependencies": { 106 | "@types/node": { 107 | "version": "15.12.2", 108 | "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.2.tgz", 109 | "integrity": "sha512-zjQ69G564OCIWIOHSXyQEEDpdpGl+G348RAKY0XXy9Z5kU9Vzv1GMNnkar/ZJ8dzXB3COzD9Mo9NtRZ4xfgUww==", 110 | "dev": true 111 | }, 112 | "@types/node-fetch": { 113 | "version": "2.5.10", 114 | "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.5.10.tgz", 115 | "integrity": "sha512-IpkX0AasN44hgEad0gEF/V6EgR5n69VEqPEgnmoM8GsIGro3PowbWs4tR6IhxUTyPLpOn+fiGG6nrQhcmoCuIQ==", 116 | "dev": true, 117 | "requires": { 118 | "@types/node": "*", 119 | "form-data": "^3.0.0" 120 | } 121 | }, 122 | "asynckit": { 123 | "version": "0.4.0", 124 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 125 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", 126 | "dev": true 127 | }, 128 | "combined-stream": { 129 | "version": "1.0.8", 130 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", 131 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", 132 | "dev": true, 133 | "requires": { 134 | "delayed-stream": "~1.0.0" 135 | } 136 | }, 137 | "delayed-stream": { 138 | "version": "1.0.0", 139 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 140 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", 141 | "dev": true 142 | }, 143 | "form-data": { 144 | "version": "3.0.1", 145 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", 146 | "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", 147 | "dev": true, 148 | "requires": { 149 | "asynckit": "^0.4.0", 150 | "combined-stream": "^1.0.8", 151 | "mime-types": "^2.1.12" 152 | } 153 | }, 154 | "mime-db": { 155 | "version": "1.48.0", 156 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", 157 | "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", 158 | "dev": true 159 | }, 160 | "mime-types": { 161 | "version": "2.1.31", 162 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", 163 | "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", 164 | "dev": true, 165 | "requires": { 166 | "mime-db": "1.48.0" 167 | } 168 | }, 169 | "node-fetch": { 170 | "version": "2.6.1", 171 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", 172 | "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==" 173 | } 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /packages/webhook-client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@guildedjs/webhook-client", 3 | "version": "1.0.6-selfbot", 4 | "description": "Library-agnostic webhook client for the guilded.gg API", 5 | "author": "Zaid \"Nico\" ", 6 | "homepage": "https://github.com/zaida04/guilded.js-selfbot/tree/main/packages/webhook-client#readme", 7 | "license": "MIT", 8 | "types": "types/index.d.ts", 9 | "main": "dist/index.js", 10 | "scripts": { 11 | "build": "tsc", 12 | "test": "npm run build && npx jest", 13 | "prepublishOnly": "npx rimraf dist/ && npx rimraf types/ && npm run build" 14 | }, 15 | "devDependencies": { 16 | "@guildedjs/guilded-api-typings": "^1.4.1-selfbot", 17 | "@types/node-fetch": "^2.5.10" 18 | }, 19 | "dependencies": { 20 | "@guildedjs/common": "^1.0.5-selfbot", 21 | "@guildedjs/embeds": "^1.0.5-selfbot", 22 | "@guildedjs/rest": "^1.0.6-selfbot", 23 | "node-fetch": "^2.6.1" 24 | }, 25 | "keywords": [ 26 | "guilded-gg", 27 | "guilded-api", 28 | "guilded-webhook" 29 | ], 30 | "directories": { 31 | "lib": "lib", 32 | "test": "__tests__" 33 | }, 34 | "files": [ 35 | "dist", 36 | "types" 37 | ], 38 | "publishConfig": { 39 | "access": "public" 40 | }, 41 | "repository": { 42 | "type": "git", 43 | "url": "git+https://github.com/zaida04/guilded.js-selfbot.git" 44 | }, 45 | "bugs": { 46 | "url": "https://github.com/zaida04/guilded.js-selfbot/issues" 47 | }, 48 | "gitHead": "0719b880becce0aa4bccaf5eb5b210ecb08b0547" 49 | } 50 | -------------------------------------------------------------------------------- /packages/webhook-client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "outDir": "./dist", 5 | "declarationDir": "./types" 6 | }, 7 | "include": [ "./lib/**/*.ts" ], 8 | "exclude": [ "*.test.ts"] 9 | } -------------------------------------------------------------------------------- /prettier.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | endOfLine: 'auto', 3 | printWidth: 150, 4 | semi: true, 5 | tabWidth: 4, 6 | trailingComma: 'all', 7 | }; 8 | -------------------------------------------------------------------------------- /scripts/jest.js: -------------------------------------------------------------------------------- 1 | const { access } = require('fs/promises'); 2 | const { join } = require('path'); 3 | const ENV_PATH = join(__dirname, '..', '.env'); 4 | 5 | (async () => { 6 | if (process.env.CI) return; 7 | try { 8 | await access(ENV_PATH); 9 | } catch (e) { 10 | throw new Error( 11 | 'An .env file is required at the root of this project to run tests. Please make sure it exists and is readable.', 12 | ); 13 | } 14 | })(); 15 | -------------------------------------------------------------------------------- /scripts/post-docs.js: -------------------------------------------------------------------------------- 1 | const { writeFile } = require('fs/promises'); 2 | const { join } = require('path'); 3 | 4 | (async () => { 5 | await writeFile(join(__dirname, '..', 'docs', 'CNAME'), 'zaida04.github.io/guildedjs-selfbot-docs'); 6 | console.log('CREATED CNAME'); 7 | })(); 8 | -------------------------------------------------------------------------------- /scripts/refresh.js: -------------------------------------------------------------------------------- 1 | require('./reset'); 2 | require('./setup'); 3 | -------------------------------------------------------------------------------- /scripts/reset.js: -------------------------------------------------------------------------------- 1 | const rimraf = require('rimraf'); 2 | const { join } = require('path'); 3 | const BASE_DIR = join(__dirname, '..'); 4 | const packages = ['common', 'embeds', 'guilded-api-typings', 'guilded.js', 'webhook-client', 'rest']; 5 | const subDirs = ['node_modules', 'dist', 'types']; 6 | 7 | rimraf.sync(join(BASE_DIR, 'node_modules')); 8 | console.log('Deleting root node_modules'); 9 | packages.forEach(package => { 10 | subDirs.forEach(dir => { 11 | rimraf.sync(join(BASE_DIR, 'packages', package, dir)); 12 | console.log(`Deleting package ${package} ${dir}`); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /scripts/setup.js: -------------------------------------------------------------------------------- 1 | const { execSync } = require('child_process'); 2 | const { join } = require('path'); 3 | 4 | const commands = ['npm i', 'npm run bootstrap', 'npm run build']; 5 | commands.forEach(command => execSync(command, { cwd: join(__dirname, '..') })); 6 | -------------------------------------------------------------------------------- /static/guilded-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zaida04/g.js-self/98d0b3736a11f6b7c543d0f363f7c68afe1846ca/static/guilded-icon.png -------------------------------------------------------------------------------- /static/itami-transparent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zaida04/g.js-self/98d0b3736a11f6b7c543d0f363f7c68afe1846ca/static/itami-transparent.png -------------------------------------------------------------------------------- /static/readme-header.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zaida04/g.js-self/98d0b3736a11f6b7c543d0f363f7c68afe1846ca/static/readme-header.png -------------------------------------------------------------------------------- /testing.env.example: -------------------------------------------------------------------------------- 1 | EMAIL= 2 | PASSWORD= 3 | ROLE_ID= 4 | TEAM_ID= 5 | GUINEAPIG_ID= 6 | CHANNEL_ID= 7 | GROUP_ID= 8 | WEBHOOK_URL= -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "alwaysStrict": true, 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "declarationMap": true, 8 | "pretty": true, 9 | "module": "CommonJS", 10 | "target": "ES6", 11 | "lib": [ 12 | "ESNext", 13 | "DOM" 14 | ], 15 | "typeRoots": [ 16 | "node_modules/@types" 17 | ], 18 | "types": [ 19 | "node", 20 | "jest" 21 | ], 22 | "sourceMap": true, 23 | "incremental": true, 24 | "esModuleInterop": true, 25 | "skipLibCheck": true, 26 | "allowSyntheticDefaultImports": true, 27 | "resolveJsonModule": true 28 | }, 29 | "exclude": [ 30 | "dist/**" 31 | ] 32 | } -------------------------------------------------------------------------------- /typedoc.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | exclude: ['**/node_modules/**', '**/dist/**', '**/types/**', '**/@types/**'], 3 | excludeExternals: true, 4 | excludeNotExported: true, 5 | 'external-modulemap': '.*packages/([^/]+)/.*', 6 | ignoreCompilerErrors: true, 7 | media: 'media', 8 | mode: 'modules', 9 | name: 'Guilded.JS', 10 | out: 'docs', 11 | preserveConstEnums: true, 12 | readme: 'README.md', 13 | stripInternal: true, 14 | theme: 'minimal', 15 | tsconfig: 'tsconfig.base.json', 16 | }; 17 | --------------------------------------------------------------------------------