# TypeScript SDK and Browser Demo

The TypeScript SDK (`sdks/typescript/`) provides `@quicproquo/client` — a
browser-ready client with WASM-powered crypto operations and WebSocket
transport.

## What you get

- **WASM crypto bundle** (175 KB) — Ed25519 signatures, X25519 + ML-KEM-768
  hybrid encryption, safety numbers, sealed sender, and message padding,
  compiled from the Rust `quicproquo-core` crate
- **`QpqClient` class** — high-level API for server connectivity and crypto
- **Offline mode** — all crypto operations work without a server connection
- **Browser demo** — interactive HTML page for trying every crypto operation

## Prerequisites

- Node.js 18+ and npm
- Rust toolchain + `wasm-pack` (for building the WASM bundle)

Install wasm-pack if you don't have it:

```bash
cargo install wasm-pack
```

## Building

### 1. Build the WASM crypto bundle

```bash
cd sdks/typescript/wasm-crypto
wasm-pack build --target web --out-dir ../pkg
```

This compiles `quicproquo-core`'s crypto modules to WebAssembly and produces
JavaScript + TypeScript bindings in `sdks/typescript/pkg/`.

### 2. Build the TypeScript SDK

```bash
cd sdks/typescript
npm install
npm run build
```

## Running the browser demo

The demo is a vanilla HTML page — no build step required beyond the WASM
bundle.

```bash
cd sdks/typescript
python3 -m http.server 8080
# Open http://localhost:8080/demo/
```

### Demo walkthrough

1. **Initialize WASM** — click the button to load the 175 KB module
2. **Generate Alice and Bob** — creates Ed25519 identity keypairs, displays
   seed and public key in hex
3. **Compute Safety Number** — derives a Signal-style 60-digit verification
   code from both public keys
4. **Sign and Verify** — type a message, sign it with Alice's key, verify
   with Alice's public key
5. **Hybrid Encrypt/Decrypt** — generate an X25519 + ML-KEM-768 keypair,
   encrypt and decrypt with post-quantum protection
6. **Sealed Sender** — create an anonymous envelope wrapping a payload with
   Alice's identity
7. **Message Padding** — pad a message to a constant-size bucket (256, 1024,
   4096, or 16384 bytes) and unpad it

The crypto operations work entirely offline — no server connection needed.

### Server connectivity

The Chat section of the demo connects via WebSocket. Since the native qpq
server speaks Cap'n Proto RPC over QUIC/TCP + Noise_XX, a WebSocket bridge
proxy is required for browser connectivity. The demo sends JSON-framed
requests over WebSocket.

## Using the SDK in your code

### Offline crypto (no server)

```typescript
import { QpqClient } from "@quicproquo/client";

const client = await QpqClient.offline();

// Generate identities
const alice = client.generateIdentity();
const bob = client.generateIdentity();

// Safety number verification
const safetyNumber = client.computeSafetyNumber(
    alice.publicKey,
    bob.publicKey,
);
console.log("Safety number:", safetyNumber);

// Sign and verify
const msg = new TextEncoder().encode("hello");
const sig = client.sign(alice.seed, msg);
console.log("Valid:", client.verify(alice.publicKey, msg, sig));

// Hybrid encryption (post-quantum)
const ciphertext = client.hybridEncrypt(bob.hybridKey, msg);
const plaintext = client.hybridDecrypt(bob.seed, ciphertext);
```

### Server connection

```typescript
const client = await QpqClient.connect({ addr: "wss://bridge.example.com" });

// Health check
const status = await client.health();

// Resolve a user
const peerKey = await client.resolveUser("bob");

// Create a DM channel
const channel = await client.createChannel(peerKey);

// Send messages
await client.send(peerKey, new TextEncoder().encode("Hello!"));
await client.sendWithTTL(peerKey, payload, 3600); // 1h TTL

// Receive
const messages = await client.receive(peerKey);

// Account deletion
await client.deleteAccount();
```

## WASM crypto functions

The WASM bundle exposes 13 functions via `wasm_bindgen`:

| Function | Description |
|---|---|
| `generate_identity()` | Generate Ed25519 seed (32 bytes) |
| `identity_public_key(seed)` | Derive public key from seed |
| `sign(seed, message)` | Ed25519 signature (64 bytes) |
| `verify(pubkey, message, sig)` | Verify signature (returns boolean) |
| `compute_safety_number(keyA, keyB)` | 60-digit verification code |
| `hybrid_generate_keypair()` | X25519 + ML-KEM-768 keypair |
| `hybrid_public_key(keypair)` | Extract public key from keypair |
| `hybrid_encrypt(pubkey, plaintext)` | Hybrid encrypt |
| `hybrid_decrypt(keypair, ciphertext)` | Hybrid decrypt |
| `seal(seed, payload)` | Sealed sender envelope |
| `unseal(envelope)` | Unseal (returns sender_key + payload) |
| `pad_message(msg)` | Pad to bucket size (256/1K/4K/16K) |
| `unpad_message(padded)` | Remove padding |

## Project structure

```
sdks/typescript/
├── src/
│   ├── index.ts       # Public API exports
│   ├── client.ts      # QpqClient class (258 lines)
│   ├── transport.ts   # WebSocket transport with reconnection (206 lines)
│   ├── crypto.ts      # WASM crypto wrapper (135 lines)
│   └── types.ts       # TypeScript type definitions
├── demo/
│   └── index.html     # Interactive browser demo (476 lines)
├── wasm-crypto/
│   ├── Cargo.toml     # Rust WASM crate (wasm-bindgen)
│   └── src/lib.rs     # 13 wasm_bindgen functions
├── pkg/               # WASM output (built by wasm-pack)
├── package.json
└── tsconfig.json
```
