@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
package/dist/index.js
CHANGED
|
@@ -10,6 +10,10 @@ import {
|
|
|
10
10
|
trimContextAfter,
|
|
11
11
|
trimContextBefore
|
|
12
12
|
} from "./chunk-HMOWKFPE.js";
|
|
13
|
+
import {
|
|
14
|
+
collaborationExtensions,
|
|
15
|
+
createCollaboration
|
|
16
|
+
} from "./chunk-XJG72F7M.js";
|
|
13
17
|
|
|
14
18
|
// src/Editor.ts
|
|
15
19
|
import { Extension as Extension5, Editor as TiptapEditor } from "@tiptap/core";
|
|
@@ -64,143 +68,6 @@ function createActionMap(editor, plugins) {
|
|
|
64
68
|
return map;
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
// src/Collaboration.ts
|
|
68
|
-
import { Collaboration } from "@tiptap/extension-collaboration";
|
|
69
|
-
import { CollaborationCursor } from "@tiptap/extension-collaboration-cursor";
|
|
70
|
-
import { Awareness } from "y-protocols/awareness";
|
|
71
|
-
import { IndexeddbPersistence } from "y-indexeddb";
|
|
72
|
-
import { WebrtcProvider } from "y-webrtc";
|
|
73
|
-
import { WebsocketProvider } from "y-websocket";
|
|
74
|
-
import * as Y from "yjs";
|
|
75
|
-
var LOCAL_SIGNALING = ["ws://localhost:4444"];
|
|
76
|
-
var warnedLocalSignaling = false;
|
|
77
|
-
function resolveSignalingUrls(signaling) {
|
|
78
|
-
if (signaling && signaling.length > 0) return signaling;
|
|
79
|
-
if (!warnedLocalSignaling) {
|
|
80
|
-
warnedLocalSignaling = true;
|
|
81
|
-
console.warn(
|
|
82
|
-
'[docflow] webrtc provider has no `signaling` configured \u2014 falling back to localhost-only sync (ws://localhost:4444 + same-browser tabs). For production self-host, run your own signaling server and pass `signaling`, or use `provider: "websocket"` with your own websocketUrl.'
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
return LOCAL_SIGNALING;
|
|
86
|
-
}
|
|
87
|
-
var LOCAL_PRESENT_DEFAULT = true;
|
|
88
|
-
function createAwarenessStates(awareness) {
|
|
89
|
-
const states = [];
|
|
90
|
-
awareness.getStates().forEach((state, clientId) => {
|
|
91
|
-
const raw = state;
|
|
92
|
-
states.push({
|
|
93
|
-
clientId,
|
|
94
|
-
user: raw.user ?? { name: "", color: "" },
|
|
95
|
-
cursor: raw.cursor ?? null,
|
|
96
|
-
// `present` defaults to true for backwards compat (legacy states
|
|
97
|
-
// don't set it) and for the local user (always considered present
|
|
98
|
-
// until PR2 toggles it off).
|
|
99
|
-
present: raw.present ?? LOCAL_PRESENT_DEFAULT
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
return states;
|
|
103
|
-
}
|
|
104
|
-
function createCollaboration(options) {
|
|
105
|
-
const ydoc = new Y.Doc();
|
|
106
|
-
if (options.initialStorageState) {
|
|
107
|
-
Y.applyUpdate(ydoc, options.initialStorageState);
|
|
108
|
-
}
|
|
109
|
-
let persistence;
|
|
110
|
-
if (options.offline) {
|
|
111
|
-
persistence = new IndexeddbPersistence(`docflow-${options.room}`, ydoc);
|
|
112
|
-
}
|
|
113
|
-
let provider = null;
|
|
114
|
-
if (options.provider === "webrtc") {
|
|
115
|
-
provider = new WebrtcProvider(options.room, ydoc, {
|
|
116
|
-
signaling: resolveSignalingUrls(options.signaling)
|
|
117
|
-
});
|
|
118
|
-
} else if (options.provider === "websocket") {
|
|
119
|
-
if (!options.websocketUrl) {
|
|
120
|
-
throw new Error('[Collaboration] websocketUrl is required when provider is "websocket"');
|
|
121
|
-
}
|
|
122
|
-
provider = new WebsocketProvider(options.websocketUrl, options.room, ydoc);
|
|
123
|
-
}
|
|
124
|
-
const awareness = provider?.awareness ?? new Awareness(ydoc);
|
|
125
|
-
awareness.setLocalStateField("user", options.user);
|
|
126
|
-
let emitCursor = options.emitCursor ?? true;
|
|
127
|
-
const setLocalCursorEnabled = (enabled) => {
|
|
128
|
-
if (emitCursor === enabled) return;
|
|
129
|
-
emitCursor = enabled;
|
|
130
|
-
if (!enabled) {
|
|
131
|
-
awareness.setLocalStateField("cursor", null);
|
|
132
|
-
}
|
|
133
|
-
awareness.setLocalStateField("emitCursor", enabled);
|
|
134
|
-
};
|
|
135
|
-
awareness.setLocalStateField("present", true);
|
|
136
|
-
awareness.setLocalStateField("emitCursor", emitCursor);
|
|
137
|
-
let awarenessHandler;
|
|
138
|
-
if (options.onAwarenessChange) {
|
|
139
|
-
const notify = () => {
|
|
140
|
-
options.onAwarenessChange?.(createAwarenessStates(awareness));
|
|
141
|
-
};
|
|
142
|
-
awarenessHandler = notify;
|
|
143
|
-
awareness.on("change", notify);
|
|
144
|
-
notify();
|
|
145
|
-
}
|
|
146
|
-
const readyParts = [];
|
|
147
|
-
if (persistence) {
|
|
148
|
-
readyParts.push(
|
|
149
|
-
persistence.whenSynced.then(
|
|
150
|
-
() => void 0,
|
|
151
|
-
() => void 0
|
|
152
|
-
)
|
|
153
|
-
);
|
|
154
|
-
}
|
|
155
|
-
if (provider && options.provider === "websocket") {
|
|
156
|
-
const ws = provider;
|
|
157
|
-
readyParts.push(
|
|
158
|
-
new Promise((resolve) => {
|
|
159
|
-
let settled = false;
|
|
160
|
-
const done = () => {
|
|
161
|
-
if (settled) return;
|
|
162
|
-
settled = true;
|
|
163
|
-
resolve();
|
|
164
|
-
};
|
|
165
|
-
if (ws.synced) {
|
|
166
|
-
done();
|
|
167
|
-
return;
|
|
168
|
-
}
|
|
169
|
-
ws.once("sync", done);
|
|
170
|
-
ws.once("synced", done);
|
|
171
|
-
setTimeout(done, 5e3);
|
|
172
|
-
})
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
const whenReady = readyParts.length === 0 ? Promise.resolve() : Promise.all(readyParts).then(() => void 0);
|
|
176
|
-
const destroy = () => {
|
|
177
|
-
if (awarenessHandler) {
|
|
178
|
-
awareness.off("change", awarenessHandler);
|
|
179
|
-
}
|
|
180
|
-
awareness.setLocalState(null);
|
|
181
|
-
provider?.destroy?.();
|
|
182
|
-
awareness.destroy?.();
|
|
183
|
-
void persistence?.destroy();
|
|
184
|
-
ydoc.destroy();
|
|
185
|
-
};
|
|
186
|
-
return { ydoc, provider, awareness, persistence, whenReady, destroy, setLocalCursorEnabled };
|
|
187
|
-
}
|
|
188
|
-
function collaborationExtensions(options) {
|
|
189
|
-
const setup = "ydoc" in options ? options : createCollaboration(options);
|
|
190
|
-
const extensions = [
|
|
191
|
-
Collaboration.configure({ document: setup.ydoc })
|
|
192
|
-
];
|
|
193
|
-
if (setup.provider) {
|
|
194
|
-
extensions.push(
|
|
195
|
-
CollaborationCursor.configure({
|
|
196
|
-
provider: setup.provider,
|
|
197
|
-
user: setup.awareness.getLocalState()?.user ?? { name: "", color: "" }
|
|
198
|
-
})
|
|
199
|
-
);
|
|
200
|
-
}
|
|
201
|
-
return extensions;
|
|
202
|
-
}
|
|
203
|
-
|
|
204
71
|
// src/BlockAttributes.ts
|
|
205
72
|
import { Extension } from "@tiptap/core";
|
|
206
73
|
import { Plugin, PluginKey } from "@tiptap/pm/state";
|
|
@@ -262,6 +129,42 @@ var BlockAttributesExtension = Extension.create({
|
|
|
262
129
|
}
|
|
263
130
|
});
|
|
264
131
|
|
|
132
|
+
// src/collab/seedEmptyFragment.ts
|
|
133
|
+
import * as Y from "yjs";
|
|
134
|
+
var PROVISIONAL_SEED_ORIGIN = "docflow:provisional-seed";
|
|
135
|
+
function isPristineEmptyParagraph(element) {
|
|
136
|
+
return element.length === 0 && Object.keys(element.getAttributes()).length === 0;
|
|
137
|
+
}
|
|
138
|
+
function seedEmptyFragment(doc, field = "default") {
|
|
139
|
+
const fragment = doc.getXmlFragment(field);
|
|
140
|
+
const paragraph = new Y.XmlElement("paragraph");
|
|
141
|
+
const observer = (_events, transaction) => {
|
|
142
|
+
if (transaction.origin === PROVISIONAL_SEED_ORIGIN) return;
|
|
143
|
+
if (paragraph.parent !== fragment) return;
|
|
144
|
+
if (!isPristineEmptyParagraph(paragraph)) return;
|
|
145
|
+
if (fragment.length < 2) return;
|
|
146
|
+
const index = fragment.toArray().indexOf(paragraph);
|
|
147
|
+
if (index === -1) return;
|
|
148
|
+
doc.transact(() => {
|
|
149
|
+
fragment.delete(index);
|
|
150
|
+
}, PROVISIONAL_SEED_ORIGIN);
|
|
151
|
+
};
|
|
152
|
+
let disposed = false;
|
|
153
|
+
const dispose = () => {
|
|
154
|
+
if (disposed) return;
|
|
155
|
+
disposed = true;
|
|
156
|
+
fragment.unobserveDeep(observer);
|
|
157
|
+
};
|
|
158
|
+
if (fragment.length > 0) {
|
|
159
|
+
return { seeded: false, dispose };
|
|
160
|
+
}
|
|
161
|
+
fragment.observeDeep(observer);
|
|
162
|
+
doc.transact(() => {
|
|
163
|
+
fragment.insert(0, [paragraph]);
|
|
164
|
+
}, PROVISIONAL_SEED_ORIGIN);
|
|
165
|
+
return { seeded: true, dispose };
|
|
166
|
+
}
|
|
167
|
+
|
|
265
168
|
// src/EditorContext.ts
|
|
266
169
|
import { Extension as Extension2 } from "@tiptap/core";
|
|
267
170
|
var EditorContextExtension = Extension2.create({
|
|
@@ -1579,7 +1482,7 @@ function createEditor(options = {}) {
|
|
|
1579
1482
|
content: options.content ? migrateContent(options.content) : options.content
|
|
1580
1483
|
};
|
|
1581
1484
|
const plugins = migratedOptions.plugins ?? [];
|
|
1582
|
-
const collaborationSetup =
|
|
1485
|
+
const collaborationSetup = migratedOptions.collaboration;
|
|
1583
1486
|
const performanceMonitor = migratedOptions.debug ? createPerformanceMonitor() : void 0;
|
|
1584
1487
|
let tiptapEditor = createTiptapEditor(migratedOptions, plugins, collaborationSetup);
|
|
1585
1488
|
let pluginActions = createActionMap(tiptapEditor, plugins);
|
|
@@ -1980,9 +1883,18 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
|
|
|
1980
1883
|
];
|
|
1981
1884
|
const content = options.collaboration ? void 0 : options.content;
|
|
1982
1885
|
if (options.collaboration && collaborationSetup) {
|
|
1886
|
+
const seed = seedEmptyFragment(collaborationSetup.ydoc);
|
|
1887
|
+
if (seed.seeded) {
|
|
1888
|
+
extensions.push(
|
|
1889
|
+
Extension5.create({
|
|
1890
|
+
name: "provisionalSeedCleanup",
|
|
1891
|
+
onDestroy: () => seed.dispose()
|
|
1892
|
+
})
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1983
1895
|
extensions = [...extensions, ...collaborationExtensions(collaborationSetup)];
|
|
1984
1896
|
}
|
|
1985
|
-
|
|
1897
|
+
const tiptapEditor = new TiptapEditor({
|
|
1986
1898
|
element: options.target,
|
|
1987
1899
|
content,
|
|
1988
1900
|
extensions,
|
|
@@ -1997,6 +1909,7 @@ function createTiptapEditor(options, plugins, collaborationSetup) {
|
|
|
1997
1909
|
transformPastedHTML: sanitizePastedHTML
|
|
1998
1910
|
}
|
|
1999
1911
|
});
|
|
1912
|
+
return tiptapEditor;
|
|
2000
1913
|
}
|
|
2001
1914
|
|
|
2002
1915
|
// src/FontSize.ts
|
|
@@ -2108,113 +2021,6 @@ var FontSizeExtension = Extension6.create({
|
|
|
2108
2021
|
};
|
|
2109
2022
|
}
|
|
2110
2023
|
});
|
|
2111
|
-
|
|
2112
|
-
// src/SubdocumentProvider.ts
|
|
2113
|
-
import { Awareness as AwarenessClass } from "y-protocols/awareness";
|
|
2114
|
-
import { WebsocketProvider as WebsocketProvider2 } from "y-websocket";
|
|
2115
|
-
import * as Y2 from "yjs";
|
|
2116
|
-
var SubdocumentProvider = class {
|
|
2117
|
-
parentDoc;
|
|
2118
|
-
subdocs;
|
|
2119
|
-
awareness;
|
|
2120
|
-
options;
|
|
2121
|
-
states = /* @__PURE__ */ new Map();
|
|
2122
|
-
activeQueue = [];
|
|
2123
|
-
parentProvider = null;
|
|
2124
|
-
constructor(options) {
|
|
2125
|
-
this.options = {
|
|
2126
|
-
maxActive: options.maxActive ?? 5,
|
|
2127
|
-
onStateChange: options.onStateChange ?? (() => {
|
|
2128
|
-
}),
|
|
2129
|
-
...options
|
|
2130
|
-
};
|
|
2131
|
-
this.parentDoc = new Y2.Doc();
|
|
2132
|
-
this.subdocs = this.parentDoc.getMap("subdocs");
|
|
2133
|
-
this.awareness = new AwarenessClass(this.parentDoc);
|
|
2134
|
-
this.awareness.setLocalStateField("user", this.options.user);
|
|
2135
|
-
this.parentProvider = new WebsocketProvider2(
|
|
2136
|
-
this.options.websocketUrl,
|
|
2137
|
-
`${this.options.roomPrefix}/_parent`,
|
|
2138
|
-
this.parentDoc
|
|
2139
|
-
);
|
|
2140
|
-
}
|
|
2141
|
-
/** Create a new subdocument. Does NOT activate it. */
|
|
2142
|
-
createSubdoc(id, initialState) {
|
|
2143
|
-
if (this.states.has(id)) return this.states.get(id).doc;
|
|
2144
|
-
const doc = new Y2.Doc();
|
|
2145
|
-
if (initialState) Y2.applyUpdate(doc, initialState);
|
|
2146
|
-
doc.getXmlFragment("default");
|
|
2147
|
-
this.subdocs.set(id, doc);
|
|
2148
|
-
this.states.set(id, {
|
|
2149
|
-
id,
|
|
2150
|
-
doc,
|
|
2151
|
-
provider: null,
|
|
2152
|
-
active: false
|
|
2153
|
-
});
|
|
2154
|
-
this.options.onStateChange(this.getAllStates());
|
|
2155
|
-
return doc;
|
|
2156
|
-
}
|
|
2157
|
-
/** Activate a subdocument — connects it to the network for live sync. */
|
|
2158
|
-
activate(id) {
|
|
2159
|
-
const state = this.states.get(id);
|
|
2160
|
-
if (!state || state.active) return;
|
|
2161
|
-
if (this.activeQueue.length >= this.options.maxActive) {
|
|
2162
|
-
const oldest = this.activeQueue.shift();
|
|
2163
|
-
if (oldest) this.deactivate(oldest);
|
|
2164
|
-
}
|
|
2165
|
-
const doc = state.doc;
|
|
2166
|
-
const roomName = `${this.options.roomPrefix}/${id}`;
|
|
2167
|
-
const provider = new WebsocketProvider2(
|
|
2168
|
-
this.options.websocketUrl,
|
|
2169
|
-
roomName,
|
|
2170
|
-
doc
|
|
2171
|
-
);
|
|
2172
|
-
provider.awareness.setLocalStateField("user", this.options.user);
|
|
2173
|
-
state.provider = provider;
|
|
2174
|
-
state.active = true;
|
|
2175
|
-
this.activeQueue.push(id);
|
|
2176
|
-
this.options.onStateChange(this.getAllStates());
|
|
2177
|
-
}
|
|
2178
|
-
/** Deactivate a subdocument — disconnects it from the network. */
|
|
2179
|
-
deactivate(id) {
|
|
2180
|
-
const state = this.states.get(id);
|
|
2181
|
-
if (!state || !state.active) return;
|
|
2182
|
-
state.provider?.destroy();
|
|
2183
|
-
state.provider = null;
|
|
2184
|
-
state.active = false;
|
|
2185
|
-
const idx = this.activeQueue.indexOf(id);
|
|
2186
|
-
if (idx >= 0) this.activeQueue.splice(idx, 1);
|
|
2187
|
-
this.options.onStateChange(this.getAllStates());
|
|
2188
|
-
}
|
|
2189
|
-
/** Get the Y.XmlFragment for a subdocument. */
|
|
2190
|
-
getFragment(id) {
|
|
2191
|
-
const doc = this.states.get(id)?.doc ?? this.subdocs.get(id);
|
|
2192
|
-
if (!doc) return null;
|
|
2193
|
-
return doc.getXmlFragment("default");
|
|
2194
|
-
}
|
|
2195
|
-
/** Check if a subdocument is currently active (syncing). */
|
|
2196
|
-
isActive(id) {
|
|
2197
|
-
return this.states.get(id)?.active ?? false;
|
|
2198
|
-
}
|
|
2199
|
-
/** Get all subdocument states. */
|
|
2200
|
-
getAllStates() {
|
|
2201
|
-
return Array.from(this.states.values());
|
|
2202
|
-
}
|
|
2203
|
-
/** Get IDs of all active subdocuments. */
|
|
2204
|
-
getActiveIds() {
|
|
2205
|
-
return [...this.activeQueue];
|
|
2206
|
-
}
|
|
2207
|
-
/** Destroy all subdocuments and providers. */
|
|
2208
|
-
destroy() {
|
|
2209
|
-
for (const [id] of this.states) {
|
|
2210
|
-
this.deactivate(id);
|
|
2211
|
-
}
|
|
2212
|
-
this.parentProvider?.destroy();
|
|
2213
|
-
this.parentDoc.destroy();
|
|
2214
|
-
this.states.clear();
|
|
2215
|
-
this.activeQueue.length = 0;
|
|
2216
|
-
}
|
|
2217
|
-
};
|
|
2218
2024
|
export {
|
|
2219
2025
|
BlockAttributesExtension,
|
|
2220
2026
|
CONTEXT_CHAR_CAP,
|
|
@@ -2225,7 +2031,6 @@ export {
|
|
|
2225
2031
|
PaginationPlus,
|
|
2226
2032
|
PerformanceMonitor,
|
|
2227
2033
|
SearchAndReplaceExtension,
|
|
2228
|
-
SubdocumentProvider,
|
|
2229
2034
|
buildAIPrompt,
|
|
2230
2035
|
clearSearch,
|
|
2231
2036
|
collaborationExtensions,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kedataindo/docflow-core",
|
|
3
3
|
"license": "UNLICENSED",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.72",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"module": "./dist/index.js",
|
|
@@ -16,6 +16,11 @@
|
|
|
16
16
|
"types": "./dist/ai/index.d.ts",
|
|
17
17
|
"import": "./dist/ai/index.js",
|
|
18
18
|
"require": "./dist/ai/index.cjs"
|
|
19
|
+
},
|
|
20
|
+
"./collab": {
|
|
21
|
+
"types": "./dist/collab/index.d.ts",
|
|
22
|
+
"import": "./dist/collab/index.js",
|
|
23
|
+
"require": "./dist/collab/index.cjs"
|
|
19
24
|
}
|
|
20
25
|
},
|
|
21
26
|
"publishConfig": {
|