API Reference

Everything You Can Build With

All the modules, functions, and capabilities built into Hype. TUI components, HTTP servers, databases, crypto, plugins, and moreβ€”everything you need to ship complete applications.

🧩 Core Modules

πŸ–₯️

TUI Module

Terminal User Interface components for building interactive console applications

View API
🌐

HTTP Module

HTTP client and server functionality for web services and APIs

View API
πŸ”Œ

WebSocket Module

Real-time bidirectional communication with WebSocket servers and clients

View API
πŸ—„οΈ

Key-Value Module

Embedded BoltDB database for persistent data storage

View API
πŸ”

Crypto Module

JWK-based cryptography with RSA, ECDSA, and Ed25519 support

View API
πŸ”

HTTP Signatures

RFC-compliant HTTP message signing and verification

View API
🧩

Plugin System

Extend functionality with versioned Lua modules

View API

TUI Module

The TUI module provides terminal-based user interface components using the tview library.

Application Management

local app = tui.newApp()

App Methods

  • app:SetRoot(primitive, fullscreen) - Set the root component
  • app:Run() - Start the application event loop
  • app:Stop() - Stop the application
  • app:SetFocus(primitive) - Set focus to a specific component
  • app:Draw() - Queue a redraw
  • app:SetInputCapture(function) - Set global key handler

UI Components

TextView

Display text content with advanced formatting, styling, and scrolling capabilities.

local textView = tui.newTextView(text)

Content & Behavior:

  • textView:SetText(text) - Set display text
  • textView:GetText() - Get current text
  • textView:SetWrap(bool) - Enable/disable text wrapping
  • textView:SetWordWrap(bool) - Enable/disable word wrapping
  • textView:SetScrollable(bool) - Make content scrollable
  • textView:SetRegions(bool) - Enable clickable regions

Enhanced Styling:

  • textView:SetDynamicColors(bool) - Enable color markup parsing
  • textView:SetBorder(bool) - Add border around component
  • textView:SetBorderColor(color) - Set border color
  • textView:SetBackgroundColor(color) - Set background color
  • textView:SetTitle(title) - Set component title
  • textView:SetTextColor(color) - Set text color

InputField

Text input component for user data entry with enhanced styling options.

local inputField = tui.newInputField()

Content & Behavior:

  • inputField:SetLabel(label) - Set field label
  • inputField:SetPlaceholder(text) - Set placeholder text
  • inputField:GetText() - Get current input text
  • inputField:SetText(text) - Set input text
  • inputField:SetDoneFunc(callback) - Set completion callback

Enhanced Styling:

  • inputField:SetBorder(bool) - Add border around input field
  • inputField:SetBorderColor(color) - Set border color
  • inputField:SetFieldBackgroundColor(color) - Set input background
  • inputField:SetFieldTextColor(color) - Set input text color
  • inputField:SetTitle(title) - Set component title

Button

Clickable button component for user actions with professional styling.

local button = tui.newButton(label)

Content & Behavior:

  • button:SetLabel(label) - Set button label
  • button:SetSelectedFunc(callback) - Set click handler

Enhanced Styling:

  • button:SetBorder(bool) - Add border around button
  • button:SetBorderColor(color) - Set border color
  • button:SetBackgroundColor(color) - Set button background
  • button:SetLabelColor(color) - Set button text color
  • button:SetTitle(title) - Set component title

Flex

Flexible layout container for organizing components with styling support.

local flex = tui.newFlex()

Layout & Behavior:

  • flex:SetDirection(direction) - Set layout direction (0=vertical, 1=horizontal)
  • flex:AddItem(primitive, fixedSize, proportion, focus) - Add component to layout

Enhanced Styling:

  • flex:SetBorder(bool) - Add border around container
  • flex:SetBorderColor(color) - Set border color
  • flex:SetBackgroundColor(color) - Set container background
  • flex:SetTitle(title) - Set container title

Color Styling & Theming

Enhanced TUI components support professional color schemes and markup.

Color Constants (256-color palette)

-- Common color constants for consistent theming
local COLORS = {
    PRIMARY = 39,      -- Bright blue
    SUCCESS = 46,      -- Bright green  
    WARNING = 226,     -- Bright yellow
    DANGER = 196,      -- Bright red
    SECONDARY = 245,   -- Light gray
    DARK = 235,        -- Dark gray
    DARKER = 232,      -- Very dark gray
    LIGHT = 255,       -- White
    ACCENT = 201,      -- Bright magenta
    INFO = 51          -- Bright cyan
}

Dynamic Color Markup

Use color markup in text content when SetDynamicColors(true) is enabled:

