@kedataindo/docflow-core 0.0.71 → 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.
- package/dist/Collaboration-CGv9OZlB.d.cts +109 -0
- package/dist/Collaboration-CGv9OZlB.d.ts +109 -0
- package/dist/chunk-XJG72F7M.js +140 -0
- package/dist/collab/index.cjs +286 -0
- package/dist/collab/index.d.cts +71 -0
- package/dist/collab/index.d.ts +71 -0
- package/dist/collab/index.js +116 -0
- package/dist/index.cjs +56 -120
- package/dist/index.d.cts +18 -150
- package/dist/index.d.ts +18 -150
- package/dist/index.js +52 -247
- package/package.json +6 -1
|
@@ -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,
|
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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({
|
|
@@ -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 =
|
|
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
|
-
|
|
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,
|