Extend the live smoke: when a registered identity is present (its sign_pub added
to the bus allowlist), assert the SAME SDK that a fresh identity gets rejected with
is now ACCEPTED — control plane no longer 401s and the nats.ws data-plane
connection succeeds. Verified 2026-06-14 against the 3-node cluster: random
identity -> 401 / 'authorization violation'; registered identity -> 403 'not a
member of this room' / connected=true. The allowlist is the only gate; the SDK
speaks both planes correctly end-to-end. Issue 0001, Phase 3.
A network smoke (self-skips unless BUS_HTTP/BUS_WS are set) that points the SDK
at the live 3-node cluster. With a fresh, unregistered identity it asserts BOTH
planes reject with an AUTHORIZATION error (not a signature/protocol error),
proving the SDK speaks the control plane (signed canonical request) and the data
plane (nats.ws + nkey) correctly end-to-end. Verified 2026-06-14 against datardos:
control-plane 401 'identity not authorized', data-plane 'authorization violation'.
Issue 0001, Phase 3.
Second half of the browser-native bus SDK (issue 0001, Phase 1), making uniweb a
peer of the bus in its own right (like unibus_android) without the Go gateway:
- busauth.ts: NATS user nkey from the Ed25519 key (base32 + crc16, no nkeys dep)
and control-plane request signing (CanonicalRequest + X-Unibus-* headers).
- room.ts: Policy / Room types (ModeNATS, ModeMatrix).
- client.ts: the pure room ENVELOPE (sealRoomMessage/openRoomMessage — AEAD with
the subject as AAD, Ed25519 sign, drop on verify/decrypt failure), a transport-
agnostic BusClient, and a signed ControlPlane HTTP client (fetch room/key/members,
open the sealed room key locally).
- wstransport.ts: concrete nats.ws WebSocket transport (validated E2E in Phase 3).
- index.ts: public SDK surface.
Parity pinned by vectors from unibus cmd/busvectors (extended with nkey + signed
control-request vectors): 19/19 green. The user's private key signs everything in
the browser and is never sent to any server. Bumps uniweb to 0.2.0.
Remaining for Phase 1 completion: the live nats.ws connection + control-plane,
which need a running unibus with the WebSocket listener — exercised in Phase 3.
First half of the browser-native bus SDK (issue 0001, Phase 1):
- crypto.ts: Ed25519 sign/verify (@noble), ChaCha20-Poly1305 AEAD (@noble),
endpoint id (sha256+base64url), and the anonymous sealed box for room-key
distribution. The sealed-box nonce is BLAKE2b-192 over ephPub||recipientPub,
matching Go's nacl/box.SealAnonymous (NOT SHA-512) so a Go-sealed key opens here.
- frame.ts: the Frame wire format, reproducing Go encoding/json byte-for-byte —
struct field order, omitempty rules, base64-std byte fields, and the default
HTML escaping (<, >, &, U+2028/U+2029) — plus sign/verify over canonical bytes.
vectors.test.ts checks all of it against the golden vectors generated by unibus
cmd/busvectors. 11/11 green: endpoint id, Ed25519 (incl. frame signature),
AEAD seal+open, sealed box open + round-trip, and frame signing-bytes + wire
marshal. This pins cross-language interop with Go/Kotlin peers.
Adds @noble/ciphers, tweetnacl (runtime) and vitest (dev).
Golden vectors generated by unibus cmd/busvectors: the contract the TypeScript
bus SDK must match byte-for-byte (Ed25519 sign, ChaCha20-Poly1305 AEAD, sealed
box, Frame wire format). Issue 0001, Phase 0.
Extracted from unibus v0.13.0: the chat SPA (web/, React+Mantine, per-user
BIP39 wallet) and the web gateway (cmd/webgw, REST+SSE) that acts as a bus
peer for the browser. Consumes unibus as a Go module via replace => ../unibus,
keeping its own replace fn-registry for the cybersecurity primitives.
go build/vet/test and pnpm build green in the new location.