feat(nodes): add capability-based node compatibility negotiation (#350)

* feat(nodes): add capability-based node compatibility negotiation

Each Sencho instance now exposes /api/meta with its version and supported
capabilities. When the user switches nodes, the frontend fetches this
metadata and disables features the remote node doesn't support via a
CapabilityGate overlay. Version is shown in the node switcher dropdown
and connection test results.

- Backend: CapabilityRegistry with static capability list and fetchRemoteMeta helper
- Backend: /api/meta (public) and /api/nodes/:id/meta (auth) endpoints
- Frontend: NodeContext enhanced with per-node meta caching (5min TTL)
- Frontend: CapabilityGate component with typed Capability union
- Frontend: 13 features wrapped with capability gates
- Docs: node-compatibility.mdx + OpenAPI spec updates

* fix(nodes): revert to require() for package.json version reading

The static import fails in the Docker multi-stage build because the
root package.json is not copied into the backend-builder stage. The
require() call resolves at runtime when the file is available.
This commit is contained in:
Anso
2026-04-03 00:06:34 -04:00
committed by GitHub
parent ec23f8c4c2
commit ee75811e25
20 changed files with 468 additions and 45 deletions
+6 -3
View File
@@ -102,6 +102,7 @@
"features/global-observability",
"features/host-console",
"features/multi-node",
"features/node-compatibility",
"features/fleet-view",
"features/stack-labels",
"features/alerts-notifications",
@@ -145,9 +146,10 @@
"pages": [
"api-reference/overview",
{
"group": "Health",
"group": "Health & Meta",
"pages": [
"GET /api/health"
"GET /api/health",
"GET /api/meta"
]
},
{
@@ -210,7 +212,8 @@
"GET /api/nodes/{id}",
"PUT /api/nodes/{id}",
"DELETE /api/nodes/{id}",
"POST /api/nodes/{id}/test"
"POST /api/nodes/{id}/test",
"GET /api/nodes/{id}/meta"
]
},
{