@easynet-run/node
v0.43.3
Published
EasyNet Axon Node.js SDK (sidecar-first with Dendrite bridge payload).
Readme
What is this?
This is the Node.js surface for Axon, a protocol-level control plane that treats agent capabilities as first-class network objects. Every ability you expose carries its own schema, trust posture, scheduling contract, and tenant isolation rules — enforced atomically at invocation time.
Axon collapses tenant isolation, rate limiting, policy evaluation, node selection, concurrency admission, and circuit breaking into a single atomic decision against the same state snapshot. No race window between policy check and routing.
The SDK ships a native Dendrite bridge binary (loaded via koffi) that provides protocol-complete Axon gRPC calls without gRPC codegen in JavaScript.
Install
npm install @easynet-run/nodePlatform / Native Bundle Notes
- The published npm artifact currently comes from the Linux x86_64 SDK pack, so the embedded native file is host-matched to that pack.
- If you need other native targets (iOS/Android/macOS/Linux arm64/Windows), use the target SDK pack from GitHub Releases:
sdk-packs-<target>.tar.gz- extract the
node/directory and install the*.tgzartifact from that directory.
- For local source development:
SDK_VERSION=<version>(optional; resolver checks this and then fallback0.1.0in the same root)EASYNET_DENDRITE_BRIDGE_LIBcan force an explicit native path.EASYNET_DENDRITE_BRIDGE_HOME=<pack-root>can be set to a shared extracted SDK pack path that containsnative/.- set
EASYNET_DENDRITE_BRIDGE_SOURCE=localif you want preset/CLI helpers to auto-probe local source-tree bridge artifacts. EASYNET_DENDRITE_BRIDGE_PLATFORM=ios|android|linux|windows|macosif host/build target mismatch (for example macOS host + iOS pack).
- For macOS-hosted iOS dev workflows, prefer a pack-native
.aand explicitEASYNET_DENDRITE_BRIDGE_LIBpath binding.
Target examples:
- macOS arm64:
sdk-packs-aarch64-apple-darwin.tar.gz - macOS x86_64:
sdk-packs-x86_64-apple-darwin.tar.gz - iOS arm64 simulator/device:
sdk-packs-aarch64-apple-ios.tar.gz - iOS x86_64 simulator:
sdk-packs-x86_64-apple-ios.tar.gz - Android arm64:
sdk-packs-aarch64-linux-android.tar.gz - Linux arm64:
sdk-packs-aarch64-unknown-linux-gnu.tar.gz - Linux x86_64:
sdk-packs-x86_64-unknown-linux-gnu.tar.gz - Windows x64:
sdk-packs-x86_64-pc-windows-msvc.tar.gz
Development
Runtime .js files and package-facing .d.ts files under src/ are generated locally from the TypeScript sources with tsc, but they are intentionally gitignored and must not be committed.
Edit src/**/*.ts, then run:
npm run build
npm run generated:checknpm pack and git-based installs run prepare/prepack, so published tarballs still include the generated runtime files.
Quick Start
Expose an ability
import { ability, serve } from "@easynet-run/node";
ability("easynet:///r/org/reg/agent.quote-bot/abilities/order.quote@1?tenant_id=tenant-test")
.handle(async ({ sku, qty = 1 }) => ({ sku, price: 19.9 * qty }))
.expose();
await serve("agent.quote-bot");Invoke an ability
import { client } from "@easynet-run/node";
const res = await client()
.tenant("tenant-test")
.ability("easynet:///r/org/reg/agent.quote-bot/abilities/order.quote@1?tenant_id=tenant-test")
.call({ sku: "A1", qty: 2 });call() returns business payload (result_json). Use callAny() or callRaw() for stream/media-oriented non-object payloads.
Bootstrap a local runtime behind NAT
import { startServer } from "@easynet-run/node";
const srv = await startServer(undefined, {
hub: "axon://hub.easynet.run:50084",
hubTenant: "tenant-test",
hubLabel: "alice-macbook",
});No public IP required — the local runtime connects outbound to the Hub and receives federated invocations over that channel.
Sub-exports
| Path | Purpose |
|---|---|
| @easynet-run/node/presets/remote-control | Remote device orchestration presets |
| @easynet-run/node/mcp | MCP stdio server and tool provider |
| @easynet-run/node/tool-adapter | Ability → LLM tool schema conversion |
Capabilities
Core Protocol
- Fluent builders —
.tenant()→.principal()→.ability()→.call()are immutable and chainable. - Native Dendrite bridge —
DendriteBridgeloads the platform C ABI via koffi; all Axon gRPC shapes (unary, server-stream, client-stream, bidi-stream) available without gRPC codegen. - Subject binding —
.principal(...)scopes invocation to a subject identity with automatic URI visibility mapping.
Ability Lifecycle
Full lifecycle management — not just invocation:
buildAbilityDescriptor()/exportAbility()— define and register abilities with schemasdeployToNode()— install + activate on target nodeslistAbilities()/invokeAbility()/uninstallAbility()discoverNodes()/executeCommand()/disconnectDevice()/drainDevice()buildDeployPackage()/deployPackage()— packaging and deployment workflows
MCP & A2A Protocols
- MCP server —
StdioMcpServerhosts JSON-RPC 2.0 tool endpoints over stdio. - MCP operations — deploy, list, call, and update MCP tools on remote nodes.
- A2A agent protocol — inter-agent discovery and task dispatch.
- Tool adapter —
AbilityToolAdapterconverts abilities to OpenAI/Anthropic/generic tool definitions; supports local handler registration with zero network overhead.
Voice & Media Signaling
First-class voice call lifecycle and transport negotiation (19+ FFI bindings):
- Call management: create, join, leave, end, watch events, report metrics
- Transport sessions: create, set description, add ICE candidates, refresh lease
- Media path updates and codec negotiation
Federation
startServer()spawns a local Axon runtime and joins the Hub — all traffic is outbound.- Federated node discovery and cross-network invocation dispatch.
- Preset status: the dedicated federation preset helper is currently Python-only; Node exposes federation through runtime bootstrap and transport-facing APIs.
Remote Control & Orchestration
- Subprocess template building, descriptor parsing, orchestrator factory.
- Ability dispatch workflows with bundle reading and media persistence.
- Deploy trace lifecycle tracking (
Phase→PhaseReceipt).
License
Apache-2.0 — see LICENSE.
