@kerebron/extension-yjs 0.6.7 → 0.7.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/esm/ExtensionYjs.d.ts +3 -11
- package/esm/ExtensionYjs.d.ts.map +1 -1
- package/esm/ExtensionYjs.js +71 -45
- package/esm/ExtensionYjs.js.map +1 -1
- package/esm/WebsocketProvider.d.ts +70 -0
- package/esm/WebsocketProvider.d.ts.map +1 -0
- package/esm/WebsocketProvider.js +377 -0
- package/esm/WebsocketProvider.js.map +1 -0
- package/esm/YjsProvider.d.ts +48 -0
- package/esm/YjsProvider.d.ts.map +1 -0
- package/esm/YjsProvider.js +12 -0
- package/esm/YjsProvider.js.map +1 -0
- package/esm/_dnt.shims.d.ts +2 -0
- package/esm/_dnt.shims.d.ts.map +1 -0
- package/esm/_dnt.shims.js +58 -0
- package/esm/_dnt.shims.js.map +1 -0
- package/esm/binding/BindingMetadata.d.ts +6 -0
- package/esm/binding/BindingMetadata.d.ts.map +1 -0
- package/esm/binding/BindingMetadata.js +2 -0
- package/esm/binding/BindingMetadata.js.map +1 -0
- package/esm/binding/DiffViewer.d.ts +17 -0
- package/esm/binding/DiffViewer.d.ts.map +1 -0
- package/esm/binding/DiffViewer.js +96 -0
- package/esm/binding/DiffViewer.js.map +1 -0
- package/esm/binding/PmYjsBinding.d.ts +45 -0
- package/esm/binding/PmYjsBinding.d.ts.map +1 -0
- package/esm/binding/PmYjsBinding.js +230 -0
- package/esm/binding/PmYjsBinding.js.map +1 -0
- package/esm/binding/convertUtils.d.ts +48 -0
- package/esm/binding/convertUtils.d.ts.map +1 -0
- package/esm/binding/convertUtils.js +80 -0
- package/esm/binding/convertUtils.js.map +1 -0
- package/esm/{createNodeFromYElement.d.ts → binding/createNodeFromYElement.d.ts} +2 -2
- package/esm/binding/createNodeFromYElement.d.ts.map +1 -0
- package/esm/{createNodeFromYElement.js → binding/createNodeFromYElement.js} +2 -2
- package/esm/binding/createNodeFromYElement.js.map +1 -0
- package/esm/{updateYFragment.d.ts → binding/updateYFragment.d.ts} +3 -3
- package/esm/binding/updateYFragment.d.ts.map +1 -0
- package/esm/{updateYFragment.js → binding/updateYFragment.js} +10 -7
- package/esm/binding/updateYFragment.js.map +1 -0
- package/esm/debug.d.ts.map +1 -1
- package/esm/debug.js +11 -0
- package/esm/debug.js.map +1 -1
- package/esm/lib.d.ts +1 -7
- package/esm/lib.d.ts.map +1 -1
- package/esm/lib.js +1 -200
- package/esm/lib.js.map +1 -1
- package/esm/position.d.ts +8 -0
- package/esm/position.d.ts.map +1 -0
- package/esm/position.js +165 -0
- package/esm/position.js.map +1 -0
- package/esm/ui/selection.d.ts +29 -0
- package/esm/ui/selection.d.ts.map +1 -0
- package/esm/ui/selection.js +129 -0
- package/esm/ui/selection.js.map +1 -0
- package/esm/utils.d.ts +1 -1
- package/esm/utils.d.ts.map +1 -1
- package/esm/utils.js.map +1 -1
- package/esm/yPositionPlugin.d.ts +6 -1
- package/esm/yPositionPlugin.d.ts.map +1 -1
- package/esm/yPositionPlugin.js +91 -50
- package/esm/yPositionPlugin.js.map +1 -1
- package/esm/ySyncPlugin.d.ts +5 -22
- package/esm/ySyncPlugin.d.ts.map +1 -1
- package/esm/ySyncPlugin.js +70 -101
- package/esm/ySyncPlugin.js.map +1 -1
- package/esm/yUndoPlugin.d.ts +11 -10
- package/esm/yUndoPlugin.d.ts.map +1 -1
- package/esm/yUndoPlugin.js +90 -52
- package/esm/yUndoPlugin.js.map +1 -1
- package/package.json +9 -6
- package/src/ExtensionYjs.ts +98 -67
- package/src/WebsocketProvider.ts +528 -0
- package/src/YjsProvider.ts +75 -0
- package/src/_dnt.shims.ts +60 -0
- package/src/binding/BindingMetadata.ts +6 -0
- package/src/binding/DiffViewer.ts +138 -0
- package/src/binding/PmYjsBinding.ts +360 -0
- package/src/binding/convertUtils.ts +124 -0
- package/src/{createNodeFromYElement.ts → binding/createNodeFromYElement.ts} +4 -4
- package/src/{updateYFragment.ts → binding/updateYFragment.ts} +15 -8
- package/src/debug.ts +21 -0
- package/src/lib.ts +4 -230
- package/src/position.ts +191 -0
- package/src/ui/selection.ts +218 -0
- package/src/utils.ts +1 -1
- package/src/yPositionPlugin.ts +122 -74
- package/src/ySyncPlugin.ts +111 -155
- package/src/yUndoPlugin.ts +113 -62
- package/esm/ProsemirrorBinding.d.ts +0 -60
- package/esm/ProsemirrorBinding.d.ts.map +0 -1
- package/esm/ProsemirrorBinding.js +0 -405
- package/esm/ProsemirrorBinding.js.map +0 -1
- package/esm/createNodeFromYElement.d.ts.map +0 -1
- package/esm/createNodeFromYElement.js.map +0 -1
- package/esm/updateYFragment.d.ts.map +0 -1
- package/esm/updateYFragment.js.map +0 -1
- package/esm/userColors.d.ts +0 -5
- package/esm/userColors.d.ts.map +0 -1
- package/esm/userColors.js +0 -11
- package/esm/userColors.js.map +0 -1
- package/src/ProsemirrorBinding.ts +0 -607
- package/src/userColors.ts +0 -10
package/esm/ExtensionYjs.d.ts
CHANGED
|
@@ -1,16 +1,9 @@
|
|
|
1
|
-
import type { Schema } from 'prosemirror-model';
|
|
2
1
|
import type { Plugin } from 'prosemirror-state';
|
|
3
|
-
import
|
|
4
|
-
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
5
|
-
import { Converter, CoreEditor, Extension } from '@kerebron/editor';
|
|
2
|
+
import { Extension } from '@kerebron/editor';
|
|
6
3
|
import type { CommandFactories, CommandShortcuts } from '@kerebron/editor/commands';
|
|
7
|
-
|
|
8
|
-
on(eventName: string, callback: (event: any) => void): void;
|
|
9
|
-
awareness: awarenessProtocol.Awareness;
|
|
10
|
-
}
|
|
11
|
-
export type CreateWsProvider = (roomId: string) => [YjsProvider, Y.Doc];
|
|
4
|
+
import type { CreateYjsProvider } from './YjsProvider.js';
|
|
12
5
|
export interface YjsConfig {
|
|
13
|
-
|
|
6
|
+
createYjsProvider: CreateYjsProvider;
|
|
14
7
|
}
|
|
15
8
|
export declare class ExtensionYjs extends Extension {
|
|
16
9
|
config: YjsConfig;
|
|
@@ -20,7 +13,6 @@ export declare class ExtensionYjs extends Extension {
|
|
|
20
13
|
getCommandFactories(): Partial<CommandFactories>;
|
|
21
14
|
getKeyboardShortcuts(): Partial<CommandShortcuts>;
|
|
22
15
|
constructor(config: YjsConfig);
|
|
23
|
-
getConverters(editor: CoreEditor, schema: Schema): Record<string, Converter>;
|
|
24
16
|
getProseMirrorPlugins(): Plugin[];
|
|
25
17
|
}
|
|
26
18
|
//# sourceMappingURL=ExtensionYjs.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExtensionYjs.d.ts","sourceRoot":"","sources":["../src/ExtensionYjs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ExtensionYjs.d.ts","sourceRoot":"","sources":["../src/ExtensionYjs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAe,MAAM,EAAe,MAAM,mBAAmB,CAAC;AAI1E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,KAAK,EACV,gBAAgB,EAEhB,gBAAgB,EACjB,MAAM,2BAA2B,CAAC;AAOnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,WAAW,SAAS;IACxB,iBAAiB,EAAE,iBAAiB,CAAC;CACtC;AAED,qBAAa,YAAa,SAAQ,SAAS;IA4Gb,MAAM,EAAE,SAAS;IA3G7C,IAAI,SAAS;IAEJ,SAAS,WAAe;IACjC,QAAQ,WAAwB;IAEvB,mBAAmB,IAAI,OAAO,CAAC,gBAAgB,CAAC;IA+FhD,oBAAoB,IAAI,OAAO,CAAC,gBAAgB,CAAC;gBAO9B,MAAM,EAAE,SAAS;IAIpC,qBAAqB,IAAI,MAAM,EAAE;CAO3C"}
|
package/esm/ExtensionYjs.js
CHANGED
|
@@ -1,26 +1,83 @@
|
|
|
1
1
|
import { Extension } from '@kerebron/editor';
|
|
2
|
-
import { ySyncPluginKey } from './keys.js';
|
|
3
2
|
import { ySyncPlugin } from './ySyncPlugin.js';
|
|
4
3
|
import { yPositionPlugin } from './yPositionPlugin.js';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
let hash = 0;
|
|
8
|
-
for (let i = 0; i < str.length; i++) {
|
|
9
|
-
hash = (hash << 5) - hash + str.charCodeAt(i);
|
|
10
|
-
hash |= 0; // force 32-bit integer
|
|
11
|
-
}
|
|
12
|
-
return Math.abs(hash) % arrayLength;
|
|
13
|
-
}
|
|
4
|
+
import { redoCommand, undoCommand, yUndoPlugin } from './yUndoPlugin.js';
|
|
5
|
+
import { ySyncPluginKey } from './keys.js';
|
|
14
6
|
export class ExtensionYjs extends Extension {
|
|
15
7
|
config;
|
|
16
8
|
name = 'yjs';
|
|
17
9
|
conflicts = ['history'];
|
|
18
10
|
requires = ['remote-selection'];
|
|
19
|
-
// declare type Command = (state: EditorState, dispatch?: (tr: Transaction) => void, view?: EditorView) => boolean;
|
|
20
11
|
getCommandFactories() {
|
|
12
|
+
const changeRoom = (roomId) => {
|
|
13
|
+
return (state, dispatch) => {
|
|
14
|
+
const tr = state.tr;
|
|
15
|
+
tr.setMeta(ySyncPluginKey, { changeRoom: { roomId } });
|
|
16
|
+
if (dispatch) {
|
|
17
|
+
dispatch(tr);
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const leaveRoom = () => {
|
|
23
|
+
return (state, dispatch) => {
|
|
24
|
+
const tr = state.tr;
|
|
25
|
+
tr.setMeta(ySyncPluginKey, { leaveRoom: true });
|
|
26
|
+
if (dispatch) {
|
|
27
|
+
dispatch(tr);
|
|
28
|
+
}
|
|
29
|
+
return true;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const getYDoc = ({ resolve, reject }) => {
|
|
33
|
+
return (state, dispatch) => {
|
|
34
|
+
const tr = state.tr;
|
|
35
|
+
tr.setMeta(ySyncPluginKey, { getYDoc: { resolve, reject } });
|
|
36
|
+
if (dispatch) {
|
|
37
|
+
dispatch(tr);
|
|
38
|
+
}
|
|
39
|
+
return true;
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const getYSnapshot = ({ resolve, reject }) => {
|
|
43
|
+
return (state, dispatch) => {
|
|
44
|
+
const tr = state.tr;
|
|
45
|
+
tr.setMeta(ySyncPluginKey, { getYSnapshot: { resolve, reject } });
|
|
46
|
+
if (dispatch) {
|
|
47
|
+
dispatch(tr);
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
50
|
+
};
|
|
51
|
+
};
|
|
52
|
+
const setYSnapshot = (opts) => {
|
|
53
|
+
return (state, dispatch) => {
|
|
54
|
+
const tr = state.tr;
|
|
55
|
+
tr.setMeta(ySyncPluginKey, { setYSnapshot: opts });
|
|
56
|
+
if (dispatch) {
|
|
57
|
+
dispatch(tr);
|
|
58
|
+
}
|
|
59
|
+
return true;
|
|
60
|
+
};
|
|
61
|
+
};
|
|
62
|
+
const resetYSnapshot = () => {
|
|
63
|
+
return (state, dispatch) => {
|
|
64
|
+
const tr = state.tr;
|
|
65
|
+
tr.setMeta(ySyncPluginKey, { resetYSnapshot: true });
|
|
66
|
+
if (dispatch) {
|
|
67
|
+
dispatch(tr);
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
21
72
|
return {
|
|
22
|
-
|
|
23
|
-
|
|
73
|
+
getYDoc,
|
|
74
|
+
changeRoom,
|
|
75
|
+
leaveRoom,
|
|
76
|
+
'undo': () => undoCommand,
|
|
77
|
+
'redo': () => redoCommand,
|
|
78
|
+
getYSnapshot,
|
|
79
|
+
setYSnapshot,
|
|
80
|
+
resetYSnapshot,
|
|
24
81
|
};
|
|
25
82
|
}
|
|
26
83
|
getKeyboardShortcuts() {
|
|
@@ -33,40 +90,9 @@ export class ExtensionYjs extends Extension {
|
|
|
33
90
|
super();
|
|
34
91
|
this.config = config;
|
|
35
92
|
}
|
|
36
|
-
// changeUser(userName: string) {
|
|
37
|
-
// const idx = stringToIndex(userName, userColors.length);
|
|
38
|
-
// const userColor = userColors[idx];
|
|
39
|
-
// this.wsProvider.awareness.setLocalStateField('user', {
|
|
40
|
-
// name: userName,
|
|
41
|
-
// color: userColor.color,
|
|
42
|
-
// colorLight: userColor.light,
|
|
43
|
-
// });
|
|
44
|
-
// }
|
|
45
|
-
// //
|
|
46
|
-
getConverters(editor, schema) {
|
|
47
|
-
return {
|
|
48
|
-
'yjs': {
|
|
49
|
-
fromDoc: async (document) => {
|
|
50
|
-
throw new Error('Not implemented');
|
|
51
|
-
},
|
|
52
|
-
toDoc: async (buffer) => {
|
|
53
|
-
const roomId = new TextDecoder().decode(buffer);
|
|
54
|
-
const tr = editor.state.tr.setMeta(ySyncPluginKey, {
|
|
55
|
-
roomId: '',
|
|
56
|
-
});
|
|
57
|
-
editor.view.dispatch(tr);
|
|
58
|
-
setTimeout(() => {
|
|
59
|
-
const tr = editor.state.tr.setMeta(ySyncPluginKey, { roomId });
|
|
60
|
-
editor.view.dispatch(tr);
|
|
61
|
-
}, 100);
|
|
62
|
-
return schema.topNodeType.createAndFill();
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
};
|
|
66
|
-
}
|
|
67
93
|
getProseMirrorPlugins() {
|
|
68
94
|
return [
|
|
69
|
-
ySyncPlugin(this.editor
|
|
95
|
+
ySyncPlugin(this.editor, this.config.createYjsProvider),
|
|
70
96
|
yPositionPlugin(this.editor),
|
|
71
97
|
yUndoPlugin(),
|
|
72
98
|
];
|
package/esm/ExtensionYjs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExtensionYjs.js","sourceRoot":"","sources":["../src/ExtensionYjs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ExtensionYjs.js","sourceRoot":"","sources":["../src/ExtensionYjs.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import * as Y from 'yjs';
|
|
2
|
+
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
3
|
+
import { MessageHandler, YjsProvider } from './YjsProvider.js';
|
|
4
|
+
interface WebsocketProviderOpts {
|
|
5
|
+
connect: boolean;
|
|
6
|
+
awareness: awarenessProtocol.Awareness;
|
|
7
|
+
params: Record<string, string>;
|
|
8
|
+
protocols: Array<string>;
|
|
9
|
+
WebSocketPolyfill: typeof WebSocket;
|
|
10
|
+
resyncInterval: number;
|
|
11
|
+
maxBackoffTime: number;
|
|
12
|
+
disableBc: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.
|
|
16
|
+
* The document name is attached to the provided url. I.e. the following example
|
|
17
|
+
* creates a websocket connection to http://localhost:1234/my-document-name
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* import * as Y from 'yjs'
|
|
21
|
+
* import { WebsocketProvider } from '@kerebron/extension-yjs/WebsocketProvider'
|
|
22
|
+
* const doc = new Y.Doc()
|
|
23
|
+
* const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)
|
|
24
|
+
*/
|
|
25
|
+
export declare class WebsocketProvider extends EventTarget implements YjsProvider {
|
|
26
|
+
roomname: string;
|
|
27
|
+
doc: Y.Doc;
|
|
28
|
+
_synced: boolean;
|
|
29
|
+
shouldConnect: boolean;
|
|
30
|
+
ws: WebSocket | undefined;
|
|
31
|
+
_resyncInterval: number;
|
|
32
|
+
serverUrl: string;
|
|
33
|
+
bcChannel: string;
|
|
34
|
+
maxBackoffTime: number;
|
|
35
|
+
/**
|
|
36
|
+
* The specified url parameters. This can be safely updated. The changed parameters will be used
|
|
37
|
+
* when a new connection is established.
|
|
38
|
+
*/
|
|
39
|
+
params: Record<string, string>;
|
|
40
|
+
protocols: string[];
|
|
41
|
+
_WS: typeof WebSocket;
|
|
42
|
+
awareness: awarenessProtocol.Awareness;
|
|
43
|
+
destroyed: boolean;
|
|
44
|
+
wsconnected: boolean;
|
|
45
|
+
wsconnecting: boolean;
|
|
46
|
+
bcconnected: boolean;
|
|
47
|
+
disableBc: boolean;
|
|
48
|
+
wsUnsuccessfulReconnects: number;
|
|
49
|
+
messageHandlers: MessageHandler<WebsocketProvider>[];
|
|
50
|
+
wsLastMessageReceived: number;
|
|
51
|
+
readonly bc: BroadcastChannel;
|
|
52
|
+
private _bcSubscriber;
|
|
53
|
+
private _updateHandler;
|
|
54
|
+
private _awarenessUpdateHandler;
|
|
55
|
+
private _exitHandler;
|
|
56
|
+
private _checkInterval;
|
|
57
|
+
setupWSTimeout: number | undefined;
|
|
58
|
+
constructor(serverUrl: string, roomname: string, doc: Y.Doc, opts?: WebsocketProviderOpts);
|
|
59
|
+
get url(): string;
|
|
60
|
+
get synced(): boolean;
|
|
61
|
+
set synced(state: boolean);
|
|
62
|
+
destroy(): void;
|
|
63
|
+
connectBc(): void;
|
|
64
|
+
disconnectBc(): void;
|
|
65
|
+
disconnect(): void;
|
|
66
|
+
connect(): void;
|
|
67
|
+
private setupMessageHandlers;
|
|
68
|
+
}
|
|
69
|
+
export {};
|
|
70
|
+
//# sourceMappingURL=WebsocketProvider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebsocketProvider.d.ts","sourceRoot":"","sources":["../src/WebsocketProvider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AAMzB,OAAO,KAAK,iBAAiB,MAAM,uBAAuB,CAAC;AAI3D,OAAO,EAGL,cAAc,EAId,WAAW,EACZ,MAAM,kBAAkB,CAAC;AAoJ1B,UAAU,qBAAqB;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,SAAS,EAAE,iBAAiB,CAAC,SAAS,CAAC;IACvC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;IACzB,iBAAiB,EAAE,OAAO,SAAS,CAAC;IACpC,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED;;;;;;;;;;GAUG;AACH,qBAAa,iBAAkB,SAAQ,WAAY,YAAW,WAAW;IACvE,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,CAAC,CAAC,GAAG,CAAC;IAEX,OAAO,UAAS;IAChB,aAAa,EAAE,OAAO,CAAC;IACvB,EAAE,EAAE,SAAS,GAAG,SAAS,CAAC;IAC1B,eAAe,SAAK;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,GAAG,EAAE,OAAO,SAAS,CAAC;IACtB,SAAS,EAAE,iBAAiB,CAAC,SAAS,CAAC;IACvC,SAAS,UAAS;IAClB,WAAW,UAAS;IACpB,YAAY,UAAS;IACrB,WAAW,UAAS;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,wBAAwB,EAAE,MAAM,CAAC;IACjC,eAAe,EAAE,cAAc,CAAC,iBAAiB,CAAC,EAAE,CAAC;IACrD,qBAAqB,EAAE,MAAM,CAAC;IAC9B,SAAgB,EAAE,EAAE,gBAAgB,CAAC;IACrC,OAAO,CAAC,aAAa,CAAuC;IAC5D,OAAO,CAAC,cAAc,CAAqC;IAC3D,OAAO,CAAC,uBAAuB,CAGrB;IACV,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,cAAc,CAAS;IAC/B,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;gBAGjC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,CAAC,CAAC,GAAG,EACV,IAAI,GAAE,qBASL;IAoGH,IAAI,GAAG,WAIN;IAED,IAAI,MAAM,IAAI,OAAO,CAEpB;IAED,IAAI,MAAM,CAAC,KAAK,EAAE,OAAO,EAMxB;IAED,OAAO;IAmBP,SAAS;IAyCT,YAAY;IAuBZ,UAAU;IAQV,OAAO;IAQP,OAAO,CAAC,oBAAoB;CAuE7B"}
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import * as time from 'lib0/time';
|
|
2
|
+
import * as encoding from 'lib0/encoding';
|
|
3
|
+
import * as decoding from 'lib0/decoding';
|
|
4
|
+
import * as syncProtocol from 'y-protocols/sync';
|
|
5
|
+
import * as authProtocol from 'y-protocols/auth';
|
|
6
|
+
import * as awarenessProtocol from 'y-protocols/awareness';
|
|
7
|
+
import * as math from 'lib0/math';
|
|
8
|
+
import * as url from 'lib0/url';
|
|
9
|
+
import { messageAuth, messageAwareness, messageQueryAwareness, messageSync, } from './YjsProvider.js';
|
|
10
|
+
// @todo - this should depend on awareness.outdatedTime
|
|
11
|
+
const messageReconnectTimeout = 30000;
|
|
12
|
+
const permissionDeniedHandler = (provider, reason) => console.warn(`Permission denied to access ${provider.url}.\n${reason}`);
|
|
13
|
+
const readMessage = (provider, buf, emitSynced) => {
|
|
14
|
+
const decoder = decoding.createDecoder(buf);
|
|
15
|
+
const encoder = encoding.createEncoder();
|
|
16
|
+
const messageType = decoding.readVarUint(decoder);
|
|
17
|
+
const messageHandler = provider.messageHandlers[messageType];
|
|
18
|
+
if (messageHandler) {
|
|
19
|
+
messageHandler(encoder, decoder, provider, emitSynced, messageType);
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
console.error('Unable to compute message');
|
|
23
|
+
}
|
|
24
|
+
return encoder;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Outsource this function so that a new websocket connection is created immediately.
|
|
28
|
+
* I suspect that the `ws.onclose` event is not always fired if there are network issues.
|
|
29
|
+
*/
|
|
30
|
+
const closeWebsocketConnection = (provider, ws, event) => {
|
|
31
|
+
if (ws === provider.ws) {
|
|
32
|
+
provider.dispatchEvent(new CustomEvent('connection-close', { detail: { event, provider } }));
|
|
33
|
+
provider.ws = undefined;
|
|
34
|
+
ws.close();
|
|
35
|
+
provider.wsconnecting = false;
|
|
36
|
+
if (provider.wsconnected) {
|
|
37
|
+
provider.wsconnected = false;
|
|
38
|
+
provider.synced = false;
|
|
39
|
+
// update awareness (all users except local left)
|
|
40
|
+
awarenessProtocol.removeAwarenessStates(provider.awareness, Array.from(provider.awareness.getStates().keys()).filter((client) => client !== provider.doc.clientID), provider);
|
|
41
|
+
provider.dispatchEvent(new CustomEvent('status', { detail: { status: 'disconnected' } }));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
provider.wsUnsuccessfulReconnects++;
|
|
45
|
+
}
|
|
46
|
+
// Start with no reconnect timeout and increase timeout by
|
|
47
|
+
// using exponential backoff starting with 100ms
|
|
48
|
+
if (!provider.destroyed) {
|
|
49
|
+
provider.setupWSTimeout = setTimeout(setupWS, math.min(math.pow(2, provider.wsUnsuccessfulReconnects) * 100, provider.maxBackoffTime), provider);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const setupWS = (provider) => {
|
|
54
|
+
provider.setupWSTimeout = undefined;
|
|
55
|
+
if (provider.shouldConnect && !provider.ws) {
|
|
56
|
+
const websocket = new provider._WS(provider.url, provider.protocols);
|
|
57
|
+
websocket.binaryType = 'arraybuffer';
|
|
58
|
+
provider.ws = websocket;
|
|
59
|
+
provider.wsconnecting = true;
|
|
60
|
+
provider.wsconnected = false;
|
|
61
|
+
provider.synced = false;
|
|
62
|
+
websocket.onmessage = (event) => {
|
|
63
|
+
provider.wsLastMessageReceived = time.getUnixTime();
|
|
64
|
+
const encoder = readMessage(provider, new Uint8Array(event.data), true);
|
|
65
|
+
if (encoding.length(encoder) > 1) {
|
|
66
|
+
websocket.send(encoding.toUint8Array(encoder));
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
websocket.onerror = (event) => {
|
|
70
|
+
provider.dispatchEvent(new CustomEvent('connection-error', { detail: { event, provider } }));
|
|
71
|
+
};
|
|
72
|
+
websocket.onclose = (event) => {
|
|
73
|
+
try {
|
|
74
|
+
closeWebsocketConnection(provider, websocket, event);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
console.error(err);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
websocket.onopen = () => {
|
|
81
|
+
provider.wsLastMessageReceived = time.getUnixTime();
|
|
82
|
+
provider.wsconnecting = false;
|
|
83
|
+
provider.wsconnected = true;
|
|
84
|
+
provider.wsUnsuccessfulReconnects = 0;
|
|
85
|
+
provider.dispatchEvent(new CustomEvent('status', { detail: { status: 'connected' } }));
|
|
86
|
+
// always send sync step 1 when connected
|
|
87
|
+
const encoder = encoding.createEncoder();
|
|
88
|
+
encoding.writeVarUint(encoder, messageSync);
|
|
89
|
+
syncProtocol.writeSyncStep1(encoder, provider.doc);
|
|
90
|
+
websocket.send(encoding.toUint8Array(encoder));
|
|
91
|
+
// broadcast local awareness state
|
|
92
|
+
if (provider.awareness.getLocalState() !== null) {
|
|
93
|
+
const encoderAwarenessState = encoding.createEncoder();
|
|
94
|
+
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
95
|
+
encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(provider.awareness, [
|
|
96
|
+
provider.doc.clientID,
|
|
97
|
+
]));
|
|
98
|
+
websocket.send(encoding.toUint8Array(encoderAwarenessState));
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
provider.dispatchEvent(new CustomEvent('status', { detail: { status: 'connecting' } }));
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
const broadcastMessage = (provider, buf) => {
|
|
105
|
+
const ws = provider.ws;
|
|
106
|
+
if (provider.wsconnected && ws && ws.readyState === ws.OPEN) {
|
|
107
|
+
ws.send(buf);
|
|
108
|
+
}
|
|
109
|
+
if (provider.bcconnected) {
|
|
110
|
+
try {
|
|
111
|
+
provider.bc.postMessage(buf);
|
|
112
|
+
}
|
|
113
|
+
catch (err) {
|
|
114
|
+
console.trace(err);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
/**
|
|
119
|
+
* Websocket Provider for Yjs. Creates a websocket connection to sync the shared document.
|
|
120
|
+
* The document name is attached to the provided url. I.e. the following example
|
|
121
|
+
* creates a websocket connection to http://localhost:1234/my-document-name
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* import * as Y from 'yjs'
|
|
125
|
+
* import { WebsocketProvider } from '@kerebron/extension-yjs/WebsocketProvider'
|
|
126
|
+
* const doc = new Y.Doc()
|
|
127
|
+
* const provider = new WebsocketProvider('http://localhost:1234', 'my-document-name', doc)
|
|
128
|
+
*/
|
|
129
|
+
export class WebsocketProvider extends EventTarget {
|
|
130
|
+
roomname;
|
|
131
|
+
doc;
|
|
132
|
+
_synced = false;
|
|
133
|
+
shouldConnect;
|
|
134
|
+
ws;
|
|
135
|
+
_resyncInterval = 0;
|
|
136
|
+
serverUrl;
|
|
137
|
+
bcChannel;
|
|
138
|
+
maxBackoffTime;
|
|
139
|
+
/**
|
|
140
|
+
* The specified url parameters. This can be safely updated. The changed parameters will be used
|
|
141
|
+
* when a new connection is established.
|
|
142
|
+
*/
|
|
143
|
+
params;
|
|
144
|
+
protocols;
|
|
145
|
+
_WS;
|
|
146
|
+
awareness;
|
|
147
|
+
destroyed = false;
|
|
148
|
+
wsconnected = false;
|
|
149
|
+
wsconnecting = false;
|
|
150
|
+
bcconnected = false;
|
|
151
|
+
disableBc;
|
|
152
|
+
wsUnsuccessfulReconnects;
|
|
153
|
+
messageHandlers;
|
|
154
|
+
wsLastMessageReceived;
|
|
155
|
+
bc;
|
|
156
|
+
_bcSubscriber;
|
|
157
|
+
_updateHandler;
|
|
158
|
+
_awarenessUpdateHandler;
|
|
159
|
+
_exitHandler;
|
|
160
|
+
_checkInterval;
|
|
161
|
+
setupWSTimeout;
|
|
162
|
+
constructor(serverUrl, roomname, doc, opts = {
|
|
163
|
+
connect: true,
|
|
164
|
+
awareness: new awarenessProtocol.Awareness(doc),
|
|
165
|
+
params: {},
|
|
166
|
+
protocols: [],
|
|
167
|
+
WebSocketPolyfill: WebSocket,
|
|
168
|
+
resyncInterval: -1,
|
|
169
|
+
maxBackoffTime: 2500,
|
|
170
|
+
disableBc: false,
|
|
171
|
+
}) {
|
|
172
|
+
super();
|
|
173
|
+
// ensure that serverUrl does not end with /
|
|
174
|
+
this.serverUrl = serverUrl;
|
|
175
|
+
this.roomname = roomname;
|
|
176
|
+
this.doc = doc;
|
|
177
|
+
while (this.serverUrl[this.serverUrl.length - 1] === '/') {
|
|
178
|
+
this.serverUrl = this.serverUrl.slice(0, this.serverUrl.length - 1);
|
|
179
|
+
}
|
|
180
|
+
this.bcChannel = this.serverUrl + '/' + roomname;
|
|
181
|
+
this.bc = new BroadcastChannel(this.bcChannel);
|
|
182
|
+
this.maxBackoffTime = opts.maxBackoffTime;
|
|
183
|
+
this.params = opts.params;
|
|
184
|
+
this.protocols = opts.protocols;
|
|
185
|
+
this._WS = opts.WebSocketPolyfill;
|
|
186
|
+
this.awareness = opts.awareness;
|
|
187
|
+
this.disableBc = opts.disableBc;
|
|
188
|
+
this.wsUnsuccessfulReconnects = 0;
|
|
189
|
+
this.messageHandlers = this.setupMessageHandlers();
|
|
190
|
+
this.wsLastMessageReceived = 0;
|
|
191
|
+
this.shouldConnect = opts.connect;
|
|
192
|
+
if (opts.resyncInterval > 0) {
|
|
193
|
+
this._resyncInterval = setInterval(() => {
|
|
194
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
195
|
+
// resend sync step 1
|
|
196
|
+
const encoder = encoding.createEncoder();
|
|
197
|
+
encoding.writeVarUint(encoder, messageSync);
|
|
198
|
+
syncProtocol.writeSyncStep1(encoder, doc);
|
|
199
|
+
this.ws.send(encoding.toUint8Array(encoder));
|
|
200
|
+
}
|
|
201
|
+
}, opts.resyncInterval);
|
|
202
|
+
}
|
|
203
|
+
this._bcSubscriber = (event) => {
|
|
204
|
+
readMessage(this, new Uint8Array(event.data), false);
|
|
205
|
+
};
|
|
206
|
+
/**
|
|
207
|
+
* Listens to Yjs updates and sends them to remote peers (ws and broadcastchannel)
|
|
208
|
+
*/
|
|
209
|
+
this._updateHandler = (update, origin) => {
|
|
210
|
+
if (origin !== this) {
|
|
211
|
+
const encoder = encoding.createEncoder();
|
|
212
|
+
encoding.writeVarUint(encoder, messageSync);
|
|
213
|
+
syncProtocol.writeUpdate(encoder, update);
|
|
214
|
+
broadcastMessage(this, encoding.toUint8Array(encoder));
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
this.doc.on('update', this._updateHandler);
|
|
218
|
+
this._awarenessUpdateHandler = ({ added, updated, removed }, _origin) => {
|
|
219
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
220
|
+
const encoder = encoding.createEncoder();
|
|
221
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
222
|
+
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(opts.awareness, changedClients));
|
|
223
|
+
broadcastMessage(this, encoding.toUint8Array(encoder));
|
|
224
|
+
};
|
|
225
|
+
this._exitHandler = () => {
|
|
226
|
+
awarenessProtocol.removeAwarenessStates(this.awareness, [doc.clientID], 'app closed');
|
|
227
|
+
};
|
|
228
|
+
// if (env.isNode && typeof process !== 'undefined') {
|
|
229
|
+
// process.on('exit', this._exitHandler);
|
|
230
|
+
// }
|
|
231
|
+
opts.awareness.on('update', this._awarenessUpdateHandler);
|
|
232
|
+
this._checkInterval = /** @type {any} */ (setInterval(() => {
|
|
233
|
+
try {
|
|
234
|
+
if (this.wsconnected &&
|
|
235
|
+
messageReconnectTimeout <
|
|
236
|
+
time.getUnixTime() - this.wsLastMessageReceived) {
|
|
237
|
+
// no message received in a long time - not even your own awareness
|
|
238
|
+
// updates (which are updated every 15 seconds)
|
|
239
|
+
if (this.ws) {
|
|
240
|
+
closeWebsocketConnection(this, this.ws, null);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
catch (err) {
|
|
245
|
+
console.error(err);
|
|
246
|
+
}
|
|
247
|
+
}, messageReconnectTimeout / 10));
|
|
248
|
+
if (opts.connect) {
|
|
249
|
+
this.connect();
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
get url() {
|
|
253
|
+
const encodedParams = url.encodeQueryParams(this.params);
|
|
254
|
+
return this.serverUrl + '/' + this.roomname +
|
|
255
|
+
(encodedParams.length === 0 ? '' : '?' + encodedParams);
|
|
256
|
+
}
|
|
257
|
+
get synced() {
|
|
258
|
+
return this._synced;
|
|
259
|
+
}
|
|
260
|
+
set synced(state) {
|
|
261
|
+
if (this._synced !== state) {
|
|
262
|
+
this._synced = state;
|
|
263
|
+
this.dispatchEvent(new CustomEvent('synced', { detail: { state } }));
|
|
264
|
+
this.dispatchEvent(new CustomEvent('sync', { detail: { state } }));
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
destroy() {
|
|
268
|
+
this.destroyed = true;
|
|
269
|
+
if (this._resyncInterval !== 0) {
|
|
270
|
+
clearInterval(this._resyncInterval);
|
|
271
|
+
}
|
|
272
|
+
if (this.setupWSTimeout) {
|
|
273
|
+
clearTimeout(this.setupWSTimeout);
|
|
274
|
+
}
|
|
275
|
+
clearInterval(this._checkInterval);
|
|
276
|
+
this.disconnect();
|
|
277
|
+
// if (env.isNode && typeof process !== 'undefined') {
|
|
278
|
+
// process.off('exit', this._exitHandler);
|
|
279
|
+
// }
|
|
280
|
+
this.awareness.off('update', this._awarenessUpdateHandler);
|
|
281
|
+
this.doc.off('update', this._updateHandler);
|
|
282
|
+
this.awareness.destroy();
|
|
283
|
+
}
|
|
284
|
+
connectBc() {
|
|
285
|
+
if (this.disableBc) {
|
|
286
|
+
return;
|
|
287
|
+
}
|
|
288
|
+
if (!this.bcconnected) {
|
|
289
|
+
this.bc.addEventListener('message', this._bcSubscriber);
|
|
290
|
+
this.bcconnected = true;
|
|
291
|
+
}
|
|
292
|
+
try {
|
|
293
|
+
// send sync step1 to bc
|
|
294
|
+
// write sync step 1
|
|
295
|
+
const encoderSync = encoding.createEncoder();
|
|
296
|
+
encoding.writeVarUint(encoderSync, messageSync);
|
|
297
|
+
syncProtocol.writeSyncStep1(encoderSync, this.doc);
|
|
298
|
+
this.bc.postMessage(encoding.toUint8Array(encoderSync));
|
|
299
|
+
// broadcast local state
|
|
300
|
+
const encoderState = encoding.createEncoder();
|
|
301
|
+
encoding.writeVarUint(encoderState, messageSync);
|
|
302
|
+
syncProtocol.writeSyncStep2(encoderState, this.doc);
|
|
303
|
+
this.bc.postMessage(encoding.toUint8Array(encoderState));
|
|
304
|
+
// write queryAwareness
|
|
305
|
+
const encoderAwarenessQuery = encoding.createEncoder();
|
|
306
|
+
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
307
|
+
this.bc.postMessage(encoding.toUint8Array(encoderAwarenessQuery));
|
|
308
|
+
// broadcast local awareness state
|
|
309
|
+
const encoderAwarenessState = encoding.createEncoder();
|
|
310
|
+
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
311
|
+
encoding.writeVarUint8Array(encoderAwarenessState, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
312
|
+
this.doc.clientID,
|
|
313
|
+
]));
|
|
314
|
+
this.bc.postMessage(encoding.toUint8Array(encoderAwarenessState));
|
|
315
|
+
}
|
|
316
|
+
catch (err) {
|
|
317
|
+
console.trace(err);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
disconnectBc() {
|
|
321
|
+
// broadcast message with local awareness state set to null (indicating disconnect)
|
|
322
|
+
const encoder = encoding.createEncoder();
|
|
323
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
324
|
+
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this.awareness, [
|
|
325
|
+
this.doc.clientID,
|
|
326
|
+
], new Map()));
|
|
327
|
+
broadcastMessage(this, encoding.toUint8Array(encoder));
|
|
328
|
+
if (this.bcconnected) {
|
|
329
|
+
setTimeout(() => {
|
|
330
|
+
try {
|
|
331
|
+
this.bc.close();
|
|
332
|
+
}
|
|
333
|
+
catch (err) {
|
|
334
|
+
console.trace(err);
|
|
335
|
+
}
|
|
336
|
+
}, 0);
|
|
337
|
+
this.bcconnected = false;
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
disconnect() {
|
|
341
|
+
this.shouldConnect = false;
|
|
342
|
+
this.disconnectBc();
|
|
343
|
+
if (this.ws) {
|
|
344
|
+
closeWebsocketConnection(this, this.ws, null);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
connect() {
|
|
348
|
+
this.shouldConnect = true;
|
|
349
|
+
if (!this.wsconnected && !this.ws) {
|
|
350
|
+
setupWS(this);
|
|
351
|
+
this.connectBc();
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
setupMessageHandlers() {
|
|
355
|
+
const messageHandlers = [];
|
|
356
|
+
messageHandlers[messageSync] = (encoder, decoder, provider, emitSynced, _messageType) => {
|
|
357
|
+
encoding.writeVarUint(encoder, messageSync);
|
|
358
|
+
const syncMessageType = syncProtocol.readSyncMessage(decoder, encoder, provider.doc, provider);
|
|
359
|
+
if (emitSynced && syncMessageType === syncProtocol.messageYjsSyncStep2 &&
|
|
360
|
+
!provider.synced) {
|
|
361
|
+
provider.synced = true;
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
messageHandlers[messageQueryAwareness] = (encoder, _decoder, provider, _emitSynced, _messageType) => {
|
|
365
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
366
|
+
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(provider.awareness, Array.from(provider.awareness.getStates().keys())));
|
|
367
|
+
};
|
|
368
|
+
messageHandlers[messageAwareness] = (_encoder, decoder, provider, _emitSynced, _messageType) => {
|
|
369
|
+
awarenessProtocol.applyAwarenessUpdate(provider.awareness, decoding.readVarUint8Array(decoder), provider);
|
|
370
|
+
};
|
|
371
|
+
messageHandlers[messageAuth] = (_encoder, decoder, provider, _emitSynced, _messageType) => {
|
|
372
|
+
authProtocol.readAuthMessage(decoder, provider.doc, (_ydoc, reason) => permissionDeniedHandler(provider, reason));
|
|
373
|
+
};
|
|
374
|
+
return messageHandlers;
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
//# sourceMappingURL=WebsocketProvider.js.map
|