docs(sdk): add comprehensive SDK documentation and wire format reference
Covers all official SDKs (Rust, Go, Python, TypeScript, C FFI), the v2 wire format with method ID tables, authentication flow, and a build-your-own-SDK guide with implementation checklist.
This commit is contained in:
128
docs/sdk/typescript.md
Normal file
128
docs/sdk/typescript.md
Normal file
@@ -0,0 +1,128 @@
|
||||
# TypeScript SDK
|
||||
|
||||
The TypeScript SDK provides a browser-compatible client with WASM-based crypto.
|
||||
|
||||
Location: `sdks/typescript/`
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install quicproquo
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```typescript
|
||||
import { QpqClient } from "quicproquo";
|
||||
|
||||
// Connect via WebSocket bridge
|
||||
const client = await QpqClient.connect({
|
||||
addr: "ws://127.0.0.1:5002",
|
||||
});
|
||||
|
||||
const status = await client.health();
|
||||
console.log("Server:", status);
|
||||
|
||||
// Set session token (obtained via OPAQUE externally)
|
||||
client.setSessionToken(token);
|
||||
|
||||
// Resolve user
|
||||
const peerKey = await client.resolveUser("bob");
|
||||
|
||||
// Create channel
|
||||
const { channelId, wasNew } = await client.createChannel(peerKey);
|
||||
|
||||
// Send message
|
||||
const seq = await client.send(peerKey, new TextEncoder().encode("hello"));
|
||||
|
||||
// Receive messages
|
||||
const messages = await client.receive(myKey);
|
||||
for (const msg of messages) {
|
||||
console.log(`[${msg.seq}] ${new TextDecoder().decode(msg.data)}`);
|
||||
}
|
||||
|
||||
client.close();
|
||||
```
|
||||
|
||||
## Offline Crypto
|
||||
|
||||
The SDK includes WASM-compiled crypto primitives that work without a server:
|
||||
|
||||
```typescript
|
||||
const client = await QpqClient.offline();
|
||||
|
||||
// Ed25519 identity
|
||||
const { seed, publicKey } = client.generateIdentity();
|
||||
const sig = client.sign(seed, message);
|
||||
const valid = client.verify(publicKey, message, sig);
|
||||
|
||||
// Hybrid KEM (X25519 + ML-KEM-768)
|
||||
const kp = client.hybridGenerateKeypair();
|
||||
const ciphertext = client.hybridEncrypt(kp.publicKey, plaintext);
|
||||
const decrypted = client.hybridDecrypt(kp.blob, ciphertext);
|
||||
|
||||
// Safety numbers
|
||||
const safetyNumber = client.computeSafetyNumber(keyA, keyB);
|
||||
|
||||
// Sealed sender
|
||||
const sealed = client.seal(seed, payload);
|
||||
const unsealed = client.unseal(sealed);
|
||||
|
||||
// Message padding
|
||||
const padded = client.padMessage(data);
|
||||
const unpadded = client.unpadMessage(padded);
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
### RPC Methods
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `QpqClient.connect(opts)` | Connect via WebSocket |
|
||||
| `QpqClient.offline()` | Crypto-only mode |
|
||||
| `client.health()` | Health check |
|
||||
| `client.resolveUser(username)` | Look up identity key |
|
||||
| `client.createChannel(peerKey)` | Create DM channel |
|
||||
| `client.send(recipientKey, payload)` | Send message |
|
||||
| `client.sendWithTTL(recipientKey, payload, ttl)` | Disappearing message |
|
||||
| `client.receive(recipientKey)` | Fetch messages |
|
||||
| `client.deleteAccount()` | Delete account |
|
||||
| `client.close()` | Disconnect |
|
||||
|
||||
### Crypto Methods
|
||||
|
||||
| Method | Description |
|
||||
|---|---|
|
||||
| `client.generateIdentity()` | Generate Ed25519 keypair |
|
||||
| `client.identityPublicKey(seed)` | Derive public key |
|
||||
| `client.sign(seed, message)` | Ed25519 sign |
|
||||
| `client.verify(publicKey, message, sig)` | Ed25519 verify |
|
||||
| `client.hybridGenerateKeypair()` | Generate hybrid keypair |
|
||||
| `client.hybridEncrypt(pk, plaintext)` | Hybrid encrypt |
|
||||
| `client.hybridDecrypt(blob, ciphertext)` | Hybrid decrypt |
|
||||
| `client.computeSafetyNumber(keyA, keyB)` | Safety number |
|
||||
| `client.seal(seed, payload)` | Sealed sender |
|
||||
| `client.unseal(envelope)` | Unseal |
|
||||
| `client.padMessage(data)` | Pad message |
|
||||
| `client.unpadMessage(data)` | Unpad message |
|
||||
|
||||
## Architecture
|
||||
|
||||
The TypeScript SDK uses a WebSocket bridge proxy because browsers cannot open raw QUIC connections. The bridge translates JSON-over-WebSocket to Cap'n Proto RPC:
|
||||
|
||||
```
|
||||
Browser ─── WebSocket ───► Bridge Proxy ─── QUIC/capnp ───► Server
|
||||
```
|
||||
|
||||
Crypto operations (Ed25519, hybrid KEM, sealed sender) run entirely in WASM, compiled from the Rust `quicproquo-core` crate.
|
||||
|
||||
## Structure
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `src/client.ts` | High-level client API |
|
||||
| `src/transport.ts` | WebSocket transport with auto-reconnect |
|
||||
| `src/crypto.ts` | WASM crypto bindings |
|
||||
| `src/types.ts` | TypeScript interfaces |
|
||||
| `wasm-crypto/` | Rust WASM crypto source |
|
||||
Reference in New Issue
Block a user