@volter/conduit
v0.1.1
Published
Authenticated discovery and protocol bindings for environment services
Readme
Conduit
Authenticated discovery and authorized protocol bindings for environment services.
Phase 1, published as @volter/conduit 0.1. It has no UI, engine or mandatory daemon.
@volter/conduit/protocol, /client and /server are dependency-free ES modules
using Fetch APIs. Importing them starts nothing. The host embeds createHost()
and supplies authentication and service adapters. createClient() connects to
that host through a trusted credential-bearing fetch function.
The environment contract defines identity, discovery and scope. The implemented HTTP profile supports discovery, finite HTTP requests and release. The optional Node WebSocket proxy adds guarded ongoing connections; actual PTY product adapters remain outstanding. It does not yet implement automatic invalidation subscriptions, native file services, or provider deployment. Do not advertise a scoped service until its adapter enforces that scope.
import { createHost } from '@volter/conduit/server';
import { createNodeHandler } from '@volter/conduit/node';
import { createClient } from '@volter/conduit/client';
// the host: one service, its adapter enforcing the scope it grants
const host = createHost({
identity: { authorityId: 'my-host', environmentId: 'env-1', generation: String(Date.now()) },
label: 'My environment',
authenticate: async (request) => request.headers.get('authorization') === `Bearer ${token}` ? 'owner' : null,
services: [myService], // { id, describe(principal), authorize(principal, scope), handle({ request, path, grant }) }
});
http.createServer(createNodeHandler({ handle: host.handle, origin: 'https://env.example' })).listen(8080);
// a client: discover, bind by the protocol it needs, use the binding
const client = createClient({ baseUrl: 'https://env.example', trustedFetch: (url, init) => fetch(url, { ...init, headers: { authorization: `Bearer ${token}` } }) });
const descriptor = await client.refresh();
const binding = await client.bind('container', { protocol: descriptor.services[0].protocol });
const answer = await binding.request('/_ping');A binding lives for the host's bindingTtlMs (five minutes by default) and is
not renewed: a channel on it ends when it expires, and the client binds again.
/node-websocket needs ws (an optional peer dependency); the other entries need
nothing. The WebSocket proxy checks no Origin itself: an embedding that
authenticates upgrades by cookie must check Origin in its authenticate.
The broader design and ordered delivery are in the
integration specification.
The implementation queue is ROADMAP.md. Contract verification uses
real HTTP servers and filesystem bytes; run npm test inside an owned World.
Install locked development dependencies with npm ci; npm run check:types
checks a consumer against the public declarations. TypeScript is development-only.
Node hosts may pass createNodeHandler({handle: host.handle, origin}) from
@volter/conduit/node to Node's createServer. The embedding configures the
trusted external origin and owns listening, TLS/proxy policy and lifecycle.
The HTTP adapter uses Node built-ins; the separate /node-websocket entry uses
the installed ws dependency. TypeScript consumers of the Node entries
need Node types. Browser consumers keep using the Fetch-native entries.
