Repository: interactions-py/interactions.py

Issue:
[FEAT] Add in `nonce` and `enforce_nonce` to `SendMixin`
### Problem Description

`nonce` has always been a thing when sending messages - it's a weird field that's rarely used. However, with [`enforce_nonce`](https://github.com/discord/discord-api-docs/commit/d8effe15d56a12eec0bb977a5bf4487b9ebffcad) being added, it suddenly has a lot more uses - at the very least, it can be used as an easy way of making sure duplicate messages don't get send.

However, `SendMixin` does not have native support for either `nonce` or `enforce_nonce`. While it *can* still be done thanks to `kwargs`, it would be nice if it were more properly supported.

### Proposed Solution

Add in `nonce` and `enforce_nonce` to `SendMixin`, with a check to make sure `nonce` was given if `enforce_nonce` is enabled.

### Alternatives Considered

_No response_

### Additional Information

_No response_

### Code of Conduct

- [X] I agree to follow the contribution requirements.


Discussion:

Resolving patch:
diff --git a/interactions/client/mixins/send.py b/interactions/client/mixins/send.py
--- a/interactions/client/mixins/send.py
+++ b/interactions/client/mixins/send.py
@@ -47,6 +47,8 @@ async def send(
         silent: bool = False,
         flags: Optional[Union[int, "MessageFlags"]] = None,
         delete_after: Optional[float] = None,
+        nonce: Optional[str | int] = None,
+        enforce_nonce: bool = False,
         **kwargs: Any,
     ) -> "Message":
         """
@@ -67,6 +69,10 @@ async def send(
             silent: Should this message be sent without triggering a notification.
             flags: Message flags to apply.
             delete_after: Delete message after this many seconds.
+            nonce: Used to verify a message was sent. Can be up to 25 characters.
+            enforce_nonce: If enabled and nonce is present, it will be checked for uniqueness in the past few minutes. \
+                If another message was created by the same author with the same nonce, that message will be returned \
+                and no new message will be created.
 
         Returns:
             New message object that was sent.
@@ -95,6 +101,9 @@ async def send(
                 "Attachments are not files. Attachments only contain metadata about the file, not the file itself - to send an attachment, you need to download it first. Check Attachment.url"
             )
 
+        if enforce_nonce and not nonce:
+            raise ValueError("You must provide a nonce to use enforce_nonce.")
+
         message_payload = models.discord.message.process_message_payload(
             content=content,
             embeds=embeds or embed,
@@ -104,6 +113,8 @@ async def send(
             reply_to=reply_to,
             tts=tts,
             flags=flags,
+            nonce=nonce,
+            enforce_nonce=enforce_nonce,
             **kwargs,
         )
 
diff --git a/interactions/models/discord/message.py b/interactions/models/discord/message.py
--- a/interactions/models/discord/message.py
+++ b/interactions/models/discord/message.py
@@ -926,6 +926,8 @@ def process_message_payload(
     attachments: Optional[List[Union[Attachment, dict]]] = None,
     tts: bool = False,
     flags: Optional[Union[int, MessageFlags]] = None,
+    nonce: Optional[str | int] = None,
+    enforce_nonce: bool = False,
     **kwargs,
 ) -> dict:
     """
@@ -941,6 +943,10 @@ def process_message_payload(
         attachments: The attachments to keep, only used when editing message.
         tts: Should this message use Text To Speech.
         flags: Message flags to apply.
+        nonce: Used to verify a message was sent.
+        enforce_nonce: If enabled and nonce is present, it will be checked for uniqueness in the past few minutes. \
+            If another message was created by the same author with the same nonce, that message will be returned \
+            and no new message will be created.
 
     Returns:
         Dictionary
@@ -969,6 +975,8 @@ def process_message_payload(
             "attachments": attachments,
             "tts": tts,
             "flags": flags,
+            "nonce": nonce,
+            "enforce_nonce": enforce_nonce,
             **kwargs,
         }
     )


Test patch: