Skip to content

Primitives & networking

@johnhenry/browsermesh-primitives and @johnhenry/browsermesh-netway are the two packages everything else either depends on or connects through. Both ship zero dependencies and pure ES modules — they run identically in a browser or Node.js.

Terminal window
npm install @johnhenry/browsermesh-primitives
import { PodIdentity, VectorClock, ORSet, CapabilityToken, ACLEngine } from '@johnhenry/browsermesh-primitives'
// Ed25519 identity
const identity = await PodIdentity.generate()
console.log(identity.podId) // base64url-encoded SHA-256 of the public key
const data = new TextEncoder().encode('hello mesh')
const sig = await identity.sign(data)
await PodIdentity.verify(identity.keyPair.publicKey, data, sig)
// CRDTs merge across peers instead of conflicting
const clockA = new VectorClock()
clockA.increment('node-a')
const clockB = new VectorClock()
clockB.increment('node-b')
const merged = clockA.merge(clockB)
const set = new ORSet()
set.add('item', identity.podId)
set.has('item') // true
  • IdentityPodIdentity (Ed25519 keypair, sign/verify), derivePodId(publicKey)
  • Wire formatmessageTypeRegistry, encodeMeshMessage(msg) / decodeMeshMessage(bytes)
  • CapabilitiesCapabilityToken (scoped, with expiry), parseScope/matchScope
  • TrustcreateTrustEdge, computeTransitiveTrust(edges, source, target) — a weighted trust graph, not just a boolean allow-list
  • ACLACLEngine, Permission, AccessGrant, matchResourcePattern (glob-style)
  • CRDTsVectorClock, LWWRegister, GCounter, PNCounter, ORSet, RGA (replicated growable array), LWWMap. All support merge(), toJSON(), fromJSON().
  • Test utilitiesDeterministicRNG, LocalChannel/createLocalChannelPair(), TestMesh — useful if you’re testing code that consumes this package without standing up a real mesh

Previously published, unscoped, as [email protected] — a real standalone repo with its own history, not extracted from a private monorepo. Imported into the @johnhenry scope as part of the browsermesh consolidation; version restarts at 0.0.0.

Terminal window
npm install @johnhenry/browsermesh-netway

BSD-socket-like abstractions — StreamSocket (TCP-like), DatagramSocket (UDP-like), Listener — running entirely in-memory, or proxied through a remote gateway.

import { VirtualNetwork, CAPABILITY } from '@johnhenry/browsermesh-netway'
const net = new VirtualNetwork()
const listener = await net.listen('mem://localhost:8080')
const client = await net.connect('mem://localhost:8080')
const server = await listener.accept()
await client.write(new TextEncoder().encode('hello'))
const chunk = await server.read() // Uint8Array: "hello"
// Scoped policy enforcement
const sandbox = net.scope({ capabilities: [CAPABILITY.LOOPBACK] })
await sandbox.connect('mem://localhost:8080') // allowed
// sandbox.connect('tcp://example.com:80') // throws PolicyDeniedError

Backends — this is where “virtual” stops meaning “fake”

Section titled “Backends — this is where “virtual” stops meaning “fake””

net.listen/net.connect dispatch on URL scheme to a backend, and the backend is what determines whether traffic actually leaves the process:

  • LoopbackBackendmem:// and loop://, purely in-memory
  • GatewayBackendwsh-proxied, for real TCP/UDP/DNS. This is the integration point with @johnhenry/wsh: netway’s socket API stays the same, but traffic goes out over wsh’s remote command/tunnel transport.
  • ServiceBackendsvc:// scheme, routes through a service registry
  • FsServiceBackend — filesystem-backed service routing
  • ChaosBackendWrapper — wraps any of the above with fault injection (latency, drops, partitions) — useful for testing reconnect/retry logic without a real flaky network

Knowing which backend a given scheme resolves to matters: mem://localhost:8080 and tcp://example.com:80 look like the same kind of address but have completely different trust and reachability implications, and nothing about the connect() call site tells you which backend you’re on unless you check the scheme.

Previously published, unscoped, as [email protected] — also a real standalone repo. Version restarts at 0.0.0 under the @johnhenry scope.