Implements Notion-style sync blocks: a Tiptap node whose content is shared across N pages. Editing via the Hocuspocus overlay propagates to all instances via Yjs collab + SSE broadcast (EventEmitter2 bus). Server: DB migration, NestJS module (CRUD + BFS cycle detection + broadcast), Hocuspocus persistence extension extended for sync-block-* docs, 3 new RBAC permissions (sync_blocks:create/edit/delete), seeded to Admin/Editor/Member. Client: SyncBlockExtension (Tiptap node), SyncBlockNodeView (NodeView + Mantine Modal overlay + SSE hook), /sync-block slash command, service client. Tests: 32 server Jest + 18 client Vitest, all green. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
21 lines
852 B
TypeScript
21 lines
852 B
TypeScript
import { Editor, Range } from "@tiptap/core";
|
|
import { syncBlocksClient } from "../services/sync-blocks-client";
|
|
|
|
/**
|
|
* Slash command handler for `/sync-block` (R4.2).
|
|
*
|
|
* Creates a new master sync block via the REST API, then inserts a
|
|
* `syncBlock` node into the editor with the returned masterId.
|
|
*
|
|
* The insert is atomic from the user's perspective: if the API call fails,
|
|
* the editor is not modified and the error is propagated to the caller.
|
|
*/
|
|
export async function insertSyncBlock(editor: Editor, range: Range): Promise<void> {
|
|
// Delete the slash trigger text before the async operation to prevent
|
|
// the slash menu from staying open on slow networks.
|
|
editor.chain().focus().deleteRange(range).run();
|
|
|
|
const block = await syncBlocksClient.create({});
|
|
|
|
editor.chain().focus().insertSyncBlock({ masterId: block.id }).run();
|
|
}
|