文件

Lua 5.5 · API v0.1

總覽

腳本是擴充您伺服器的小型 Lua 程式。它們在與機器人完全隔離的 Lua 5.5 沙盒程序中執行。腳本絕不會接觸資料庫、檔案系統或其他伺服器。所有功能都必須經過白名單內的主機 API,並透過 IPC 交還給機器人處理。

每個腳本一個沙盒

沒有載入腳本,就不會有程序存在。

主機呼叫有速率限制

bot:* 與 msg:* 的呼叫由機器人檢查權限,而非由 Lua 檢查。

原生功能優先

自動管理、歡迎訊息與客服單一律照常運作。腳本只是加強,並非取代。

錯誤不會擴散

當機的腳本會被卸載或隔離,機器人仍會持續運作。

沒有瀏覽器內的編輯器。請在真正的編輯器中撰寫 .lua,再於伺服器的「腳本」頁面上傳。

快速開始

  1. 1

    在本機撰寫 .lua 檔案

    使用 VS Code、Neovim 或任何編輯器。
  2. 2

    在本機檢查(選用)

    script_runner --check file.lua 會輸出 check: ok。
  3. 3

    上傳

    開啟伺服器的「腳本」頁面,貼上程式碼或上傳 .lua 檔案(最大 64 KiB)。
  4. 4

    試執行

    在不執行任何內容的情況下,驗證大小、編碼、位元組碼與禁用 API。
  5. 5

    啟用

    等待管理團隊核准該版本,然後按下「啟用」。機器人會在數秒內載入。
  6. 6

    設定記錄頻道

    在該頻道接收 bot:log 輸出與錯誤通知。

本機 CLI

執行器與機器人使用的是同一個執行檔。

  • script_runner --check file.lua

    不執行的靜態語法/禁用 API 檢查。輸出 'check: ok'。

  • script_runner --eval 'code'

    在本機沙盒中執行一段程式碼。錯誤會輸出類型與訊息。

  • script_runner --self-test

    執行沙盒、通訊協定與 socket 的自我測試。

生命週期與審核

腳本有版本管理。版本在您提交時即被凍結,並以其 SHA-256 識別。只有已核准的版本可以啟用,而機器人只會載入已啟用的版本。

  1. 1

    撰寫

    在本機使用 VS Code、Neovim 或任何編輯器建立 .lua 檔案。設計上不提供瀏覽器內的編輯器。
  2. 2

    試執行/上傳

    在伺服器「腳本」頁面貼上程式碼或上傳 .lua 檔案(≤ 64 KiB,不得為二進位)。試執行會在不執行任何內容的情況下驗證大小、編碼、位元組碼與禁用 API。
  3. 3

    審核

    每個新腳本與每個新版本都從待處理開始。管理團隊會在程式碼能夠執行之前,核准或拒絕該確切的程式碼修訂。
  4. 4

    啟用

    您啟用已核准的版本。待處理或已拒絕的版本無法啟用。機器人只會載入已啟用的版本。
  5. 5

    執行

    機器人會將版本(程式碼 + SHA-256,由執行器驗證)載入隔離的 Lua 5.5 沙盒。事件只會分發給以 bot:on 註冊的處理常式。
  6. 6

    更新/還原

    上傳新版本(再次進入待處理),或啟用較舊的已核准版本以還原。KV 儲存內容會保留。
  7. 7

    停用/刪除

    停用會立即停止載入,「全部停用」會影響該伺服器所有啟用中的腳本。刪除會移除腳本、其版本、KV 與錯誤。

腳本狀態

會以徽章顯示在每個腳本上。

  • 草稿

    已建立,但尚無啟用的版本。

  • 待處理

    等待某些事項(例如首次核准),不會以草稿狀態執行。

  • 啟用中

    已核准的版本已啟用並由機器人載入。

  • 已拒絕

    管理團隊已拒絕;腳本不會載入。

  • 已停用

    被手動停用(由您、管理團隊、「全部停用」或配額移除)— 已卸載。

  • 已隔離

    因濫用限制(速率暴增、佇列暴增、重複錯誤)而自動關閉。已卸載,需要管理團隊處理。