-- Color markup format: [color_code]text[reset_color]
textView:SetDynamicColors(true)
textView:SetText("[46]SUCCESS:[255] Operation completed!")

-- Advanced example with multiple colors
local statusText = string.format([[
[%d]πŸŽ‰ Welcome to Dashboard![%d]

[%d]Status:[%d] %s
[%d]Uptime:[%d] %s
]], 
    COLORS.PRIMARY, COLORS.LIGHT,
    COLORS.INFO, COLORS.LIGHT, "Online",
    COLORS.SUCCESS, COLORS.LIGHT, "2 days"
)

Professional Styling Example

-- Create a professionally styled component
local panel = tui.newTextView("")
panel:SetDynamicColors(true)
panel:SetBorder(true)
panel:SetTitle("πŸ“Š System Metrics")
panel:SetBorderColor(COLORS.INFO)
panel:SetBackgroundColor(COLORS.DARK)
panel:SetScrollable(true)

-- Button with custom styling
local button = tui.newButton("πŸš€ Execute")
button:SetBorder(true)
button:SetBorderColor(COLORS.SUCCESS)
button:SetBackgroundColor(COLORS.SUCCESS)
button:SetLabelColor(COLORS.LIGHT)

Event Handling

Event objects in input capture callbacks provide:

  • event:Key() - Get key code
  • event:Rune() - Get character rune

Example: Enhanced TUI App

local app = tui.newApp()
local textView = tui.newTextView("[39]Hello from Hype![255]")
textView:SetDynamicColors(true)
textView:SetBorder(true)
textView:SetTitle("πŸš€ My Enhanced App")
textView:SetBorderColor(39) -- Blue border
textView:SetBackgroundColor(235) -- Dark background

app:SetInputCapture(function(event)
    if event:Key() == 27 then -- ESC key
        app:Stop()
        return nil
    end
    return event
end)

app:SetRoot(textView, true)
app:Run()

HTTP Module

Provides HTTP client and server functionality for web services and API development.

HTTP Client

local http = require('http')

GET Requests

local response, err = http.get(url, options)

Parameters:

  • url - Target URL string
  • options - Optional table with:
    • timeout - Request timeout in seconds
    • headers - Custom headers table

Response Structure:

{
  status = 200,
  body = "response body",
  headers = { ["Content-Type"] = "application/json" }
}

Example: HTTP Client Usage

local http = require('http')
local response, err = http.get("https://api.example.com/data", {
    timeout = 10,
    headers = {["User-Agent"] = "MyApp/1.0"}
})

if response then
    print("Status:", response.status)
    print("Body:", response.body)
else
    print("Error:", err)
end

HTTP Server

local server = http.newServer()

Server Methods

  • server:handle(pattern, handler) - Register route handler
  • server:listen(port) - Start server on port
  • server:stop() - Stop server

Handler Function

Handler functions receive request and response objects:

server:handle("/api/users", function(req, res)
    -- Request object (req) contains:
    -- req.method, req.url, req.path, req.headers, req.query, req.body
    
    -- Response object (res) methods:
    res:write(content)           -- Write text response
    res:json(table)              -- Write JSON response
    res:status(code)             -- Set HTTP status code
    res:header(key, value)       -- Set response header
end)

Example: HTTP Server

local http = require('http')
local server = http.newServer()

server:handle("/", function(req, res)
    res:json({ message = "Hello World!" })
end)

server:handle("/api/echo", function(req, res)
    res:json({ 
        method = req.method,
        path = req.path,
        query = req.query,
        body = req.body
    })
end)

server:listen(8080)
print("Server running on :8080")

WebSocket Module

Real-time bidirectional communication with WebSocket servers and clients for building interactive applications.

WebSocket Server

local websocket = require('websocket')
local server = websocket.newServer()

Server Methods

  • server:handle(path, handler) - Register WebSocket route handler
  • server:listen(port) - Start server on port
  • server:stop() - Stop server gracefully

Connection Handler

Route handlers receive a WebSocket connection object:

server:handle("/ws", function(conn)
    -- Set up event handlers for this connection
    conn:onMessage(function(message)
        print("Received:", message.data)
        conn:send("Echo: " .. message.data)
    end)
    
    conn:onClose(function()
        print("Connection closed")
    end)
    
    conn:onError(function(err)
        print("Error:", err)
    end)
    
    -- Send welcome message
    conn:send("Connected to WebSocket server!")
end)

Example: WebSocket Echo Server

local websocket = require('websocket')
local server = websocket.newServer()

server:handle("/echo", function(conn)
    print("New WebSocket connection")
    
    conn:onMessage(function(message)
        print("Received:", message.data)
        -- Echo message back to client
        conn:send("Echo: " .. message.data)
    end)
    
    conn:onClose(function()
        print("Client disconnected")
    end)
    
    conn:onError(function(err)
        print("WebSocket error:", err)
    end)
    
    -- Send welcome message
    conn:send("Welcome to echo server!")
end)

server:listen(8080)
print("WebSocket server running at ws://localhost:8080/echo")

-- Keep server running
while true do
    os.execute("sleep 1")
end

WebSocket Client

local client = websocket.connect(url)

Parameters:

  • url - WebSocket URL (e.g., "ws://localhost:8080/ws")

Returns: WebSocket connection object or nil on failure

Example: WebSocket Client

local websocket = require('websocket')
local client = websocket.connect("ws://localhost:8080/echo")

if not client then
    print("Failed to connect to WebSocket server")
    os.exit(1)
end

-- Set up event handlers
client:onMessage(function(message)
    print("Received:", message.data)
    print("Type:", message.type)  -- "text" or "binary"
end)

client:onClose(function()
    print("Connection closed")
end)

client:onError(function(err)
    print("WebSocket error:", err)
end)

-- Send messages
client:send("Hello from Lua client!")
client:sendBinary("Binary message")

-- Ping the server
client:ping()

-- Close when done
client:close()

Connection Methods

Both server and client connections support these methods:

  • conn:send(message) - Send text message
  • conn:sendBinary(data) - Send binary message
  • conn:onMessage(handler) - Set message event handler
  • conn:onClose(handler) - Set close event handler
  • conn:onError(handler) - Set error event handler
  • conn:close() - Close connection
  • conn:ping() - Send ping frame

Message Object Structure

{
  data = "message content",  -- String content of the message
  type = "text"              -- "text" or "binary"
}

Real-Time Chat Example

Multi-Client Chat Server

local websocket = require('websocket')
local clients = {}

local server = websocket.newServer()

server:handle("/chat", function(conn)
    -- Add client to list
    table.insert(clients, conn)
    local clientId = #clients
    print("Client " .. clientId .. " connected")
    
    -- Broadcast join message
    for i, client in ipairs(clients) do
        if client ~= conn then
            client:send("Client " .. clientId .. " joined")
        end
    end
    
    conn:onMessage(function(message)
        local msg = "Client " .. clientId .. ": " .. message.data
        print(msg)
        
        -- Broadcast to all clients
        for i, client in ipairs(clients) do
            client:send(msg)
        end
    end)
    
    conn:onClose(function()
        -- Remove client from list
        for i, client in ipairs(clients) do
            if client == conn then
                table.remove(clients, i)
                break
            end
        end
        
        -- Notify others
        for i, client in ipairs(clients) do
            client:send("Client " .. clientId .. " left")
        end
    end)
end)

server:listen(8080)
print("Chat server running at ws://localhost:8080/chat")

Key-Value Module

BoltDB-based embedded database for persistent storage with ACID transactions.

Database Connection

local kv = require('kv')
local db, err = kv.open(path, options)

Parameters:

  • path - Database file path
  • options - Optional configuration table

Bucket Management

  • db:open_db(bucketName) - Create/open bucket

Buckets are like tables in traditional databases, used to organize key-value pairs.

Basic Operations

  • db:put(bucket, key, value) - Store key-value pair
  • db:get(bucket, key) - Retrieve value by key
  • db:delete(bucket, key) - Delete key
  • db:close() - Close database connection

Example: Basic Usage

local kv = require('kv')
local db, err = kv.open("./data.db")

if not db then
    print("Error opening database:", err)
    return
end

-- Create/open bucket
db:open_db("users")

-- Store data
db:put("users", "john", "John Doe")
db:put("users", "jane", "Jane Smith")

-- Retrieve data
local name = db:get("users", "john")
print("User:", name)  -- Output: User: John Doe

-- Delete data
db:delete("users", "john")

-- Close database
db:close()

Batch Operations

  • db:keys(bucket, prefix) - Get all keys (optionally with prefix)
  • db:foreach(bucket, callback) - Iterate over all key-value pairs

Example: Batch Operations

-- Get all keys
local keys = db:keys("users")
for i, key in ipairs(keys) do
    print("Key:", key)
end

-- Get keys with prefix
local userKeys = db:keys("users", "user_")

-- Iterate over all key-value pairs
db:foreach("users", function(key, value)
    print(key .. " = " .. value)
    return true  -- Continue iteration
end)

Transaction Support

Transactions provide ACID guarantees for multiple operations.

local txn, err = db:begin_txn(readonly)

Transaction Methods

  • txn:put(bucket, key, value) - Store in transaction
  • txn:get(bucket, key) - Retrieve in transaction
  • txn:delete(bucket, key) - Delete in transaction
  • txn:commit() - Commit transaction
  • txn:abort() - Abort transaction

Example: Transactions

-- Begin read-write transaction
local txn, err = db:begin_txn(false)
if not txn then
    print("Error starting transaction:", err)
    return
end

-- Perform multiple operations
txn:put("users", "alice", "Alice Johnson")
txn:put("users", "bob", "Bob Wilson")

-- Get data within transaction
local alice = txn:get("users", "alice")
print("Alice:", alice)

-- Commit all changes
local success, err = txn:commit()
if not success then
    print("Transaction failed:", err)
    txn:abort()
end

Crypto Module

Professional-grade cryptography using JSON Web Key (JWK) format with support for RSA (including PSS), ECDSA, and Ed25519 algorithms, plus SHA-256/384/512 hashing with deep hashing support for complex data structures.

Getting Started

local crypto = require('crypto')

The crypto module provides modern cryptographic operations using the industry-standard JWK format for key management.

Key Generation

local jwk = crypto.generate_jwk(algorithm)
local jwk = crypto.generate_jwk(algorithm, key_size)  -- RSA only

Supported Algorithms:

  • "RS256", "RS384", "RS512" - RSA PKCS#1 v1.5 with SHA-256/384/512
  • "PS256", "PS384", "PS512" - RSA-PSS with SHA-256/384/512
  • "ES256", "ES384", "ES512" - ECDSA with SHA-256/384/512
  • "EdDSA" - Ed25519 (EdDSA)

Returns: JWK table with algorithm-specific fields

Example: Generate Different Key Types

-- Generate RSA key (default 2048-bit)
local rsa_key = crypto.generate_jwk("RS256")
print("RSA Key Type:", rsa_key.kty)  -- "RSA"

-- Generate 4096-bit RSA key
local rsa_4096 = crypto.generate_jwk("RS256", 4096)
print("Generated 4096-bit RSA key")

-- Generate 3072-bit RSA-PSS key
local rsa_pss = crypto.generate_jwk("PS256", 3072)
print("Generated 3072-bit RSA-PSS key")

-- Generate ECDSA key  
local ecdsa_key = crypto.generate_jwk("ES256")
print("ECDSA Key Type:", ecdsa_key.kty)  -- "EC"

-- Generate Ed25519 key
local ed25519_key = crypto.generate_jwk("EdDSA")
print("Ed25519 Key Type:", ed25519_key.kty)  -- "OKP"

RSA Key Sizes:

  • 2048 - Default for RS256/PS256
  • 3072 - Default for RS384/RS512/PS384/PS512
  • 4096 - Maximum supported size for enhanced security

Digital Signatures

Signing

local signature = crypto.sign(jwk, message)

Parameters:

  • jwk - Private JWK key (from generate_jwk)
  • message - String data to sign

Returns: Binary signature string or nil on error

Verification

local is_valid = crypto.verify(public_jwk, message, signature)

Parameters:

  • public_jwk - Public JWK key (from jwk_to_public)
  • message - Original string data
  • signature - Binary signature to verify

Returns: Boolean validation result

Example: Sign and Verify

local crypto = require('crypto')

-- Generate key pair
local private_key = crypto.generate_jwk("ES256")
local public_key = crypto.jwk_to_public(private_key)

-- Sign message
local message = "Important document content"
local signature = crypto.sign(private_key, message)

if signature then
    print("βœ… Message signed successfully")
    
    -- Verify signature
    local is_valid = crypto.verify(public_key, message, signature)
    
    if is_valid then
        print("βœ… Signature verified!")
    else
        print("❌ Invalid signature")
    end
else
    print("❌ Signing failed")
end

Key Management

Extract Public Key

local public_jwk = crypto.jwk_to_public(private_jwk)

Extracts the public key component from a private JWK for sharing and verification.

Key Thumbprint

local thumbprint = crypto.jwk_thumbprint(jwk)

Generates a unique SHA-256 thumbprint for key identification (RFC 7638).

JSON Serialization

-- Export to JSON
local json_string = crypto.jwk_to_json(jwk)

-- Import from JSON
local jwk = crypto.jwk_from_json(json_string)

Convert JWK objects to/from JSON for storage and transmission.

Example: Key Management

local crypto = require('crypto')

-- Generate and manage keys
local private_key = crypto.generate_jwk("RS256")
local public_key = crypto.jwk_to_public(private_key)

-- Get unique identifier
local key_id = crypto.jwk_thumbprint(private_key)
print("Key ID:", key_id)

