refactor!: rewrite

🎉🎉
This commit is contained in:
Jozef Steinhübl 2023-04-09 15:48:51 +02:00 committed by GitHub
commit 7c63c373c1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
143 changed files with 14424 additions and 11554 deletions

View file

@ -1,4 +0,0 @@
dist/
tests/
packages/website/
webpack.config.js

View file

@ -1,33 +0,0 @@
{
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 12
},
"plugins": [
"@typescript-eslint"
],
"rules": {
"indent": [
"error",
"tab"
],
"linebreak-style": [
"error",
"unix"
],
"quotes": [
"error",
"single"
],
"semi": [
"error",
"always"
],
"prefer-const": "error",
"@typescript-eslint/no-explicit-any": "off"
}
}

View file

@ -1,32 +0,0 @@
const fs = require('fs');
const hyttpo = require('hyttpo').default;
const list = fs.readFileSync('./list.txt', 'utf-8').split('\n');
let now = Number(fs.readFileSync('./now.txt', 'utf-8'));
(async() => {
if (now === list.length) now = 0;
const url = list[now + 1];
const req = await hyttpo.request({
method: 'GET',
responseType: 'buffer',
url
}).catch(e => e)
const base64 = `data:image/png;base64,${req.data.toString('base64')}`;
const bot = await hyttpo.request({
url: 'https://discord.com/api/v9/applications/745599648110215260',
method: 'PATCH',
headers: {
'Authorization': 'Bot'
},
body: JSON.stringify({
icon: base64
})
}).catch(e => e)
console.log(bot)
})();

View file

@ -1,6 +0,0 @@
https://izboxo.cz/sources/images/Bucket_of_Cod_JE2_BE2.png
https://izboxo.cz/sources/images/Bucket_of_Axolotl_JE1_BE1.png
https://izboxo.cz/sources/images/Bucket_of_Pufferfish_JE2_BE2.png
https://izboxo.cz/sources/images/Bucket_of_Salmon_JE2_BE2.png
https://izboxo.cz/sources/images/Bucket_of_Tadpole_BE1.png
https://izboxo.cz/sources/images/Bucket_of_Tropical_Fish_JE3_BE2.png

View file

@ -1 +0,0 @@
0

Binary file not shown.

Before

Width:  |  Height:  |  Size: 966 B

View file

@ -1,61 +0,0 @@
{
"name": "avatar-changer",
"version": "1.0.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "avatar-changer",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"hyttpo": "^0.3.2"
}
},
"node_modules/follow-redirects": {
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/hyttpo": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/hyttpo/-/hyttpo-0.3.2.tgz",
"integrity": "sha512-Y1QJlBXOZtHKhME6AEBdxPrzJrV5xcORZm/+rbHwXGlau2n2OBNAbsiIJ3eiT1ZizJClm+RmwjytDSySOXJcOg==",
"dependencies": {
"follow-redirects": "^1.14.6"
},
"engines": {
"node": ">=16.x"
}
}
},
"dependencies": {
"follow-redirects": {
"version": "1.14.6",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz",
"integrity": "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A=="
},
"hyttpo": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/hyttpo/-/hyttpo-0.3.2.tgz",
"integrity": "sha512-Y1QJlBXOZtHKhME6AEBdxPrzJrV5xcORZm/+rbHwXGlau2n2OBNAbsiIJ3eiT1ZizJClm+RmwjytDSySOXJcOg==",
"requires": {
"follow-redirects": "^1.14.6"
}
}
}
}

View file

@ -1,15 +0,0 @@
{
"name": "avatar-changer",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"hyttpo": "^0.3.2"
}
}

View file

@ -1,30 +0,0 @@
name: Pages Deployment
on:
push:
branches: [master]
jobs:
website:
name: Website
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- uses: actions/setup-node@v1
with:
node-version: 12
- name: Build
run: |
cd packages/website
npm i
npm run build
npm run export
- name: Deploy site
uses: JamesIves/github-pages-deploy-action@4.1.4
with:
branch: gh-pages
folder: packages/website/out

49
.gitignore vendored
View file

@ -1,9 +1,5 @@
# Created by https://www.toptal.com/developers/gitignore/api/visualstudiocode,node
# Created by https://www.toptal.com/developers/gitignore/api/node # Edit at https://www.toptal.com/developers/gitignore?templates=visualstudiocode,node
# Edit at https://www.toptal.com/developers/gitignore?templates=node
# My
wrangler.toml
### Node ### ### Node ###
# Logs # Logs
@ -62,6 +58,9 @@ web_modules/
# Optional eslint cache # Optional eslint cache
.eslintcache .eslintcache
# Optional stylelint cache
.stylelintcache
# Microbundle cache # Microbundle cache
.rpt2_cache/ .rpt2_cache/
.rts2_cache_cjs/ .rts2_cache_cjs/
@ -77,10 +76,12 @@ web_modules/
# Yarn Integrity file # Yarn Integrity file
.yarn-integrity .yarn-integrity
# dotenv environment variables file # dotenv environment variable files
.env .env
.env.test .env.development.local
.env.production .env.test.local
.env.production.local
.env.local
# parcel-bundler cache (https://parceljs.org/) # parcel-bundler cache (https://parceljs.org/)
.cache .cache
@ -103,6 +104,12 @@ dist
# vuepress build output # vuepress build output
.vuepress/dist .vuepress/dist
# vuepress v2.x temp and cache directory
.temp
# Docusaurus cache and generated files
.docusaurus
# Serverless directories # Serverless directories
.serverless/ .serverless/
@ -130,9 +137,29 @@ dist
.webpack/ .webpack/
# Optional stylelint cache # Optional stylelint cache
.stylelintcache
# SvelteKit build / generate output # SvelteKit build / generate output
.svelte-kit .svelte-kit
# End of https://www.toptal.com/developers/gitignore/api/node ### VisualStudioCode ###
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
### VisualStudioCode Patch ###
# Ignore all local history of files
.history
.ionide
# End of https://www.toptal.com/developers/gitignore/api/visualstudiocode,node
.turbo

17
.vscode/settings.json vendored
View file

@ -1,10 +1,11 @@
{ {
"liveServer.settings.port": 5501, "[typescript]": {
"liveSassCompile.settings.formats": [ "editor.defaultFormatter": "rome.rome"
{ },
"format": "expanded", "[javascript]": {
"extensionName": ".css", "editor.defaultFormatter": "rome.rome"
"savePath": "/packages/website/styles/css" },
} "[astro]": {
] "editor.defaultFormatter": "esbenp.prettier-vscode"
}
} }

113
CONTRIBUTING.md Normal file
View file

