santoku
santoku

santoku

A Lua framework for building applications end to end

Lua 5.1 from the build system to the server to the browser. Every example on this site runs in your browser. Edit one and run it.


santoku targets Lua 5.1, because 5.1 is the version its platforms actually share. LuaJIT implements 5.1 and OpenResty embeds LuaJIT, so server code, client code and the build harness all run the same language. Compiled to WebAssembly, the 5.1 core is smaller to embed, and its single number type sidesteps the integer and float split introduced in 5.3, which keeps numeric values crossing the JavaScript boundary simple. Support for newer versions is meant to come from compatibility shims layered over the 5.1 core rather than version branches in the tree; contributions and design ideas for that layer are welcome.

santoku-brotli

View on LuaRocks

brotli on google/brotli 1.2.0: compress with a quality, window and mode, matching brotli -q 11 at the defaults, and decompress with a max_out cap against decompression bombs

santoku-brotli binds google/brotli 1.2.0 into one module, santoku.brotli, with two functions: compress and decompress. brotli is vendored and linked statically. At its defaults compress writes the same bytes as brotli -q 11, and an optional max_out byte limit stops a decompression bomb. Every failure raises a structured error naming the function. santoku-make compresses each page chunk with it to pick the smaller of source and bytecode. This page's wasm bundle doesn't include it, so the examples are shown for reading.

compress and decompress

compress(s[, opts]) returns the brotli stream of s. opts.quality is 0 to 11, 11 by default. opts.lgwin is the window in bits, 10 to 24, and defaults to the smallest window that holds s. opts.mode is "generic", the default, "text" or "font". decompress(s[, opts]) returns the decoded bytes. This run prints 8800 text bytes, 51 at quality 11 and 49 at quality 5 in text mode.

local brotli = require("santoku.brotli") local str = require("santoku.string") local text = str.rep("the quick brown fox jumps over the lazy dog\n", 200) local packed = brotli.compress(text) print("text bytes:", #text, "brotli -q 11 bytes:", #packed) local fast = brotli.compress(text, { quality = 5, mode = "text" }) print("quality 5, text mode:", #fast) print("round trip:", brotli.decompress(packed) == text) return #packed
Illustrative: runs outside the browser.

max_out and errors

decompress's opts.max_out caps the decoded size in bytes and raises "output exceeds max_out" past it; without it the output has no cap. Options are checked by name and range, so a misspelt option or a quality of 12 raises, and input that isn't brotli raises "corrupt input" with brotli's error code. Errors arrive as the function name and the message, so err.pcall returns false, "decompress", "output exceeds max_out".

local brotli = require("santoku.brotli") local err = require("santoku.error") local str = require("santoku.string") local bomb = brotli.compress(str.rep("\0", 1048576)) print("1 MB of zeros compresses to:", #bomb) print("max_out 2 MB:", #brotli.decompress(bomb, { max_out = 2097152 })) print(err.pcall(brotli.decompress, bomb, { max_out = 65536 })) print(err.pcall(brotli.compress, "x", { quality = 12 })) print(err.pcall(brotli.compress, "x", { qualty = 5 })) print(err.pcall(brotli.decompress, "not brotli")) return #bomb
Illustrative: runs outside the browser.