OmniFlux Programming Language Reference Manual πŸ“–

Welcome to the official reference manual for OmniFlux, a minimalist, self-healing backend programming language designed to run with zero compile-time friction.

OmniFlux code compiles directly into optimized, production-ready backend code.


1. Syntax & Core

1.1 Comments πŸ’¬

OmniFlux supports multiple comment styles with a clear distinction to give you flexibility:

1.2 Variables

$app_name = "OmniFlux App"  # Global variable
var local_counter = 1      // Block-scoped local variable

1.3 Tasks (Functions)

Tasks (or functions) in OmniFlux are declared using the define task syntax. There are two simple variations:

1.4 Printing to the Screen πŸ“Ί

OmniFlux provides built-in options for outputting text to the screen:

Supported format specifiers include:

1.5 Input & CLI Arguments πŸ“₯

OmniFlux provides simple tools to read input and arguments when building command line interfaces:

1.6 AI Directives (Interactive Code Completion) πŸ€–

OmniFlux features a unique AI-assisted compilation pipeline. You can guide the AI to write entire blocks of code for you on demand using two simple mechanisms:


2. Control Flow & Conditionals

OmniFlux provides simple structures for making decisions and handling execution flow.

2.1 Conditionals (if and switch)

Making Decisions with if / else

Use if, else if, and else to execute code based on conditions. Parentheses around conditions are optional.

var score = 85

if score >= 90 {
    print("Excellent!")
} else if score >= 70 {
    print("Good job!")
} else {
    print("Keep trying!")
}

Multi-way Branching with switch

When you need to compare a variable against multiple values, a switch statement is cleaner than multiple if conditions.

var role = "admin"

switch role {
    case "admin":
        print("Welcome, Administrator!")
        break
    case "editor":
        print("Welcome, Editor!")
        break
    default:
        print("Welcome, User!")
}

2.2 Loops

Loops are used to execute a block of code multiple times. OmniFlux provides two simple loop constructs:

The for Loop (Iterating over Lists)

Used to step through items in an array or list. The loop variable (like fruit in the example below) is created automatically for you without needing the var keyword.

var fruits = ["apple", "banana", "cherry"]

for fruit of fruits {
    print("I like " + fruit)
}

The while Loop (Iterating with Conditions)

Repeats a block of code as long as a specific condition remains true. This is also perfect for counter-based loops.

var count = 1

while count <= 5 {
    print("Count is " + count)
    count = count + 1
}

2.3 Delayed Execution (wait)

Allows delaying execution without blocking.

on start {
    print("Initializing...")
    wait 2 seconds
    print("Ready!")
}

2.4 Periodic Execution (every)

Runs a code block periodically.

every 5 minutes {
    clean_expired_sessions()
}

2.5 Lifecycle Hooks & Execution Order

[!WARNING] Root-Level Execution & Order of Operations: Any code written at the root level (outside of any function or on block) executes immediately when the file is loaded. However, if root-level code contains asynchronous operations (like wait), the order of operations cannot be guaranteed. Subsequent synchronous lines will continue executing while the asynchronous task runs in the background. Always place your main execution logic inside on start or functions to ensure predictable, sequential execution.

OmniFlux provides several lifecycle hooks to manage application state and events cleanly:

2.6 Local Error Handling (on error) πŸ›‘οΈ

To keep your code simple, readable, and free of nested boilerplate (like the try-catch blocks found in other languages), OmniFlux provides a clean, flat syntax to handle errors locally.

You can attach an on error (err) block directly to the closing brace of any Route Handler or Task:

1. Route-Level Error Handling

When attached to a route handler, any network, database, or runtime error thrown inside the route will immediately divert execution to your error handler. This allows you to respond to the client with a custom status and message:

POST "/v1/chat/completions" (req, res) {
    # If networkpost fails (e.g. network timeout), execution jumps straight to the on error block
    var response = networkpost("https://api.provider.com/v1/chat", req.body, {
        "Authorization": "Bearer key"
    })
    respond json response
} on error (err) {
    # Respond gracefully without crashing the server
    respond status 502 and json { 
        "error": "Failed to reach AI provider", 
        "details": err.message 
    }
}

2. Task-Level Error Handling

Similarly, you can attach an on error block to task definitions:

define task load_config(path) {
    var content = fileread(path)
    return JSON.parse(content)
} on error (err) {
    print("Failed to load config: %s", err.message)
    return { "status": "fallback_default" }
}

3. Default Compiler Protection

If you do not specify an on error block:

4. Call-Level Error Handling

