@kedataindo/docflow-core 0.0.71 → 0.0.73

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,71 @@
1
+ import { Awareness } from 'y-protocols/awareness';
2
+ import { WebsocketProvider } from 'y-websocket';
3
+ import * as Y from 'yjs';
4
+ export { A as AwarenessState, C as CollaborationOptions, a as CollaborationSetup, c as collaborationExtensions, b as createCollaboration } from '../Collaboration-CGv9OZlB.cjs';
5
+ import '@tiptap/core';
6
+ import 'y-indexeddb';
7
+ import 'y-webrtc';
8
+
9
+ interface SubdocState {
10
+ id: string;
11
+ doc: Y.Doc;
12
+ provider: WebsocketProvider | null;
13
+ active: boolean;
14
+ }
15
+ interface SubdocumentProviderOptions {
16
+ /** WebSocket URL for the collaboration server. */
17
+ websocketUrl: string;
18
+ /** Room prefix — subdocuments use `${roomPrefix}/${id}` as room name. */
19
+ roomPrefix: string;
20
+ /** User info for awareness. */
21
+ user: {
22
+ name: string;
23
+ color: string;
24
+ };
25
+ /** Number of subdocuments to keep active (buffer around visible viewport). */
26
+ maxActive?: number;
27
+ /** Called when subdocument state changes (active/deactivated). */
28
+ onStateChange?: (states: SubdocState[]) => void;
29
+ }
30
+ /**
31
+ * Manages multiple Y.Doc subdocuments under a parent document.
32
+ *
33
+ * Use case: large documents (100+ pages) split into per-section subdocuments.
34
+ * Only active (visible) subdocuments are connected to the network via
35
+ * WebSocketProvider; inactive ones keep local state but stop syncing.
36
+ *
37
+ * Usage:
38
+ * const provider = new SubdocumentProvider({ websocketUrl, roomPrefix, user })
39
+ * provider.createSubdoc('section-1')
40
+ * provider.activate('section-1') // starts syncing
41
+ * provider.deactivate('section-1') // stops syncing
42
+ * const frag = provider.getFragment('section-1') // Y.XmlFragment for editor
43
+ */
44
+ declare class SubdocumentProvider {
45
+ readonly parentDoc: Y.Doc;
46
+ readonly subdocs: Y.Map<Y.Doc>;
47
+ readonly awareness: Awareness;
48
+ private readonly options;
49
+ private readonly states;
50
+ private readonly activeQueue;
51
+ private readonly parentProvider;
52
+ constructor(options: SubdocumentProviderOptions);
53
+ /** Create a new subdocument. Does NOT activate it. */
54
+ createSubdoc(id: string, initialState?: Uint8Array): Y.Doc;
55
+ /** Activate a subdocument — connects it to the network for live sync. */
56
+ activate(id: string): void;
57
+ /** Deactivate a subdocument — disconnects it from the network. */
58
+ deactivate(id: string): void;
59
+ /** Get the Y.XmlFragment for a subdocument. */
60
+ getFragment(id: string): Y.XmlFragment | null;
61
+ /** Check if a subdocument is currently active (syncing). */
62
+ isActive(id: string): boolean;
63
+ /** Get all subdocument states. */
64
+ getAllStates(): SubdocState[];
65
+ /** Get IDs of all active subdocuments. */
66
+ getActiveIds(): string[];
67
+ /** Destroy all subdocuments and providers. */
68
+ destroy(): void;
69
+ }
70
+
71
+ export { type SubdocState, SubdocumentProvider, type SubdocumentProviderOptions };
@@ -0,0 +1,71 @@
1
+ import { Awareness } from 'y-protocols/awareness';
2
+ import { WebsocketProvider } from 'y-websocket';
3
+ import * as Y from 'yjs';
4
+ export { A as AwarenessState, C as CollaborationOptions, a as CollaborationSetup, c as collaborationExtensions, b as createCollaboration } from '../Collaboration-CGv9OZlB.js';
5
+ import '@tiptap/core';
6
+ import 'y-indexeddb';
7
+ import 'y-webrtc';
8
+
9
+ interface SubdocState {
10
+ id: string;
11
+ doc: Y.Doc;
12
+ provider: WebsocketProvider | null;
13
+ active: boolean;
14
+ }
15
+ interface SubdocumentProviderOptions {
16
+ /** WebSocket URL for the collaboration server. */
17
+ websocketUrl: string;
18
+ /** Room prefix — subdocuments use `${roomPrefix}/${id}` as room name. */
19
+ roomPrefix: string;
20
+ /** User info for awareness. */
21
+ user: {
22
+ name: string;
23
+ color: string;
24
+ };
25
+ /** Number of subdocuments to keep active (buffer around visible viewport). */
26
+ maxActive?: number;
27
+ /** Called when subdocument state changes (active/deactivated). */
28
+ onStateChange?: (states: SubdocState[]) => void;
29
+ }
30
+ /**
31
+ * Manages multiple Y.Doc subdocuments under a parent document.
32
+ *
33
+ * Use case: large documents (100+ pages) split into per-section subdocuments.
34
+ * Only active (visible) subdocuments are connected to the network via
35
+ * WebSocketProvider; inactive ones keep local state but stop syncing.
36
+ *
37
+ * Usage:
38
+ * const provider = new SubdocumentProvider({ websocketUrl, roomPrefix, user })
39
+ * provider.createSubdoc('section-1')
40
+ * provider.activate('section-1') // starts syncing
41
+ * provider.deactivate('section-1') // stops syncing
42
+ * const frag = provider.getFragment('section-1') // Y.XmlFragment for editor
43
+ */
44
+ declare class SubdocumentProvider {
45
+ readonly parentDoc: Y.Doc;
46
+ readonly subdocs: Y.Map<Y.Doc>;
47
+ readonly awareness: Awareness;
48
+ private readonly options;
49
+ private readonly states;
50
+ private readonly activeQueue;
51
+ private readonly parentProvider;
52
+ constructor(options: SubdocumentProviderOptions);
53
+ /** Create a new subdocument. Does NOT activate it. */
54
+ createSubdoc(id: string, initialState?: Uint8Array): Y.Doc;
55
+ /** Activate a subdocument — connects it to the network for live sync. */
56
+ activate(id: string): void;
57
+ /** Deactivate a subdocument — disconnects it from the network. */
58
+ deactivate(id: string): void;
59
+ /** Get the Y.XmlFragment for a subdocument. */
60
+ getFragment(id: string): Y.XmlFragment | null;
61
+ /** Check if a subdocument is currently active (syncing). */
62
+ isActive(id: string): boolean;
63
+ /** Get all subdocument states. */
64
+ getAllStates(): SubdocState[];
65
+ /** Get IDs of all active subdocuments. */
66
+ getActiveIds(): string[];
67
+ /** Destroy all subdocuments and providers. */
68
+ destroy(): void;
69
+ }
70
+
71
+ export { type SubdocState, SubdocumentProvider, type SubdocumentProviderOptions };
@@ -0,0 +1,116 @@
1
+ import {
2
+ collaborationExtensions,
3
+ createCollaboration
4
+ } from "../chunk-XJG72F7M.js";
5
+
6
+ // src/SubdocumentProvider.ts
7
+ import { Awareness as AwarenessClass } from "y-protocols/awareness";
8
+ import { WebsocketProvider } from "y-websocket";
9
+ import * as Y from "yjs";
10
+ var SubdocumentProvider = class {
11
+ parentDoc;
12
+ subdocs;
13
+ awareness;
14
+ options;
15
+ states = /* @__PURE__ */ new Map();
16
+ activeQueue = [];
17
+ parentProvider = null;
18
+ constructor(options) {
19
+ this.options = {
20
+ maxActive: options.maxActive ?? 5,
21
+ onStateChange: options.onStateChange ?? (() => {
22
+ }),
23
+ ...options
24
+ };
25
+ this.parentDoc = new Y.Doc();
26
+ this.subdocs = this.parentDoc.getMap("subdocs");
27
+ this.awareness = new AwarenessClass(this.parentDoc);
28
+ this.awareness.setLocalStateField("user", this.options.user);
29
+ this.parentProvider = new WebsocketProvider(
30
+ this.options.websocketUrl,
31
+ `${this.options.roomPrefix}/_parent`,
32
+ this.parentDoc
33
+ );
34
+ }
35
+ /** Create a new subdocument. Does NOT activate it. */
36
+ createSubdoc(id, initialState) {
37
+ if (this.states.has(id)) return this.states.get(id).doc;
38
+ const doc = new Y.Doc();
39
+ if (initialState) Y.applyUpdate(doc, initialState);
40
+ doc.getXmlFragment("default");
41
+ this.subdocs.set(id, doc);
42
+ this.states.set(id, {
43
+ id,
44
+ doc,
45
+ provider: null,
46
+ active: false
47
+ });
48
+ this.options.onStateChange(this.getAllStates());
49
+ return doc;
50
+ }
51
+ /** Activate a subdocument — connects it to the network for live sync. */
52
+ activate(id) {
53
+ const state = this.states.get(id);
54
+ if (!state || state.active) return;
55
+ if (this.activeQueue.length >= this.options.maxActive) {
56
+ const oldest = this.activeQueue.shift();
57
+ if (oldest) this.deactivate(oldest);
58
+ }
59
+ const doc = state.doc;
60
+ const roomName = `${this.options.roomPrefix}/${id}`;
61
+ const provider = new WebsocketProvider(
62
+ this.options.websocketUrl,
63
+ roomName,
64
+ doc
65
+ );
66
+ provider.awareness.setLocalStateField("user", this.options.user);
67
+ state.provider = provider;
68
+ state.active = true;
69
+ this.activeQueue.push(id);
70
+ this.options.onStateChange(this.getAllStates());
71
+ }
72
+ /** Deactivate a subdocument — disconnects it from the network. */
73
+ deactivate(id) {
74
+ const state = this.states.get(id);
75
+ if (!state || !state.active) return;
76
+ state.provider?.destroy();
77
+ state.provider = null;
78
+ state.active = false;
79
+ const idx = this.activeQueue.indexOf(id);
80
+ if (idx >= 0) this.activeQueue.splice(idx, 1);
81
+ this.options.onStateChange(this.getAllStates());
82
+ }
83
+ /** Get the Y.XmlFragment for a subdocument. */
84
+ getFragment(id) {
85
+ const doc = this.states.get(id)?.doc ?? this.subdocs.get(id);
86
+ if (!doc) return null;
87
+ return doc.getXmlFragment("default");
88
+ }
89
+ /** Check if a subdocument is currently active (syncing). */
90
+ isActive(id) {
91
+ return this.states.get(id)?.active ?? false;
92
+ }
93
+ /** Get all subdocument states. */
94
+ getAllStates() {
95
+ return Array.from(this.states.values());
96
+ }
97
+ /** Get IDs of all active subdocuments. */
98
+ getActiveIds() {
99
+ return [...this.activeQueue];
100
+ }
101
+ /** Destroy all subdocuments and providers. */
102
+ destroy() {
103
+ for (const [id] of this.states) {
104
+ this.deactivate(id);
105
+ }
106
+ this.parentProvider?.destroy();
107
+ this.parentDoc.destroy();
108
+ this.states.clear();
109
+ this.activeQueue.length = 0;
110
+ }
111
+ };
112
+ export {
113
+ SubdocumentProvider,
114
+ collaborationExtensions,
115
+ createCollaboration
116
+ };
package/dist/index.cjs CHANGED
@@ -39,7 +39,6 @@ __export(index_exports, {
39
39
  PaginationPlus: () => PaginationPlus,
40
40
  PerformanceMonitor: () => PerformanceMonitor,
41
41
  SearchAndReplaceExtension: () => SearchAndReplaceExtension,
42
- SubdocumentProvider: () => SubdocumentProvider,
43
42
  buildAIPrompt: () => buildAIPrompt,
44
43
  clearSearch: () => clearSearch,
45
44
  collaborationExtensions: () => collaborationExtensions,
@@ -72,8 +71,8 @@ __export(index_exports, {
72
71
  module.exports = __toCommonJS(index_exports);
73
72
 
74
73
  // src/Editor.ts
75
- var import_core5 = require("@tiptap/core");
76
- var import_state4 = require("@tiptap/pm/state");
74
+ var import_core6 = require("@tiptap/core");
75
+ var import_state5 = require("@tiptap/pm/state");
77
76
  var import_starter_kit = __toESM(require("@tiptap/starter-kit"), 1);
78
77
  var import_extension_text_style = __toESM(require("@tiptap/extension-text-style"), 1);
79
78
 
@@ -128,9 +127,6 @@ function createActionMap(editor, plugins) {
128
127
  var import_extension_collaboration = require("@tiptap/extension-collaboration");
129
128
  var import_extension_collaboration_cursor = require("@tiptap/extension-collaboration-cursor");
130
129
  var import_awareness = require("y-protocols/awareness");
131
- var import_y_indexeddb = require("y-indexeddb");
132
- var import_y_webrtc = require("y-webrtc");
133
- var import_y_websocket = require("y-websocket");
134
130
  var Y = __toESM(require("yjs"), 1);
135
131
  var LOCAL_SIGNALING = ["ws://localhost:4444"];
136
132
  var warnedLocalSignaling = false;
@@ -161,25 +157,28 @@ function createAwarenessStates(awareness) {
161
157
  });
162
158
  return states;
163
159
  }
164
- function createCollaboration(options) {
160
+ async function createCollaboration(options) {
165
161
  const ydoc = new Y.Doc();
166
162
  if (options.initialStorageState) {
167
163
  Y.applyUpdate(ydoc, options.initialStorageState);
168
164
  }
169
165
  let persistence;
170
166
  if (options.offline) {
171
- persistence = new import_y_indexeddb.IndexeddbPersistence(`docflow-${options.room}`, ydoc);
167
+ const { IndexeddbPersistence } = await import("y-indexeddb");
168
+ persistence = new IndexeddbPersistence(`docflow-${options.room}`, ydoc);
172
169
  }
173
170
  let provider = null;
174
171
  if (options.provider === "webrtc") {
175
- provider = new import_y_webrtc.WebrtcProvider(options.room, ydoc, {
172
+ const { WebrtcProvider } = await import("y-webrtc");
173
+ provider = new WebrtcProvider(options.room, ydoc, {
176
174
  signaling: resolveSignalingUrls(options.signaling)
177
175
  });
178
176
  } else if (options.provider === "websocket") {
179
177
  if (!options.websocketUrl) {
180
178
  throw new Error('[Collaboration] websocketUrl is required when provider is "websocket"');
181
179
  }
182
- provider = new import_y_websocket.WebsocketProvider(options.websocketUrl, options.room, ydoc);
180
+ const { WebsocketProvider } = await import("y-websocket");
181
+ provider = new WebsocketProvider(options.websocketUrl, options.room, ydoc);
183
182
  }
184
183
  const awareness = provider?.awareness ?? new import_awareness.Awareness(ydoc);
185
184
  awareness.setLocalStateField("user", options.user);
@@ -245,8 +244,7 @@ function createCollaboration(options) {
245
244
  };
246
245
  return { ydoc, provider, awareness, persistence, whenReady, destroy, setLocalCursorEnabled };
247
246
  }
248
- function collaborationExtensions(options) {
249
- const setup = "ydoc" in options ? options : createCollaboration(options);
247
+ function collaborationExtensions(setup) {
250
248
  const extensions = [
251
249
  import_extension_collaboration.Collaboration.configure({ document: setup.ydoc })
252
250
  ];
@@ -322,6 +320,42 @@ var BlockAttributesExtension = import_core.Extension.create({
322
320
  }
323
321
  });
324
322
 
323
+ // src/collab/seedEmptyFragment.ts
324
+ var Y2 = __toESM(require("yjs"), 1);
325
+ var PROVISIONAL_SEED_ORIGIN = "docflow:provisional-seed";
326
+ function isPristineEmptyParagraph(element) {
327
+ return element.length === 0 && Object.keys(element.getAttributes()).length === 0;
328
+ }
329
+ function seedEmptyFragment(doc, field = "default") {
330
+ const fragment = doc.getXmlFragment(field);
331
+ const paragraph = new Y2.XmlElement("paragraph");
332
+ const observer = (_events, transaction) => {
333
+ if (transaction.origin === PROVISIONAL_SEED_ORIGIN) return;
334
+ if (paragraph.parent !== fragment) return;
335
+ if (!isPristineEmptyParagraph(paragraph)) return;
336
+ if (fragment.length < 2) return;
337
+ const index = fragment.toArray().indexOf(paragraph);
338
+ if (index === -1) return;
339
+ doc.transact(() => {
340
+ fragment.delete(index);
341
+ }, PROVISIONAL_SEED_ORIGIN);
342
+ };
343
+ let disposed = false;
344
+ const dispose = () => {
345
+ if (disposed) return;
346
+ disposed = true;
347
+ fragment.unobserveDeep(observer);
348
+ };
349
+ if (fragment.length > 0) {
350
+ return { seeded: false, dispose };
351
+ }
352
+ fragment.observeDeep(observer);
353
+ doc.transact(() => {
354
+ fragment.insert(0, [paragraph]);
355
+ }, PROVISIONAL_SEED_ORIGIN);
356
+ return { seeded: true, dispose };
357
+ }
358
+
325
359
  // src/EditorContext.ts
326
360
  var import_core2 = require("@tiptap/core");
327
361
  var EditorContextExtension = import_core2.Extension.create({
@@ -1272,6 +1306,94 @@ var PaginationPlus = import_core4.Extension.create({
1272
1306
  }
1273
1307
  });
1274
1308
 
1309
+ // src/pagination/PaginationCaretFix.ts
1310
+ var import_core5 = require("@tiptap/core");
1311
+ var import_state4 = require("@tiptap/pm/state");
1312
+ var PAGINATION_CLASS = "rm-with-pagination";
1313
+ var PAGINATION_DISABLED_ATTR = "rm-pagination-disabled";
1314
+ var dragStates = /* @__PURE__ */ new WeakMap();
1315
+ var isPaginationActive = (view) => {
1316
+ const dom = view.dom;
1317
+ return dom.classList.contains(PAGINATION_CLASS) && dom.getAttribute(PAGINATION_DISABLED_ATTR) === null;
1318
+ };
1319
+ var isEditable = (view) => view.dom.getAttribute("contenteditable") !== "false";
1320
+ var isPlainSingleLeftClick = (event) => event.button === 0 && event.detail === 1 && !event.shiftKey && !event.altKey && !event.ctrlKey && !event.metaKey;
1321
+ function posFromTextOffset(view, textNode, offset) {
1322
+ if (textNode.nodeType !== Node.TEXT_NODE || !view.dom.contains(textNode)) return null;
1323
+ const text = textNode;
1324
+ const clamped = Math.min(Math.max(0, offset), text.length);
1325
+ const parent = text.parentElement;
1326
+ if (parent?.closest?.('[contenteditable="false"]')) return null;
1327
+ let pos = view.posAtDOM(text, clamped, -1);
1328
+ if (pos < 0) pos = view.posAtDOM(text, clamped, 1);
1329
+ if (pos < 0) return null;
1330
+ return view.state.doc.resolve(pos).parent.isTextblock ? pos : null;
1331
+ }
1332
+ function resolvePosFromNativePoint(view, clientX, clientY) {
1333
+ const doc = view.dom.ownerDocument;
1334
+ if (typeof doc.caretRangeFromPoint !== "function") return null;
1335
+ const range = doc.caretRangeFromPoint(clientX, clientY);
1336
+ if (!range) return null;
1337
+ return posFromTextOffset(view, range.startContainer, range.startOffset);
1338
+ }
1339
+ function stopDrag(view) {
1340
+ const drag = dragStates.get(view);
1341
+ if (!drag) return;
1342
+ dragStates.delete(view);
1343
+ const doc = view.dom.ownerDocument;
1344
+ doc.removeEventListener("mousemove", drag.onMouseMove);
1345
+ doc.removeEventListener("mouseup", drag.onMouseUp);
1346
+ }
1347
+ function beginDrag(view, anchorPos) {
1348
+ stopDrag(view);
1349
+ const doc = view.dom.ownerDocument;
1350
+ const onMouseMove = (event) => {
1351
+ const drag = dragStates.get(view);
1352
+ if (!drag) return;
1353
+ const pos = resolvePosFromNativePoint(view, event.clientX, event.clientY);
1354
+ if (pos === null) return;
1355
+ const from = Math.min(drag.anchorPos, pos);
1356
+ const to = Math.max(drag.anchorPos, pos);
1357
+ view.dispatch(view.state.tr.setSelection(import_state4.TextSelection.create(view.state.doc, from, to)));
1358
+ };
1359
+ const onMouseUp = () => {
1360
+ stopDrag(view);
1361
+ };
1362
+ dragStates.set(view, { anchorPos, onMouseMove, onMouseUp });
1363
+ doc.addEventListener("mousemove", onMouseMove);
1364
+ doc.addEventListener("mouseup", onMouseUp);
1365
+ }
1366
+ function interceptPaginationMouseDown(view, event) {
1367
+ if (!isPaginationActive(view) || !isPlainSingleLeftClick(event) || !isEditable(view)) return false;
1368
+ const pos = resolvePosFromNativePoint(view, event.clientX, event.clientY);
1369
+ if (pos === null) return false;
1370
+ view.focus();
1371
+ view.dispatch(view.state.tr.setSelection(import_state4.TextSelection.create(view.state.doc, pos)));
1372
+ beginDrag(view, pos);
1373
+ return true;
1374
+ }
1375
+ var PaginationCaretFix = import_core5.Extension.create({
1376
+ name: "paginationCaretFix",
1377
+ addProseMirrorPlugins() {
1378
+ return [
1379
+ new import_state4.Plugin({
1380
+ key: new import_state4.PluginKey("paginationCaretFix"),
1381
+ props: {
1382
+ handleDOMEvents: {
1383
+ mousedown: (view, event) => {
1384
+ try {
1385
+ return interceptPaginationMouseDown(view, event);
1386
+ } catch {
1387
+ return false;
1388
+ }
1389
+ }
1390
+ }
1391
+ }
1392
+ })
1393
+ ];
1394
+ }
1395
+ });
1396
+
1275
1397
  // src/PerformanceMonitor.ts
1276
1398
  var TARGET_FRAME_MS = 1e3 / 60;
1277
1399
  var formatMb = (bytes) => `${Math.round(bytes / 1024 / 1024)}MB`;
@@ -1639,7 +1761,7 @@ function createEditor(options = {}) {
1639
1761
  content: options.content ? migrateContent(options.content) : options.content
1640
1762
  };
1641
1763
  const plugins = migratedOptions.plugins ?? [];
1642
- const collaborationSetup = !migratedOptions.collaboration ? void 0 : "ydoc" in migratedOptions.collaboration ? migratedOptions.collaboration : createCollaboration(migratedOptions.collaboration);
1764
+ const collaborationSetup = migratedOptions.collaboration;
1643
1765
  const performanceMonitor = migratedOptions.debug ? createPerformanceMonitor() : void 0;
1644
1766
  let tiptapEditor = createTiptapEditor(migratedOptions, plugins, collaborationSetup);
1645
1767
  let pluginActions = createActionMap(tiptapEditor, plugins);
@@ -1700,11 +1822,11 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
1700
1822
  const pluginExtensions = collectExtensions(plugins);
1701
1823
  const blockAttrs = options.getPageMap ? BlockAttributesExtension.configure({ pageMap: options.getPageMap }) : BlockAttributesExtension;
1702
1824
  const paginationExt = options.paginationOptions ? PaginationPlus.configure(options.paginationOptions) : PaginationPlus;
1703
- const ManualColumnResize = import_core5.Extension.create({
1825
+ const ManualColumnResize = import_core6.Extension.create({
1704
1826
  name: "manualColumnResize",
1705
1827
  addProseMirrorPlugins() {
1706
- const key2 = new import_state4.PluginKey("manualColumnResize");
1707
- return [new import_state4.Plugin({
1828
+ const key2 = new import_state5.PluginKey("manualColumnResize");
1829
+ return [new import_state5.Plugin({
1708
1830
  key: key2,
1709
1831
  view(view) {
1710
1832
  function pauseObserver() {
@@ -2026,6 +2148,10 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
2026
2148
  import_extension_text_style.default,
2027
2149
  blockAttrs,
2028
2150
  paginationExt,
2151
+ // Always present — fixes caret-on-click misplacement caused by the
2152
+ // pagination DOM (header/footer/gap widgets breaking linear coordinates).
2153
+ // No-op (gated at runtime) when pagination is off or disabled.
2154
+ PaginationCaretFix,
2029
2155
  // Always present — carries host-injected ports (onImageUpload, citation, …)
2030
2156
  // in storage so plugin commands can reach them through the editor instance.
2031
2157
  EditorContextExtension.configure({
@@ -2040,9 +2166,18 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
2040
2166
  ];
2041
2167
  const content = options.collaboration ? void 0 : options.content;
2042
2168
  if (options.collaboration && collaborationSetup) {
2169
+ const seed = seedEmptyFragment(collaborationSetup.ydoc);
2170
+ if (seed.seeded) {
2171
+ extensions.push(
2172
+ import_core6.Extension.create({
2173
+ name: "provisionalSeedCleanup",
2174
+ onDestroy: () => seed.dispose()
2175
+ })
2176
+ );
2177
+ }
2043
2178
  extensions = [...extensions, ...collaborationExtensions(collaborationSetup)];
2044
2179
  }
2045
- return new import_core5.Editor({
2180
+ const tiptapEditor = new import_core6.Editor({
2046
2181
  element: options.target,
2047
2182
  content,
2048
2183
  extensions,
@@ -2057,10 +2192,11 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
2057
2192
  transformPastedHTML: sanitizePastedHTML
2058
2193
  }
2059
2194
  });
2195
+ return tiptapEditor;
2060
2196
  }
2061
2197
 
2062
2198
  // src/FontSize.ts
2063
- var import_core6 = require("@tiptap/core");
2199
+ var import_core7 = require("@tiptap/core");
2064
2200
  function mergeFontSize(textStyleType, existing, fontSize) {
2065
2201
  if (fontSize === null) {
2066
2202
  const { fontSize: _removed, ...rest } = existing?.attrs ?? {};
@@ -2071,7 +2207,7 @@ function mergeFontSize(textStyleType, existing, fontSize) {
2071
2207
  function hasAttrs(mark) {
2072
2208
  return Object.values(mark.attrs).some((v) => v != null);
2073
2209
  }
2074
- var FontSizeExtension = import_core6.Extension.create({
2210
+ var FontSizeExtension = import_core7.Extension.create({
2075
2211
  name: "fontSize",
2076
2212
  addGlobalAttributes() {
2077
2213
  return [
@@ -2169,113 +2305,6 @@ var FontSizeExtension = import_core6.Extension.create({
2169
2305
  }
2170
2306
  });
2171
2307
 
2172
- // src/SubdocumentProvider.ts
2173
- var import_awareness2 = require("y-protocols/awareness");
2174
- var import_y_websocket2 = require("y-websocket");
2175
- var Y2 = __toESM(require("yjs"), 1);
2176
- var SubdocumentProvider = class {
2177
- parentDoc;
2178
- subdocs;
2179
- awareness;
2180
- options;
2181
- states = /* @__PURE__ */ new Map();
2182
- activeQueue = [];
2183
- parentProvider = null;
2184
- constructor(options) {
2185
- this.options = {
2186
- maxActive: options.maxActive ?? 5,
2187
- onStateChange: options.onStateChange ?? (() => {
2188
- }),
2189
- ...options
2190
- };
2191
- this.parentDoc = new Y2.Doc();
2192
- this.subdocs = this.parentDoc.getMap("subdocs");
2193
- this.awareness = new import_awareness2.Awareness(this.parentDoc);
2194
- this.awareness.setLocalStateField("user", this.options.user);
2195
- this.parentProvider = new import_y_websocket2.WebsocketProvider(
2196
- this.options.websocketUrl,
2197
- `${this.options.roomPrefix}/_parent`,
2198
- this.parentDoc
2199
- );
2200
- }
2201
- /** Create a new subdocument. Does NOT activate it. */
2202
- createSubdoc(id, initialState) {
2203
- if (this.states.has(id)) return this.states.get(id).doc;
2204
- const doc = new Y2.Doc();
2205
- if (initialState) Y2.applyUpdate(doc, initialState);
2206
- doc.getXmlFragment("default");
2207
- this.subdocs.set(id, doc);
2208
- this.states.set(id, {
2209
- id,
2210
- doc,
2211
- provider: null,
2212
- active: false
2213
- });
2214
- this.options.onStateChange(this.getAllStates());
2215
- return doc;
2216
- }
2217
- /** Activate a subdocument — connects it to the network for live sync. */
2218
- activate(id) {
2219
- const state = this.states.get(id);
2220
- if (!state || state.active) return;
2221
- if (this.activeQueue.length >= this.options.maxActive) {
2222
- const oldest = this.activeQueue.shift();
2223
- if (oldest) this.deactivate(oldest);
2224
- }
2225
- const doc = state.doc;
2226
- const roomName = `${this.options.roomPrefix}/${id}`;
2227
- const provider = new import_y_websocket2.WebsocketProvider(
2228
- this.options.websocketUrl,
2229
- roomName,
2230
- doc
2231
- );
2232
- provider.awareness.setLocalStateField("user", this.options.user);
2233
- state.provider = provider;
2234
- state.active = true;
2235
- this.activeQueue.push(id);
2236
- this.options.onStateChange(this.getAllStates());
2237
- }
2238
- /** Deactivate a subdocument — disconnects it from the network. */
2239
- deactivate(id) {
2240
- const state = this.states.get(id);
2241
- if (!state || !state.active) return;
2242
- state.provider?.destroy();
2243
- state.provider = null;
2244
- state.active = false;
2245
- const idx = this.activeQueue.indexOf(id);
2246
- if (idx >= 0) this.activeQueue.splice(idx, 1);
2247
- this.options.onStateChange(this.getAllStates());
2248
- }
2249
- /** Get the Y.XmlFragment for a subdocument. */
2250
- getFragment(id) {
2251
- const doc = this.states.get(id)?.doc ?? this.subdocs.get(id);
2252
- if (!doc) return null;
2253
- return doc.getXmlFragment("default");
2254
- }
2255
- /** Check if a subdocument is currently active (syncing). */
2256
- isActive(id) {
2257
- return this.states.get(id)?.active ?? false;
2258
- }
2259
- /** Get all subdocument states. */
2260
- getAllStates() {
2261
- return Array.from(this.states.values());
2262
- }
2263
- /** Get IDs of all active subdocuments. */
2264
- getActiveIds() {
2265
- return [...this.activeQueue];
2266
- }
2267
- /** Destroy all subdocuments and providers. */
2268
- destroy() {
2269
- for (const [id] of this.states) {
2270
- this.deactivate(id);
2271
- }
2272
- this.parentProvider?.destroy();
2273
- this.parentDoc.destroy();
2274
- this.states.clear();
2275
- this.activeQueue.length = 0;
2276
- }
2277
- };
2278
-
2279
2308
  // src/ai/prompts.ts
2280
2309
  var CONTEXT_CHAR_CAP = 1500;
2281
2310
  var ONLY_RESULT = "Return ONLY the resulting text \u2014 no preamble, no explanation, no commentary, no markdown fences.";
@@ -2549,7 +2578,6 @@ function openaiCompatibleProvider(config) {
2549
2578
  PaginationPlus,
2550
2579
  PerformanceMonitor,
2551
2580
  SearchAndReplaceExtension,
2552
- SubdocumentProvider,
2553
2581
  buildAIPrompt,
2554
2582
  clearSearch,
2555
2583
  collaborationExtensions,