-- Serialize for storage
local private_json = crypto.jwk_to_json(private_key)
local public_json = crypto.jwk_to_json(public_key)

-- Save public key for sharing
local file = io.open("public_key.json", "w")
file:write(public_json)
file:close()

-- Later: load and use
local loaded_json = io.open("public_key.json"):read("*all")
local loaded_key = crypto.jwk_from_json(loaded_json)
print("Loaded key algorithm:", loaded_key.alg)

Hashing Functions

Basic Hash Functions

local hash = crypto.sha256(data)
local hash = crypto.sha384(data)
local hash = crypto.sha512(data)

Compute SHA-256, SHA-384, or SHA-512 hash of input data.

Parameters:

  • data - String data to hash

Returns: Hexadecimal hash string

Generic Hash Function

local hash = crypto.hash(algorithm, data)

Parameters:

  • algorithm - Hash algorithm: "sha256", "sha384", or "sha512"
  • data - String data to hash

Returns: Hexadecimal hash string or nil + error

Deep Hash Function

local hash = crypto.deep_hash(value, algorithm)

Compute a deterministic hash of complex data structures including nested tables.

Parameters:

  • value - Any Lua value (string, number, boolean, nil, table)
  • algorithm - Optional: "sha256", "sha384", or "sha512" (defaults to "sha384")

Returns: Hexadecimal hash string or nil + error

Example: Hashing Operations

local crypto = require('crypto')

-- Basic hashing
local data = "Important data to hash"
local sha256 = crypto.sha256(data)
local sha384 = crypto.sha384(data)
local sha512 = crypto.sha512(data)

print("SHA-256:", sha256)
print("SHA-384:", sha384)
print("SHA-512:", sha512)

-- Generic hash function
local hash = crypto.hash("sha384", data)
print("Generic SHA-384:", hash)

-- Deep hashing for complex structures
local complex_data = {
    user = {
        id = 123,
        name = "Alice",
        roles = {"admin", "user"}
    },
    settings = {
        theme = "dark",
        notifications = true
    },
    timestamp = os.time()
}

-- Deep hash with SHA-384 (default)
local deep_hash = crypto.deep_hash(complex_data)
print("Deep hash:", deep_hash)

-- Deep hash with specific algorithm
local deep_sha256 = crypto.deep_hash(complex_data, "sha256")
print("Deep SHA-256:", deep_sha256)

-- Consistent hashing regardless of key order
local reordered = {
    timestamp = os.time(),
    settings = {
        notifications = true,
        theme = "dark"
    },
    user = {
        roles = {"admin", "user"},
        name = "Alice",
        id = 123
    }
}

local hash1 = crypto.deep_hash(complex_data)
local hash2 = crypto.deep_hash(reordered)
print("Hashes match:", hash1 == hash2)  -- true

Use Cases for Hashing

  • Data Integrity: Verify data hasn't been modified
  • Cache Keys: Generate consistent keys for complex data
  • Deduplication: Identify duplicate data structures
  • API ETags: Generate entity tags for HTTP caching
  • Audit Logs: Create tamper-evident records

Security Best Practices

  • Key Storage: Store private keys securely, never in plain text
  • Algorithm Choice: Use ES256 for most applications (fast + secure)
  • Key Rotation: Regularly rotate keys and use thumbprints for identification
  • Public Key Sharing: Only share public keys, never private keys
  • Message Integrity: Always verify signatures before trusting data

Algorithm Comparison

Performance Characteristics:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Algorithmβ”‚ Key Size    β”‚ Signature   β”‚ Performance  β”‚ Security  β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ RS256   β”‚ 2048 bits   β”‚ 256 bytes   β”‚ Slower       β”‚ Good      β”‚
β”‚ PS256   β”‚ 2048 bits   β”‚ 256 bytes   β”‚ Slower       β”‚ Better    β”‚
β”‚ ES256   β”‚ 256 bits    β”‚ 64 bytes    β”‚ Fast         β”‚ Good      β”‚
β”‚ EdDSA   β”‚ 256 bits    β”‚ 64 bytes    β”‚ Fastest      β”‚ Good      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Recommendations:

  • ES256: Best general-purpose choice (NIST P-256)
  • EdDSA: Fastest performance, modern alternative
  • PS256/384/512: Use for RSA with enhanced security (PSS padding)
  • RS256: Use when legacy RSA compatibility is required

HTTP Signatures Module

RFC-compliant HTTP message signing and verification for secure API communication, webhooks, and microservice authentication.

Getting Started

local crypto = require('crypto')
local httpsig = require('httpsig')

