@pointyink/rogue 0.1.2 → 0.2.1
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/checkpoint.js +1 -0
- package/dist/comments.js +1 -0
- package/dist/crdt_error.js +1 -0
- package/dist/doc-bus.js +1 -0
- package/dist/doc-cache.js +1 -0
- package/dist/editor-session.js +1 -0
- package/dist/index.js +1 -1
- package/dist/oplog.js +1 -1
- package/dist/replica.js +1 -0
- package/dist/rogue.wasm.js +1 -1
- package/dist/rogue_text.js +1 -1
- package/dist/suggestions.js +1 -0
- package/dist/sync-client.js +1 -1
- package/dist/sync.js +6 -3
- package/index.d.ts +14 -0
- package/package.json +17 -5
- package/types/checkpoint.d.ts +24 -0
- package/types/comments.d.ts +157 -0
- package/types/crdt_error.d.ts +22 -0
- package/types/doc-bus.d.ts +24 -0
- package/types/doc-cache.d.ts +21 -0
- package/types/editor-session.d.ts +96 -0
- package/types/oplog.d.ts +5 -0
- package/types/replica.d.ts +41 -0
- package/types/suggestions.d.ts +83 -0
- package/types/sync-client.d.ts +13 -1
- package/types/sync.d.ts +77 -10
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {{ id: string, author_id: string, start_id: string, end_id: string,
|
|
3
|
+
* replacement: string, status: string, created_at: string, updated_at: string }} Suggestion
|
|
4
|
+
* @typedef {Suggestion & { range: import('./comments.js').DomRange | null }} ResolvedSuggestion
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Resolve a suggestion's node-id anchor to a live DOM range with fencepost
|
|
8
|
+
* semantics. Unlike comments, a suggestion brackets a *region*: if a boundary
|
|
9
|
+
* char is edited away, the range steps inward to the nearest surviving visible
|
|
10
|
+
* node (next_vis for the left edge, prev_vis for the right) rather than going
|
|
11
|
+
* stale. Null only when the region between the ids has fully collapsed.
|
|
12
|
+
*
|
|
13
|
+
* @param {import('./comments.js').CrdtSurface} crdt
|
|
14
|
+
* @param {import('./comments.js').RopeSurface} rope
|
|
15
|
+
* @param {string} startId @param {string} endId
|
|
16
|
+
* @returns {import('./comments.js').DomRange | null}
|
|
17
|
+
*/
|
|
18
|
+
export function resolveSuggestionAnchor(crdt: import("./comments.js").CrdtSurface, rope: import("./comments.js").RopeSurface, startId: string, endId: string): import("./comments.js").DomRange | null;
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {{
|
|
21
|
+
* crdt: import('./comments.js').CrdtSurface,
|
|
22
|
+
* rope: import('./comments.js').RopeSurface,
|
|
23
|
+
* baseUrl: string,
|
|
24
|
+
* fetchFn?: import('./comments.js').CommentsFetcher,
|
|
25
|
+
* rerender?: (suggestions: ResolvedSuggestion[]) => void,
|
|
26
|
+
* onError?: (error: Error) => void,
|
|
27
|
+
* markUserEdit?: () => void,
|
|
28
|
+
* getSelectionRange?: () => import('./comments.js').DomRange | null,
|
|
29
|
+
* }} SuggestionsOptions
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* @typedef {{
|
|
33
|
+
* load: () => Promise<ResolvedSuggestion[]>,
|
|
34
|
+
* suggestions: () => ResolvedSuggestion[],
|
|
35
|
+
* create: (replacement: string) => Promise<void>,
|
|
36
|
+
* accept: (suggestionId: string) => Promise<void>,
|
|
37
|
+
* reject: (suggestionId: string) => Promise<void>,
|
|
38
|
+
* handleDocumentChange: (range: { minIx: number, maxIx: number } | null) => void,
|
|
39
|
+
* handleRemoteChange: () => Promise<ResolvedSuggestion[]>,
|
|
40
|
+
* destroy: () => void,
|
|
41
|
+
* }} Suggestions
|
|
42
|
+
*/
|
|
43
|
+
/**
|
|
44
|
+
* @param {SuggestionsOptions} options
|
|
45
|
+
* @returns {Suggestions}
|
|
46
|
+
*/
|
|
47
|
+
export function createSuggestions({ crdt, rope, baseUrl, fetchFn, rerender, onError, markUserEdit, getSelectionRange }: SuggestionsOptions): Suggestions;
|
|
48
|
+
export type Suggestion = {
|
|
49
|
+
id: string;
|
|
50
|
+
author_id: string;
|
|
51
|
+
start_id: string;
|
|
52
|
+
end_id: string;
|
|
53
|
+
replacement: string;
|
|
54
|
+
status: string;
|
|
55
|
+
created_at: string;
|
|
56
|
+
updated_at: string;
|
|
57
|
+
};
|
|
58
|
+
export type ResolvedSuggestion = Suggestion & {
|
|
59
|
+
range: import("./comments.js").DomRange | null;
|
|
60
|
+
};
|
|
61
|
+
export type SuggestionsOptions = {
|
|
62
|
+
crdt: import("./comments.js").CrdtSurface;
|
|
63
|
+
rope: import("./comments.js").RopeSurface;
|
|
64
|
+
baseUrl: string;
|
|
65
|
+
fetchFn?: import("./comments.js").CommentsFetcher;
|
|
66
|
+
rerender?: (suggestions: ResolvedSuggestion[]) => void;
|
|
67
|
+
onError?: (error: Error) => void;
|
|
68
|
+
markUserEdit?: () => void;
|
|
69
|
+
getSelectionRange?: () => import("./comments.js").DomRange | null;
|
|
70
|
+
};
|
|
71
|
+
export type Suggestions = {
|
|
72
|
+
load: () => Promise<ResolvedSuggestion[]>;
|
|
73
|
+
suggestions: () => ResolvedSuggestion[];
|
|
74
|
+
create: (replacement: string) => Promise<void>;
|
|
75
|
+
accept: (suggestionId: string) => Promise<void>;
|
|
76
|
+
reject: (suggestionId: string) => Promise<void>;
|
|
77
|
+
handleDocumentChange: (range: {
|
|
78
|
+
minIx: number;
|
|
79
|
+
maxIx: number;
|
|
80
|
+
} | null) => void;
|
|
81
|
+
handleRemoteChange: () => Promise<ResolvedSuggestion[]>;
|
|
82
|
+
destroy: () => void;
|
|
83
|
+
};
|
package/types/sync-client.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @param {SyncClientOptions} options
|
|
3
3
|
* @returns {SyncClient}
|
|
4
4
|
*/
|
|
5
|
-
export function createSyncClient({ wsUrl, docId, mergeOp, getToken, onStatus, onReady }: SyncClientOptions): SyncClient;
|
|
5
|
+
export function createSyncClient({ wsUrl, docId, mergeOp, getToken, onStatus, onReady, onSyncStart, onProgress, onCommentChanged, onSuggestionChanged, onDocDeleted }: SyncClientOptions): SyncClient;
|
|
6
6
|
export type SyncStatus = "connecting" | "connected" | "disconnected";
|
|
7
7
|
export type SyncClientOptions = {
|
|
8
8
|
wsUrl: string;
|
|
@@ -11,9 +11,21 @@ export type SyncClientOptions = {
|
|
|
11
11
|
getToken: () => Promise<string>;
|
|
12
12
|
onStatus?: (status: SyncStatus) => void;
|
|
13
13
|
onReady?: () => void;
|
|
14
|
+
onSyncStart?: (bytes: number) => void;
|
|
15
|
+
onProgress?: (progress: number) => void;
|
|
16
|
+
onCommentChanged?: (info: {
|
|
17
|
+
comment_id: string;
|
|
18
|
+
op: string;
|
|
19
|
+
}) => void;
|
|
20
|
+
onSuggestionChanged?: (info: {
|
|
21
|
+
suggestion_id: string;
|
|
22
|
+
op: string;
|
|
23
|
+
}) => void;
|
|
24
|
+
onDocDeleted?: (docId: string) => void;
|
|
14
25
|
};
|
|
15
26
|
export type SyncClient = {
|
|
16
27
|
send: (payload: Uint8Array) => void;
|
|
28
|
+
sendDelete: () => void;
|
|
17
29
|
destroy: () => void;
|
|
18
30
|
isReady: () => boolean;
|
|
19
31
|
};
|
package/types/sync.d.ts
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Whether an HTML string
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* round-trip is much cheaper than rebuilding a rope. Exported for direct tests.
|
|
2
|
+
* Whether an HTML string survives a browser-parse round-trip unchanged. `context`
|
|
3
|
+
* is an element whose *tag* supplies the parse context — pass the region's parent
|
|
4
|
+
* so `<td>`/`<tr>`/`<li>` parse in their real context (a bare `<div>` would drop
|
|
5
|
+
* table internals). Omitted → a bare `<div>`. Raw innerHTML is used (not the
|
|
6
|
+
* rope+scrub serialization) because the CRDT render is already clean (scrubbed +
|
|
7
|
+
* escaped). Exported for direct tests.
|
|
9
8
|
* @param {string} html
|
|
10
|
-
* @param {
|
|
9
|
+
* @param {Element} [context]
|
|
11
10
|
* @returns {boolean}
|
|
12
11
|
*/
|
|
13
|
-
export function
|
|
12
|
+
export function validHtml(html: string, context?: Element): boolean;
|
|
14
13
|
/**
|
|
15
14
|
* The vis-index span a reference node contributes to a scoped-sync range, robust
|
|
16
15
|
* to the DOM churning mid-batch (see localRegion):
|
|
@@ -44,6 +43,29 @@ export function nodeSpan(rope: NonNullable<ReturnType<typeof buildRope>>, node:
|
|
|
44
43
|
* undo, presence, and cursor attribution key off it — or to coordinate ids
|
|
45
44
|
* server-side so concurrent replicas never collide (the u16 space is ~65k).
|
|
46
45
|
* @property {(payload: Uint8Array) => void} [onCommit]
|
|
46
|
+
* @property {number} [maxOpBytes = 8388608] Hard cap on a single committed op
|
|
47
|
+
* batch (one edit = one wire frame). An edit whose inserts exceed this is
|
|
48
|
+
* rejected — `onOpTooLarge` fires and the DOM is reverted to the CRDT — so a
|
|
49
|
+
* pathological paste (or programmatic insert) can't blow the server's read
|
|
50
|
+
* limit. The server (WS_MAX_MESSAGE_SIZE) remains the precise backstop; this
|
|
51
|
+
* guard is the friendly first line for any host, whether or not it uses the
|
|
52
|
+
* engine's own paste listener.
|
|
53
|
+
* @property {(bytes: number, limit: number) => void} [onOpTooLarge] Called when
|
|
54
|
+
* an edit is rejected for exceeding `maxOpBytes`.
|
|
55
|
+
* @property {() => void} [onDocTooLarge] Called when an edit can't be applied
|
|
56
|
+
* because the document has reached its storage capacity. The edit is reverted
|
|
57
|
+
* (the CRDT is left untouched).
|
|
58
|
+
* @property {(error: import('./crdt_error.js').CrdtError) => void} [onError]
|
|
59
|
+
* Called when an operation fails for a reason other than the known limits
|
|
60
|
+
* above — receives the structured error the WASM wrote into its output buffer
|
|
61
|
+
* (`{ type, name, desc? }`, see CrdtErrorKind), so a host can log or toast it.
|
|
62
|
+
* `out_of_memory` on the local commit path continues to route through
|
|
63
|
+
* `onDocTooLarge`.
|
|
64
|
+
* @property {(range: { minIx: number, maxIx: number } | null) => void} [onChange]
|
|
65
|
+
* Called after the document's visible text changes (local edits, remote ops,
|
|
66
|
+
* undo/redo) with the affected vis-index range, or null when it can't be
|
|
67
|
+
* localized. Internal to the rogue layer — comments.js uses it to re-resolve
|
|
68
|
+
* anchored ranges; hosts generally don't need it.
|
|
47
69
|
* @property {false | { maxBytes?: number, onRejected?: (bytes: number, limit: number) => void }} [paste]
|
|
48
70
|
* Paste handling. `false` skips the engine's own paste listener — hosts like
|
|
49
71
|
* TinyMCE have their own paste-clean pipeline, so running both would double-insert.
|
|
@@ -76,6 +98,9 @@ export function nodeSpan(rope: NonNullable<ReturnType<typeof buildRope>>, node:
|
|
|
76
98
|
* drainParked: () => void,
|
|
77
99
|
* setSyncDebug: (on: boolean) => void,
|
|
78
100
|
* markUserEdit: () => void,
|
|
101
|
+
* reserve: (nodes: number) => void,
|
|
102
|
+
* crdt: import('./comments.js').CrdtSurface,
|
|
103
|
+
* rope: import('./dom_rope.js').DomRope,
|
|
79
104
|
* destroy: () => void,
|
|
80
105
|
* }} RogueNode
|
|
81
106
|
*/
|
|
@@ -83,7 +108,7 @@ export function nodeSpan(rope: NonNullable<ReturnType<typeof buildRope>>, node:
|
|
|
83
108
|
* @param {RogueNodeOptions} options
|
|
84
109
|
* @returns {Promise<RogueNode>}
|
|
85
110
|
*/
|
|
86
|
-
export function createRogueNode({ element: editorRoot, replicaId, onCommit, paste, doc, win, serializeNode, omitNode, unwrapNode, }: RogueNodeOptions): Promise<RogueNode>;
|
|
111
|
+
export function createRogueNode({ element: editorRoot, replicaId, onCommit, maxOpBytes, onOpTooLarge, onDocTooLarge, onError, onChange, paste, doc, win, serializeNode, omitNode, unwrapNode, }: RogueNodeOptions): Promise<RogueNode>;
|
|
87
112
|
export type RogueNodeOptions = {
|
|
88
113
|
/**
|
|
89
114
|
* The container the engine renders into and
|
|
@@ -101,6 +126,45 @@ export type RogueNodeOptions = {
|
|
|
101
126
|
*/
|
|
102
127
|
replicaId?: number | undefined;
|
|
103
128
|
onCommit?: ((payload: Uint8Array) => void) | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Hard cap on a single committed op
|
|
131
|
+
* batch (one edit = one wire frame). An edit whose inserts exceed this is
|
|
132
|
+
* rejected — `onOpTooLarge` fires and the DOM is reverted to the CRDT — so a
|
|
133
|
+
* pathological paste (or programmatic insert) can't blow the server's read
|
|
134
|
+
* limit. The server (WS_MAX_MESSAGE_SIZE) remains the precise backstop; this
|
|
135
|
+
* guard is the friendly first line for any host, whether or not it uses the
|
|
136
|
+
* engine's own paste listener.
|
|
137
|
+
*/
|
|
138
|
+
maxOpBytes?: number | undefined;
|
|
139
|
+
/**
|
|
140
|
+
* Called when
|
|
141
|
+
* an edit is rejected for exceeding `maxOpBytes`.
|
|
142
|
+
*/
|
|
143
|
+
onOpTooLarge?: ((bytes: number, limit: number) => void) | undefined;
|
|
144
|
+
/**
|
|
145
|
+
* Called when an edit can't be applied
|
|
146
|
+
* because the document has reached its storage capacity. The edit is reverted
|
|
147
|
+
* (the CRDT is left untouched).
|
|
148
|
+
*/
|
|
149
|
+
onDocTooLarge?: (() => void) | undefined;
|
|
150
|
+
/**
|
|
151
|
+
* Called when an operation fails for a reason other than the known limits
|
|
152
|
+
* above — receives the structured error the WASM wrote into its output buffer
|
|
153
|
+
* (`{ type, name, desc? }`, see CrdtErrorKind), so a host can log or toast it.
|
|
154
|
+
* `out_of_memory` on the local commit path continues to route through
|
|
155
|
+
* `onDocTooLarge`.
|
|
156
|
+
*/
|
|
157
|
+
onError?: ((error: import("./crdt_error.js").CrdtError) => void) | undefined;
|
|
158
|
+
/**
|
|
159
|
+
* Called after the document's visible text changes (local edits, remote ops,
|
|
160
|
+
* undo/redo) with the affected vis-index range, or null when it can't be
|
|
161
|
+
* localized. Internal to the rogue layer — comments.js uses it to re-resolve
|
|
162
|
+
* anchored ranges; hosts generally don't need it.
|
|
163
|
+
*/
|
|
164
|
+
onChange?: ((range: {
|
|
165
|
+
minIx: number;
|
|
166
|
+
maxIx: number;
|
|
167
|
+
} | null) => void) | undefined;
|
|
104
168
|
/**
|
|
105
169
|
* Paste handling. `false` skips the engine's own paste listener — hosts like
|
|
106
170
|
* TinyMCE have their own paste-clean pipeline, so running both would double-insert.
|
|
@@ -149,6 +213,9 @@ export type RogueNode = {
|
|
|
149
213
|
drainParked: () => void;
|
|
150
214
|
setSyncDebug: (on: boolean) => void;
|
|
151
215
|
markUserEdit: () => void;
|
|
216
|
+
reserve: (nodes: number) => void;
|
|
217
|
+
crdt: import("./comments.js").CrdtSurface;
|
|
218
|
+
rope: import("./dom_rope.js").DomRope;
|
|
152
219
|
destroy: () => void;
|
|
153
220
|
};
|
|
154
221
|
import { buildRope } from "./dom_rope.js";
|