diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml
index b350cc0ec..551eb65cc 100644
--- a/.github/workflows/deploy_docs.yml
+++ b/.github/workflows/deploy_docs.yml
@@ -1,4 +1,4 @@
-name: deploy dev docs
+name: Deploy dev docs to nyxx.l7ssha.xyz
on:
push:
diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml
index 0329025b5..a99b14e5b 100644
--- a/.github/workflows/integration_tests.yml
+++ b/.github/workflows/integration_tests.yml
@@ -1,4 +1,4 @@
-name: unit tests
+name: Integration tests
on:
push:
@@ -6,64 +6,13 @@ on:
- main
jobs:
- analyze:
- name: Analyze
- runs-on: ubuntu-latest
- env:
- TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
- steps:
- - name: Setup Dart Action
- uses: dart-lang/setup-dart@v1
-
- - name: Checkout
- uses: actions/checkout@v2.3.4
-
- - name: Cache
- uses: actions/cache@v2
- with:
- path: ~/.pub-cache
- key: ${{ runner.os }}-pubspec-${{ hashFiles('**/pubspec.lock') }}
- restore-keys: |
- ${{ runner.os }}-pubspec-
-
- - name: Install dependencies
- run: dart pub get
-
- - name: Analyze project source
- run: dart analyze
-
- format:
- name: Format
- runs-on: ubuntu-latest
- env:
- TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
- steps:
- - name: Setup Dart Action
- uses: dart-lang/setup-dart@v1
-
- - name: Checkout
- uses: actions/checkout@v2.3.4
-
- - name: Cache
- uses: actions/cache@v2
- with:
- path: ~/.pub-cache
- key: ${{ runner.os }}-pubspec-${{ hashFiles('**/pubspec.lock') }}
- restore-keys: |
- ${{ runner.os }}-pubspec-
-
- - name: Install dependencies
- run: dart pub get
-
- - name: Format
- run: dart format --set-exit-if-changed -l 160 ./lib
-
tests:
- needs: [ format, analyze ]
- name: Tests
+ name: Run integration tests
runs-on: ubuntu-latest
env:
TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
+ TEST_TEXT_CHANNEL: ${{ secrets.TEST_TEXT_CHANNEL }}
+ TEST_GUILD: ${{ secrets.TEST_GUILD }}
steps:
- name: Setup Dart Action
uses: dart-lang/setup-dart@v1
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index a4ed848f3..9573a04b2 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,4 +1,4 @@
-name: publish
+name: Publish nyxx to pub.dev
on:
push:
diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml
index 6aee520af..5a7f564ee 100644
--- a/.github/workflows/unit_tests.yml
+++ b/.github/workflows/unit_tests.yml
@@ -1,4 +1,4 @@
-name: unit tests
+name: Run unit tests
on:
push:
@@ -8,10 +8,8 @@ on:
jobs:
analyze:
- name: Analyze
+ name: Analyze project source
runs-on: ubuntu-latest
- env:
- TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
steps:
- name: Setup Dart Action
uses: dart-lang/setup-dart@v1
@@ -34,10 +32,8 @@ jobs:
run: dart analyze
format:
- name: Format
+ name: Check project formatting
runs-on: ubuntu-latest
- env:
- TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
steps:
- name: Setup Dart Action
uses: dart-lang/setup-dart@v1
@@ -61,10 +57,12 @@ jobs:
tests:
needs: [ format, analyze ]
- name: Tests
+ name: Unit tests
runs-on: ubuntu-latest
env:
TEST_TOKEN: ${{ secrets.TEST_TOKEN }}
+ TEST_TEXT_CHANNEL: ${{ secrets.TEST_TEXT_CHANNEL }}
+ TEST_GUILD: ${{ secrets.TEST_GUILD }}
steps:
- name: Setup Dart Action
uses: dart-lang/setup-dart@v1
diff --git a/.gitignore b/.gitignore
index 04ab2398c..a5b616259 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,29 +1,53 @@
-local/
-.atom/
+# See https://www.dartlang.org/guides/libraries/private-files
+
+# Files and directories created by pub
+.dart_tool/
+.packages
+build/
+pubspec.lock
+
+# Pubspec overrides for local testing
+pubspec_overrides.yaml
+
+# Directory created by dartdoc
+doc/api/
+
+# dotenv environment variables file
+.env*
+
+# Avoid committing generated Javascript files:
+*.dart.js
+*.info.json # Produced by the --dump-info flag.
+*.js # When generated by dart2js. Don't specify *.js if your
+ # project includes source files written in JavaScript.
+*.js_
+*.js.deps
+*.js.map
+
+.flutter-plugins
+.flutter-plugins-dependencies
+
+# IDE configuration folders
.vscode/
+.atom/
+.idea/
+*.iml
+
+# Test output and coverage
+log.txt
+coverage/
+
+local/
index.html
docs/
.buildlog
-.packages
.project
.pub
-**/build
**/packages
-*.dart.js
-*.part.js
-*.js.deps
-*.js.map
-*.info.json
-doc/api/
-pubspec.lock
-*.iml
-.idea
*~
*#
.#*
-.dart_tool/
/README.html
-/log.txt
/nyxx.wiki/
/test/private.dart
/publish_docs.sh
@@ -32,8 +56,3 @@ pubspec.lock
private-*.dart
test-*.dart
[Rr]pc*
-**/doc/api/**
-**/coverage/**
-coverage.json
-lcov.info
-.vscode/
diff --git a/.pubignore b/.pubignore
deleted file mode 100644
index 8c082ddfe..000000000
--- a/.pubignore
+++ /dev/null
@@ -1,40 +0,0 @@
-local/
-.atom/
-.vscode/
-index.html
-docs/
-.buildlog
-.packages
-.project
-.pub
-**/build
-**/packages
-*.dart.js
-*.part.js
-*.js.deps
-*.js.map
-*.info.json
-doc/api/
-pubspec.lock
-*.iml
-.idea
-*~
-*#
-.#*
-.dart_tool/
-/README.html
-/log.txt
-/nyxx.wiki/
-/test/private.dart
-/publish_docs.sh
-/test/mirrors.dart
-/private
-private-*.dart
-test-*.dart
-[Rr]pc*
-**/doc/api/**
-**/coverage/**
-coverage.json
-lcov.info
-.github/
-.vscode/
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 672e5e677..60a65d5e9 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,66 @@
+## 6.0.0
+__16.10.2023__
+
+- rewrite: The entire library has been rewritten from the ground up. No pre-`6.0.0` code is compatible.
+ To explore the rewrite, check out [the API documentation](https://pub.dev/documentation/nyxx) or the [documentation website](https://nyxx.l7ssha.xyz).
+ For help migrating, use the [migration tool](https://github.com/abitofevrything/nyxx-migration-script) or join [our Discord server](https://discord.gg/nyxx) for additional help.
+
+#### Changes since 6.0.0-dev.3
+- bug: Fix `ModalBuilder` having the incorrect data type.
+- feat: Add the new `state` field to `ActivityBuilder`.
+- bug: Fix `activities` not being sent in the presence update payload.
+- bug: Fix casts when parsing `Snowflake`s triggering errors when using ETF.
+- bug: Fix incorrect payload preventing the client from muting/deafening itself.
+- bug: Correctly export `NyxxPluginState`.
+- feat: Implement all new features since the start of the rewrite (including premium subscriptions).
+- bug: Fix incorrect parsing of `MessageUpdateEvent`s.
+- feat: Add `logger` to plugins and make `name` inferred from `runtimeType` by default.
+
+## 6.0.0-dev.3
+__16.09.2023__
+
+- rewrite: Interaction responses now throw errors instead of using assertions.
+- rewrite: Improved plugin interface with support for plugin state and a simpler API.
+- feat: Added constructors to most builders with multiple configurations.
+- feat: Added support for authenticating via OAuth2.
+- feat: Added `HttpHandler.onRateLimit` for tracking client rate limiting.
+- feat: Parse emoji in reaction events.
+- feat: Allow specifying `stdout` and `stderr` in `Logging`.
+- feat: Add `NyxxRest.user` to get the current user.
+- feat: `Attachment` now implements `CdnAsset` for easier fetching.
+- bug: Fixed emoji in SelectMenuBuilder not being sent correctly.
+- bug: Fixed parsing members in interaction data.
+- bug: `DiscordColor` did not allow a value of `0xffffff` (white).
+- bug: Fixed parsing role mentions as role objects in messages.
+
+
+## 6.0.0-dev.2
+__24.08.2023__
+
+- rewrite: Changed `MessageBuilder.embeds` and `MessageUpdateBuilder.embeds` to use a new `EmbedBuilder` instead of `Embed` objects.
+- rewrite: Changed all builders to be mutable.
+- rewrite: Implement the interactions & message components API.
+- rewrite: `ActivityBuilder` is now exported.
+- rewrite: Fixed some typos: `ChannelManager.parseForumChanel` -> `ChannelManager.parseForumChannel` and `chanel` -> `channel` in the docs for `VoiceChannel.videoQualityMode`.
+- rewrite: Added wrappers around CDN endpoints and assets.
+- feat: Added `Permissions.allPermissions`, the set of permission flags with all permissions.
+- feat: Added `HttpHandler.latency`, `HttpHandler.realLatency`, `Gateway.latency` and `Shard.latency` for tracking the client's latency.
+- feat: `Flags` now has the `~` and the `^` operators.
+- feat: Added `HttpHandler.onRequest` and `HttpHandler.onResponse` streams for tracking HTTP requests and responses.
+- bug: Fixed `MessageUpdateEvent`s causing a parsing error.
+- bug: Fixed classes creating uncaught async errors when `toString()` was invoked on them.
+- bug: Empty caches are no longer stored.
+- bug: Fixed stickers causing a parsing error.
+- bug: Fixed rate limits not applying correctly when multiple requests were queued.
+- bug: Fixed `applyGlobalRatelimit` in `HttpRequest` not doing anything.
+
+## 6.0.0-dev.1
+__03.07.2023__
+
+- rewrite: The entire library has been rewritten from the ground up. No pre-`6.0.0-dev.1` code is compatible.
+ Join our Discord server for updates concerning the migration path and help upgrading.
+ For now, check out the new examples and play around with the rewrite to get a feel for it.
+
## 5.1.1
__11.08.2023__
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 260d84064..70c5a2f30 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -21,6 +21,11 @@ All issues marked with 'help-needed' badge are free to be picked up by any membe
Pull requests should be descriptive about changes that are made.
If adding new functionality or modifying existing, documentation should be added/modified to reflect changes.
+When submitting a pull request, please, always create a new branch with the following format; `[scope]/name`.
+`[scope]` must be the type of changes your PR alter. E.g, when adding a new feature, it must be `feat/`, for a bugfix, `bug/` or `fix/`, etc..
+
+Do not push your changes on the three main branches, it can messes up with rebases.
+
## Coding style
We attempt to conform [Effective Dart Coding Style](https://dart.dev/guides/language/effective-dart/style) where possible.
diff --git a/README.md b/README.md
index e13a151b7..21947bbf4 100644
--- a/README.md
+++ b/README.md
@@ -1,42 +1,28 @@
# nyxx
-[![Discord Shield](https://discordapp.com/api/guilds/846136758470443069/widget.png?style=shield)](https://discord.gg/nyxx)
-[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dartlang.org/packages/nyxx)
-[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://www.dartdocs.org/documentation/nyxx/latest/)
+[![Discord](https://discordapp.com/api/guilds/846136758470443069/widget.png?style=shield)](https://discord.gg/nyxx)
+[![pub](https://img.shields.io/pub/v/nyxx.svg)](https://pub.dev/packages/nyxx)
+[![documentation](https://img.shields.io/badge/Documentation-nyxx-yellow.svg)](https://pub.dev/documentation/nyxx/latest/)
-Simple, robust framework for creating discord bots for Dart language.
+A complete, robust and efficient wrapper around Discord's API for bots & applications.
-
+To get started using nyxx, follow our [getting started guide](https://nyxx.l7ssha.xyz/docs/guides/writing_your_first_bot) to write your first bot.
-### Features
-
-- **Slash commands support**
- Supports and provides easy API for creating and handling slash commands
-- **Commands framework included**
- A fast way to create a bot with command support. Implementing the framework is simple - and everything is done automatically.
-- **Cross Platform**
- Nyxx works on the command line, in the browser, and on mobile devices.
-- **Fine Control**
- Nyxx allows you to control every outgoing HTTP request or WebSocket message.
-- **Complete**
- Nyxx supports nearly all Discord API endpoints.
+If you're already familiar with Discord's API, here's a quick example to get you started:
+```dart
+import 'package:nyxx/nyxx.dart';
+void main() async {
+ final client = await Nyxx.connectGateway('', GatewayIntents.allUnprivileged);
-## Quick example
+ final botUser = await client.users.fetchCurrentUser();
-Basic usage:
-```dart
-void main() {
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent)
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen for message events
- bot.eventsWs.onMessageReceived.listen((event) async {
- if (event.message.content == "!ping") {
- await event.message.channel.sendMessage(MessageBuilder.content("Pong!"));
+ client.onMessageCreate.listen((event) async {
+ if (event.mentions.contains(botUser)) {
+ await event.message.channel.sendMessage(MessageBuilder(
+ content: 'You mentioned me!',
+ replyId: event.message.id,
+ ));
}
});
}
@@ -44,43 +30,39 @@ void main() {
## Other nyxx packages
-- [nyxx_interactions](https://github.com/nyxx-discord/nyxx_interactions)
-- [nyxx_commander](https://github.com/nyxx-discord/nyxx_commander)
-- [nyxx_extensions](https://github.com/nyxx-discord/nyxx_extensions)
-- [nyxx_lavalink](https://github.com/nyxx-discord/nyxx_lavalink)
-- [nyxx_pagination](https://github.com/nyxx-discord/nyxx_pagination)
+- [nyxx_commands](https://pub.dev/packages/nyxx_commands): A command framework for handling both simple & complex commands.
+- [nyxx_pagination](https://pub.dev/packages/nyxx_pagination): Pagination support for nyxx.
+- [nyxx_lavalink](https://pub.dev/packages/nyxx_lavalink): Lavalink support for playing audio in voice channels.
+- [nyxx_extensions](https://pub.dev/packages/nyxx_extensions): Miscellaneous helpers for common situations when developing bots.
## More examples
-Nyxx examples can be found [here](https://github.com/nyxx-discord/nyxx/tree/dev/example).
-
-### Example bots
-- [Running on Dart](https://github.com/l7ssha/running_on_dart)
+- More examples can be found in our GitHub repository [here](https://github.com/nyxx-discord/nyxx/tree/main/example).
+- [Running on Dart](https://github.com/nyxx-discord/running_on_dart) is a complete example of a bot written with nyxx.
-## Documentation, help and examples
+## Additional documentation & help
-**Dartdoc documentation for latest stable version is hosted on [pub](https://www.dartdocs.org/documentation/nyxx/latest/)**
+The API documentation for the latest stable version can be found on [pub](https://pub.dev/documentation/nyxx).
-#### [Docs and wiki](https://nyxx.l7ssha.xyz)
-You can read docs and wiki articles for latest stable version on my website. This website also hosts docs for latest
-dev changes to framework (`dev` branch)
+### [Docs and wiki](https://nyxx.l7ssha.xyz)
+Tutorials and wiki articles are hosted here, as well as API documentation for development versions from GitHub.
-#### [Official nyxx discord server](https://discord.gg/nyxx)
-If you need assistance in developing bot using nyxx you can join official nyxx discord guild.
+### [Official nyxx Discord server](https://discord.gg/nyxx)
+Our Discord server is where you can get help for any nyxx packages, as well as release announcements and discussions about the library.
-#### [Discord API docs](https://discordapp.com/developers/docs/intro)
-Discord API documentation features rich descriptions about all topics that nyxx covers.
+### [Discord API docs](https://discord.dev/)
+Discord's API documentation details what nyxx implements & provides more detailed explanations of certain topics.
-#### [Discord API Guild](https://discord.gg/discord-api)
+### [Discord API Server](https://discord.gg/discord-api)
The unofficial guild for Discord Bot developers. To get help with nyxx check `#dart_nyxx` channel.
-#### [Dartdocs](https://www.dartdocs.org/documentation/nyxx/latest/)
+### [Pub.dev docs](https://pub.dev/documentation/nyxx)
The dartdocs page will always have the documentation for the latest release.
## Contributing to Nyxx
-Read [contributing document](https://github.com/nyxx-discord/nyxx/blob/dev/CONTRIBUTING.md)
+Read the [contributing document](https://github.com/nyxx-discord/nyxx/blob/dev/CONTRIBUTING.md)
## Credits
- * [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx).
+- Thanks to [Hackzzila's](https://github.com/Hackzzila) for [nyx](https://github.com/Hackzzila/nyx), the original project nyxx was forked from.
diff --git a/example/adding_roles.dart b/example/adding_roles.dart
new file mode 100644
index 000000000..5a708338b
--- /dev/null
+++ b/example/adding_roles.dart
@@ -0,0 +1,23 @@
+import 'dart:io';
+
+import 'package:nyxx/nyxx.dart';
+
+void main() async {
+ final client = await Nyxx.connectGateway(
+ Platform.environment['TOKEN']!,
+ GatewayIntents.allUnprivileged | GatewayIntents.messageContent,
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
+
+ client.onMessageCreate.listen((event) async {
+ if (!event.message.content.startsWith('!new-role')) return;
+ if (event.guild == null) return;
+
+ final role = await event.guild!.roles.create(RoleBuilder(
+ name: 'Test role',
+ color: DiscordColor.fromRgb(66, 165, 245),
+ ));
+
+ await event.member!.addRole(role.id);
+ });
+}
diff --git a/example/application_commands.dart b/example/application_commands.dart
new file mode 100644
index 000000000..178b7cc1c
--- /dev/null
+++ b/example/application_commands.dart
@@ -0,0 +1,29 @@
+import 'dart:io';
+
+import 'package:nyxx/nyxx.dart';
+
+void main() async {
+ final client = await Nyxx.connectGateway(
+ Platform.environment['TOKEN']!,
+ GatewayIntents.allUnprivileged,
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
+
+ // Create a new command named "ping" that takes no arguments.
+ // You don't need to create commands every time your client starts - just once
+ // when the command is created or updated is sufficient.
+ await client.commands.create(
+ ApplicationCommandBuilder.chatInput(
+ name: 'ping',
+ description: 'Ping the bot',
+ options: [],
+ ),
+ );
+
+ // Listen to the interaction stream and handle the ping command.
+ client.onApplicationCommandInteraction.listen((event) async {
+ if (event.interaction.data.name == 'ping') {
+ await event.interaction.respond(MessageBuilder(content: 'Pong!'));
+ }
+ });
+}
diff --git a/example/channel.dart b/example/channel.dart
deleted file mode 100644
index e8fccc5f8..000000000
--- a/example/channel.dart
+++ /dev/null
@@ -1,42 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() async {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!embed"
- if (e.message.content == "!create_channel") {
- // Make sure that the message was sent in a guild and not in a dm, because we can only create channels in guilds
- if (e.message.guild == null) {
- return;
- }
-
- // Get guild object from message
- final guild = e.message.guild!.getFromCache()!;
-
- // Created text channel. Remember discord will lower the case of name and replace spaces with - and do other sanitization
- final channel = await guild.createChannel(TextChannelBuilder.create("Test channel")) as ITextGuildChannel;
-
- // Send feedback
- await e.message.channel.sendMessage(MessageBuilder.content("Crated ${channel.mention}"));
-
- // Delete channel that we just created
- await channel.delete();
-
- // Send feedback
- await e.message.channel.sendMessage(MessageBuilder.content("Deleted ${channel.mention}"));
- }
- });
-}
diff --git a/example/create_add_role.dart b/example/create_add_role.dart
deleted file mode 100644
index 96efd74e6..000000000
--- a/example/create_add_role.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() async {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!embed"
- if (e.message.content == "!role") {
- // Make sure that the message was sent in a guild and not in a dm, because we cant add roles in dms
- if (e.message.guild == null) {
- return;
- }
-
- // Creating a role with RoleBuilder with a given color.
- final role = await e.message.guild!.getFromCache()!.createRole(RoleBuilder("testRole")..color = DiscordColor.chartreuse);
-
- // Add role to member.
- await e.message.member!.addRole(role);
-
- // Send message with confirmation of given action
- await e.message.channel.sendMessage(MessageBuilder.content("Added [${role.name}] to user: [${e.message.author.tag}"));
- }
- });
-}
diff --git a/example/creating_channels.dart b/example/creating_channels.dart
new file mode 100644
index 000000000..085e44386
--- /dev/null
+++ b/example/creating_channels.dart
@@ -0,0 +1,26 @@
+import 'dart:io';
+
+import 'package:nyxx/nyxx.dart';
+
+void main() async {
+ final client = await Nyxx.connectGateway(
+ Platform.environment['TOKEN']!,
+ GatewayIntents.allUnprivileged | GatewayIntents.messageContent,
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
+
+ client.onMessageCreate.listen((event) async {
+ if (!event.message.content.startsWith('!create-channel')) return;
+
+ // We can't create channels outside of a guild.
+ if (event.guild == null) return;
+
+ // Fetch the channel & cast it to a GuildChannel so we can get its parentId.
+ final channel = await event.message.channel.get() as GuildChannel;
+
+ await event.guild!.createChannel(GuildTextChannelBuilder(
+ name: 'test-channel',
+ parentId: channel.parentId,
+ ));
+ });
+}
diff --git a/example/embeds.dart b/example/embeds.dart
deleted file mode 100644
index 890c003be..000000000
--- a/example/embeds.dart
+++ /dev/null
@@ -1,51 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-DiscordColor getColorForUserFromMessage(IMessage message) {
- if (message.guild != null) {
- return PermissionsUtils.getMemberHighestRole(message.member!).color;
- }
-
- return DiscordColor.black;
-}
-
-// Main function
-void main() async {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()); // Plugin that handles uncaught exceptions that may occur
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!embed"
- if (e.message.content == "!embed") {
-
- // Create embed with author and footer section.
- final embed = EmbedBuilder()
- ..addField(name: "Example field title", content: "Example value")
- ..addField(builder: (field) {
- field.content = "Hi";
- field.name = "Example Field";
- })
- ..addAuthor((author) {
- author.name = e.message.author.username;
- author.iconUrl = e.message.author.avatarUrl();
- })
- ..addFooter((footer) {
- footer.text = "Footer example, good";
- })
- ..color = getColorForUserFromMessage(e.message);
-
- // Sent an embed to channel where message received was sent
- await e.message.channel.sendMessage(MessageBuilder.embed(embed));
- }
- });
-
- await bot.connect();
-}
diff --git a/example/emojis.dart b/example/emojis.dart
deleted file mode 100644
index ca2886a3a..000000000
--- a/example/emojis.dart
+++ /dev/null
@@ -1,45 +0,0 @@
-import 'package:nyxx/nyxx.dart';
-
-void main(List args) {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- bot.eventsWs.onReady.listen((_) {
- print('Ready!');
- });
-
- // This event is called when a message is received
- bot.eventsWs.onMessageReceived.listen((event) async {
- if (event.message.content == '!emoji') {
- final emoji = event.message.guild?.getFromCache()?.emojis.values.firstWhere((emo) => emo.name == 'nyxx');
- final msg = await event.message.channel.sendMessage(MessageBuilder.content('Look at this emoji: $emoji'));
- await msg.createReaction(emoji!);
- // For unicode emoji use `UnicodeEmoji` class
- await msg.createReaction(UnicodeEmoji('🤔'));
- }
- });
-
- // This event is called when a reaction has been added to a message
- bot.eventsWs.onMessageReactionAdded.listen((event) async {
- if (event.emoji is UnicodeEmoji) {
- await event.message?.channel.sendMessage(
- MessageBuilder.content(
- 'Woah! This is a unicode emoji: ${event.emoji}',
- ),
- );
- } else if (event.emoji is IGuildEmojiPartial) {
- if (event.emoji is IResolvableGuildEmojiPartial) {
- final emoji = (event.emoji as IResolvableGuildEmojiPartial).resolve();
- await event.message?.channel.sendMessage(
- MessageBuilder.content(
- 'Woah! This is a custom emoji: ${emoji.name}',
- ),
- );
- }
- }
- });
-}
diff --git a/example/example.dart b/example/example.dart
index 845d008dd..b106cadec 100644
--- a/example/example.dart
+++ b/example/example.dart
@@ -1,25 +1,15 @@
-import "package:nyxx/nyxx.dart";
+import 'dart:io';
-// Main function
-void main() {
- // Create new bot instance
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
+import 'package:nyxx/nyxx.dart';
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((e) {
- print("Ready!");
- });
+void main() async {
+ final client = await Nyxx.connectGateway(
+ Platform.environment['TOKEN']!,
+ GatewayIntents.allUnprivileged,
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((e) {
- // Check if message content equals "!ping"
- if (e.message.content == "!ping") {
- // Send "Pong!" to channel where message was received
- e.message.channel.sendMessage(MessageBuilder.content("Pong!"));
- }
- });
+ await for (final MessageCreateEvent(:message) in client.onMessageCreate) {
+ print('${message.id} sent by ${message.author.id} in ${message.channelId}!');
+ }
}
diff --git a/example/invite.dart b/example/invite.dart
deleted file mode 100644
index 2dce5e00b..000000000
--- a/example/invite.dart
+++ /dev/null
@@ -1,33 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!create_channel"
- if (e.message.content == "!create_channel") {
- // Make sure that the message was sent in a guild and not in a dm, because we cant make invites in dms
- if (e.message.guild == null) {
- return;
- }
-
- // Create default invite. We have to cast channel to access guild specific functionality.
- final invite = await (e.message.channel as ITextGuildChannel).createInvite();
-
- // Send back invite url
- await e.message.channel.sendMessage(MessageBuilder.content(invite.url));
- }
- });
-}
diff --git a/example/kick_ban.dart b/example/kick_ban.dart
deleted file mode 100644
index 589d2a6d1..000000000
--- a/example/kick_ban.dart
+++ /dev/null
@@ -1,64 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-// Returns user that can be banned from message. Parses mention or raw id from message
-SnowflakeEntity getUserToKickOrBan(IMessage message) {
- // If mentions are not empty return first mention
- if (message.mentions.isNotEmpty) {
- return message.mentions.first.id.toSnowflakeEntity();
- }
-
- // Otherwise split message by spaces then take last part and parse it to snowflake and return as Snowflake entity
- return SnowflakeEntity(message.content.split(" ").last.toSnowflake());
-}
-
-// Main function
-void main() {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!ban"
- if (e.message.content == "!ban") {
- // Make sure that the message was sent in a guild and not in a dm, because we cant ban people in dms
- if (e.message.guild == null) {
- return;
- }
-
- // Get user to ban
- final userToBan = getUserToKickOrBan(e.message);
-
- // Ban user using variable initialized before
- await e.message.guild!.getFromCache()!.ban(userToBan);
-
- // Send feedback
- await e.message.channel.sendMessage(MessageBuilder.content("👍"));
- }
-
- // Check if message content equals "!kick"
- if (e.message.content == "!kick") {
- // Make sure that the message was sent in a guild and not in a dm, because we cant kick people in dms
- if (e.message.guild == null) {
- return;
- }
-
- // Get user to kick
- final userToBan = getUserToKickOrBan(e.message);
-
- // Kick user
- await e.message.guild!.getFromCache()!.kick(userToBan);
-
- // Send feedback
- await e.message.channel.sendMessage(MessageBuilder.content("👍"));
- }
- });
-}
diff --git a/example/message_components.dart b/example/message_components.dart
new file mode 100644
index 000000000..677549b43
--- /dev/null
+++ b/example/message_components.dart
@@ -0,0 +1,49 @@
+import 'dart:io';
+
+import 'package:nyxx/nyxx.dart';
+
+void main() async {
+ final client = await Nyxx.connectGateway(
+ Platform.environment['TOKEN']!,
+ GatewayIntents.allUnprivileged | GatewayIntents.messageContent,
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
+
+ client.onMessageCreate.listen((event) async {
+ if (!event.message.content.startsWith('!component')) return;
+
+ await event.message.channel.sendMessage(MessageBuilder(
+ content: 'Here are some components for you to play with!',
+ components: [
+ ActionRowBuilder(components: [
+ ButtonBuilder(
+ label: 'Visit nyxx on pub.dev',
+ style: ButtonStyle.link,
+ url: Uri.https('pub.dev', '/packages/nyxx'),
+ ),
+ ButtonBuilder(
+ label: 'A primary button',
+ style: ButtonStyle.primary,
+ customId: 'primary_button',
+ ),
+ ButtonBuilder(
+ label: 'A secondary button',
+ style: ButtonStyle.secondary,
+ customId: 'secondary_button',
+ ),
+ ]),
+ ActionRowBuilder(components: [
+ SelectMenuBuilder(
+ type: MessageComponentType.stringSelect,
+ customId: 'a_custom_id',
+ options: [
+ SelectMenuOptionBuilder(label: 'Option 1', value: 'option_1'),
+ SelectMenuOptionBuilder(label: 'Option 2', value: 'option_2'),
+ SelectMenuOptionBuilder(label: 'Option 3', value: 'option_3'),
+ ],
+ ),
+ ]),
+ ],
+ ));
+ });
+}
diff --git a/example/permissions.dart b/example/permissions.dart
deleted file mode 100644
index 0b80cafeb..000000000
--- a/example/permissions.dart
+++ /dev/null
@@ -1,47 +0,0 @@
-// ignore_for_file: unused_local_variable
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!embed"
- if (e.message.content == "!addReadPerms") {
-
- // Dont process message when not send in guild context
- if(e.message.guild != null) {
- return;
- }
-
- // Get current channel
- final messageChannel = e.message.channel.getFromCache() as IGuildChannel;
-
- // Get member from id
- final member = e.message.guild!.getFromCache()!.members[302359032612651009.toSnowflake()]!;
-
- // Get current member permissions in context of channel
- final permissions = await messageChannel.effectivePermissions(member);
-
- // Get current member permissions as builder
- final permissionsAsBuilder = permissions.toBuilder()..sendMessages = true; // @ig
-
- // Get first channel override as builder and edit sendMessages property to allow sending messages for entities included in this override
- final channelOverridesAsBuilder = messageChannel.permissionOverrides.first.toBuilder()..sendMessages = true;
-
- // Create new channel permission override
- await messageChannel.editChannelPermissions(PermissionsBuilder()..sendMessages = true, member);
- }
- });
-}
diff --git a/example/ping_pong.dart b/example/ping_pong.dart
deleted file mode 100644
index 45c81eb13..000000000
--- a/example/ping_pong.dart
+++ /dev/null
@@ -1,25 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() {
- // Create new bot instance
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((e) async {
- // Check if message content equals "!ping"
- if (e.message.content == "!ping") {
- // Send "Pong!" to channel where message was received
- await e.message.channel.sendMessage(MessageBuilder.content("Pong!"));
- }
- });
-}
diff --git a/example/private_emoji.dart b/example/private_emoji.dart
deleted file mode 100644
index ecb5cf5d3..000000000
--- a/example/private_emoji.dart
+++ /dev/null
@@ -1,40 +0,0 @@
-//<:Pepega:547759324836003842>
-
-import "package:nyxx/nyxx.dart";
-import 'dart:io';
-
-// Main function
-void main() {
- // Create new bot instance
- final bot = NyxxFactory.createNyxxWebsocket(Platform.environment['BOT_TOKEN']!, GatewayIntents.allUnprivileged | GatewayIntents.messageContent)
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((e) async {
- // Check if message content equals "!ping"
- if (e.message.content == "!ping") {
- bot.httpEndpoints.fetchChannel(Snowflake(961916452967944223));
-
- e.message.guild?.getFromCache()?.shard;
- // Send "Pong!" to channel where message was received
- e.message.channel.sendMessage(MessageBuilder.content(IBaseGuildEmoji.fromId(Snowflake(502563517774299156), bot).formatForMessage()));
- }
-
- print(await (await e.message.guild?.getOrDownload())!.getBans().toList());
-
- if (e.message.content == "!create-thread") {
- bot.httpEndpoints.startForumThread(
- Snowflake(961916452967944223),
- ForumThreadBuilder(
- 'test',
- message: MessageBuilder.content(
- 'this is test content <@${e.message.author.id}>',
- ),
- ),
- );
- }
- });
-}
diff --git a/example/reactions.dart b/example/reactions.dart
new file mode 100644
index 000000000..dfc10d926
--- /dev/null
+++ b/example/reactions.dart
@@ -0,0 +1,17 @@
+import 'dart:io';
+
+import 'package:nyxx/nyxx.dart';
+
+void main() async {
+ final client = await Nyxx.connectGateway(
+ Platform.environment['TOKEN']!,
+ GatewayIntents.allUnprivileged | GatewayIntents.messageContent,
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
+
+ client.onMessageCreate.listen((event) async {
+ if (event.message.content.contains('nyxx')) {
+ await event.message.react(ReactionBuilder(name: '❤️', id: null));
+ }
+ });
+}
diff --git a/example/reply_to_message.dart b/example/reply_to_message.dart
deleted file mode 100644
index 9a58baada..000000000
--- a/example/reply_to_message.dart
+++ /dev/null
@@ -1,36 +0,0 @@
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() {
- // Create new bot instance. Replace string with your token
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot is connected to all shards. Note that cache can be empty or not incomplete.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- // Listen to all incoming messages
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // Check if message content equals "!reply"
- if (e.message.content == "!reply") {
- // Create message with some content and then add to builder
- // additional ReplyBuilder that is created from message we received in event
- final replyBuilder = ReplyBuilder.fromMessage(e.message);
- final messageBuilder = MessageBuilder.content("This is how replies work")
- ..replyBuilder = replyBuilder;
-
- // If you dont want to mention user that invoked that command, use AllowedMentions
- final allowedMentionsBuilder = AllowedMentions()
- ..allow(reply: false);
-
- messageBuilder.allowedMentions = allowedMentionsBuilder;
-
- await e.message.channel.sendMessage(messageBuilder);
- }
- });
-}
diff --git a/example/sending_file.dart b/example/sending_file.dart
deleted file mode 100644
index f1adc39a6..000000000
--- a/example/sending_file.dart
+++ /dev/null
@@ -1,60 +0,0 @@
-import "dart:io";
-
-import "package:nyxx/nyxx.dart";
-
-// Main function
-void main() {
- // Create new bot instance
- final bot = NyxxFactory.createNyxxWebsocket("", GatewayIntents.allUnprivileged | GatewayIntents.messageContent) // Here we use the privilegied intent message content to receive incoming messages.
- ..registerPlugin(Logging()) // Default logging plugin
- ..registerPlugin(CliIntegration()) // Cli integration for nyxx allows stopping application via SIGTERM and SIGKILl
- ..registerPlugin(IgnoreExceptions()) // Plugin that handles uncaught exceptions that may occur
- ..connect();
-
- // Listen to ready event. Invoked when bot started listening to events.
- bot.eventsWs.onReady.listen((IReadyEvent e) {
- print("Ready!");
- });
-
- late IMessage message;
-
- // Listen to all incoming messages via Dart Stream
- bot.eventsWs.onMessageReceived.listen((IMessageReceivedEvent e) async {
- // When receive specific message send new file to channel
- if (e.message.content == "!give-me-file") {
- // Files argument needs to be list of AttachmentBuilder object with
- // path to file that you want to send. You can also use other
- // AttachmentBuilder constructors to send File object or raw bytes
- message = await e.message.channel.sendMessage(MessageBuilder()..files = [AttachmentBuilder.path("test-image.png")]);
- }
-
- // You can remove attachment from message by converting `IAttachment` instance to `AttachmentMetaDataBuilder` via `toBuilder` method.
- // Also new file can be added to message by adding new file to files property of message builder
- // Remember that files can be received out of order.
- if (e.message.content == "!edit-with-more-files") {
- message.edit(
- MessageBuilder.content("Remove first file and add one more")
- ..attachments = [message.attachments.first.toBuilder()]
- ..files = [AttachmentBuilder.path('test-image2.png')]
- );
- }
-
- // Check if message content equals "!givemeembed"
- if (e.message.content == "!givemeembed") {
- // Files can be used within embeds as custom images
- final attachment = AttachmentBuilder.file(File("test-image.jpg"));
-
- // use attachUrl getter from AttachmentBuilder class to get reference to uploaded file
- final embed = EmbedBuilder()
- ..title = "Example Title"
- ..thumbnailUrl = attachment.attachUrl;
-
- // Send everything we created before to channel where message was received.
- e.message.channel.sendMessage(
- MessageBuilder.content("HEJKA!")
- ..embeds = [embed]
- ..files = [attachment]
- );
- }
- });
-}
diff --git a/example/simple_command.dart b/example/simple_command.dart
new file mode 100644
index 000000000..d112c6631
--- /dev/null
+++ b/example/simple_command.dart
@@ -0,0 +1,35 @@
+import 'dart:io';
+
+import 'package:nyxx/nyxx.dart';
+
+void main() async {
+ final client = await Nyxx.connectGateway(
+ // Replace this line with a string containing your bot's token, or set
+ // the TOKEN environment variable to your token.
+ Platform.environment['TOKEN']!,
+
+ // Intents specify which events your bot will receive.
+ // The [messageContent] intent is needed to read the content of messages
+ // sent on Discord. It is a privileged intent, so you will need to
+ // activate it in the developer portal for your application.
+ GatewayIntents.allUnprivileged | GatewayIntents.messageContent,
+
+ // We configure our client with the logging and cliIntegration plugins
+ // to get logging output and to close the client cleanly when the process
+ // is killed.
+ options: GatewayClientOptions(plugins: [logging, cliIntegration]),
+ );
+
+ // We listen to the onMessageCreate stream which emits an event when the
+ // client receives a message.
+ client.onMessageCreate.listen((event) async {
+ if (event.message.content.startsWith('!ping')) {
+ // Send a message with the content "Pong!", replying to the message that
+ // we received.
+ await event.message.channel.sendMessage(MessageBuilder(
+ content: 'Pong!',
+ replyId: event.message.id,
+ ));
+ }
+ });
+}
diff --git a/lib/nyxx.dart b/lib/nyxx.dart
index 5c358ac58..3c6582746 100644
--- a/lib/nyxx.dart
+++ b/lib/nyxx.dart
@@ -1,208 +1,318 @@
-/// Nyxx Discord API wrapper for Dart
-///
-/// Main library which contains all stuff needed to connect and interact with Discord API.
-library nyxx;
+export 'src/api_options.dart' show ApiOptions, RestApiOptions, GatewayApiOptions, GatewayCompression, GatewayPayloadFormat, OAuth2ApiOptions;
+export 'src/client.dart' show Nyxx, NyxxRest, NyxxGateway, NyxxOAuth2;
+export 'src/client_options.dart' show ClientOptions, RestClientOptions, GatewayClientOptions;
+export 'src/errors.dart'
+ show
+ NyxxException,
+ InvalidEventException,
+ MemberAlreadyExistsException,
+ ShardDisconnectedError,
+ RoleNotFoundException,
+ AuditLogEntryNotFoundException,
+ EntitlementNotFoundException,
+ OutOfRemainingSessionsError,
+ IntegrationNotFoundException,
+ AlreadyAcknowledgedError,
+ AlreadyRespondedError;
+
+export 'src/builders/builder.dart' show Builder, CreateBuilder, UpdateBuilder;
+export 'src/builders/image.dart' show ImageBuilder;
+export 'src/builders/user.dart' show UserUpdateBuilder;
+export 'src/builders/permission_overwrite.dart' show PermissionOverwriteBuilder;
+export 'src/builders/channel/channel_position.dart' show ChannelPositionBuilder;
+export 'src/builders/channel/forum_tag.dart' show ForumTagBuilder;
+export 'src/builders/channel/group_dm.dart' show GroupDmUpdateBuilder;
+export 'src/builders/channel/guild_channel.dart'
+ show
+ ForumChannelUpdateBuilder,
+ GuildAnnouncementChannelUpdateBuilder,
+ GuildChannelUpdateBuilder,
+ GuildTextChannelUpdateBuilder,
+ GuildVoiceChannelUpdateBuilder,
+ GuildStageChannelUpdateBuilder,
+ ForumChannelBuilder,
+ GuildAnnouncementChannelBuilder,
+ GuildCategoryBuilder,
+ GuildCategoryUpdateBuilder,
+ GuildChannelBuilder,
+ GuildStageChannelBuilder,
+ GuildTextChannelBuilder,
+ GuildVoiceChannelBuilder;
+export 'src/builders/channel/stage_instance.dart' show StageInstanceBuilder, StageInstanceUpdateBuilder;
+export 'src/builders/channel/thread.dart' show ThreadUpdateBuilder, ForumThreadBuilder, ThreadBuilder, ThreadFromMessageBuilder;
+export 'src/builders/message/allowed_mentions.dart' show AllowedMentions;
+export 'src/builders/message/attachment.dart' show AttachmentBuilder;
+export 'src/builders/message/embed.dart' show EmbedBuilder, EmbedAuthorBuilder, EmbedFieldBuilder, EmbedFooterBuilder, EmbedImageBuilder, EmbedThumbnailBuilder;
+export 'src/builders/message/message.dart' show MessageBuilder, MessageUpdateBuilder;
+export 'src/builders/message/component.dart'
+ show ActionRowBuilder, ButtonBuilder, MessageComponentBuilder, SelectMenuBuilder, SelectMenuOptionBuilder, TextInputBuilder;
+export 'src/builders/webhook.dart' show WebhookBuilder, WebhookUpdateBuilder;
+export 'src/builders/guild/guild.dart' show GuildBuilder, GuildUpdateBuilder;
+export 'src/builders/guild/member.dart' show CurrentMemberUpdateBuilder, MemberBuilder, MemberUpdateBuilder;
+export 'src/builders/guild/welcome_screen.dart' show WelcomeScreenUpdateBuilder;
+export 'src/builders/guild/widget.dart' show WidgetSettingsUpdateBuilder;
+export 'src/builders/guild/scheduled_event.dart' show ScheduledEventBuilder, ScheduledEventUpdateBuilder;
+export 'src/builders/guild/template.dart' show GuildTemplateBuilder, GuildTemplateUpdateBuilder;
+export 'src/builders/guild/auto_moderation.dart' show AutoModerationRuleBuilder, AutoModerationRuleUpdateBuilder;
+export 'src/builders/role.dart' show RoleBuilder, RoleUpdateBuilder;
+export 'src/builders/voice.dart' show CurrentUserVoiceStateUpdateBuilder, VoiceStateUpdateBuilder, GatewayVoiceStateBuilder;
+export 'src/builders/presence.dart' show PresenceBuilder, CurrentUserStatus, ActivityBuilder;
+export 'src/builders/application_role_connection.dart' show ApplicationRoleConnectionUpdateBuilder;
+export 'src/builders/emoji/emoji.dart' show EmojiBuilder, EmojiUpdateBuilder;
+export 'src/builders/emoji/reaction.dart' show ReactionBuilder;
+export 'src/builders/invite.dart' show InviteBuilder;
+export 'src/builders/sticker.dart' show StickerBuilder, StickerUpdateBuilder;
+export 'src/builders/application_command.dart'
+ show ApplicationCommandBuilder, ApplicationCommandUpdateBuilder, CommandOptionBuilder, CommandOptionChoiceBuilder;
+export 'src/builders/interaction_response.dart' show InteractionResponseBuilder, ModalBuilder, InteractionCallbackType;
+export 'src/builders/entitlement.dart' show TestEntitlementBuilder, TestEntitlementType;
+export 'src/builders/application.dart' show ApplicationUpdateBuilder;
+
+export 'src/cache/cache.dart' show Cache, CacheConfig;
-export 'src/client_options.dart' show CacheOptions, ClientOptions, GatewayIntents;
-export 'src/nyxx.dart' show INyxx, INyxxRest, INyxxWebsocket, NyxxFactory;
-export 'src/typedefs.dart' show RawApiMap, RawApiList, RawApiListOfMaps;
-export 'src/core/allowed_mentions.dart' show AllowedMentions;
-export 'src/core/discord_color.dart' show DiscordColor;
-export 'src/core/snowflake.dart' show Snowflake;
-export 'src/core/snowflake_entity.dart' show SnowflakeEntity;
-export "src/core/application/app_team.dart" show IAppTeam;
-export "src/core/application/app_team_member.dart" show IAppTeamMember;
-export "src/core/application/app_team_user.dart" show IAppTeamUser;
-export "src/core/application/client_oauth2_application.dart" show IClientOAuth2Application;
-export "src/core/application/oauth2_application.dart" show IOAuth2Application;
-export 'src/core/audit_logs/audit_log.dart' show IAuditLog;
-export 'src/core/audit_logs/audit_log_change.dart' show ChangeKeyType, IAuditLogChange;
-export 'src/core/audit_logs/audit_log_entry.dart' show IAuditLogEntry, AuditLogEntryType;
-export 'src/core/audit_logs/audit_log_options.dart' show IAuditLogOptions;
-export 'src/core/channel/cacheable_text_channel.dart' show ICacheableTextChannel;
-export 'src/core/channel/channel.dart' show IChannel, ChannelType;
-export 'src/core/channel/dm_channel.dart' show IDMChannel;
-export 'src/core/channel/invite.dart' show IInviteWithMeta, IInvite;
-export 'src/core/channel/text_channel.dart' show ITextChannel;
-export 'src/core/channel/thread_channel.dart' show IThreadMember, IThreadChannel, IThreadMemberWithMember;
-export 'src/core/channel/thread_preview_channel.dart' show IThreadPreviewChannel;
-export 'src/core/channel/guild/activity_types.dart' show VoiceActivityType;
-export 'src/core/channel/guild/category_guild_channel.dart' show ICategoryGuildChannel;
-export 'src/core/channel/guild/guild_channel.dart' show IGuildChannel, IMinimalGuildChannel;
-export 'src/core/channel/guild/text_guild_channel.dart' show ITextGuildChannel;
-export 'src/core/channel/guild/voice_channel.dart'
- show IVoiceGuildChannel, IStageChannelInstance, IStageVoiceGuildChannel, ITextVoiceTextChannel, StageChannelInstancePrivacyLevel, VideoQualityMode;
-export 'src/core/channel/guild/forum/forum_channel.dart' show IForumChannel, ForumSortOrder, ForumLayout;
-export 'src/core/channel/guild/forum/forum_channel_tags.dart' show IForumChannelTags;
-export 'src/core/channel/guild/forum/forum_tag.dart' show IForumTag;
-export 'src/core/embed/embed.dart' show IEmbed;
-export 'src/core/embed/embed_author.dart' show IEmbedAuthor;
-export 'src/core/embed/embed_field.dart' show IEmbedField;
-export 'src/core/embed/embed_footer.dart' show IEmbedFooter;
-export 'src/core/embed/embed_provider.dart' show IEmbedProvider;
-export 'src/core/embed/embed_thumbnail.dart' show IEmbedThumbnail;
-export 'src/core/embed/embed_video.dart' show IEmbedVideo;
-export 'src/core/guild/ban.dart' show IBan;
-export 'src/core/guild/auto_moderation.dart'
- show IActionMetadata, IActionStructure, IAutoModerationRule, ITriggerMetadata, ActionTypes, EventTypes, TriggerTypes, KeywordPresets;
-export 'src/core/guild/client_user.dart' show IClientUser;
-export 'src/core/guild/guild.dart' show IGuild;
-export 'src/core/guild/guild_feature.dart' show GuildFeature;
-export 'src/core/guild/guild_nsfw_level.dart' show GuildNsfwLevel;
-export 'src/core/guild/guild_preview.dart' show IGuildPreview;
-export 'src/core/guild/premium_tier.dart' show PremiumTier;
-export 'src/core/guild/role.dart' show IRole, IRoleTags;
-export 'src/core/guild/scheduled_event.dart' show IEntityMetadata, IGuildEvent, IGuildEventUser, GuildEventPrivacyLevel, GuildEventStatus, GuildEventType;
-export 'src/core/guild/status.dart' show IClientStatus, UserStatus;
-export 'src/core/guild/webhook.dart' show IWebhook, WebhookType;
-export 'src/core/guild/guild_welcome_screen.dart' show IGuildWelcomeScreen, IGuildWelcomeChannel;
-export 'src/core/guild/system_channel_flags.dart' show SystemChannelFlags;
-export 'src/core/message/attachment.dart' show IAttachment;
-export 'src/core/message/emoji.dart' show IEmoji;
-export 'src/core/message/guild_emoji.dart' show IBaseGuildEmoji, IGuildEmoji, IGuildEmojiPartial, IResolvableGuildEmojiPartial;
-export 'src/core/message/message.dart' show IMessage;
-export 'src/core/message/message_flags.dart' show MessageFlags;
-export 'src/core/message/message_reference.dart' show IMessageReference;
-export 'src/core/message/message_time_stamp.dart' show IMessageTimestamp, TimeStampStyle;
-export 'src/core/message/message_type.dart' show MessageType;
-export 'src/core/message/reaction.dart' show IReaction;
-export 'src/core/message/referenced_message.dart' show IReferencedMessage;
-export 'src/core/message/sticker.dart' show IStandardSticker, IStickerPack, ISticker, IGuildSticker, IPartialSticker;
-export 'src/core/message/unicode_emoji.dart' show IUnicodeEmoji, UnicodeEmoji;
-export 'src/core/message/components/component_style.dart' show ButtonStyle;
-export 'src/core/message/components/message_component.dart'
+export 'src/http/bucket.dart' show HttpBucket;
+export 'src/http/handler.dart' show HttpHandler, Oauth2HttpHandler, RateLimitInfo;
+export 'src/http/request.dart' show BasicRequest, HttpRequest, MultipartRequest, FormDataRequest;
+export 'src/http/response.dart' show FieldError, HttpErrorData, HttpResponse, HttpResponseError, HttpResponseSuccess;
+export 'src/http/route.dart' show HttpRoute, HttpRouteParam, HttpRoutePart;
+export 'src/http/cdn/cdn_asset.dart' show CdnAsset, CdnFormat;
+export 'src/http/cdn/cdn_request.dart' show CdnRequest;
+export 'src/http/managers/manager.dart' show Manager, ReadOnlyManager;
+export 'src/http/managers/channel_manager.dart' show ChannelManager;
+export 'src/http/managers/message_manager.dart' show MessageManager;
+export 'src/http/managers/user_manager.dart' show UserManager;
+export 'src/http/managers/webhook_manager.dart' show WebhookManager;
+export 'src/http/managers/guild_manager.dart' show GuildManager;
+export 'src/http/managers/application_manager.dart' show ApplicationManager;
+export 'src/http/managers/voice_manager.dart' show VoiceManager;
+export 'src/http/managers/invite_manager.dart' show InviteManager;
+export 'src/http/managers/member_manager.dart' show MemberManager;
+export 'src/http/managers/role_manager.dart' show RoleManager;
+export 'src/http/managers/gateway_manager.dart' show GatewayManager;
+export 'src/http/managers/scheduled_event_manager.dart' show ScheduledEventManager;
+export 'src/http/managers/auto_moderation_manager.dart' show AutoModerationManager;
+export 'src/http/managers/integration_manager.dart' show IntegrationManager;
+export 'src/http/managers/emoji_manager.dart' show EmojiManager;
+export 'src/http/managers/audit_log_manager.dart' show AuditLogManager;
+export 'src/http/managers/sticker_manager.dart' show GuildStickerManager, GlobalStickerManager;
+export 'src/http/managers/application_command_manager.dart' show ApplicationCommandManager, GlobalApplicationCommandManager, GuildApplicationCommandManager;
+export 'src/http/managers/interaction_manager.dart' show InteractionManager;
+export 'src/http/managers/entitlement_manager.dart' show EntitlementManager;
+
+export 'src/gateway/gateway.dart' show Gateway;
+export 'src/gateway/message.dart' show Disconnecting, Dispose, ErrorReceived, EventReceived, GatewayMessage, Send, ShardData, ShardMessage;
+export 'src/gateway/shard.dart' show Shard;
+
+export 'src/models/discord_color.dart' show DiscordColor;
+export 'src/models/locale.dart' show Locale;
+export 'src/models/permission_overwrite.dart' show PermissionOverwrite, PermissionOverwriteType;
+export 'src/models/snowflake.dart' show Snowflake;
+export 'src/models/permissions.dart' show Permissions;
+export 'src/models/snowflake_entity/snowflake_entity.dart' show SnowflakeEntity, ManagedSnowflakeEntity, WritableSnowflakeEntity;
+export 'src/models/user/application_role_connection.dart' show ApplicationRoleConnection;
+export 'src/models/user/connection.dart' show Connection, ConnectionType, ConnectionVisibility;
+export 'src/models/user/user.dart' show PartialUser, User, UserFlags, NitroType;
+export 'src/models/channel/channel.dart' show Channel, ChannelFlags, PartialChannel, ChannelType;
+export 'src/models/channel/followed_channel.dart' show FollowedChannel;
+export 'src/models/channel/guild_channel.dart' show GuildChannel;
+export 'src/models/channel/has_threads_channel.dart' show HasThreadsChannel;
+export 'src/models/channel/thread_aggregate.dart' show ThreadsOnlyChannel;
+export 'src/models/channel/text_channel.dart' show PartialTextChannel, TextChannel;
+export 'src/models/channel/thread_list.dart' show ThreadList;
+export 'src/models/channel/thread.dart' show PartialThreadMember, Thread, ThreadMember;
+export 'src/models/channel/voice_channel.dart' show VoiceChannel, VideoQualityMode;
+export 'src/models/channel/stage_instance.dart' show StageInstance, PrivacyLevel;
+export 'src/models/channel/types/announcement_thread.dart' show AnnouncementThread;
+export 'src/models/channel/types/directory.dart' show DirectoryChannel;
+export 'src/models/channel/types/dm.dart' show DmChannel;
+export 'src/models/channel/types/forum.dart' show DefaultReaction, ForumChannel, ForumTag, ForumLayout, ForumSort;
+export 'src/models/channel/types/group_dm.dart' show GroupDmChannel;
+export 'src/models/channel/types/guild_announcement.dart' show GuildAnnouncementChannel;
+export 'src/models/channel/types/guild_category.dart' show GuildCategory;
+export 'src/models/channel/types/guild_stage.dart' show GuildStageChannel;
+export 'src/models/channel/types/guild_text.dart' show GuildTextChannel;
+export 'src/models/channel/types/guild_voice.dart' show GuildVoiceChannel;
+export 'src/models/channel/types/private_thread.dart' show PrivateThread;
+export 'src/models/channel/types/public_thread.dart' show PublicThread;
+export 'src/models/channel/types/guild_media.dart' show GuildMediaChannel;
+export 'src/models/message/activity.dart' show MessageActivity, MessageActivityType;
+export 'src/models/message/attachment.dart' show Attachment, AttachmentFlags;
+export 'src/models/message/author.dart' show MessageAuthor;
+export 'src/models/message/channel_mention.dart' show ChannelMention;
+export 'src/models/message/embed.dart' show Embed, EmbedAuthor, EmbedField, EmbedFooter, EmbedImage, EmbedProvider, EmbedThumbnail, EmbedVideo;
+export 'src/models/message/message.dart' show Message, MessageFlags, PartialMessage, MessageType, MessageInteraction;
+export 'src/models/message/reaction.dart' show Reaction, ReactionCountDetails;
+export 'src/models/message/reference.dart' show MessageReference;
+export 'src/models/message/role_subscription_data.dart' show RoleSubscriptionData;
+export 'src/models/message/component.dart'
+ show
+ ActionRowComponent,
+ ButtonComponent,
+ MessageComponent,
+ SelectMenuComponent,
+ SelectMenuOption,
+ TextInputComponent,
+ ButtonStyle,
+ MessageComponentType,
+ TextInputStyle;
+export 'src/models/invite/invite.dart' show Invite, TargetType;
+export 'src/models/invite/invite_metadata.dart' show InviteWithMetadata;
+export 'src/models/webhook.dart' show PartialWebhook, Webhook, WebhookType, WebhookAuthor;
+export 'src/models/guild/ban.dart' show Ban;
+export 'src/models/guild/guild_preview.dart' show GuildPreview;
+export 'src/models/guild/guild_widget.dart' show GuildWidget, WidgetSettings, WidgetImageStyle;
+export 'src/models/guild/guild.dart'
show
- IMessageButton,
- ILinkMessageButton,
- IMessageComponent,
- IMessageComponentEmoji,
- IMessageMultiselect,
- IMessageMultiselectOption,
- MessageComponentEmoji,
- ComponentType,
- IMessageTextInput,
- IMessageUserMultiSelect,
- IMessageRoleMultiSelect,
- IMessageMentionableMultiSelect,
- IMessageChannelMultiSelect;
-export 'src/core/permissions/permission_overrides.dart' show IPermissionsOverrides;
-export 'src/core/permissions/permissions.dart' show IPermissions;
-export 'src/core/permissions/permissions_constants.dart' show PermissionsConstants;
-export 'src/core/user/member.dart' show IMember;
-export 'src/core/user/nitro_type.dart' show NitroType;
-export 'src/core/user/presence.dart'
- show IActivity, IActivityEmoji, IActivityFlags, IActivityParty, IActivityTimestamps, IGameAssets, IGameSecrets, ActivityType, IPartialPresence;
-export 'src/core/user/user.dart' show IUser;
-export 'src/core/user/user_flags.dart' show IUserFlags;
-export 'src/core/user/member_flags.dart' show IMemberFlags;
-export 'src/core/voice/voice_region.dart' show IVoiceRegion;
-export 'src/core/voice/voice_state.dart' show IVoiceState;
-export 'src/events/channel_events.dart' show IChannelCreateEvent, IChannelDeleteEvent, IChannelPinsUpdateEvent, IChannelUpdateEvent, IStageInstanceEvent;
-export 'src/events/disconnect_event.dart' show IDisconnectEvent, DisconnectEventReason;
-export 'src/events/guild_events.dart'
+ Guild,
+ GuildFeatures,
+ PartialGuild,
+ SystemChannelFlags,
+ ExplicitContentFilterLevel,
+ MessageNotificationLevel,
+ MfaLevel,
+ NsfwLevel,
+ PremiumTier,
+ VerificationLevel;
+export 'src/models/guild/integration.dart' show PartialIntegration, Integration, IntegrationAccount, IntegrationApplication, IntegrationExpireBehavior;
+export 'src/models/guild/member.dart' show Member, MemberFlags, PartialMember;
+export 'src/models/guild/onboarding.dart' show Onboarding, OnboardingPrompt, OnboardingPromptOption, OnboardingPromptType;
+export 'src/models/guild/welcome_screen.dart' show WelcomeScreen, WelcomeScreenChannel;
+export 'src/models/guild/scheduled_event.dart' show EntityMetadata, PartialScheduledEvent, ScheduledEvent, ScheduledEventUser, EventStatus, ScheduledEntityType;
+export 'src/models/guild/audit_log.dart' show AuditLogChange, AuditLogEntry, AuditLogEntryInfo, PartialAuditLogEntry, AuditLogEvent;
+export 'src/models/application.dart'
+ show Application, ApplicationFlags, InstallationParameters, PartialApplication, ApplicationRoleConnectionMetadata, ConnectionMetadataType;
+export 'src/models/guild/template.dart' show GuildTemplate;
+export 'src/models/guild/auto_moderation.dart'
show
- IGuildBanAddEvent,
- IGuildBanRemoveEvent,
- IGuildCreateEvent,
- IGuildDeleteEvent,
- IGuildEmojisUpdateEvent,
- IGuildMemberAddEvent,
- IGuildMemberRemoveEvent,
- IGuildMemberUpdateEvent,
- IGuildStickerUpdate,
- IGuildUpdateEvent,
- IRoleCreateEvent,
- IRoleDeleteEvent,
- IRoleUpdateEvent,
- IAutoModerationRuleCreateEvent,
- IAutoModerationRuleUpdateEvent,
- IAutoModerationRuleDeleteEvent,
- IAutoModerationActionExecutionEvent,
- IGuildEventCreateEvent,
- IGuildEventUpdateEvent,
- IGuildEventDeleteEvent,
- IWebhookUpdateEvent;
-export 'src/events/http_events.dart' show IHttpResponseEvent, IHttpErrorEvent;
-export 'src/events/invite_events.dart' show IInviteCreatedEvent, IInviteDeletedEvent;
-export 'src/events/member_chunk_event.dart' show IMemberChunkEvent;
-export 'src/events/message_events.dart'
+ ActionMetadata,
+ AutoModerationAction,
+ AutoModerationRule,
+ PartialAutoModerationRule,
+ TriggerMetadata,
+ ActionType,
+ AutoModerationEventType,
+ KeywordPresetType,
+ TriggerType;
+export 'src/models/voice/voice_state.dart' show VoiceState;
+export 'src/models/voice/voice_region.dart' show VoiceRegion;
+export 'src/models/role.dart' show PartialRole, Role, RoleTags, RoleFlags;
+export 'src/models/gateway/gateway.dart' show GatewayBot, GatewayConfiguration, SessionStartLimit;
+export 'src/models/gateway/event.dart'
show
- IMessageReactionEvent,
- IMessageDeleteBulkEvent,
- IMessageDeleteEvent,
- IMessageReactionAddedEvent,
- IMessageReactionRemovedEvent,
- IMessageReactionRemoveEmojiEvent,
- IMessageReactionsRemovedEvent,
- IMessageReceivedEvent,
- IMessageUpdateEvent;
-export 'src/events/presence_update_event.dart' show IPresenceUpdateEvent;
-export 'src/events/ratelimit_event.dart' show IRatelimitEvent;
-export 'src/events/raw_event.dart' show IRawEvent;
-export 'src/events/ready_event.dart' show IReadyEvent;
-export 'src/events/thread_create_event.dart' show IThreadCreateEvent, IThreadUpdateEvent;
-export 'src/events/thread_deleted_event.dart' show IThreadDeletedEvent;
-export 'src/events/thread_list_sync_event.dart' show IThreadListSyncEvent;
-export 'src/events/thread_members_update_event.dart' show IThreadMembersUpdateEvent, IThreadMemberUpdateEvent;
-export 'src/events/typing_event.dart' show ITypingEvent;
-export 'src/events/user_update_event.dart' show IUserUpdateEvent;
-export 'src/events/voice_server_update_event.dart' show IVoiceServerUpdateEvent;
-export 'src/events/voice_state_update_event.dart' show IVoiceStateUpdateEvent;
-export 'src/internal/constants.dart' show Constants, OPCodes, Encoding, CdnConstants;
-export 'src/internal/event_controller.dart' show IWebsocketEventController, IRestEventController;
-export 'src/internal/http_endpoints.dart' show IHttpEndpoints;
-export 'src/internal/cdn_http_endpoints.dart' show ICdnHttpEndpoints;
-export 'src/internal/cache/cache.dart' show SnowflakeCache, ICache, InMemoryCache;
-export 'src/internal/cache/cache_policy.dart'
- show CachePolicyPredicate, CachePolicyLocation, CachePolicy, ChannelCachePolicy, MemberCachePolicy, MessageCachePolicy;
-export 'src/internal/cache/cacheable.dart' show Cacheable;
-export 'src/internal/exceptions/embed_builder_argument_exception.dart' show EmbedBuilderArgumentException;
-export 'src/internal/exceptions/invalid_shard_exception.dart' show InvalidShardException;
-export 'src/internal/exceptions/invalid_snowflake_exception.dart' show InvalidSnowflakeException;
-export 'src/internal/exceptions/missing_token_error.dart' show MissingTokenError;
-export 'src/internal/exceptions/unrecoverable_nyxx_error.dart' show UnrecoverableNyxxError;
-export 'src/internal/http/http_route_param.dart' show HttpRouteParam, CdnHttpRouteParam;
-export 'src/internal/http/http_route_part.dart' show HttpRoutePart, CdnHttpRoutePart;
-export 'src/internal/http/http_route.dart' show IHttpRoute, ICdnHttpRoute;
-export 'src/internal/http/http_response.dart' show IHttpResponse, IHttpResponseError, IHttpResponseSuccess;
-export 'src/internal/interfaces/convertable.dart' show Convertable;
-export 'src/internal/interfaces/disposable.dart' show Disposable;
-export 'src/internal/interfaces/message_author.dart' show IMessageAuthor;
-export 'src/internal/interfaces/send.dart' show ISend;
-export 'src/internal/interfaces/mentionable.dart' show Mentionable;
-export 'src/internal/response_wrapper/error_response_wrapper.dart' show IHttpErrorData, IFieldError;
-export 'src/internal/response_wrapper/thread_list_result_wrapper.dart' show IThreadListResultWrapper;
-export 'src/internal/shard/shard.dart' show IShard;
-export 'src/internal/shard/shard_manager.dart' show IShardManager;
-export 'src/utils/enum.dart' show IEnum;
-export 'src/utils/builders/attachment_builder.dart' show AttachmentBuilder, AttachmentMetadataBuilder;
-export 'src/utils/builders/builder.dart' show Builder;
-export 'src/utils/builders/embed_author_builder.dart' show EmbedAuthorBuilder;
-export 'src/utils/builders/embed_builder.dart' show EmbedBuilder;
-export 'src/utils/builders/embed_field_builder.dart' show EmbedFieldBuilder;
-export 'src/utils/builders/embed_footer_builder.dart' show EmbedFooterBuilder;
-export 'src/utils/builders/guild_builder.dart' show GuildBuilder, RoleBuilder;
-export 'src/utils/builders/channel_builder.dart' show ChannelBuilder, TextChannelBuilder, VoiceChannelBuilder, ForumChannelBuilder;
-export 'src/utils/builders/message_builder.dart' show MessageBuilder, MessageDecoration, MessageFlagBuilder;
-export 'src/utils/builders/member_builder.dart' show MemberBuilder, MemberFlagsBuilder;
-export 'src/utils/builders/permissions_builder.dart' show PermissionOverrideBuilder, PermissionsBuilder;
-export 'src/utils/builders/presence_builder.dart' show PresenceBuilder, ActivityBuilder;
-export 'src/utils/builders/reply_builder.dart' show ReplyBuilder;
-export 'src/utils/builders/sticker_builder.dart' show StickerBuilder;
-export 'src/utils/builders/thread_builder.dart' show ThreadArchiveTime, ThreadBuilder;
-export 'src/utils/builders/guild_event_builder.dart' show GuildEventBuilder, EntityMetadataBuilder;
-export 'src/utils/builders/forum_thread_builder.dart' show ForumThreadBuilder, ForumTagBuilder, AvailableTagBuilder;
-export 'src/utils/builders/auto_moderation_builder.dart' show ActionMetadataBuilder, ActionStructureBuilder, AutoModerationRuleBuilder, TriggerMetadataBuilder;
-export 'src/utils/extensions.dart' show IntExtensions, SnowflakeEntityListExtensions, StringExtensions;
-export 'src/utils/permissions.dart' show PermissionsUtils;
-export 'src/utils/utils.dart' show ListSafeFirstWhere;
+ DispatchEvent,
+ GatewayEvent,
+ HeartbeatAckEvent,
+ HeartbeatEvent,
+ HelloEvent,
+ InvalidSessionEvent,
+ RawDispatchEvent,
+ ReconnectEvent,
+ UnknownDispatchEvent;
+export 'src/models/gateway/opcode.dart' show Opcode;
+export 'src/models/gateway/events/application_command.dart' show ApplicationCommandPermissionsUpdateEvent;
+export 'src/models/gateway/events/auto_moderation.dart'
+ show AutoModerationActionExecutionEvent, AutoModerationRuleCreateEvent, AutoModerationRuleDeleteEvent, AutoModerationRuleUpdateEvent;
+export 'src/models/gateway/events/channel.dart'
+ show
+ ChannelCreateEvent,
+ ChannelDeleteEvent,
+ ChannelPinsUpdateEvent,
+ ChannelUpdateEvent,
+ ThreadCreateEvent,
+ ThreadDeleteEvent,
+ ThreadListSyncEvent,
+ ThreadMemberUpdateEvent,
+ ThreadMembersUpdateEvent,
+ ThreadUpdateEvent;
+export 'src/models/gateway/events/guild.dart'
+ show
+ GuildBanAddEvent,
+ GuildBanRemoveEvent,
+ GuildCreateEvent,
+ GuildDeleteEvent,
+ GuildAuditLogCreateEvent,
+ GuildEmojisUpdateEvent,
+ GuildIntegrationsUpdateEvent,
+ GuildMemberAddEvent,
+ GuildMemberRemoveEvent,
+ GuildMemberUpdateEvent,
+ GuildMembersChunkEvent,
+ GuildRoleCreateEvent,
+ GuildRoleDeleteEvent,
+ GuildRoleUpdateEvent,
+ GuildScheduledEventCreateEvent,
+ GuildScheduledEventDeleteEvent,
+ GuildScheduledEventUpdateEvent,
+ GuildScheduledEventUserAddEvent,
+ GuildScheduledEventUserRemoveEvent,
+ GuildStickersUpdateEvent,
+ GuildUpdateEvent,
+ UnavailableGuildCreateEvent;
+export 'src/models/gateway/events/integration.dart' show IntegrationCreateEvent, IntegrationDeleteEvent, IntegrationUpdateEvent;
+export 'src/models/gateway/events/interaction.dart' show InteractionCreateEvent;
+export 'src/models/gateway/events/invite.dart' show InviteCreateEvent, InviteDeleteEvent;
+export 'src/models/gateway/events/message.dart'
+ show
+ MessageBulkDeleteEvent,
+ MessageCreateEvent,
+ MessageDeleteEvent,
+ MessageReactionAddEvent,
+ MessageReactionRemoveAllEvent,
+ MessageReactionRemoveEmojiEvent,
+ MessageReactionRemoveEvent,
+ MessageUpdateEvent;
+export 'src/models/gateway/events/presence.dart' show PresenceUpdateEvent, TypingStartEvent, UserUpdateEvent;
+export 'src/models/gateway/events/ready.dart' show ReadyEvent, ResumedEvent;
+export 'src/models/gateway/events/stage_instance.dart' show StageInstanceCreateEvent, StageInstanceDeleteEvent, StageInstanceUpdateEvent;
+export 'src/models/gateway/events/voice.dart' show VoiceServerUpdateEvent, VoiceStateUpdateEvent;
+export 'src/models/gateway/events/webhook.dart' show WebhooksUpdateEvent;
+export 'src/models/gateway/events/entitlement.dart' show EntitlementCreateEvent, EntitlementDeleteEvent, EntitlementUpdateEvent;
+export 'src/models/presence.dart'
+ show Activity, ActivityAssets, ActivityButton, ActivityFlags, ActivityParty, ActivitySecrets, ActivityTimestamps, ClientStatus, ActivityType, UserStatus;
+export 'src/models/emoji.dart' show Emoji, GuildEmoji, PartialEmoji, TextEmoji;
+export 'src/models/sticker/guild_sticker.dart' show GuildSticker, PartialGuildSticker;
+export 'src/models/sticker/global_sticker.dart' show GlobalSticker, PartialGlobalSticker;
+export 'src/models/sticker/sticker.dart' show Sticker, StickerType, StickerFormatType, StickerItem;
+export 'src/models/sticker/sticker_pack.dart' show StickerPack;
+export 'src/models/commands/application_command.dart' show ApplicationCommand, PartialApplicationCommand, ApplicationCommandType;
+export 'src/models/commands/application_command_option.dart' show CommandOption, CommandOptionChoice, CommandOptionType, CommandOptionMentionable;
+export 'src/models/commands/application_command_permissions.dart' show CommandPermission, CommandPermissions, CommandPermissionType;
+export 'src/models/team.dart' show Team, TeamMember, TeamMembershipState, TeamMemberRole;
+export 'src/models/interaction.dart'
+ show
+ ApplicationCommandInteractionData,
+ Interaction,
+ InteractionOption,
+ MessageComponentInteractionData,
+ MessageResponse,
+ ModalResponse,
+ ModalSubmitInteractionData,
+ ResolvedData,
+ InteractionType,
+ ApplicationCommandAutocompleteInteraction,
+ ApplicationCommandInteraction,
+ MessageComponentInteraction,
+ ModalSubmitInteraction,
+ PingInteraction;
+export 'src/models/entitlement.dart' show Entitlement, PartialEntitlement, EntitlementType;
+export 'src/models/sku.dart' show Sku, SkuType;
+
+export 'src/utils/flags.dart' show Flag, Flags;
+export 'src/intents.dart' show GatewayIntents;
-export 'src/plugin/plugin.dart' show BasePlugin;
-export 'src/plugin/plugin_manager.dart' show IPluginManager;
-export 'src/plugin/plugins/cli_integration.dart' show CliIntegration;
-export 'src/plugin/plugins/ignore_exception.dart' show IgnoreExceptions;
-export 'src/plugin/plugins/logging.dart' show Logging;
+export 'src/plugin/plugin.dart' show NyxxPlugin, NyxxPluginState;
+export 'src/plugin/logging.dart' show Logging, logging;
+export 'src/plugin/cli_integration.dart' show CliIntegration, cliIntegration;
+export 'src/plugin/ignore_exceptions.dart' show IgnoreExceptions, ignoreExceptions;
-// Export classes used in the nyxx API to avoid users having to import the package themselves
-export 'package:retry/retry.dart' show RetryOptions;
-export 'package:logging/logging.dart' show Level;
+// Types also used in the nyxx API from other packages
+export 'package:http/http.dart'
+ // Don't export MultipartRequest as it conflicts with our MultipartRequest
+ show
+ BaseRequest,
+ Request,
+ MultipartFile,
+ BaseResponse,
+ StreamedResponse;
+export 'package:logging/logging.dart' show Logger, Level;
+export 'package:runtime_type/runtime_type.dart' show RuntimeType;
diff --git a/lib/src/api_options.dart b/lib/src/api_options.dart
new file mode 100644
index 000000000..8938a6075
--- /dev/null
+++ b/lib/src/api_options.dart
@@ -0,0 +1,148 @@
+import 'package:nyxx/src/builders/presence.dart';
+import 'package:nyxx/src/intents.dart';
+import 'package:nyxx/src/utils/flags.dart';
+import 'package:oauth2/oauth2.dart';
+
+/// Options for connecting to the Discord API.
+abstract class ApiOptions {
+ /// The version of nyxx used in [defaultUserAgent].
+ static const nyxxVersion = '6.0.0';
+
+ /// The URL to the nyxx repository used in [defaultUserAgent].
+ static const nyxxRepositoryUrl = 'https://github.com/nyxx-discord/nyxx';
+
+ /// The default value for the `User-Agent` header for bots made with nyxx.
+ static const defaultUserAgent = 'Nyxx ($nyxxRepositoryUrl, $nyxxVersion)';
+
+ /// The host at which the API can be found.
+ ///
+ /// This is always `discord.com`.
+ String get host => 'discord.com';
+
+ /// The base URI relative to the [host] where the API can be found.
+ String get baseUri => '/api/v$apiVersion';
+
+ /// The version of the API to use.
+ int get apiVersion => 10;
+
+ /// The value of the `Authorization` header to use when authenticating requests.
+ String get authorizationHeader;
+
+ /// The value of the `User-Agent` header to send with each request.
+ final String userAgent;
+
+ /// The host at which the CDN can be found.
+ ///
+ /// This is always `cdn.discordapp.com`.
+ String get cdnHost => 'cdn.discordapp.com';
+
+ /// Create a new [ApiOptions].
+ ApiOptions({this.userAgent = defaultUserAgent});
+}
+
+/// Options for connecting to the Discord API to make HTTP requests with a bot token.
+class RestApiOptions extends ApiOptions {
+ /// The token to use.
+ final String token;
+
+ @override
+ String get authorizationHeader => 'Bot $token';
+
+ /// Create a new [RestApiOptions].
+ RestApiOptions({required this.token, super.userAgent});
+}
+
+/// Options for connecting the the Discord API using credentials from an OAuth2 flow.
+class OAuth2ApiOptions extends ApiOptions implements RestApiOptions {
+ /// The credentials to use when connecting to the API.
+ Credentials credentials;
+
+ @override
+ String get token => credentials.accessToken;
+
+ @override
+ String get authorizationHeader => 'Bearer ${credentials.accessToken}';
+
+ /// Create a new [OAuth2ApiOptions].
+ OAuth2ApiOptions({required this.credentials, super.userAgent});
+}
+
+/// Options for connecting to the Discord API for making HTTP requests and connecting to the Gateway
+/// with a bot token.
+class GatewayApiOptions extends RestApiOptions {
+ /// The intents to use.
+ final Flags intents;
+
+ /// The format of the Gateway payloads.
+ final GatewayPayloadFormat payloadFormat;
+
+ /// The compression to use on the Gateway connection.
+ final GatewayCompression compression;
+
+ /// The IDs of the shards to spawn by this client.
+ ///
+ /// If this is not set, the client spawns all shards from `0` to [totalShards].
+ final List? shards;
+
+ /// The total number of shards in the current session.
+ ///
+ /// If this is not set, the client will use the recommended shard count from Discord.
+ final int? totalShards;
+
+ /// The threshold after which guilds are considered large in the Gateway.
+ final int? largeThreshold;
+
+ /// The presence the client will set after first connecting to the Gateway.
+ final PresenceBuilder? initialPresence;
+
+ /// The query parameters to append to the Gateway connection URL.
+ Map get gatewayConnectionOptions => {
+ 'v': apiVersion.toString(),
+ 'encoding': payloadFormat.value,
+ if (compression == GatewayCompression.transport) 'compress': 'zlib-stream',
+ };
+
+ /// Create a new [GatewayApiOptions].
+ GatewayApiOptions({
+ required super.token,
+ super.userAgent,
+ required this.intents,
+ this.payloadFormat = GatewayPayloadFormat.json,
+ this.compression = GatewayCompression.transport,
+ this.shards,
+ this.totalShards,
+ this.largeThreshold,
+ this.initialPresence,
+ });
+}
+
+/// The format of Gateway payloads.
+enum GatewayPayloadFormat {
+ /// Payloads are sent as JSON.
+ json._('json'),
+
+ /// Payloads are sent as ETF.
+ etf._('etf');
+
+ /// The value of this [GatewayPayloadFormat].
+ final String value;
+
+ const GatewayPayloadFormat._(this.value);
+
+ @override
+ String toString() => value;
+}
+
+/// The compression of a Gateway connection.
+enum GatewayCompression {
+ /// No compression is used.
+ none,
+
+ /// The entire connection is compressed.
+ transport,
+
+ /// Each packet is individually compressed.
+ ///
+ /// Cannot be used if [GatewayPayloadFormat.etf] is used.
+ payload,
+}
diff --git a/lib/src/builders/application.dart b/lib/src/builders/application.dart
new file mode 100644
index 000000000..03fc247d4
--- /dev/null
+++ b/lib/src/builders/application.dart
@@ -0,0 +1,53 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/image.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/application.dart';
+import 'package:nyxx/src/utils/flags.dart';
+
+class ApplicationUpdateBuilder extends UpdateBuilder {
+ Uri? customInstallUrl;
+
+ String? description;
+
+ Uri? roleConnectionsVerificationUrl;
+
+ InstallationParameters? installationParameters;
+
+ Flags? flags;
+
+ ImageBuilder? icon;
+
+ ImageBuilder? coverImage;
+
+ Uri? interactionsEndpointUrl;
+
+ List? tags;
+
+ ApplicationUpdateBuilder({
+ this.customInstallUrl,
+ this.description,
+ this.roleConnectionsVerificationUrl,
+ this.installationParameters,
+ this.flags,
+ this.icon = sentinelImageBuilder,
+ this.coverImage = sentinelImageBuilder,
+ this.interactionsEndpointUrl,
+ this.tags,
+ });
+
+ @override
+ Map build() => {
+ if (customInstallUrl != null) 'custom_install_url': customInstallUrl!.toString(),
+ if (description != null) 'description': description,
+ if (roleConnectionsVerificationUrl != null) 'role_connections_verification_url': roleConnectionsVerificationUrl!.toString(),
+ if (installationParameters != null)
+ 'install_params': {
+ 'scopes': installationParameters!.scopes,
+ 'permissions': installationParameters!.permissions.toString(),
+ },
+ if (flags != null) 'flags': flags!.value,
+ if (!identical(icon, sentinelImageBuilder)) 'icon': icon?.buildDataString(),
+ if (!identical(coverImage, sentinelImageBuilder)) 'cover_image': coverImage?.buildDataString(),
+ if (tags != null) 'tags': tags,
+ };
+}
diff --git a/lib/src/builders/application_command.dart b/lib/src/builders/application_command.dart
new file mode 100644
index 000000000..8687a06a0
--- /dev/null
+++ b/lib/src/builders/application_command.dart
@@ -0,0 +1,419 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/channel/channel.dart';
+import 'package:nyxx/src/models/commands/application_command.dart';
+import 'package:nyxx/src/models/commands/application_command_option.dart';
+import 'package:nyxx/src/models/locale.dart';
+import 'package:nyxx/src/models/permissions.dart';
+import 'package:nyxx/src/utils/flags.dart';
+
+class ApplicationCommandBuilder extends CreateBuilder {
+ String name;
+
+ Map? nameLocalizations;
+
+ String? description;
+
+ Map? descriptionLocalizations;
+
+ List? options;
+
+ Flags? defaultMemberPermissions;
+
+ bool? hasDmPermission;
+
+ ApplicationCommandType type;
+
+ bool? isNsfw;
+
+ ApplicationCommandBuilder({
+ required this.name,
+ required this.type,
+ this.nameLocalizations,
+ this.description,
+ this.descriptionLocalizations,
+ this.options,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ });
+
+ ApplicationCommandBuilder.chatInput({
+ required this.name,
+ this.nameLocalizations,
+ required String this.description,
+ this.descriptionLocalizations,
+ required List this.options,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ }) : type = ApplicationCommandType.chatInput;
+
+ ApplicationCommandBuilder.message({
+ required this.name,
+ this.nameLocalizations,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ }) : type = ApplicationCommandType.message,
+ description = null,
+ descriptionLocalizations = null,
+ options = null;
+
+ ApplicationCommandBuilder.user({
+ required this.name,
+ this.nameLocalizations,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ }) : type = ApplicationCommandType.user,
+ description = null,
+ descriptionLocalizations = null,
+ options = null;
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (nameLocalizations != null) 'name_localizations': {for (final MapEntry(:key, :value) in nameLocalizations!.entries) key.identifier: value},
+ if (description != null) 'description': description,
+ if (descriptionLocalizations != null)
+ 'description_localizations': {for (final MapEntry(:key, :value) in descriptionLocalizations!.entries) key.identifier: value},
+ if (options != null) 'options': options!.map((e) => e.build()).toList(),
+ if (defaultMemberPermissions != null) 'default_member_permissions': defaultMemberPermissions!.value.toString(),
+ if (hasDmPermission != null) 'dm_permission': hasDmPermission,
+ 'type': type.value,
+ if (isNsfw != null) 'nsfw': isNsfw,
+ };
+}
+
+class ApplicationCommandUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ Map? nameLocalizations;
+
+ String? description;
+
+ Map? descriptionLocalizations;
+
+ List? options;
+
+ Flags? defaultMemberPermissions;
+
+ bool? hasDmPermission;
+
+ bool? isNsfw;
+
+ ApplicationCommandUpdateBuilder({
+ this.name,
+ this.nameLocalizations = sentinelMap,
+ this.description,
+ this.descriptionLocalizations = sentinelMap,
+ this.options,
+ this.defaultMemberPermissions = sentinelFlags,
+ this.hasDmPermission,
+ this.isNsfw,
+ });
+
+ ApplicationCommandUpdateBuilder.chatInput({
+ required this.name,
+ this.nameLocalizations = sentinelMap,
+ this.description,
+ this.descriptionLocalizations = sentinelMap,
+ this.options,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ });
+
+ ApplicationCommandUpdateBuilder.message({
+ this.name,
+ this.nameLocalizations,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ }) : description = null,
+ descriptionLocalizations = null,
+ options = null;
+
+ ApplicationCommandUpdateBuilder.user({
+ this.name,
+ this.nameLocalizations,
+ this.defaultMemberPermissions,
+ this.hasDmPermission,
+ this.isNsfw,
+ }) : description = null,
+ descriptionLocalizations = null,
+ options = null;
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (!identical(nameLocalizations, sentinelMap)) 'name_localizations': nameLocalizations?.map((key, value) => MapEntry(key.toString(), value)),
+ if (description != null) 'description': description,
+ if (!identical(descriptionLocalizations, sentinelMap))
+ 'description_localizations': descriptionLocalizations?.map((key, value) => MapEntry(key.toString(), value)),
+ if (options != null) 'options': options!.map((e) => e.build()).toList(),
+ if (!identical(defaultMemberPermissions, sentinelFlags)) 'default_member_permissions': defaultMemberPermissions?.value.toString(),
+ if (hasDmPermission != null) 'dm_permission': hasDmPermission,
+ if (isNsfw != null) 'nsfw': isNsfw,
+ };
+}
+
+class CommandOptionBuilder extends CreateBuilder {
+ CommandOptionType type;
+
+ String name;
+
+ Map? nameLocalizations;
+
+ String description;
+
+ Map? descriptionLocalizations;
+
+ bool? isRequired;
+
+ List>? choices;
+
+ List? options;
+
+ List? channelTypes;
+
+ num? minValue;
+
+ num? maxValue;
+
+ int? minLength;
+
+ int? maxLength;
+
+ bool? hasAutocomplete;
+
+ CommandOptionBuilder({
+ required this.type,
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ this.choices,
+ this.options,
+ this.channelTypes,
+ this.minValue,
+ this.maxValue,
+ this.minLength,
+ this.maxLength,
+ this.hasAutocomplete,
+ });
+
+ CommandOptionBuilder.subCommand({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ required List this.options,
+ }) : type = CommandOptionType.subCommand,
+ isRequired = null,
+ choices = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.subCommandGroup({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ required List this.options,
+ }) : type = CommandOptionType.subCommandGroup,
+ isRequired = null,
+ choices = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.string({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ List>? this.choices,
+ this.minLength,
+ this.maxLength,
+ this.hasAutocomplete,
+ }) : type = CommandOptionType.string,
+ options = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null;
+
+ CommandOptionBuilder.integer({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ List>? this.choices,
+ int? this.minValue,
+ int? this.maxValue,
+ this.hasAutocomplete,
+ }) : type = CommandOptionType.integer,
+ options = null,
+ channelTypes = null,
+ minLength = null,
+ maxLength = null;
+
+ CommandOptionBuilder.boolean({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ }) : type = CommandOptionType.boolean,
+ choices = null,
+ options = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.user({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ }) : type = CommandOptionType.user,
+ choices = null,
+ options = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.channel({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ this.channelTypes,
+ }) : type = CommandOptionType.channel,
+ choices = null,
+ options = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.role({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ }) : type = CommandOptionType.role,
+ choices = null,
+ options = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.mentionable({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ }) : type = CommandOptionType.mentionable,
+ choices = null,
+ options = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ CommandOptionBuilder.number({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ List>? this.choices,
+ double? this.minValue,
+ double? this.maxValue,
+ this.hasAutocomplete,
+ }) : type = CommandOptionType.number,
+ options = null,
+ channelTypes = null,
+ minLength = null,
+ maxLength = null;
+
+ CommandOptionBuilder.attachment({
+ required this.name,
+ this.nameLocalizations,
+ required this.description,
+ this.descriptionLocalizations,
+ this.isRequired,
+ }) : type = CommandOptionType.attachment,
+ choices = null,
+ options = null,
+ channelTypes = null,
+ minValue = null,
+ maxValue = null,
+ minLength = null,
+ maxLength = null,
+ hasAutocomplete = null;
+
+ @override
+ Map build() => {
+ 'type': type.value,
+ 'name': name,
+ if (nameLocalizations != null) 'name_localizations': {for (final MapEntry(:key, :value) in nameLocalizations!.entries) key.identifier: value},
+ 'description': description,
+ if (descriptionLocalizations != null)
+ 'description_localizations': {for (final MapEntry(:key, :value) in nameLocalizations!.entries) key.identifier: value},
+ if (isRequired != null) 'required': isRequired,
+ if (choices != null) 'choices': choices!.map((e) => e.build()).toList(),
+ if (options != null) 'options': options!.map((e) => e.build()).toList(),
+ if (channelTypes != null) 'channel_types': channelTypes!.map((e) => e.value).toList(),
+ if (minValue != null) 'min_value': minValue,
+ if (maxValue != null) 'max_value': maxValue,
+ if (minLength != null) 'min_length': minLength,
+ if (maxLength != null) 'max_length': maxLength,
+ if (hasAutocomplete != null) 'autocomplete': hasAutocomplete,
+ };
+}
+
+class CommandOptionChoiceBuilder extends CreateBuilder {
+ String name;
+
+ Map? nameLocalizations;
+
+ T value;
+
+ CommandOptionChoiceBuilder({required this.name, this.nameLocalizations, required this.value});
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (nameLocalizations != null) 'name_localizations': {for (final MapEntry(:key, :value) in nameLocalizations!.entries) key.identifier: value},
+ 'value': value,
+ };
+}
diff --git a/lib/src/builders/application_role_connection.dart b/lib/src/builders/application_role_connection.dart
new file mode 100644
index 000000000..4b49e2c66
--- /dev/null
+++ b/lib/src/builders/application_role_connection.dart
@@ -0,0 +1,20 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/user/application_role_connection.dart';
+
+class ApplicationRoleConnectionUpdateBuilder extends UpdateBuilder {
+ String? platformName;
+
+ String? platformUsername;
+
+ Map? metadata;
+
+ ApplicationRoleConnectionUpdateBuilder({this.platformName = sentinelString, this.platformUsername = sentinelString, this.metadata});
+
+ @override
+ Map build() => {
+ if (!identical(platformName, sentinelString)) 'platform_name': platformName,
+ if (!identical(platformUsername, sentinelString)) 'platform_username': platformUsername,
+ if (metadata != null) 'metadata': metadata,
+ };
+}
diff --git a/lib/src/builders/builder.dart b/lib/src/builders/builder.dart
new file mode 100644
index 000000000..e5782858c
--- /dev/null
+++ b/lib/src/builders/builder.dart
@@ -0,0 +1,13 @@
+abstract class Builder {
+ const Builder();
+
+ Map build();
+}
+
+abstract class CreateBuilder extends Builder {
+ const CreateBuilder();
+}
+
+abstract class UpdateBuilder extends Builder {
+ const UpdateBuilder();
+}
diff --git a/lib/src/builders/channel/channel_position.dart b/lib/src/builders/channel/channel_position.dart
new file mode 100644
index 000000000..e41a1d7b1
--- /dev/null
+++ b/lib/src/builders/channel/channel_position.dart
@@ -0,0 +1,28 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/channel/guild_channel.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class ChannelPositionBuilder extends UpdateBuilder {
+ Snowflake channelId;
+
+ int? position;
+
+ bool? lockPermissions;
+
+ Snowflake? parentId;
+
+ ChannelPositionBuilder({
+ required this.channelId,
+ this.position,
+ this.lockPermissions,
+ this.parentId,
+ });
+
+ @override
+ Map build() => {
+ 'id': channelId.toString(),
+ if (position != null) 'position': position,
+ if (lockPermissions != null) 'lock_permissions': lockPermissions,
+ if (parentId != null) 'parent_id': parentId!.toString(),
+ };
+}
diff --git a/lib/src/builders/channel/forum_tag.dart b/lib/src/builders/channel/forum_tag.dart
new file mode 100644
index 000000000..3542fca88
--- /dev/null
+++ b/lib/src/builders/channel/forum_tag.dart
@@ -0,0 +1,23 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/channel/types/forum.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class ForumTagBuilder extends CreateBuilder {
+ String name;
+
+ bool? isModerated;
+
+ Snowflake? emojiId;
+
+ String? emojiName;
+
+ ForumTagBuilder({required this.name, this.isModerated, this.emojiId, this.emojiName});
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (isModerated != null) 'moderated': isModerated,
+ if (emojiId != null) 'emoji_id': emojiId!.toString(),
+ if (emojiName != null) 'emoji_name': emojiName,
+ };
+}
diff --git a/lib/src/builders/channel/group_dm.dart b/lib/src/builders/channel/group_dm.dart
new file mode 100644
index 000000000..99a40ee89
--- /dev/null
+++ b/lib/src/builders/channel/group_dm.dart
@@ -0,0 +1,18 @@
+import 'dart:convert';
+
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/channel/types/group_dm.dart';
+
+class GroupDmUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ List? icon;
+
+ GroupDmUpdateBuilder({this.name, this.icon});
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (icon != null) 'icon': base64Encode(icon!),
+ };
+}
diff --git a/lib/src/builders/channel/guild_channel.dart b/lib/src/builders/channel/guild_channel.dart
new file mode 100644
index 000000000..6016f440c
--- /dev/null
+++ b/lib/src/builders/channel/guild_channel.dart
@@ -0,0 +1,449 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/channel/channel.dart';
+import 'package:nyxx/src/models/channel/guild_channel.dart';
+import 'package:nyxx/src/models/channel/types/forum.dart';
+import 'package:nyxx/src/models/channel/types/guild_announcement.dart';
+import 'package:nyxx/src/models/channel/types/guild_category.dart';
+import 'package:nyxx/src/models/channel/types/guild_stage.dart';
+import 'package:nyxx/src/models/channel/types/guild_text.dart';
+import 'package:nyxx/src/models/channel/types/guild_voice.dart';
+import 'package:nyxx/src/models/channel/voice_channel.dart';
+import 'package:nyxx/src/models/permission_overwrite.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+import 'package:nyxx/src/utils/flags.dart';
+
+class GuildChannelBuilder extends CreateBuilder {
+ String name;
+
+ ChannelType type;
+
+ int? position;
+
+ List>? permissionOverwrites;
+
+ GuildChannelBuilder({
+ required this.name,
+ required this.type,
+ this.position,
+ this.permissionOverwrites,
+ });
+
+ @override
+ Map build() => {
+ 'name': name,
+ 'type': type.value,
+ if (position != null) 'position': position,
+ if (permissionOverwrites != null) 'permission_overwrites': permissionOverwrites!.map((e) => e.build()).toList(),
+ };
+}
+
+class GuildChannelUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ int? position;
+
+ List>? permissionOverwrites;
+
+ GuildChannelUpdateBuilder({this.name, this.position = sentinelInteger, this.permissionOverwrites});
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (!identical(position, sentinelInteger)) 'position': position,
+ if (permissionOverwrites != null) 'permission_overwrites': permissionOverwrites!.map((e) => e.build()).toList(),
+ };
+}
+
+class GuildTextChannelBuilder extends GuildChannelBuilder {
+ String? topic;
+
+ Duration? rateLimitPerUser;
+
+ Snowflake? parentId;
+
+ bool? isNsfw;
+
+ Duration? defaultAutoArchiveDuration;
+
+ GuildTextChannelBuilder({
+ required super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.topic,
+ this.rateLimitPerUser,
+ this.parentId,
+ this.isNsfw,
+ this.defaultAutoArchiveDuration,
+ }) : super(type: ChannelType.guildText);
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (topic != null) 'topic': topic,
+ if (rateLimitPerUser != null) 'rate_limit_per_user': rateLimitPerUser!.inSeconds,
+ if (parentId != null) 'parent_id': parentId!.toString(),
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (defaultAutoArchiveDuration != null) 'default_auto_archive_duration': defaultAutoArchiveDuration!.inMinutes,
+ };
+}
+
+class GuildTextChannelUpdateBuilder extends GuildChannelUpdateBuilder {
+ ChannelType? type;
+
+ String? topic;
+
+ bool? isNsfw;
+
+ Duration? rateLimitPerUser;
+
+ Snowflake? parentId;
+
+ Duration? defaultAutoArchiveDuration;
+
+ Duration? defaultThreadRateLimitPerUser;
+
+ GuildTextChannelUpdateBuilder({
+ super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.type,
+ this.topic = sentinelString,
+ this.isNsfw,
+ this.rateLimitPerUser = sentinelDuration,
+ this.parentId = sentinelSnowflake,
+ this.defaultAutoArchiveDuration = sentinelDuration,
+ this.defaultThreadRateLimitPerUser,
+ });
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (type != null) 'type': type!.value,
+ if (!identical(topic, sentinelString)) 'topic': topic,
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (!identical(rateLimitPerUser, sentinelDuration)) 'rate_limit_per_user': rateLimitPerUser?.inSeconds,
+ if (!identical(parentId, sentinelSnowflake)) 'parent_id': parentId?.toString(),
+ if (!identical(defaultAutoArchiveDuration, sentinelDuration)) 'default_auto_archive_duration': defaultAutoArchiveDuration?.inMinutes,
+ if (defaultThreadRateLimitPerUser != null) 'default_thread_rate_limit_per_user': defaultThreadRateLimitPerUser!.inSeconds,
+ };
+}
+
+class GuildAnnouncementChannelBuilder extends GuildChannelBuilder {
+ String? topic;
+
+ Snowflake? parentId;
+
+ bool? isNsfw;
+
+ Duration? defaultAutoArchiveDuration;
+
+ GuildAnnouncementChannelBuilder({
+ required super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.topic,
+ this.parentId,
+ this.isNsfw,
+ this.defaultAutoArchiveDuration,
+ }) : super(type: ChannelType.guildAnnouncement);
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (topic != null) 'topic': topic,
+ if (parentId != null) 'parent_id': parentId!.toString(),
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (defaultAutoArchiveDuration != null) 'default_auto_archive_duration': defaultAutoArchiveDuration!.inMinutes,
+ };
+}
+
+class GuildAnnouncementChannelUpdateBuilder extends GuildChannelUpdateBuilder {
+ ChannelType? type;
+
+ String? topic;
+
+ bool? isNsfw;
+
+ Snowflake? parentId;
+
+ Duration? defaultAutoArchiveDuration;
+
+ GuildAnnouncementChannelUpdateBuilder({
+ super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.type,
+ this.topic = sentinelString,
+ this.isNsfw,
+ this.parentId = sentinelSnowflake,
+ this.defaultAutoArchiveDuration = sentinelDuration,
+ });
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (type != null) 'type': type!.value,
+ if (!identical(topic, sentinelString)) 'topic': topic,
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (!identical(parentId, sentinelSnowflake)) 'parent_id': parentId?.toString(),
+ if (!identical(defaultAutoArchiveDuration, sentinelDuration)) 'default_auto_archive_duration': defaultAutoArchiveDuration?.inMinutes,
+ };
+}
+
+class ForumChannelBuilder extends GuildChannelBuilder {
+ String? topic;
+
+ Duration? rateLimitPerUser;
+
+ Snowflake? parentId;
+
+ bool? isNsfw;
+
+ Duration? defaultAutoArchiveDuration;
+
+ DefaultReaction? defaultReaction;
+
+ List>? tags;
+
+ ForumSort? defaultSortOrder;
+
+ ForumChannelBuilder({
+ required super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.topic,
+ this.rateLimitPerUser,
+ this.parentId,
+ this.isNsfw,
+ this.defaultAutoArchiveDuration,
+ this.defaultReaction,
+ this.tags,
+ this.defaultSortOrder,
+ }) : super(type: ChannelType.guildForum);
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (topic != null) 'topic': topic,
+ if (rateLimitPerUser != null) 'rate_limit_per_user': rateLimitPerUser!.inSeconds,
+ if (parentId != null) 'parent_id': parentId!.toString(),
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (defaultAutoArchiveDuration != null) 'default_auto_archive_duration': defaultAutoArchiveDuration!.inMinutes,
+ if (!identical(defaultReaction, sentinelDefaultReaction))
+ 'default_reaction_emoji': defaultReaction == null
+ ? null
+ : {
+ if (defaultReaction!.emojiId != null) 'emoji_id': defaultReaction!.emojiId!.toString(),
+ if (defaultReaction!.emojiName != null) 'emoji_name': defaultReaction!.emojiName,
+ },
+ if (tags != null) 'available_tags': tags!.map((e) => e.build()).toList(),
+ if (defaultSortOrder != null) 'default_sort_order': defaultSortOrder!.value,
+ };
+}
+
+class ForumChannelUpdateBuilder extends GuildChannelUpdateBuilder {
+ String? topic;
+
+ bool? isNsfw;
+
+ Duration? rateLimitPerUser;
+
+ Snowflake? parentId;
+
+ Duration? defaultAutoArchiveDuration;
+
+ Flags? flags;
+
+ List>? tags;
+
+ DefaultReaction? defaultReaction;
+
+ Duration? defaultThreadRateLimitPerUser;
+
+ ForumSort? defaultSortOrder;
+
+ ForumLayout? defaultLayout;
+
+ ForumChannelUpdateBuilder({
+ super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.topic,
+ this.isNsfw,
+ this.rateLimitPerUser = sentinelDuration,
+ this.parentId = sentinelSnowflake,
+ this.defaultAutoArchiveDuration = sentinelDuration,
+ this.flags,
+ this.tags,
+ this.defaultReaction = sentinelDefaultReaction,
+ this.defaultThreadRateLimitPerUser,
+ this.defaultSortOrder,
+ this.defaultLayout,
+ });
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (topic != null) 'topic': topic,
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (!identical(rateLimitPerUser, sentinelDuration)) 'rate_limit_per_user': rateLimitPerUser?.inSeconds,
+ if (!identical(parentId, sentinelSnowflake)) 'parent_id': parentId?.toString(),
+ if (!identical(defaultAutoArchiveDuration, sentinelDuration)) 'default_auto_archive_duration': defaultAutoArchiveDuration?.inMinutes,
+ if (flags != null) 'flags': flags!.value,
+ if (tags != null) 'available_tags': tags!.map((e) => e.build()).toList(),
+ if (!identical(defaultReaction, sentinelDefaultReaction))
+ 'default_reaction_emoji': defaultReaction == null
+ ? null
+ : {
+ if (defaultReaction!.emojiId != null) 'emoji_id': defaultReaction!.emojiId!.toString(),
+ if (defaultReaction!.emojiName != null) 'emoji_name': defaultReaction!.emojiName,
+ },
+ if (defaultThreadRateLimitPerUser != null) 'default_thread_rate_limit_per_user': defaultThreadRateLimitPerUser!.inSeconds,
+ if (defaultSortOrder != null) 'default_sort_order': defaultSortOrder!.value,
+ if (defaultLayout != null) 'default_forum_layout': defaultLayout!.value,
+ };
+}
+
+abstract class _GuildVoiceOrStageChannelBuilder extends GuildChannelBuilder {
+ int? bitRate;
+
+ int? userLimit;
+
+ Snowflake? parentId;
+
+ bool? isNsfw;
+
+ String? rtcRegion;
+
+ VideoQualityMode? videoQualityMode;
+
+ _GuildVoiceOrStageChannelBuilder({
+ required super.name,
+ required super.type,
+ super.position,
+ super.permissionOverwrites,
+ this.bitRate,
+ this.userLimit,
+ this.parentId,
+ this.isNsfw,
+ this.rtcRegion,
+ this.videoQualityMode,
+ });
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (bitRate != null) 'bitrate': bitRate,
+ if (userLimit != null) 'user_limit': userLimit,
+ if (parentId != null) 'parent_id': parentId?.toString(),
+ if (rtcRegion != null) 'rtc_region': rtcRegion,
+ if (videoQualityMode != null) 'video_quality_mode': videoQualityMode!.value,
+ };
+}
+
+class GuildVoiceChannelBuilder extends _GuildVoiceOrStageChannelBuilder {
+ GuildVoiceChannelBuilder({
+ required super.name,
+ super.position,
+ super.permissionOverwrites,
+ super.bitRate,
+ super.userLimit,
+ super.parentId,
+ super.isNsfw,
+ super.rtcRegion,
+ super.videoQualityMode,
+ }) : super(type: ChannelType.guildVoice);
+}
+
+class GuildStageChannelBuilder extends _GuildVoiceOrStageChannelBuilder {
+ GuildStageChannelBuilder({
+ required super.name,
+ super.position,
+ super.permissionOverwrites,
+ super.bitRate,
+ super.userLimit,
+ super.parentId,
+ super.isNsfw,
+ super.rtcRegion,
+ super.videoQualityMode,
+ }) : super(type: ChannelType.guildStageVoice);
+}
+
+class _GuildVoiceOrStageChannelUpdateBuilder extends GuildChannelUpdateBuilder {
+ bool? isNsfw;
+
+ int? bitRate;
+
+ int? userLimit;
+
+ Snowflake? parentId;
+
+ String? rtcRegion;
+
+ VideoQualityMode? videoQualityMode;
+
+ _GuildVoiceOrStageChannelUpdateBuilder({
+ super.name,
+ super.position,
+ super.permissionOverwrites,
+ this.isNsfw,
+ this.bitRate,
+ this.userLimit,
+ this.parentId = sentinelSnowflake,
+ this.rtcRegion = sentinelString,
+ this.videoQualityMode,
+ });
+
+ @override
+ Map build() => {
+ ...super.build(),
+ if (isNsfw != null) 'nsfw': isNsfw,
+ if (bitRate != null) 'bitrate': bitRate,
+ if (userLimit != null) 'user_limit': userLimit,
+ if (!identical(parentId, sentinelSnowflake)) 'parent_id': parentId?.toString(),
+ if (!identical(rtcRegion, sentinelString)) 'rtc_region': rtcRegion,
+ if (videoQualityMode != null) 'video_quality_mode': videoQualityMode!.value,
+ };
+}
+
+class GuildVoiceChannelUpdateBuilder extends _GuildVoiceOrStageChannelUpdateBuilder {
+ GuildVoiceChannelUpdateBuilder({
+ super.name,
+ super.position,
+ super.permissionOverwrites,
+ super.isNsfw,
+ super.bitRate,
+ super.userLimit,
+ super.parentId = sentinelSnowflake,
+ super.rtcRegion = sentinelString,
+ super.videoQualityMode,
+ });
+}
+
+class GuildStageChannelUpdateBuilder extends _GuildVoiceOrStageChannelUpdateBuilder {
+ GuildStageChannelUpdateBuilder({
+ super.name,
+ super.position,
+ super.permissionOverwrites,
+ super.isNsfw,
+ super.bitRate,
+ super.userLimit,
+ super.parentId = sentinelSnowflake,
+ super.rtcRegion = sentinelString,
+ super.videoQualityMode,
+ });
+}
+
+class GuildCategoryBuilder extends GuildChannelBuilder {
+ GuildCategoryBuilder({
+ required super.name,
+ super.position,
+ super.permissionOverwrites,
+ }) : super(type: ChannelType.guildCategory);
+}
+
+class GuildCategoryUpdateBuilder extends GuildChannelUpdateBuilder {
+ GuildCategoryUpdateBuilder({super.name, super.position, super.permissionOverwrites});
+}
diff --git a/lib/src/builders/channel/stage_instance.dart b/lib/src/builders/channel/stage_instance.dart
new file mode 100644
index 000000000..f398f0ca7
--- /dev/null
+++ b/lib/src/builders/channel/stage_instance.dart
@@ -0,0 +1,42 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/channel/stage_instance.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class StageInstanceBuilder extends CreateBuilder {
+ String topic;
+
+ PrivacyLevel? privacyLevel;
+
+ bool? sendStartNotification;
+
+ Snowflake? guildScheduledEventId;
+
+ StageInstanceBuilder({
+ required this.topic,
+ this.privacyLevel,
+ this.sendStartNotification,
+ this.guildScheduledEventId,
+ });
+
+ @override
+ Map build() => {
+ 'topic': topic,
+ if (privacyLevel != null) 'privacy_level': privacyLevel!.value,
+ if (sendStartNotification != null) 'send_start_notification': sendStartNotification,
+ if (guildScheduledEventId != null) 'guild_scheduled_event_id': guildScheduledEventId!.toString(),
+ };
+}
+
+class StageInstanceUpdateBuilder extends UpdateBuilder {
+ String? topic;
+
+ PrivacyLevel? privacyLevel;
+
+ StageInstanceUpdateBuilder({this.topic, this.privacyLevel});
+
+ @override
+ Map build() => {
+ if (topic != null) 'topic': topic,
+ if (privacyLevel != null) 'privacy_level': privacyLevel!.value,
+ };
+}
diff --git a/lib/src/builders/channel/thread.dart b/lib/src/builders/channel/thread.dart
new file mode 100644
index 000000000..f838d1f10
--- /dev/null
+++ b/lib/src/builders/channel/thread.dart
@@ -0,0 +1,120 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/message/message.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/channel/channel.dart';
+import 'package:nyxx/src/models/channel/thread.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+import 'package:nyxx/src/utils/flags.dart';
+
+class ThreadFromMessageBuilder extends CreateBuilder {
+ String name;
+
+ Duration? autoArchiveDuration;
+
+ Duration? rateLimitPerUser;
+
+ ThreadFromMessageBuilder({required this.name, this.autoArchiveDuration, this.rateLimitPerUser});
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (autoArchiveDuration != null) 'auto_archive_duration': autoArchiveDuration!.inMinutes,
+ if (rateLimitPerUser != null) 'rate_limit_per_user': rateLimitPerUser!.inSeconds,
+ };
+}
+
+class ThreadBuilder extends CreateBuilder {
+ static const archiveOneHour = Duration(minutes: 60);
+ static const archiveOneDay = Duration(minutes: 1440);
+ static const archiveThreeDays = Duration(minutes: 4320);
+ static const archiveOneWeek = Duration(minutes: 10080);
+
+ String name;
+
+ Duration? autoArchiveDuration;
+
+ ChannelType type;
+
+ bool? invitable;
+
+ Duration? rateLimitPerUser;
+
+ ThreadBuilder({required this.name, this.autoArchiveDuration, required this.type, this.invitable, this.rateLimitPerUser});
+
+ ThreadBuilder.publicThread({required this.name, this.autoArchiveDuration, this.rateLimitPerUser}) : type = ChannelType.publicThread;
+
+ ThreadBuilder.privateThread({required this.name, this.autoArchiveDuration, this.invitable, this.rateLimitPerUser}) : type = ChannelType.privateThread;
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (autoArchiveDuration != null) 'auto_archive_duration': autoArchiveDuration!.inMinutes,
+ 'type': type.value,
+ if (invitable != null) 'invitable': invitable,
+ if (rateLimitPerUser != null) 'rate_limit_per_user': rateLimitPerUser!.inSeconds,
+ };
+}
+
+class ForumThreadBuilder extends CreateBuilder {
+ String name;
+
+ Duration? autoArchiveDuration;
+
+ Duration? rateLimitPerUser;
+
+ MessageBuilder message;
+
+ List? appliedTags;
+
+ ForumThreadBuilder({required this.name, this.autoArchiveDuration, this.rateLimitPerUser, required this.message, this.appliedTags});
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (autoArchiveDuration != null) 'auto_archive_duration': autoArchiveDuration!.inMinutes,
+ if (rateLimitPerUser != null) 'rate_limit_per_user': rateLimitPerUser!.inSeconds,
+ 'message': message.build(),
+ if (appliedTags != null) 'applied_tags': appliedTags!.map((e) => e.toString()).toList(),
+ };
+}
+
+class ThreadUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ bool? isArchived;
+
+ Duration? autoArchiveDuration;
+
+ bool? isLocked;
+
+ bool? isInvitable;
+
+ Duration? rateLimitPerUser;
+
+ Flags? flags;
+
+ List? appliedTags;
+
+ ThreadUpdateBuilder({
+ this.name,
+ this.isArchived,
+ this.autoArchiveDuration,
+ this.isLocked,
+ this.isInvitable,
+ this.rateLimitPerUser = sentinelDuration,
+ this.flags,
+ this.appliedTags,
+ });
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (isArchived != null) 'archived': isArchived,
+ if (autoArchiveDuration != null) 'auto_archive_duration': autoArchiveDuration!.inMinutes,
+ if (isLocked != null) 'locked': isLocked,
+ if (isInvitable != null) 'invitable': isInvitable,
+ if (!identical(rateLimitPerUser, sentinelDuration)) 'rate_limit_per_user': rateLimitPerUser?.inSeconds,
+ if (flags != null) 'flags': flags!.value,
+ if (appliedTags != null) 'applied_tags': appliedTags!.map((e) => e.toString()).toList(),
+ };
+}
diff --git a/lib/src/builders/emoji/emoji.dart b/lib/src/builders/emoji/emoji.dart
new file mode 100644
index 000000000..a0bee4642
--- /dev/null
+++ b/lib/src/builders/emoji/emoji.dart
@@ -0,0 +1,47 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/image.dart';
+import 'package:nyxx/src/models/emoji.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class EmojiBuilder implements CreateBuilder {
+ /// The name of the emoji.
+ String name;
+
+ /// The 128x128 emoji image.
+ ImageBuilder image;
+
+ /// The roles allowed to use this emoji.
+ Iterable roles;
+
+ EmojiBuilder({
+ required this.name,
+ required this.image,
+ required this.roles,
+ });
+
+ @override
+ Map build() => {
+ 'name': name,
+ 'image': image.buildDataString(),
+ 'roles': roles.map((s) => s.toString()).toList(),
+ };
+}
+
+class EmojiUpdateBuilder implements UpdateBuilder {
+ /// The name of the emoji.
+ String? name;
+
+ /// The roles allowed to use this emoji.
+ Iterable? roles;
+
+ EmojiUpdateBuilder({
+ this.name,
+ this.roles,
+ });
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (roles != null) 'roles': roles!.map((s) => s.toString()).toList(),
+ };
+}
diff --git a/lib/src/builders/emoji/reaction.dart b/lib/src/builders/emoji/reaction.dart
new file mode 100644
index 000000000..c86416ea4
--- /dev/null
+++ b/lib/src/builders/emoji/reaction.dart
@@ -0,0 +1,17 @@
+import 'package:nyxx/src/models/emoji.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class ReactionBuilder {
+ String name;
+
+ Snowflake? id;
+
+ ReactionBuilder({required this.name, required this.id});
+
+ factory ReactionBuilder.fromEmoji(Emoji emoji) => ReactionBuilder(
+ name: emoji.name!,
+ id: emoji.id == Snowflake.zero ? null : emoji.id,
+ );
+
+ String build() => '$name${id == null ? '' : ':$id'}';
+}
diff --git a/lib/src/builders/entitlement.dart b/lib/src/builders/entitlement.dart
new file mode 100644
index 000000000..29d93be78
--- /dev/null
+++ b/lib/src/builders/entitlement.dart
@@ -0,0 +1,29 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/entitlement.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class TestEntitlementBuilder extends CreateBuilder {
+ Snowflake skuId;
+
+ Snowflake ownerId;
+
+ TestEntitlementType ownerType;
+
+ TestEntitlementBuilder({required this.skuId, required this.ownerId, required this.ownerType});
+
+ @override
+ Map build() => {
+ 'sku_id': skuId.toString(),
+ 'owner_id': ownerId.toString(),
+ 'owner_type': ownerType.value,
+ };
+}
+
+enum TestEntitlementType {
+ guildSubscription._(1),
+ userSubscription._(2);
+
+ final int value;
+
+ const TestEntitlementType._(this.value);
+}
diff --git a/lib/src/builders/guild/auto_moderation.dart b/lib/src/builders/guild/auto_moderation.dart
new file mode 100644
index 000000000..43eee516b
--- /dev/null
+++ b/lib/src/builders/guild/auto_moderation.dart
@@ -0,0 +1,120 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/guild/auto_moderation.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class AutoModerationRuleBuilder extends CreateBuilder {
+ String name;
+
+ AutoModerationEventType eventType;
+
+ TriggerType triggerType;
+
+ TriggerMetadata? metadata;
+
+ List actions;
+
+ bool? isEnabled;
+
+ List? exemptRoleIds;
+
+ List? exemptChannelIds;
+
+ AutoModerationRuleBuilder({
+ required this.name,
+ required this.eventType,
+ required this.triggerType,
+ this.metadata,
+ required this.actions,
+ this.isEnabled,
+ this.exemptRoleIds,
+ this.exemptChannelIds,
+ });
+
+ @override
+ Map build() => {
+ 'name': name,
+ 'event_type': eventType.value,
+ 'trigger_type': triggerType.value,
+ if (metadata != null)
+ 'trigger_metadata': {
+ 'keyword_filter': metadata!.keywordFilter,
+ 'regex_patterns': metadata!.regexPatterns,
+ 'presets': metadata!.presets?.map((type) => type.value).toList(),
+ 'allow_list': metadata!.allowList,
+ 'mention_total_limit': metadata!.mentionTotalLimit,
+ 'mention_raid_protection_enabled': metadata!.isMentionRaidProtectionEnabled,
+ },
+ 'actions': [
+ for (final action in actions)
+ {
+ 'type': action.type.value,
+ if (action.metadata != null)
+ 'metadata': {
+ 'channel_id': action.metadata!.channelId?.toString(),
+ 'duration_seconds': action.metadata!.duration?.inSeconds,
+ 'custom_message': action.metadata!.customMessage,
+ }
+ }
+ ],
+ if (isEnabled != null) 'enabled': isEnabled,
+ if (exemptRoleIds != null) 'exempt_roles': exemptRoleIds!.map((id) => id.toString()).toList(),
+ if (exemptChannelIds != null) 'exempt_channels': exemptChannelIds!.map((id) => id.toString()).toList(),
+ };
+}
+
+class AutoModerationRuleUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ AutoModerationEventType? eventType;
+
+ TriggerMetadata? metadata;
+
+ List? actions;
+
+ bool? isEnabled;
+
+ List? exemptRoleIds;
+
+ List? exemptChannelIds;
+
+ AutoModerationRuleUpdateBuilder({
+ this.name,
+ this.eventType,
+ this.metadata,
+ this.actions,
+ this.isEnabled,
+ this.exemptRoleIds,
+ this.exemptChannelIds,
+ });
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (eventType != null) 'event_type': eventType!.value,
+ if (metadata != null)
+ 'trigger_metadata': {
+ 'keyword_filter': metadata!.keywordFilter,
+ 'regex_patterns': metadata!.regexPatterns,
+ 'presets': metadata!.presets?.map((type) => type.value).toList(),
+ 'allow_list': metadata!.allowList,
+ 'mention_total_limit': metadata!.mentionTotalLimit,
+ 'mention_raid_protection_enabled': metadata!.isMentionRaidProtectionEnabled,
+ },
+ if (actions != null)
+ 'actions': [
+ for (final action in actions!)
+ {
+ 'type': action.type.value,
+ if (action.metadata != null)
+ 'metadata': {
+ 'channel_id': action.metadata!.channelId?.toString(),
+ 'duration_seconds': action.metadata!.duration?.inSeconds,
+ 'custom_message': action.metadata!.customMessage,
+ }
+ }
+ ],
+ if (isEnabled != null) 'enabled': isEnabled,
+ if (exemptRoleIds != null) 'exempt_roles': exemptRoleIds!.map((id) => id.toString()).toList(),
+ if (exemptChannelIds != null) 'exempt_channels': exemptChannelIds!.map((id) => id.toString()).toList(),
+ };
+}
diff --git a/lib/src/builders/guild/guild.dart b/lib/src/builders/guild/guild.dart
new file mode 100644
index 000000000..374a45939
--- /dev/null
+++ b/lib/src/builders/guild/guild.dart
@@ -0,0 +1,148 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/channel/guild_channel.dart';
+import 'package:nyxx/src/builders/image.dart';
+import 'package:nyxx/src/builders/role.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/http/managers/guild_manager.dart';
+import 'package:nyxx/src/models/guild/guild.dart';
+import 'package:nyxx/src/models/locale.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+import 'package:nyxx/src/utils/flags.dart';
+
+class GuildBuilder extends CreateBuilder {
+ String name;
+
+ ImageBuilder? icon;
+
+ VerificationLevel? verificationLevel;
+
+ MessageNotificationLevel? defaultMessageNotificationLevel;
+
+ ExplicitContentFilterLevel? explicitContentFilterLevel;
+
+ List? roles;
+
+ List? channels;
+
+ Snowflake? afkChannelId;
+
+ Duration? afkTimeout;
+
+ Snowflake? systemChannelId;
+
+ Flags? systemChannelFlags;
+
+ GuildBuilder({
+ required this.name,
+ this.icon,
+ this.verificationLevel,
+ this.defaultMessageNotificationLevel,
+ this.explicitContentFilterLevel,
+ this.roles,
+ this.channels,
+ this.afkChannelId,
+ this.afkTimeout,
+ this.systemChannelId,
+ this.systemChannelFlags,
+ });
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (icon != null) 'icon': icon!.buildDataString(),
+ if (verificationLevel != null) 'verification_level': verificationLevel!.value,
+ if (defaultMessageNotificationLevel != null) 'default_message_notification_level': defaultMessageNotificationLevel!.value,
+ if (explicitContentFilterLevel != null) 'explicit_content_filter_level': explicitContentFilterLevel!.value,
+ if (roles != null) 'roles': roles!.map((b) => b.build()).toList(),
+ if (channels != null) 'channels': channels!.map((b) => b.build()).toList(),
+ if (afkChannelId != null) 'afk_channel_id': afkChannelId!.toString(),
+ if (afkTimeout != null) 'afk_timeout': afkTimeout!.inSeconds,
+ if (systemChannelId != null) 'system_channel_id': systemChannelId!.toString(),
+ if (systemChannelFlags != null) 'system_channel_flags': systemChannelFlags!.value,
+ };
+}
+
+class GuildUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ VerificationLevel? verificationLevel;
+
+ MessageNotificationLevel? defaultMessageNotificationLevel;
+
+ ExplicitContentFilterLevel? explicitContentFilterLevel;
+
+ Snowflake? afkChannelId;
+
+ Duration? afkTimeout;
+
+ ImageBuilder? icon;
+
+ Snowflake? newOwnerId;
+
+ ImageBuilder? splash;
+
+ ImageBuilder? discoverySplash;
+
+ ImageBuilder? banner;
+
+ Snowflake? systemChannelId;
+
+ Flags? systemChannelFlags;
+
+ Snowflake? rulesChannelId;
+
+ Snowflake? publicUpdatesChannelId;
+
+ Locale? preferredLocale;
+
+ Flags? features;
+
+ String? description;
+
+ bool? premiumProgressBarEnabled;
+
+ GuildUpdateBuilder({
+ this.name,
+ this.verificationLevel,
+ this.defaultMessageNotificationLevel,
+ this.explicitContentFilterLevel,
+ this.afkChannelId = sentinelSnowflake,
+ this.afkTimeout,
+ this.icon = sentinelImageBuilder,
+ this.newOwnerId,
+ this.splash = sentinelImageBuilder,
+ this.discoverySplash = sentinelImageBuilder,
+ this.banner = sentinelImageBuilder,
+ this.systemChannelId,
+ this.systemChannelFlags,
+ this.rulesChannelId,
+ this.publicUpdatesChannelId,
+ this.preferredLocale,
+ this.features,
+ this.description = sentinelString,
+ this.premiumProgressBarEnabled,
+ });
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (verificationLevel != null) 'verificationLevel': verificationLevel!.value,
+ if (defaultMessageNotificationLevel != null) 'defaultMessageNotificationLevel': defaultMessageNotificationLevel!.value,
+ if (explicitContentFilterLevel != null) 'explicitContentFilterLevel': explicitContentFilterLevel!.value,
+ if (!identical(afkChannelId, sentinelSnowflake)) 'afkChannelId': afkChannelId?.toString(),
+ if (afkTimeout != null) 'afkTimeout': afkTimeout!.inSeconds,
+ if (!identical(icon, sentinelImageBuilder)) 'icon': icon?.buildDataString(),
+ if (newOwnerId != null) 'newOwnerId': newOwnerId!.toString(),
+ if (!identical(splash, sentinelImageBuilder)) 'splash': splash?.buildDataString(),
+ if (!identical(discoverySplash, sentinelImageBuilder)) 'discoverySplash': discoverySplash?.buildDataString(),
+ if (!identical(banner, sentinelImageBuilder)) 'banner': banner?.buildDataString(),
+ if (systemChannelId != null) 'systemChannelId': systemChannelId!.toString(),
+ if (systemChannelFlags != null) 'systemChannelFlags': systemChannelFlags!.value,
+ if (rulesChannelId != null) 'rulesChannelId': rulesChannelId!.toString(),
+ if (publicUpdatesChannelId != null) 'publicUpdatesChannelId': publicUpdatesChannelId!.toString(),
+ if (preferredLocale != null) 'preferredLocale': preferredLocale!.identifier,
+ if (features != null) 'features': GuildManager.serializeGuildFeatures(features!),
+ if (!identical(description, sentinelString)) 'description': description,
+ if (premiumProgressBarEnabled != null) 'premiumProgressBarEnabled': premiumProgressBarEnabled,
+ };
+}
diff --git a/lib/src/builders/guild/member.dart b/lib/src/builders/guild/member.dart
new file mode 100644
index 000000000..6e2ec5112
--- /dev/null
+++ b/lib/src/builders/guild/member.dart
@@ -0,0 +1,85 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/guild/member.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+import 'package:nyxx/src/utils/flags.dart';
+
+class MemberBuilder extends CreateBuilder {
+ String accessToken;
+
+ Snowflake userId;
+
+ String? nick;
+
+ List? roleIds;
+
+ bool? isMute;
+
+ bool? isDeaf;
+
+ MemberBuilder({
+ required this.accessToken,
+ required this.userId,
+ this.nick,
+ this.roleIds,
+ this.isMute,
+ this.isDeaf,
+ });
+
+ @override
+ Map build() => {
+ 'access_token': accessToken,
+ if (nick != null) 'nick': nick,
+ if (roleIds != null) 'roles': roleIds!.map((e) => e.toString()).toList(),
+ if (isMute != null) 'mute': isMute,
+ if (isDeaf != null) 'deaf': isDeaf,
+ };
+}
+
+class MemberUpdateBuilder extends UpdateBuilder {
+ String? nick;
+
+ List? roleIds;
+
+ bool? isMute;
+
+ bool? isDeaf;
+
+ Snowflake? voiceChannelId;
+
+ DateTime? communicationDisabledUntil;
+
+ Flags? flags;
+
+ MemberUpdateBuilder({
+ this.nick = sentinelString,
+ this.roleIds,
+ this.isMute,
+ this.isDeaf,
+ this.voiceChannelId = sentinelSnowflake,
+ this.communicationDisabledUntil = sentinelDateTime,
+ this.flags,
+ });
+
+ @override
+ Map build() => {
+ if (!identical(nick, sentinelString)) 'nick': nick,
+ if (roleIds != null) 'roles': roleIds!.map((e) => e.toString()).toList(),
+ if (isMute != null) 'mute': isMute,
+ if (isDeaf != null) 'deaf': isDeaf,
+ if (!identical(voiceChannelId, sentinelSnowflake)) 'channel_id': voiceChannelId?.toString(),
+ if (!identical(communicationDisabledUntil, sentinelDateTime)) 'communication_disabled_until': communicationDisabledUntil?.toIso8601String(),
+ if (flags != null) 'flags': flags!.value,
+ };
+}
+
+class CurrentMemberUpdateBuilder extends UpdateBuilder {
+ String? nick;
+
+ CurrentMemberUpdateBuilder({this.nick = sentinelString});
+
+ @override
+ Map build() => {
+ if (!identical(nick, sentinelString)) 'nick': nick,
+ };
+}
diff --git a/lib/src/builders/guild/scheduled_event.dart b/lib/src/builders/guild/scheduled_event.dart
new file mode 100644
index 000000000..0a94e9ffb
--- /dev/null
+++ b/lib/src/builders/guild/scheduled_event.dart
@@ -0,0 +1,100 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/image.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/channel/stage_instance.dart';
+import 'package:nyxx/src/models/guild/scheduled_event.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class ScheduledEventBuilder extends CreateBuilder {
+ Snowflake? channelId;
+
+ EntityMetadata? metadata;
+
+ String name;
+
+ PrivacyLevel privacyLevel;
+
+ DateTime scheduledStartTime;
+
+ DateTime? scheduledEndTime;
+
+ String? description;
+
+ ScheduledEntityType type;
+
+ ImageBuilder? image;
+
+ ScheduledEventBuilder({
+ required this.channelId,
+ this.metadata,
+ required this.name,
+ required this.privacyLevel,
+ required this.scheduledStartTime,
+ required this.scheduledEndTime,
+ this.description,
+ required this.type,
+ this.image,
+ });
+
+ @override
+ Map build() => {
+ if (channelId != null) 'channel_id': channelId.toString(),
+ if (metadata != null) 'metadata': {'location': metadata!.location},
+ 'name': name,
+ 'privacy_level': privacyLevel.value,
+ 'scheduled_start_time': scheduledStartTime.toIso8601String(),
+ if (scheduledEndTime != null) 'scheduled_end_time': scheduledEndTime!.toIso8601String(),
+ if (description != null) 'description': description,
+ 'entity_type': type.value,
+ if (image != null) 'image': image!.buildDataString(),
+ };
+}
+
+class ScheduledEventUpdateBuilder extends UpdateBuilder {
+ Snowflake? channelId;
+
+ EntityMetadata? metadata;
+
+ String? name;
+
+ PrivacyLevel? privacyLevel;
+
+ DateTime? scheduledStartTime;
+
+ DateTime? scheduledEndTime;
+
+ String? description;
+
+ ScheduledEntityType? type;
+
+ EventStatus? status;
+
+ ImageBuilder? image;
+
+ ScheduledEventUpdateBuilder({
+ this.channelId = sentinelSnowflake,
+ this.metadata = sentinelEntityMetadata,
+ this.name,
+ this.privacyLevel,
+ this.scheduledStartTime,
+ this.scheduledEndTime = sentinelDateTime,
+ this.description = sentinelString,
+ this.type,
+ this.status,
+ this.image,
+ });
+
+ @override
+ Map build() => {
+ if (!identical(channelId, sentinelSnowflake)) 'channel_id': channelId?.toString(),
+ if (!identical(metadata, sentinelEntityMetadata)) 'metadata': metadata == null ? null : {'location': metadata!.location},
+ if (name != null) 'name': name,
+ if (privacyLevel != null) 'privacy_level': privacyLevel!.value,
+ if (scheduledStartTime != null) 'scheduled_start_time': scheduledStartTime!.toIso8601String(),
+ if (!identical(scheduledEndTime, sentinelDateTime)) 'scheduled_end_time': scheduledEndTime?.toIso8601String(),
+ if (!identical(description, sentinelString)) 'description': description,
+ if (type != null) 'entity_type': type!.value,
+ if (status != null) 'status': status!.value,
+ if (image != null) 'image': image!.buildDataString(),
+ };
+}
diff --git a/lib/src/builders/guild/template.dart b/lib/src/builders/guild/template.dart
new file mode 100644
index 000000000..346cd5e75
--- /dev/null
+++ b/lib/src/builders/guild/template.dart
@@ -0,0 +1,31 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/guild/template.dart';
+
+class GuildTemplateBuilder extends CreateBuilder {
+ String name;
+
+ String? description;
+
+ GuildTemplateBuilder({required this.name, this.description});
+
+ @override
+ Map build() => {
+ 'name': name,
+ if (description != null) 'description': description,
+ };
+}
+
+class GuildTemplateUpdateBuilder extends UpdateBuilder {
+ String? name;
+
+ String? description;
+
+ GuildTemplateUpdateBuilder({this.name, this.description = sentinelString});
+
+ @override
+ Map build() => {
+ if (name != null) 'name': name,
+ if (!identical(description, sentinelString)) 'description': description,
+ };
+}
diff --git a/lib/src/builders/guild/welcome_screen.dart b/lib/src/builders/guild/welcome_screen.dart
new file mode 100644
index 000000000..8ea232fb0
--- /dev/null
+++ b/lib/src/builders/guild/welcome_screen.dart
@@ -0,0 +1,29 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/guild/welcome_screen.dart';
+
+class WelcomeScreenUpdateBuilder extends UpdateBuilder {
+ bool? isEnabled;
+
+ List? channels;
+
+ String? description;
+
+ WelcomeScreenUpdateBuilder({this.isEnabled, this.channels, this.description = sentinelString});
+
+ @override
+ Map build() => {
+ if (isEnabled != null) 'enabled': isEnabled,
+ if (channels != null)
+ 'channels': [
+ for (final channel in channels!)
+ {
+ 'channel_id': channel.channelId.toString(),
+ 'description': channel.description,
+ 'emoji_id': channel.emojiId?.toString(),
+ 'emoji_name': channel.emojiName,
+ },
+ ],
+ if (!identical(description, sentinelString)) 'description': description,
+ };
+}
diff --git a/lib/src/builders/guild/widget.dart b/lib/src/builders/guild/widget.dart
new file mode 100644
index 000000000..56cfcc8b8
--- /dev/null
+++ b/lib/src/builders/guild/widget.dart
@@ -0,0 +1,18 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/sentinels.dart';
+import 'package:nyxx/src/models/guild/guild_widget.dart';
+import 'package:nyxx/src/models/snowflake.dart';
+
+class WidgetSettingsUpdateBuilder extends UpdateBuilder {
+ bool? isEnabled;
+
+ Snowflake? channelId;
+
+ WidgetSettingsUpdateBuilder({this.isEnabled, this.channelId = sentinelSnowflake});
+
+ @override
+ Map build() => {
+ if (isEnabled != null) 'enabled': isEnabled,
+ if (!identical(channelId, sentinelSnowflake)) 'channel_id': channelId?.toString(),
+ };
+}
diff --git a/lib/src/builders/image.dart b/lib/src/builders/image.dart
new file mode 100644
index 000000000..4759df255
--- /dev/null
+++ b/lib/src/builders/image.dart
@@ -0,0 +1,43 @@
+import 'dart:convert';
+import 'dart:io';
+
+import 'package:path/path.dart' as p;
+
+class ImageBuilder {
+ List data;
+ String format;
+
+ ImageBuilder({required this.data, required this.format});
+
+ ImageBuilder.png(this.data) : format = 'png';
+
+ ImageBuilder.jpeg(this.data) : format = 'jpeg';
+
+ ImageBuilder.gif(this.data) : format = 'gif';
+
+ static Future fromFile(File file, {String? format}) async {
+ format ??= p.extension(file.path);
+
+ const formats = {
+ 'png': 'png',
+ 'jpeg': 'jpeg',
+ 'jpg': 'jpeg',
+ 'gif': 'gif',
+ 'json': 'lottie',
+ };
+
+ final actualFormat = formats[format];
+
+ if (actualFormat == null) {
+ throw ArgumentError('Invalid format $format');
+ }
+
+ final data = await file.readAsBytes();
+
+ return ImageBuilder(data: data, format: actualFormat);
+ }
+
+ String buildDataString() => 'data:image/$format;base64,${base64Encode(data)}';
+
+ List buildRawData() => data;
+}
diff --git a/lib/src/builders/interaction_response.dart b/lib/src/builders/interaction_response.dart
new file mode 100644
index 000000000..1b9efdc7e
--- /dev/null
+++ b/lib/src/builders/interaction_response.dart
@@ -0,0 +1,136 @@
+import 'package:nyxx/src/builders/application_command.dart';
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/builders/message/component.dart';
+import 'package:nyxx/src/builders/message/message.dart';
+import 'package:nyxx/src/models/message/message.dart';
+
+class InteractionResponseBuilder extends CreateBuilder {
+ InteractionCallbackType type;
+
+ dynamic data;
+
+ InteractionResponseBuilder({required this.type, required this.data});
+
+ factory InteractionResponseBuilder.pong() => InteractionResponseBuilder(type: InteractionCallbackType.pong, data: null);
+
+ factory InteractionResponseBuilder.channelMessage(MessageBuilder message, {bool? isEphemeral}) => InteractionResponseBuilder(
+ type: InteractionCallbackType.channelMessageWithSource,
+ data: _EphemeralMessageBuilder(
+ content: message.content,
+ nonce: message.nonce,
+ tts: message.tts,
+ embeds: message.embeds,
+ allowedMentions: message.allowedMentions,
+ replyId: message.replyId,
+ requireReplyToExist: message.requireReplyToExist,
+ components: message.components,
+ stickerIds: message.stickerIds,
+ attachments: message.attachments,
+ suppressEmbeds: message.suppressEmbeds,
+ suppressNotifications: message.suppressNotifications,
+ isEphemeral: isEphemeral,
+ ),
+ );
+
+ factory InteractionResponseBuilder.deferredChannelMessage({bool? isEphemeral}) => InteractionResponseBuilder(
+ type: InteractionCallbackType.deferredChannelMessageWithSource,
+ data: isEphemeral == null ? null : {'flags': (isEphemeral ? MessageFlags.ephemeral.value : 0)},
+ );
+
+ factory InteractionResponseBuilder.updateMessage(MessageUpdateBuilder message) => InteractionResponseBuilder(
+ type: InteractionCallbackType.updateMessage,
+ data: message,
+ );
+
+ factory InteractionResponseBuilder.deferredUpdateMessage() => InteractionResponseBuilder(
+ type: InteractionCallbackType.deferredUpdateMessage,
+ data: null,
+ );
+
+ factory InteractionResponseBuilder.autocompleteResult(List> choices) => InteractionResponseBuilder(
+ type: InteractionCallbackType.applicationCommandAutocompleteResult,
+ data: choices,
+ );
+
+ factory InteractionResponseBuilder.modal(ModalBuilder modal) => InteractionResponseBuilder(type: InteractionCallbackType.modal, data: modal);
+
+ factory InteractionResponseBuilder.premiumRequired() => InteractionResponseBuilder(type: InteractionCallbackType.premiumRequired, data: null);
+
+ @override
+ Map build() {
+ final builtData = switch (data) {
+ final Builder builder => builder.build(),
+ final List> builders => builders.map((e) => e.build()).toList(),
+ Map() || List