Dokumen

Lua 5.5 · API v0.1

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.

Satu sandbox per skrip

Tidak ada skrip yang dimuat, tidak ada proses yang ada.

Panggilan host dibatasi laju

Panggilan bot:* dan msg:* diperiksa kapabilitasnya oleh bot, bukan oleh Lua.

Fitur bawaan lebih utama

AutoMod, sambutan, dan tiket selalu berjalan. Skrip menghias, tidak menggantikan.

Error tetap terkendali

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. 1

    Tulis file .lua secara lokal

    VS Code, Neovim, atau editor apa pun.
  2. 2

    Periksa secara lokal (opsional)

    script_runner --check file.lua mencetak check: ok.
  3. 3

    Unggah

    Buka halaman Skrip server Anda lalu tempel kode atau unggah file .lua (hingga 64 KiB).
  4. 4

    Dry-run

    Memvalidasi ukuran, encoding, bytecode, dan API terlarang tanpa menjalankan apa pun.
  5. 5

    Aktifkan

    Tunggu persetujuan staf untuk versi tersebut, lalu tekan Aktifkan. Bot memuatnya dalam hitungan detik.
  6. 6

    Atur channel log

    Terima keluaran bot:log dan 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. 1

    Tulis

    Buat file .lua secara lokal di VS Code, Neovim, atau editor apa pun. Memang tidak ada editor di browser.
  2. 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. 3

    Tinjau

    Setiap skrip baru dan setiap versi baru dimulai sebagai tertunda. Staf menyetujui atau menolak revisi kode yang tepat sebelum dapat berjalan.
  4. 4

    Aktifkan

    Anda mengaktifkan versi yang disetujui. Aktivasi versi tertunda atau ditolak ditolak oleh sistem. Hanya versi aktif yang dimuat oleh bot.
  5. 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. 6

    Perbarui / rollback

    Unggah versi baru (kembali tertunda) atau aktifkan versi lama yang disetujui untuk rollback. Penyimpanan KV tetap ada.
  7. 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.

luaLua
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.