Operational transformation engine
npm install ot-engine

!Build Status
Operational transformation engine
https://ot-engine-rich-text.herokuapp.com/
- typescript full stack
- support local undo/redo
- support presence(cursors)
``ts`
export type OTType = {
name: string;
create?(data: any): S;
applyAndInvert?(snapshot: S, op: P, invert: boolean): [S, P | undefined];
apply?(snapshot: S, op: P): S;
invert?(op: P): P;
invertWithDoc?(op: P, snapshot: S): P;
transform(op: P, refOp: P, side: OTSide): P;
transformPresence?(presence: Pr, refOp: P, isOwnOp:boolean): Pr;
serialize?(s: S): any;
deserialize?(data: any): S;
};
` { export interface Snapshot export type SnapshotAndOps []; export interface GetOpsParams { export interface GetSnapshotParams { export interface CommitOpParams { ; export interface SaveSnapshotParams export interface DB { (params: GetOpsParams): Promise (params: CommitOpParams ): Promisets`
export interface Op
version: number;
id: string;
content: P;
} {
version: number;
rollback?: boolean;
content: S;
} = {
snapshot: Snapshot;
ops: Op
};
custom?: any;
collection: string;
docId: string;
fromVersion: number;
toVersion?: number;
}
custom?: any;
collection: string;
docId: string;
version?: number;
toVersion?: number;
}
custom?: any;
collection: string;
docId: string;
op: Op
} {
custom?: any;
collection: string;
docId: string;
snapshot: Snapshot;
}
getOps
getSnapshot(params: GetSnapshotParams): Promise
commitOp
saveSnapshot(params: SaveSnapshotParams): Promise
}
export interface PubSubData {
data: any;
}
export interface PubSub {
subscribe(channel: string, callback: (d: PubSubData) => void): void;
publish(channel: string, data: any): void;
unsubscribe(channel: string, callback: (d: PubSubData) => void): void;
}
export interface ServerConfig {
saveInterval?: number;
db?: DB;
pubSub?: PubSub;
}
export interface AgentConfig {
/* passed to db /
custom?:Custom;
stream: Duplex;
collection: string;
docId: string;
clientId: string;
otType: OTType;
}
export declare class Server {
constructor(params?: ServerConfig);
handleStream(config: AgentConfig): void;
}
`ts
import { Event,EventTarget } from 'ts-event-target';
interface DocConfig {
socket: WebSocket;
otType: OTType;
clientId: string;
undoStackLimit?: number;
cacheServerOpsLimit?: number;
}
declare class OpEvent
extends Event<'op'> {
ops: P[];
undoRedo: boolean;
source: boolean;
constructor();
}
declare class BeforeOpEvent
extends Event<'beforeOp'> {
ops: P[];
undoRedo: boolean;
source: boolean;
constructor();
}
declare class RemoteDeleteDocEvent extends Event<'remoteDeleteDoc'> {
constructor();
}
declare class RollbackEvent extends Event<'rollback'> {
constructor();
}
export declare class Doc extends EventTarget<[
OpEvent
,
BeforeOpEvent
,
RemoteDeleteDocEvent,
RollbackEvent
]> {
constructor(config: DocConfig);
canUndo(): boolean;
canRedo(): boolean;
undo(): void;
redo(): void;
destroy(): void;
submitOp(opContent: P): void;
submitPresence(presence: Pr): void;
delete(): Promise
rollback(params: {version:number}): Promise
fetch(): Promise
data:S;
remotePresences:Record
}
`
``
npm i pnpm@8.x -g
pnpm i
pnpm dev
open: http://localhost:3000/
```
npm run pub
git push heroku main:master --force