Skip to content

TypeScript API Reference

The TypeScript bridge — type-safe passage between Mac and VM, because runtime errors at 3 AM are a lifestyle choice

The TypeScript config module at command-center/lib/config.ts provides typed access to the Sanctum instance configuration. It reads from the same ~/.sanctum/instance.yaml file as the shell library and is used by the command center dashboard and any Node.js tooling.

Same YAML. Same config. Same house. But now with type safety, because if your haus is going to be managed by code, that code should at least know the difference between a string and a number. The shell library makes no such promises.

import {
get,
getConfig,
isEnabled,
expand,
slug,
name,
vmSsh,
whoami,
isNode,
myNodeType,
nodeGet,
nodeSsh,
nodeSshTs,
nodeVmSsh,
getNodes,
getNodesByType,
isNodeOnline,
isNodeServiceEnabled,
nodeService,
nodeHub,
getSatellites,
} from './lib/config';

Read any value from the instance config by dot-notation path.

function get(keyPath: string): string | undefined
ParameterTypeDescription
keyPathstringDot-delimited path into the config
const port = get('services.gateway.port');
// "1977"
const vmIp = get('network.vm_ip');
// "10.10.10.10"
const tz = get('instance.timezone');
// "America/Montreal"

Return the entire parsed configuration object. The whole thing. Every detail your house knows about itself, in one typed object.

function getConfig(): SanctumConfig
const config = getConfig();
console.log(config.instance.name);
// "Manoir Nepveu"

Check whether a config path evaluates to true.

function isEnabled(keyPath: string): boolean
if (isEnabled('services.gateway.enabled')) {
console.log('Gateway is active');
}
if (isEnabled('services.signal_bridge.enabled')) {
// ...
}

Expand {{PLACEHOLDER}} tokens in a template string using config values. The same template engine as the shell side, but in TypeScript, where the curly braces feel more at haus.

function expand(template: string): string
const result = expand('SSH to {{network.vm_ip}} as {{users.vm}}');
// "SSH to 10.10.10.10 as ubuntu"

Return the instance slug.

function slug(): string
slug();
// "manoir-nepveu"

Return the human-readable instance name.

function name(): string
name();
// "Manoir Nepveu"

Return the SSH alias for the VM connection.

function vmSsh(): string
vmSsh();
// "openclaw"

Return the current node identity (read from ~/.sanctum/.node_id).

function whoami(): string
whoami();
// "manoir"

Check if the current machine matches a given node identifier.

function isNode(nodeId: string): boolean
if (isNode('manoir')) {
console.log('Running on the hub');
}

Return the node type of the current machine.

function myNodeType(): 'hub' | 'satellite' | 'mobile' | 'sensor'
myNodeType();
// "hub"

A union type for the kinds of places your house exists. The type system doesn’t judge. It just wants to know.


Read a config value for a specific node.

function nodeGet(nodeId: string, keyPath: string): string | undefined
ParameterTypeDescription
nodeIdstringNode identifier (e.g., "manoir", "chalet")
keyPathstringDot-delimited path within the node config
nodeGet('manoir', 'tailscale_ip');
// "100.112.178.25"
nodeGet('chalet', 'type');
// "satellite"
nodeGet('manoir', 'host');
// "192.168.1.10"

Return all node IDs defined in the config.

function getNodes(): string[]
getNodes();
// ["manoir", "chalet"]

Return node IDs filtered by type.

function getNodesByType(type: string): string[]
getNodesByType('hub');
// ["manoir"]
getNodesByType('satellite');
// ["chalet"]

Convenience function to return all satellite node IDs.

function getSatellites(): string[]
getSatellites();
// ["chalet"]

Return the node ID of the hub node.

function nodeHub(): string
nodeHub();
// "manoir"

Check if a node is reachable (async, uses ping/Tailscale check).

async function isNodeOnline(nodeId: string): Promise<boolean>
const online = await isNodeOnline('chalet');
if (online) {
console.log('Chalet is reachable');
}

Return the SSH connection string for a node over LAN.

function nodeSsh(nodeId: string): string
nodeSsh('manoir');

Return the SSH connection string for a node over Tailscale.

function nodeSshTs(nodeId: string): string
nodeSshTs('chalet');

Return the SSH connection string for the VM on a specific node.

function nodeVmSsh(nodeId: string): string
nodeVmSsh('manoir');

Check if a service is enabled on a specific node.

function isNodeServiceEnabled(nodeId: string, service: string): boolean
isNodeServiceEnabled('manoir', 'gateway');
// true
isNodeServiceEnabled('chalet', 'vm');
// false

Get a service config value for a node.

function nodeService(nodeId: string, service: string, key: string): string | undefined
nodeService('manoir', 'gateway', 'port');
// "1977"

The command center dashboard serves the instance config (with secrets excluded) at the /api/config endpoint:

server/index.ts
import { getConfig, slug } from '../lib/config';
app.get('/api/config', (req, res) => {
const config = getConfig();
// Strip secrets section before serving
const { secrets, ...safeConfig } = config;
res.json(safeConfig);
});

Both vite.config.ts and server/index.ts read ports, paths, and SSH targets from the config module rather than using hardcoded values:

vite.config.ts
import { get } from './lib/config';
export default defineConfig({
server: {
port: Number(get('services.dashboard.dev_port')) || 1111,
},
});