This repo covers how Real-Time Collaboration (RTC) with end-to-end encryption is achieved on is achieved via the Fileverse middleware on ddocs.new . Our approach offers both privacy and security via client-side encryption and by offering decentralized ways of enabling RTC on one's own documents. Tl;dr By default, RTC v0.2 on dDocs is facilitated by a stateless web-socket server (v0.1 was WebRTC) that deletes all the encrypted data it stores about a RTC session once the latest state of the document is pushed on IPFS and added to the document creator’s personal onchain content registry. All data touching the stateless web-socket server is stored only ephemerally and is first encrypted client-side.
Self-hosting and Decentralization:
- Bring your own Server: RTC on ddocs.new can also work by self-hosting your own web-socket server and enabling your collaboration session through it.
- Decentralisation explorations: People using dDocs can also turn on the Waku servers discovery feature, which lets them discover and connect to community-hosted servers for RTC via Waku. This feature is still in early Alpha and highly experimental
⚠️ . Please use at your own risk. Thank you team Waku and Vàclav san for all the insights in helping us add this first version on dDocs! For the waku enabled version check this branch: feat/waku
This repo is currently being audited by Dedalo. Findings will be shared in a report here when completed.
- ✅ Real-time Collaboration: WebSocket-based communication for instant updates
- ✅ Y.js Integration: CRDT-based conflict resolution for collaborative editing
- ✅ Awareness Protocol: Real-time cursor and selection sharing
- ✅ UCAN Authentication: Decentralized authentication using cryptographic capabilities
- ✅ In-Memory Storage: Fast, ephemeral storage for development and testing
- ✅ Room Management: Multi-user document rooms with role-based access
- ✅ TypeScript: Full type safety and excellent developer experience
npm install# Start in development mode with auto-reload
npm run dev# Build the project
npm run build
# Start the production server
npm start
# Or use the convenient start script
./start.sh
# Or with PM2 for process management
pm2 start ecosystem.config.js --env productionCopy env.example to .env and adjust the settings:
cp env.example .envPORT: Server port (default: 5000)HOST: Server host (default: 0.0.0.0)NODE_ENV: Environment mode (development/production)CORS_ORIGINS: Comma-separated list of allowed originsSERVER_DID: Server's DID for UCAN authenticationMONGODB_URI: MongoDB URI where you want your updates to be saved temporarilyRPC_URL: RPC URL to query onchain state and only allow people with relevant access to create rooms related to DDocsWS_URL: Optional env vars if you want your node to participate in the waku discovery
For this you just need to start the server with WS_URL set as the wss url that is being provided for the running rtc server. Once the server is up and running you just need to go to settings and trigger waku enabled rtc server discover and let your frontend find this server. If there are multiple options frontend client selects one of the url at random from the avaiable community servers. You can always over ride that option and set it to your own server's wss endpoint.
GET /health- Health check and server stats
Connect to ws://${env.HOST}:{env.PORT}/ and send JSON messages:
{
"cmd": "/auth",
"args": {
"username": "user123",
"token": "ucan_token_here",
"documentId": "room123"
},
"seqId": "unique_id"
}{
"cmd": "/documents/update",
"args": {
"documentId": "room123",
"data": "encrypted_yjs_update",
"update_snapshot_ref": null
},
"seqId": "unique_id"
}{
"cmd": "/documents/commit",
"args": {
"documentId": "room123",
"updates": ["update_id_1", "update_id_2"],
"cid": "ipfs_hash",
"data": "encrypted_document_state"
},
"seqId": "unique_id"
}{
"cmd": "/documents/peers/list",
"args": {
"documentId": "room123"
},
"seqId": "unique_id"
}{
"cmd": "/documents/awareness",
"args": {
"documentId": "room123",
"data": {
"position": "encrypted_cursor_data"
}
},
"seqId": "unique_id"
}This server is designed to work with the @fileverse-dev/sync package. Here's how to configure the client:
import { useSyncMachine } from "@fileverse-dev/sync";
const { connect, disconnect, isConnected, ydoc, isReady } = useSyncMachine({
roomId: "your-room-id",
wsProvider: "ws://localhost:5000/",
onError: (err) => console.error(err),
});
// Connect with username and room key
const roomKey = await crypto.subtle.importKey(/* ... */);
connect("username", roomKey);┌─────────────────┐ ┌──────────────────┐ ┌─────────────────┐
│ Client App │ │ Collaboration │ │ Memory Store │
│ │ │ Server │ │ │
│ ┌───────────┐ │ │ │ │ ┌───────────┐ │
│ │ Sync Pkg │──┼────┼─► WebSocket │ │ │ Documents │ │
│ └───────────┘ │ │ Manager │ │ │ Updates │ │
│ │ │ │ │ │ Commits │ │
│ ┌───────────┐ │ │ ┌─────────────┐ │ │ │ Members │ │
│ │ Y.js Doc │ │ │ │ Auth Service│ │ │ └───────────┘ │
│ └───────────┘ │ │ └─────────────┘ │ │ │
└─────────────────┘ └──────────────────┘ └─────────────────┘
src/
├── config/ # Configuration management
├── services/ # Core business logic
│ ├── auth.ts # UCAN authentication
│ ├── memory-store.ts # In-memory data storage
│ └── websocket-manager.ts # WebSocket handling
├── types/ # TypeScript type definitions
└── index.ts # Server entry point
- New WebSocket Commands: Add handlers in
websocket-manager.ts - Authentication: Modify
auth.tsfor custom auth logic - Storage: Replace
memory-store.tswith persistent storage - Middleware: Add Express middleware in
index.ts
- Set
NODE_ENV=production - Configure proper CORS origins
- Set up monitoring and logging
- Use a process manager like PM2 for production
- Implement proper authentication key management
- Consider using a reverse proxy (nginx) for SSL termination
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests if applicable
- Submit a pull request
MIT License - see LICENSE file for details