---
id: TASK-43
title: 'Implement Event Broadcasting: canvas-wide pub/sub system'
status: Done
assignee: []
created_date: '2026-02-18 20:06'
updated_date: '2026-03-11 23:14'
labels:
  - feature
  - phase-2
  - ecosystem
milestone: m-1
dependencies:
  - TASK-41
references:
  - rspace-online/lib/community-sync.ts
  - rspace-online/server/community-store.ts
priority: medium
---

## Description

<!-- SECTION:DESCRIPTION:BEGIN -->
Add a pub/sub event system so shapes can broadcast and subscribe to named events across the canvas.

New file lib/event-bus.ts:
- CanvasEventBus class with emit(), subscribe(), unsubscribe(), getSubscribers()
- Events written to CRDT doc.eventLog (bounded ring buffer, last 100 entries)
- Remote users see events replayed via Automerge patch application
- Re-entrancy guard kills chains after 10 levels to prevent infinite loops

Automerge schema additions:
- doc.eventLog: EventEntry[] (id, channel, sourceShapeId, payload, timestamp)
- shapes[id].subscriptions: string[] (channel names)

Shapes opt in with onEventReceived(channel, payload) method.

Example: Timer emits "timer:done" → all subscribed Budget shapes recalculate.
<!-- SECTION:DESCRIPTION:END -->

## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 CanvasEventBus emits events to CRDT eventLog
- [x] #2 Shapes can subscribe to channels and receive events
- [x] #3 Events sync to remote users via Automerge
- [x] #4 Ring buffer bounded at 100 entries with GC
- [x] #5 Re-entrancy guard prevents infinite event loops
- [x] #6 Works offline (events queued in CRDT, replayed on reconnect)
<!-- AC:END -->

## Implementation Notes

<!-- SECTION:NOTES:BEGIN -->
Implementation started: CanvasEventBus class, CommunityDoc schema updates, CommunitySync helper methods

Complete. Created lib/event-bus.ts with CanvasEventBus class. Updated CommunityDoc with eventLog field, ShapeData with subscriptions field. Added appendEvent(), getEventLog(), setShapeSubscriptions(), getShapeSubscriptions(), getShapesSubscribedTo(), getShapeElement() methods to CommunitySync. Added eventlog-changed dispatch in both patch and full-sync paths. Added onEventReceived() optional method on FolkShape. Exported from lib/index.ts.
<!-- SECTION:NOTES:END -->
