Collab Server (server/)
Lightweight Node.js WebSocket server for realtime collaboration. Manages project rooms, syncs file changes between connected Songbird clients, and performs structured merges on .bird and JSON files.
Architecture
Files
| File | Purpose |
|---|---|
server.js | Main WebSocket server — room management, push/pull sync, presence broadcasting, merge orchestration |
merge/bird-merge.js | Structured .bird file parser (parseBird), serializer (serializeBird), and three-way merge (mergeBird) at track-per-section granularity |
merge/json-merge.js | Recursive deep-merge for JSON state files. Handles arrays element-by-element, objects key-by-key. mergeStateJson() for mixer state, mergeEditJson() for plugin state |
test-merge.js | Test suite — 7 tests covering parse round-trip, auto-merge of different tracks/sections, and last-write-wins conflict resolution |
package.json | Dependencies: ws (WebSocket), nanoid (invite codes) |
Room Management
Each project collaboration session is a room:- Create — A user creates a room, receives an 8-character invite code. Their current project files are sent to the server as the initial state.
- Join — A user joins with an invite code and receives the current project files from the server.
- Leave — On disconnect, peers are notified. Empty rooms are cleaned up after 60 seconds.
Merge Engine
.bird Three-Way Merge
The .bird merge works by parsing the file into a structured tree and merging at the track-per-section level:
- Parse
base,ours,theirsinto trees - For each block (
sig,tracks,arr): iftheirschanged frombase, taketheirs; else keepours - For each section → each track: if only one side changed, take the change. If both changed the same track in the same section → last-write-wins (take
theirs) - Serialize the merged tree back to
.birdtext
JSON Deep Merge
Recursive merge at every level of the JSON tree:- Objects: merge key-by-key recursively
- Arrays: merge element-by-element by index (critical for the
tracksarray indaw.state.json) - Leaves: if both changed, last-write-wins (take
theirs)
Running
Extending
Adding New File Types
To add merge support for a new file type:- Create a new merge module in
merge/(e.g.,merge/new-format-merge.js) - Export a
mergeNewFormat(base, ours, theirs)function - Add a file extension check in
server.js’smergeFile()function - Unknown file types already fall back to last-write-wins