luafend
v2.5.0
Published
Command line client for Luafend - Lua and Luau source code protection.
Maintainers
Readme
Luafend
Command line tool and Node.js library for Luafend — source protection for Lua and Luau. One package: protect a script from your terminal, from a build script, from CI, or from your own code.
Targets Luau, Lua 5.1 and Lua 5.4, covering Roblox, Garry's Mod, LuaJIT, embedded Lua and standalone hosts.
Install
npm install -g luafendOr run it without installing:
npx luafendRequires Node.js 18 or newer. No dependencies.
Two ways to run the command line
Type one word — in Command Prompt or PowerShell on Windows, in Terminal on macOS and Linux — and Luafend opens its own shell. Inside it, every command starts with a slash:
luafend
luafend ~ > /login
luafend ~ > /obfuscate main.lua --mode maximum
luafend ~ > /exitTab completes commands, files, flags and values. Typing -- suggests the flags that
command accepts. /help lists everything.
Or drop the slash and run the same command straight from your own shell. Nothing opens, the job runs, you get your prompt back — this is the form a build script or CI job uses:
luafend login
luafend obfuscate main.lua --mode maximum --lua luauGetting started
luafend login # opens your browser, no password typed
luafend obfuscate main.lua # writes main.obf.luaThe first run asks for the mode and the Lua version and remembers both. Every run after that is silent, and prints what it used and where the setting came from.
Use it from code
The short way: set it on the package, then run.
const luafend = require("luafend");
luafend.key = "luf_YOUR_KEY";
luafend.mode = "maximum";
luafend.lua = "luau";
const result = await luafend.run('print("hello")');
if (result.ok) {
console.log(result.output);
} else {
console.log(result.error);
}Set luafend.out = "main.obf.lua" and the file is written for you as UTF-8. Set
luafend.source and run() needs no argument at all.
These settings live on the package, so there is one set of them per program. That is right for a script and wrong for concurrent work; for a server use a client, which carries its own:
const client = new luafend.Luafend({ key: "luf_YOUR_KEY" });
client.mode = "maximum";
const result = await client.run(source);Or describe a single build one line at a time:
const luafend = require("luafend");
const job = new luafend.Job();
job.key = "luf_YOUR_KEY";
job.source = 'print("hello")';
job.mode = "maximum";
job.lua = "luau";
const result = await job.run();
if (result.ok) {
console.log(result.output);
} else {
console.log(result.error);
}run() never rejects. Every Result also carries the measurements, with no flag to switch
on:
console.log(result.size); // bytes of the protected script
console.log(result.sourceSize); // bytes of what you sent
console.log(result.seconds); // how long it took
console.log(result.timestamp); // when it finished, UTC
console.log(result.quotaLeft); // obfuscations left this monthSet job.out = "main.obf.lua" and the file is written for you as UTF-8, line endings
intact.
If you just want the string and are happy for a failure to throw, there is a one line form
that rejects with a LuafendError instead:
console.log(await luafend.obfuscate('print("hello")', {
key: "luf_YOUR_KEY", mode: "maximum", lua: "luau",
}));Leave key out and LUAFEND_TOKEN is used, then the account from luafend login.
mode is lite, balanced or maximum; lua is luau, lua-5.1 or lua-5.4.
Commands
| Command | What it does |
|---|---|
| login | Sign in through your browser |
| logout | Sign out and revoke this machine's token |
| whoami | Name, email, sign-in provider, plan |
| billing | Plan, credits, monthly usage and limits |
| obfuscate <file> | Protect one script |
| batch <pattern> | Protect many files at once |
| settings | Show, reset or write project settings |
| cd [folder] | Show or change the current folder |
| update | Check for a newer version and install it |
| docs | Open the documentation |
| version | Show the CLI version |
Options
| Flag | Meaning |
|---|---|
| --mode lite\|balanced\|maximum | How much protection. Lite is fastest, Maximum compiles the script into its own virtual machine |
| --lua luau\|lua-5.1\|lua-5.4 | Which Lua the result has to run on |
| -o, --out <path> | Where to write. A folder for batch, a file for obfuscate |
| --pick | Choose mode and version again instead of using the saved ones |
| --force | Overwrite an existing output file |
| --stdout | Print the result instead of writing a file |
| --all | batch only: rebuild every file, including unchanged ones |
Without --lua, the version is guessed from the file: a .luau extension or Roblox
globals such as game:GetService mean Luau. The guess is always printed.
Protecting many files
luafend batch "src/**/*.lua" -o dist* and ? never cross a path separator, ** matches any number of directories. A plain
folder means every .lua and .luau inside it. Files that have not changed since their
last build are skipped, so a rebuild does not spend your monthly quota twice. Requests are
paced to your account's rate limit.
Project settings
luafend.json pins how a project builds, so everyone working on it gets the same result:
{
"mode": "maximum",
"lua": "luau",
"out": "dist",
"include": ["src/**/*.lua"]
}It is searched for upwards from the current folder, so any subfolder of the project
behaves the same. With an include list, plain luafend batch is enough.
luafend settings shows what applies and where each value came from. luafend settings
init writes a starter file next to your token, which then applies everywhere you have no
project file.
Signing in
login never asks for a password. It opens a consent page in the browser where you are
already signed in and waits for approval. The token it receives is stored in your OS
config directory, never in the working directory:
| | |
|---|---|
| Windows | %APPDATA%\luafend\config.json |
| macOS | ~/Library/Application Support/luafend/config.json |
| Linux | ~/.config/luafend/config.json |
On macOS and Linux the file is created with mode 0600. logout revokes the token on the
server as well as deleting it here.
The token is only ever sent to the official Luafend API or to a server on your own machine.
In CI
Set LUAFEND_TOKEN instead of signing in. It takes priority over the config file, so no
login step is needed:
- run: npx luafend batch "src/**/*.lua" -o dist --mode balanced --lua luau
env:
LUAFEND_TOKEN: ${{ secrets.LUAFEND_TOKEN }}Without a terminal, nothing is ever asked interactively: a missing setting fails with the flag it needs named, rather than blocking on a prompt nobody can answer.
Exit codes:
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Error |
| 2 | Not signed in, or the session expired |
| 3 | Out of credits, or the plan does not allow that mode |
Environment
| Variable | Effect |
|---|---|
| LUAFEND_TOKEN | Use this token instead of the stored one |
| LUAFEND_API | Point at a different API host, for local development |
| NO_COLOR | Turn colour off |
| LUAFEND_ASCII=1 | Plain ASCII instead of box drawing characters |
Links
- Website — https://bypass.onl
- Documentation — https://bypass.onl/docs
- The same client for Python — https://pypi.org/project/luafend/