HTTP Signatures provide message-level security by cryptographically signing HTTP requests and responses using the draft-cavage-http-signatures specification.

HTTP Request Signing

local signed_result = httpsig.sign(message, options)

Message Structure (Request):

{
    type = "request",
    method = "POST",           -- HTTP method
    path = "/api/users",       -- URL path
    headers = {                -- HTTP headers
        ["Host"] = "api.example.com",
        ["Content-Type"] = "application/json"
    },
    body = '{"name": "Alice"}'  -- Message body
}

Signing Options:

{
    jwk = private_key,                    -- Private JWK for signing
    key_id = "my-key-2024",              -- Key identifier
    headers = {"(request-target)", "host", "date", "digest"},  -- Headers to sign
    created = os.time(),                 -- Optional: signature creation time
    expires = os.time() + 300           -- Optional: signature expiration
}

Returns: Table with signed headers or nil on error

Example: Sign HTTP Request

local crypto = require('crypto')
local httpsig = require('httpsig')

-- Generate signing key
local signing_key = crypto.generate_jwk("ES256")

-- Create request to sign
local request = {
    type = "request",
    method = "POST",
    path = "/api/transfer", 
    headers = {
        ["Host"] = "bank-api.com",
        ["Content-Type"] = "application/json"
    },
    body = '{"amount": 1000, "to": "account123"}'
}

-- Sign the request
local signed = httpsig.sign(request, {
    jwk = signing_key,
    key_id = "client-2024",
    headers = {"(request-target)", "host", "content-type", "digest", "date"}
})

if signed then
    print("βœ… Request signed successfully")
    print("Signature:", signed.headers.signature:sub(1, 50) .. "...")
    print("Digest:", signed.headers.digest)
    print("Date:", signed.headers.date)
else
    print("❌ Signing failed")
end

HTTP Response Signing

Message Structure (Response):

{
    type = "response",
    status = 200,              -- HTTP status code
    headers = {                -- HTTP headers
        ["Content-Type"] = "application/json",
        ["Server"] = "MyAPI/1.0"
    },
    body = '{"status": "success"}'  -- Response body
}

Example: Sign HTTP Response

-- Server response signing
local server_key = crypto.generate_jwk("RS256")

local response = {
    type = "response",
    status = 201,
    headers = {
        ["Content-Type"] = "application/json",
        ["Location"] = "/api/users/123"
    },
    body = '{"id": 123, "created": true}'
}

local signed_response = httpsig.sign(response, {
    jwk = server_key,
    key_id = "server-rsa-key",
    headers = {"(status)", "content-type", "location", "digest", "date"}
})

if signed_response then
    print("βœ… Response signed by server")
    print("Status signed:", response.status)
end

Signature Verification

local result = httpsig.verify(message, options)

Verification Options:

{
    jwk = public_key,                    -- Public JWK for verification
    required_headers = {"host", "date"}, -- Headers that must be signed
    max_age = 300                       -- Max signature age in seconds
}

Returns: Verification result table

{
    valid = true,                       -- Boolean: signature valid
    key_id = "client-2024",            -- Key ID from signature
    algorithm = "ecdsa-256",           -- Algorithm used
    reason = "digest mismatch"         -- Error reason if invalid
}

Example: Verify Signature

-- Extract public key for verification
local public_key = crypto.jwk_to_public(signing_key)

-- Verify received message
local verification = httpsig.verify(received_message, {
    jwk = public_key,
    required_headers = {"host", "content-type"},
    max_age = 300  -- 5 minutes
})

if verification.valid then
    print("βœ… Signature verified!")
    print("Signed by:", verification.key_id)
    print("Algorithm:", verification.algorithm)
    
    -- Process trusted message
    process_secure_request(received_message)
else
    print("❌ Invalid signature:", verification.reason)
    -- Reject untrusted message
    return_error("Signature verification failed")
end

Digest Operations

Message digests ensure content integrity and are automatically included when body content is present.

Create Digest

local digest = httpsig.create_digest(content, algorithm)

Parameters:

  • content - String content to hash
  • algorithm - "sha256" or "sha512" (default: "sha256")

Verify Digest

local is_valid = httpsig.verify_digest(content, digest_header)

Example: Manual Digest Operations

local content = '{"sensitive": "data", "amount": 5000}'

-- Create digest
local digest = httpsig.create_digest(content, "sha256")
print("Digest:", digest)  -- "SHA-256=base64encodedHash"

-- Verify digest
local is_valid = httpsig.verify_digest(content, digest)
print("Valid:", is_valid)  -- true

