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 6ccde219e..810a8c13b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,41 @@
+## 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.0.1
+__18.03.2023__
+
+- documentation: Channel invites (#448)
+- bug: Correctly dispose all resources on bot stop (#451)
+
+## 4.5.1
+__19.03.2023__
+
+- bug: Correctly dispose all resources on bot stop (#451)
+
## 5.0.0
__04.03.2023__
diff --git a/README.md b/README.md
index e13a151b7..3efffa197 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.connectWebsocket('', 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..8ff513fb7 100644
--- a/lib/nyxx.dart
+++ b/lib/nyxx.dart
@@ -1,208 +1,308 @@
-/// 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,
+ 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/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/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/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/message/activity.dart' show MessageActivity, MessageActivityType;
+export 'src/models/message/attachment.dart' show Attachment;
+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;
+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;
+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/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;
+export 'src/models/interaction.dart'
+ show
+ ApplicationCommandInteractionData,
+ Interaction,
+ InteractionOption,
+ MessageComponentInteractionData,
+ MessageResponse,
+ ModalResponse,
+ ModalSubmitInteractionData,
+ ResolvedData,
+ InteractionType,
+ ApplicationCommandAutocompleteInteraction,
+ ApplicationCommandInteraction,
+ MessageComponentInteraction,
+ ModalSubmitInteraction,
+ PingInteraction;
+
+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;
+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;
diff --git a/lib/src/api_options.dart b/lib/src/api_options.dart
new file mode 100644
index 000000000..72130c88d
--- /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-dev.2';
+
+ /// 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_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..6fa0d3107
--- /dev/null
+++ b/lib/src/builders/channel/stage_instance.dart
@@ -0,0 +1,37 @@
+import 'package:nyxx/src/builders/builder.dart';
+import 'package:nyxx/src/models/channel/stage_instance.dart';
+
+class StageInstanceBuilder extends CreateBuilder {
+ String topic;
+
+ PrivacyLevel? privacyLevel;
+
+ bool? sendStartNotification;
+
+ StageInstanceBuilder({
+ required this.topic,
+ this.privacyLevel,
+ this.sendStartNotification,
+ });
+
+ @override
+ Map build() => {
+ 'topic': topic,
+ if (privacyLevel != null) 'privacy_level': privacyLevel!.value,
+ if (sendStartNotification != null) 'send_start_notification': sendStartNotification,
+ };
+}
+
+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/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..be130ff26
--- /dev/null
+++ b/lib/src/builders/interaction_response.dart
@@ -0,0 +1,133 @@
+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);
+
+ @override
+ Map build() {
+ final builtData = switch (data) {
+ final Builder builder => builder.build(),
+ final List> builders => builders.map((e) => e.build()).toList(),
+ Map() || List