@ -0,0 +1,113 @@
## <a name="commit"></a> Commit Message Format
_This specification is inspired by and supersedes the [Brainclements commit message format](https://gist.github.com/brianclements/841ea7bffdb01346392c)._
We have very precise rules over how our Git commit messages must be formatted.
This format leads to **easier to read commit history**.
Each commit message consists of a **header**, a **body**, and a **footer**.
```
<header>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>
```
The `header` is mandatory and must conform to the [Commit Message Header](#commit-header) format.
The `body` is mandatory for all commits except for those of type "docs".
When the body is present it must be at least 20 characters long and must conform to the [Commit Message Body](#commit-body) format.
The `footer` is optional. The [Commit Message Footer](#commit-footer) format describes what the footer is used for and the structure it must have.
#### <a name="commit-header"></a>Commit Message Header
```
<type>(<scope>)(!?): <short summary>
│ │ │ │
│ │ │ └─⫸ Summary in present tense. Not capitalized. No period at the end.
│ │ │
│ │ └─⫸ Exclamation mark: breaking change
│ │
│ └─⫸ Commit Scope: bot|website|serialize|redis-api|redis-api-client|builders
└─⫸ Commit Type: build|ci|docs|feat|fix|perf|refactor|test
```
The `<type>` and `<summary>` fields are mandatory, the `(<scope>)` field is optional.
Exclamation mark is optional too, but it's used to mark breaking changes.
##### Type
Must be one of the following:
- **build**: Changes that affect the build system or external dependencies (example scopes: gulp, broccoli, npm)
- **ci**: Changes to our CI configuration files and scripts (examples: CircleCi, SauceLabs)
- **docs**: Documentation only changes
- **feat**: A new feature
- **fix**: A bug fix
- **perf**: A code change that improves performance
- **refactor**: A code change that neither fixes a bug nor adds a feature
- **test**: Adding missing tests or correcting existing tests
##### Scope
The scope should be the name of the npm package affected (as perceived by the person reading the changelog generated from commit messages).
The following is the list of supported scopes:
- `bot`
- `website`
- `serialize`
- `redis-api`
- `redis-api-client`
- `builders`
There are currently a few exceptions to the "use package name" rule:
- none/empty string: useful for `test` and `refactor` changes that are done across all packages (e.g. `test: add missing unit tests`) and for docs changes that are not related to a specific package (e.g. `docs: fix typo in tutorial`).
##### Summary
Use the summary field to provide a succinct description of the change:
- use the imperative, present tense: "change" not "changed" nor "changes"
- don't capitalize the first letter
- no dot (.) at the end
#### <a name="commit-body"></a>Commit Message Body
Just as in the summary, use the imperative, present tense: "fix" not "fixed" nor "fixes".
Explain the motivation for the change in the commit message body. This commit message should explain _why_ you are making the change.
You can include a comparison of the previous behavior with the new behavior in order to illustrate the impact of the change.
#### <a name="commit-footer"></a>Commit Message Footer
The footer is optional and is used for two purposes:
- To reference issues that this commit closes
- To include information that doesn't fit in the header or body, such as a link to a file or a suggestion to review a pull request
The format for the footer is as follows:
```
Closes/Fixes #<issue number>
```
or
```
See pull request #<pull request number>
```
### Revert commits
If the commit reverts a previous commit, it should begin with `revert: `, followed by the header of the reverted commit.
The content of the commit message body should contain:
- information about the SHA of the commit being reverted in the following format: `This reverts commit <SHA>`,
- a clear description of the reason for reverting the commit message.

View file

@ -1,7 +1,46 @@
<div align="center"> <h1 align="center">
<h1>Discord Roles Bot</h1> <br>
</div> <img src="https://github.com/xHyroM/website/blob/main/src/assets/logo.png?raw=true" alt="Hyro" width="256">
<br>
</h1>
<h4 align="center">Source code for Roles Bot, a discord bot.</h4>
<p align="center">
<a href="https://discord.gg/kFPKmEKeMS/" alt="Discord">
<img src="https://img.shields.io/discord/1046534628577640528?label=discord&style=for-the-badge&color=2fbfc4"/>
</a>
</p>
## Informations
Discord bot for reaction roles that works with [Cloudflare Workers](https://workers.cloudflare.com/). Discord bot for reaction roles that works with [Cloudflare Workers](https://workers.cloudflare.com/).
You can add the bot to your server, just click [here](https://discord.com/api/oauth2/authorize?client_id=923267906941370368&permissions=268435456&scope=bot%20applications.commands). You can add the bot to your server, just click [here](https://discord.com/api/oauth2/authorize?client_id=923267906941370368&permissions=268435456&scope=bot%20applications.commands).
## Setup
1. Clone this repository: `git clone https://github.com/xHyroM/roles-bot.git`
2. Navigate to the project directory: `cd roles-bot`
3. Install the dependencies: `pnpm install`
## Usage
- To run the development server: `pnpm run dev`
- To build the project for production: `pnpm run build`
- To preview the production build of website: `pnpm run preview`
- To deploy bot to CF workers: `pnpm run deploy`
## Contributing
To contribute to this project, please follow the [standard Git workflow](https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository#The-Standard-Git-Workflow) and [CONTRIBUTING](./CONTRIBUTING.md).
1. Fork this repository
2. Create a new branch for your changes: `git checkout -b my-feature`
3. Commit your changes: `git commit -am "Add my feature"`
4. Push the branch: `git push origin my-feature`
5. Open a pull request
## License
This project is licensed under the [MIT License](./LICENSE).

21
apps/redis-api/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Jozef Steinhübl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

2
apps/redis-api/README.md Normal file
View file

@ -0,0 +1,2 @@
For caching user selected options, we use the [Redis](http://redis.io/) key-value store. This package provides a simple API for interacting with Redis.
We need this API because CloudFlare Workers (they doesn't support TCP)

View file

@ -0,0 +1,20 @@
{
"name": "redis-api",
"version": "0.0.1",
"author": "xHyroM",
"main": "dist/index.mjs",
"types": "dist/index.d.ts",
"scripts": {
"build": "node scripts/build.mjs",
"dev": "node scripts/build.mjs --dev && node dist/index.mjs"
},
"devDependencies": {
"esbuild": "^0.15.11",
"typescript": "^4.8.4"
},
"dependencies": {
"dotenv": "^16.0.3",
"fastify": "^4.15.0",
"ioredis": "^5.3.1"
}
}

View file

@ -0,0 +1,49 @@
import esbuild from "esbuild";
import { rmSync, existsSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
if (existsSync(join(__dirname, "..", "dist")))
rmSync(join(__dirname, "..", "dist"), { recursive: true });
const watch = process.argv.includes("--watch");
const dev = process.argv.includes("--dev");
Promise.all([
esbuild.build({
bundle: true,
logLevel: "info",
format: "esm",
platform: "node",
target: "es2020",
entryPoints: ["./src/index.ts"],
outfile: "./dist/index.mjs",
sourcemap: dev,
charset: "utf8",
minify: !dev,
watch: watch,
plugins: [
{
name: "make-all-packages-external",
setup(build) {
const filter = /^[^.\/]|^\.[^.\/]|^\.\.[^\/]/; // Must not start with "/" or "./" or "../"
build.onResolve({ filter }, (args) => ({
path: args.path,
external: true,
}));
},
},
],
}),
])
.catch((err) => {
console.error("Redis api failed to build");
console.error(err.message);
})
.then(() => {
console.log(
watch ? "Waiting for your changes..." : "Redis api has been built",
);
});

View file

@ -0,0 +1,45 @@
import "dotenv/config";
import redis from "./redis";
import Fastify from "fastify";
const fastify = Fastify();
fastify.addHook("preHandler", async (request, reply) => {
const Authorization = request.headers.authorization?.replace("Bearer ", "");
if (Authorization !== process.env.API_KEY)
reply.status(401).send("Unauthorized");
});
fastify.post("/set", async (request, reply) => {
const { key, value } = request.body as { key: string; value: string };
reply.send(await redis.set(key, value));
});
fastify.post("/setex", async (request, reply) => {
const { key, value, seconds } = request.body as {
key: string;
value: string;
seconds: number;
};
reply.send(await redis.setex(key, seconds, value));
});
fastify.get("/get", async (request, reply) => {
const { key } = request.query as { key: string };
reply.send(await redis.get(key));
});
fastify.delete("/del", async (request, reply) => {
const { key } = (request.body || request.query) as { key: string };
reply.send(await redis.del(key));
});
fastify.post("/flush", async (request, reply) => {
reply.send(await redis.flushdb());
});
fastify.listen({ port: 51253 }, console.log);

View file

@ -0,0 +1,11 @@
import Redis from "ioredis";
const redis = new Redis(
// rome-ignore lint/style/noNonNullAssertion: env vars are always defined
parseInt(process.env.REDIS_PORT!),
process.env.REDIS_HOST as string,
{
password: process.env.REDIS_PASSWORD,
},
);
export default redis;

View file

@ -0,0 +1,4 @@
REDIS_PORT=
REDIS_HOST=
REDIS_PASSWORD=
API_KEY=

View file

@ -0,0 +1,15 @@
{
"compilerOptions": {
"rootDir": "src",
"outDir": "dist",
"target": "ESNext",
"lib": ["ESNext"],
"module": "ESNext",
"strict": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"declaration": true,
"emitDeclarationOnly": true
}
}

21
apps/website/.gitignore vendored Normal file
View file

@ -0,0 +1,21 @@
# build output
dist/
# generated types
.astro/
# dependencies
node_modules/
# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
# environment variables
.env
.env.production
# macOS-specific files
.DS_Store

View file

@ -0,0 +1 @@
dist/*

View file

@ -0,0 +1,14 @@
module.exports = {
plugins: [
require.resolve("prettier-plugin-astro"),
require.resolve("prettier-plugin-tailwindcss"),
],
overrides: [
{
files: "*.astro",
options: {
parser: "astro",
},
},
],
};

55
apps/website/README.md Normal file
View file

@ -0,0 +1,55 @@
# Astro Starter Kit: Basics
```
npm create astro@latest -- --template basics
```
[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics)
[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics)
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json)
> 🧑‍🚀 **Seasoned astronaut?** Delete this file. Have fun!
![basics](https://user-images.githubusercontent.com/4677417/186188965-73453154-fdec-4d6b-9c34-cb35c248ae5b.png)
## 🚀 Project Structure
Inside of your Astro project, you'll see the following folders and files:
```
/
├── public/
│ └── favicon.svg
├── src/
│ ├── components/
│ │ └── Card.astro
│ ├── layouts/
│ │ └── Layout.astro
│ └── pages/
│ └── index.astro
└── package.json
```
Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name.
There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components.
Any static assets, like images, can be placed in the `public/` directory.
## 🧞 Commands
All commands are run from the root of the project, from a terminal:
| Command | Action |
| :--------------------- | :----------------------------------------------- |
| `npm install` | Installs dependencies |
| `npm run dev` | Starts local dev server at `localhost:3000` |
| `npm run build` | Build your production site to `./dist/` |
| `npm run preview` | Preview your build locally, before deploying |
| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` |
| `npm run astro --help` | Get help using the Astro CLI |
## 👀 Want to learn more?
Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat).

View file

@ -0,0 +1,46 @@
import path from "path";
import { fileURLToPath } from "url";
import { defineConfig } from "astro/config";
import sitemap from "@astrojs/sitemap";
import robotsTxt from "astro-robots-txt";
import compress from "astro-compress";
import tailwind from "@astrojs/tailwind";
import { CONFIG } from "./src/config";
const __dirname = path.dirname(fileURLToPath(import.meta.url));
export default defineConfig({
site: CONFIG.origin,
base: "/",
trailingSlash: "always",
output: "static",
integrations: [
sitemap(),
robotsTxt({
policy: [
{
userAgent: "*",
},
],
sitemap: true,
}),
compress({
css: true,
html: true,
img: true,
js: true,
svg: true,
}),
tailwind(),
],
vite: {
resolve: {
alias: {
"~": path.resolve(__dirname, "./src"),
},
},
},
});

31
apps/website/package.json Normal file
View file

@ -0,0 +1,31 @@
{
"name": "website",
"type": "module",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/prefetch": "^0.2.1",
"@astrojs/sitemap": "^1.2.1",
"@astrojs/tailwind": "^3.1.1",
"@tailwindcss/typography": "^0.5.9",
"astro": "^2.1.9",
"astro-compress": "^1.1.35",
"astro-google-fonts-optimizer": "^0.2.2",
"astro-icon": "^0.8.0",
"astro-robots-txt": "^0.4.1",
"tailwindcss": "^3.3.1"
},
"devDependencies": {
"autoprefixer": "^10.4.14",
"cssnano": "^6.0.0",
"postcss": "^8.4.21",
"prettier": "^2.8.7",
"prettier-plugin-astro": "^0.8.0",
"prettier-plugin-tailwindcss": "^0.2.6"
}
}

View file

@ -0,0 +1,17 @@
const tailwindcss = require("tailwindcss");
const autoprefixer = require("autoprefixer");
const cssnano = require("cssnano");
const mode = process.env.NODE_ENV;
const dev = mode === "development";
module.exports = {
plugins: [
tailwindcss,
autoprefixer,
!dev &&
cssnano({
preset: "default",
}),
],
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 200 KiB

View file

@ -0,0 +1,15 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" class="h-6 w-6"
><path
fill="#CCD6DD"
d="M36 22c0 2.209-1.791 4-4 4H4c-2.209 0-4-1.791-4-4V4c0-2.209 1.791-4 4-4h28c2.209 0 4 1.791 4 4v18z"
></path><path fill="#5DADEC" d="M4 4h28v18H4z"></path><path
fill="#CCD6DD"
d="M13 26h10v6H13z"></path><path fill="#9AAAB4" d="M13 26h10v2H13z"
></path><path
fill="#E1E8ED"
d="M36 33c0-1.657-1.343-3-3-3H3c-1.657 0-3 1.343-3 3s1.343 3 3 3h30c1.657 0 3-1.343 3-3z"
></path><path
fill="#F5F8FA"
d="M3 32h2v2H3zm4 0h2v2H7zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2zm4 0h2v2h-2z"
></path></svg
>

After

Width:  |  Height:  |  Size: 650 B

View file

@ -0,0 +1,18 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 36 36" class="h-8 w-8"
><path
fill="#55ACEE"
d="M7 12c0 .552-.448 1-1 1H1c-.552 0-1-.448-1-1s.448-1 1-1h5c.552 0 1 .448 1 1m-2 5c0 .552-.448 1-1 1H1c-.552 0-1-.448-1-1s.448-1 1-1h3c.552 0 1 .448 1 1m-2 5c0 .553-.448 1-1 1H1c-.552 0-1-.447-1-1s.448-1 1-1h1c.552 0 1 .447 1 1"
></path><path
fill="#CCD6DD"
d="M32.301 25c-.626 2.209-2.925 4-5.134 4h-20c-2.209 0-3.492-1.791-2.866-4l3.398-12c.626-2.209 2.924-4 5.133-4h20c2.209 0 3.493 1.791 2.867 4l-3.398 12z"
></path><path
fill="#99AAB5"
d="M17.336 17.636L4.384 26.949c-.034.028-.054.063-.085.091.179.57.518 1.043.992 1.384.035-.023.073-.033.107-.06L18.35 19.05c.501-.391.681-1.023.401-1.414-.281-.391-.913-.391-1.415 0m13.81 9.404c-.015-.028-.016-.063-.034-.09l-7.674-9.314c-.281-.391-.913-.391-1.416 0-.501.391-.68 1.023-.4 1.414l7.676 9.314c.018.026.051.037.072.06.666-.34 1.274-.814 1.776-1.384"
></path><path
fill="#99AAB5"
d="M35.699 13c.626-2.209-.658-4-2.867-4h-20c-2.209 0-4.507 1.791-5.133 4l-.021.074 8.806 8.452c1.631 1.584 3.788 1.475 5.725.371l13.227-7.964.263-.933z"
></path><path
fill="#E1E8ED"
d="M32.832 9h-20c-1.578 0-3.189.921-4.217 2.248l9.217 8.794c.749.719 2.434.729 3.656 0l14.294-8.768C35.516 9.933 34.42 9 32.832 9z"
></path></svg
>

After

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,7 @@
export const CONFIG = {
name: "Roles Bot",
description:
"Ultimate solution for managing reaction roles in your Discord server, and the best part is, it's completely free! No hidden charges or payments like other bots. Try it out today and see for yourself how easy it is to use!",
themeColor: "#fbc11a",
origin: "https://roles-bot.xhyrom.dev",
};

1
apps/website/src/env.d.ts vendored Normal file
View file

@ -0,0 +1 @@
/// <reference types="astro/client" />

View file

@ -0,0 +1,43 @@
---
import { CONFIG } from "~/config";
import { GoogleFontsOptimizer } from "astro-google-fonts-optimizer";
---
<html lang="sk-SK">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<!-- Primary Meta Tags -->
<title>{CONFIG.name}</title>
<meta name="title" content={CONFIG.name} />
<meta name="description" content={CONFIG.name} />
<link rel="icon" href="logo.png" type="image/png" sizes="64x64" />
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website" />
<meta property="og:url" content={CONFIG.origin} />
<meta property="og:site_name" content={CONFIG.name} />
<meta property="og:title" content={CONFIG.name} />
<meta property="og:description" content={CONFIG.description} />
<!-- <meta property="og:image" content={image} /> -->
<!-- <meta property="og:image:alt" content={imageAlt} /> -->
<!-- Twitter -->
<meta property="twitter:card" content="summary_large_image" />
<meta property="twitter:url" content={CONFIG.origin} />
<meta property="twitter:title" content={CONFIG.name} />
<meta property="twitter:description" content={CONFIG.description} />
<!--<meta property="twitter:image" content={image} /> -->
<!-- <meta name="twitter:image:alt" content={imageAlt} /> -->
<meta name="theme-color" content={CONFIG.themeColor} />
<GoogleFontsOptimizer
url="https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,100;0,200;0,400;0,500;0,600;0,700;0,800;0,900;1,300;1,500;1,700;1,900&display=swap"
/>
<link rel="stylesheet" href="../src/assets/styles/base.css" />
</head>
<body class="bg-dark font-body">
<slot />
</body>
</html>

View file

@ -0,0 +1,46 @@
---
import Layout from "~/layouts/Layout.astro";
import Invite from "~/components/Invite.astro";
import Computer from "~/components/Computer.astro";
---
<Layout>
<main class="flex h-screen items-center justify-center text-center">
<div
class="flex flex-col items-center px-4 text-center md:flex-row md:text-left"
>
<img
src="https://raw.githubusercontent.com/Hyro-Blobs/blobs/main/other/hyro_santa_bucket.png"
alt=""
class="mb-6 h-48 w-48 rounded-full md:h-64 md:w-64"
/>
<div>
<h1 class="mb-4 text-6xl font-extrabold text-white md:text-7xl">
Roles Bot
</h1>
<p class="max-w-3xl text-lg text-gray-300 md:text-xl">
Ultimate solution for managing reaction roles in your Discord server,
and the best part is, it's completely <strong>free</strong>! No hidden
charges or payments like other bots. Try it out today and see for
yourself how <strong>easy</strong> it is to use!
</p>
<div class="mt-6 flex flex-col gap-6 md:flex-row">
<a
href=""
class="broder-1 flex items-center justify-center gap-x-3 rounded-lg border border-[#4e59d6] bg-[#373a54]/50 px-10 py-3 text-lg font-semibold text-white transition-colors hover:bg-[#373a54]"
>
<Computer />
GitHub</a
>
<a
href=""
class="broder-1 flex items-center justify-center gap-x-3 rounded-lg border border-[#fbc11a] bg-[#735d1d]/50 px-10 py-3 text-lg font-semibold text-white transition-colors hover:bg-[#735d1d]"
>
<Invite />
Invite</a
>
</div>
</div>
</div>
</main>
</Layout>

View file

@ -0,0 +1,15 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {
colors: {
dark: "#111111",
},
fontFamily: {
body: ["Montserrat", "sans-serif"],
},
},
},
plugins: [],
};

View file

@ -0,0 +1,11 @@
{
"extends": "astro/tsconfigs/base",
"compilerOptions": {
"strictNullChecks": true,
"allowJs": true,
"baseUrl": ".",
"paths": {
"~/*": ["src/*"]
}
}
}

5071
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,25 +1,21 @@
{ {
"name": "roles-bot", "name": "roles-bot",
"version": "1.0.0", "description": "",
"main": "dist/worker.production.js", "private": true,
"scripts": { "scripts": {
"build": "webpack ./packages/bot", "build": "turbo run build",
"dev": "cross-env NODE_ENV=development npm run build" "dev": "turbo run dev",
"preview": "turbo run preview",
"deploy": "turbo run deploy",
"test": "turbo run test",
"lint": "rome check .",
"format": "rome format --write ."
}, },
"keywords": [], "keywords": [],
"author": "", "author": "xHyroM",
"license": "ISC", "license": "MIT",
"packageManager": "pnpm@8.1.0",
"devDependencies": { "devDependencies": {
"@cloudflare/workers-types": "^3.3.0", "rome": "^12.0.0"
"@types/jest": "^27.0.3",
"@types/service-worker-mock": "^2.0.1",
"@typescript-eslint/eslint-plugin": "^5.8.1",
"discord-api-types": "^0.25.2",
"eslint": "^8.6.0",
"service-worker-mock": "^2.0.5",
"ts-loader": "^9.2.6",
"typescript": "^4.5.4",
"webpack": "^5.65.0",
"webpack-cli": "^4.9.1"
} }
} }

21
packages/bot/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Jozef Steinhübl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

7
packages/bot/README.md Normal file
View file

@ -0,0 +1,7 @@
<div align="center">
<h1>Discord Roles Bot</h1>
</div>
Discord bot for reaction roles that works with [Cloudflare Workers](https://workers.cloudflare.com/).
You can add the bot to your server, just click [here](https://discord.com/api/oauth2/authorize?client_id=923267906941370368&permissions=268435456&scope=bot%20applications.commands).

View file

@ -1,100 +0,0 @@
import { APIApplicationCommandInteraction, APIMessageComponentInteraction, APIPingInteraction, ApplicationCommandType, ComponentType, InteractionResponseType, InteractionType, MessageFlags, RouteBases, Routes } from 'discord-api-types/v9';
import { badFormatting } from './utils/badFormatting';
import { isJSON } from './utils/isJson';
import { resolveButtonComponents, resolveSelectMenuComponents } from './utils/resolveComponents';
import { respond } from './utils/respond';
import { verify } from './utils/verify';
export const handleRequest = async(request: Request): Promise<Response> => {
if (!request.headers.get('X-Signature-Ed25519') || !request.headers.get('X-Signature-Timestamp')) return Response.redirect('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
if (!await verify(request)) return new Response('', { status: 401 });
const interaction = await request.json() as APIPingInteraction | APIApplicationCommandInteraction | APIMessageComponentInteraction;
if (interaction.type === InteractionType.Ping)
return respond({
type: InteractionResponseType.Pong
});
if (interaction.type === InteractionType.ApplicationCommand && interaction.data.type === ApplicationCommandType.ChatInput && interaction.data.name === 'setup') {
if ((Number(interaction.member?.permissions) & 0x10) !== 0x10) return respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
flags: 64,
content: 'Required permissions: `MANAGE_ROLES`'
}
});
// @ts-expect-error No typings for value
const json = isJSON(interaction.data.options?.[0]?.value) ? JSON.parse(interaction.data.options?.[0]?.value) : null;
if (!json) return badFormatting();
const channelId = json.channel;
let message = json.message?.toString();
let roles = json.roles;
if (!channelId) return badFormatting();
if (!message) message = '';
if (!roles || Object.values(json.roles).filter((role: any) => role.id && role.label).length === 0 || roles.length === 0 || roles.length > 25) return badFormatting(roles.length > 25);
const finalComponents = json.type === "1" ? resolveButtonComponents(roles) : resolveSelectMenuComponents(roles, json.placeholder?.toString());
const fetched = await fetch(`${RouteBases.api}/channels/${channelId}/messages`, {
method: 'POST',
headers: {
'Authorization': `Bot ${CLIENT_TOKEN}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
content: message,
components: finalComponents
})
}).catch(e => e);
return respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
flags: 64,
content: fetched?.ok ? 'Done!' : 'Error, bad channel id/missing permissions/invalid emojis.'
}
});
} else if (interaction.type === InteractionType.MessageComponent) {
const roleId = interaction.data.component_type === ComponentType.Button ? interaction.data.custom_id : interaction.data.values[0];
const url = `${RouteBases.api}${Routes.guildMemberRole(interaction.guild_id || '', interaction.member?.user.id || '', roleId)}`;
let method = '';
let content = '';
if (!interaction?.member?.roles?.includes(roleId)) {
content = `Gave the <@&${roleId}> role!`;
method = 'PUT';
} else {
content = `Removed the <@&${roleId}> role!`;
method = 'DELETE';
}
await fetch(url, {
method: method,
headers: {
'Authorization': `Bot ${CLIENT_TOKEN}`
}
}).catch(e => e);
return respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
flags: MessageFlags.Ephemeral,
content: content,
allowed_mentions: { parse: [] }
}
});
} else {
return respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
flags: MessageFlags.Ephemeral,
content: 'Beep boop, boop beep?'
}
});
}
};

View file

@ -1,5 +0,0 @@
import { handleRequest } from './bot';
addEventListener('fetch', (event) => {
event.respondWith(handleRequest(event.request));
});

29
packages/bot/package.json Normal file
View file

@ -0,0 +1,29 @@
{
"name": "bot",
"main": "dist/worker.mjs",
"type": "module",
"scripts": {
"build": "node scripts/build.mjs",
"dev": "miniflare --watch --debug --port 8787",
"dev:tunnel": "cloudflared tunnel --url localhost:8787/",
"deploy": "cross-env NODE_ENV=production wrangler publish"
},
"keywords": [],
"author": "xHyroM",
"license": "MIT",
"devDependencies": {
"@cloudflare/workers-types": "^3.17.0",
"@types/jest": "^29.1.2",
"esbuild": "^0.15.11",
"eslint": "^8.25.0",
"jest": "^29.2.0",
"miniflare": "^2.10.0",
"typescript": "^4.8.4"
},
"dependencies": {
"builders": "workspace:*",
"serialize": "workspace:*",
"redis-api-client": "workspace:*",
"discord-api-types": "^0.37.37"
}
}

View file

@ -0,0 +1,39 @@
import esbuild from "esbuild";
import { rmSync, existsSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
if (existsSync(join(__dirname, "..", "dist")))
rmSync(join(__dirname, "..", "dist"), { recursive: true });
const watch = process.argv.includes("--watch");
const dev = process.argv.includes("--dev");
Promise.all([
esbuild.build({
bundle: true,
logLevel: "info",
format: "esm",
mainFields: ["browser", "module", "main"],
platform: "neutral",
target: "es2020",
entryPoints: ["./src/index.ts"],
outfile: "./dist/worker.mjs",
sourcemap: dev,
charset: "utf8",
minify: !dev,
watch: watch,
external: ["node:events"],
}),
])
.catch((err) => {
console.error("Roles Bot failed to build");
console.error(err.message);
})
.then(() => {
console.log(
watch ? "Waiting for your changes..." : "Roles Bot has been built",
);
});

View file

@ -0,0 +1,61 @@
import { Command } from "../structs/Command";
import {
APIRole,
ChannelType,
MessageFlags,
RouteBases,
Routes,
} from "discord-api-types/v10";
import { ActionRowBuilder, ChannelSelectMenuBuilder } from "builders";
import { REDIS } from "../things";
import { encodeToHex } from "serialize";
// Part 1 ## select channel
new Command({
name: "setup",
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
if (!ctx.guildId)
return await ctx.editReply({
content: "Guild not found.",
});
// Delete the data if it exists
await REDIS.del(`roles-bot-setup:${ctx.guildId}`);
const roles = (await (
await fetch(`${RouteBases.api}${Routes.guildRoles(ctx.guildId)}`, {
headers: {
Authorization: `Bot ${ctx.env.token}`,
},
})
).json()) as APIRole[];
await REDIS.setex(
`roles-bot-setup-roles:${ctx.guildId}`,
encodeToHex(
roles.map((r) => ({
id: r.id,
name: r.name,
})),
),
3600,
);
await ctx.editReply({
content: "Select the channel to which the panel will be sent.",
components: [
new ActionRowBuilder<ChannelSelectMenuBuilder>()
.addComponents(
new ChannelSelectMenuBuilder()
.setCustomId("setup:part-channel")
.addChannelTypes(
ChannelType.GuildAnnouncement,
ChannelType.GuildText,
),
)
.toJSON(),
],
});
},
});

View file

@ -0,0 +1,61 @@
import {
ComponentType,
MessageFlags,
RouteBases,
Routes,
} from "discord-api-types/v10";
import { Component } from "../structs/Component";
new Component({
id: "select:role",
default: true,
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
if (!ctx.guildId)
return ctx.editReply({
content: "Guild not found.",
});
if (!ctx.interaction.member)
return ctx.editReply({
content: "Member not found.",
});
const roleId =
ctx.interaction.data.component_type === ComponentType.StringSelect
? ctx.interaction.data.values[0].startsWith("role:")
? ctx.interaction.data.values[0].split(":")[1]
: // support for legacy select menus
ctx.interaction.data.values[0]
: ctx.interaction.data.custom_id.startsWith("role:")
? ctx.interaction.data.custom_id.split(":")[1]
: // support for legacy select menus
ctx.interaction.data.custom_id;
const content = !ctx.interaction.member?.roles.includes(roleId)
? `Gave the <@&${roleId}> role!`
: `Removed the <@&${roleId}> role!`;
const method = !ctx.interaction.member?.roles.includes(roleId)
? "PUT"
: "DELETE";
await fetch(
`${RouteBases.api}${Routes.guildMemberRole(
ctx.guildId,
ctx.interaction.member.user.id,
roleId,
)}`,
{
method,
headers: {
Authorization: `Bot ${ctx.env.token}`,
},
},
);
await ctx.editReply({
content,
});
},
});

View file

@ -0,0 +1,268 @@
import {
ActionRowBuilder,
ButtonBuilder,
RoleSelectMenuBuilder,
TextInputBuilder,
} from "builders";
import { Component } from "../structs/Component";
import {
APIMessageComponentSelectMenuInteraction,
ButtonStyle,
InteractionResponseType,
MessageFlags,
TextInputStyle,
} from "discord-api-types/v10";
import returnRoleLpe from "../utils/returnRoleLpe";
import { REDIS } from "../things";
import { encodeToHex, decodeFromString } from "serialize";
import sendFinal from "../utils/sendFinal";
// Part 2 Channels ## select button/dropdowns
new Component({
id: "setup:part-channel",
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
if (!ctx.interaction.guild_id)
return await ctx.editReply({
content: "Guild not found.",
});
const interaction =
ctx.interaction as APIMessageComponentSelectMenuInteraction;
const data = {
channelId: interaction.data.values[0],
};
await REDIS.setex(
`roles-bot-setup:${interaction.guild_id}`,
encodeToHex(data),
600,
);
await ctx.editReply({
content:
"Choose whether you want to use buttons or dropdown menu (select menu).",
components: [
new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel("Buttons")
.setCustomId("setup:part-selecting:buttons")
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setLabel("Dropdowns")
.setCustomId("setup:part-selecting:dropdowns")
.setStyle(ButtonStyle.Primary),
)
.toJSON(),
],
});
},
});
// Part 3 Selecting ## select roles
new Component({
id: "setup:part-selecting",
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
if (!ctx.interaction.guild_id)
return await ctx.editReply({ content: "Guild not found." });
const rawData = await REDIS.get(
`roles-bot-setup:${ctx.interaction.guild_id}`,
);
if (!rawData)
return await ctx.editReply({
content: "Data not found. Try running setup again.",
});
const data = decodeFromString(rawData);
data.selecting = ctx.interaction.data.custom_id.split(":")[2];
await REDIS.setex(
`roles-bot-setup:${ctx.interaction.guild_id}`,
encodeToHex(data),
600,
);
await ctx.editReply({
content: "Select the roles that will be available in the menu.",
components: [
new ActionRowBuilder<RoleSelectMenuBuilder>()
.addComponents(
new RoleSelectMenuBuilder()
.setCustomId("setup:part-roles")
.setPlaceholder("Select roles")
.setMinValues(1)
.setMaxValues(25),
)
.toJSON(),
],
});
},
});
// Part 4 Roles ## open modal for role lpe OR message preview
new Component({
id: "setup:part-roles",
acknowledge: false,
run: async (ctx) => {
if (!ctx.interaction.guild_id)
return await ctx.editReply({ content: "Guild not found." });
const interaction =
ctx.interaction as APIMessageComponentSelectMenuInteraction;
const rawData = await REDIS.get(
`roles-bot-setup:${ctx.interaction.guild_id}`,
);
if (!rawData)
return ctx.respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
content: "Data not found. Try running setup again.",
flags: MessageFlags.Ephemeral,
},
});
const data = decodeFromString(rawData);
const rawRoleIds = (data.rawRoleIds as string[]) ?? interaction.data.values;
data.rawRoleIds = rawRoleIds;
await REDIS.setex(
`roles-bot-setup:${ctx.interaction.guild_id}`,
encodeToHex(data),
600,
);
return rawRoleIds.length > 0
? returnRoleLpe(data, ctx, rawRoleIds[0])
: ctx.returnModal({
title: "Message Preview",
custom_id: "setup:part-messageContent",
components: [
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Content")
.setCustomId("content")
.setPlaceholder("Select beautiful roles <3")
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(2000)
.setRequired(false),
)
.toJSON(),
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Embed Title")
.setCustomId("embedTitle")
.setPlaceholder("I love you")
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(256)
.setRequired(false),
)
.toJSON(),
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Embed Description")
.setCustomId("embedDescription")
.setPlaceholder("1. lol\n2. lol\n3. lol")
.setStyle(TextInputStyle.Paragraph)
.setMaxLength(4000)
.setRequired(false),
)
.toJSON(),
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Embed Color")
.setCustomId("embedColor")
.setPlaceholder("#4287f5")
.setStyle(TextInputStyle.Short)
.setMaxLength(7)
.setRequired(false),
)
.toJSON(),
],
});
},
});
// Part 7 Send As ## finish or open modal for webhook preview
new Component({
id: "setup:part-sendAs",
acknowledge: false,
run: async (ctx) => {
if (!ctx.guildId)
return await ctx.editReply({ content: "Guild not found." });
const rawData = await REDIS.get(`roles-bot-setup:${ctx.guildId}`);
if (!rawData)
return ctx.respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
content: "Data not found. Try running setup again.",
flags: MessageFlags.Ephemeral,
},
});
const data = decodeFromString(rawData);
const sendAs = ctx.interaction.data.custom_id.split(":")[2];
data.sendAs = sendAs;
await REDIS.setex(
`roles-bot-setup:${ctx.interaction.guild_id}`,
encodeToHex(data),
600,
);
switch (sendAs) {
case "webhook": {
return ctx.returnModal({
title: "Webhook Preview",
custom_id: "setup:part-webhook",
components: [
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Webhook Name")
.setCustomId("name")
.setPlaceholder("Roles Bot")
.setStyle(TextInputStyle.Short)
.setMaxLength(80)
.setRequired(true),
)
.toJSON(),
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Webhook Avatar URL")
.setCustomId("avatarUrl")
.setPlaceholder(
"https://raw.githubusercontent.com/Hyro-Blobs/blobs/main/base/hyro_blob-upscaled.png",
)
.setStyle(TextInputStyle.Short)
.setRequired(false),
)
.toJSON(),
],
});
}
case "bot": {
sendFinal(ctx, data);
return ctx.respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
content: "Setup completed!",
flags: MessageFlags.Ephemeral,
},
});
}
}
},
});

120
packages/bot/src/index.ts Normal file
View file

@ -0,0 +1,120 @@
import "./commands/setup";
import "./components/setup";
import "./components/select";
import "./modals/setup";
import {
APIApplicationCommandInteraction,
APIMessageComponentInteraction,
APIModalSubmitInteraction,
APIPingInteraction,
InteractionResponseType,
InteractionType,
} from "discord-api-types/v10";
import { COMMANDS, COMPONENTS, MODALS, REDIS, setRedis } from "./things";
import { verify } from "./utils/verify";
import respond from "./utils/respond";
import { CommandContext } from "./structs/contexts/CommandContext";
import { ComponentContext } from "./structs/contexts/ComponentContext";
import { ModalContext } from "./structs/contexts/ModalContext";
import { Env } from "./types";
export default {
fetch: async (request: Request, env: Env) => {
if (!REDIS) setRedis(env.redisApiClientKey, env.redisApiClientHost);
if (
!request.headers.get("X-Signature-Ed25519") ||
!request.headers.get("X-Signature-Timestamp")
)
return Response.redirect("https://xhyrom.dev");
if (!(await verify(request, env)))
return new Response("Invalid request signature", { status: 401 });
const interaction = (await request.json()) as
| APIPingInteraction
| APIApplicationCommandInteraction
| APIModalSubmitInteraction
| APIMessageComponentInteraction;
if (interaction.type === InteractionType.Ping)
return respond({
type: InteractionResponseType.Pong,
});
switch (interaction.type) {
case InteractionType.ApplicationCommand: {
const command = COMMANDS.find(
(cmd) => cmd.name === interaction.data.name,
);
if (!command) return new Response("Unknown command", { status: 404 });
try {
if (command.acknowledge)
return respond({
type: InteractionResponseType.DeferredChannelMessageWithSource,
data: {
flags: command.flags,
},
});
} finally {
if (command.acknowledge)
command.run(new CommandContext(interaction, env));
// rome-ignore lint/correctness/noUnsafeFinally: it works, must do better typings etc...
else return command.run(new CommandContext(interaction, env));
}
break;
}
case InteractionType.ModalSubmit: {
const context = new ModalContext(interaction, env);
const modal = MODALS.find((md) =>
context.interaction.data.custom_id.startsWith(md.id),
);
if (!modal) return new Response("Unknown modal", { status: 404 });
try {
if (modal.acknowledge)
return respond({
type: InteractionResponseType.DeferredChannelMessageWithSource,
data: {
flags: modal.flags,
},
});
} finally {
if (modal.acknowledge) modal.run(context);
// rome-ignore lint/correctness/noUnsafeFinally: it works, must do better typings etc...
else return modal.run(context);
}
break;
}
case InteractionType.MessageComponent: {
const context = new ComponentContext(interaction, env);
const component =
COMPONENTS.find((cmp) =>
context.interaction.data.custom_id.startsWith(cmp.id),
) ?? COMPONENTS.find((cmp) => cmp.default);
if (!component)
return new Response("Unknown component", { status: 404 });
try {
if (component.acknowledge)
return respond({
type: InteractionResponseType.DeferredChannelMessageWithSource,
data: {
flags: component.flags,
},
});
} finally {
if (component.acknowledge) component.run(context);
// rome-ignore lint/correctness/noUnsafeFinally: it works, must do better typings etc...
else return component.run(context);
}
}
}
},
};

View file

@ -0,0 +1,189 @@
import {
APIWebhook,
ButtonStyle,
MessageFlags,
RouteBases,
Routes,
} from "discord-api-types/v10";
import { Modal } from "../structs/Modal";
import { ActionRowBuilder, ButtonBuilder } from "builders";
import { encodeToHex, decodeFromString } from "serialize";
import { REDIS } from "../things";
import sendFinal from "../utils/sendFinal";
import { RoleId } from "../types";
// Part 5 Roles ## add label, placeholder, emoji OR message content
new Modal({
id: "setup:part-roles-lpe",
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
const rawData = await REDIS.get(
`roles-bot-setup:${ctx.interaction.guild_id}`,
);
if (!rawData)
return await ctx.editReply({
content: "Data not found. Try running setup again.",
});
const data = decodeFromString(rawData);
const rawRoleIds = data.rawRoleIds as string[];
const roleIds = (data.roleIds ?? []) as RoleId[];
const label = ctx.interaction.data.components[0].components[0].value;
const emoji = ctx.interaction.data.components[1].components[0].value;
switch (data.selecting) {
case "buttons": {
const style = ctx.interaction.data.components[2].components[0].value;
roleIds.push({ label, style, emoji, id: rawRoleIds[0] });
break;
}
case "dropdowns": {
const description =
ctx.interaction.data.components[2].components[0].value;
roleIds.push({ label, description, emoji, id: rawRoleIds[0] });
break;
}
}
rawRoleIds.shift();
data.rawRoleIds = rawRoleIds;
data.roleIds = roleIds;
await REDIS.setex(
`roles-bot-setup:${ctx.interaction.guild_id}`,
encodeToHex(data),
600,
);
return await ctx.editReply({
content:
rawRoleIds.length > 0
? "Click the button to set the label, placeholder and emoji for next role."
: "Click the button to set message content or embed.",
components: [
new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel(rawRoleIds.length > 0 ? "Next Role" : "Message Content")
.setCustomId("setup:part-roles")
.setStyle(ButtonStyle.Primary),
)
.toJSON(),
],
});
},
});
// Part 6 Message Content ## select send as webhook/as bot
new Modal({
id: "setup:part-messageContent",
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
const rawData = await REDIS.get(
`roles-bot-setup:${ctx.interaction.guild_id}`,
);
if (!rawData)
return await ctx.editReply({
content: "Data not found. Try running setup again.",
});
const data = decodeFromString(rawData);
const content = ctx.interaction.data.components[0].components[0].value;
const embedTitle = ctx.interaction.data.components[1].components[0].value;
const embedDescription =
ctx.interaction.data.components[2].components[0].value;
const embedColor = ctx.interaction.data.components[3].components[0].value;
if (!content && !embedTitle && !embedDescription) {
await ctx.editReply({
content: "You must provide a message content or embed.",
components: [],
});
return;
}
data.message = { content, embedTitle, embedDescription, embedColor };
await REDIS.setex(
`roles-bot-setup:${ctx.interaction.guild_id}`,
encodeToHex(data),
600,
);
await ctx.editReply({
content:
"Choose whether you want to send the message as a webhook or as a bot.",
components: [
new ActionRowBuilder<ButtonBuilder>()
.addComponents(
new ButtonBuilder()
.setLabel("Webhook")
.setCustomId("setup:part-sendAs:webhook")
.setStyle(ButtonStyle.Primary),
new ButtonBuilder()
.setLabel("Bot")
.setCustomId("setup:part-sendAs:bot")
.setStyle(ButtonStyle.Primary),
)
.toJSON(),
],
});
},
});
// Part 8 (ONLY IF WEBHOOK) Webhook ## send webhook
new Modal({
id: "setup:part-webhook",
flags: MessageFlags.Ephemeral,
run: async (ctx) => {
const rawData = await REDIS.get(
`roles-bot-setup:${ctx.interaction.guild_id}`,
);
if (!rawData)
return await ctx.editReply({
content: "Data not found. Try running setup again.",
});
const data = decodeFromString(rawData);
const webhookName = ctx.interaction.data.components[0].components[0].value;
const webhookAvatarUrl =
ctx.interaction.data.components[1].components[0].value;
const webhook = (await (
await fetch(
`${RouteBases.api}${Routes.channelWebhooks(data.channelId)}`,
{
method: "POST",
headers: {
Authorization: `Bot ${ctx.env.token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Roles Bot Webhook",
}),
},
)
).json()) as APIWebhook;
data.webhook = {
name: webhookName,
avatarUrl: webhookAvatarUrl,
id: webhook.id,
token: webhook.token,
};
sendFinal(ctx, data);
await ctx.editReply({
content: "Setup completed!",
});
},
});

View file

@ -0,0 +1,26 @@
import { MessageFlags } from "discord-api-types/v10";
import { registerCommand } from "../things";
import { CommandContext } from "./contexts/CommandContext";
interface CommandOptions {
name: string;
acknowledge?: boolean;
flags?: MessageFlags;
run: (interaction: CommandContext) => void;
}
export class Command {
public name: string;
public acknowledge: boolean;
public flags: MessageFlags | undefined;
public run: (interaction: CommandContext) => void | Response;
constructor(options: CommandOptions) {
this.name = options.name;
this.acknowledge = options.acknowledge ?? true;
this.flags = options.flags;
this.run = options.run;
registerCommand(this);
}
}

View file

@ -0,0 +1,29 @@
import { MessageFlags } from "discord-api-types/v10";
import { registerComponent } from "../things";
import { ComponentContext } from "./contexts/ComponentContext";
interface ComponentOptions {
id: string;
acknowledge?: boolean;
default?: boolean;
flags?: MessageFlags;
run: (interaction: ComponentContext) => void;
}
export class Component {
public id: string;
public acknowledge: boolean;
public default: boolean;
public flags: MessageFlags | undefined;
public run: (interaction: ComponentContext) => void | Response;
constructor(options: ComponentOptions) {
this.id = options.id;
this.acknowledge = options.acknowledge ?? true;
this.default = options.default ?? false;
this.flags = options.flags;
this.run = options.run;
registerComponent(this);
}
}

View file

@ -0,0 +1,26 @@
import { MessageFlags } from "discord-api-types/v10";
import { registerModal } from "../things";
import { ModalContext } from "./contexts/ModalContext";
interface ModalOptions {
id: string;
acknowledge?: boolean;
flags?: MessageFlags;
run: (interaction: ModalContext) => void;
}
export class Modal {
public id: string;
public acknowledge: boolean;
public flags: MessageFlags | undefined;
public run: (interaction: ModalContext) => void;
constructor(options: ModalOptions) {
this.id = options.id;
this.acknowledge = options.acknowledge ?? true;
this.flags = options.flags;
this.run = options.run;
registerModal(this);
}
}

View file

@ -0,0 +1,13 @@
import { APIApplicationCommandInteraction } from "discord-api-types/v10";
import { Context } from "./Context";
import { Env } from "../../types";
export class CommandContext extends Context {
public interaction: APIApplicationCommandInteraction;
constructor(interaction: APIApplicationCommandInteraction, env: Env) {
super(interaction, env);
this.interaction = interaction;
}
}

View file

@ -0,0 +1,13 @@
import { APIMessageComponentInteraction } from "discord-api-types/v10";
import { Env } from "../../types";
import { Context } from "./Context";
export class ComponentContext extends Context {
public interaction: APIMessageComponentInteraction;
constructor(interaction: APIMessageComponentInteraction, env: Env) {
super(interaction, env);
this.interaction = interaction;
}
}

View file

@ -0,0 +1,70 @@
import {
APIInteraction,
APIInteractionResponseCallbackData,
APIModalInteractionResponseCallbackData,
InteractionResponseType,
RouteBases,
Routes,
} from "discord-api-types/v10";
import respond from "../../utils/respond";
import { Env } from "../../types";
export class Context {
public interaction: APIInteraction;
public env: Env;
constructor(interaction: APIInteraction, env: Env) {
this.interaction = interaction;
this.env = env;
}
get guildId() {
return this.interaction.guild_id;
}
public respond = respond;
public async editReply(content: APIInteractionResponseCallbackData) {
return await fetch(
`${RouteBases.api}${Routes.webhookMessage(
this.interaction.application_id,
this.interaction.token,
)}`,
{
method: "PATCH",
body: JSON.stringify(content),
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${this.env.token}`,
},
},
);
}
public async showModal(content: APIModalInteractionResponseCallbackData) {
return await fetch(
`${RouteBases.api}${Routes.interactionCallback(
this.interaction.id,
this.interaction.token,
)}`,
{
method: "POST",
body: JSON.stringify({
type: InteractionResponseType.Modal,
data: content,
}),
headers: {
"Content-Type": "application/json",
Authorization: `Bot ${this.env.token}`,
},
},
);
}
public async returnModal(content: APIModalInteractionResponseCallbackData) {
return respond({
type: InteractionResponseType.Modal,
data: content,
});
}
}

View file

@ -0,0 +1,13 @@
import { APIModalSubmitInteraction } from "discord-api-types/v10";
import { Context } from "./Context";
import { Env } from "../../types";
export class ModalContext extends Context {
public interaction: APIModalSubmitInteraction;
constructor(interaction: APIModalSubmitInteraction, env: Env) {
super(interaction, env);
this.interaction = interaction;
}
}

View file

@ -0,0 +1,25 @@
import { RedisAPIClient } from "redis-api-client";
import { Command } from "./structs/Command";
import { Component } from "./structs/Component";
import { Modal } from "./structs/Modal";
export const COMMANDS: Command[] = [];
export const COMPONENTS: Component[] = [];
export const MODALS: Modal[] = [];
export let REDIS: RedisAPIClient;
export const setRedis = (apiKey: string, host: string) => {
REDIS = new RedisAPIClient(apiKey, host);
};
export const registerCommand = (command: Command) => {
COMMANDS.push(command);
};
export const registerComponent = (component: Component) => {
COMPONENTS.push(component);
};
export const registerModal = (modal: Modal) => {
MODALS.push(modal);
};

43
packages/bot/src/types.d.ts vendored Normal file
View file

@ -0,0 +1,43 @@
import type { Generic } from "serialize";
// secrets: wrangler secret put <name>
declare let MINIFLARE; // just check because algorithm is different
declare type DeclaredId = Record<
string,
| string
| {
[key: string]: Generic;
}
> & {
data: {
[key: string]: Generic;
};
};
declare interface Env {
publicKey: string;
token: string;
redisApiClientKey: string;
redisApiClientHost: string;
}
declare interface RoleId {
label: string;
description?: string;
emoji: string;
id: string;
style?: string;
}
declare interface BasicData {
channelId: string;
selecting: "buttons" | "dropdowns";
roleIds: RoleId[];
message: {
content: string;
embedTitle: string;
embedDescription: string;
embedColor: string;
};
}

View file

@ -0,0 +1,12 @@
import { RGBTuple } from "builders";
export default function (hex: string): RGBTuple | null {
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return result
? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16),
]
: null;
}

View file

@ -0,0 +1,16 @@
import { ButtonStyle } from "discord-api-types/v10";
export default function (style: string) {
switch (style.toLowerCase()) {
case "primary":
return ButtonStyle.Primary;
case "secondary":
return ButtonStyle.Secondary;
case "success":
return ButtonStyle.Success;
case "danger":
return ButtonStyle.Danger;
default:
return ButtonStyle.Primary;
}
}

View file

@ -0,0 +1,18 @@
// https://github.com/discordjs/discord.js/blob/6412da4921a5fd9ed0987205508bacd2b4868fd6/packages/discord.js/src/util/Util.js#L90-L109
export function parseEmoji(text: string) {
if (text.includes("%")) text = decodeURIComponent(text);
if (!text.includes(":"))
return { animated: false, name: text, id: undefined };
const match = text.match(/<?(?:(a):)?(\w{2,32}):(\d{17,19})?>?/);
return match && { animated: Boolean(match[1]), name: match[2], id: match[3] };
}
export function resolvePartialEmoji(emoji: string) {
if (!emoji) return null;
if (typeof emoji === "string")
return /^\d{17,19}$/.test(emoji) ? { id: emoji } : parseEmoji(emoji);
const { id, name, animated } = emoji;
if (!id && !name) return null;
return { id, name, animated: Boolean(animated) };
}

View file

@ -0,0 +1,7 @@
import { APIInteractionResponse } from "discord-api-types/v10";
export default function (response: APIInteractionResponse) {
return new Response(JSON.stringify(response), {
headers: { "content-type": "application/json" },
});
}

View file

@ -0,0 +1,90 @@
import { Context } from "../structs/contexts/Context";
import { ActionRowBuilder, TextInputBuilder } from "builders";
import {
APIRole,
InteractionResponseType,
MessageFlags,
TextInputStyle,
} from "discord-api-types/v10";
import { REDIS } from "../things";
import { decodeFromString } from "serialize";
import { BasicData } from "../types";
export default async function (data: BasicData, ctx: Context, rawRole: string) {
const rolesRaw = await REDIS.get(`roles-bot-setup-roles:${ctx.guildId}`);
if (!rolesRaw)
return ctx.respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
content:
"Something went wrong. Please try again.\nIf this problem persists, please contact [Support Server](https://discord.gg/kFPKmEKeMS/).",
flags: MessageFlags.Ephemeral,
},
});
const roles = decodeFromString(rolesRaw) as Partial<APIRole>[];
const roleName = roles?.find((r) => r.id === rawRole)?.name;
const components = [
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Label")
.setCustomId("label")
.setPlaceholder("Ping")
.setStyle(TextInputStyle.Short)
.setRequired(true),
)
.toJSON(),
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Emoji")
.setCustomId("emoji")
.setPlaceholder("emoji 💡")
.setStyle(TextInputStyle.Short)
.setRequired(false),
)
.toJSON(),
];
switch (data.selecting) {
case "buttons": {
components.push(
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Style")
.setCustomId("style")
.setPlaceholder("Primary, Secondary, Success or Danger")
.setStyle(TextInputStyle.Short)
.setRequired(true),
)
.toJSON(),
);
break;
}
case "dropdowns": {
components.push(
new ActionRowBuilder<TextInputBuilder>()
.addComponents(
new TextInputBuilder()
.setLabel("Description")
.setCustomId("description")
.setPlaceholder("pingping pong pong")
.setStyle(TextInputStyle.Short)
.setRequired(false),
)
.toJSON(),
);
}
}
return ctx.returnModal({
title: `${roleName?.slice(0, 39)} Role`,
custom_id: "setup:part-roles-lpe",
components,
});
}

View file

@ -0,0 +1,174 @@
import {
APIActionRowComponent,
APIEmbed,
APIMessageActionRowComponent,
ButtonStyle,
RouteBases,
Routes,
} from "discord-api-types/v10";
import { Context } from "../structs/contexts/Context";
import { REDIS } from "../things";
import {
ActionRowBuilder,
ButtonBuilder,
EmbedBuilder,
StringSelectMenuBuilder,
StringSelectMenuOptionBuilder,
} from "builders";
import hexToRGB from "./hexToRGB";
import splitArray from "./splitArray";
import { resolvePartialEmoji } from "./resolveEmoji";
import { BasicData } from "../types";
import resolveButtonStyle from "./resolveButtonStyle";
type DataBot = BasicData & {
sendAs: "bot";
};
type DataWebhook = BasicData & {
sendAs: "webhook";
webhook: {
name: string;
avatarUrl: string;
id: string;
token: string;
};
};
type Data = DataBot | DataWebhook;
export default async function (ctx: Context, data: Data) {
await REDIS.del(`roles-bot-setup:${ctx.guildId}`);
await REDIS.del(`roles-bot-setup-roles:${ctx.guildId}`);
const payload: {
content?: string;
embeds?: APIEmbed[];
components: APIActionRowComponent<APIMessageActionRowComponent>[];
} = {
components: [],
};
if (data.message.content) payload.content = data.message.content;
if (data.message.embedTitle || data.message.embedDescription) {
payload.embeds = [
new EmbedBuilder()
.setTitle(data.message.embedTitle)
.setDescription(data.message.embedDescription)
.setColor(
data.message.embedColor ? hexToRGB(data.message.embedColor) : null,
)
.toJSON(),
];
}
const components: APIActionRowComponent<APIMessageActionRowComponent>[] = [];
const array = splitArray(data.roleIds, 25);
for (const items of array) {
const actionRow = new ActionRowBuilder();
const selectMenu = new StringSelectMenuBuilder().setCustomId("select:role");
for (const item of items) {
switch (data.selecting) {
case "buttons": {
const button = new ButtonBuilder()
.setLabel(item.label)
.setCustomId(`role:${item.id}`)
// rome-ignore lint/style/noNonNullAssertion: defined
.setStyle(resolveButtonStyle(item.style!));
if (item.emoji && resolvePartialEmoji(item.emoji))
// rome-ignore lint/style/noNonNullAssertion: its fine
button.setEmoji(resolvePartialEmoji(item.emoji)!);
actionRow.addComponents(button);
break;
}
case "dropdowns": {
const option = new StringSelectMenuOptionBuilder()
.setLabel(item.label)
// rome-ignore lint/style/noNonNullAssertion: defined
.setDescription(item.description!)
.setValue(`role:${item.id}`);
if (item.emoji && resolvePartialEmoji(item.emoji))
// rome-ignore lint/style/noNonNullAssertion: its fine
option.setEmoji(resolvePartialEmoji(item.emoji)!);
option.setValue(item.id);
selectMenu.addOptions(option);
}
}
}
if (data.selecting === "dropdowns") actionRow.addComponents(selectMenu);
// @ts-expect-error i know i know
components.push(actionRow);
}
payload.components = components;
switch (data.sendAs) {
case "bot": {
const res = await fetch(
`${RouteBases.api}${Routes.channelMessages(data.channelId)}`,
{
method: "POST",
headers: {
Authorization: `Bot ${ctx.env.token}`,
"Content-Type": "application/json",
},
body: JSON.stringify(payload),
},
);
if (!res.ok) {
const json: { message: string; code: string } = await res.json();
await ctx.editReply({
content: `Error: ${json.message} (${json.code})`,
});
}
break;
}
case "webhook": {
const res = await fetch(
`${RouteBases.api}${Routes.webhook(
data.webhook.id,
data.webhook.token,
)}`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
...payload,
username: data.webhook.name,
avatar_url: data.webhook.avatarUrl,
}),
},
);
if (!res.ok) {
const json: { message: string; code: string } = await res.json();
await ctx.editReply({
content: `Error: ${json.message} (${json.code})`,
});
} else {
await fetch(
`${RouteBases.api}${Routes.webhook(
data.webhook.id,
data.webhook.token,
)}`,
{
method: "DELETE",
},
);
}
}
}
}

View file

@ -0,0 +1,7 @@
export default function <T>(array: T[], x: number): T[][] {
const result: T[][] = [];
for (let i = 0; i < array.length; i += x) {
result.push(array.slice(i, i + x));
}
return result;
}

View file

@ -0,0 +1,40 @@
// from https://gist.github.com/devsnek/77275f6e3f810a9545440931ed314dc1
"use strict";
import type { Env } from "../types";
function hex2bin(hex: string) {
const buf = new Uint8Array(Math.ceil(hex.length / 2));
for (let i = 0; i < buf.length; i++) {
buf[i] = parseInt(hex.substring(i * 2, i * 2 + 2), 16);
}
return buf;
}
const encoder = new TextEncoder();
export async function verify(request: Request, env: Env) {
const subtle = await crypto.subtle.importKey(
"raw",
hex2bin(env.publicKey),
{
name: typeof MINIFLARE !== "undefined" ? "Ed25519" : "NODE-ED25519",
namedCurve: typeof MINIFLARE !== "undefined" ? "Ed25519" : "NODE-ED25519",
},
true,
["verify"],
);
// rome-ignore lint/style/noNonNullAssertion: its fine
const signature = hex2bin(request.headers.get("X-Signature-Ed25519")!);
const timestamp = request.headers.get("X-Signature-Timestamp");
const unknown = await request.clone().text();
return await crypto.subtle.verify(
typeof MINIFLARE !== "undefined" ? "Ed25519" : "NODE-ED25519",
subtle,
signature,
encoder.encode(timestamp + unknown),
);
}

View file

@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "esnext",
"downlevelIteration": true,
"lib": ["esnext", "webworker"],
"strict": true,
"moduleResolution": "node",
"skipLibCheck": true,
"esModuleInterop": true,
"types": ["@cloudflare/workers-types", "jest"]
}
}

View file

@ -1,2 +0,0 @@
declare const CLIENT_PUBLIC_KEY: string;
declare const CLIENT_TOKEN: string;

View file

@ -1,12 +0,0 @@
import { InteractionResponseType } from 'discord-api-types/v9';
import { respond } from './respond';
export const badFormatting = (rolesMax?: boolean) => {
return respond({
type: InteractionResponseType.ChannelMessageWithSource,
data: {
flags: 64,
content: `${rolesMax ? 'You can have maximum 25 buttons. (5x5)' : 'Bad formatting, generate [here](https://xhyrom.github.io/roles-bot)'}`
}
});
};

View file

@ -1,11 +0,0 @@
export const isJSON = (data: any): boolean => {
if (typeof data !== 'string') return false;
try {
const result = JSON.parse(data);
const type = result.toString();
return type === '[object Object]' || type === '[object Array]';
} catch (err) {
return false;
}
};

View file

@ -1,73 +0,0 @@
import { ButtonStyle, ComponentType, Snowflake } from 'discord-api-types/v9';
import { resolvePartialEmoji } from './resolveEmoji';
interface Role {
id: Snowflake;
style?: ButtonStyle;
label: string;
description?: string;
emoji: string | null;
}
export const resolveButtonComponents = (roles: Array<Role>) => {
roles = roles.map((r: Role) => {
const o: any = {
type: ComponentType.Button,
style: r.style || ButtonStyle.Secondary,
label: r.label,
custom_id: r.id
};
if (r.emoji) o.emoji = resolvePartialEmoji(r.emoji);
return o;
});
let finalComponents = [];
for (let i = 0; i <= roles.length; i += 5) {
const row: any = {
type: ComponentType.ActionRow,
components: []
};
const btnslice: any = roles.slice(i, i + 5);
for (let y = 0; y < btnslice.length; y++) row.components.push(btnslice[y]);
finalComponents.push(row);
}
finalComponents = finalComponents.filter(a => a.components.length > 0);
return finalComponents;
}
export const resolveSelectMenuComponents = (roles: Array<Role>, placeholder?: string) => {
roles = roles.map((r: Role) => {
const o: any = {
label: r.label,
value: r.id,
description: r.description,
};
if (r.emoji) o.emoji = resolvePartialEmoji(r.emoji);
return o;
});
const actionRow = [
{
type: ComponentType.ActionRow,
components: [
{
type: ComponentType.SelectMenu,
custom_id: 'role_select',
options: roles,
}
]
}
];
// @ts-expect-error No typings
if (placeholder) actionRow[0].components[0].placeholder = placeholder;
return actionRow;
}

View file

@ -1,19 +0,0 @@
/**
* https://github.com/discordjs/discord.js/blob/3c0bbac82fa9988af4a62ff00c66d149fbe6b921/packages/discord.js/src/util/Util.js#L292-L311
*/
export const resolvePartialEmoji = (emoji: string) => {
if (!emoji) return null;
if (typeof emoji === 'string') return /^\d{17,19}$/.test(emoji) ? { id: emoji } : parseEmoji(emoji);
const { id, name, animated } = emoji;
if (!id && !name) return null;
return { id, name, animated: Boolean(animated) };
};
export const parseEmoji = (text: string) => {
if (text.includes('%')) text = decodeURIComponent(text);
if (!text.includes(':')) return { animated: false, name: text, id: null };
const match = text.match(/<?(?:(a):)?(\w{2,32}):(\d{17,19})?>?/);
return match && { animated: Boolean(match[1]), name: match[2], id: match[3] ?? null };
};

View file

@ -1,3 +0,0 @@
import { APIInteractionResponse } from 'discord-api-types/v9';
export const respond = (response: APIInteractionResponse) => new Response(JSON.stringify(response), {headers: {'content-type': 'application/json'}});

View file

@ -1,37 +0,0 @@
// from https://github.com/advaith1/activities/blob/main/src/verify.ts
'use strict';
function hex2bin(hex: string) {
const buf = new Uint8Array(Math.ceil(hex.length / 2));
for (let i = 0; i < buf.length; i++) {
buf[i] = parseInt(hex.slice(i * 2, i * 2 + 2), 16);
}
return buf;
}
const PUBLIC_KEY = crypto.subtle.importKey(
'raw',
hex2bin(CLIENT_PUBLIC_KEY || ''),
{
name: 'NODE-ED25519',
namedCurve: 'NODE-ED25519',
},
true,
['verify'],
);
const encoder = new TextEncoder();
export async function verify(request: Request) {
const signature = hex2bin(request.headers.get('X-Signature-Ed25519') || '');
const timestamp = request.headers.get('X-Signature-Timestamp');
const unknown = await request.clone().text();
return await crypto.subtle.verify(
'NODE-ED25519',
await PUBLIC_KEY,
signature,
encoder.encode(timestamp + unknown),
);
}

View file

@ -0,0 +1,12 @@
name = "roles-bot"
type = "javascript"
account_id = "294bee38d448e390dab3757215c63f03"
compatibility_date = "2022-07-12"
main = "dist/worker.mjs"
[build]
command = "pnpm build"
[build.upload]
format = "modules"
main = "./worker.mjs"

191
packages/builders/LICENSE Normal file
View file

@ -0,0 +1,191 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View file

@ -0,0 +1 @@
Just [https://github.com/discordjs/discord.js/tree/main/packages/builders](https://github.com/discordjs/discord.js/tree/main/packages/builders) without validators and other bloated stuff.

View file

@ -0,0 +1,17 @@
{
"name": "builders",
"version": "0.0.1",
"main": "dist/index.mjs",
"types": "dist/index.d.ts",
"scripts": {
"build": "node scripts/build.mjs && tsc --declaration --emitDeclarationOnly src/index.ts --outDir dist"
},
"devDependencies": {
"esbuild": "^0.15.11",
"typescript": "^4.8.4"
},
"dependencies": {
"@discordjs/util": "^0.2.0",
"discord-api-types": "^0.37.37"
}
}

View file

@ -0,0 +1,38 @@
import esbuild from "esbuild";
import { rmSync, existsSync } from "node:fs";
import { join } from "node:path";
import { fileURLToPath } from "node:url";
const __dirname = fileURLToPath(new URL(".", import.meta.url));
if (existsSync(join(__dirname, "..", "dist")))
rmSync(join(__dirname, "..", "dist"), { recursive: true });
const watch = process.argv.includes("--watch");
const dev = process.argv.includes("--dev");
Promise.all([
esbuild.build({
bundle: true,
logLevel: "info",
format: "esm",
mainFields: ["browser", "module", "main"],
platform: "neutral",
target: "es2020",
entryPoints: ["./src/index.ts"],
outfile: "./dist/index.mjs",
sourcemap: dev,
charset: "utf8",
minify: !dev,
watch: watch,
}),
])
.catch((err) => {
console.error("Builders failed to build");
console.error(err.message);
})
.then(() => {
console.log(
watch ? "Waiting for your changes..." : "Builders has been built",
);
});

View file

@ -0,0 +1,326 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
// https://github.com/discordjs/discord/blob/main/packages/builders/src/components/ActionRow.ts
import {
type APIActionRowComponent,
ComponentType,
type APIMessageActionRowComponent,
type APIModalActionRowComponent,
type APIActionRowComponentTypes,
} from "discord-api-types/v10";
import { normalizeArray, type RestOrArray } from "../util/normalizeArray";
import { ComponentBuilder } from "./Component";
import { createComponentBuilder } from "./Components";
import type { ButtonBuilder } from "./button/Button";
import type { ChannelSelectMenuBuilder } from "./selectMenu/ChannelSelectMenu";
import type { MentionableSelectMenuBuilder } from "./selectMenu/MentionableSelectMenu";
import type { RoleSelectMenuBuilder } from "./selectMenu/RoleSelectMenu";
import type { StringSelectMenuBuilder } from "./selectMenu/StringSelectMenu";
import type { UserSelectMenuBuilder } from "./selectMenu/UserSelectMenu";
import type { TextInputBuilder } from "./textInput/TextInput";
export type MessageComponentBuilder =
| ActionRowBuilder<MessageActionRowComponentBuilder>
| MessageActionRowComponentBuilder;
export type ModalComponentBuilder =
| ActionRowBuilder<ModalActionRowComponentBuilder>
| ModalActionRowComponentBuilder;
export type MessageActionRowComponentBuilder =
| ButtonBuilder
| ChannelSelectMenuBuilder
| MentionableSelectMenuBuilder
| RoleSelectMenuBuilder
| StringSelectMenuBuilder
| UserSelectMenuBuilder;
export type ModalActionRowComponentBuilder = TextInputBuilder;
export type AnyComponentBuilder =
| MessageActionRowComponentBuilder
| ModalActionRowComponentBuilder;
/**
* Represents an action row component
*
* @typeParam T - The types of components this action row holds
*/
export class ActionRowBuilder<
T extends AnyComponentBuilder,
> extends ComponentBuilder<
APIActionRowComponent<
APIMessageActionRowComponent | APIModalActionRowComponent
>
> {
/**
* The components within this action row
*/
public readonly components: T[];
/**
* Creates a new action row from API data
*
* @param data - The API data to create this action row with
* @example
* Creating an action row from an API data object
* ```ts
* const actionRow = new ActionRowBuilder({
* components: [
* {
* custom_id: "custom id",
* label: "Type something",
* style: TextInputStyle.Short,
* type: ComponentType.TextInput,
* },
* ],
* });
* ```
* @example
* Creating an action row using setters and API data
* ```ts
* const actionRow = new ActionRowBuilder({
* components: [
* {
* custom_id: "custom id",
* label: "Click me",
* style: ButtonStyle.Primary,
* type: ComponentType.Button,
* },
* ],
* })
* .addComponents(button2, button3);
* ```
*/
public constructor({
components,
...data
}: Partial<APIActionRowComponent<APIActionRowComponentTypes>> = {}) {
super({ type: ComponentType.ActionRow, ...data });
this.components = (components?.map((component) =>
createComponentBuilder(component),
) ?? []) as T[];
}
/**
* Adds components to this action row.
*
* @param components - The components to add to this action row.
*/
public addComponents(...components: RestOrArray<T>) {
this.components.push(...normalizeArray(components));
return this;
}
/**
* Sets the components in this action row
*
* @param components - The components to set this row to
*/
public setComponents(...components: RestOrArray<T>) {
this.components.splice(
0,
this.components.length,
...normalizeArray(components),
);
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APIActionRowComponent<ReturnType<T["toJSON"]>> {
return {
...this.data,
components: this.components.map((component) => component.toJSON()),
} as APIActionRowComponent<ReturnType<T["toJSON"]>>;
}
}

View file

@ -0,0 +1,235 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { JSONEncodable } from "../util/JSONEncodable";
import type {
APIActionRowComponent,
APIActionRowComponentTypes,
APIBaseComponent,
ComponentType,
} from "discord-api-types/v10";
export type AnyAPIActionRowComponent =
| APIActionRowComponent<APIActionRowComponentTypes>
| APIActionRowComponentTypes;
/**
* Represents a discord component
*
* @typeParam DataType - The type of internal API data that is stored within the component
*/
export abstract class ComponentBuilder<
DataType extends Partial<
APIBaseComponent<ComponentType>
> = APIBaseComponent<ComponentType>,
> implements JSONEncodable<AnyAPIActionRowComponent>
{
/**
* The API data associated with this component
*/
public readonly data: Partial<DataType>;
/**
* Serializes this component to an API-compatible JSON object
*
* @remarks
* This method runs validations on the data before serializing it.
* As such, it may throw an error if the data is invalid.
*/
public abstract toJSON(): AnyAPIActionRowComponent;
public constructor(data: Partial<DataType>) {
this.data = data;
}
}

View file

@ -0,0 +1,265 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
ComponentType,
type APIMessageComponent,
type APIModalComponent,
} from "discord-api-types/v10";
import {
ActionRowBuilder,
type AnyComponentBuilder,
type MessageComponentBuilder,
type ModalComponentBuilder,
} from "./ActionRow";
import { ComponentBuilder } from "./Component";
import { ButtonBuilder } from "./button/Button";
import { ChannelSelectMenuBuilder } from "./selectMenu/ChannelSelectMenu";
import { MentionableSelectMenuBuilder } from "./selectMenu/MentionableSelectMenu";
import { RoleSelectMenuBuilder } from "./selectMenu/RoleSelectMenu";
import { StringSelectMenuBuilder } from "./selectMenu/StringSelectMenu";
import { UserSelectMenuBuilder } from "./selectMenu/UserSelectMenu";
import { TextInputBuilder } from "./textInput/TextInput";
export interface MappedComponentTypes {
[ComponentType.ActionRow]: ActionRowBuilder<AnyComponentBuilder>;
[ComponentType.Button]: ButtonBuilder;
[ComponentType.StringSelect]: StringSelectMenuBuilder;
[ComponentType.TextInput]: TextInputBuilder;
[ComponentType.UserSelect]: UserSelectMenuBuilder;
[ComponentType.RoleSelect]: RoleSelectMenuBuilder;
[ComponentType.MentionableSelect]: MentionableSelectMenuBuilder;
[ComponentType.ChannelSelect]: ChannelSelectMenuBuilder;
}
/**
* Factory for creating components from API data
*
* @param data - The api data to transform to a component class
*/
export function createComponentBuilder<T extends keyof MappedComponentTypes>(
// eslint-disable-next-line @typescript-eslint/sort-type-union-intersection-members
data: (APIModalComponent | APIMessageComponent) & { type: T },
): MappedComponentTypes[T];
export function createComponentBuilder<
C extends MessageComponentBuilder | ModalComponentBuilder,
>(data: C): C;
export function createComponentBuilder(
data: APIMessageComponent | APIModalComponent | MessageComponentBuilder,
): ComponentBuilder {
if (data instanceof ComponentBuilder) {
return data;
}
switch (data.type) {
case ComponentType.ActionRow:
return new ActionRowBuilder(data);
case ComponentType.Button:
return new ButtonBuilder(data);
case ComponentType.StringSelect:
return new StringSelectMenuBuilder(data);
case ComponentType.TextInput:
return new TextInputBuilder(data);
case ComponentType.UserSelect:
return new UserSelectMenuBuilder(data);
case ComponentType.RoleSelect:
return new RoleSelectMenuBuilder(data);
case ComponentType.MentionableSelect:
return new MentionableSelectMenuBuilder(data);
case ComponentType.ChannelSelect:
return new ChannelSelectMenuBuilder(data);
default:
// @ts-expect-error: This case can still occur if we get a newer unsupported component type
throw new Error(`Cannot properly serialize component type: ${data.type}`);
}
}

View file

@ -0,0 +1,314 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import {
ComponentType,
type APIMessageComponentEmoji,
type APIButtonComponent,
type APIButtonComponentWithURL,
type APIButtonComponentWithCustomId,
type ButtonStyle,
} from "discord-api-types/v10";
import { ComponentBuilder } from "../Component";
/**
* Represents a button component
*/
export class ButtonBuilder extends ComponentBuilder<APIButtonComponent> {
/**
* Creates a new button from API data
*
* @param data - The API data to create this button with
* @example
* Creating a button from an API data object
* ```ts
* const button = new ButtonBuilder({
* custom_id: 'a cool button',
* style: ButtonStyle.Primary,
* label: 'Click Me',
* emoji: {
* name: 'smile',
* id: '123456789012345678',
* },
* });
* ```
* @example
* Creating a button using setters and API data
* ```ts
* const button = new ButtonBuilder({
* style: ButtonStyle.Secondary,
* label: 'Click Me',
* })
* .setEmoji({ name: '🙂' })
* .setCustomId('another cool button');
* ```
*/
public constructor(data?: Partial<APIButtonComponent>) {
super({ type: ComponentType.Button, ...data });
}
/**
* Sets the style of this button
*
* @param style - The style of the button
*/
public setStyle(style: ButtonStyle) {
this.data.style = style;
return this;
}
/**
* Sets the URL for this button
*
* @remarks
* This method is only available to buttons using the `Link` button style.
* Only three types of URL schemes are currently supported: `https://`, `http://` and `discord://`
* @param url - The URL to open when this button is clicked
*/
public setURL(url: string) {
(this.data as APIButtonComponentWithURL).url = url;
return this;
}
/**
* Sets the custom id for this button
*
* @remarks
* This method is only applicable to buttons that are not using the `Link` button style.
* @param customId - The custom id to use for this button
*/
public setCustomId(customId: string) {
(this.data as APIButtonComponentWithCustomId).custom_id = customId;
return this;
}
/**
* Sets the emoji to display on this button
*
* @param emoji - The emoji to display on this button
*/
public setEmoji(emoji: APIMessageComponentEmoji) {
this.data.emoji = emoji;
return this;
}
/**
* Sets whether this button is disabled
*
* @param disabled - Whether to disable this button
*/
public setDisabled(disabled = true) {
this.data.disabled = disabled;
return this;
}
/**
* Sets the label for this button
*
* @param label - The label to display on this button
*/
public setLabel(label: string) {
this.data.label = label;
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APIButtonComponent {
return {
...this.data,
} as APIButtonComponent;
}
}

View file

@ -0,0 +1,255 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { APISelectMenuComponent } from "discord-api-types/v10";
import { ComponentBuilder } from "../Component";
export class BaseSelectMenuBuilder<
SelectMenuType extends APISelectMenuComponent,
> extends ComponentBuilder<SelectMenuType> {
/**
* Sets the placeholder for this select menu
*
* @param placeholder - The placeholder to use for this select menu
*/
public setPlaceholder(placeholder: string) {
this.data.placeholder = placeholder;
return this;
}
/**
* Sets the minimum values that must be selected in the select menu
*
* @param minValues - The minimum values that must be selected
*/
public setMinValues(minValues: number) {
this.data.min_values = minValues;
return this;
}
/**
* Sets the maximum values that must be selected in the select menu
*
* @param maxValues - The maximum values that must be selected
*/
public setMaxValues(maxValues: number) {
this.data.max_values = maxValues;
return this;
}
/**
* Sets the custom id for this select menu
*
* @param customId - The custom id to use for this select menu
*/
public setCustomId(customId: string) {
this.data.custom_id = customId;
return this;
}
/**
* Sets whether this select menu is disabled
*
* @param disabled - Whether this select menu is disabled
*/
public setDisabled(disabled = true) {
this.data.disabled = disabled;
return this;
}
public toJSON(): SelectMenuType {
return {
...this.data,
} as SelectMenuType;
}
}

View file

@ -0,0 +1,256 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type {
APIChannelSelectComponent,
ChannelType,
} from "discord-api-types/v10";
import { ComponentType } from "discord-api-types/v10";
import { normalizeArray, type RestOrArray } from "../../util/normalizeArray";
import { BaseSelectMenuBuilder } from "./BaseSelectMenu";
export class ChannelSelectMenuBuilder extends BaseSelectMenuBuilder<APIChannelSelectComponent> {
/**
* Creates a new select menu from API data
*
* @param data - The API data to create this select menu with
* @example
* Creating a select menu from an API data object
* ```ts
* const selectMenu = new ChannelSelectMenuBuilder({
* custom_id: 'a cool select menu',
* placeholder: 'select an option',
* max_values: 2,
* });
* ```
* @example
* Creating a select menu using setters and API data
* ```ts
* const selectMenu = new ChannelSelectMenuBuilder({
* custom_id: 'a cool select menu',
* })
* .addChannelTypes(ChannelType.GuildText, ChannelType.GuildAnnouncement)
* .setMinValues(2)
* ```
*/
public constructor(data?: Partial<APIChannelSelectComponent>) {
super({ ...data, type: ComponentType.ChannelSelect });
}
public addChannelTypes(...types: RestOrArray<ChannelType>) {
// eslint-disable-next-line no-param-reassign
types = normalizeArray(types);
this.data.channel_types ??= [];
this.data.channel_types.push(...types);
return this;
}
public setChannelTypes(...types: RestOrArray<ChannelType>) {
// eslint-disable-next-line no-param-reassign
types = normalizeArray(types);
this.data.channel_types ??= [];
this.data.channel_types.splice(0, this.data.channel_types.length, ...types);
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public override toJSON(): APIChannelSelectComponent {
return {
...this.data,
} as APIChannelSelectComponent;
}
}

View file

@ -0,0 +1,224 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { APIMentionableSelectComponent } from "discord-api-types/v10";
import { ComponentType } from "discord-api-types/v10";
import { BaseSelectMenuBuilder } from "./BaseSelectMenu";
export class MentionableSelectMenuBuilder extends BaseSelectMenuBuilder<APIMentionableSelectComponent> {
/**
* Creates a new select menu from API data
*
* @param data - The API data to create this select menu with
* @example
* Creating a select menu from an API data object
* ```ts
* const selectMenu = new MentionableSelectMenuBuilder({
* custom_id: 'a cool select menu',
* placeholder: 'select an option',
* max_values: 2,
* });
* ```
* @example
* Creating a select menu using setters and API data
* ```ts
* const selectMenu = new MentionableSelectMenuBuilder({
* custom_id: 'a cool select menu',
* })
* .setMinValues(1)
* ```
*/
public constructor(data?: Partial<APIMentionableSelectComponent>) {
super({ ...data, type: ComponentType.MentionableSelect });
}
}

View file

@ -0,0 +1,224 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { APIRoleSelectComponent } from "discord-api-types/v10";
import { ComponentType } from "discord-api-types/v10";
import { BaseSelectMenuBuilder } from "./BaseSelectMenu";
export class RoleSelectMenuBuilder extends BaseSelectMenuBuilder<APIRoleSelectComponent> {
/**
* Creates a new select menu from API data
*
* @param data - The API data to create this select menu with
* @example
* Creating a select menu from an API data object
* ```ts
* const selectMenu = new RoleSelectMenuBuilder({
* custom_id: 'a cool select menu',
* placeholder: 'select an option',
* max_values: 2,
* });
* ```
* @example
* Creating a select menu using setters and API data
* ```ts
* const selectMenu = new RoleSelectMenuBuilder({
* custom_id: 'a cool select menu',
* })
* .setMinValues(1)
* ```
*/
public constructor(data?: Partial<APIRoleSelectComponent>) {
super({ ...data, type: ComponentType.RoleSelect });
}
}

View file

@ -0,0 +1,348 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import { ComponentType } from "discord-api-types/v10";
import type {
APIStringSelectComponent,
APISelectMenuOption,
} from "discord-api-types/v10";
import { normalizeArray, type RestOrArray } from "../../util/normalizeArray";
import { BaseSelectMenuBuilder } from "./BaseSelectMenu";
import { StringSelectMenuOptionBuilder } from "./StringSelectMenuOption";
/**
* Represents a string select menu component
*/
export class StringSelectMenuBuilder extends BaseSelectMenuBuilder<APIStringSelectComponent> {
/**
* The options within this select menu
*/
public readonly options: StringSelectMenuOptionBuilder[];
/**
* Creates a new select menu from API data
*
* @param data - The API data to create this select menu with
* @example
* Creating a select menu from an API data object
* ```ts
* const selectMenu = new StringSelectMenuBuilder({
* custom_id: 'a cool select menu',
* placeholder: 'select an option',
* max_values: 2,
* options: [
* { label: 'option 1', value: '1' },
* { label: 'option 2', value: '2' },
* { label: 'option 3', value: '3' },
* ],
* });
* ```
* @example
* Creating a select menu using setters and API data
* ```ts
* const selectMenu = new StringSelectMenuBuilder({
* custom_id: 'a cool select menu',
* })
* .setMinValues(1)
* .addOptions({
* label: 'Catchy',
* value: 'catch',
* });
* ```
*/
public constructor(data?: Partial<APIStringSelectComponent>) {
const { options, ...initData } = data ?? {};
super({ ...initData, type: ComponentType.StringSelect });
this.options =
options?.map(
(option: APISelectMenuOption) =>
new StringSelectMenuOptionBuilder(option),
) ?? [];
}
/**
* Adds options to this select menu
*
* @param options - The options to add to this select menu
* @returns
*/
public addOptions(
...options: RestOrArray<APISelectMenuOption | StringSelectMenuOptionBuilder>
) {
// eslint-disable-next-line no-param-reassign
options = normalizeArray(options);
this.options.push(
...options.map((option) =>
option instanceof StringSelectMenuOptionBuilder
? option
: new StringSelectMenuOptionBuilder(option),
),
);
return this;
}
/**
* Sets the options on this select menu
*
* @param options - The options to set on this select menu
*/
public setOptions(
...options: RestOrArray<APISelectMenuOption | StringSelectMenuOptionBuilder>
) {
return this.spliceOptions(0, this.options.length, ...options);
}
/**
* Removes, replaces, or inserts options in the string select menu.
*
* @remarks
* This method behaves similarly
* to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice | Array.prototype.splice}.
*
* It's useful for modifying and adjusting order of the already-existing options of a string select menu.
* @example
* Remove the first option
* ```ts
* selectMenu.spliceOptions(0, 1);
* ```
* @example
* Remove the first n option
* ```ts
* const n = 4
* selectMenu.spliceOptions(0, n);
* ```
* @example
* Remove the last option
* ```ts
* selectMenu.spliceOptions(-1, 1);
* ```
* @param index - The index to start at
* @param deleteCount - The number of options to remove
* @param options - The replacing option objects or builders
*/
public spliceOptions(
index: number,
deleteCount: number,
...options: RestOrArray<APISelectMenuOption | StringSelectMenuOptionBuilder>
) {
// eslint-disable-next-line no-param-reassign
options = normalizeArray(options);
const clone = [...this.options];
clone.splice(
index,
deleteCount,
...options.map((option) =>
option instanceof StringSelectMenuOptionBuilder
? option
: new StringSelectMenuOptionBuilder(option),
),
);
this.options.splice(0, this.options.length, ...clone);
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public override toJSON(): APIStringSelectComponent {
return {
...this.data,
options: this.options.map((option) => option.toJSON()),
} as APIStringSelectComponent;
}
}

View file

@ -0,0 +1,288 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { JSONEncodable } from "../../util/JSONEncodable";
import type {
APIMessageComponentEmoji,
APISelectMenuOption,
} from "discord-api-types/v10";
/**
* Represents an option within a string select menu component
*/
export class StringSelectMenuOptionBuilder
implements JSONEncodable<APISelectMenuOption>
{
/**
* Creates a new string select menu option from API data
*
* @param data - The API data to create this string select menu option with
* @example
* Creating a string select menu option from an API data object
* ```ts
* const selectMenuOption = new SelectMenuOptionBuilder({
* label: 'catchy label',
* value: '1',
* });
* ```
* @example
* Creating a string select menu option using setters and API data
* ```ts
* const selectMenuOption = new SelectMenuOptionBuilder({
* default: true,
* value: '1',
* })
* .setLabel('woah')
* ```
*/
public constructor(public data: Partial<APISelectMenuOption> = {}) {}
/**
* Sets the label of this option
*
* @param label - The label to show on this option
*/
public setLabel(label: string) {
this.data.label = label;
return this;
}
/**
* Sets the value of this option
*
* @param value - The value of this option
*/
public setValue(value: string) {
this.data.value = value;
return this;
}
/**
* Sets the description of this option
*
* @param description - The description of this option
*/
public setDescription(description: string) {
this.data.description = description;
return this;
}
/**
* Sets whether this option is selected by default
*
* @param isDefault - Whether this option is selected by default
*/
public setDefault(isDefault = true) {
this.data.default = isDefault;
return this;
}
/**
* Sets the emoji to display on this option
*
* @param emoji - The emoji to display on this option
*/
public setEmoji(emoji: APIMessageComponentEmoji) {
this.data.emoji = emoji;
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APISelectMenuOption {
return {
...this.data,
} as APISelectMenuOption;
}
}

View file

@ -0,0 +1,224 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { APIUserSelectComponent } from "discord-api-types/v10";
import { ComponentType } from "discord-api-types/v10";
import { BaseSelectMenuBuilder } from "./BaseSelectMenu";
export class UserSelectMenuBuilder extends BaseSelectMenuBuilder<APIUserSelectComponent> {
/**
* Creates a new select menu from API data
*
* @param data - The API data to create this select menu with
* @example
* Creating a select menu from an API data object
* ```ts
* const selectMenu = new UserSelectMenuBuilder({
* custom_id: 'a cool select menu',
* placeholder: 'select an option',
* max_values: 2,
* });
* ```
* @example
* Creating a select menu using setters and API data
* ```ts
* const selectMenu = new UserSelectMenuBuilder({
* custom_id: 'a cool select menu',
* })
* .setMinValues(1)
* ```
*/
public constructor(data?: Partial<APIUserSelectComponent>) {
super({ ...data, type: ComponentType.UserSelect });
}
}

View file

@ -0,0 +1,336 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import type { JSONEncodable } from "../../util/JSONEncodable";
import type { Equatable } from "../../util/Equatable";
import {
ComponentType,
type TextInputStyle,
type APITextInputComponent,
} from "discord-api-types/v10";
import { ComponentBuilder } from "../Component";
export class TextInputBuilder
extends ComponentBuilder<APITextInputComponent>
implements
Equatable<APITextInputComponent | JSONEncodable<APITextInputComponent>>
{
/**
* Creates a new text input from API data
*
* @param data - The API data to create this text input with
* @example
* Creating a select menu option from an API data object
* ```ts
* const textInput = new TextInputBuilder({
* custom_id: 'a cool select menu',
* label: 'Type something',
* style: TextInputStyle.Short,
* });
* ```
* @example
* Creating a select menu option using setters and API data
* ```ts
* const textInput = new TextInputBuilder({
* label: 'Type something else',
* })
* .setCustomId('woah')
* .setStyle(TextInputStyle.Paragraph);
* ```
*/
public constructor(
data?: APITextInputComponent & { type?: ComponentType.TextInput },
) {
super({ type: ComponentType.TextInput, ...data });
}
/**
* Sets the custom id for this text input
*
* @param customId - The custom id of this text input
*/
public setCustomId(customId: string) {
this.data.custom_id = customId;
return this;
}
/**
* Sets the label for this text input
*
* @param label - The label for this text input
*/
public setLabel(label: string) {
this.data.label = label;
return this;
}
/**
* Sets the style for this text input
*
* @param style - The style for this text input
*/
public setStyle(style: TextInputStyle) {
this.data.style = style;
return this;
}
/**
* Sets the minimum length of text for this text input
*
* @param minLength - The minimum length of text for this text input
*/
public setMinLength(minLength: number) {
this.data.min_length = minLength;
return this;
}
/**
* Sets the maximum length of text for this text input
*
* @param maxLength - The maximum length of text for this text input
*/
public setMaxLength(maxLength: number) {
this.data.max_length = maxLength;
return this;
}
/**
* Sets the placeholder of this text input
*
* @param placeholder - The placeholder of this text input
*/
public setPlaceholder(placeholder: string) {
this.data.placeholder = placeholder;
return this;
}
/**
* Sets the value of this text input
*
* @param value - The value for this text input
*/
public setValue(value: string) {
this.data.value = value;
return this;
}
/**
* Sets whether this text input is required
*
* @param required - Whether this text input is required
*/
public setRequired(required = true) {
this.data.required = required;
return this;
}
/**
* {@inheritDoc ComponentBuilder.toJSON}
*/
public toJSON(): APITextInputComponent {
return {
...this.data,
} as APITextInputComponent;
}
/**
* {@inheritDoc Equatable.equals}
*/
public equals(
other: APITextInputComponent | JSONEncodable<APITextInputComponent>,
): boolean {
// imagine using this lol
return true;
}
}

View file

@ -0,0 +1,225 @@
/**
* Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
Copyright 2021 Noel Buechler
Copyright 2021 Vlad Frangu
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
export * from "./messages/embed/Embed.js";
export * from "./components/ActionRow";
export * from "./components/button/Button";
export * from "./components/Component";
export * from "./components/Components";
export * from "./components/textInput/TextInput";
export * from "./components/selectMenu/BaseSelectMenu";
export * from "./components/selectMenu/ChannelSelectMenu";
export * from "./components/selectMenu/MentionableSelectMenu";
export * from "./components/selectMenu/RoleSelectMenu";
export * from "./components/selectMenu/StringSelectMenu";
// TODO: Remove those aliases in v2
export {
/**
* @deprecated Will be removed in the next major version, use {@link StringSelectMenuBuilder} instead.
*/
StringSelectMenuBuilder as SelectMenuBuilder,
} from "./components/selectMenu/StringSelectMenu";
export {
/**
* @deprecated Will be removed in the next major version, use {@link StringSelectMenuOptionBuilder} instead.
*/
StringSelectMenuOptionBuilder as SelectMenuOptionBuilder,
} from "./components/selectMenu/StringSelectMenuOption";
export * from "./components/selectMenu/StringSelectMenuOption";
export * from "./components/selectMenu/UserSelectMenu";
export * from "./util/componentUtil";
export * from "./util/normalizeArray";

View file

@ -0,0 +1,262 @@
import type {
APIEmbed,
APIEmbedAuthor,
APIEmbedField,
APIEmbedFooter,
APIEmbedImage,
} from "discord-api-types/v10";
import { normalizeArray, type RestOrArray } from "../../util/normalizeArray.js";
export type RGBTuple = [red: number, green: number, blue: number];
export interface IconData {
/**
* The URL of the icon
*/
iconURL?: string;
/**
* The proxy URL of the icon
*/
proxyIconURL?: string;
}
export type EmbedAuthorData = IconData &
Omit<APIEmbedAuthor, "icon_url" | "proxy_icon_url">;
export type EmbedAuthorOptions = Omit<EmbedAuthorData, "proxyIconURL">;
export type EmbedFooterData = IconData &
Omit<APIEmbedFooter, "icon_url" | "proxy_icon_url">;
export type EmbedFooterOptions = Omit<EmbedFooterData, "proxyIconURL">;
export interface EmbedImageData extends Omit<APIEmbedImage, "proxy_url"> {
/**
* The proxy URL for the image
*/
proxyURL?: string;
}
/**
* Represents a embed in a message (image/video preview, rich embed, etc.)
*/
export class EmbedBuilder {
public readonly data: APIEmbed;
public constructor(data: APIEmbed = {}) {
this.data = { ...data };
if (data.timestamp)
this.data.timestamp = new Date(data.timestamp).toISOString();
}
/**
* Appends fields to the embed
*
* @remarks
* This method accepts either an array of fields or a variable number of field parameters.
* The maximum amount of fields that can be added is 25.
* @example
* Using an array
* ```ts
* const fields: APIEmbedField[] = ...;
* const embed = new EmbedBuilder()
* .addFields(fields);
* ```
* @example
* Using rest parameters (variadic)
* ```ts
* const embed = new EmbedBuilder()
* .addFields(
* { name: 'Field 1', value: 'Value 1' },
* { name: 'Field 2', value: 'Value 2' },
* );
* ```
* @param fields - The fields to add
*/
public addFields(...fields: RestOrArray<APIEmbedField>): this {
// eslint-disable-next-line no-param-reassign
fields = normalizeArray(fields);
if (this.data.fields) this.data.fields.push(...fields);
else this.data.fields = fields;
return this;
}
/**
* Removes, replaces, or inserts fields in the embed.
*
* @remarks
* This method behaves similarly
* to {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/splice | Array.prototype.splice}.
* The maximum amount of fields that can be added is 25.
*
* It's useful for modifying and adjusting order of the already-existing fields of an embed.
* @example
* Remove the first field
* ```ts
* embed.spliceFields(0, 1);
* ```
* @example
* Remove the first n fields
* ```ts
* const n = 4
* embed.spliceFields(0, n);
* ```
* @example
* Remove the last field
* ```ts
* embed.spliceFields(-1, 1);
* ```
* @param index - The index to start at
* @param deleteCount - The number of fields to remove
* @param fields - The replacing field objects
*/
public spliceFields(
index: number,
deleteCount: number,
...fields: APIEmbedField[]
): this {
if (this.data.fields)
this.data.fields.splice(index, deleteCount, ...fields);
else this.data.fields = fields;
return this;
}
/**
* Sets the embed's fields
*
* @remarks
* This method is an alias for {@link EmbedBuilder.spliceFields}. More specifically,
* it splices the entire array of fields, replacing them with the provided fields.
*
* You can set a maximum of 25 fields.
* @param fields - The fields to set
*/
public setFields(...fields: RestOrArray<APIEmbedField>) {
this.spliceFields(
0,
this.data.fields?.length ?? 0,
...normalizeArray(fields),
);
return this;
}
/**
* Sets the author of this embed
*
* @param options - The options for the author
*/
public setAuthor(options: EmbedAuthorOptions | null): this {
if (options === null) {
this.data.author = undefined;
return this;
}
this.data.author = {
name: options.name,
url: options.url,
icon_url: options.iconURL,
};
return this;
}
/**
* Sets the color of this embed
*
* @param color - The color of the embed
*/
public setColor(color: RGBTuple | number | null): this {
if (Array.isArray(color)) {
const [red, green, blue] = color;
this.data.color = (red << 16) + (green << 8) + blue;
return this;
}
this.data.color = color ?? undefined;
return this;
}
/**
* Sets the description of this embed
*
* @param description - The description
*/
public setDescription(description: string | null): this {
this.data.description = description ?? undefined;
return this;
}
/**
* Sets the footer of this embed
*
* @param options - The options for the footer
*/
public setFooter(options: EmbedFooterOptions | null): this {
if (options === null) {
this.data.footer = undefined;
return this;
}
this.data.footer = { text: options.text, icon_url: options.iconURL };
return this;
}
/**
* Sets the image of this embed
*
* @param url - The URL of the image
*/
public setImage(url: string | null): this {
this.data.image = url ? { url } : undefined;
return this;
}
/**
* Sets the thumbnail of this embed
*
* @param url - The URL of the thumbnail
*/
public setThumbnail(url: string | null): this {
this.data.thumbnail = url ? { url } : undefined;
return this;
}
/**
* Sets the timestamp of this embed
*
* @param timestamp - The timestamp or date
*/
public setTimestamp(timestamp: number | null = Date.now()): this {
this.data.timestamp = timestamp
? new Date(timestamp).toISOString()
: undefined;
return this;
}
/**
* Sets the title of this embed
*
* @param title - The title
*/
public setTitle(title: string | null): this {
this.data.title = title ?? undefined;
return this;
}
/**
* Sets the URL of this embed
*
* @param url - The URL
*/
public setURL(url: string | null): this {
this.data.url = url ?? undefined;
return this;
}
/**
* Transforms the embed to a plain object
*/
public toJSON(): APIEmbed {
return { ...this.data };
}
}

View file

@ -0,0 +1,27 @@
/**
* Represents a structure that can be checked against another
* given structure for equality
*
* @typeParam T - The type of object to compare the current object to
*/
export interface Equatable<T> {
/**
* Whether or not this is equal to another structure
*/
equals(other: T): boolean;
}
/**
* Indicates if an object is equatable or not.
*
* @param maybeEquatable - The object to check against
*/
export function isEquatable(
maybeEquatable: unknown,
): maybeEquatable is Equatable<unknown> {
return (
maybeEquatable !== null &&
typeof maybeEquatable === "object" &&
"equals" in maybeEquatable
);
}

View file

@ -0,0 +1,26 @@
/**
* Represents an object capable of representing itself as a JSON object
*
* @typeParam T - The JSON type corresponding to {@link JSONEncodable.toJSON} outputs.
*/
export interface JSONEncodable<T> {
/**
* Transforms this object to its JSON format
*/
toJSON(): T;
}
/**
* Indicates if an object is encodable or not.
*
* @param maybeEncodable - The object to check against
*/
export function isJSONEncodable(
maybeEncodable: unknown,
): maybeEncodable is JSONEncodable<unknown> {
return (
maybeEncodable !== null &&
typeof maybeEncodable === "object" &&
"toJSON" in maybeEncodable
);
}

View file

@ -0,0 +1,14 @@
import type { APIEmbed } from "discord-api-types/v10";
export function embedLength(data: APIEmbed) {
return (
(data.title?.length ?? 0) +
(data.description?.length ?? 0) +
(data.fields?.reduce(
(prev, curr) => prev + curr.name.length + curr.value.length,
0,
) ?? 0) +
(data.footer?.text.length ?? 0) +
(data.author?.name.length ?? 0)
);
}

View file

@ -0,0 +1,6 @@
export function normalizeArray<T>(arr: RestOrArray<T>): T[] {
if (Array.isArray(arr[0])) return arr[0];
return arr as T[];
}
export type RestOrArray<T> = T[] | [T[]];

View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Jozef Steinhübl
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View file

@ -0,0 +1 @@
Client for [Redis API](../../apps/redis-api/)

Some files were not shown because too many files have changed in this diff Show more