browsermesh
browsermesh is peer-to-peer mesh networking for browser environments: cryptographic identity (Ed25519), CRDTs for state that merges instead of conflicting, capability-based trust and access control, a BSD-socket-style virtual network, and the higher-level building blocks — transport, sync, discovery, and an application runtime — that sit on top.
npm install @johnhenry/browsermesh-primitives<!-- In <head>, before any <script type="module"> or modulepreload. --><script type="importmap"> { "imports": { "@johnhenry/browsermesh-primitives": "https://cdn.jsdelivr.net/npm/@johnhenry/[email protected]/src/index.mjs" } }</script><script type="module"> import * as browsermeshPrimitives from "@johnhenry/browsermesh-primitives";</script>That single install gets you identity, wire format, CRDTs, capabilities, trust, and ACLs with zero dependencies. Everything else in the family builds on it.
Why ten packages under one scope
Section titled “Why ten packages under one scope”This isn’t ten libraries that happened to end up together — it’s one family, consolidated. Three packages (primitives, netway, pod) were already real, independent, publicly-published repos. The other seven (core, transport, sync, discovery, apps, kernel, embed) were extracted from a private monorepo (clawser), where they’d been manually npm published once each, unscoped, with no CI ever touching them again. All ten now live in one johnhenry/browsermesh monorepo (npm workspaces + Turborepo), publish under @johnhenry/browsermesh-*, and restart at version 0.0.0 — a new address, a new era, not a maturity signal. browsermesh-embed also carries a rename: it was clawser-embed before extraction, renamed specifically so a public package wouldn’t carry the name of a private product. Its README still exports ClawserEmbed as a backward-compatible alias of EmbeddedPod — that’s why the name survives inside the code even though it’s gone from the package name.
The ten packages
Section titled “The ten packages”| Package | What it does | Depends on |
|---|---|---|
@johnhenry/browsermesh-primitives |
Wire format, Ed25519 identity, CRDTs, capabilities, trust, ACL | (nothing) |
@johnhenry/browsermesh-netway |
BSD-socket-style virtual networking (streams, datagrams, DNS, policy) | (nothing) |
@johnhenry/browsermesh-pod |
Pod base class: identity, discovery, peer messaging for any execution context | primitives |
@johnhenry/browsermesh-embed |
Thin widget embedding a Pod-backed agent workspace into any web page | pod |
@johnhenry/browsermesh-core |
Identity, crypto, peer management, and trust layer | primitives |
@johnhenry/browsermesh-transport |
WebSocket/WebRTC/WebTransport adapters, stream multiplexing | primitives |
@johnhenry/browsermesh-sync |
CRDT/delta sync, file transfer, real-time collaboration | primitives |
@johnhenry/browsermesh-discovery |
DHT, peer discovery, naming, swarm coordination | primitives |
@johnhenry/browsermesh-apps |
Application layer: marketplace, chat, payments, mesh-native storage, serverless sites/functions, compute orchestration, agent tools | primitives, sync (required); core, transport, discovery, kernel, netway, andbox (optional) |
@johnhenry/browsermesh-kernel |
Capability-secure browser microkernel: resource handles, IPC, tracing, chaos engineering | (nothing) |
Three packages are genuinely standalone: primitives, netway, and kernel ship zero npm dependencies each, and none of them declares a dependency on another. Everything else in the mesh/app stack depends on primitives, directly or transitively — the kernel is a deliberately separate concern (a browser microkernel, not a mesh peer).
Cross-package dependencies are peer dependencies with a bounded range
Section titled “Cross-package dependencies are peer dependencies with a bounded range”Every package that depends on another package in this family declares it as a peerDependencies entry — not a regular dependencies entry — with a range of the form >=x <1.0.0, where x is the oldest release the dependent is known to work with. As of the 2026-10-07 releases:
| Package | Peer dependencies |
|---|---|
pod 0.0.3 |
primitives >=0.2.0 <1.0.0 |
core 0.6.0 |
primitives >=0.2.0 <1.0.0; apps >=0.4.0 <1.0.0 (optional) |
transport 0.3.3, sync 0.2.1, discovery 0.0.6 |
primitives >=0.2.0 <1.0.0 |
apps 0.11.0 |
primitives >=0.2.0 <1.0.0 and sync >=0.0.0 <1.0.0 (required); core >=0.5.0, transport >=0.1.0, discovery >=0.0.1, kernel >=0.0.0, netway >=0.0.0, @johnhenry/andbox >=0.0.1, each <1.0.0 (all optional) |
embed 0.1.0 |
pod >=0.0.0 <1.0.0 |
primitives 0.2.0, kernel 0.2.0, netway 0.0.1 |
(none) |
Two consequences: (1) a package’s peers are not part of its own install — see each page’s own install command, which lists every required peer explicitly; and (2) the lower bounds matter. primitives 0.2.0 changed the argument order of PodIdentity.verify(), so the peer ranges of the packages built on it now start at >=0.2.0 — an older primitives is flagged as a peer-range conflict instead of surfacing as a runtime surprise. The <1.0.0 upper bound means a future primitives 1.x will not be accepted silently either. Keep the family at matching versions deliberately.
Breaking in the 2026-10-07 releases: PodIdentity.verify() argument order
Section titled “Breaking in the 2026-10-07 releases: PodIdentity.verify() argument order”PodIdentity.verify(publicKey, signature, data) now takes the same order as crypto.subtle.verify; it used to take (publicKey, data, signature). The old order throws a TypeError rather than returning false. See primitives for the details, and the application layer for the callbacks you pass to apps.
Node versions
Section titled “Node versions”The packages that sit on primitives — primitives, pod, core, transport, sync, discovery, and apps — each declare "engines": { "node": ">=26.0.0" }. kernel and netway declare ">=24.0.0", and so does embed (0.1.0). Nothing in the mesh stack is tested against, or expected to work on, a Node major earlier than its floor.
The pages here
Section titled “The pages here”- Primitives & networking — wire format, identity, CRDTs, capabilities, trust, ACL, and the virtual BSD-socket network built without depending on anything
- Pod & embed — the execution-context base class (window, iframe, worker, service worker) and the widget that embeds an agent workspace on top of it
- Core services — identity/keyring/trust (
core), transport adapters (transport), CRDT/delta sync (sync), and DHT/discovery (discovery) - Application layer — marketplace, chat, payments, mesh-native storage (CloudStorage/MeshKv), serverless sites/functions, compute orchestration, and agent tooling built on the four services above
- Kernel — the standalone capability-secure microkernel, unrelated to mesh networking except by shared origin
Source: github.com/johnhenry/browsermesh