@communication-engine/core-sdk
v0.1.0-alpha.0
Published
Web SDK for Communication Engine — embedded comms for 3D experiences (Three.js + UE).
Readme
@communication-engine/core-sdk
Web SDK skeleton for Communication Engine — embedded comms for 3D experiences.
Phase 1 status
| Surface | Status |
| --------------------------------------------- | ----------------------------------------------------- |
| generateDpopKeyPair / generateDpopProof | WORKING — Phase 1 |
| CryptoEngine | stub — Phase 2 (Signal Protocol via libsignal-client) |
| ChatClient | stub — Phase 2 (1:1) / Phase 3 (group MLS) |
| CallClient | stub — Phase 3 (1:1 audio) / Phase 4 (group video) |
| PTTClient | stub — Phase 2 (sub-300ms thesis prover) |
| Spatializer | stub — Phase 2 (WebAudio PannerNode + AudioWorkletNode) |
| FileTransfer | stub — Phase 5 (DataChannel chunked) |
| WsClient | stub — Phase 2 (Phoenix Channels) |
| GroupCrypto interface + NotImplementedGroupCrypto | stub — Phase 2 (OpenMLS via WASM) |
Why ESM + CJS dual publish?
Host platforms vary. Web bundlers + Node ESM consumers prefer ESM; legacy Node (still common in some host stacks) needs CJS. tsup builds both with one config. Tree-shakeable via per-file modules.
DPoP
The DPoP proof generator is FULLY WORKING in Phase 1 (per IDEN-03 + Claude's
discretion: "DPoP shipping in Phase 1 from the start"). Web SDK calls
generateDpopProof() per request; services/auth (Plan 03) validates via
AxisCommunications/go-dpop on the server side.
import {
generateDpopKeyPair,
generateDpopProof,
} from '@communication-engine/core-sdk'
const dpopKeyPair = await generateDpopKeyPair() // ONCE per session
const proof = await generateDpopProof(
{
htm: 'POST',
htu: 'https://ce.example.com/v1/auth/exchange',
},
dpopKeyPair,
)
await fetch('https://ce.example.com/v1/auth/exchange', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
DPoP: proof,
},
body: JSON.stringify({
grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer',
assertion: hostJwt, // minted by @communication-engine/host-issuer
}),
})The keypair is non-extractable (extractable: false) by default in
production — the private key cannot be dumped via XSS (T-05-03 mitigation).
The CE session JWT returned by /v1/auth/exchange carries cnf.jkt bound
to this keypair (RFC 9449 §6.1 sender-constraint).
Algorithm choice — ECDSA P-256 (ES256) for DPoP
DPoP proofs use ES256, NOT EdDSA. RFC 9449 §6.1 lists ES256 as universally supported; EdDSA for DPoP exists in some browsers but not all in 2026.
HOST JWTs (minted by @communication-engine/host-issuer) ARE EdDSA per
D-01.5 — that's a separate keypair for a separate purpose. The two never
mix.
PTT-10 invariant — host owns input
PTTClient.startTransmit / stopTransmit are HOST-callable. The SDK does
NOT bind keyboard / controller / touch input. Input policy belongs to the
host platform (Three.js or UE project). This is non-negotiable: a key-down
handler embedded in the SDK would fight the host's own input layer.
Anti-Pattern A — PTT does NOT cross the chat WS
PTT audio frames travel over UDP via services/ptt-relay, NEVER over the
chat WebSocket. There is intentionally NO pttFrame event surface on
WsClient or ChatClient — the WS multiplexer never carries PTT audio
frames. Putting PTT on the chat WS is the anti-pattern this contract
exists to prevent (PTTClient documents this in its source comments).
Where this fits in the stack
host (Three.js platform)
├── @communication-engine/host-issuer (mints host JWT — EdDSA)
└── @communication-engine/core-sdk ← THIS PACKAGE
├── generateDpopProof(...) → DPoP proof per request
├── CryptoEngine → Phase 2 (Signal Protocol)
├── ChatClient → Phase 2 / 3
├── CallClient → Phase 3 / 4
├── PTTClient → Phase 2 (sub-300ms hot path)
├── Spatializer → Phase 2 (WebAudio PannerNode)
├── FileTransfer → Phase 5
└── WsClient → Phase 2 (Phoenix Channels)
network ──────────────────────────────────────────────────────────
CE backend
├── services/auth (Plan 03) — RFC 7523 + DPoP validation
├── services/key-server (Plan 03b) — prekey bundles (D-04)
├── services/chat (Plan 04) — Phoenix WS + ChatWeb.EchoChannel
└── services/ptt-relay (Plan 04) — Rust UDP, sub-300ms targetFuture plans
- Phase 2 lands
WsClientreal implementation,PTTClientthesis prover,SpatializerWebAudio path, and the OpenMLS WASM crate behindGroupCrypto. - Phase 3 lands
CallClient1:1 audio + group chat MLS. - Phase 4 lands group video + UE production plugin.
- Phase 5 lands
FileTransfer.
