Skip to content

Commit 951b63d

Browse files
committed
feat: initial telemachus typescript client
Core client with REST, batch datalink, and WebSocket streaming APIs. Generated typed accessors for all 520 API keys across 27 categories. Framework wrappers: - React (hooks + context provider) - Svelte (stores, compatible with v4 & v5) - Vue 3 (composables + provide/inject) - Open MCT (telemetry source plugin) Tooling: - Mock server for testing without KSP - Schema sync from upstream CI/CD - Conventional commits (commitlint + husky) - CI/CD with npm publish on tag
0 parents  commit 951b63d

20 files changed

Lines changed: 6269 additions & 0 deletions

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: ["**"]
6+
tags: ["v*"]
7+
pull_request:
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: oven-sh/setup-bun@v2
16+
with:
17+
bun-version: latest
18+
19+
- run: bun install --frozen-lockfile
20+
- run: bun run build
21+
22+
publish:
23+
needs: build
24+
if: startsWith(github.ref, 'refs/tags/v')
25+
runs-on: ubuntu-latest
26+
permissions:
27+
contents: read
28+
id-token: write
29+
steps:
30+
- uses: actions/checkout@v4
31+
32+
- uses: oven-sh/setup-bun@v2
33+
with:
34+
bun-version: latest
35+
36+
- run: bun install --frozen-lockfile
37+
- run: bun run build
38+
39+
- uses: actions/setup-node@v4
40+
with:
41+
node-version: "22"
42+
registry-url: "https://registry.npmjs.org"
43+
44+
- run: npm publish --provenance --access public
45+
env:
46+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.github/workflows/sync.yml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
name: Sync API Schema
2+
3+
on:
4+
workflow_dispatch:
5+
repository_dispatch:
6+
types: [telemachus-release]
7+
8+
jobs:
9+
sync:
10+
runs-on: ubuntu-latest
11+
permissions:
12+
contents: write
13+
pull-requests: write
14+
steps:
15+
- uses: actions/checkout@v4
16+
17+
- uses: oven-sh/setup-bun@v2
18+
with:
19+
bun-version: latest
20+
21+
- run: bun install --frozen-lockfile
22+
23+
- name: Sync schema from latest release
24+
run: bun run sync
25+
env:
26+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
27+
28+
- name: Regenerate and build
29+
run: |
30+
bun run generate
31+
bun run build
32+
33+
- name: Create PR if changed
34+
run: |
35+
if git diff --quiet; then
36+
echo "No schema changes"
37+
exit 0
38+
fi
39+
BRANCH="auto/sync-schema-$(date +%Y%m%d)"
40+
git checkout -b "$BRANCH"
41+
git add -A
42+
git commit -m "chore: sync api-schema from upstream release"
43+
git push -u origin "$BRANCH"
44+
gh pr create \
45+
--title "chore: sync API schema from upstream" \
46+
--body "Automated sync from TeleIO/Telemachus-1 latest release." \
47+
--base main
48+
env:
49+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
dist/

.husky/commit-msg

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
bun run commitlint