版本審核

每一次程式碼修訂都必須經過管理團隊審核。

  • 待處理

    管理團隊尚未決定,無法啟用。

  • 已核准

    可以啟用。已安裝之商店腳本的新上傳會略過佇列(商店項目的版本已核准過)。

  • 已拒絕

    管理團隊拒絕了此程式碼修訂。請改為上傳新版本。

配額:每個伺服器免費版可有 2 個啟用中的腳本,進階版為 10 個。若配額縮減,超出部分中最早啟用的腳本會自動停用,並透過腳本記錄頻道通知您。

處理常式與事件

使用 bot:on(event, fn) 註冊處理常式。腳本在載入時會回報其註冊的事件,且只有這些事件會傳送給它。未知的事件名稱會導致載入失敗,且每個腳本對每個事件最多可註冊 8 個處理常式。

luaLua
bot:on("message_create", function(msg)
  if msg.content == "!ping" then
    msg:reply("pong")
  end
end)

類訊息事件(message_*、automod_check)會傳遞帶有方法的訊息物件,請參閱訊息物件。

主機呼叫會讓出執行權:當處理常式等待 bot:kv_get 等呼叫時,同一個腳本不會同時執行第二個事件。新事件會在容量為 32 的佇列中等待,溢出時會丟棄最舊的事件,持續的大量湧入則會讓腳本被隔離。

guild_id 一律會被注入事件內容中。事件只會傳送給以 bot:on 註冊的處理常式。未知的事件名稱會導致載入失敗並出現政策錯誤。沒有 voice_state 事件。

事件內容

每個事件內容都帶有 guild_id。欄位為小寫 snake_case 的資料表。

  • message_create

    id, guild_id, channel_id, author_id, author, content, attachments, referenced_id

    在標籤/自動回覆之前觸發。附件:最多 8 筆項目 { id, filename, size }。沒有回覆參照時,referenced_id 為 0。

  • message_update

    same as message_create

  • message_delete

    channel_id, id

  • message_delete_bulk

    channel_id, ids

    ids 是已刪除訊息 ID 的陣列。

  • guild_member_add

    user_id

    機器人帳號會被略過。

  • guild_member_remove

    user_id

  • guild_member_update

    user_id

  • reaction_add

    channel_id, id, author_id, user_id, emoji, emoji_id

    機器人的反應會被略過。emoji 為名稱,Unicode 表情符號的 emoji_id 為 0。

  • reaction_remove

    channel_id, id, author_id, user_id, emoji, emoji_id

  • channel_create

    id, name, type

  • channel_update

    id, name, type

  • channel_delete

    id, name

  • role_create

    id, name

  • role_update

    id, name

  • role_delete

    id, name

  • thread_create

    id, name

  • thread_update

    id, name

  • thread_delete

    id

  • invite_create

    code, uses

  • invite_delete

    code

  • guild_ban_add

    user_id

  • guild_ban_remove

    user_id

  • welcome_before

    user_id, username

    在原生歡迎訊息之前觸發。僅限非機器人的加入。

  • goodbye_before

    user_id

    在原生告別訊息之前觸發。

  • ticket_created

    ticket_id, user_id, channel_id

  • automod_check

    content, channel_id, author_id, id

    在原生自動管理之前觸發。msg:escalate() 會刪除處理中的訊息;原生拒絕一律優先;msg:allow() 不會有任何作用。

  • webhooks_update

    channel_id

  • emoji_update

    count, ids

    ids 上限為 8。

  • tick

    unix

    每 60 秒一次,只會傳送給註冊了 bot:on("tick") 的腳本。unix 為 Unix 時間。

主機 API

