Skip to content

feat(yjs): collaborative editing framework - #2785

Open
JammingBen wants to merge 36 commits into
mainfrom
feat/realtime-collaboration
Open

feat(yjs): collaborative editing framework#2785
JammingBen wants to merge 36 commits into
mainfrom
feat/realtime-collaboration

Conversation

@JammingBen

@JammingBen JammingBen commented Jul 1, 2026

Copy link
Copy Markdown
Member

Description

Subset of #2755 without the example apps we don't want to have in our monorepo, but with some architectual changes, improvements and bug fixes.

This is quite a lot, I recommend reading dev/docs/yjs.md to get more information about the implementation.

Huge thanks to @dschmidt for the heavy lifting groundwork in the original PR!

Setup

Pull the latest OpenCloud image and run a fresh docker compose up -d.

How has this been tested

  • Locally by myself
  • Claude via headless browsers (see dev/docs/yjs-manual-tests.md)

This of obviously far from being battle tested. It will be especially interesting to see how it performs under load and with more than 2-3 concurrent peers.

What next?

#3033 lists all the follow-ups and categorizes them into priorities.

@JammingBen JammingBen self-assigned this Jul 1, 2026
@JammingBen
JammingBen force-pushed the feat/realtime-collaboration branch 4 times, most recently from 035fead to e1fbb9f Compare July 2, 2026 13:12
@JammingBen JammingBen mentioned this pull request Aug 5, 2026
19 tasks
@JammingBen JammingBen changed the title feat(yjs): collaborative editing framework (base) feat(yjs): collaborative editing framework Aug 5, 2026
@JammingBen
JammingBen force-pushed the feat/realtime-collaboration branch from e1fbb9f to 17f3f90 Compare August 6, 2026 07:59
@JammingBen
JammingBen force-pushed the feat/realtime-collaboration branch 6 times, most recently from 1608ce6 to faf7cfd Compare August 7, 2026 13:49
@JammingBen
JammingBen force-pushed the feat/realtime-collaboration branch 2 times, most recently from 7604e60 to f129eb8 Compare August 10, 2026 11:11
@JammingBen
JammingBen marked this pull request as ready for review August 10, 2026 12:43
dschmidt and others added 7 commits August 11, 2026 10:16
…p apps

Brings the realtime-collaboration PoC from opencloud-eu/web-extensions
into the canonical web repo:

- New `@opencloud-eu/web-pkg` component family at
  `src/components/Collaborative/`: `CollaborativeWrapper.vue` +
  `CollaborativeAdapter` type contract. Reads `useAuthStore` /
  `useConfigStore` via the existing composables barrel.
- web-pkg deps gain `@hocuspocus/provider`, `yjs`, `y-protocols`,
  `semver` (+ `@types/semver` devDep). Editor-binding deps
  (`y-codemirror.next`, `@tiptap/y-tiptap`, `@tiptap/markdown`,
  `@tiptap/extension-collaboration`, `@codemirror/*`) stay with the
  consuming apps — web-pkg only ships the editor-agnostic plumbing.
- `realtimeUrl` prop is now three-state on the wrapper:
  `string` for an explicit URL, `null` for forced local-only mode,
  `undefined` (default) to derive from `configStore.serverUrl` plus
  the `/realtime` convention. Means collab is on out-of-the-box once
  the sidecar runs on the OC host. A first-class `options.realtimeUrl`
  field in OC's web config schema is a separate follow-up.
- Tiptap StarterKit uses the v3 `undoRedo: false` option name (was
  `history: false` in v2) — clears the lingering `Partial<StarterKitOptions>`
  type error and keeps yUndoPlugin from `@tiptap/y-tiptap` as the
  collab-aware undo manager.
Removes the CollaborativeWrapper component in favor of a new composable
useCollaborativeDocument, making the entire yjs & collaboration
architecture a bit simpler.
@JammingBen
JammingBen force-pushed the feat/realtime-collaboration branch from ccffa57 to 775e1ca Compare August 11, 2026 09:23

@dschmidt dschmidt left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically: LGTM :)

Just a bunch of nit picks here and there

Comment thread dev/docs/yjs-manual-tests.md
Comment thread dev/docs/yjs.md
Comment thread dev/docs/yjs.md
Comment thread packages/web-app-text-editor/src/App.vue Outdated
Comment thread packages/web-app-text-editor/src/index.ts Outdated
currentContent: Ref<string>
currentFileContext: FileContext
/** Fetching this costs a WebDAV GET of the whole file. */
currentContent: string

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this correct? Cant we have different types depending on what the app defines how it wants content to be injected? Or is this just urls not content?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, setting currentContent results in a WebDAV GET because of if (unref(hasProp('currentContent'))) in the AppWrapper.

Comment thread packages/web-pkg/src/editor/composables/strategies/plainText.ts
]
}
})
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's only a few lines of code, so it's not too important - but is this something we should upstream somewhere? in @tiptap/extension-collaboration maybe?

Comment thread packages/web-pkg/src/editor/types.ts Outdated
Comment thread services/yjs/src/server.ts Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants