diff --git a/Cargo.lock b/Cargo.lock index d05231da..34ef6f45 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -673,9 +673,9 @@ dependencies = [ [[package]] name = "chrono-tz" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd6dd8046d00723a59a2f8c5f295c515b9bb9a331ee4f8f3d4dd49e428acd3b6" +checksum = "9c6ac4f2c0bf0f44e9161aec9675e1050aa4a530663c4a9e37e108fa948bca9f" dependencies = [ "chrono", "chrono-tz-build", @@ -1973,7 +1973,7 @@ dependencies = [ [[package]] name = "khronos_runtime" version = "1.0.0" -source = "git+https://github.com/anti-raid/khronos#02aa8fe75d594172734ae76f391ea2ab1021399a" +source = "git+https://github.com/anti-raid/khronos#07e4afb944ef3510bdbfc326142c3871764f5e14" dependencies = [ "antiraid-types", "arrayvec", @@ -2328,7 +2328,7 @@ dependencies = [ [[package]] name = "mlua_scheduler" version = "1.0.0" -source = "git+https://github.com/anti-raid/mlua_scheduler#2c625ef72d10a81a67036cf00cf71d7302448923" +source = "git+https://github.com/anti-raid/mlua_scheduler#b575e1b476c6d6e798b5420862f417ac311e37ec" dependencies = [ "futures-util", "log", @@ -2339,7 +2339,7 @@ dependencies = [ [[package]] name = "mlua_scheduler_ext" version = "1.0.0" -source = "git+https://github.com/anti-raid/mlua_scheduler#2c625ef72d10a81a67036cf00cf71d7302448923" +source = "git+https://github.com/anti-raid/mlua_scheduler#b575e1b476c6d6e798b5420862f417ac311e37ec" dependencies = [ "log", "mlua", @@ -4863,9 +4863,9 @@ dependencies = [ [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" diff --git a/Makefile b/Makefile index ba8386ee..4866432e 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,9 @@ copyassets: rm -rf services/badgerfang/src/types/splashtail cp -rf services/website/src/lib/generated services/badgerfang/src/types/splashtail +docs: + python3 docs/gen_khronos_docs.py ~/khronos docs/src/dev/templating/2-plugins.md + tests: ./out/bot test diff --git a/core/rust b/core/rust index 1edc18e7..70933318 160000 --- a/core/rust +++ b/core/rust @@ -1 +1 @@ -Subproject commit 1edc18e74efa2f607c3ff232999ecf26013c0b83 +Subproject commit 709333180731b6809cf074bcc03296f9da091577 diff --git a/docs/gen_khronos_docs.py b/docs/gen_khronos_docs.py new file mode 100644 index 00000000..86080a9d --- /dev/null +++ b/docs/gen_khronos_docs.py @@ -0,0 +1,19 @@ +import pathlib +import sys + +if len(sys.argv) != 3: + print("Usage: python gen_khronos_docs.py ") + sys.exit(1) + +# Delete the output file if it exists +if pathlib.Path(sys.argv[2]).exists(): + pathlib.Path(sys.argv[2]).unlink() + +for path in sorted(pathlib.Path(sys.argv[1]).rglob("README.md")): + if path.parent == pathlib.Path(sys.argv[1]): + continue + print(path) + with open(path, "r") as f: + with open(sys.argv[2], "a") as output: + output.write(f.read()) + output.write("\n---\n") diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index 2d714496..21ace802 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -6,11 +6,7 @@ - [Permissions](./user/permissions/README.md) - [Templating](./user/templating/README.md) - - [Introduction](./user/templating/1-intro.md) - - [Plugins](./user/templating/2-plugins.md) - - [A Simple Example](./user/templating/3-example.md) - - [Ecosystem](./user/templating/4-luau-ecosystem.md) - - [Hooks](./user/templating/5-hooks.md) + - [Loading Templates](./user/templating/1-intro.md) - [Captcha](./user/captcha/README.md) - [Introduction](./user/captcha/1-intro.md) - [Examples](./user/captcha/2-examples.md) @@ -23,5 +19,10 @@ - [Backups](./dev/go_jobs/backups.md) - [Lockdown Module](./dev/rust_bot_modules_lockdown/README.md) - [Silverpelt](./dev/rust_silverpelt/README.md) -- [Templating](./dev/rust_templating/README.md) +- [Templating](./dev/templating/README.md) + - [Introduction](./dev/templating/1-intro.md) + - [Plugins](./dev/templating/2-plugins.md) + - [A Simple Example](./dev/templating/3-example.md) + - [Ecosystem](./dev/templating/4-luau-ecosystem.md) + - [Hooks](./dev/templating/5-hooks.md) - [Text](./dev/rust_text/README.md) \ No newline at end of file diff --git a/docs/src/dev/rust_silverpelt/README.md b/docs/src/dev/rust_silverpelt/README.md deleted file mode 100644 index e6754c5a..00000000 --- a/docs/src/dev/rust_silverpelt/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Silverpelt - -Silverpelt provides a standard library for all Anti-Raid modules. - -To create a new Anti-Raid bot making use of Anti-Raid modules, simply implement the trait ``modules::Module``. These modules must then be added to a ``SilverpeltCache`` which is then inserted into ``silverpelt::Data``. - -Most things in silverpelt are abstracted out through traits or dispatched via events. This allows silverpelt to be used as an abstract interface allowing for Anti-Raid to quickly evolve and change/adapt to different targets. - -**Note:** AntiRaid uses a event-driven architecture. This means that modules+the main bot process make events that are dispatched to modules. The event system is currently passive (meaning there is no continously running event loop), however this is subject to change in the future. - -## Interfaces - -### Sting - -Silverpelt provides concrete structures, utilities and special events for handling stings. - -### Punishments - -Silverpelt provides concrete structures, utilities and special events for handling punishments. - -## Some extra misc points - -- A command is the base unit for access control. This means that all operations with differing access controls must have commands associated with them. - -- This means that all operations (list backup, create/restore backup, delete backup) *MUST* have associated commands - -- Sometimes, an operation (such as a web-only operation) may not have a module/command associated with it. In such cases, a 'virtual' module should be used. Virtual modules are modules with commands that are not registered via Discord's API. They are used to group commands together for access control purposes and to ensure that each operation is tied to a command diff --git a/docs/src/dev/rust_text/README.md b/docs/src/dev/rust_text/README.md deleted file mode 100644 index d230d300..00000000 --- a/docs/src/dev/rust_text/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Text difference utilities - -**diff.rs:** Taken from https://docs.rs/text-diff/latest/src/text_diff with some modernizing. All credits go to the author. - -Other utilities are taken too. To be documented \ No newline at end of file diff --git a/docs/src/dev/templating/1-intro.md b/docs/src/dev/templating/1-intro.md new file mode 100644 index 00000000..dd559ffc --- /dev/null +++ b/docs/src/dev/templating/1-intro.md @@ -0,0 +1,90 @@ +# Lua Templating + +At AntiRaid, we prioritize flexibility and customization for our users. To this end, our bot supports advanced templating to allow for extensive personalization of embeds and messages. While many bots utilize proprietary languages or templating engines, we have chosen to leverage Lua—a renowned scripting language widely used in game development and other applications. This decision ensures that our users benefit from a powerful, well-documented, and versatile language, enhancing the capability and ease of customizing their AntiRaid experience. + +Specifically, Anti Raid uses a variant of Lua called Luau. If you've ever used Roblox before, this is the same variant of Lua used there too (which is why Luau is also known as Roblox Lua in many places). You can check out the [Luau docs](https://luau-lang.org/) for more information on the language itself. Unlike PUC Lua (the reference implementation), Luau is both faster and offers robust sandboxing capabilities allowing AntiRaid to run scripts in as safe an environment as possible. + +## Getting Started + +Note that the remainder of these docs will cover AntiRaids Lua SDKs. To learn more about Lua itself, please checkout Lua's official tutorial for Lua 5.0 [here](https://www.lua.org/pil/1.html). Other resources for Lua exist (Lua is very popular after all), including [Roblox's tutorial](https://devforum.roblox.com/t/lua-scripting-starter-guide/394618#print-5) (ignore the Studio bits), [TutorialPoint](https://www.tutorialspoint.com/lua/lua_quick_guide.htm) and [Codecademy](https://www.codecademy.com/learn/learn-lua). + +## Limitations + +AntiRaid applies the following 3 global limits to all Lua templates. Note that we may provide increased limits as a Premium feature in the future: + +```rust +pub const MAX_TEMPLATE_MEMORY_USAGE: usize = 1024 * 1024 * 3; // 3MB maximum memory +pub const MAX_TEMPLATES_EXECUTION_TIME: std::time::Duration = std::time::Duration::from_secs(30); // 30 seconds maximum execution time +``` + +The above limits are in place to prevent abuse and ensure that the bot remains responsive. If you require increased limits, please contact support (once again, this may change in the future). + +## Some key notes + +- Each guild is assigned a dedicated Lua VM. This VM is used to execute Lua code that is used in the templates. +- The total memory usage that a guild can use is limited to ``MAX_TEMPLATE_MEMORY_USAGE`` (currently 3MB). This is to prevent a single guild from using too much memory. +- Execution of all scripts is timed out when the last executed script takes longer than ``MAX_TEMPLATES_EXECUTION_TIME`` (currently 30 seconds). +- A guilds Lua VM will persist until marked as broken (either by explicitly requesting it or by exceeding memory limits) +- AntiRaid monkey-patches ``_G`` to be read-write for new values while preserving Luau's sandboxing features. This means that builtins will remain read-only, but new values can be added. +- The standard ``require`` statement can be used to import AntiRaid plugins. **Note that plugins are read-only** and cannot be monkey-patched etc. +- All templates are executed as Luau threads. + +In general, all AntiRaid templates should start with the following: + +```lua +local args, token = ... +-- Do something +return output +``` + +## Interop + +Many features of Lua don't work so well when calling functions within the AntiRaid SDK. For example, both arrays and maps are expressed as tables in Lua. However, AntiRaid, being written in Rust, doesn't know this and hance needs some help to convert certain types for FFI. This is where the `@antiraid/interop` module comes in. + +### Arrays + +To pass arrays to modules within the AntiRaid SDK, you need to set the metatable to ``@antiraid/interop#array_metatable``. This will allow the SDK to convert the array to a Rust ``Vec`` internally. + +```lua +local interop = require '@antiraid/interop' +setmetatable({a = 5}, interop.array_metatable) +``` + +### Null + +While the Lua ``nil`` does work in many cases (and even when calling the SDK), its not the best choice. When querying AntiRaid SDK, the SDK will use the ``@antiraid/interop#null`` value to represent a null value. Your Lua templates can also use this value if desired + +```lua +local interop = require '@antiraid/interop' +local null = interop.null -- This is the null value +``` + +### Memory Usage + +While not strictly useful for interop, it is often desirable to know the memory usage of a Lua template as AntiRaid will kill your template if it exceeds the memory limit. For this, you can use the `@antiraid/interop#memusage` function. + +```lua +local interop = require '@antiraid/interop' +print(interop.memusage()) +``` + +## Events + +All Lua templates are invoked via events. As such, the first argument to the template is an ``Event``. ``Event`` is a ``userdata``. The below will explain the most important fields exposed by ``Event``. Note that all fields, unless stated otherwise, are read-only and cached. + +## Template Context + +All Lua templates are passed both the ``Event`` (denoted by `args`) and a `TemplateContext` userdata (denoted by `token`). Note that like ``Event``, ``TemplateContext`` is a *userdata* (not a table). As such, they cannot be manually constructed in templates themselves. + +"Executors" and other sensistive APIs use the `TemplateContext` to read internal data. Examples of executors include the ``@antiraid/discord`` `DiscordActionExecutor`, which allows you to perform actions such as banning/kicking/timing out users and other Discord actions and ``@antiraid/kv`` `KvExecutor` which allow for persistent storage via a key-value interface. + +``TemplateContext`` is guaranteed to be valid while accessible in the VM . This means that templates can choose to share their capabilities with other templates using ``_G``. + +Likewise, it is also guaranteed that the created executor is complete and does not rely on the token itself whatsoever after creation. This means that a template executor can be used after the template has finished executing (e.g. in a coroutine). + +### Example + +```lua +local args, token = ... +print(token) +``` \ No newline at end of file diff --git a/docs/src/dev/templating/2-plugins.md b/docs/src/dev/templating/2-plugins.md new file mode 100644 index 00000000..28c8c3b3 --- /dev/null +++ b/docs/src/dev/templating/2-plugins.md @@ -0,0 +1,2585 @@ +# @antiraid/datetime + +This plugin allows for the managing timezones. + +## Types + +
+ +### Timezone + +A timezone object. + +#### Methods + +##### Timezone:utcToTz + +```lua +function Timezone:utcToTz(year: number, month: number, day: number, hours: number, minutes: number, secs: number, all: boolean?) +``` + +Translates a timestamp in UTC time to a datetime in the said specific timezone. + +###### Parameters + +- `year` ([number](#type.number)): The year to translate. +- `month` ([number](#type.number)): The month to translate. +- `day` ([number](#type.number)): The day to translate. +- `hours` ([number](#type.number)): The hours to translate. +- `minutes` ([number](#type.number)): The minutes to translate. +- `secs` ([number](#type.number)): The seconds to translate. +- `all` ([boolean?](#type.boolean)): Whether to return both offsets if the time is ambiguous. + + +###### Returns + +- `date` ([DateTime](#type.DateTime)): The translated datetime.- `date2` ([DateTime?](#type.DateTime)): The second translated datetime if the time is ambiguous. +##### Timezone:tzToUtc + +```lua +function Timezone:tzToUtc(year: number, month: number, day: number, hours: number, minutes: number, secs: number, all: boolean?) +``` + +Translates a timestamp in the specified timezone to a datetime in UTC. + +###### Parameters + +- `year` ([number](#type.number)): The year to translate. +- `month` ([number](#type.number)): The month to translate. +- `day` ([number](#type.number)): The day to translate. +- `hours` ([number](#type.number)): The hours to translate. +- `minutes` ([number](#type.number)): The minutes to translate. +- `secs` ([number](#type.number)): The seconds to translate. +- `all` ([boolean?](#type.boolean)): Whether to return both offsets if the time is ambiguous. + + +###### Returns + +- `date` ([DateTime](#type.DateTime)): The translated datetime.- `date2` ([DateTime?](#type.DateTime)): The second translated datetime if the time is ambiguous. +##### Timezone:timeUtcToTz + +```lua +function Timezone:timeUtcToTz(hours: number, minutes: number, secs: number): DateTime +``` + +Translates a time of the current day in UTC time to a datetime in the said specific timezone. + +###### Parameters + +- `hours` ([number](#type.number)): The hours to translate. +- `minutes` ([number](#type.number)): The minutes to translate. +- `secs` ([number](#type.number)): The seconds to translate. + + +###### Returns + +- `date` ([DateTime](#type.DateTime)): The translated datetime. +##### Timezone:timeTzToUtc + +```lua +function Timezone:timeTzToUtc(hours: number, minutes: number, secs: number): DateTime +``` + +Translates a time of the current day in the said specific timezone to a datetime in UTC. + +###### Parameters + +- `hours` ([number](#type.number)): The hours to translate. +- `minutes` ([number](#type.number)): The minutes to translate. +- `secs` ([number](#type.number)): The seconds to translate. + + +###### Returns + +- `date` ([DateTime](#type.DateTime)): The translated datetime. +##### Timezone:now + +```lua +function Timezone:now(): DateTime +``` + +Translates the current timestamp to a datetime in the said specific timezone. + +###### Returns + +- `date` ([DateTime](#type.DateTime)): The translated datetime. + + +
+ +### TimeDelta + +A time delta object. Supports addition/subtraction with another TimeDelta object as well as comparisons with them. + + + +#### Fields + +- `nanos` ([number](#type.number)): The number of nanoseconds in the time delta. +- `micros` ([number](#type.number)): The number of microseconds in the time delta. +- `millis` ([number](#type.number)): The number of milliseconds in the time delta. +- `seconds` ([number](#type.number)): The number of seconds in the time delta. +- `minutes` ([number](#type.number)): The number of minutes in the time delta. +- `hours` ([number](#type.number)): The number of hours in the time delta. +- `days` ([number](#type.number)): The number of days in the time delta. +- `weeks` ([number](#type.number)): The number of weeks in the time delta. + + +#### Methods + +##### TimeDelta:offset_string + +```lua +function TimeDelta:offset_string(): string +``` + +Returns the offset as a string. + +###### Returns + +- `offset` ([string](#type.string)): The offset as a string. + + +
+ +### DateTime + +A datetime object. Supports addition/subtraction with TimeDelta objects as well as comparisons with other DateTime objects. + + + +#### Fields + +- `year` ([number](#type.number)): The year of the datetime. +- `month` ([number](#type.number)): The month of the datetime. +- `day` ([number](#type.number)): The day of the datetime. +- `hour` ([number](#type.number)): The hour of the datetime. +- `minute` ([number](#type.number)): The minute of the datetime. +- `second` ([number](#type.number)): The second of the datetime. +- `timestamp_seconds` ([number](#type.number)): The timestamp in seconds of the datetime from the Unix epoch. +- `timestamp_millis` ([number](#type.number)): The timestamp in milliseconds of the datetime from the Unix epoch. +- `timestamp_micros` ([number](#type.number)): The timestamp in microseconds of the datetime from the Unix epoch. +- `timestamp_nanos` ([number](#type.number)): The timestamp in nanoseconds of the datetime from the Unix epoch. +- `tz` ([Timezone](#type.Timezone)): The timezone of the datetime. +- `offset` ([TimeDelta](#type.TimeDelta)): The offset of the datetime. + + +#### Methods + +##### DateTime:with_timezone + +```lua +function DateTime:with_timezone(tz: Timezone): DateTime +``` + +Converts the datetime to the specified timezone. + +###### Parameters + +- `tz` ([Timezone](#type.Timezone)): The timezone to convert to. + + +###### Returns + +- `dt` ([DateTime](#type.DateTime)): The converted datetime. +##### DateTime:format + +```lua +function DateTime:format(format: string): string +``` + +Formats the datetime using the specified format string. + +###### Parameters + +- `format` ([string](#type.string)): The format string to use. + + +###### Returns + +- `formatted` ([string](#type.string)): The formatted datetime. +##### DateTime:duration_since + +```lua +function DateTime:duration_since(other: DateTime): TimeDelta +``` + +Calculates the duration between the current datetime and another datetime. + +###### Parameters + +- `other` ([DateTime](#type.DateTime)): The other datetime to calculate the duration to. + + +###### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The duration between the two datetimes. + + +## Methods + +### new + +```lua +function new(timezone: string): Timezone +``` + +Returns a new Timezone object if the timezone is recognized/supported. + +#### Parameters + +- `timezone` ([string](#type.string)): The timezone to get the offset for. + + +#### Returns + +- `tzobj` ([Timezone](#type.Timezone)): The timezone userdata object. + +### timedelta_weeks + +```lua +function timedelta_weeks(weeks: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of weeks. + +#### Parameters + +- `weeks` ([number](#type.number)): The number of weeks. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_days + +```lua +function timedelta_days(days: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of days. + +#### Parameters + +- `days` ([number](#type.number)): The number of days. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_hours + +```lua +function timedelta_hours(hours: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of hours. + +#### Parameters + +- `hours` ([number](#type.number)): The number of hours. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_minutes + +```lua +function timedelta_minutes(minutes: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of minutes. + +#### Parameters + +- `minutes` ([number](#type.number)): The number of minutes. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_seconds + +```lua +function timedelta_seconds(seconds: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of seconds. + +#### Parameters + +- `seconds` ([number](#type.number)): The number of seconds. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_millis + +```lua +function timedelta_millis(millis: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of milliseconds. + +#### Parameters + +- `millis` ([number](#type.number)): The number of milliseconds. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_micros + +```lua +function timedelta_micros(micros: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of microseconds. + +#### Parameters + +- `micros` ([number](#type.number)): The number of microseconds. + + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +### timedelta_nanos + +```lua +function timedelta_nanos(nanos: number): TimeDelta +``` + +Creates a new TimeDelta object with the specified number of nanoseconds. + +#### Parameters + +- `nanos` ([number](#type.number)): The number of nanoseconds. + +#### Returns + +- `td` ([TimeDelta](#type.TimeDelta)): The TimeDelta object. + +--- +# @antiraid/discord + +This plugin allows for templates to interact with the Discord API. Types are as defined by Discord if not explicitly documented + +## Types + +
+ +### GetAuditLogOptions + +Options for getting audit logs in Discord + +```json +{ + "action_type": 1, + "user_id": "0", + "before": "0", + "limit": 0 +} +``` + +#### Fields + +- `action_type` ([Serenity.AuditLogs.Action?](#type.Serenity.AuditLogs.Action)): The action type to filter by +- `user_id` ([string?](#type.string)): The user ID to filter by +- `before` ([string?](#type.string)): The entry ID to filter by +- `limit` ([number?](#type.number)): The limit of entries to return + + +
+ +### GetChannelOptions + +Options for getting a channel in Discord + +```json +{ + "channel_id": "0" +} +``` + +#### Fields + +- `channel_id` ([string](#type.string)): The channel ID to get + + +
+ +### EditChannel + +The data for editing a channel in Discord + +```json +{ + "name": "my-channel", + "type": 0, + "position": 7, + "topic": "My channel topic", + "nsfw": true, + "rate_limit_per_user": 5, + "user_limit": 10, + "parent_id": "0", + "rtc_region": "us-west", + "video_quality_mode": 1, + "default_auto_archive_duration": 1440, + "flags": 18, + "default_reaction_emoji": { + "emoji_id": "0", + "emoji_name": null + }, + "status": "online", + "archived": false, + "auto_archive_duration": 1440, + "locked": false, + "invitable": true +} +``` + +#### Fields + +- `type` ([number?](#type.number)): The type of the channel +- `position` ([number?](#type.number)): The position of the channel +- `topic` ([string?](#type.string)): The topic of the channel +- `nsfw` ([bool?](#type.bool)): Whether the channel is NSFW +- `rate_limit_per_user` ([number?](#type.number)): The rate limit per user/Slow mode of the channel +- `bitrate` ([number?](#type.number)): The bitrate of the channel +- `permission_overwrites` ([{Serenity.PermissionOverwrite}?](#type.Serenity.PermissionOverwrite)): The permission overwrites of the channel +- `parent_id` ([string??](#type.string)): The parent ID of the channel +- `rtc_region` ([string??](#type.string)): The RTC region of the channel +- `video_quality_mode` ([number?](#type.number)): The video quality mode of the channel +- `default_auto_archive_duration` ([number?](#type.number)): The default auto archive duration of the channel +- `flags` ([string?](#type.string)): The flags of the channel +- `available_tags` ([{Serenity.ForumTag}?](#type.Serenity.ForumTag)): The available tags of the channel +- `default_reaction_emoji` ([Serenity.ForumEmoji??](#type.Serenity.ForumEmoji)): The default reaction emoji of the channel +- `default_thread_rate_limit_per_user` ([number?](#type.number)): The default thread rate limit per user +- `default_sort_order` ([number?](#type.number)): The default sort order of the channel +- `default_forum_layout` ([number?](#type.number)): The default forum layout of the channel +- `archived` ([bool?](#type.bool)): Whether the thread is archived (thread only) +- `auto_archive_duration` ([number?](#type.number)): The auto archive duration of the thread (thread only) +- `locked` ([bool?](#type.bool)): Whether the thread is locked (thread only) +- `invitable` ([bool?](#type.bool)): Whether the thread is invitable (thread only) +- `applied_tags` ([{Serenity.ForumTag}?](#type.Serenity.ForumTag)): The applied tags of the thread (thread only) + + +
+ +### EditChannelOptions + +Options for editing a channel in Discord + +```json +{ + "channel_id": "0", + "reason": "", + "data": { + "name": "my-channel", + "type": 0, + "position": 7, + "topic": "My channel topic", + "nsfw": true, + "rate_limit_per_user": 5, + "user_limit": 10, + "parent_id": "0", + "rtc_region": "us-west", + "video_quality_mode": 1, + "default_auto_archive_duration": 1440, + "flags": 18, + "default_reaction_emoji": { + "emoji_id": "0", + "emoji_name": null + }, + "status": "online", + "archived": false, + "auto_archive_duration": 1440, + "locked": false, + "invitable": true + } +} +``` + +#### Fields + +- `channel_id` ([string](#type.string)): The channel ID to edit +- `reason` ([string](#type.string)): The reason for editing the channel +- `data` ([EditChannel](#type.EditChannel)): The new channels' data + + +
+ +### DeleteChannelOptions + +Options for deleting a channel in Discord + +```json +{ + "channel_id": "0", + "reason": "" +} +``` + +#### Fields + +- `channel_id` ([string](#type.string)): The channel ID to delete +- `reason` ([string](#type.string)): The reason for deleting the channel + + +
+ +### CreateMessageAttachment + +An attachment in a message + +```json +[ + { + "id": 0, + "filename": "test.txt", + "description": "Test file" + } +] +``` + +#### Fields + +- `filename` ([string](#type.string)): The filename of the attachment +- `description` ([string?](#type.string)): The description (if any) of the attachment +- `content` ([{byte}](#type.byte)): The content of the attachment + + +
+ +### CreateMessageOptions + +Options for sending a message in a channel in Discord + +```json +{ + "channel_id": "0", + "data": { + "tts": false, + "embeds": [], + "sticker_ids": [], + "enforce_nonce": false + } +} +``` + +#### Fields + +- `channel_id` ([string](#type.string)): The channel ID to send the message in +- `data` ([Serenity.CreateMessage](#type.Serenity.CreateMessage)): The data of the message to send + + +
+ +### CreateInteractionResponse + +Options for creating an interaction response in Discord + + + +#### Fields + +- `interaction_id` ([string](#type.string)): The interaction ID to respond to +- `interaction_token` ([string](#type.string)): The interaction token to respond to +- `data` ([Serenity.InteractionResponse](#type.Serenity.InteractionResponse)): The interaction response body +- `files` ([{Serenity.CreateMessageAttachment}?](#type.Serenity.CreateMessageAttachment)): The files to send with the response + + +
+ +### DiscordExecutor + +DiscordExecutor allows templates to access/use the Discord API in a sandboxed form. + + + +#### Methods + +##### DiscordExecutor:get_audit_logs + +```lua +function DiscordExecutor:get_audit_logs(data: GetAuditLogOptions): +``` + +Gets the audit logs + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([GetAuditLogOptions](#type.GetAuditLogOptions)): Options for getting audit logs. + + +###### Returns + +- `Lazy` ([](#type.)): The audit log entry +##### DiscordExecutor:get_channel + +```lua +function DiscordExecutor:get_channel(data: GetChannelOptions): +``` + +Gets a channel + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([GetChannelOptions](#type.GetChannelOptions)): Options for getting a channel. + + +###### Returns + +- `Lazy` ([](#type.)): The guild channel +##### DiscordExecutor:edit_channel + +```lua +function DiscordExecutor:edit_channel(data: EditChannelOptions): +``` + +Edits a channel + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([EditChannelOptions](#type.EditChannelOptions)): Options for editing a channel. + + +###### Returns + +- `Lazy` ([](#type.)): The guild channel +##### DiscordExecutor:delete_channel + +```lua +function DiscordExecutor:delete_channel(data: DeleteChannelOptions): +``` + +Deletes a channel + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([DeleteChannelOptions](#type.DeleteChannelOptions)): Options for deleting a channel. + + +###### Returns + +- `Lazy` ([](#type.)): The guild channel +##### DiscordExecutor:create_message + +```lua +function DiscordExecutor:create_message(data: SendMessageChannelAction): +``` + +Creates a message + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([SendMessageChannelAction](#type.SendMessageChannelAction)): Options for creating a message. + + +###### Returns + +- `Lazy` ([](#type.)): The message +##### DiscordExecutor:create_interaction_response + +```lua +function DiscordExecutor:create_interaction_response(data: CreateInteractionResponse): +``` + +Creates an interaction response + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([CreateInteractionResponse](#type.CreateInteractionResponse)): Options for creating a message. + + +###### Returns + +- `Lazy` ([](#type.)): The message + + +## Methods + +### new + +```lua +function new(token: TemplateContext): DiscordExecutor +``` + +#### Parameters + +- `token` ([TemplateContext](#type.TemplateContext)): The token of the template to use. + + +#### Returns + +- `executor` ([DiscordExecutor](#type.DiscordExecutor)): A discord executor. +--- +# @antiraid/img_captcha + +This plugin allows for the creation of text/image CAPTCHA's with customizable filters which can be useful in protecting against bots. + +## Types + +
+ +### CaptchaConfig + +Captcha configuration. See examples for the arguments + +```json +{ + "char_count": 5, + "filters": [ + { + "filter": "Noise", + "prob": 0.1 + }, + { + "filter": "Wave", + "f": 4.0, + "amp": 2.0, + "d": "horizontal" + }, + { + "filter": "Line", + "p1": [ + 1.0, + 0.0 + ], + "p2": [ + 20.0, + 20.0 + ], + "thickness": 2.0, + "color": { + "r": 0, + "g": 30, + "b": 100 + } + }, + { + "filter": "RandomLine" + }, + { + "filter": "Grid", + "y_gap": 30, + "x_gap": 10 + }, + { + "filter": "ColorInvert" + } + ], + "viewbox_size": [ + 512, + 512 + ], + "set_viewbox_at_idx": null +} +``` + +#### Fields + +- `char_count` ([u8](#type.u8)): The number of characters the CAPTCHA should have. +- `filters` ([{any}](#type.any)): See example for the parameters to pass for the filter as well as https://github.com/Anti-Raid/captcha +- `viewbox_size` ([(u32, u32)](#type.(u32, u32))): The size of the viewbox to render the CAPTCHA in. +- `set_viewbox_at_idx` ([Option](#type.Option)): At what index of CAPTCHA generation should a viewbox be created at. + + +## Methods + +### new + +```lua +function new(config: CaptchaConfig): {u8} +``` + +Creates a new CAPTCHA with the given configuration. + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +#### Parameters + +- `config` ([CaptchaConfig](#type.CaptchaConfig)): The configuration to use for the CAPTCHA. + + +#### Returns + +- `captcha` ([{u8}](#type.u8)): The created CAPTCHA object. +--- +# @antiraid/interop + +This plugin allows interoperability with the Luau controller. + +## Types + +
+ +### null + +`null` is a special value that represents nothing. It is often used in AntiRaid instead of `nil` due to issues regarding existence etc. `null` is not equal to `nil` but is also an opaque type. + + + +
+ +### array_metatable + +`array_metatable` is a special metatable that is used to represent arrays across the Lua-AntiRaid templating subsystem boundary. This metatable must be set on all arrays over this boundary and is required to ensure AntiRaid knows the value you're sending it is actually an array and not an arbitrary Luau table. + + + +## Methods + +### memusage + +```lua +function memusage(): f64 +``` + +Returns the current memory usage of the Lua VM. + +#### Returns + +- `memory_usage` ([f64](#type.f64)): The current memory usage, in bytes, of the Lua VM. + +--- +# @antiraid/kv + +Utilities for key-value operations. + +## Types + +
+ +### KvRecord + +KvRecord represents a key-value record with metadata. + +```json +{ + "key": "", + "value": null, + "exists": false, + "created_at": null, + "last_updated_at": null +} +``` + +#### Fields + +- `key` ([string](#type.string)): The key of the record. +- `value` ([any](#type.any)): The value of the record. +- `exists` ([bool](#type.bool)): Whether the record exists. +- `created_at` ([datetime](#type.datetime)): The time the record was created. +- `last_updated_at` ([datetime](#type.datetime)): The time the record was last updated. + + +
+ +### KvExecutor + +KvExecutor allows templates to get, store and find persistent data within a scope. + +#### Methods + +##### KvExecutor:find + +Finds records in a scoped key-value database. ``%`` can be used as wildcards before/after the query. E.g. ``%{KEY}%`` will search for ``{KEY}`` anywhere in the string, ``%{KEY}`` will search for keys which end with ``{KEY}`` and ``_{KEY}`` will search for a single character before ``{KEY}``. + +```lua +function KvExecutor:find(key: string): {KvRecord} +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + +###### Parameters + +- `key` ([string](#type.string)): The key to search for. % matches zero or more characters; _ matches a single character. To search anywhere in a string, surround {KEY} with %, e.g. %{KEY}% + +###### Returns + +- `records` ([{KvRecord}](#type.KvRecord)): The records found. + +##### KvExecutor:exists + +Determines if a key exists in the scoped key-value database. + +```lua +function KvExecutor:exists(key: string): bool +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + +###### Parameters + +- `key` ([string](#type.string)): The key to check for existence. + +###### Returns + +- `exists` ([bool](#type.bool)): Whether the key exists. + +##### KvExecutor:get + +Returns the value of a key in the scoped key-value database. + +```lua +function KvExecutor:get(key: string) +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `key` ([string](#type.string)): The key to get. + + +###### Returns + +- `value` ([any](#type.any)): The value of the key.- `exists` ([bool](#type.bool)): Whether the key exists. +##### KvExecutor:getrecord + +```lua +function KvExecutor:getrecord(key: string): KvRecord +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `key` ([string](#type.string)): The key to get. + + +###### Returns + +- `record` ([KvRecord](#type.KvRecord)): The record of the key. +##### KvExecutor:set + +```lua +function KvExecutor:set(key: string, value: any) +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `key` ([string](#type.string)): The key to set. +- `value` ([any](#type.any)): The value to set. + +##### KvExecutor:delete + +```lua +function KvExecutor:delete(key: string) +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `key` ([string](#type.string)): The key to delete. + + + +## Methods + +### new + +```lua +function new(token: TemplateContext, scope: string?): KvExecutor +``` + +#### Parameters + +- `token` ([TemplateContext](#type.TemplateContext)): The token of the template to use. +- `scope` ([string?](#type.string)): The scope of the executor. `this_guild` to use the originating guilds data, `owner_guild` to use the KV of the guild that owns the template on the shop. Defaults to `this_guild` if not specified. + + +#### Returns + +- `executor` ([KvExecutor](#type.KvExecutor)): A key-value executor. + + +TO MOVE TO PRIMITIVES DOCS + +- `guild_id` ([string](#type.string)): The guild ID the executor will perform key-value operations on. +- `origin_guild_id` ([string](#type.string)): The originating guild ID (the guild ID of the template itself). +- `allowed_caps` ([{string}](#type.{string})): The allowed capabilities in the current context. +- `has_cap` ([function](#type.function)): A function that returns `true` if the current context has the capability specified. +- `scope` ([string](#type.string)): The scope of the executor. Either ``this_guild`` for the originating guild, or ``owner_guild`` for the guild that owns the template (the template that owns the template on the shop if a shop template or the guild that owns the template otherwise). +--- +# @antiraid/lazy + +This plugin allows for templates to interact with and create 'lazy' data as well as providing documentation for the type. Note that events are *not* 'lazy' data's and have their own semantics. + +## Types + +
+ +### Lazy + +A lazy data type that is only serialized to Lua upon first access. This can be much more efficient than serializing the data every time it is accessed. Note that events are *not* 'lazy' data's and have their own semantics. + +#### Fields + +- `data` ([T](#type.T)): The inner data. This is cached upon first access +- `lazy` ([boolean](#type.boolean)): Always returns true. Allows the user to check if the data is a lazy or not + + +## Methods + +### new + +```lua +function new(data: TemplateContext): Lazy +``` + +Creates a new Lazy type from data. This can be useful as a deep-copy implementation [``lazy.new(value).data`` is guaranteed to do a deepcopy of data as long as ``value`` is serializable] + +#### Parameters + +- `data` ([TemplateContext](#type.TemplateContext)): The data to wrap in a lazy + +#### Returns + +- `lazy` ([Lazy](#type.Lazy)): A lazy value +--- +# @antiraid/lockdowns + +This plugin allows for templates to interact with AntiRaid lockdowns + +## Types + +
+ +### Lockdown + +A created lockdown + +```json +{ + "id": "805c0dd1-a625-4875-81e4-8edc6a14f659", + "reason": "Testing", + "type": "qsl", + "data": {}, + "created_at": "2025-01-13T04:57:43.488340240Z" +} +``` + +#### Fields + +- `id` ([string](#type.string)): The id of the lockdown +- `reason` ([string](#type.string)): The reason for the lockdown +- `type` ([string](#type.string)): The type of lockdown in string form +- `data` ([any](#type.any)): The data associated with the lockdown +- `created_at` ([string](#type.string)): The time the lockdown was created + + +
+ +### LockdownExecutor + +An executor for listing, creating and removing lockdowns + + + +#### Methods + +##### LockdownExecutor:list + +```lua +function LockdownExecutor:list(): {Lockdown} +``` + +Lists all active lockdowns + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Returns + +- `lockdowns` ([{Lockdown}](#type.Lockdown)): A list of all currently active lockdowns +##### LockdownExecutor:qsl + +```lua +function LockdownExecutor:qsl(reason: string) +``` + +Starts a quick server lockdown + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `reason` ([string](#type.string)): The reason for the lockdown + +##### LockdownExecutor:tsl + +```lua +function LockdownExecutor:tsl(reason: string) +``` + +Starts a traditional server lockdown + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `reason` ([string](#type.string)): The reason for the lockdown + +##### LockdownExecutor:scl + +```lua +function LockdownExecutor:scl(channel: string, reason: string) +``` + +Starts a lockdown on a single channel + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `channel` ([string](#type.string)): The channel to lock down +- `reason` ([string](#type.string)): The reason for the lockdown + +##### LockdownExecutor:role + +```lua +function LockdownExecutor:role(role: string, reason: string) +``` + +Starts a lockdown on a role + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `role` ([string](#type.string)): The role to lock down +- `reason` ([string](#type.string)): The reason for the lockdown + +##### LockdownExecutor:remove + +```lua +function LockdownExecutor:remove(id: string) +``` + +Removes a lockdown + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `id` ([string](#type.string)): The id of the lockdown to remove + + + +## Methods + +### new + +```lua +function new(token: TemplateContext): LockdownExecutor +``` + +#### Parameters + +- `token` ([TemplateContext](#type.TemplateContext)): The token of the template to use + + +#### Returns + +- `executor` ([LockdownExecutor](#type.LockdownExecutor)): A lockdown executor +--- +# @antiraid/permissions + +Utilities for handling permission checks. + +## Types + +
+ +### Permission + +Permission is the primitive permission type used by AntiRaid. See https://github.com/InfinityBotList/kittycat for more information + +```json +{ + "namespace": "moderation", + "perm": "ban", + "negator": false +} +``` + +#### Fields + +- `namespace` ([string](#type.string)): The namespace of the permission. +- `perm` ([string](#type.string)): The permission bit on the namespace. +- `negator` ([bool](#type.bool)): Whether the permission is a negator permission or not + + +
+ +### StaffPermissions + +StaffPermissions as per kittycat terminology. + +```json +{ + "user_positions": [ + { + "id": "1234567890", + "index": 1, + "perms": [ + { + "namespace": "moderation", + "perm": "ban", + "negator": false + }, + { + "namespace": "moderation", + "perm": "kick", + "negator": false + } + ] + }, + { + "id": "0987654321", + "index": 2, + "perms": [ + { + "namespace": "moderation", + "perm": "ban", + "negator": false + }, + { + "namespace": "moderation", + "perm": "kick", + "negator": false + } + ] + } + ], + "perm_overrides": [ + { + "namespace": "moderation", + "perm": "ban", + "negator": true + }, + { + "namespace": "moderation", + "perm": "kick", + "negator": true + } + ] +} +``` + +#### Fields + +- `perm_overrides` ([{Permission}](#type.Permission)): Permission overrides on the member. +- `user_positions` ([{PartialStaffPosition}](#type.PartialStaffPosition)): The staff positions of the user. + + +
+ +### PartialStaffPosition + +PartialStaffPosition as per kittycat terminology. + +```json +{ + "id": "1234567890", + "index": 1, + "perms": [ + { + "namespace": "moderation", + "perm": "ban", + "negator": false + }, + { + "namespace": "moderation", + "perm": "kick", + "negator": false + } + ] +} +``` + +#### Fields + +- `id` ([string](#type.string)): The ID of the staff member. +- `index` ([number](#type.number)): The index of the staff member. +- `perms` ([{Permission}](#type.Permission)): The permissions of the staff member. + + +## Methods + +### permission_from_string + +```lua +function permission_from_string(perm_string: string): Permission +``` + +Returns a Permission object from a string. + +#### Parameters + +- `perm_string` ([string](#type.string)): The string to parse into a Permission object. + + +#### Returns + +- `permission` ([Permission](#type.Permission)): The parsed Permission object. + +### permission_to_string + +```lua +function permission_to_string(permission: Permission): string +``` + +Returns a string from a Permission object. + +#### Parameters + +- `permission` ([Permission](#type.Permission)): The Permission object to parse into a string. + + +#### Returns + +- `perm_string` ([string](#type.string)): The parsed string. + +### has_perm + +```lua +function has_perm(permissions: {Permission}, permission: Permission): bool +``` + +Checks if a list of permissions in Permission object form contains a specific permission. + +#### Parameters + +- `permissions` ([{Permission}](#type.Permission)): The list of permissions +- `permission` ([Permission](#type.Permission)): The permission to check for. + + +#### Returns + +- `has_perm` ([bool](#type.bool)): Whether the permission is present in the list of permissions as per kittycat rules. + +### has_perm_str + +```lua +function has_perm_str(permissions: {string}, permission: string): bool +``` + +Checks if a list of permissions in canonical string form contains a specific permission. + +#### Parameters + +- `permissions` ([{string}](#type.string)): The list of permissions +- `permission` ([string](#type.string)): The permission to check for. + + +#### Returns + +- `has_perm` ([bool](#type.bool)): Whether the permission is present in the list of permissions as per kittycat rules. + +### staff_permissions_resolve + +```lua +function staff_permissions_resolve(sp: StaffPermissions): {Permission} +``` + +Resolves a StaffPermissions object into a list of Permission objects. See https://github.com/InfinityBotList/kittycat for more details + +#### Parameters + +- `sp` ([StaffPermissions](#type.StaffPermissions)): The StaffPermissions object to resolve. + + +#### Returns + +- `permissions` ([{Permission}](#type.Permission)): The resolved list of Permission objects. + +### check_patch_changes + +```lua +function check_patch_changes(manager_perms: {Permission}, current_perms: {Permission}, new_perms: {Permission}) +``` + +Checks if a list of permissions can be patched to another list of permissions. + +#### Parameters + +- `manager_perms` ([{Permission}](#type.Permission)): The permissions of the manager. +- `current_perms` ([{Permission}](#type.Permission)): The current permissions of the user. +- `new_perms` ([{Permission}](#type.Permission)): The new permissions of the user. + +#### Returns + +- `can_patch` ([bool](#type.bool)): Whether the permissions can be patched.- `error` ([any](#type.any)): The error if the permissions cannot be patched. Will contain ``type`` field with the error type and additional fields depending on the error type. +--- +# @antiraid/promise + +Lua Promises, yield for a promise to execute the async action returning its result. + +## Types + +
+ +### LuaPromise + +LuaPromise provides a promise that must be yielded to actually execute and get the result of the async action. + +## Methods + +### yield + +```lua +function yield(promise: LuaPromise): T +``` + +Yields the promise to execute the async action and return its result. Note that this is the only function other than `stream.next` that yields. + +#### Parameters + +- `promise` ([LuaPromise](#type.LuaPromise)): The promise to yield. + + +#### Returns + +- `T` ([T](#type.T)): The result of executing the promise. + +--- + +## Promise Execution Cycle + +When you create a promise, it does not do anything (in essence, it acts like a *future*). You must yield the promise to actually execute the async action and get the result. This is because the Lua VM is single-threaded and cannot execute things concurrently so your code must yield to allow the Promises' internal code to run and return the result back, which *resumes* your code. + +```lua +local promise = someAsyncAction() -- A LuaPromise is returned +local result = promise.yield(promise) -- Now, result is a ``T``! +``` + +While usually not very useful, the created promise can also be re-used multiple times, as it is not consumed by yielding it. + +```lua +local promise = someAsyncAction() -- A LuaPromise is returned +local result1 = promise.yield(promise) -- Now, result1 is a ``T``! +local result2 = promise.yield(promise) -- Now, result2 is a ``T``! +``` + +--- +# @antiraid/stings + +List, get, create, update and delete stings on Anti-Raid. + +## Types + +
+ +### StingCreate + +A type representing a new sting to be created. + +```json +{ + "src": "test", + "stings": 10, + "reason": "test", + "void_reason": null, + "guild_id": "128384", + "creator": "system", + "target": "user:1945824", + "state": "active", + "duration": { + "secs": 60, + "nanos": 0 + }, + "sting_data": { + "a": "b" + } +} +``` + +#### Fields + +- `src` ([string?](#type.string)): The source of the sting. +- `stings` ([number](#type.number)): The number of stings. +- `reason` ([string?](#type.string)): The reason for the stings. +- `void_reason` ([string?](#type.string)): The reason the stings were voided. +- `guild_id` ([string](#type.string)): The guild ID the sting targets. **MUST MATCH THE GUILD ID THE TEMPLATE IS RUNNING ON** +- `creator` ([StingTarget](#type.StingTarget)): The creator of the sting. +- `target` ([StingTarget](#type.StingTarget)): The target of the sting. +- `state` ([string](#type.string)): The state of the sting. Must be one of 'active', 'voided' or 'handled' +- `duration` ([Duration?](#type.Duration)): When the sting expires as a duration. +- `sting_data` ([any?](#type.any)): The data/metadata present within the sting, if any. + + +
+ +### Sting + +Represents a sting on AntiRaid + +```json +{ + "id": "470a2958-3827-4e59-8b97-928a583a37a3", + "src": "test", + "stings": 10, + "reason": "test", + "void_reason": null, + "guild_id": "128384", + "creator": "system", + "target": "user:1945824", + "state": "active", + "created_at": "2025-01-13T04:57:43.488668165Z", + "duration": { + "secs": 60, + "nanos": 0 + }, + "sting_data": { + "a": "b" + }, + "handle_log": { + "a": "b" + } +} +``` + +#### Fields + +- `id` ([string](#type.string)): The sting ID. +- `src` ([string?](#type.string)): The source of the sting. +- `stings` ([number](#type.number)): The number of stings. +- `reason` ([string?](#type.string)): The reason for the stings. +- `void_reason` ([string?](#type.string)): The reason the stings were voided. +- `guild_id` ([string](#type.string)): The guild ID the sting targets. **MUST MATCH THE GUILD ID THE TEMPLATE IS RUNNING ON** +- `creator` ([StingTarget](#type.StingTarget)): The creator of the sting. +- `target` ([StingTarget](#type.StingTarget)): The target of the sting. +- `state` ([StingState](#type.StingState)): The state of the sting. +- `duration` ([Duration?](#type.Duration)): When the sting expires as a duration. +- `sting_data` ([any?](#type.any)): The data/metadata present within the sting, if any. +- `handle_log` ([any](#type.any)): The handle log encountered while handling the sting. +- `created_at` ([string](#type.string)): When the sting was created at. + + +
+ +### StingExecutor + +An sting executor is used to execute actions related to stings from Lua templates + + + +#### Methods + +##### StingExecutor:list + +```lua +function StingExecutor:list(page: number): {Sting} +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `page` ([number](#type.number)): The page number to fetch. + + +###### Returns + +- `stings` ([{Sting}](#type.Sting)): The list of stings. +##### StingExecutor:get + +```lua +function StingExecutor:get(id: string): Sting +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `id` ([string](#type.string)): The sting ID. + + +###### Returns + +- `sting` ([Sting](#type.Sting)): The sting. +##### StingExecutor:create + +```lua +function StingExecutor:create(data: StingCreate): string +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([StingCreate](#type.StingCreate)): The sting data. + + +###### Returns + +- `id` ([string](#type.string)): The sting ID of the created sting. +##### StingExecutor:update + +```lua +function StingExecutor:update(data: Sting) +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `data` ([Sting](#type.Sting)): The sting to update to. Note that if an invalid ID is used, this method may either do nothing or error out. + +##### StingExecutor:delete + +```lua +function StingExecutor:delete(id: string) +``` + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `id` ([string](#type.string)): The sting ID. + + + +## Enums + +
+ +### StingTarget + +The target of the sting. + +There are two variants: ``system`` (A system target/no associated user) and ``user:{user_id}`` (A user target) + +--- +# @antiraid/typesext + +Extra types used by Anti-Raid Lua templating subsystem to either add in common functionality such as streams or handle things like u64/i64 types performantly. + +## Types + +
+ +### MultiOption + +MultiOption allows distinguishing between `null` and empty fields. Use the value to show both existence and value (`Some(Some(value))`) an empty object to show existence (``Some(None)``) or null to show neither (`None`) + + + +
+ +### U64 + +U64 is a 64-bit unsigned integer type. Implements Add/Subtract/Multiply/Divide/Modulus/Power/Integer Division/Equality/Comparison (Lt/Le and its complements Gt/Ge) and ToString with a type name of U64 + + + +#### Methods + +##### U64:to_ne_bytes + +```lua +function U64:to_ne_bytes(): {u8} +``` + +Converts the U64 to a little-endian byte array. + +###### Returns + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. +##### U64:from_ne_bytes + +```lua +function U64:from_ne_bytes(bytes: {u8}): U64 +``` + +Converts a little-endian byte array to a U64. + +###### Parameters + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. + + +###### Returns + +- `u64` ([U64](#type.U64)): The U64 value. +##### U64:to_le_bytes + +```lua +function U64:to_le_bytes(): {u8} +``` + +Converts the U64 to a little-endian byte array. + +###### Returns + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. +##### U64:from_le_bytes + +```lua +function U64:from_le_bytes(bytes: {u8}): U64 +``` + +Converts a little-endian byte array to a U64. + +###### Parameters + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. + + +###### Returns + +- `u64` ([U64](#type.U64)): The U64 value. +##### U64:to_be_bytes + +```lua +function U64:to_be_bytes(): {u8} +``` + +Converts the U64 to a big-endian byte array. + +###### Returns + +- `bytes` ([{u8}](#type.u8)): The big-endian byte array. +##### U64:from_be_bytes + +```lua +function U64:from_be_bytes(bytes: {u8}): U64 +``` + +Converts a big-endian byte array to a U64. + +###### Parameters + +- `bytes` ([{u8}](#type.u8)): The big-endian byte array. + + +###### Returns + +- `u64` ([U64](#type.U64)): The U64 value. +##### U64:to_i64 + +```lua +function U64:to_i64(): I64 +``` + +Converts the U64 to an i64. + +###### Returns + +- `i64` ([I64](#type.I64)): The i64 value. + + +
+ +### I64 + +I64 is a 64-bit signed integer type. Implements Add/Subtract/Multiply/Divide/Modulus/Power/Integer Division/Equality/Comparison (Lt/Le and its complements Gt/Ge) and ToString with a type name of I64 + + + +#### Methods + +##### I64:to_ne_bytes + +```lua +function I64:to_ne_bytes(): {u8} +``` + +Converts the I64 to a little-endian byte array. + +###### Returns + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. +##### I64:from_ne_bytes + +```lua +function I64:from_ne_bytes(bytes: {u8}): I64 +``` + +Converts a little-endian byte array to a I64. + +###### Parameters + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. + + +###### Returns + +- `i64` ([I64](#type.I64)): The I64 value. +##### I64:to_le_bytes + +```lua +function I64:to_le_bytes(): {u8} +``` + +Converts the I64 to a little-endian byte array. + +###### Returns + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. +##### I64:from_le_bytes + +```lua +function I64:from_le_bytes(bytes: {u8}): I64 +``` + +Converts a little-endian byte array to a I64. + +###### Parameters + +- `bytes` ([{u8}](#type.u8)): The little-endian byte array. + + +###### Returns + +- `i64` ([I64](#type.I64)): The I64 value. +##### I64:to_be_bytes + +```lua +function I64:to_be_bytes(): {u8} +``` + +Converts the I64 to a big-endian byte array. + +###### Returns + +- `bytes` ([{u8}](#type.u8)): The big-endian byte array. +##### I64:from_be_bytes + +```lua +function I64:from_be_bytes(bytes: {u8}): I64 +``` + +Converts a big-endian byte array to a I64. + +###### Parameters + +- `bytes` ([{u8}](#type.u8)): The big-endian byte array. + + +###### Returns + +- `i64` ([I64](#type.I64)): The I64 value. +##### I64:to_u64 + +```lua +function I64:to_u64(): U64 +``` + +Converts the I64 to a U64. + +###### Returns + +- `u64` ([U64](#type.U64)): The U64 value. + + +
+ +### bitu64 + +[bit32](https://luau.org/library#bit32-library) but for U64 datatype. Note that bit64 is experimental and may not be properly documented at all times. When in doubt, reach for Luau's bit32 documentation and simply replace 31's with 63's + + + +#### Methods + +##### bitu64:band + +```lua +function bitu64:band(values: {U64}): U64 +``` + +Performs a bitwise AND operation on the given values. + +###### Parameters + +- `values` ([{U64}](#type.U64)): The values to perform the operation on. + + +###### Returns + +- `result` ([U64](#type.U64)): The result of the operation. +##### bitu64:bnor + +```lua +function bitu64:bnor(n: U64): U64 +``` + +Performs a bitwise NOR operation on the given value. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to perform the operation on. + + +###### Returns + +- `result` ([U64](#type.U64)): The result of the operation. +##### bitu64:bor + +```lua +function bitu64:bor(values: {U64}): U64 +``` + +Performs a bitwise OR operation on the given values. + +###### Parameters + +- `values` ([{U64}](#type.U64)): The values to perform the operation on. + + +###### Returns + +- `result` ([U64](#type.U64)): The result of the operation. +##### bitu64:bxor + +```lua +function bitu64:bxor(values: {U64}): U64 +``` + +Performs a bitwise XOR operation on the given values. + +###### Parameters + +- `values` ([{U64}](#type.U64)): The values to perform the operation on. + + +###### Returns + +- `result` ([U64](#type.U64)): The result of the operation. +##### bitu64:btest + +```lua +function bitu64:btest(values: {U64}): bool +``` + +Tests if the bitwise AND of the given values is not zero. + +###### Parameters + +- `values` ([{U64}](#type.U64)): The values to perform the operation on. + + +###### Returns + +- `result` ([bool](#type.bool)): True if the bitwise AND of the values is not zero, false otherwise. +##### bitu64:extract + +```lua +function bitu64:extract(n: U64, f: u64, w: u64): U64 +``` + +Extracts a field from a value. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to extract the field from. +- `f` ([u64](#type.u64)): The field to extract. +- `w` ([u64](#type.u64)): The width of the field to extract. + + +###### Returns + +- `result` ([U64](#type.U64)): The extracted field. +##### bitu64:lrotate + +```lua +function bitu64:lrotate(n: U64, i: i64): U64 +``` + +Rotates a value left or right. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to rotate. +- `i` ([i64](#type.i64)): The amount to rotate by. + + +###### Returns + +- `result` ([U64](#type.U64)): The rotated value. +##### bitu64:lshift + +```lua +function bitu64:lshift(n: U64, i: i64): U64 +``` + +Shifts a value left or right. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to shift. +- `i` ([i64](#type.i64)): The amount to shift by. + + +###### Returns + +- `result` ([U64](#type.U64)): The shifted value. +##### bitu64:replace + +```lua +function bitu64:replace(n: U64, v: U64, f: u64, w: u64): U64 +``` + +Replaces a field in a value. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to replace the field in. +- `v` ([U64](#type.U64)): The value to replace the field with. +- `f` ([u64](#type.u64)): The field to replace. +- `w` ([u64](#type.u64)): The width of the field to replace. + + +###### Returns + +- `result` ([U64](#type.U64)): The value with the field replaced. +##### bitu64:rrotate + +```lua +function bitu64:rrotate(n: U64, i: i64): U64 +``` + +Rotates a value left or right. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to rotate. +- `i` ([i64](#type.i64)): The amount to rotate by. + + +###### Returns + +- `result` ([U64](#type.U64)): The rotated value. +##### bitu64:rshift + +```lua +function bitu64:rshift(n: U64, i: i64): U64 +``` + +Shifts a value left or right. + +###### Parameters + +- `n` ([U64](#type.U64)): The value to shift. +- `i` ([i64](#type.i64)): The amount to shift by. + + +###### Returns + +- `result` ([U64](#type.U64)): The shifted value. + + +## Methods + +### U64 + +```lua +function U64(value: u64): U64 +``` + +Creates a new U64. + +#### Parameters + +- `value` ([u64](#type.u64)): The value of the U64. + + +#### Returns + +- `u64` ([U64](#type.U64)): The U64 value. + +### I64 + +```lua +function I64(value: i64): I64 +``` + +Creates a new I64. + +#### Parameters + +- `value` ([i64](#type.i64)): The value of the I64. + + +#### Returns + +- `i64` ([I64](#type.I64)): The I64 value. + +--- +# @antiraid/userinfo + +This plugin allows for templates to interact with user's core information on AntiRaid (permissions etc) + +## Types + +
+ +### UserInfo + +A user info object + +```json +{ + "discord_permissions": "2111062325329919", + "kittycat_staff_permissions": { + "user_positions": [], + "perm_overrides": [ + { + "namespace": "global", + "perm": "*", + "negator": false + } + ] + }, + "kittycat_resolved_permissions": [ + { + "namespace": "moderation", + "perm": "kick", + "negator": false + }, + { + "namespace": "moderation", + "perm": "ban", + "negator": false + } + ], + "guild_owner_id": "1234567890", + "guild_roles": [], + "member_roles": [ + "1234567890" + ] +} +``` + +#### Fields + +- `discord_permissions` ([string](#type.string)): The discord permissions of the user +- `kittycat_staff_permissions` ([StaffPermissions](#type.StaffPermissions)): The staff permissions of the user +- `kittycat_resolved_permissions` ([{Permission}](#type.Permission)): The resolved permissions of the user +- `guild_owner_id` ([string](#type.string)): The guild owner id +- `guild_roles` ([{[string]: Serenity.Role}](#type.[string]: Serenity.Role)): The roles of the guild +- `member_roles` ([{string}](#type.string)): The roles of the member + + +
+ +### UserInfoExecutor + +UserInfoExecutor allows templates to access/use user infos not otherwise sent via events. + + + +#### Methods + +##### UserInfoExecutor:get + +```lua +function UserInfoExecutor:get(user: string): +``` + +Gets the user info of a user. + +**Note that this method returns a promise that must be yielded using [`promise.yield`](#type.promise.yield) to actually execute and return results.** + + + +###### Parameters + +- `user` ([string](#type.string)): The user id to get the info of. + + +###### Returns + +- `UserInfo` ([](#type.)): The user info of the user. + + +## Methods + +### new + +```lua +function new(token: TemplateContext): UserInfoExecutor +``` + +#### Parameters + +- `token` ([TemplateContext](#type.TemplateContext)): The token of the template to use. + + +#### Returns + +- `executor` ([UserInfoExecutor](#type.UserInfoExecutor)): A userinfo executor. +--- +# Primitives + +
+ +## u8 + +```lua +type u8 = number +``` + +An unsigned 8-bit integer. **Note: u8 arrays (`{u8}`) are often used to represent an array of bytes in AntiRaid** + +### Constraints + +- **range**: The range of values this number can take on (accepted values: 0-255) + +--- + +
+ +## u16 + +```lua +type u16 = number +``` + +An unsigned 16-bit integer. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: 0-65535) + +--- + +
+ +## u32 + +```lua +type u32 = number +``` + +An unsigned 32-bit integer. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: 0-4294967295) + +--- + +
+ +## u64 + +```lua +type u64 = number +``` + +An unsigned 64-bit integer. **Note that most, if not all, cases of `i64` in the actual API are either `string` or the `I64` custom type from typesext** + +### Constraints + +- **range**: The range of values this number can take on (accepted values: 0-18446744073709551615) + +--- + +
+ +## i8 + +```lua +type i8 = number +``` + +A signed 8-bit integer. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: -128-127) + +--- + +
+ +## i16 + +```lua +type i16 = number +``` + +A signed 16-bit integer. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: -32768-32767) + +--- + +
+ +## i32 + +```lua +type i32 = number +``` + +A signed 32-bit integer. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: -2147483648-2147483647) + +--- + +
+ +## i64 + +```lua +type i64 = number +``` + +A signed 64-bit integer. **Note that most, if not all, cases of `i64` in the actual API are either `string` or the `I64` custom type from typesext** + +### Constraints + +- **range**: The range of values this number can take on (accepted values: -9223372036854775808-9223372036854775807) + +--- + +
+ +## f32 + +```lua +type f32 = number +``` + +A 32-bit floating point number. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: IEEE 754 single-precision floating point) + +--- + +
+ +## f64 + +```lua +type f64 = number +``` + +A 64-bit floating point number. + +### Constraints + +- **range**: The range of values this number can take on (accepted values: IEEE 754 double-precision floating point) + +--- + +
+ +## byte + +```lua +type byte = number +``` + +An unsigned 8-bit integer that semantically stores a byte of information + +### Constraints + +- **range**: The range of values this number can take on (accepted values: 0-255) + +--- + +
+ +## bool + +```lua +type bool = boolean +``` + +A boolean value. + +--- + +
+ +## char + +```lua +type char = string +``` + +A single Unicode character. + +### Constraints + +- **length**: The length of the string (accepted values: 1) + +--- + +
+ +## string + +```lua +type string = string +``` + +A UTF-8 encoded string. + +### Constraints + +- **encoding**: Accepted character encoding (accepted values: UTF-8 *only*) + +--- + +
+ +## function + +```lua +type function = function +``` + +A Lua function. + +--- + +# Types + +
+ +## Event + +An event that has been dispatched to the template. This is what `args` is in the template. + + + +### Fields + +- `base_name` ([string](#type.string)): The base name of the event. +- `name` ([string](#type.string)): The name of the event. +- `data` ([unknown](#type.unknown)): The data of the event. +- `can_respond` ([boolean](#type.boolean)): Whether the event can be responded to. +- `response` ([unknown](#type.unknown)): The current response of the event. This can be overwritten by the template by just setting it to a new value. +- `author` ([string?](#type.string)): The author of the event, if any. If there is no known author, this field will either be `nil` or `null`. + + +
+ +## Template + +`Template` is a struct that represents the data associated with a template. Fields are still being documented and subject to change. + +```json +{ + "guild_id": "0", + "name": "", + "description": null, + "shop_name": null, + "shop_owner": null, + "events": [], + "error_channel": null, + "content": "", + "lang": "luau", + "allowed_caps": [], + "created_by": "", + "created_at": "1970-01-01T00:00:00Z", + "updated_by": "", + "updated_at": "1970-01-01T00:00:00Z" +} +``` + +### Fields + +- `language` ([string](#type.string)): The language of the template. +- `allowed_caps` ([{string}](#type.string)): The allowed capabilities provided to the template. + + +
+ +## TemplateContext + +`TemplateContext` is a struct that represents the context of a template. Stores data including the templates data, pragma and what capabilities it should have access to. Passing a TemplateContext is often required when using AntiRaid plugins for security purposes. + + + +### Fields + +- `template_data` ([TemplateData](#type.TemplateData)): The data associated with the template. +- `guild_id` ([string](#type.string)): The current guild ID the template is running on. +- `current_user` ([Serenity.User](#type.Serenity.User)): Returns AntiRaid's discord user object [the current discord bot user driving the template]. + +--- diff --git a/docs/src/user/templating/3-example.md b/docs/src/dev/templating/3-example.md similarity index 100% rename from docs/src/user/templating/3-example.md rename to docs/src/dev/templating/3-example.md diff --git a/docs/src/user/templating/4-luau-ecosystem.md b/docs/src/dev/templating/4-luau-ecosystem.md similarity index 100% rename from docs/src/user/templating/4-luau-ecosystem.md rename to docs/src/dev/templating/4-luau-ecosystem.md diff --git a/docs/src/user/templating/5-hooks.md b/docs/src/dev/templating/5-hooks.md similarity index 100% rename from docs/src/user/templating/5-hooks.md rename to docs/src/dev/templating/5-hooks.md diff --git a/docs/src/user/templating/6-types-and-ext.md b/docs/src/dev/templating/6-types-and-ext.md similarity index 100% rename from docs/src/user/templating/6-types-and-ext.md rename to docs/src/dev/templating/6-types-and-ext.md diff --git a/docs/src/dev/rust_templating/README.md b/docs/src/dev/templating/README.md similarity index 100% rename from docs/src/dev/rust_templating/README.md rename to docs/src/dev/templating/README.md diff --git a/docs/src/user/templating/1-intro.md b/docs/src/user/templating/1-intro.md index 3d4fda66..e26afadd 100644 --- a/docs/src/user/templating/1-intro.md +++ b/docs/src/user/templating/1-intro.md @@ -1,107 +1,3 @@ -# Lua Templating +# Loading templates from the shop -At AntiRaid, we prioritize flexibility and customization for our users. To this end, our bot supports advanced templating to allow for extensive personalization of embeds and messages. While many bots utilize proprietary languages or templating engines, we have chosen to leverage Lua—a renowned scripting language widely used in game development and other applications. This decision ensures that our users benefit from a powerful, well-documented, and versatile language, enhancing the capability and ease of customizing their AntiRaid experience. - -Specifically, Anti Raid uses a variant of Lua called Luau. If you've ever used Roblox before, this is the same variant of Lua used there too (which is why Luau is also known as Roblox Lua in many places). You can check out the [Luau docs](https://luau-lang.org/) for more information on the language itself. Unlike PUC Lua (the reference implementation), Luau is both faster and offers robust sandboxing capabilities allowing AntiRaid to run scripts in as safe an environment as possible. - -## Getting Started - -Note that the remainder of these docs will cover AntiRaids Lua SDKs. To learn more about Lua itself, please checkout Lua's official tutorial for Lua 5.0 [here](https://www.lua.org/pil/1.html). Other resources for Lua exist (Lua is very popular after all), including [Roblox's tutorial](https://devforum.roblox.com/t/lua-scripting-starter-guide/394618#print-5) (ignore the Studio bits), [TutorialPoint](https://www.tutorialspoint.com/lua/lua_quick_guide.htm) and [Codecademy](https://www.codecademy.com/learn/learn-lua). - -## Limitations - -AntiRaid applies the following 3 global limits to all Lua templates. Note that we may provide increased limits as a Premium feature in the future: - -```rust -pub const MAX_TEMPLATE_MEMORY_USAGE: usize = 1024 * 1024 * 3; // 3MB maximum memory -pub const MAX_TEMPLATES_EXECUTION_TIME: std::time::Duration = std::time::Duration::from_secs(30); // 30 seconds maximum execution time -``` - -The above limits are in place to prevent abuse and ensure that the bot remains responsive. If you require increased limits, please contact support (once again, this may change in the future). - -## Some key notes - -- Each guild is assigned a dedicated Lua VM. This VM is used to execute Lua code that is used in the templates. -- The total memory usage that a guild can use is limited to ``MAX_TEMPLATE_MEMORY_USAGE`` (currently 3MB). This is to prevent a single guild from using too much memory. -- Execution of all scripts is timed out when the last executed script takes longer than ``MAX_TEMPLATES_EXECUTION_TIME`` (currently 30 seconds). -- A guilds Lua VM will persist until marked as broken (either by explicitly requesting it or by exceeding memory limits) -- The ``__stack`` table can be used to share data across templates safely *while the VM is running*. without affecting other templates. This is useful for sharing data between templates such as Audit Logs. **Note that AntiRaid uses luau sandboxing meaning that `_G` is readonly.** -- The standard ``require`` statement can be used to import AntiRaid modules. **Note that the modules are read-only** and cannot be monkey-patched etc. -- **Because Lua is a single-threaded language, only one template can be executed at a time** - -In general, all AntiRaid templates should start with the following: - -```lua -local args, token = ... --- Do something -return output -``` - -## Interop - -Many features of Lua don't work so well when calling functions within the AntiRaid SDK. For example, both arrays and maps are expressed as tables in Lua. However, AntiRaid, being written in Rust, doesn't know this and hance needs some help to convert certain types for FFI. This is where the `@antiraid/interop` module comes in. - -### Arrays - -To pass arrays to modules within the AntiRaid SDK, you need to set the metatable to ``@antiraid/interop#array_metatable``. This will allow the SDK to convert the array to a Rust ``Vec`` internally. - -```lua -local interop = require '@antiraid/interop' -setmetatable({a = 5}, interop.array_metatable) -``` - -### Null - -While the Lua ``nil`` does work in many cases (and even when calling the SDK), its not the best choice. When querying AntiRaid SDK, the SDK will use the ``@antiraid/interop#null`` value to represent a null value. Your Lua templates can also use this value if desired - -```lua -local interop = require '@antiraid/interop' -local null = interop.null -- This is the null value -``` - -### Memory Usage - -While not strictly useful for interop, it is often desirable to know the memory usage of a Lua template as AntiRaid will kill your template if it exceeds the memory limit. For this, you can use the `@antiraid/interop#memusage` function. - -```lua -local interop = require '@antiraid/interop' -print(interop.memusage()) -``` - -### User Error vs Runtime Error - -As Lua does not have a built-in way to distinguish between user errors and runtime errors, AntiRaid provides a way to do so. Simply return a table with the key ``__error`` set, and the value set to the error message to create a user error. You can use the standard ``error`` function for runtime errors. E.g. - - -```lua --- User Error -return { __error = "You have reached the maximum number of tries in this 5 minute window." } - --- Runtime Error -error("Could not parse user ID for some reason") -``` - -## Events - -All Lua templates are invoked via events. As such, the first argument to the template is an ``Event``. ``Event`` is a ``userdata``. The below will explain the most important fields exposed by ``Event``. Note that all fields, unless stated otherwise, are read-only: - -- `` - -## Template Context - -All Lua templates are passed both the ``Event`` (denoted by `args`) and a `TemplateContext` userdata (denoted by `token`). Note that like ``Event``, ``TemplateContext`` is a *userdata* (not a table). As such, they cannot be manually constructed in templates themselves. - -"Executors" and other sensistive APIs use the `TemplateContext` to read ``template_data`` including the pragma (note that `template_data` is also exposed to templates as a read-only field). This is what allows AntiRaids capability system to correctly sandbox templates based on what capabilities they have been given. - -Examples of executors include the ``@antiraid/actions`` `ActionExecutor`, which allows you to perform actions such as banning/kicking/timing out users and other Discord actions and ``@antiraid/kv`` `KvExecutor` which allow for persistent storage via a key-value interface. - -``TemplateContext`` is guaranteed to be valid while accessible in the VM . This means that templates can choose to share their capabilities with other templates using the ``__stack``. - -It is also guaranteed that the created executor is complete and does not rely on the token itself whatsoever after creation. This means that a template executor can be used after the template has finished executing (e.g. in a coroutine). - -### Example - -```lua -local args, token = ... -print(token) -``` \ No newline at end of file +You can use the ``/load`` command to load templates from the shop. \ No newline at end of file diff --git a/docs/src/user/templating/2-plugins.md b/docs/src/user/templating/2-plugins.md deleted file mode 100644 index ef57da1f..00000000 --- a/docs/src/user/templating/2-plugins.md +++ /dev/null @@ -1,4 +0,0 @@ -No/unknown command specified! - -start: [start the template worker itself] -templatedocs: [generate template docs] diff --git a/infra/templating-template b/infra/templating-template index 948e56b6..068b1294 160000 --- a/infra/templating-template +++ b/infra/templating-template @@ -1 +1 @@ -Subproject commit 948e56b63275e4a55ed754ffcb6ff324ead6a28b +Subproject commit 068b129428e5fb9c4fa05dda48b5c8e98d3f90c0 diff --git a/infra/templating-types b/infra/templating-types index ce592ce7..163c9c8b 160000 --- a/infra/templating-types +++ b/infra/templating-types @@ -1 +1 @@ -Subproject commit ce592ce7ee779ae38a0aac7c0806dd544370f5a4 +Subproject commit 163c9c8be5e1b4f928cfdc40d7543bb40ff9399e diff --git a/services/api b/services/api index 1757c10a..97874692 160000 --- a/services/api +++ b/services/api @@ -1 +1 @@ -Subproject commit 1757c10a27ca2d9d957f3522cced5c6b68f78e21 +Subproject commit 97874692e80161ff817ab6fe7825507d4202e188 diff --git a/services/bot b/services/bot index 3c28b062..c3cb6095 160000 --- a/services/bot +++ b/services/bot @@ -1 +1 @@ -Subproject commit 3c28b062b8b14256ba96dfc53df51c1359ff58b2 +Subproject commit c3cb6095105b848f36544454f2bdb210e59dfb94 diff --git a/services/template-worker b/services/template-worker index 71c2cff0..9ce37a03 160000 --- a/services/template-worker +++ b/services/template-worker @@ -1 +1 @@ -Subproject commit 71c2cff0fc53aa75b7893b6aee58e4e3473da586 +Subproject commit 9ce37a03ded0e54db3042b7f5683ce0259315f4c diff --git a/services/website b/services/website index 91b08aef..9dfb4640 160000 --- a/services/website +++ b/services/website @@ -1 +1 @@ -Subproject commit 91b08aef7c4eba1d7f8506a80d1dc07243d31009 +Subproject commit 9dfb46403abc3f23f3620357a846f41c4776d656