這些呼叫會透過 IPC 讓出執行權給機器人。每個腳本的速率限制:每 10 秒 30 次主機呼叫,以及每 10 秒 5 次 Discord 傳送(reply、channel_send、react、edit、delete、pin、escalate、http_get)。member_get 與 guild_get 等快取讀取不會直接存取 Discord。

  • bot:log(msg)

    寫入腳本記錄頻道與錯誤記錄。計入每 10 秒 30 次呼叫的限制。

  • bot:kv_get(key)

    回傳儲存的 JSON 值或 nil。鍵:1–64 個字元 [A-Za-z0-9_-]。

  • bot:kv_set(key, value)

    儲存最多 8 KiB 的 JSON。每個腳本 256 個鍵、每個腳本 1 MiB(進階版 8 MiB)、每個伺服器 8 MiB。

  • bot:kv_del(key)

    刪除一個鍵。

  • bot:kv_keys()

    回傳最多 256 個已排序的鍵。

  • bot:kv_incr(key, delta?)

    遞增已儲存的 JSON 數字,預設增量為 1,增量限制在 ±1,000,000,000。

  • bot:db_exec(sql, binds?)

    對伺服器腳本資料庫執行一條寫入或結構語句(CREATE TABLE/INDEX、INSERT、UPDATE、DELETE、DROP)。選用的綁定參數:由 nil、boolean、number 或 string 組成的陣列,最多 8 個。回傳 { changes, last_insert_rowid }。配額、忙碌或限制問題會回傳 { error, kind } 而不是拋出錯誤;被禁止的語句則會拋出政策錯誤。

  • bot:db_query(sql, binds?)

    執行一條 SELECT(可帶綁定參數),最多回傳 50 列,每列都是以欄位名稱為鍵的資料表。請務必使用 LIMIT。失敗時會回傳 { error, kind },因此請檢查 rows.error。

  • bot:http_get(url)

    僅限 HTTPS GET。主機必須位於伺服器允許清單中。回傳 { status, body, truncated };body 上限為 16 KiB。等待時間不計入 100 ms 的 Lua 實際時間限制。

  • bot:channel_send(channel_id, text, embed?)

    傳送到本伺服器中機器人可寫入的任何頻道。內容規則與 msg:reply 相同。

  • bot:channel_get(channel_id)

    快取讀取:{ id, name, type, parent_id }。僅限本伺服器。

  • bot:member_get(user_id)

    快取讀取:{ id, nick, bot, roles(最多 20 個)}。

  • bot:role_get(role_id)

    快取讀取:{ id, name, position, color }。

  • bot:guild_get()

    本伺服器快取:{ id, name, owner_id, member_count }。

  • bot:self()

    機器人使用者:{ id, username, bot }。

  • bot:has_role(user_id, role_id)

    快取讀取,回傳 { has: true|false }。

  • bot:channels()

    伺服器頻道的快取清單(最多 50 個)。

  • bot:roles()

    伺服器身分組的快取清單(最多 50 個)。

  • bot:now()

    以秒為單位的 Unix 時間。

  • bot:id()

    此腳本的 UUID。不會讓出執行權,也不計入速率限制。

  • bot:message_get(channel_id, message_id)

    從機器人訊息快取讀取(不會透過網路擷取)。

  • bot:can_send(channel_id)

    回傳 { ok: true|false },表示機器人是否可以在該頻道傳送訊息。

bot:http_get 接受的內容

  • 僅限 HTTPS

    http:// 網址會被拒絕。不得包含使用者資訊(user:pass@host)。

  • 伺服器允許清單

    主機必須位於該伺服器的 HTTP 允許清單中(「腳本」頁面,最多 32 個主機),由您自行管理。

  • 不允許基礎設施主機

    IP 字面值、localhost、*.local 與 *.internal 一律會被拒絕。

  • 回應

    { status, body, truncated },body 上限 16 KiB。逾時 3 秒。與每 10 秒 5 次的 Discord 配額共用。