README.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
# telemachus-client
2+
3+
TypeScript client for the [Telemachus Reborn](https://github.com/TeleIO/Telemachus-1) KSP telemetry API. Covers all three transport layers — REST, batch datalink, and WebSocket streaming — with fully typed accessors generated from the API schema.
4+
5+
## Install
6+
7+
```bash
8+
bun add telemachus-client
9+
```
10+
11+
## Quick Start
12+
13+
```ts
14+
import { createClient } from "telemachus-client";
15+
16+
const ksp = createClient({ host: "http://localhost:8085" });
17+
```
18+
19+
### REST — Single Key
20+
21+
```ts
22+
const alt = await ksp.vessel.vAltitude(); // typed: number
23+
const pe = await ksp.orbit.oPeA(); // typed: number
24+
const mods = await ksp.system.aMods(); // typed: Record<string, unknown>
25+
26+
// Actions (POST)
27+
await ksp.flight.fStage();
28+
await ksp.flight.fSetThrottle(0.5);
29+
30+
// Raw key access
31+
const val = await ksp.query("v.altitude");
32+
await ksp.action("f.stage");
33+
```
34+
35+
### Batch Datalink
36+
37+
Query multiple keys in a single HTTP call:
38+
39+
```ts
40+
const data = await ksp.batch(["v.altitude", "o.PeA", "o.ApA"]);
41+
// → { "v.altitude": 12500, "o.PeA": 75000, "o.ApA": 120000 }
42+
```
43+
44+
With scaling (for embedded controllers):
45+
46+
```ts
47+
const data = await ksp.batch(
48+
["v.altitude", "o.PeA"],
49+
{ precision: 2, int: true }
50+
);
51+
```
52+
53+
Per-key pipe modifiers via `batchRaw`:
54+
55+
```ts
56+
const data = await ksp.batchRaw({
57+
alt: "v.altitude|precision:2|int",
58+
throttle: "f.setThrottle[512]|scale:0,1023",
59+
});
60+
```
61+
62+
### WebSocket Streaming
63+
64+
```ts
65+
const stream = ksp.stream({
66+
subscribe: ["v.altitude", "o.PeA"],
67+
rate: 200,
68+
});
69+
70+
stream.on((data) => {
71+
console.log(data["v.altitude"], data["o.PeA"]);
72+
});
73+
74+
// Dynamic subscription
75+
stream.subscribe("v.verticalSpeed");
76+
stream.unsubscribe("o.PeA");
77+
stream.setRate(100);
78+
79+
// Cleanup
80+
stream.close();
81+
```
82+
83+
Auto-reconnects with exponential backoff by default. Disable with `reconnect: false`.
84+
85+
## Scaling (Embedded Controllers)
86+
87+
For integer-only boards (Pico, MicroBlocks, etc.), use scaling options on any endpoint:
88+
89+
```ts
90+
// REST with scaling
91+
const val = await ksp.queryScaled("v.altitude", [], {
92+
precision: 2,
93+
int: true,
94+
});
95+
// 12345.678 → 1234568 (divide by 100 on board)
96+
97+
// Input scaling for actions
98+
const val = await ksp.queryScaled("f.setThrottle", [512], {
99+
scale: [0, 1023],
100+
});
101+
// Maps 10-bit ADC value to 0.0–1.0
102+
```
103+
104+
## API Categories
105+
106+
All 520 API keys are organized into typed accessor groups:
107+
108+
| Accessor | Keys | Example |
109+
|----------|------|---------|
110+
| `ksp.vessel` | `v.*` | `vAltitude()`, `vVerticalSpeed()` |
111+
| `ksp.orbit` | `o.*` | `oPeA()`, `oApA()`, `oInclination()` |
112+
| `ksp.flight` | `f.*` | `fSetThrottle(n)`, `fStage()` |
113+
| `ksp.body` | `b.*` | `bName(id)`, `bRadius(id)` |
114+
| `ksp.resource` | `r.*` | `rGetCurrentAmount(name)` |
115+
| `ksp.maneuver` | `m.*` | `mDeltaV()`, `mTimeTo()` |
116+
| `ksp.target` | `tar.*` | `tarName()`, `tarDistance()` |
117+
| `ksp.docking` | `dock.*` | `dockAngle()` |
118+
| `ksp.navigation` | `n.*` | `nHeading()`, `nPitch()` |
119+
| `ksp.system` | `a.*` | `aApi()`, `aMods()` |
120+
121+
Mod-dependent keys (MechJeb, FAR, Principia, etc.) are included and documented — check `a.mods` at runtime to see what's available.
122+
123+
## Key Metadata
124+
125+
Access key metadata at runtime:
126+
127+
```ts
128+
import { KEY_META } from "telemachus-client";
129+
130+
KEY_META["v.altitude"];
131+
// { description: "Altitude", units: "m", isAction: false, plotable: true, category: "vessel", returnType: "double" }
132+
```
133+
134+
## Regenerating Types
135+
136+
When the upstream API schema changes:
137+
138+
```bash
139+
cp ../Telemachus-1/docs/api-schema.json tools/
140+
bun run generate
141+
bun run build
142+
```
143+
144+
## License
145+
146+
MIT

0 commit comments

Comments
 (0)