Copies the peer list
It calls GET /v1/peers on the starting peer. If your node has no peers yet, it saves that list. If it already has peers, it keeps its own list.
Build / Node guide
A node is your piece of the Stellarium network. It hosts your APIs, learns about everyone else's, and forwards requests to the right place. This guide takes you from an empty folder to a running node in a few steps.
Step 01
You will need three things before you start:
Resource type that describes the APIs your node hosts.Then install the node along with the packages your app imports directly:
npm install stellarium-ts fastify requestscriptStep 02
A resource is an object that RequestScript programs can call. Its path and name together make its full name, for example com.example.Weather. Each function lists its parameter types and return type, and its exec function runs right here in your process.
Call register before start. When you call start, the node creates its SQLite database, mounts the HTTP API, and starts listening.
import Fastify from "fastify";
import { StellariumNode } from "stellarium-ts";
import type { Resource } from "requestscript";
const weather: StellariumResource = {
metadata: {},
path: "com.example",
name: "Weather",
functions: [
{
name: "temperature",
parameters: [{ name: "city", type: "string" }],
returnType: "int32",
exec: async (args) => {
const city = args.find((arg) => arg.name === "city")?.value;
return city === "Oslo" ? 12 : 20;
},
},
],
};
const node = new StellariumNode();
await node.register(weather);
const fastify = Fastify({ logger: true });
await node.start(fastify, {
port: 3000,
// Omit this to run standalone. Set it to copy peers and resources
// from a node that is already up.
startingPeer: "http://127.0.0.1:3001",
});| Option | Default | What it does |
|---|---|---|
port | 3000 | The port Fastify listens on. |
startingPeer | none | The address of a peer to join through. Leave off the /v1 at the end. |
The node loads a .env file from your working directory automatically, so you can put these settings there.
| Variable | What it does |
|---|---|
BASE_URL | The public address of this node. Peers send resource calls to {BASE_URL}/v1/run/resource, so set it to something like http://127.0.0.1:3000. Don't include /v1. |
SIGNING_PRIVATE_KEY | Your ED25519 private key, base64url encoded. The node uses it to sign what it publishes to peers. |
SIGNING_PUBLIC_KEY | The matching ED25519 public key, base64url encoded. Peers use it to check your signatures. It must pair with the private key. |
API_KEY | A secret your clients must send as Authorization: Bearer <API_KEY> to run requests on this node. |
OPERATOR_URL | Only needed if you host priced resources. The operator address your node sends payment vouchers to. |
BASE_URL=http://127.0.0.1:3000
SIGNING_PRIVATE_KEY=<your base64url private key>
SIGNING_PUBLIC_KEY=<your base64url public key>
API_KEY=<a secret your clients send to this node>Don't have signing keys yet? Run this script to generate a pair:
node --input-type=module -e '
import { generateKeyPairSync } from "node:crypto";
const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
publicKeyEncoding: { type: "spki", format: "der" },
privateKeyEncoding: { type: "pkcs8", format: "der" },
});
console.log(JSON.stringify({
publicKey: publicKey.toString("base64url"),
privateKey: privateKey.toString("base64url"),
}, null, 2));
'The node keeps the peers and resources it learns about in a file called requestscript.db in your working directory. It is created the first time the node starts.
Step 03
A node with no startingPeer runs on its own. To join an existing network, set startingPeer to the address of a node that is already running. Once your node is listening, it does four things:
It calls GET /v1/peers on the starting peer. If your node has no peers yet, it saves that list. If it already has peers, it keeps its own list.
It calls GET /v1/resources and saves each resource along with the address of the node that hosts it.
It tells every peer in the network that it exists.
It tells the network about the resources you registered, so others can call them.
After that, requests just work. If a program asks for a resource registered on your node, your exec function runs locally. If it asks for one hosted somewhere else, your node forwards the request to that peer and hands back its answer.
Step 04
Every node exposes a small HTTP API under /v1.
| Route | Body | What it does |
|---|---|---|
GET /v1/ | none | Health check. Responds with { "hello": "world" }. |
GET /v1/peers | none | Lists the peers this node knows about. |
GET /v1/resources | none | Lists resources hosted here and resources learned from peers. Function code always stays on the node that hosts it. |
POST /v1/run | { "source": "..." } | Runs one RequestScript request. Requires your API_KEY. |
Send the script as the source field of a JSON body to /v1/run, with your API_KEY as a bearer token. The script must be a request.
curl -X POST http://127.0.0.1:3000/v1/run \
-H 'Content-Type: application/json' \
-H "Authorization: Bearer $API_KEY" \
-d '{"source": "request GetTemperature {\n const weather: com.example.Weather\n const reading = weather.temperature(city: \"Oslo\")\n return reading.value\n}"}'If it works, you get back a 200 with the result:
{ "returnValue": 12 }A missing or wrong API key returns a 401. If the script isn't a request, you get a 400 with { "error": "Invalid script" }. Anything else that goes wrong returns a 500. A resource call that fails does not fail the request: it comes back as an error value your script can check.
To learn more about writing scripts, read the RequestScript docs. For the full reference, see the stellarium-ts README.
Got a node running? Come say hi.
Meet the community →