Skip to content

Commit 6510fdd

Browse files
authored
Feat: e2ee (#1)
* feat: e2ee phase 1 * ai: fix agents.md * ai: update agents.md * feat: phase 2 * feat: phase 3 * feat: phase 4 * feat: rust impl (unreviewed) * feat: phase 6 * feat(client-rs): adaptor-based CRDT API (Loro/ELO) and fragmentation - Add CrdtDocAdaptor trait with implementations: - LoroDocAdaptor (plaintext Loro) - EloDocAdaptor (AES‑GCM, snapshot-only packaging for now) - Add LoroWebsocketClient::join_with_adaptor plus helpers: - join_loro_with_adaptor, join_elo_with_adaptor - Implement outbound fragmentation and inbound fragment reassembly - Buffer pre-join updates (e.g., %ELO backfills) and flush on activation - Reader fallback: import DocUpdate(s) directly into LoroDoc when using legacy join_loro (fixes docupdate roundtrip e2e) - Simplify examples/elo_index_client.rs to use adaptor API (remove manual WS/AES) - Add async-trait dependency and fix Arc move issues in reader task * test(rust): add client adaptor test
1 parent a469149 commit 6510fdd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+5503
-776
lines changed

AGENTS.md

Lines changed: 188 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -1,97 +1,228 @@
11
# AGENTS.md
22

3-
Guidance for code agents working in this repository.
3+
This file provides guidance to ai agents when working with code in this repository.
44

55
## Project Overview
66

7-
Loro Protocol is a transport‑agnostic synchronization protocol for collaborative real‑time data structures (CRDTs). This monorepo contains:
8-
9-
- TypeScript protocol encoder/decoder (`packages/loro-protocol`)
10-
- WebSocket client and a minimal Node server (`packages/loro-websocket`)
11-
- Adaptors that bridge the protocol to the Loro CRDT (`packages/loro-adaptors`)
12-
- A Rust workspace with protocol/client/server equivalents under `rust/`
13-
14-
No Cloudflare/DO code lives in this repo.
7+
Loro Protocol is a transport‑agnostic synchronization protocol for collaborative CRDTs. This monorepo contains a TypeScript implementation (protocol, WebSocket client/server, adaptors) and Rust counterparts. It supports Loro, Yjs, and other CRDT systems over WebSocket and P2P connections. An optional end‑to‑end encrypted flow for Loro documents ("%ELO") is included.
158

169
## Common Development Commands
1710

1811
```bash
1912
# Install dependencies
2013
pnpm install
2114

22-
# Build / test / lint across packages
23-
pnpm -r build
24-
pnpm -r test
25-
pnpm -r typecheck
26-
pnpm -r lint
15+
# Run development watch mode
16+
pnpm dev
17+
18+
# Run tests
19+
pnpm test
2720

28-
# Dev/watch (where supported)
29-
pnpm -r dev
21+
# Build all packages
22+
pnpm build
23+
24+
# Type checking
25+
pnpm typecheck
26+
27+
# Linting
28+
pnpm lint
3029

3130
# Clean build artifacts
32-
pnpm -r clean
31+
pnpm clean
3332
```
3433

3534
## Architecture
3635

3736
### Monorepo Structure
3837

39-
- `packages/loro-protocol`: Core wire encoding/decoding logic (TS)
40-
- `packages/loro-websocket`: WebSocket client and `SimpleServer` (TS)
41-
- `packages/loro-adaptors`: Adaptors for `loro-crdt` docs and ephemeral state (TS)
42-
- `examples/excalidraw-example`: React demo using `SimpleServer`
43-
- `rust/`: Rust workspace with `loro-protocol`, `loro-websocket-client`, `loro-websocket-server`
38+
- **packages/loro-protocol**: Protocol types and binary encoders/decoders, bytes utilities, and `%ELO` container/crypto helpers (TypeScript). Key files: `src/{protocol,encoding,bytes,e2ee}.ts` with tests under `src/`.
39+
- **packages/loro-websocket**: WebSocket client and a `SimpleServer` (TypeScript).
40+
- Features: message fragmentation/reassembly (≤256 KiB), connection‑scoped keepalive frames (`"ping"/"pong"` text), permission hooks, optional persistence hooks.
41+
- **packages/loro-adaptors**: Adaptors that connect the WebSocket client to `loro-crdt` (`LoroAdaptor`, `LoroEphemeralAdaptor`) and `%ELO` (`EloLoroAdaptor`).
42+
- **examples/excalidraw-example**: React demo using `SimpleServer`; syncs a Loro doc and ephemeral presence.
43+
- **rust/**: Rust workspace mirroring the TS packages:
44+
- `rust/loro-protocol`: Encoder/decoder parity with JS (snapshot tests included).
45+
- `rust/loro-websocket-client`: Minimal client.
46+
- `rust/loro-websocket-server`: Async server with workspace isolation, auth hooks, and persistence example (see `examples/simple-server.rs`).
47+
48+
### Protocol Overview
49+
50+
- **CRDT magic bytes**: `%LOR` (Loro), `%EPH` (Ephemeral), `%YJS`, `%YAW`, `%ELO` (E2EE Loro).
51+
- **Messages**: JoinRequest/JoinResponseOk/JoinError, DocUpdate, DocUpdateFragmentHeader/Fragment, UpdateError, Leave.
52+
- **Limits**: 256 KiB max per message; large payloads are fragmented and reassembled.
53+
- **Keepalive**: Text frames `"ping"`/`"pong"` are connection‑scoped and bypass the envelope.
54+
- **%ELO**: DocUpdate payload is a container of encrypted records (DeltaSpan/Snapshot). Each record has a plaintext header (peer/version metadata, `keyId`, 12‑byte IV) and AES‑GCM ciphertext (`ct||tag`). Servers route/broadcast without decrypting.
55+
56+
### Testing
57+
58+
- **TypeScript**: `vitest` across packages via `vitest.workspace.ts` (unit + e2e in `packages/loro-websocket`).
59+
- **Rust**: `cargo test` in each crate; server/client e2e and auth tests under `rust/loro-websocket-server/tests`.
60+
61+
## Important Design Documents
62+
63+
**When implementation behavior doesn't match expectations, these documents are the source of truth:**
64+
65+
- `/protocol.md`: Wire protocol specification - defines message formats and syncing process
66+
- `/protocol-e2ee.md`: End-to-end encryption protocol
67+
68+
These documents represent the ground truth design. If there are inconsistencies between code and these specs, follow the specifications.
69+
70+
# Development Guidelines
71+
72+
## Philosophy
73+
74+
### Core Beliefs
75+
76+
- **Incremental progress over big bangs** - Small changes that compile and pass tests
77+
- **Learning from existing code** - Study and plan before implementing
78+
- **Pragmatic over dogmatic** - Adapt to project reality
79+
- **Clear intent over clever code** - Be boring and obvious
80+
81+
### Simplicity Means
82+
83+
- Single responsibility per function/class
84+
- Avoid premature abstractions
85+
- No clever tricks - choose the boring solution
86+
- If you need to explain it, it's too complex
87+
- Avoid over-engineering, don't write low-value docs/comments/tests. They'll increase the maintenance cost and make code review harder.
88+
- Your changes should be easy to review. Please address the part that you want human to focus on by adding `TODO: REVIEW [reason]`.
89+
- Don't test obvious things.
90+
91+
## Process
92+
93+
### 1. Planning & Staging
94+
95+
Break complex work into 3-5 stages. Document in `IMPLEMENTATION_PLAN.md`:
96+
97+
```markdown
98+
## Stage N: [Name]
99+
100+
**Goal**: [Specific deliverable]
101+
**Success Criteria**: [Testable outcomes]
102+
**Tests**: [Specific test cases]
103+
**Status**: [Not Started|In Progress|Complete]
104+
```
105+
106+
- Update status as you progress
107+
- Remove file when all stages are done
108+
109+
### 2. Implementation Flow
110+
111+
1. **Understand** - Study existing patterns in codebase
112+
2. **Test** - Write test first (red)
113+
3. **Implement** - Minimal code to pass (green)
114+
4. **Refactor** - Clean up with tests passing
115+
5. **Commit** - With clear message linking to plan
116+
117+
### 3. When Stuck (After 3 Attempts)
118+
119+
**CRITICAL**: Maximum 3 attempts per issue, then STOP.
120+
121+
1. **Document what failed**:
122+
- What you tried
123+
- Specific error messages
124+
- Why you think it failed
125+
126+
2. **Research alternatives**:
127+
- Find 2-3 similar implementations
128+
- Note different approaches used
129+
130+
3. **Question fundamentals**:
131+
- Is this the right abstraction level?
132+
- Can this be split into smaller problems?
133+
- Is there a simpler approach entirely?
134+
135+
4. **Try different angle**:
136+
- Different library/framework feature?
137+
- Different architectural pattern?
138+
- Remove abstraction instead of adding?
139+
140+
## Technical Standards
141+
142+
### Architecture Principles
143+
144+
- **Composition over inheritance** - Use dependency injection
145+
- **Interfaces over singletons** - Enable testing and flexibility
146+
- **Explicit over implicit** - Clear data flow and dependencies
147+
- **Test-driven when possible** - Never disable tests, fix them
148+
149+
### Code Quality
150+
151+
- **Every commit must**:
152+
- Compile successfully
153+
- Pass all existing tests
154+
- Include tests for new functionality
155+
- Follow project formatting/linting
156+
157+
- **Before committing**:
158+
- Run formatters/linters
159+
- Self-review changes
160+
- Ensure commit message explains "why"
161+
162+
### Error Handling
44163

45-
### Protocol Essentials
164+
- Fail fast with descriptive messages
165+
- Include context for debugging
166+
- Handle errors at appropriate level
167+
- Never silently swallow exceptions
46168

47-
See `/protocol.md`.
169+
## Decision Framework
48170

49-
- Message envelope: 4‑byte CRDT magic, varBytes roomId (≤128B), 1‑byte type, payload
50-
- Types: JoinRequest/JoinResponseOk/JoinError, DocUpdate, DocUpdateFragmentHeader/Fragment, UpdateError, Leave
51-
- Limit: 256 KiB max per message; large payloads must be fragmented
52-
- Keepalive: connection‑scoped text frames "ping"/"pong" (out‑of‑band)
171+
When multiple valid approaches exist, choose based on:
53172

54-
Key TS files:
173+
1. **Testability** - Can I easily test this?
174+
2. **Readability** - Will someone understand this in 6 months?
175+
3. **Consistency** - Does this match project patterns?
176+
4. **Simplicity** - Is this the simplest solution that works?
177+
5. **Reversibility** - How hard to change later?
55178

56-
- `packages/loro-protocol/src/{bytes,encoding,protocol}.ts`
179+
## Project Integration
57180

58-
## Build & Test
181+
### Learning the Codebase
59182

60-
- TypeScript: `vitest` tests are co‑located with sources (`*.test.ts`). The websocket package includes e2e tests spinning up `SimpleServer`.
61-
- Rust: run with `cargo` under `rust/` (tests in crates and `tests/`).
183+
- Find 3 similar features/components
184+
- Identify common patterns and conventions
185+
- Use same libraries/utilities when possible
186+
- Follow existing test patterns
62187

63-
Useful references:
188+
### Tooling
64189

65-
- TS E2E: `packages/loro-websocket/src/e2e.test.ts`
66-
- Rust server example: `rust/loro-websocket-server/examples/simple-server.rs`
190+
- Use project's existing build system
191+
- Use project's test framework
192+
- Use project's formatter/linter settings
193+
- Don't introduce new tools without strong justification
67194

68-
## Implementation Notes
195+
## Quality Gates
69196

70-
- Fragmentation: servers/clients reassemble using `DocUpdateFragmentHeader` + `DocUpdateFragment` with an 8‑byte batch id
71-
- Rooms: one WS connection can join multiple rooms (CRDT+roomId pair)
72-
- CRDTs: Loro (`%LOR`), Loro Ephemeral (`%EPH`), Yjs (`%YJS`), Yjs Awareness (`%YAW`)
73-
- Errors: explicit small codes for join/update failures
74-
- Auth: `SimpleServer` exposes `authenticate` and snapshot load/save hooks
197+
### Definition of Done
75198

76-
## Development Guidelines
199+
- [ ] Tests written and passing
200+
- [ ] Code follows project conventions
201+
- [ ] No linter/formatter warnings
202+
- [ ] Commit messages are clear
203+
- [ ] Implementation matches plan
204+
- [ ] No TODOs without issue numbers
77205

78-
Principles:
206+
### Test Guidelines
79207

80-
- Incremental, boring, and obvious code
81-
- Single responsibility; avoid premature abstractions
82-
- Tests for new behavior; don’t disable existing tests
208+
- Test behavior, not implementation
209+
- One assertion per test when possible
210+
- Clear test names describing scenario
211+
- Use existing test utilities/helpers
212+
- Tests should be deterministic
83213

84-
Process:
214+
## Important Reminders
85215

86-
1. Understand existing patterns
87-
2. Add/adjust tests
88-
3. Implement minimally to pass
89-
4. Refactor with tests passing
216+
**NEVER**:
90217

91-
Quality gates:
218+
- Use `--no-verify` to bypass commit hooks
219+
- Disable tests instead of fixing them
220+
- Commit code that doesn't compile
221+
- Make assumptions - verify with existing code
92222

93-
- All packages build and tests pass
94-
- Lint/format clean
95-
- Clear commit messages (explain “why”)
223+
**ALWAYS**:
96224

97-
When stuck (≤3 attempts): document failures, explore alternatives, question assumptions, try a simpler angle.
225+
- Commit working code incrementally
226+
- Update plan documentation as you go
227+
- Learn from existing implementations
228+
- Stop after 3 failed attempts and reassess

0 commit comments

Comments
 (0)