@kedataindo/docflow-core 0.0.83 → 0.0.84
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/LICENSE +201 -44
- package/README.md +39 -0
- package/dist/ai/index.d.cts +1 -1
- package/dist/ai/index.d.ts +1 -1
- package/dist/{index-BTF6gajh.d.cts → index-BsIFJXPk.d.cts} +3 -35
- package/dist/{index-BTF6gajh.d.ts → index-BsIFJXPk.d.ts} +3 -35
- package/dist/index.cjs +978 -975
- package/dist/index.d.cts +151 -99
- package/dist/index.d.ts +151 -99
- package/dist/index.js +1108 -974
- package/package.json +2 -7
- package/dist/Collaboration-CGv9OZlB.d.cts +0 -109
- package/dist/Collaboration-CGv9OZlB.d.ts +0 -109
- package/dist/chunk-XJG72F7M.js +0 -140
- package/dist/collab/index.cjs +0 -286
- package/dist/collab/index.d.cts +0 -71
- package/dist/collab/index.d.ts +0 -71
- package/dist/collab/index.js +0 -116
package/dist/index.d.cts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { AnyExtension, Editor, Extension } from '@tiptap/core';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
2
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
3
|
+
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
4
|
+
import { WebrtcProvider } from 'y-webrtc';
|
|
5
|
+
import { WebsocketProvider } from 'y-websocket';
|
|
6
|
+
import * as Y from 'yjs';
|
|
7
|
+
import { I as ImageUploadHandler, C as CitationPort, A as AIStreamFn, a as AIDraftFn } from './index-BsIFJXPk.cjs';
|
|
8
|
+
export { b as AIAction, c as AIActionRequest, d as AICompleteRequest, e as AIConfig, f as AIDraftCitation, g as AIDraftEvent, h as AIProvider, i as AIProviderFactory, j as Auth, k as CONTEXT_CHAR_CAP, l as CslDate, m as CslItemData, n as CslName, H as HttpKeyStorageUrls, o as ImageUploadResult, K as KeyStorage, L as LOCAL_STORAGE_KEY, O as OpenAICompatibleConfig, S as StreamEvent, p as buildAIPrompt, q as httpKeyStorage, r as localStorageKeyStorage, s as memoryKeyStorage, t as openaiCompatibleProvider, u as toAIStreamFn, v as trimContextAfter, w as trimContextBefore } from './index-BsIFJXPk.cjs';
|
|
9
|
+
import { PaginationPlusOptions } from 'tiptap-pagination-plus';
|
|
10
|
+
export { PAGE_SIZES, PageSize, PaginationPlus, PaginationPlusOptions } from 'tiptap-pagination-plus';
|
|
6
11
|
import { PluginKey } from '@tiptap/pm/state';
|
|
7
12
|
import { Node } from '@tiptap/pm/model';
|
|
8
|
-
import 'y-protocols/awareness';
|
|
9
|
-
import 'y-indexeddb';
|
|
10
|
-
import 'y-webrtc';
|
|
11
|
-
import 'y-websocket';
|
|
12
|
-
import 'yjs';
|
|
13
13
|
|
|
14
14
|
interface ToolbarItem {
|
|
15
15
|
id: string;
|
|
@@ -18,16 +18,6 @@ interface ToolbarItem {
|
|
|
18
18
|
label?: string;
|
|
19
19
|
action: string;
|
|
20
20
|
args?: unknown[];
|
|
21
|
-
/**
|
|
22
|
-
* Group this item into the toolbar's compact groups instead of rendering it
|
|
23
|
-
* as a flat button. Currently only `'insert'` (the "+" / Sisipkan dropdown)
|
|
24
|
-
* is supported; built-in insert actions (link, image, table, footnote, page
|
|
25
|
-
* break, …) are grouped automatically, so plugins only need this flag for
|
|
26
|
-
* their OWN actions.
|
|
27
|
-
*
|
|
28
|
-
* Defaults to `undefined` → flat toolbar button (previous behaviour).
|
|
29
|
-
*/
|
|
30
|
-
menu?: 'insert';
|
|
31
21
|
}
|
|
32
22
|
interface SlashCommand {
|
|
33
23
|
name: string;
|
|
@@ -50,67 +40,86 @@ declare function collectExtensions(plugins: DocsEditorPlugin[]): AnyExtension[];
|
|
|
50
40
|
declare function resolveAction(editor: Editor, action: string, ...args: unknown[]): boolean;
|
|
51
41
|
declare function createActionMap(editor: Editor, plugins: DocsEditorPlugin[]): Record<string, (...args: unknown[]) => boolean>;
|
|
52
42
|
|
|
53
|
-
interface
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
interface AwarenessState {
|
|
44
|
+
clientId: number;
|
|
45
|
+
user: {
|
|
46
|
+
name: string;
|
|
47
|
+
color: string;
|
|
48
|
+
};
|
|
49
|
+
cursor?: {
|
|
50
|
+
from: number;
|
|
51
|
+
to: number;
|
|
52
|
+
} | null;
|
|
53
|
+
/**
|
|
54
|
+
* Phase 9 PR2 — *present* flag. False when the local user has navigated
|
|
55
|
+
* away from the editor route (the Yjs provider is still alive but the
|
|
56
|
+
* host has gated cursor emission off, per the §6 *\"TOC sidebar orphan
|
|
57
|
+
* wiring\"* / REST-heartbeat scope notes). Peers see this instantly
|
|
58
|
+
* via the awareness `change` event — far faster than the 15s REST
|
|
59
|
+
* heartbeat fallback. Defaults to true when the user is in the editor.
|
|
60
|
+
*/
|
|
61
|
+
present: boolean;
|
|
60
62
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
pageNumber: number;
|
|
89
|
-
}) => void;
|
|
63
|
+
interface CollaborationOptions {
|
|
64
|
+
room: string;
|
|
65
|
+
provider?: 'webrtc' | 'websocket';
|
|
66
|
+
websocketUrl?: string;
|
|
67
|
+
signaling?: string[];
|
|
68
|
+
user: {
|
|
69
|
+
name: string;
|
|
70
|
+
color: string;
|
|
71
|
+
};
|
|
72
|
+
onAwarenessChange?: (states: AwarenessState[]) => void;
|
|
73
|
+
initialStorageState?: Uint8Array;
|
|
74
|
+
/**
|
|
75
|
+
* Phase 9 PR2 — when false, the local user is treated as
|
|
76
|
+
* out-of-editor: their cursor field is nulled and `present` is false.
|
|
77
|
+
* Default is true (in editor). Toggle at runtime via
|
|
78
|
+
* `setLocalCursorEnabled()` returned from `createCollaboration`.
|
|
79
|
+
*/
|
|
80
|
+
emitCursor?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Phase 9 OF1 — when true, mirror the room's Y.Doc into IndexedDB
|
|
83
|
+
* (`docflow-<room>`) via y-indexeddb so edits survive offline and reload.
|
|
84
|
+
* Reconcile-on-reconnect is plain Yjs merge — no conflict resolution
|
|
85
|
+
* needed. The IndexedDB mirror is NEVER a seed source: the server (or the
|
|
86
|
+
* legacy-JSON seed path) still owns initial state; the mirror only
|
|
87
|
+
* contributes local offline edits via the normal Yjs update exchange.
|
|
88
|
+
*/
|
|
89
|
+
offline?: boolean;
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
91
|
+
interface CollaborationSetup {
|
|
92
|
+
ydoc: Y.Doc;
|
|
93
|
+
provider: WebrtcProvider | WebsocketProvider | null;
|
|
94
|
+
awareness: Awareness;
|
|
95
|
+
/**
|
|
96
|
+
* Phase 9 OF1 — y-indexeddb persistence instance, present only when
|
|
97
|
+
* `options.offline` is true. Exposed so hosts/tests can `await
|
|
98
|
+
* persistence.whenSynced` before asserting the mirror contents. Do not
|
|
99
|
+
* use it as a seed source.
|
|
100
|
+
*/
|
|
101
|
+
persistence?: IndexeddbPersistence;
|
|
102
|
+
/**
|
|
103
|
+
* Issue #117 — resolves after BOTH the offline mirror (if `offline`) AND
|
|
104
|
+
* the provider's first sync (if `websocket`) have completed. Hosts MUST
|
|
105
|
+
* `await setup.whenReady` before binding the editor, otherwise the
|
|
106
|
+
* TipTap view can render against the IndexedDB cache before the
|
|
107
|
+
* authoritative server state arrives, briefly showing — and on a
|
|
108
|
+
* disconnected peer potentially re-broadcasting — nodes the server has
|
|
109
|
+
* since deleted. Resolves immediately when neither side applies.
|
|
110
|
+
*/
|
|
111
|
+
whenReady: Promise<void>;
|
|
112
|
+
destroy: () => void;
|
|
113
|
+
/**
|
|
114
|
+
* Phase 9 PR2 — toggle the local cursor emission + present flag.
|
|
115
|
+
* Pass `false` when the editor route unmounts, `true` when it remounts.
|
|
116
|
+
* Triggers an awareness `change` event so peers see the leave/rejoin
|
|
117
|
+
* instantly (no REST-heartbeat lag).
|
|
118
|
+
*/
|
|
119
|
+
setLocalCursorEnabled: (enabled: boolean) => void;
|
|
113
120
|
}
|
|
121
|
+
declare function createCollaboration(options: CollaborationOptions): CollaborationSetup;
|
|
122
|
+
declare function collaborationExtensions(options: CollaborationOptions | CollaborationSetup): AnyExtension[];
|
|
114
123
|
|
|
115
124
|
/**
|
|
116
125
|
* Lightweight client-side performance monitor (debug overlay).
|
|
@@ -207,31 +216,12 @@ interface EditorOptions {
|
|
|
207
216
|
plugins?: DocsEditorPlugin[];
|
|
208
217
|
editable?: boolean;
|
|
209
218
|
onUpdate?: (json: object) => void;
|
|
210
|
-
|
|
211
|
-
* Prebuilt collaboration setup from `await createCollaboration(...)`.
|
|
212
|
-
*
|
|
213
|
-
* A `CollaborationSetup` — never raw `CollaborationOptions` (issue
|
|
214
|
-
* fe-aktifai#230): building a provider is async (lazy-imports of
|
|
215
|
-
* y-webrtc/y-websocket), so `createEditor` cannot construct one itself.
|
|
216
|
-
* When set, history is disabled and the Yjs document is authoritative
|
|
217
|
-
* (local `content` is not seeded).
|
|
218
|
-
*
|
|
219
|
-
* **Ownership (host-owned):** the host that built the setup owns its
|
|
220
|
-
* lifecycle. `editor.destroy()` tears down the TipTap view only — it does
|
|
221
|
-
* **not** call `setup.destroy()`. This is deliberate: hosts routinely
|
|
222
|
-
* remount the editor against the same room (Vue `:key` bumps, tab
|
|
223
|
-
* switches, external document refreshes), and destroying the shared
|
|
224
|
-
* `Y.Doc`/provider/awareness on every remount silently kills sync and
|
|
225
|
-
* remote cursors until a full page reload. Destroy the setup yourself when
|
|
226
|
-
* the room is no longer needed (unmount, room change, `createCollaboration`
|
|
227
|
-
* resolving after disposal).
|
|
228
|
-
*/
|
|
229
|
-
collaboration?: CollaborationSetup;
|
|
219
|
+
collaboration?: CollaborationOptions | CollaborationSetup;
|
|
230
220
|
getPageMap?: () => Map<number, {
|
|
231
221
|
page: number;
|
|
232
222
|
blockIndex: number;
|
|
233
223
|
}>;
|
|
234
|
-
paginationOptions?: PaginationPlusOptions
|
|
224
|
+
paginationOptions?: Partial<PaginationPlusOptions>;
|
|
235
225
|
/** Host-injected image upload port (see docs/LIBRARY_CONTRACT.md). */
|
|
236
226
|
onImageUpload?: ImageUploadHandler;
|
|
237
227
|
/** Host-injected citation port (Phase 6 — reference library + CSL styles). */
|
|
@@ -343,4 +333,66 @@ declare function replaceCurrent(editor: Editor, replacement: string): boolean;
|
|
|
343
333
|
/** Replace every match in one transaction (applied back-to-front). */
|
|
344
334
|
declare function replaceAll(editor: Editor, replacement: string): number;
|
|
345
335
|
|
|
346
|
-
|
|
336
|
+
interface SubdocState {
|
|
337
|
+
id: string;
|
|
338
|
+
doc: Y.Doc;
|
|
339
|
+
provider: WebsocketProvider | null;
|
|
340
|
+
active: boolean;
|
|
341
|
+
}
|
|
342
|
+
interface SubdocumentProviderOptions {
|
|
343
|
+
/** WebSocket URL for the collaboration server. */
|
|
344
|
+
websocketUrl: string;
|
|
345
|
+
/** Room prefix — subdocuments use `${roomPrefix}/${id}` as room name. */
|
|
346
|
+
roomPrefix: string;
|
|
347
|
+
/** User info for awareness. */
|
|
348
|
+
user: {
|
|
349
|
+
name: string;
|
|
350
|
+
color: string;
|
|
351
|
+
};
|
|
352
|
+
/** Number of subdocuments to keep active (buffer around visible viewport). */
|
|
353
|
+
maxActive?: number;
|
|
354
|
+
/** Called when subdocument state changes (active/deactivated). */
|
|
355
|
+
onStateChange?: (states: SubdocState[]) => void;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Manages multiple Y.Doc subdocuments under a parent document.
|
|
359
|
+
*
|
|
360
|
+
* Use case: large documents (100+ pages) split into per-section subdocuments.
|
|
361
|
+
* Only active (visible) subdocuments are connected to the network via
|
|
362
|
+
* WebSocketProvider; inactive ones keep local state but stop syncing.
|
|
363
|
+
*
|
|
364
|
+
* Usage:
|
|
365
|
+
* const provider = new SubdocumentProvider({ websocketUrl, roomPrefix, user })
|
|
366
|
+
* provider.createSubdoc('section-1')
|
|
367
|
+
* provider.activate('section-1') // starts syncing
|
|
368
|
+
* provider.deactivate('section-1') // stops syncing
|
|
369
|
+
* const frag = provider.getFragment('section-1') // Y.XmlFragment for editor
|
|
370
|
+
*/
|
|
371
|
+
declare class SubdocumentProvider {
|
|
372
|
+
readonly parentDoc: Y.Doc;
|
|
373
|
+
readonly subdocs: Y.Map<Y.Doc>;
|
|
374
|
+
readonly awareness: Awareness;
|
|
375
|
+
private readonly options;
|
|
376
|
+
private readonly states;
|
|
377
|
+
private readonly activeQueue;
|
|
378
|
+
private readonly parentProvider;
|
|
379
|
+
constructor(options: SubdocumentProviderOptions);
|
|
380
|
+
/** Create a new subdocument. Does NOT activate it. */
|
|
381
|
+
createSubdoc(id: string, initialState?: Uint8Array): Y.Doc;
|
|
382
|
+
/** Activate a subdocument — connects it to the network for live sync. */
|
|
383
|
+
activate(id: string): void;
|
|
384
|
+
/** Deactivate a subdocument — disconnects it from the network. */
|
|
385
|
+
deactivate(id: string): void;
|
|
386
|
+
/** Get the Y.XmlFragment for a subdocument. */
|
|
387
|
+
getFragment(id: string): Y.XmlFragment | null;
|
|
388
|
+
/** Check if a subdocument is currently active (syncing). */
|
|
389
|
+
isActive(id: string): boolean;
|
|
390
|
+
/** Get all subdocument states. */
|
|
391
|
+
getAllStates(): SubdocState[];
|
|
392
|
+
/** Get IDs of all active subdocuments. */
|
|
393
|
+
getActiveIds(): string[];
|
|
394
|
+
/** Destroy all subdocuments and providers. */
|
|
395
|
+
destroy(): void;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export { AIDraftFn, AIStreamFn, type AwarenessState, BlockAttributesExtension, CitationPort, type ClipboardSource, type CollaborationOptions, type CollaborationSetup, type DocsEditor, type DocsEditorPlugin, EditorContextExtension, type EditorContextOptions, type EditorOptions, FontSizeExtension, ImageUploadHandler, type MonitorMetric, PerformanceMonitor, type PerformanceMonitorOptions, SearchAndReplaceExtension, type SearchMatch, type SearchState, type SlashCommand, type SubdocState, SubdocumentProvider, type SubdocumentProviderOptions, type ToolbarItem, clearSearch, collaborationExtensions, collectExtensions, createActionMap, createCollaboration, createEditor, createPerformanceMonitor, definePlugin, detectClipboardSource, findMatches, getSearchState, normalizeClipboardHTML, replaceAll, replaceCurrent, resolveAction, sanitizePastedHTML, searchAndReplaceKey, searchNext, searchPrev, setSearchQuery };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { AnyExtension, Editor, Extension } from '@tiptap/core';
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
|
|
2
|
+
import { Awareness } from 'y-protocols/awareness';
|
|
3
|
+
import { IndexeddbPersistence } from 'y-indexeddb';
|
|
4
|
+
import { WebrtcProvider } from 'y-webrtc';
|
|
5
|
+
import { WebsocketProvider } from 'y-websocket';
|
|
6
|
+
import * as Y from 'yjs';
|
|
7
|
+
import { I as ImageUploadHandler, C as CitationPort, A as AIStreamFn, a as AIDraftFn } from './index-BsIFJXPk.js';
|
|
8
|
+
export { b as AIAction, c as AIActionRequest, d as AICompleteRequest, e as AIConfig, f as AIDraftCitation, g as AIDraftEvent, h as AIProvider, i as AIProviderFactory, j as Auth, k as CONTEXT_CHAR_CAP, l as CslDate, m as CslItemData, n as CslName, H as HttpKeyStorageUrls, o as ImageUploadResult, K as KeyStorage, L as LOCAL_STORAGE_KEY, O as OpenAICompatibleConfig, S as StreamEvent, p as buildAIPrompt, q as httpKeyStorage, r as localStorageKeyStorage, s as memoryKeyStorage, t as openaiCompatibleProvider, u as toAIStreamFn, v as trimContextAfter, w as trimContextBefore } from './index-BsIFJXPk.js';
|
|
9
|
+
import { PaginationPlusOptions } from 'tiptap-pagination-plus';
|
|
10
|
+
export { PAGE_SIZES, PageSize, PaginationPlus, PaginationPlusOptions } from 'tiptap-pagination-plus';
|
|
6
11
|
import { PluginKey } from '@tiptap/pm/state';
|
|
7
12
|
import { Node } from '@tiptap/pm/model';
|
|
8
|
-
import 'y-protocols/awareness';
|
|
9
|
-
import 'y-indexeddb';
|
|
10
|
-
import 'y-webrtc';
|
|
11
|
-
import 'y-websocket';
|
|
12
|
-
import 'yjs';
|
|
13
13
|
|
|
14
14
|
interface ToolbarItem {
|
|
15
15
|
id: string;
|
|
@@ -18,16 +18,6 @@ interface ToolbarItem {
|
|
|
18
18
|
label?: string;
|
|
19
19
|
action: string;
|
|
20
20
|
args?: unknown[];
|
|
21
|
-
/**
|
|
22
|
-
* Group this item into the toolbar's compact groups instead of rendering it
|
|
23
|
-
* as a flat button. Currently only `'insert'` (the "+" / Sisipkan dropdown)
|
|
24
|
-
* is supported; built-in insert actions (link, image, table, footnote, page
|
|
25
|
-
* break, …) are grouped automatically, so plugins only need this flag for
|
|
26
|
-
* their OWN actions.
|
|
27
|
-
*
|
|
28
|
-
* Defaults to `undefined` → flat toolbar button (previous behaviour).
|
|
29
|
-
*/
|
|
30
|
-
menu?: 'insert';
|
|
31
21
|
}
|
|
32
22
|
interface SlashCommand {
|
|
33
23
|
name: string;
|
|
@@ -50,67 +40,86 @@ declare function collectExtensions(plugins: DocsEditorPlugin[]): AnyExtension[];
|
|
|
50
40
|
declare function resolveAction(editor: Editor, action: string, ...args: unknown[]): boolean;
|
|
51
41
|
declare function createActionMap(editor: Editor, plugins: DocsEditorPlugin[]): Record<string, (...args: unknown[]) => boolean>;
|
|
52
42
|
|
|
53
|
-
interface
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
43
|
+
interface AwarenessState {
|
|
44
|
+
clientId: number;
|
|
45
|
+
user: {
|
|
46
|
+
name: string;
|
|
47
|
+
color: string;
|
|
48
|
+
};
|
|
49
|
+
cursor?: {
|
|
50
|
+
from: number;
|
|
51
|
+
to: number;
|
|
52
|
+
} | null;
|
|
53
|
+
/**
|
|
54
|
+
* Phase 9 PR2 — *present* flag. False when the local user has navigated
|
|
55
|
+
* away from the editor route (the Yjs provider is still alive but the
|
|
56
|
+
* host has gated cursor emission off, per the §6 *\"TOC sidebar orphan
|
|
57
|
+
* wiring\"* / REST-heartbeat scope notes). Peers see this instantly
|
|
58
|
+
* via the awareness `change` event — far faster than the 15s REST
|
|
59
|
+
* heartbeat fallback. Defaults to true when the user is in the editor.
|
|
60
|
+
*/
|
|
61
|
+
present: boolean;
|
|
60
62
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
pageNumber: number;
|
|
89
|
-
}) => void;
|
|
63
|
+
interface CollaborationOptions {
|
|
64
|
+
room: string;
|
|
65
|
+
provider?: 'webrtc' | 'websocket';
|
|
66
|
+
websocketUrl?: string;
|
|
67
|
+
signaling?: string[];
|
|
68
|
+
user: {
|
|
69
|
+
name: string;
|
|
70
|
+
color: string;
|
|
71
|
+
};
|
|
72
|
+
onAwarenessChange?: (states: AwarenessState[]) => void;
|
|
73
|
+
initialStorageState?: Uint8Array;
|
|
74
|
+
/**
|
|
75
|
+
* Phase 9 PR2 — when false, the local user is treated as
|
|
76
|
+
* out-of-editor: their cursor field is nulled and `present` is false.
|
|
77
|
+
* Default is true (in editor). Toggle at runtime via
|
|
78
|
+
* `setLocalCursorEnabled()` returned from `createCollaboration`.
|
|
79
|
+
*/
|
|
80
|
+
emitCursor?: boolean;
|
|
81
|
+
/**
|
|
82
|
+
* Phase 9 OF1 — when true, mirror the room's Y.Doc into IndexedDB
|
|
83
|
+
* (`docflow-<room>`) via y-indexeddb so edits survive offline and reload.
|
|
84
|
+
* Reconcile-on-reconnect is plain Yjs merge — no conflict resolution
|
|
85
|
+
* needed. The IndexedDB mirror is NEVER a seed source: the server (or the
|
|
86
|
+
* legacy-JSON seed path) still owns initial state; the mirror only
|
|
87
|
+
* contributes local offline edits via the normal Yjs update exchange.
|
|
88
|
+
*/
|
|
89
|
+
offline?: boolean;
|
|
90
90
|
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
91
|
+
interface CollaborationSetup {
|
|
92
|
+
ydoc: Y.Doc;
|
|
93
|
+
provider: WebrtcProvider | WebsocketProvider | null;
|
|
94
|
+
awareness: Awareness;
|
|
95
|
+
/**
|
|
96
|
+
* Phase 9 OF1 — y-indexeddb persistence instance, present only when
|
|
97
|
+
* `options.offline` is true. Exposed so hosts/tests can `await
|
|
98
|
+
* persistence.whenSynced` before asserting the mirror contents. Do not
|
|
99
|
+
* use it as a seed source.
|
|
100
|
+
*/
|
|
101
|
+
persistence?: IndexeddbPersistence;
|
|
102
|
+
/**
|
|
103
|
+
* Issue #117 — resolves after BOTH the offline mirror (if `offline`) AND
|
|
104
|
+
* the provider's first sync (if `websocket`) have completed. Hosts MUST
|
|
105
|
+
* `await setup.whenReady` before binding the editor, otherwise the
|
|
106
|
+
* TipTap view can render against the IndexedDB cache before the
|
|
107
|
+
* authoritative server state arrives, briefly showing — and on a
|
|
108
|
+
* disconnected peer potentially re-broadcasting — nodes the server has
|
|
109
|
+
* since deleted. Resolves immediately when neither side applies.
|
|
110
|
+
*/
|
|
111
|
+
whenReady: Promise<void>;
|
|
112
|
+
destroy: () => void;
|
|
113
|
+
/**
|
|
114
|
+
* Phase 9 PR2 — toggle the local cursor emission + present flag.
|
|
115
|
+
* Pass `false` when the editor route unmounts, `true` when it remounts.
|
|
116
|
+
* Triggers an awareness `change` event so peers see the leave/rejoin
|
|
117
|
+
* instantly (no REST-heartbeat lag).
|
|
118
|
+
*/
|
|
119
|
+
setLocalCursorEnabled: (enabled: boolean) => void;
|
|
113
120
|
}
|
|
121
|
+
declare function createCollaboration(options: CollaborationOptions): CollaborationSetup;
|
|
122
|
+
declare function collaborationExtensions(options: CollaborationOptions | CollaborationSetup): AnyExtension[];
|
|
114
123
|
|
|
115
124
|
/**
|
|
116
125
|
* Lightweight client-side performance monitor (debug overlay).
|
|
@@ -207,31 +216,12 @@ interface EditorOptions {
|
|
|
207
216
|
plugins?: DocsEditorPlugin[];
|
|
208
217
|
editable?: boolean;
|
|
209
218
|
onUpdate?: (json: object) => void;
|
|
210
|
-
|
|
211
|
-
* Prebuilt collaboration setup from `await createCollaboration(...)`.
|
|
212
|
-
*
|
|
213
|
-
* A `CollaborationSetup` — never raw `CollaborationOptions` (issue
|
|
214
|
-
* fe-aktifai#230): building a provider is async (lazy-imports of
|
|
215
|
-
* y-webrtc/y-websocket), so `createEditor` cannot construct one itself.
|
|
216
|
-
* When set, history is disabled and the Yjs document is authoritative
|
|
217
|
-
* (local `content` is not seeded).
|
|
218
|
-
*
|
|
219
|
-
* **Ownership (host-owned):** the host that built the setup owns its
|
|
220
|
-
* lifecycle. `editor.destroy()` tears down the TipTap view only — it does
|
|
221
|
-
* **not** call `setup.destroy()`. This is deliberate: hosts routinely
|
|
222
|
-
* remount the editor against the same room (Vue `:key` bumps, tab
|
|
223
|
-
* switches, external document refreshes), and destroying the shared
|
|
224
|
-
* `Y.Doc`/provider/awareness on every remount silently kills sync and
|
|
225
|
-
* remote cursors until a full page reload. Destroy the setup yourself when
|
|
226
|
-
* the room is no longer needed (unmount, room change, `createCollaboration`
|
|
227
|
-
* resolving after disposal).
|
|
228
|
-
*/
|
|
229
|
-
collaboration?: CollaborationSetup;
|
|
219
|
+
collaboration?: CollaborationOptions | CollaborationSetup;
|
|
230
220
|
getPageMap?: () => Map<number, {
|
|
231
221
|
page: number;
|
|
232
222
|
blockIndex: number;
|
|
233
223
|
}>;
|
|
234
|
-
paginationOptions?: PaginationPlusOptions
|
|
224
|
+
paginationOptions?: Partial<PaginationPlusOptions>;
|
|
235
225
|
/** Host-injected image upload port (see docs/LIBRARY_CONTRACT.md). */
|
|
236
226
|
onImageUpload?: ImageUploadHandler;
|
|
237
227
|
/** Host-injected citation port (Phase 6 — reference library + CSL styles). */
|
|
@@ -343,4 +333,66 @@ declare function replaceCurrent(editor: Editor, replacement: string): boolean;
|
|
|
343
333
|
/** Replace every match in one transaction (applied back-to-front). */
|
|
344
334
|
declare function replaceAll(editor: Editor, replacement: string): number;
|
|
345
335
|
|
|
346
|
-
|
|
336
|
+
interface SubdocState {
|
|
337
|
+
id: string;
|
|
338
|
+
doc: Y.Doc;
|
|
339
|
+
provider: WebsocketProvider | null;
|
|
340
|
+
active: boolean;
|
|
341
|
+
}
|
|
342
|
+
interface SubdocumentProviderOptions {
|
|
343
|
+
/** WebSocket URL for the collaboration server. */
|
|
344
|
+
websocketUrl: string;
|
|
345
|
+
/** Room prefix — subdocuments use `${roomPrefix}/${id}` as room name. */
|
|
346
|
+
roomPrefix: string;
|
|
347
|
+
/** User info for awareness. */
|
|
348
|
+
user: {
|
|
349
|
+
name: string;
|
|
350
|
+
color: string;
|
|
351
|
+
};
|
|
352
|
+
/** Number of subdocuments to keep active (buffer around visible viewport). */
|
|
353
|
+
maxActive?: number;
|
|
354
|
+
/** Called when subdocument state changes (active/deactivated). */
|
|
355
|
+
onStateChange?: (states: SubdocState[]) => void;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Manages multiple Y.Doc subdocuments under a parent document.
|
|
359
|
+
*
|
|
360
|
+
* Use case: large documents (100+ pages) split into per-section subdocuments.
|
|
361
|
+
* Only active (visible) subdocuments are connected to the network via
|
|
362
|
+
* WebSocketProvider; inactive ones keep local state but stop syncing.
|
|
363
|
+
*
|
|
364
|
+
* Usage:
|
|
365
|
+
* const provider = new SubdocumentProvider({ websocketUrl, roomPrefix, user })
|
|
366
|
+
* provider.createSubdoc('section-1')
|
|
367
|
+
* provider.activate('section-1') // starts syncing
|
|
368
|
+
* provider.deactivate('section-1') // stops syncing
|
|
369
|
+
* const frag = provider.getFragment('section-1') // Y.XmlFragment for editor
|
|
370
|
+
*/
|
|
371
|
+
declare class SubdocumentProvider {
|
|
372
|
+
readonly parentDoc: Y.Doc;
|
|
373
|
+
readonly subdocs: Y.Map<Y.Doc>;
|
|
374
|
+
readonly awareness: Awareness;
|
|
375
|
+
private readonly options;
|
|
376
|
+
private readonly states;
|
|
377
|
+
private readonly activeQueue;
|
|
378
|
+
private readonly parentProvider;
|
|
379
|
+
constructor(options: SubdocumentProviderOptions);
|
|
380
|
+
/** Create a new subdocument. Does NOT activate it. */
|
|
381
|
+
createSubdoc(id: string, initialState?: Uint8Array): Y.Doc;
|
|
382
|
+
/** Activate a subdocument — connects it to the network for live sync. */
|
|
383
|
+
activate(id: string): void;
|
|
384
|
+
/** Deactivate a subdocument — disconnects it from the network. */
|
|
385
|
+
deactivate(id: string): void;
|
|
386
|
+
/** Get the Y.XmlFragment for a subdocument. */
|
|
387
|
+
getFragment(id: string): Y.XmlFragment | null;
|
|
388
|
+
/** Check if a subdocument is currently active (syncing). */
|
|
389
|
+
isActive(id: string): boolean;
|
|
390
|
+
/** Get all subdocument states. */
|
|
391
|
+
getAllStates(): SubdocState[];
|
|
392
|
+
/** Get IDs of all active subdocuments. */
|
|
393
|
+
getActiveIds(): string[];
|
|
394
|
+
/** Destroy all subdocuments and providers. */
|
|
395
|
+
destroy(): void;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
export { AIDraftFn, AIStreamFn, type AwarenessState, BlockAttributesExtension, CitationPort, type ClipboardSource, type CollaborationOptions, type CollaborationSetup, type DocsEditor, type DocsEditorPlugin, EditorContextExtension, type EditorContextOptions, type EditorOptions, FontSizeExtension, ImageUploadHandler, type MonitorMetric, PerformanceMonitor, type PerformanceMonitorOptions, SearchAndReplaceExtension, type SearchMatch, type SearchState, type SlashCommand, type SubdocState, SubdocumentProvider, type SubdocumentProviderOptions, type ToolbarItem, clearSearch, collaborationExtensions, collectExtensions, createActionMap, createCollaboration, createEditor, createPerformanceMonitor, definePlugin, detectClipboardSource, findMatches, getSearchState, normalizeClipboardHTML, replaceAll, replaceCurrent, resolveAction, sanitizePastedHTML, searchAndReplaceKey, searchNext, searchPrev, setSearchQuery };
|