Skip to content

Commit f62a5fb

Browse files
authored
Merge pull request #42 from tekwani/release/v0.3.0
release v0.3.0
2 parents b065a0c + c8e4a52 commit f62a5fb

144 files changed

Lines changed: 9488 additions & 4919 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.nvmrc

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

CHANGELOG.md

Lines changed: 260 additions & 227 deletions
Large diffs are not rendered by default.

README.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# MDK
22

3-
[![Release](https://img.shields.io/github/v/release/tetherto/mdk?display_name=tag&style=flat-square)](https://github.com/tetherto/mdk/releases/tag/v0.2.0)
3+
[![Release](https://img.shields.io/github/v/release/tetherto/mdk?display_name=tag&style=flat-square)](https://github.com/tetherto/mdk/releases/tag/v0.3.0)
44
[![MDK UI CI](https://img.shields.io/github/actions/workflow/status/tetherto/mdk/ui.yaml?branch=main&label=UI%20CI&style=flat-square&logo=github)](https://github.com/tetherto/mdk/actions/workflows/ui.yaml)
55
[![MDK Core CI](https://img.shields.io/github/actions/workflow/status/tetherto/mdk/core.yaml?branch=main&label=Core%20CI&style=flat-square&logo=github)](https://github.com/tetherto/mdk/actions/workflows/core.yaml)
66
[![CodeQL](https://github.com/tetherto/mdk/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/tetherto/mdk/actions/workflows/github-code-scanning/codeql)
@@ -12,7 +12,7 @@
1212

1313
MDK is under active development and is **not yet considered stable**.
1414

15-
Current release: [v0.2.0](https://github.com/tetherto/mdk/releases/tag/v0.2.0).
15+
Current release: [v0.3.0](https://github.com/tetherto/mdk/releases/tag/v0.3.0).
1616

1717
## Table of Contents
1818

@@ -130,10 +130,10 @@ leverage the packages provided for React (Vue, Svelte, and Web Components on the
130130

131131
## Releases
132132

133-
The latest development code is available on the [`main`](https://github.com/tetherto/mdk/tree/main) branch. MDK follows [Semantic Versioning 2.0.0](https://semver.org/): `0.y.z` versions are initial development (public API not stable until `1.0.0`).
133+
The latest development code is available on the [`main`](https://github.com/tetherto/mdk/tree/main) branch. MDK follows [Semantic Versioning 2.0.0](https://semver.org/): `0.y.z` versions are initial development (public API not stable until `1.0.0`); `1.0.0` and above denote a stable public API.
134134

135-
- [`/docs/reference/release-notes/`](./docs/reference/release-notes)
136-
- Full [`CHANGELOG.md`](./CHANGELOG.md)
135+
Releases have notes [`docs/reference/release-notes/](docs/reference/release-notes/) and the full version history is
136+
detailed in the [`CHANGELOG.md`](CHANGELOG.md).
137137

138138
## Get started
139139

backend/core/app-node/README.md

Lines changed: 106 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,28 @@
1-
# @tetherto/mdk-app-node
1+
# App Node
22

3-
The **App Node** is the mandatory gateway between the client-facing world (UI, AI agents) and the ORK kernel. It is a Fastify-based HTTP/WebSocket server that handles authentication, RBAC, fleet aggregation, and MCP endpoint exposure.
3+
## Overview
44

5-
UI and AI agents never connect to ORK directly. All traffic flows through the App Node.
5+
[App Node](../../../docs/concepts/stack/app-node.md), `@tetherto/mdk-app-node`, wraps [`@tetherto/mdk-client`](../client/README.md)
6+
and delivers an authenticated HTTP, WebSocket, and MCP interface for consumers that need those capabilities.
7+
It handles authentication, RBAC, fleet aggregation, and MCP endpoint exposure on top of the [ORK kernel](../ork/README.md).
8+
For use cases that do not need the App Node's HTTP surface, RBAC, or plugin system, see
9+
[Use an alternative gateway](../../../docs/concepts/stack/app-node.md#use-an-alternative-gateway).
610

7-
## Quick Start
11+
> [!TIP]
12+
> New to the App Node? Read the [App Node concept page](../../../docs/concepts/stack/app-node.md).
13+
> Ready to run it? Follow the [run guide](../../../docs/how-to/app-node/run.md).
814
9-
The easiest way to start the App Node is through `@tetherto/mdk`:
15+
> [!NOTE]
16+
> The App Node connects to ORK via [`@tetherto/mdk-client`](../client/README.md). While
17+
> `startAppNode()` currently accepts one ORK endpoint — `ork`, `orkKey`, or `orkIpc`,
18+
> multi-site aggregation (a single App Node fronting several per-site ORK kernels via `mdk-client`) is
19+
> on the roadmap.
1020
11-
```js
12-
const { getOrk, startAppNode } = require('@tetherto/mdk')
13-
14-
const ork = await getOrk()
15-
const server = await startAppNode({ ork, port: 3000, noAuth: true })
16-
// HTTP server is up at http://localhost:3000
17-
```
18-
19-
For production (with OAuth2):
20-
```js
21-
const server = await startAppNode({
22-
ork,
23-
port: 3000,
24-
auth: {
25-
h0: { method: 'google', credentials: { client: { id: '...', secret: '...' } }, users: ['admin@example.com'] }
26-
}
27-
})
28-
```
29-
30-
## Responsibilities
31-
32-
- **Authentication:** OAuth2 via Google / Microsoft. JWT validation on all routes. Session management.
33-
- **RBAC:** Role-based access control guards all ORK operations.
34-
- **Fleet Aggregation:** Queries multiple workers via ORK and merges responses (site hashrate, average temperature, cross-rack efficiency).
35-
- **ORK Proxy:** Forwards device commands and telemetry queries to ORK via `@tetherto/mdk-client` (IPC by default).
36-
- **WebSocket:** Real-time telemetry subscriptions for the UI.
37-
- **MCP Endpoint:** AI agent integration via the Model Context Protocol.
21+
## HTTP API overview
3822

39-
## HTTP API Overview
23+
The App Node exposes two categories of REST routes:
4024

41-
The App Node exposes REST routes for:
25+
**Core ORK-proxy routes** — hardcoded in `workers/lib/server/routes/`, always present:
4226

4327
| Category | Endpoints |
4428
|----------|-----------|
@@ -51,13 +35,24 @@ The App Node exposes REST routes for:
5135
| Stats | Aggregated site statistics |
5236
| Health | Worker health status |
5337

54-
## WebSocket
38+
**Plugin routes** — loaded through the plugin system, extendable via `extraPluginDirs`:
39+
40+
| Plugin | Routes |
41+
|--------|--------|
42+
| `auth` | `/auth/userinfo`, `/auth/token`, `/auth/permissions`, `/auth/ext-data` |
43+
| `telemetry` | `/auth/metrics/*` (hashrate, consumption, efficiency, temperature, containers) |
44+
| `site-hashrate` | `/api/site/hashrate-history` |
45+
46+
The [plugin reference](../plugins/README.md) lists every default route, its method, auth requirement, and parameters.
47+
48+
## WebSocket subscriptions
5549

5650
Connect to `ws://localhost:3000/ws` for real-time telemetry subscriptions. Authentication is required in production mode.
5751

5852
## Configuration
5953

60-
Config files are written to `opts.root/config/facs/` by `startAppNode()`. Example files ship in `backend/core/app-node/config/facs/*.example`. Edit the generated files to persist your changes across restarts.
54+
Config files are written to `opts.root/config/facs/` by `startAppNode()`. Example files ship in `backend/core/app-node/config/facs/*.example`.
55+
Edit the generated files to persist your changes across restarts.
6156

6257
| File | Controls |
6358
|------|---------|
@@ -68,26 +63,69 @@ Config files are written to `opts.root/config/facs/` by `startAppNode()`. Exampl
6863
| `net.config.json` | IP assignment (DHCP facility) |
6964
| `logging.config.json` | Log level, format |
7065

71-
## ORK Connection
66+
## ORK connection
67+
68+
Two transports are available. Pass exactly one to `startAppNode()`:
69+
70+
**IPC (default — same host)**
7271

73-
The App Node connects to ORK over IPC (Unix socket) by default. The socket path is configured in `common.json`:
72+
The App Node dials ORK over a Unix socket. The default socket path is `os.tmpdir()/mdk/ork.sock`.
7473

7574
```json
7675
{ "orkIpc": "/tmp/mdk/ork.sock" }
7776
```
7877

79-
Override via `startAppNode({ orkIpc: '/custom/path.sock' })` or pass `orkIpc: false` to disable the MDK client (useful when testing without a live ORK).
78+
Override via `startAppNode({ orkIpc: '/custom/path.sock' })` or pass `orkIpc: false` to disable the MDK client
79+
(useful when testing without a live ORK).
80+
81+
**HRPC (cross-host)**
82+
83+
When ORK runs on a separate host, pass the ORK HRPC gateway public key. This selects the HRPC transport and disables IPC automatically:
84+
85+
```js
86+
await startAppNode({ orkKey: '<ork-gateway-pubkey-hex>' })
87+
```
88+
89+
Obtain the ORK gateway key with `ork.getPublicKey().toString('hex')` on the host running ORK, then share it with the App Node host.
90+
91+
Pre v1.0, ORK's `auth.whitelist` defaults to empty (any HRPC caller is admitted). When an allowlist is configured, the App Node's DHT
92+
public key must be added before the connection is accepted — see [ORK transports](../ork/README.md#transports).
8093

81-
## Security Model
94+
## Security model
8295

8396
- UI and AI agents authenticate via **JWT Bearer tokens**
84-
- ORK is protected by an HRPC **whitelist** — the App Node's public key must be in ORK's allowed list
85-
- Once whitelisted, ORK trusts all messages from the App Node implicitly; user-level auth is the App Node's responsibility
86-
- AI agents are treated as authenticated clients — they go through the same JWT/RBAC path as human API consumers
97+
- **ORK connection security** depends on the transport:
98+
- **IPC (same host, default)**: implicit trust — no allowlisting needed
99+
- **HRPC (remote ORK)**: ORK maintains an HRPC firewall; the App Node's DHT public key must be in ORK's `auth.whitelist`.
100+
See [ORK Transports](../ork/README.md#transports) and the [`auth-whitelist` example](../../../examples/backend/ork/auth-whitelist.js)
101+
for the key exchange pattern.
102+
- Once connected, ORK trusts all messages from the App Node implicitly; user-level auth is the App Node's responsibility
103+
- AI agents are treated as authenticated clients, going through the same JWT/RBAC path as human API consumers
87104

88-
## Extending the App Node
105+
## Extend the App Node
89106

90-
Add custom routes by passing `additionalRoutes` to `startAppNode()`:
107+
### Plugin system (recommended)
108+
109+
Pass plugin directories via `extraPluginDirs` to load additional routes at startup alongside the default plugins:
110+
111+
```js
112+
await startAppNode({
113+
ork,
114+
extraPluginDirs: [
115+
path.join(__dirname, 'plugins/my-metrics')
116+
]
117+
})
118+
```
119+
120+
Plugins receive `(req, services)` in every controller, where `services.mdkClient` and `services.dataProxy` give access to ORK
121+
and historical data without any protocol knowledge. The default plugins (`auth`, `telemetry`, `site-hashrate`) are loaded the same way.
122+
123+
The [plugin authoring guide](../../../docs/how-to/app-node/plugins.md) and the [plugin reference](../plugins/README.md) cover the full manifest schema, controller
124+
contract, services bag, and loader errors.
125+
126+
### Raw Fastify routes
127+
128+
For one-off handlers that do not need the plugin manifest format, pass `additionalRoutes` directly:
91129

92130
```js
93131
await startAppNode({
@@ -102,28 +140,36 @@ await startAppNode({
102140
})
103141
```
104142

105-
## Running Standalone
143+
These are registered as plain Fastify routes — no `services` injection, no manifest validation, no auth wiring.
106144

107-
```bash
108-
cd backend/core/app-node
109-
npm install
110-
npm run dev # Development mode on port 3000
111-
npm start # Production mode
112-
```
113-
114-
## Directory Layout
145+
## Directory layout
115146

116147
```
117148
app-node/
118149
├── workers/
119-
│ └── http.node.wrk.js # WrkServerHttp — Fastify worker
150+
│ ├── http.node.wrk.js # WrkServerHttp — Fastify worker, mounts plugins and routes
151+
│ └── lib/
152+
│ ├── plugin-loader.js # Loads mdk-plugin.json manifests, validates structure
153+
│ ├── plugin-adapter.js # Converts plugin routes to Fastify handlers, wires auth/cache
154+
│ ├── auth.js # JWT validation, OAuth2 callbacks
155+
│ ├── data.proxy.js # Historical data aggregation via worker tail-logs
156+
│ └── server/ # Raw Fastify route definitions (non-plugin routes)
120157
├── config/
121-
│ └── facs/ # Example config files (*.json.example)
122-
├── db/ # SQLite database files
123-
├── store/ # Hyperbee storage
158+
│ └── facs/ # Example config files (*.json.example)
159+
├── db/ # SQLite database files
160+
├── store/ # Hyperbee storage
124161
└── tests/
125162
├── unit/
126163
└── integration/
127-
├── api.test.js # HTTP route tests
128-
└── ws.test.js # WebSocket tests
164+
├── api.test.js # HTTP route tests
165+
└── ws.test.js # WebSocket tests
129166
```
167+
168+
## Next steps
169+
170+
- Understand the [App Node as a development surface](../../../docs/concepts/stack/app-node.md)
171+
- [Run the App Node](../../../docs/how-to/app-node/run.md)
172+
- [Add routes with the plugin system](../../../docs/how-to/app-node/plugins.md)
173+
- Browse the [default plugin route reference](../plugins/README.md)
174+
- See a complete [worked example](../../../examples/full-site/README.md)
175+
- Browse the [`startAppNode()` options](../mdk/README.md)

0 commit comments

Comments
 (0)