You can also catch errors on a specific function call or statement using on error (err) on the same line. This is perfect for capturing exceptions from library calls (like standard library tasks) and supplying a default/fallback value:

[!NOTE] Syntax Design: The start of the call-level on error (err) { block must be placed on the same physical line as the target statement or function call. This design choice prevents ambiguity, clearly distinguishing local statement-level fallbacks from global process-wide on error lifecycle hooks.


3. Web Server & Routing

OmniFlux has built-in primitives for setting up web servers and HTTP routing.

3.1 Initializing Server

listen on port 3000

3.2 Route Handlers & Responses

Define route handlers to respond to HTTP requests. The syntax specifies the HTTP method (like GET or POST), the URL path, and a block containing the response:

GET "/users" (req, res) {
    # Send a JSON response with status code
    respond with status 200 and json { "status": "ok" }
}

Procedural Response Primitives

OmniFlux provides simple, procedural statements for sending HTTP responses, fully hiding Node.js/Express objects. The keyword with is optional in all respond statements:

Deployment Note (Apache + Phusion Passenger): When running an OmniFlux server behind Apache with Passenger, Apache's document root is typically set to the public/ directory. This means any static assets placed in public/ (CSS, images, JS) are served directly by Apache and never reach the OmniFlux application. This is more efficient than serving them through Node.js. Dynamic routes (GET "/", POST "/api/...", etc.) are transparently proxied by Passenger to the OmniFlux process.

To serve static assets when running standalone (without Apache), define a single wildcard route:

GET "/public/*file" (req, res) {
    var file_path = req.params.file.join("/")
    respond with file "public/" + file_path
}

This route is harmlessly ignored under Apache, since Apache intercepts those requests first.


4. Native Bindings

OmniFlux provides native bindings to common backend services, making setups extremely fast:

4.1 Local JSON Database πŸ—„οΈ

OmniFlux includes a built-in, zero-setup database that stores your data in a local file (db.json). It runs entirely in memory for lightning-fast reads, making it perfect for blogs, catalogs, and basic websites.

Database Location & Production Environment Config (DB_FILE)

By default, the database is stored in a file named db.json in the current working directory (CWD) from which the process was started.

[!WARNING] Security Best Practice: Never store the database file (db.json) inside a public directory served by web servers like Apache or Nginx (e.g. public/, www/, or public_html/). Doing so allows anyone to download your entire database directly via a browser. Always configure DB_FILE to point to a secure, non-public directory (like /var/lib/omniflux/db.json or a folder outside of your web root).

If your application is deployed to a production environment where the code directory is write-protected, you can easily configure the database file location by setting the DB_FILE environment variable:

# Run the server with the database file saved in a secure, writable directory
DB_FILE=/var/lib/omniflux/db.json ./omniflux server/proxy.of

Programmatic Database Path (dbsetfile / db_set_file)

You can also change the database file path directly within your code using the built-in function dbsetfile(path) (alias: db_set_file(path)). This is useful if you want to determine the path dynamically or read it from a custom config file:

# Set a custom database location programmatically
dbsetfile("/var/lib/omniflux/db.json")

# Any subsequent database calls will read/write to this file
dbinsert("logs", { event: "startup", time: time() })

Core Concepts for Beginners

1. Inserting Data (dbinsert)

Adds a new item to a collection. It automatically generates a unique id for the record if you don't provide one.

# Save a new user to the "users" collection
var new_user = dbinsert("users", { name: "Alice", email: "alice@example.com", age: 30 })

# The returned object contains the auto-generated unique ID
print("New user created with ID: %s", new_user.id)

2. Querying & Finding Data (dbselect)

Retrieves records matching a filter. It always returns an array (a list) of items.

# Find all users who are admins (using a filter)
var admins = dbselect("users", { role: "admin" })

# Loop through the list to print names
for (var admin of admins) {
    print("Admin: %s", admin.name)
}

# Find a single user by ID
var results = dbselect("users", { id: "mqrlgor5eywc" })
if len(results) > 0 {
    var user = results[0]
    print("Found user: %s", user.name)
}

# Retrieve everything in the collection (no filter)
var all_users = dbselect("users")

3. Updating Data (dbupdate)

Modifies existing records in a collection matching a filter. Returns the number of updated items.

# Update age for the user with a specific ID
var updated_count = dbupdate("users", { id: "mqrlgor5eywc" }, { age: 31 })
print("Updated %d users.", updated_count)

4. Deleting Data (dbdelete)

Removes matching records from a collection. Returns the number of deleted items.

# Delete all users who are under 18
var deleted_count = dbdelete("users", { age: 17 })
print("Deleted %d users.", deleted_count)

5. Compiler CLI Options πŸ› οΈ

The omniflux command line tool provides options to control how your code is compiled and executed:


6. Direct Node.js / JavaScript Integration (@{ ... @}) ⚑

OmniFlux is designed to keep development simple and clean. However, when you need direct access to the Node.js ecosystem, npm modules, or raw JavaScript APIs, you can write JavaScript code directly inside an escape block using the @{ and @} markers.

How it works

1. Reading a file using Node's standard fs library

define task read_config_file {
    # Escape to Node.js to read a file using the native fs module
    @{
        const fs = require('fs');
        const data = fs.readFileSync('config.json', 'utf8');
        return JSON.parse(data);
    @}
}

2. Performing native JavaScript calculations or operations

define task get_js_time {
    @{
        return new Date().toISOString();
    @}
}

3. Error Handling and Line Mapping

If an error occurs inside your @{ ... @} block at runtime, the OmniFlux runtime automatically catches the error and maps the line number back to the exact line in your .of source file, making debugging extremely easy!


7. Standard Libraries & Inclusions (include) πŸ“¦

OmniFlux allows modularizing your code using the include directive. The standard library (stdlib/) contains pre-built tasks for common activities.

The include Directive

To import another file's variables and tasks into your script, use include followed by the relative path of the file:

include "stdlib/datetime.of"
include "stdlib/network.of"
include "stdlib/system.of"

7.1 Date & Time Library (stdlib/datetime.of)

Provides simplified tasks for reading and formatting dates:

include "stdlib/datetime.of"

on start {
    var now = datetime_now()
    var pretty_date = datetime_format(now, "YYYY-MM-DD HH:mm:ss")
    print("Current time: %s", pretty_date)
}

7.2 Network Library (stdlib/network.of)

Provides tasks for sending HTTP requests and talking to public APIs:

include "stdlib/network.of"

on start {
    # Fetch a joke from a public API
    var joke = networkget("https://official-joke-api.appspot.com/random_joke")
    print("Joke: %s", joke.setup)
    print("Answer: %s", joke.punchline)
    
    # Submit data to an API
    var response = networkpost("https://httpbin.org/post", { username: "Alice" })
    print("Response status: %s", response.url)
}

7.3 System Commands Library (stdlib/system.of)

Provides tasks for executing and managing processes in the host OS shell:

include "stdlib/system.of"

on start {
    # 1. Run a command and capture output
    var folder_contents = system("ls -la")
    print("Files:\n%s", folder_contents)
    
    # 2. Run a command and check success status
    var status = exec("git status")
    if status == 0 {
        print("Git command completed successfully!")
    } else {
        print("Git command failed with status code: %d", status)
    }
    
    # 3. Spawn a background process and kill it later
    var pid = spawn("node", ["server.js"])
    print("Spawned process with PID: %d", pid)
    
    wait 2000
    
    var success = kill(pid, "SIGTERM")
    print("Process termination result: %s", success)
}

8. Using NPM Packages πŸ“¦

OmniFlux runs on top of the Node.js runtime and utilizes esbuild for its compilation and bundling steps. This makes it incredibly easy to use any package from the npm registry directly in your OmniFlux code!

How to Install and Require Packages

  1. Initialize a Node.js project if your directory does not have a package.json file yet. This ensures npm packages are installed locally in your project folder (under node_modules/) rather than inherited from a parent directory:
    npm init -y
    
  2. Install the package in your project directory:
    npm install package-name
    
  3. Require the package in your OmniFlux code using the built-in require() function:
    var pkg = require("package-name")
    
  4. Compilation & Bundling: When you compile your application, the compiler automatically bundles the required npm package code into your final standalone binary. You do not need node_modules at runtime!

Example 1: Rendering Markdown with marked

This example shows how to install and use the marked library to parse Markdown text into HTML.

Installation:

npm install marked

Code (render_md.of):

on start {
    # Import the marked library
    var marked = require("marked")
    
    var markdown = "# OmniFlux Guide\n\nOmniFlux is a *minimalist* language."
    
    # Parse Markdown text to HTML
    var html = marked.parse(markdown)
    
    print("Parsed HTML output:\n%s", html)
}

Example 2: Generating Unique IDs with uuid

This example shows how to install and use the uuid library to generate cryptographically strong unique identifiers.

Installation:

npm install uuid

Code (generate_id.of):

on start {
    # Import the uuid library
    var uuid = require("uuid")
    
    # Generate a random UUID
    var new_id = uuid.v4()
    
    print("Generated Unique ID: %s", new_id)
}