Skip to content

feat(editor): add wireCollab extension point + typed mutation events#38

Merged
lassediercks merged 1 commit into
mainfrom
feat/collab-api
May 27, 2026
Merged

feat(editor): add wireCollab extension point + typed mutation events#38
lassediercks merged 1 commit into
mainfrom
feat/collab-api

Conversation

@lassediercks

Copy link
Copy Markdown
Owner

Adds a small extension point that downstream consumers can use to mirror the editor's in-memory graph into an external store without copying code or shadowing internal modules.

Two pieces:

  1. Extended wireMutations (src/editor/mutations.ts) — onMutate callback fires alongside scheduleSave for every mutation. The event carries the kind ("box" | "edge" | "text" | "line" | "stroke" | "currentMap" | "doc") and the current map path so a consumer can scope a diff to the affected slice.

    getMapPath is also new and optional (defaults to "/"). All existing wireMutations callers continue to compile and run unchanged.

  2. New src/editor/collab-api.ts — exports whenCollabReady(cb) and a CollabHandle interface:

    interface CollabHandle {
    snapshot(): FlowgoGraph;
    applyRemotePatch(fn: (g: FlowgoGraph) => void): void;
    onLocalMutation(cb: (e: MutationEvent) => void): () => void;
    }

    Plugins call whenCollabReady from a separate bundle; the editor's main.ts calls exposeCollabHandle at the end of bootstrap with an impl that snapshots the live graph (structuredClone), applies remote patches in place + re-renders, and fans onMutate events out to subscribers.

    FlowgoGraph + FlowgoBox/Edge/Text/Line/Stroke types mirror the pkg/graph.Graph shape verbatim so a plugin can pass snapshots to a Go/Rust sidecar via JSON without translation.

./collab added to the package.json exports map so consumers can import "@flowgo/editor/collab".

Bundle size: 103.82 KB (+414 bytes vs main, almost all from the type-only declarations that get erased at build time).

All 120 vitest tests pass; tsc --noEmit clean; vite build clean. Zero behaviour change for CLI / single-user consumers — the new file ships in every bundle but does nothing until a downstream plugin calls whenCollabReady.

Adds a small extension point that downstream consumers can use to
mirror the editor's in-memory graph into an external store without
copying code or shadowing internal modules.

Two pieces:

1. Extended `wireMutations` (src/editor/mutations.ts) — `onMutate`
   callback fires alongside `scheduleSave` for every mutation.
   The event carries the kind ("box" | "edge" | "text" | "line" |
   "stroke" | "currentMap" | "doc") and the current map path so a
   consumer can scope a diff to the affected slice.

   `getMapPath` is also new and optional (defaults to "/"). All
   existing wireMutations callers continue to compile and run
   unchanged.

2. New `src/editor/collab-api.ts` — exports `whenCollabReady(cb)`
   and a `CollabHandle` interface:

     interface CollabHandle {
       snapshot(): FlowgoGraph;
       applyRemotePatch(fn: (g: FlowgoGraph) => void): void;
       onLocalMutation(cb: (e: MutationEvent) => void): () => void;
     }

   Plugins call whenCollabReady from a separate bundle; the editor's
   main.ts calls exposeCollabHandle at the end of bootstrap with an
   impl that snapshots the live graph (structuredClone), applies
   remote patches in place + re-renders, and fans onMutate events
   out to subscribers.

   FlowgoGraph + FlowgoBox/Edge/Text/Line/Stroke types mirror the
   pkg/graph.Graph shape verbatim so a plugin can pass snapshots to
   a Go/Rust sidecar via JSON without translation.

`./collab` added to the package.json exports map so consumers can
import "@flowgo/editor/collab".

Bundle size: 103.82 KB (+414 bytes vs main, almost all from the
type-only declarations that get erased at build time).

All 120 vitest tests pass; tsc --noEmit clean; vite build clean.
Zero behaviour change for CLI / single-user consumers — the new
file ships in every bundle but does nothing until a downstream
plugin calls whenCollabReady.
@lassediercks lassediercks merged commit 52ea1ee into main May 27, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant