Ringkasan
Skrip adalah program Lua kecil yang memperluas server Anda. Skrip berjalan dalam proses sandbox Lua 5.5 yang terisolasi, sepenuhnya terpisah dari bot. Skrip tidak pernah menyentuh database, sistem file, atau server lain. Setiap kemampuan melewati API host yang masuk whitelist dan menyerahkan kendali kembali ke bot lewat IPC.
Tidak ada skrip yang dimuat, tidak ada proses yang ada.
Panggilan bot:* dan msg:* diperiksa kapabilitasnya oleh bot, bukan oleh Lua.
AutoMod, sambutan, dan tiket selalu berjalan. Skrip menghias, tidak menggantikan.
Skrip yang crash akan dibongkar atau dikarantina, bot tetap berjalan.
Tidak ada editor di browser. Tulis .lua di editor sungguhan dan unggah di halaman Skrip server Anda.
Memulai
- 1
Tulis file .lua secara lokal
VS Code, Neovim, atau editor apa pun. - 2
Periksa secara lokal (opsional)
script_runner --check file.luamencetakcheck: ok. - 3
Unggah
Buka halaman Skrip server Anda lalu tempel kode atau unggah file .lua (hingga 64 KiB). - 4
Dry-run
Memvalidasi ukuran, encoding, bytecode, dan API terlarang tanpa menjalankan apa pun. - 5
Aktifkan
Tunggu persetujuan staf untuk versi tersebut, lalu tekan Aktifkan. Bot memuatnya dalam hitungan detik. - 6
Atur channel log
Terima keluaranbot:logdan notifikasi error di sana.
CLI lokal
Runner adalah biner yang sama dengan yang digunakan bot.
- script_runner --check file.lua
Pemeriksaan statis sintaks/API terlarang tanpa menjalankan. Mencetak 'check: ok'.
- script_runner --eval 'code'
Jalankan potongan kode di sandbox secara lokal. Error mencetak jenis + pesan.
- script_runner --self-test
Menjalankan self-test sandbox, protokol, dan socket.
Siklus hidup & peninjauan
Skrip memiliki versi. Sebuah versi dibekukan saat Anda mengirimkannya dan diidentifikasi dengan SHA-256-nya. Hanya versi yang disetujui yang dapat diaktifkan, dan hanya versi aktif yang dimuat oleh bot.
- 1
Tulis
Buat file .lua secara lokal di VS Code, Neovim, atau editor apa pun. Memang tidak ada editor di browser. - 2
Dry-run / unggah
Tempel kode atau unggah file .lua di halaman Skrip server (≤ 64 KiB, bukan biner). Dry-run memvalidasi ukuran, encoding, bytecode, dan API terlarang tanpa menjalankan apa pun. - 3
Tinjau
Setiap skrip baru dan setiap versi baru dimulai sebagai tertunda. Staf menyetujui atau menolak revisi kode yang tepat sebelum dapat berjalan. - 4
Aktifkan
Anda mengaktifkan versi yang disetujui. Aktivasi versi tertunda atau ditolak ditolak oleh sistem. Hanya versi aktif yang dimuat oleh bot. - 5
Jalankan
Bot memuat versi (kode + SHA-256, diverifikasi oleh runner) ke sandbox Lua 5.5 yang terisolasi. Event hanya diteruskan ke handler yang didaftarkan dengan bot:on. - 6
Perbarui / rollback
Unggah versi baru (kembali tertunda) atau aktifkan versi lama yang disetujui untuk rollback. Penyimpanan KV tetap ada. - 7
Nonaktifkan / hapus
Nonaktifkan langsung menghentikan pemuatan, 'Nonaktifkan semua' berlaku untuk setiap skrip aktif di server. Hapus menghilangkan skrip, versinya, KV, dan error.
Status skrip
Ditampilkan sebagai lencana pada setiap skrip.
- draf
Sudah dibuat, belum ada versi aktif.
- tertunda
Menunggu sesuatu (mis. persetujuan pertama) — tidak pernah berjalan sebagai draf.
- aktif
Versi yang disetujui sudah diaktifkan dan dimuat oleh bot.
- ditolak
Ditolak staf; skrip tidak akan dimuat.
- nonaktif
Dinonaktifkan secara manual (oleh Anda, staf, 'Nonaktifkan semua', atau pencabutan kuota) — dibongkar.
- dikarantina
Dimatikan otomatis setelah penyalahgunaan batas (banjir laju, banjir antrean, kesalahan berulang). Dibongkar dan memerlukan perhatian staf.
Peninjauan versi
Setiap revisi kode melewati peninjauan staf.
- tertunda
Staf belum memutuskan. Tidak dapat diaktifkan.
- disetujui
Boleh diaktifkan. Unggahan baru dari skrip toko yang terpasang melewati antrean (versi listing sudah disetujui).
- ditolak
Staf menolak revisi kode ini. Unggah versi baru sebagai gantinya.
Kuota: 2 skrip aktif per server gratis, 10 dengan premium. Jika kuota menyusut, skrip aktif tertua di atas kuota dinonaktifkan otomatis dan Anda diberi tahu lewat channel log skrip.
Handler & event
Daftarkan handler dengan bot:on(event, fn). Skrip melaporkan event yang didaftarkannya saat dimuat, dan hanya event itu yang dikirim ke skrip. Nama event yang tidak dikenal membuat pemuatan gagal, dan satu skrip dapat mendaftarkan maksimal 8 handler per event.
bot:on("message_create", function(msg)
if msg.content == "!ping" then
msg:reply("pong")
end
end)Event bertipe pesan (message_*, automod_check) meneruskan objek pesan dengan metode, lihat Objek pesan.
Panggilan host menyerahkan kendali: saat handler menunggu bot:kv_get dan panggilan serupa, tidak ada event kedua yang berjalan di skrip yang sama. Event baru menunggu dalam antrean 32, kelebihan membuang event tertua, dan banjir terus-menerus mengarantina skrip.
guild_id selalu disisipkan ke payload. Event hanya dikirim ke handler yang didaftarkan dengan bot:on. Nama event yang tidak dikenal membuat pemuatan gagal dengan error kebijakan. Tidak ada event voice_state.
Payload event
Setiap payload membawa guild_id. Kolom berupa tabel snake_case huruf kecil.
- message_create
id, guild_id, channel_id, author_id, author, content, attachments, referenced_id
Terpicu sebelum tag/ autoresponder. Lampiran: hingga 8 entri { id, filename, size }. referenced_id bernilai 0 jika tidak ada referensi balasan.
- message_update
same as message_create
- message_delete
channel_id, id
- message_delete_bulk
channel_id, ids
ids adalah array id pesan yang dihapus.
- guild_member_add
user_id
Akun bot dilewati.
- guild_member_remove
user_id
- guild_member_update
user_id
- reaction_add
channel_id, id, author_id, user_id, emoji, emoji_id
Reaksi bot dilewati. emoji adalah nama, emoji_id bernilai 0 untuk emoji unicode.
- 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
Terpicu sebelum pesan sambutan bawaan. Hanya untuk yang bukan bot.
- goodbye_before
user_id
Terpicu sebelum pesan perpisahan bawaan.
- ticket_created
ticket_id, user_id, channel_id
- automod_check
content, channel_id, author_id, id
Terpicu sebelum AutoMod bawaan. msg:escalate() menghapus pesan yang sedang diproses; penolakan bawaan selalu menang; msg:allow() tidak melakukan apa-apa.
- webhooks_update
channel_id
- emoji_update
count, ids
ids dibatasi 8.
- tick
unix
Setiap 60 detik, hanya dikirim ke skrip yang mendaftarkan bot:on("tick"). unix adalah waktu unix.
API host
Panggilan ini menyerahkan kendali ke bot lewat IPC. Batas laju per skrip: 30 panggilan host / 10 dtk, ditambah 5 pengiriman Discord / 10 dtk (reply, channel_send, react, edit, delete, pin, escalate, http_get). Pembacaan cache seperti member_get dan guild_get tidak pernah langsung mengakses Discord.
- bot:log(msg)
Menulis ke channel log skrip dan log error. Dihitung dalam batas 30 panggilan / 10 dtk.
- bot:kv_get(key)
Mengembalikan nilai JSON yang tersimpan atau nil. Kunci: 1–64 karakter [A-Za-z0-9_-].
- bot:kv_set(key, value)
Menyimpan hingga 8 KiB JSON. 256 kunci per skrip, 1 MiB per skrip (8 MiB premium), 8 MiB per server.
- bot:kv_del(key)
Menghapus satu kunci.
- bot:kv_keys()
Mengembalikan hingga 256 kunci, terurut.
- bot:kv_incr(key, delta?)
Menambah angka JSON yang tersimpan, delta default 1, delta dibatasi ±1.000.000.000.
- bot:db_exec(sql, binds?)
Menjalankan satu pernyataan tulis atau skema (CREATE TABLE/INDEX, INSERT, UPDATE, DELETE, DROP) pada database skrip server. Bind opsional: array berisi nil, boolean, number, atau string, hingga 8. Mengembalikan { changes, last_insert_rowid }. Masalah kuota, sibuk, atau batas mengembalikan { error, kind } alih-alih melempar error; pernyataan terlarang melempar error kebijakan.
- bot:db_query(sql, binds?)
Menjalankan satu SELECT dengan bind opsional dan mengembalikan hingga 50 baris, masing-masing berupa tabel berkunci nama kolom. Selalu gunakan LIMIT. Jika gagal, mengembalikan { error, kind }, jadi periksa rows.error.
- bot:http_get(url)
Hanya GET HTTPS. Host harus ada di allowlist server. Mengembalikan { status, body, truncated }; body dibatasi 16 KiB. Waktu tunggu tidak dihitung dalam 100 ms Lua wall clock.
- bot:channel_send(channel_id, text, embed?)
Kirim ke channel mana pun di server sendiri yang dapat ditulisi bot. Aturan konten sama dengan msg:reply.
- bot:channel_get(channel_id)
Baca cache: { id, name, type, parent_id }. Hanya server sendiri.
- bot:member_get(user_id)
Baca cache: { id, nick, bot, roles (hingga 20) }.
- bot:role_get(role_id)
Baca cache: { id, name, position, color }.
- bot:guild_get()
Cache server sendiri: { id, name, owner_id, member_count }.
- bot:self()
Pengguna bot: { id, username, bot }.
- bot:has_role(user_id, role_id)
Baca cache, mengembalikan { has: true|false }.
- bot:channels()
Daftar cache channel server (maks. 50).
- bot:roles()
Daftar cache role server (maks. 50).
- bot:now()
Waktu unix dalam detik.
- bot:id()
UUID skrip ini. Tidak menyerahkan kendali, tidak dihitung dalam batas laju.
- bot:message_get(channel_id, message_id)
Baca cache pesan bot (tanpa pengambilan lewat jaringan).
- bot:can_send(channel_id)
Mengembalikan { ok: true|false } apakah bot boleh mengirim di channel itu.
Yang diterima bot:http_get
- Hanya HTTPS
URL http:// ditolak. Tanpa userinfo (user:pass@host).
- Allowlist server
Host harus ada di allowlist HTTP server (halaman Skrip, hingga 32 host). Anda mengelolanya sendiri.
- Tanpa host infrastruktur
Literal IP, localhost, *.local, dan *.internal selalu ditolak.
- Respons
{ status, body, truncated }, body dibatasi 16 KiB. Timeout 3 dtk. Berbagi bucket Discord 5 per 10 dtk.
Objek pesan
Event pesan meneruskan tabel msg beserta kolom payload. Metode hanya bekerja pada pesan event yang sedang diproses, Anda tidak dapat mengambil dan mengedit pesan sembarang.
Aturan konten di mana pun: teks 1 hingga 2000 byte, paling banyak satu embed { title, description, color }, mention hanya diselesaikan untuk penulis event, @everyone dan @here dihapus. Tanpa file, tanpa stiker.
- msg:reply(text, embed?)
Membalas di channel event. Mention hanya diselesaikan untuk penulis event; @everyone / @here dihapus. Teks 1–2000 byte, maks. satu embed.
- msg:react(emoji)
Menambahkan reaksi pada pesan event.
- msg:unreact(emoji)
Menghapus reaksi milik skrip sendiri.
- msg:edit(text, embed?)
Mengedit pesan yang sedang diproses. Aturan konten sama dengan reply.
- msg:delete()
Menghapus pesan yang sedang diproses.
- msg:pin() / msg:unpin()
Pin/unpin pesan yang sedang diproses.
- msg:escalate()
Hanya automod_check: menghapus pesan yang sedang diproses (aksi tambahan, dibatasi laju). Keputusan AutoMod bawaan selalu menang.
- msg:allow()
Hanya automod_check: menandai pesan sebagai diizinkan. Ini tidak dapat membatalkan penolakan bawaan — pada dasarnya hanya penanda tanpa efek.
Batas & kuota
Semua batas berada dalam satu file konfigurasi yang digunakan bersama oleh bot dan runner. Batas ini ditegakkan saat runtime, bukan hanya didokumentasikan di sini. Angkanya adalah default saat ini.
- Bahasa
Lua 5.5, hanya chunk teks (bytecode ditolak). Tanpa io/os.file/require/load/debug/coroutine.
- Komputasi
~100 ms wall clock per handler, 10.000.000 instruksi (count hook).
- Memori
2 MB per skrip gratis, 8 MB premium.
- Ukuran kode
64 KiB .lua UTF-8, tanpa byte NUL, tanpa bytecode.
- Panggilan host
30 per 10 dtk per skrip (termasuk bot:log).
- Pengiriman Discord
5 per 10 dtk per skrip (reply, channel_send, react/unreact, edit, delete, pin/unpin, escalate, http_get). 8 penolakan dalam 10 dtk → karantina.
- Handler
Maks. 8 per event per skrip. Nama event yang tidak dikenal ditolak saat pemuatan.
- Antrean event
Kedalaman 32 per skrip, buang yang tertua saat kelebihan. 8+ pembuangan dalam 10 dtk → karantina.
- HTTP
HTTPS + allowlist server, timeout 3 dtk, body 16 KiB, tanpa host IP/localhost/internal, tanpa userinfo.
- KV
Kunci 1–64 [A-Za-z0-9_-], nilai ≤ 8 KiB JSON, 256 kunci/skrip, 1 MiB/skrip (8 MiB premium), 8 MiB/server.
- Database
Satu file SQLite per server, dibagi oleh semua skripnya: 1 MiB (8 MiB premium), satu pernyataan per panggilan, SQL ≤ 2 KiB, ≤ 8 bind, ≤ 50 baris, 20 ms per pernyataan, 64 tabel dan indeks. Tanpa ATTACH, PRAGMA, transaksi, trigger, view, atau WITH. Setiap skrip di server dapat membaca dan menghapus setiap tabel.
- Skrip aktif
2 per server gratis, 10 premium. Kelebihan skrip aktif tertua dinonaktifkan otomatis.
- Versi
Jumlah per skrip tidak dibatasi; setiap versi baru menunggu hingga staf menyetujuinya.
- Mention
Hanya penulis event. @everyone / @here dihapus. Tanpa file, tanpa stiker.
- Isolasi
3 kesalahan (timeout/memori/kebijakan/runtime) → worker terisolasi sendiri (maks. 4), jika tidak karantina + bongkar.
- Log error
24 jam terakhir terlihat di dasbor, entri dihapus setelah 7 hari.
- Terlarang
Tanpa voice_state, tanpa API mod_* (ban/kick/timeout), tanpa akses lintas server, tanpa database/sistem file, tanpa monetisasi.
- AutoMod
AutoMod bawaan berjalan lebih dulu dan selalu menang atas skrip.
Validasi
Sebelum sebuah versi disimpan, backend menjalankan pemeriksaan statis. Dry-run melakukan hal yang sama tanpa menyimpan. Sandbox itu sendiri adalah lapisan kedua: global terlarang memang tidak ada saat runtime.
- Ukuran / encoding
Tidak kosong, ≤ 64 KiB, UTF-8 tanpa byte NUL.
- Bytecode
Apa pun yang diawali tanda tangan bytecode Lua ditolak.
- API terlarang
Pemindaian statis menolak: load(, loadfile, dofile, require(, os.execute, io.open, debug., string.dump, loadstring, getfenv, setfenv, package., coroutine., ffi., jit.
- Sandbox runtime
Bahkan jika ada yang lolos dari pemindaian statis, sandbox memang tidak menyediakan global ini — panggilan gagal dengan error kebijakan.
Fungsi bawaan yang tersedia: pustaka standar Lua tanpa akses file. string, table, math, tostring, tonumber, type, pairs, ipairs, os.time, os.clock, os.difftime, dan bot.
Error & karantina
Setiap error handler dicatat dengan jenisnya dan ditampilkan di halaman detail skrip (24 jam terakhir). Entri dihapus setelah 7 hari.
- runtime
Error Lua di handler Anda (akses nil, argumen salah, …). Pesannya menyertakan teks error Lua.
- timeout
Handler melebihi 100 ms wall clock atau panggilan IPC habis waktu (1 dtk).
- memory
Skrip melebihi batas memorinya.
- policy
Skrip mencoba sesuatu yang tidak diizinkan: event tidak dikenal, terlalu banyak handler, API yang tidak diizinkan, payload terlalu besar.
Penyalahgunaan berulang meningkat otomatis: 3 kesalahan (timeout, memori, kebijakan, runtime) memindahkan skrip ke worker terisolasi miliknya sendiri. Jika perilaku buruk berlanjut, atau tidak ada slot terisolasi yang kosong (maks. 4), skrip dikarantina: dibongkar dan ditandai di dasbor. Banjir laju (8 pengiriman Discord ditolak atau 8 pembuangan antrean dalam 10 dtk) langsung dikarantina. Anda diberi tahu lewat channel log skrip atau DM.
Sisi operasional: bot dapat dijeda secara global lewat kill switch tanpa restart, dan sinyal scripts:updated memuat ulang versi yang berubah dalam hitungan detik. Keduanya adalah tindakan staf.
Toko
Toko memungkinkan Anda membagikan skrip secara publik dan memasang skrip dari server lain. Memublikasikan dan memasang sama-sama membuat salinan. Memasang listing membuat skrip independen di server Anda, tidak tetap terhubung dengan kode penulis.
- Publikasi
Memerlukan skrip aktif dengan versi yang disetujui, deskripsi (10–512 karakter), dan 1–8 tag ([a-z0-9-], 1–24 karakter). Anda harus menyetujui ToS toko sekali sebelum publikasi pertama.
- Pasang
Memasang menyalin listing ke server Anda sebagai skrip tersendiri (draf, versi yang sudah disetujui, nama sendiri dengan akhiran jika sudah dipakai). KV tidak disalin. Penghitung pemasangan pada listing bertambah.
- Batalkan publikasi
Menghapus listing dari toko. Salinan yang ada tetap ada dan terus berjalan; hanya tidak lagi menerima pembaruan.
- Tanpa uang
Penjualan, paywall, tautan donasi/kripto, dan monetisasi serupa di deskripsi atau kode ditolak saat publikasi dan dapat membuat skrip dilarang.
- Laporan
Siapa pun yang memiliki akses server dapat melaporkan listing beserta alasannya. Staf melihat antrean laporan terbuka dan menutup laporan setelah ditinjau.
- Batas
Daftar toko menampilkan hingga 50 listing per kueri (cari, tag, urutkan menurut jumlah pemasangan atau terbaru). Kuota skrip server yang normal berlaku untuk pemasangan.
Contoh
Pilih contoh untuk melihat kodenya.