Schema Compiler

Schema Compiler

Define message types in .sia files and generate serialization code for TypeScript, Go, Python, and C++.

The Sia schema compiler (@timeleap/sia-schema) is a Node.js CLI tool that lets you define message types and RPC plugins in .sia files, then generate serialization code for TypeScript, Go, Python, and C++. The compiler itself requires Node.js, but the generated code is native to each target language with no Node.js dependency.

Instead of writing addString8 / readString8 calls by hand, you define your data structures once and let the compiler produce the encode/decode functions.

When to Use the Schema Compiler

  • You have many message types and writing paired serialize/deserialize functions by hand is tedious
  • You want cross-language compatibility guaranteed by generating code from the same schema
  • You're building RPC plugins for the Timeleap network

If you only have a few simple messages, writing the serialization code by hand is simpler and gives you full control.

Installation

npm install -g @timeleap/sia-schema

Or use it without installing:

npx @timeleap/sia-schema compile schema.sia -o schema.ts
npx @timeleap/sia-schema compile schema.sia -o schema.go
npx @timeleap/sia-schema compile schema.sia -o schema.py
npx @timeleap/sia-schema compile schema.sia -o schema.cpp

The CLI binary is named sia.

A Quick Example

Given this schema file:

schema User {
  name    string8
  age     uint8
  email   string16
  active  bool
}

Run the compiler:

sia compile user.sia -o user.ts
sia compile user.sia -o user.go
sia compile user.sia -o user.py
sia compile user.sia -o user.cpp

The generated code includes paired encode/decode functions:

import { Sia } from "@timeleap/sia";

export interface User {
  name: string;
  age: number;
  email: string;
  active: boolean;
}

export function encodeUser(sia: Sia, user: User): Sia {
  sia.addString8(user.name);
  sia.addUInt8(user.age);
  sia.addString16(user.email);
  sia.addBool(user.active);
  return sia;
}

export function decodeUser(sia: Sia): User {
  return {
    name: sia.readString8(),
    age: sia.readUInt8(),
    email: sia.readString16(),
    active: sia.readBool(),
  };
}
package schema

import sia "github.com/TimeleapLabs/go-sia/v2/pkg"

type User struct {
  Name   string `json:"name"`
  Age    uint8  `json:"age"`
  Email  string `json:"email"`
  Active bool   `json:"active"`
}

func (u *User) Sia() sia.Sia {
  s := sia.New()
  s.AddString8(u.Name)
  s.AddUInt8(u.Age)
  s.AddString16(u.Email)
  s.AddBool(u.Active)
  return s
}

func (u *User) FromSia(s sia.Sia) *User {
  u.Name = s.ReadString8()
  u.Age = s.ReadUInt8()
  u.Email = s.ReadString16()
  u.Active = s.ReadBool()
  return u
}
from sia import Sia

class User():
    def __init__(self, name: str, age: int, email: str, active: bool):
        self.name = name
        self.age = age
        self.email = email
        self.active = active

    def encode(self, sia: Sia) -> Sia:
        sia.add_string8(self.name)
        sia.add_uint8(self.age)
        sia.add_string16(self.email)
        sia.add_bool(self.active)
        return sia

    @classmethod
    def decode(cls, sia: Sia) -> "User":
        return cls(
            name=sia.read_string8(),
            age=sia.read_uint8(),
            email=sia.read_string16(),
            active=sia.read_bool(),
        )
// user.hpp
#pragma once
#include <sia/sia.hpp>
#include <string>
#include <memory>

struct User {
  std::string name;
  uint8_t age;
  std::string email;
  bool active;
};

std::shared_ptr<sia::Sia> encodeUser(User user);
User decodeUser(std::shared_ptr<sia::Sia> sia);
// user.cpp
#include "user.hpp"

std::shared_ptr<sia::Sia> encodeUser(User user) {
  auto s = sia::New();
  s->AddString8(user.name);
  s->AddUInt8(user.age);
  s->AddString16(user.email);
  s->AddBool(user.active);
  return s;
}

User decodeUser(std::shared_ptr<sia::Sia> sia) {
  User user;
  user.name = sia->ReadString8();
  user.age = sia->ReadUInt8();
  user.email = sia->ReadString16();
  user.active = sia->ReadBool();
  return user;
}

CLI Commands

sia compile

Compile a .sia file to a target language:

sia compile <file> [options]
OptionDescription
-s, --stringPrint generated code to stdout
-o, --output <file>Write generated code to file
-e, --extension <ext>Target language: ts, go, py, cpp

If you don't specify -e, the compiler infers the target from the output file extension. If there's no extension, it auto-detects by looking for project files (tsconfig.json for TypeScript, go.sum for Go, pyproject.toml for Python, CMakeLists.txt for C++).

sia ir

Compile a .sia file and output the intermediate representation (JSON):

sia ir <file> [options]
OptionDescription
-s, --stringPrint formatted JSON to stdout
-o, --output <file>Write JSON to file

This is useful for debugging schemas or building custom tooling on top of the IR.

Using the Generated Code

The generated code is ready to import and use — no glue code required:

import { Sia } from "@timeleap/sia";
import { encodeUser, decodeUser, type User } from "./user";

const alice: User = {
  name: "Alice",
  age: 30,
  email: "alice@example.com",
  active: true,
};

// Encode to bytes
const bytes = encodeUser(new Sia(), alice).toUint8Array();

// Decode from bytes
const decoded = decodeUser(new Sia(bytes));
console.log(decoded.name); // "Alice"
alice := User{Name: "Alice", Age: 30, Email: "alice@example.com", Active: true}

// Encode to bytes
bytes := alice.Sia().Bytes()

// Decode from bytes
var decoded User
decoded.FromSia(sia.NewFromBytes(bytes))
fmt.Println(decoded.Name) // "Alice"
alice = User(name="Alice", age=30, email="alice@example.com", active=True)

# Encode to bytes
s = Sia()
alice.encode(s)
raw = s.content

# Decode from bytes
decoded = User.decode(Sia(raw))
print(decoded.name)  # "Alice"
User alice{"Alice", 30, "alice@example.com", true};

// Encode to bytes
auto encoded = encodeUser(alice);

// Decode from bytes
auto decoded = decodeUser(sia::NewFromBytes(encoded->Bytes()));
std::cout << decoded.name << std::endl; // "Alice"

For a complete walkthrough including sending data over the wire and working with nested schemas, see the Schema Quick Start.

Sections

Syntax Reference

Complete reference for the .sia schema language: types, fields, options, and comments.

Code Generation

How the compiler generates code for each language, with full output examples.

Plugins & RPC

Define RPC plugins with methods, timeouts, and fees for the Timeleap network.

VS Code Extension

Syntax highlighting for .sia files in VS Code.

Repository