-- Test with tampered content
local tampered = '{"sensitive": "HACKED", "amount": 5000}'
local tampered_valid = httpsig.verify_digest(tampered, digest)
print("Tampered valid:", tampered_valid)  -- false

Security Features

  • Automatic Digest Creation: Body content automatically hashed and signed
  • Tampering Detection: Modified content fails verification
  • Replay Protection: Timestamps prevent replay attacks
  • Flexible Headers: Sign any combination of HTTP headers
  • Multiple Algorithms: Support for RSA, ECDSA, and Ed25519
  • Key Identification: Key IDs enable multi-key scenarios

Common Use Cases

Webhook Security

-- Sign webhook payload
local webhook_signature = httpsig.sign({
    type = "request",
    method = "POST",
    path = "/webhook",
    headers = {
        ["Host"] = "client.example.com",
        ["X-Event-Type"] = "user.created"
    },
    body = '{"user_id": 123, "event": "created"}'
}, {
    jwk = webhook_signing_key,
    key_id = "webhook-2024"
})

API Authentication

-- Client signs API request
local api_request = httpsig.sign({
    type = "request", 
    method = "GET",
    path = "/api/user/profile",
    headers = {
        ["Host"] = "api.service.com",
        ["Authorization"] = "Bearer " .. access_token
    }
}, {
    jwk = client_key,
    key_id = "client-app-2024",
    headers = {"(request-target)", "host", "authorization", "date"}
})

Microservice Communication

-- Service-to-service authentication
local service_request = httpsig.sign({
    type = "request",
    method = "POST", 
    path = "/internal/process",
    headers = {
        ["Host"] = "worker-service",
        ["X-Service-ID"] = "gateway-v1"
    },
    body = process_data
}, {
    jwk = service_key,
    key_id = "gateway-service",
    created = os.time(),
    expires = os.time() + 60  -- 1 minute expiry
})

Best Practices

  • Always Sign Critical Headers: Include host, date, and content-type
  • Use Digest for Body Content: Include "digest" header when signing requests with bodies
  • Set Reasonable Expiration: Use expires or max_age to prevent replay attacks
  • Validate Required Headers: Specify required_headers in verification
  • Key Management: Use unique key_id values and rotate keys regularly
  • Algorithm Selection: Use ES256 for most applications (fast + secure)

Plugin System

Extend Hype applications with versioned Lua modules that embed seamlessly into your executables.

Using Plugins

Plugins are loaded using the --plugins command line flag and accessed in Lua using require().

Plugin Specifications

  • fs - Simple name (uses auto-discovery)
  • fs@1.0.0 - Name with specific version
  • myfs=./path/to/plugin - Custom alias with path
  • myfs=./path/to/plugin@2.0.0 - Alias with path and version

Example: Using Plugins

-- app.lua
local fs = require("fs")
local config = require("config")

-- Use filesystem plugin
local content, err = fs.readFile("data.txt")
if content then
    print("File content:", content)
else
    print("Error:", err)
end

-- Use configuration plugin
config.load("app.conf")
local port = config.get("server", "port", 8080)
# Run with plugins ./hype run app.lua --plugins fs@1.0.0,config@2.1.0 # Build with embedded plugins ./hype build app.lua --plugins fs@1.0.0,config@2.1.0 -o myapp

Plugin Discovery

Hype automatically searches for plugins in conventional directories:

  • ./plugins/[name]/ - Local plugins directory
  • ./examples/plugins/[name]/ - Example plugins
  • ./[name]-plugin/ - Plugin suffix convention
  • ./examples/plugins/[name]-plugin/ - Example plugin suffix

Example: Plugin Directory Structure

project/
β”œβ”€β”€ app.lua
β”œβ”€β”€ plugins/
β”‚   β”œβ”€β”€ fs/
β”‚   β”‚   β”œβ”€β”€ hype-plugin.yaml
β”‚   β”‚   └── plugin.lua
β”‚   └── utils/
β”‚       β”œβ”€β”€ hype-plugin.yaml
β”‚       └── plugin.lua
└── examples/
    └── plugins/
        └── fs-plugin/
            β”œβ”€β”€ hype-plugin.yaml
            └── plugin.lua

Plugin Manifest

Each plugin requires a hype-plugin.yaml manifest file:

name: "fs"
version: "1.0.0"
type: "lua"
main: "plugin.lua"
description: "Basic filesystem operations"

Manifest Fields

  • name - Plugin identifier (required)
  • version - Semantic version string (required)
  • type - Plugin type, currently only "lua" (required)
  • main - Entry point file (required)
  • description - Human-readable description (optional)

Plugin Development

Plugins are standard Lua modules that return a table of functions:

Example: Simple Plugin

