@kedataindo/docflow-core 0.0.70 → 0.0.72

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
+ };
@@ -84,6 +84,8 @@ interface AIActionRequest {
84
84
  before: string;
85
85
  after: string;
86
86
  } & AIContextLocation;
87
+ /** Cursor location context (page, line, paragraph index, section heading). */
88
+ location?: AIContextLocation;
87
89
  /** User instruction (/ai prompt, chat message, tone target, target language). */
88
90
  prompt?: string;
89
91
  /** For doc-aware chat / RAG scoping. */
@@ -84,6 +84,8 @@ interface AIActionRequest {
84
84
  before: string;
85
85
  after: string;
86
86
  } & AIContextLocation;
87
+ /** Cursor location context (page, line, paragraph index, section heading). */
88
+ location?: AIContextLocation;
87
89
  /** User instruction (/ai prompt, chat message, tone target, target language). */
88
90
  prompt?: string;
89
91
  /** For doc-aware chat / RAG scoping. */
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,
@@ -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({
@@ -729,27 +763,27 @@ var calculatePageCount = (view, pageOptions, headerHeight = 0, footerHeight = 0)
729
763
  return currentPageCount;
730
764
  }
731
765
  }
766
+ let totalEditorContentHeight = 0;
767
+ for (const child of Array.from(editorDom.children)) {
768
+ if (!(child instanceof HTMLElement)) continue;
769
+ if (child.hasAttribute("data-rm-pagination")) continue;
770
+ if (child.classList.contains("rm-page-break")) continue;
771
+ totalEditorContentHeight += child.getBoundingClientRect().height;
772
+ }
773
+ const maxPagesByContent = Math.ceil(totalEditorContentHeight / pageContentAreaHeight);
774
+ const contentCap = Math.max(currentPageCount, maxPagesByContent + 1);
732
775
  const prev = pageGapTracker.get(editorDom);
733
- if (prev && prev.pages < currentPageCount && lastPageGap > prev.gap - 2) {
776
+ if (prev && prev.pages < currentPageCount && lastPageGap > prev.gap - 2 && currentPageCount >= maxPagesByContent) {
734
777
  return currentPageCount;
735
778
  }
736
779
  const recent = prev?.recent ?? [];
737
780
  let flapping = prev?.flapping ?? [];
738
- if (recent.length >= 4 && recent.filter((p) => p === currentPageCount + addPage).length >= 2) {
781
+ if (recent.length >= 4 && recent.filter((p) => p === currentPageCount + addPage).length >= 2 && currentPageCount >= maxPagesByContent) {
739
782
  flapping = [.../* @__PURE__ */ new Set([...flapping, currentPageCount + addPage, currentPageCount])];
740
783
  pageGapTracker.set(editorDom, { gap: lastPageGap, pages: currentPageCount, recent, flapping });
741
784
  return currentPageCount;
742
785
  }
743
786
  pageGapTracker.set(editorDom, { gap: lastPageGap, pages: currentPageCount, recent, flapping });
744
- let totalEditorContentHeight = 0;
745
- for (const child of Array.from(editorDom.children)) {
746
- if (!(child instanceof HTMLElement)) continue;
747
- if (child.hasAttribute("data-rm-pagination")) continue;
748
- if (child.classList.contains("rm-page-break")) continue;
749
- totalEditorContentHeight += child.getBoundingClientRect().height;
750
- }
751
- const maxPagesByContent = Math.ceil(totalEditorContentHeight / pageContentAreaHeight);
752
- const contentCap = Math.max(currentPageCount, maxPagesByContent + 1);
753
787
  if (currentPageCount + addPage > contentCap) {
754
788
  return contentCap;
755
789
  }
@@ -1639,7 +1673,7 @@ function createEditor(options = {}) {
1639
1673
  content: options.content ? migrateContent(options.content) : options.content
1640
1674
  };
1641
1675
  const plugins = migratedOptions.plugins ?? [];
1642
- const collaborationSetup = !migratedOptions.collaboration ? void 0 : "ydoc" in migratedOptions.collaboration ? migratedOptions.collaboration : createCollaboration(migratedOptions.collaboration);
1676
+ const collaborationSetup = migratedOptions.collaboration;
1643
1677
  const performanceMonitor = migratedOptions.debug ? createPerformanceMonitor() : void 0;
1644
1678
  let tiptapEditor = createTiptapEditor(migratedOptions, plugins, collaborationSetup);
1645
1679
  let pluginActions = createActionMap(tiptapEditor, plugins);
@@ -2040,9 +2074,18 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
2040
2074
  ];
2041
2075
  const content = options.collaboration ? void 0 : options.content;
2042
2076
  if (options.collaboration && collaborationSetup) {
2077
+ const seed = seedEmptyFragment(collaborationSetup.ydoc);
2078
+ if (seed.seeded) {
2079
+ extensions.push(
2080
+ import_core5.Extension.create({
2081
+ name: "provisionalSeedCleanup",
2082
+ onDestroy: () => seed.dispose()
2083
+ })
2084
+ );
2085
+ }
2043
2086
  extensions = [...extensions, ...collaborationExtensions(collaborationSetup)];
2044
2087
  }
2045
- return new import_core5.Editor({
2088
+ const tiptapEditor = new import_core5.Editor({
2046
2089
  element: options.target,
2047
2090
  content,
2048
2091
  extensions,
@@ -2057,6 +2100,7 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
2057
2100
  transformPastedHTML: sanitizePastedHTML
2058
2101
  }
2059
2102
  });
2103
+ return tiptapEditor;
2060
2104
  }
2061
2105
 
2062
2106
  // src/FontSize.ts
@@ -2169,113 +2213,6 @@ var FontSizeExtension = import_core6.Extension.create({
2169
2213
  }
2170
2214
  });
2171
2215
 
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
2216
  // src/ai/prompts.ts
2280
2217
  var CONTEXT_CHAR_CAP = 1500;
2281
2218
  var ONLY_RESULT = "Return ONLY the resulting text \u2014 no preamble, no explanation, no commentary, no markdown fences.";
@@ -2549,7 +2486,6 @@ function openaiCompatibleProvider(config) {
2549
2486
  PaginationPlus,
2550
2487
  PerformanceMonitor,
2551
2488
  SearchAndReplaceExtension,
2552
- SubdocumentProvider,
2553
2489
  buildAIPrompt,
2554
2490
  clearSearch,
2555
2491
  collaborationExtensions,