訊息物件

訊息事件會傳遞 msg 資料表以及事件內容欄位。這些方法只作用於處理中的事件訊息,您無法擷取並編輯任意訊息。

各處通用的內容規則:文字 1 至 2000 位元組,最多一個嵌入訊息 { title, description, color },提及只會對事件作者解析,@everyone 與 @here 會被移除。不允許檔案與貼圖。

  • msg:reply(text, embed?)

    在事件所在頻道回覆。提及只會對事件作者解析;@everyone / @here 會被移除。文字 1–2000 位元組,最多一個嵌入訊息。

  • msg:react(emoji)

    在事件訊息上新增反應。

  • msg:unreact(emoji)

    移除腳本自己的反應。

  • msg:edit(text, embed?)

    編輯處理中的訊息。內容規則與回覆相同。

  • msg:delete()

    刪除處理中的訊息。

  • msg:pin() / msg:unpin()

    釘選/取消釘選處理中的訊息。

  • msg:escalate()

    僅限 automod_check:刪除處理中的訊息(額外動作,有速率限制)。原生自動管理的判定一律優先。

  • msg:allow()

    僅限 automod_check:將訊息標記為允許。這無法推翻原生的拒絕,實際上只是一個沒有作用的標記。

限制與配額

所有限制都放在機器人與執行器共用的單一設定檔中,並在執行時強制套用,不只是在這裡列出。這些數字是目前的預設值。

  • 語言

    Lua 5.5,僅限文字區塊(位元組碼會被拒絕)。不提供 io/os.file/require/load/debug/coroutine。

  • 運算

    每個處理常式約 100 ms 實際時間,10,000,000 個指令(計數掛鉤)。

  • 記憶體

    每個腳本免費版 2 MB,進階版 8 MB。

  • 程式碼大小

    64 KiB UTF-8 .lua,不得含 NUL 位元組,不得為位元組碼。

  • 主機呼叫

    每個腳本每 10 秒 30 次(含 bot:log)。

  • Discord 傳送

    每個腳本每 10 秒 5 次(reply、channel_send、react/unreact、edit、delete、pin/unpin、escalate、http_get)。10 秒內被拒絕 8 次 → 隔離。

  • 處理常式

    每個腳本每個事件最多 8 個。未知的事件名稱會在載入時被拒絕。

  • 事件佇列

    每個腳本深度 32,溢出時丟棄最舊的。10 秒內丟棄 8 次以上 → 隔離。

  • HTTP

    HTTPS + 伺服器允許清單,逾時 3 秒,body 16 KiB,不允許 IP/localhost/內部主機,不允許使用者資訊。

  • KV

    鍵 1–64 個字元 [A-Za-z0-9_-],值 ≤ 8 KiB JSON,每個腳本 256 個鍵,每個腳本 1 MiB(進階版 8 MiB),每個伺服器 8 MiB。

  • 資料庫

    每個伺服器一個 SQLite 檔案,由該伺服器所有腳本共用:1 MiB(進階版 8 MiB),每次呼叫一條語句,SQL ≤ 2 KiB,≤ 8 個綁定參數,≤ 50 列,每條語句 20 ms,64 個資料表與索引。不支援 ATTACH、PRAGMA、交易、觸發器、檢視表或 WITH。伺服器上的每個腳本都能讀取並刪除所有資料表。

  • 啟用中的腳本

    每個伺服器免費版 2 個,進階版 10 個。超出部分中最早啟用的腳本會自動停用。

  • 版本

    每個腳本的版本數量不限;每個新版本在管理團隊核准前都處於待審核狀態。

  • 提及

    僅限事件作者。@everyone / @here 會被移除。不允許檔案與貼圖。

  • 隔離

    3 次錯誤(逾時/記憶體/政策/執行時)→ 專屬的隔離工作程序(最多 4 個),否則隔離並卸載。

  • 錯誤記錄

    控制台可查看最近 24 小時,項目於 7 天後清除。

  • 禁止項目

    不得使用 voice_state、mod_* API(封鎖/踢出/逾時),不得跨伺服器存取,不得存取資料庫/檔案系統,不得營利。

  • 自動管理

    原生自動管理優先執行,且一律優先於腳本。

驗證

在儲存版本之前,後端會執行靜態檢查。試執行會做同樣的檢查但不儲存。沙盒本身則是第二道防線:被禁止的全域變數在執行時根本不存在。

  • 大小/編碼

    不得為空,≤ 64 KiB,UTF-8 且不含 NUL 位元組。

  • 位元組碼

    任何以 Lua 位元組碼簽章開頭的內容都會被拒絕。

  • 禁用 API

    靜態掃描會拒絕:load(、loadfile、dofile、require(、os.execute、io.open、debug.、string.dump、loadstring、getfenv、setfenv、package.、coroutine.、ffi.、jit.

  • 執行時沙盒

    即使有內容通過了靜態掃描,沙盒也根本不會提供這些全域變數 — 呼叫會因政策錯誤而失敗。

可用的內建項目:不含檔案存取的標準 Lua 函式庫。string、table、math、tostring、tonumber、type、pairs、ipairs、os.time、os.clock、os.difftime 與 bot。

錯誤與隔離

每個處理常式錯誤都會連同類型一起記錄,並顯示在腳本詳細頁面(最近 24 小時)。項目會在 7 天後清除。

  • runtime

    處理常式中的 Lua 錯誤(存取 nil、引數錯誤等)。訊息包含 Lua 錯誤文字。

  • timeout

    處理常式超過 100 ms 的實際時間限制,或 IPC 呼叫逾時(1 秒)。

  • memory

    腳本超過其記憶體上限。

  • policy

    腳本嘗試了不被允許的操作:未知事件、處理常式過多、使用被禁止的 API、內容過大。

重複濫用會自動升級處理:3 次錯誤(逾時、記憶體、政策、執行時)會讓腳本移至專屬的隔離工作程序。若持續不當行為,或沒有可用的隔離位置(最多 4 個),腳本就會被隔離:卸載並在控制台中標示。速率暴增(10 秒內有 8 次被拒絕的 Discord 傳送,或 8 次佇列丟棄)會立即隔離。系統會透過腳本記錄頻道或私訊通知您。

營運端:機器人可透過緊急開關在不重新啟動的情況下全域暫停,並且 scripts:updated 訊號會在數秒內重新載入變更的版本。兩者皆為管理團隊的操作。

商店

商店讓您能公開分享腳本,並安裝其他伺服器的腳本。發佈與安裝都會建立副本。安裝商店項目會在您的伺服器中建立一個獨立的腳本,不會與作者的程式碼保持連結。

  • 發佈

    需要一個含有已核准版本的啟用中腳本、一段說明(10–512 個字元)以及 1–8 個標籤([a-z0-9-],1–24 個字元)。首次發佈前必須先接受一次商店服務條款。

  • 安裝

    安裝會將商店項目複製到您的伺服器成為獨立腳本(草稿、已預先核准的版本,若名稱已被使用則加上後綴)。不會複製 KV。商店項目上的安裝計數會增加。

  • 取消發佈

    將項目從商店移除。既有的副本會保留並繼續執行,只是不會再收到更新。

  • 禁止營利

    在說明或程式碼中出現銷售、付費牆、捐款/加密貨幣連結及類似的營利行為,會在發佈時被拒絕,且可能導致腳本被禁用。

  • 檢舉

    任何擁有伺服器存取權限的人都可以附上原因檢舉商店項目。管理團隊會看到待處理的檢舉佇列,並在審核後關閉檢舉。

  • 限制

    商店清單每次查詢最多顯示 50 個項目(搜尋、標籤、依安裝數或最新排序)。安裝時適用一般的伺服器腳本配額。

範例

選擇範例以查看其程式碼。