Plugins & RPC
The .sia schema language supports plugin definitions for building RPC (Remote Procedure Call) endpoints on the Timeleap network. A plugin groups related methods that can be called over the network.
Plugin Syntax
plugin swiss.timeleap.isWizard.v1 as Sorcery {
method isWizard(timeout = 5000) {
age uint8
name string8
} returns {
isWizard bool
message string8
}
}
Plugin Name
The plugin name is a dot-delimited identifier that uniquely identifies it on the Timeleap network:
swiss.timeleap.isWizard.v1
Convention: {region}.{org}.{name}.{version}
Alias (as)
The as clause provides a short name used as the generated class name:
plugin swiss.timeleap.isWizard.v1 as Sorcery { ... }
If omitted, the compiler auto-generates a PascalCase name from the plugin identifier.
Methods
Each method has a name, optional parameters (type options), input fields, and return fields:
method methodName(timeout = 5000, fee = 100, currency = "TLP") {
// input fields
} returns {
// output fields
}
Method Options
| Option | Type | Default | Description |
|---|---|---|---|
timeout | Number (ms) | 5000 | How long to wait for a response |
fee | Number | 0 | Fee for calling this method |
currency | String | "TLP" | Currency for the fee |
Schema References as Parameters
Instead of inline field definitions, methods can reference existing schemas:
schema WizardRequest {
age uint8
name string8
}
schema WizardResponse {
isWizard bool
message string8
}
plugin swiss.timeleap.isWizard.v1 as Sorcery {
method isWizard(timeout = 5000) WizardRequest returns WizardResponse
}
Code Generation
TypeScript is the only language with full plugin code generation. The compiler produces a class with:
- A
connectstatic factory method - Lazy-cached method instances via a
Map - Async methods that serialize parameters, invoke the RPC, and deserialize the response
import { Sia } from "@timeleap/sia";
import { Client, Function } from "@timeleap/client";
export class Sorcery {
private methods: Map<string, Function> = new Map();
private pluginName = "swiss.timeleap.isWizard.v1";
constructor(private client: Client) {}
static connect(client: Client): Sorcery {
return new Sorcery(client);
}
private getMethod(
method: string,
timeout: number,
fee: { currency: string; amount: number },
): Function {
if (!this.methods.has(method)) {
this.methods.set(
method,
this.client.method({
plugin: this.pluginName,
method,
timeout,
fee,
}),
);
}
return this.methods.get(method)!;
}
public async isWizard(
sia: Sia,
age: number,
name: string[],
): Promise<{
isWizard: boolean;
message: string;
}> {
sia.addUInt8(age);
sia.addArray8(name, (s: Sia, v) => sia.addString8(v));
const method = this.getMethod("isWizard", 5000, {
currency: "TLP",
amount: 0,
});
const response = await method.populate(sia).invoke();
const respIsWizard = response.readBool();
const respMessage = response.readString8();
return {
isWizard: respIsWizard,
message: respMessage,
};
}
}
Usage
import { Client } from "@timeleap/client";
import { Sia } from "@timeleap/sia";
import { Sorcery } from "./schema";
const client = new Client(/* connection config */);
const sorcery = Sorcery.connect(client);
const sia = new Sia();
const result = await sorcery.isWizard(sia, 25, ["Gandalf"]);
console.log(result.isWizard); // true
console.log(result.message); // "You shall pass!"
Multiple Methods
A plugin can have multiple methods:
plugin swiss.timeleap.math.v1 as MathService {
method add(timeout = 3000) {
a int32
b int32
} returns {
result int32
}
method multiply(timeout = 3000) {
a int32
b int32
} returns {
result int64
}
method divide(timeout = 5000, fee = 10) {
numerator int64
denominator int32
} returns {
quotient int64
remainder int32
}
}
Each method becomes a separate async method on the generated class.