-- plugin.lua
local fs = {}

function fs.readFile(path)
    local file = io.open(path, "r")
    if not file then
        return nil, "File not found: " .. path
    end
    
    local content = file:read("*all")
    file:close()
    return content, nil
end

function fs.writeFile(path, content)
    local file = io.open(path, "w")
    if not file then
        return nil, "Cannot write file: " .. path
    end
    
    file:write(content)
    file:close()
    return true, nil
end

function fs.exists(path)
    local file = io.open(path, "r")
    if file then
        file:close()
        return true
    end
    return false
end

return fs

Version Management

Plugins support exact version matching for compatibility:

  • fs@1.0.0 - Exact version match required
  • fs or fs@latest - Any version accepted
  • Version validation prevents compatibility issues

Example: Version-Specific Usage

# Use specific version
./hype run app.lua --plugins fs@1.0.0

# Use latest version
./hype run app.lua --plugins fs

# Multiple plugins with versions
./hype run app.lua --plugins fs@1.0.0,json@2.1.0,utils

Available Plugins

Hype includes example plugins for common use cases:

Filesystem Plugin (fs@1.0.0)

  • fs.readFile(path) - Read file contents
  • fs.writeFile(path, content) - Write file contents
  • fs.exists(path) - Check file existence
  • fs.size(path) - Get file size
  • fs.listDir(path) - List directory contents
  • fs.mkdir(path) - Create directory

Enhanced Filesystem Plugin (fs@2.0.0)

  • All v1.0.0 features plus:
  • fs.copyFile(src, dst) - Copy file
  • fs.moveFile(src, dst) - Move file
  • fs.deleteFile(path) - Delete file
  • fs.version() - Get plugin version

Example: Filesystem Operations

local fs = require("fs")

-- Read configuration
local config, err = fs.readFile("config.json")
if not config then
    print("Error:", err)
    return
end

-- Create backup
local success, err = fs.copyFile("data.txt", "backup.txt")
if success then
    print("Backup created successfully")
end

-- List files
local files, err = fs.listDir("./logs")
if files then
    for _, file in ipairs(files) do
        print("Found:", file)
    end
end

Plugin Best Practices

  • Error Handling: Return nil, error_message on failure
  • Consistent API: Follow standard Lua conventions
  • Version Compatibility: Use semantic versioning
  • Documentation: Include clear function descriptions
  • Testing: Test plugins with hype run before building

Command Line Interface

Build and execution options for Hype applications.

Build Command

hype build script.lua [options]

Options

  • -o, --output NAME - Set executable name
  • --target PLATFORM - Target platform (current, linux, windows, darwin)
  • --plugins LIST - Comma-separated list of plugins to embed

Build Examples

# Build for current platform
hype build myapp.lua

# Specify output name
hype build myapp.lua -o myserver

# Build with plugins
hype build myapp.lua --plugins fs@1.0.0,json -o myapp

# Cross-compile for different platforms
hype build myapp.lua --target linux
hype build myapp.lua --target windows
hype build myapp.lua --target darwin

Run Command

Run Lua scripts directly for development and testing.

hype run script.lua [--plugins LIST] [-- args...]

Options

  • --plugins LIST - Comma-separated list of plugins to load

Run Examples

# Run script directly
hype run server.lua

# Run with plugins
hype run myapp.lua --plugins fs@1.0.0,json

# Pass command line arguments
hype run myapp.lua -- --port 3000 --debug

# Plugins with arguments
hype run myapp.lua --plugins fs@1.0.0 -- --debug

Command Line Arguments

Access arguments in your Lua scripts via the global arg table:

  • arg[0] - Script/executable name
  • arg[1], arg[2], ... - Command line arguments

Example: Argument Handling

-- args.lua
print("Script name:", arg[0])
print("Number of arguments:", #arg)

for i = 1, #arg do
    print("Arg " .. i .. ":", arg[i])
end

-- Usage: hype run args.lua -- hello world 123
-- Output:
-- Script name: args.lua
-- Number of arguments: 3
-- Arg 1: hello
-- Arg 2: world
-- Arg 3: 123

Standard Lua Libraries

All standard Lua libraries are available in Hype applications:

🌐

Global Environment

Access to _G and global functions

πŸ“¦

Package System

Module loading with require() and package

πŸ”„

Coroutines

Cooperative multitasking with coroutine

πŸ“‹

Table Operations

Data structure manipulation with table

πŸ“„

File I/O

File operations with io library

βš™οΈ

System Access

Operating system interface with os

πŸ”€

String Processing

Text manipulation with string

πŸ”’

Mathematics

Mathematical functions with math