@hocuspocus/provider
Version:
hocuspocus provider
470 lines (469 loc) • 17.1 kB
TypeScript
import { Awareness } from "y-protocols/awareness";
import * as Y from "yjs";
import * as lib0_encoding0 from "lib0/encoding";
import { Encoder } from "lib0/encoding";
import { CloseEvent } from "@hocuspocus/common";
import { Decoder } from "lib0/decoding";
//#region packages/provider/src/EventEmitter.d.ts
declare class EventEmitter {
callbacks: {
[key: string]: Function[];
};
on(event: string, fn: Function): this;
protected emit(event: string, ...args: any): this;
off(event: string, fn?: Function): this;
removeAllListeners(): void;
}
//#endregion
//#region packages/provider/src/IncomingMessage.d.ts
declare class IncomingMessage {
data: any;
encoder: Encoder;
decoder: Decoder;
constructor(data: any);
peekVarString(): string;
readVarUint(): MessageType;
readVarString(): string;
readVarUint8Array(): Uint8Array<ArrayBufferLike>;
writeVarUint(type: MessageType): void;
writeVarString(string: string): void;
writeVarUint8Array(data: Uint8Array): void;
length(): number;
}
//#endregion
//#region packages/provider/src/OutgoingMessage.d.ts
declare class OutgoingMessage implements OutgoingMessageInterface {
encoder: Encoder;
type?: MessageType;
constructor();
get(args: Partial<OutgoingMessageArguments>): Encoder | undefined;
toUint8Array(): Uint8Array<ArrayBuffer>;
}
//#endregion
//#region packages/provider/src/OutgoingMessages/AuthenticationMessage.d.ts
declare class AuthenticationMessage extends OutgoingMessage {
type: MessageType;
description: string;
get(args: Partial<OutgoingMessageArguments>): lib0_encoding0.Encoder;
}
//#endregion
//#region packages/provider/src/OutgoingMessages/AwarenessMessage.d.ts
declare class AwarenessMessage extends OutgoingMessage {
type: MessageType;
description: string;
get(args: Partial<OutgoingMessageArguments>): lib0_encoding0.Encoder;
}
//#endregion
//#region packages/provider/src/OutgoingMessages/QueryAwarenessMessage.d.ts
declare class QueryAwarenessMessage extends OutgoingMessage {
type: MessageType;
description: string;
get(args: Partial<OutgoingMessageArguments>): lib0_encoding0.Encoder;
}
//#endregion
//#region packages/provider/src/OutgoingMessages/SyncStepOneMessage.d.ts
declare class SyncStepOneMessage extends OutgoingMessage {
type: MessageType;
description: string;
get(args: Partial<OutgoingMessageArguments>): lib0_encoding0.Encoder;
}
//#endregion
//#region packages/provider/src/OutgoingMessages/SyncStepTwoMessage.d.ts
declare class SyncStepTwoMessage extends OutgoingMessage {
type: MessageType;
description: string;
get(args: Partial<OutgoingMessageArguments>): lib0_encoding0.Encoder;
}
//#endregion
//#region packages/provider/src/OutgoingMessages/UpdateMessage.d.ts
declare class UpdateMessage extends OutgoingMessage {
type: MessageType;
description: string;
get(args: Partial<OutgoingMessageArguments>): lib0_encoding0.Encoder;
}
//#endregion
//#region packages/provider/src/types.d.ts
declare enum MessageType {
Sync = 0,
Awareness = 1,
Auth = 2,
QueryAwareness = 3,
Stateless = 5,
CLOSE = 7,
SyncStatus = 8,
Ping = 9,
Pong = 10
}
declare enum WebSocketStatus {
Connecting = "connecting",
Connected = "connected",
Disconnected = "disconnected"
}
type AuthorizedScope = "read-write" | "readonly";
interface OutgoingMessageInterface {
encoder: Encoder;
type?: MessageType;
}
interface OutgoingMessageArguments {
documentName: string;
token: string;
document: Y.Doc;
awareness: Awareness;
clients: number[];
states: Map<number, {
[key: string]: any;
}>;
update: any;
payload: string;
encoder: Encoder;
}
interface Constructable<T> {
new (...args: any): T;
}
type ConstructableOutgoingMessage = Constructable<AuthenticationMessage> | Constructable<AwarenessMessage> | Constructable<QueryAwarenessMessage> | Constructable<SyncStepOneMessage> | Constructable<SyncStepTwoMessage> | Constructable<UpdateMessage>;
type onAuthenticationFailedParameters = {
reason: string;
};
type onAuthenticatedParameters = {
scope: AuthorizedScope;
};
type onOpenParameters = {
event: Event;
};
type onMessageParameters = {
event: MessageEvent;
message: IncomingMessage;
};
type onOutgoingMessageParameters = {
message: OutgoingMessage;
};
type onStatusParameters = {
status: WebSocketStatus;
};
type onSyncedParameters = {
state: boolean;
};
type onUnsyncedChangesParameters = {
number: number;
};
type onDisconnectParameters = {
event: CloseEvent;
};
type onCloseParameters = {
event: CloseEvent;
};
type onAwarenessUpdateParameters = {
states: StatesArray;
};
type onAwarenessChangeParameters = {
states: StatesArray;
};
type onStatelessParameters = {
payload: string;
};
type StatesArray = {
clientId: number;
[key: string | number]: any;
}[];
//#endregion
//#region packages/provider/src/HocuspocusProviderWebsocket.d.ts
type HocuspocusWebSocket = WebSocket & {
identifier: string;
};
type HocusPocusWebSocket = HocuspocusWebSocket;
type HocuspocusProviderWebsocketConfiguration = Required<Pick<CompleteHocuspocusProviderWebsocketConfiguration, "url">> & Partial<CompleteHocuspocusProviderWebsocketConfiguration>;
interface CompleteHocuspocusProviderWebsocketConfiguration {
/**
* Whether to connect automatically when creating the provider instance. Default=true
*/
autoConnect: boolean;
/**
* URL of your @hocuspocus/server instance
*/
url: string;
/**
* By default, trailing slashes are removed from the URL. Set this to true
* to preserve trailing slashes if your server configuration requires them.
*/
preserveTrailingSlash: boolean;
/**
* An optional WebSocket polyfill, for example for Node.js
*/
WebSocketPolyfill: any;
/**
* Disconnect when no message is received for the defined amount of milliseconds.
*/
messageReconnectTimeout: number;
/**
* The delay between each attempt in milliseconds. You can provide a factor to have the delay grow exponentially.
*/
delay: number;
/**
* The initialDelay is the amount of time to wait before making the first attempt. This option should typically be 0 since you typically want the first attempt to happen immediately.
*/
initialDelay: number;
/**
* The factor option is used to grow the delay exponentially.
*/
factor: number;
/**
* The maximum number of attempts or 0 if there is no limit on number of attempts.
*/
maxAttempts: number;
/**
* minDelay is used to set a lower bound of delay when jitter is enabled. This property has no effect if jitter is disabled.
*/
minDelay: number;
/**
* The maxDelay option is used to set an upper bound for the delay when factor is enabled. A value of 0 can be provided if there should be no upper bound when calculating delay.
*/
maxDelay: number;
/**
* If jitter is true then the calculated delay will be a random integer value between minDelay and the calculated delay for the current iteration.
*/
jitter: boolean;
/**
* A timeout in milliseconds. If timeout is non-zero then a timer is set using setTimeout. If the timeout is triggered then future attempts will be aborted.
*/
timeout: number;
handleTimeout: (() => Promise<unknown>) | null;
onOpen: (data: onOpenParameters) => void;
onConnect: () => void;
onMessage: (data: onMessageParameters) => void;
onOutgoingMessage: (data: onOutgoingMessageParameters) => void;
onStatus: (data: onStatusParameters) => void;
onDisconnect: (data: onDisconnectParameters) => void;
onClose: (data: onCloseParameters) => void;
onDestroy: () => void;
onAwarenessUpdate: (data: onAwarenessUpdateParameters) => void;
onAwarenessChange: (data: onAwarenessChangeParameters) => void;
/**
* Map of attached providers keyed by documentName.
*/
providerMap: Map<string, HocuspocusProvider>;
}
declare class HocuspocusProviderWebsocket extends EventEmitter {
private static readonly DEDUPLICATABLE_TYPES;
private messageQueue;
configuration: CompleteHocuspocusProviderWebsocketConfiguration;
webSocket: HocusPocusWebSocket | null;
webSocketHandlers: {
[key: string]: any;
};
shouldConnect: boolean;
status: WebSocketStatus;
lastMessageReceived: number;
identifier: number;
intervals: any;
connectionAttempt: {
resolve: (value?: any) => void;
reject: (reason?: any) => void;
} | null;
constructor(configuration: HocuspocusProviderWebsocketConfiguration);
receivedOnOpenPayload?: Event | undefined;
onOpen(event: Event): Promise<void>;
attach(provider: HocuspocusProvider): void;
detach(provider: HocuspocusProvider): void;
setConfiguration(configuration?: Partial<HocuspocusProviderWebsocketConfiguration>): void;
cancelWebsocketRetry?: () => void;
connect(): Promise<unknown>;
attachWebSocketListeners(ws: HocusPocusWebSocket, reject: Function): void;
cleanupWebSocket(): void;
createWebSocketConnection(): Promise<unknown>;
onMessage(event: MessageEvent): void;
/**
* Send application-level Pong response to server Ping
*/
private sendPong;
resolveConnectionAttempt(): void;
stopConnectionAttempt(): void;
rejectConnectionAttempt(): void;
closeTries: number;
checkConnection(): void;
get serverUrl(): string;
get url(): string;
disconnect(): void;
private parseQueuedMessage;
private addToQueue;
send(message: any): void;
onClose({
event
}: onCloseParameters): void;
destroy(): void;
}
//#endregion
//#region packages/provider/src/HocuspocusProvider.d.ts
type HocuspocusProviderConfiguration = Required<Pick<CompleteHocuspocusProviderConfiguration, "name">> & Partial<CompleteHocuspocusProviderConfiguration> & ((Required<Pick<CompleteHocuspocusProviderWebsocketConfiguration, "url">> & Partial<Pick<CompleteHocuspocusProviderWebsocketConfiguration, "preserveTrailingSlash">>) | Required<Pick<CompleteHocuspocusProviderConfiguration, "websocketProvider">>);
interface CompleteHocuspocusProviderConfiguration {
/**
* The identifier/name of your document
*/
name: string;
/**
* The actual Y.js document
*/
document: Y.Doc;
/**
* An Awareness instance to keep the presence state of all clients.
*
* You can disable sharing awareness information by passing `null`.
* Note that having no awareness information shared across all connections will break our ping checks
* and thus trigger reconnects. You should always have at least one Provider with enabled awareness per
* socket connection, or ensure that the Provider receives messages before running into `HocuspocusProviderWebsocket.messageReconnectTimeout`.
*/
awareness: Awareness | null;
/**
* A token that’s sent to the backend for authentication purposes.
*/
token: string | (() => string) | (() => Promise<string>) | null;
/**
* Hocuspocus websocket provider
*/
websocketProvider: HocuspocusProviderWebsocket;
/**
* Enable session-aware multiplexing. When true, the provider embeds a unique
* sessionId in the documentName field of every message, allowing multiple
* providers with the same document name on a single WebSocket connection.
*
* Only set this to `true` when connecting to a v4 server that does
* support session awareness.
*
* Default: false
*/
sessionAwareness: boolean;
/**
* Force syncing the document in the defined interval.
*/
forceSyncInterval: false | number;
/**
* Batch outgoing document and awareness updates over a short window (in
* milliseconds) instead of sending one message per change. During heavy
* editing this drastically reduces the number of websocket messages: Yjs
* updates collected in the window are merged with `Y.mergeUpdates` into a
* single message, and awareness collapses to the latest state of each
* changed client.
*
* The window is a fixed batch, not a resetting debounce, so the added
* latency is capped at `flushDelay` even while the user keeps typing. Keep
* it small (e.g. 500) to avoid delaying what other clients see.
*
* Set to `false` (the default) to send every change immediately.
*/
flushDelay: false | number;
onAuthenticated: (data: onAuthenticatedParameters) => void;
onAuthenticationFailed: (data: onAuthenticationFailedParameters) => void;
onOpen: (data: onOpenParameters) => void;
onConnect: () => void;
onStatus: (data: onStatusParameters) => void;
onMessage: (data: onMessageParameters) => void;
onOutgoingMessage: (data: onOutgoingMessageParameters) => void;
onSynced: (data: onSyncedParameters) => void;
onDisconnect: (data: onDisconnectParameters) => void;
onClose: (data: onCloseParameters) => void;
onDestroy: () => void;
onAwarenessUpdate: (data: onAwarenessUpdateParameters) => void;
onAwarenessChange: (data: onAwarenessChangeParameters) => void;
onStateless: (data: onStatelessParameters) => void;
onUnsyncedChanges: (data: onUnsyncedChangesParameters) => void;
}
declare class AwarenessError extends Error {
code: number;
}
declare class HocuspocusProvider extends EventEmitter {
configuration: CompleteHocuspocusProviderConfiguration;
isSynced: boolean;
unsyncedChanges: number;
isAuthenticated: boolean;
authorizedScope: AuthorizedScope | undefined;
manageSocket: boolean;
private _isAttached;
/**
* Outgoing document updates buffered for the current `flushDelay` window.
*/
private pendingUpdates;
/**
* Awareness client ids whose latest state should be sent on the next flush.
*/
private pendingAwarenessClients;
private flushTimeout;
/**
* Unique session identifier for this provider instance.
* Used for multiplexing multiple providers with the same document name on a single WebSocket.
*/
sessionId: string;
/**
* The effective name used as the first VarString in messages.
* When `sessionAwareness` is enabled, returns a composite key (documentName\0sessionId).
* Otherwise, returns the plain document name.
*/
get effectiveName(): string;
intervals: any;
constructor(configuration: HocuspocusProviderConfiguration);
boundDocumentUpdateHandler: (update: Uint8Array, origin: any) => void;
boundAwarenessUpdateHandler: ({
added,
updated,
removed
}: any, origin: any) => void;
boundPageHide: () => void;
boundOnOpen: (event: Event) => Promise<void>;
boundOnClose: () => void;
forwardConnect: () => this;
forwardStatus: (e: onStatusParameters) => this;
forwardClose: (e: onCloseParameters) => this;
forwardDisconnect: (e: onDisconnectParameters) => this;
forwardDestroy: () => this;
setConfiguration(configuration?: Partial<HocuspocusProviderConfiguration>): void;
get document(): Y.Doc;
get isAttached(): boolean;
get awareness(): Awareness | null;
get hasUnsyncedChanges(): boolean;
private resetUnsyncedChanges;
incrementUnsyncedChanges(): void;
decrementUnsyncedChanges(): void;
forceSync(): void;
pageHide(): void;
registerEventListeners(): void;
sendStateless(payload: string): void;
sendToken(): Promise<void>;
private get batchingEnabled();
documentUpdateHandler(update: Uint8Array, origin: any): void;
awarenessUpdateHandler({
added,
updated,
removed
}: any, origin: any): void;
private scheduleFlush;
/**
* Send everything buffered for the current `flushDelay` window right away.
* Buffered document updates are merged into a single message and awareness
* collapses to the latest state of each changed client. Safe to call when
* nothing is pending.
*/
flushPendingUpdates(): void;
/**
* Indicates whether a first handshake with the server has been established
*
* Note: this does not mean all updates from the client have been persisted to the backend. For this,
* use `hasUnsyncedChanges`.
*/
get synced(): boolean;
set synced(state: boolean);
receiveStateless(payload: string): void;
connect(): Promise<unknown>;
disconnect(): void;
onOpen(event: Event): Promise<void>;
getToken(): Promise<string | null>;
startSync(): void;
send(message: ConstructableOutgoingMessage, args: any): void;
onMessage(event: MessageEvent): void;
onClose(): void;
destroy(): void;
detach(): void;
attach(): void;
permissionDeniedHandler(reason: string): void;
authenticatedHandler(scope: string): void;
setAwarenessField(key: string, value: any): void;
}
//#endregion
export { AuthorizedScope, AwarenessError, CompleteHocuspocusProviderConfiguration, CompleteHocuspocusProviderWebsocketConfiguration, Constructable, ConstructableOutgoingMessage, HocusPocusWebSocket, HocuspocusProvider, HocuspocusProviderConfiguration, HocuspocusProviderWebsocket, HocuspocusProviderWebsocketConfiguration, HocuspocusWebSocket, MessageType, OutgoingMessageArguments, OutgoingMessageInterface, StatesArray, WebSocketStatus, onAuthenticatedParameters, onAuthenticationFailedParameters, onAwarenessChangeParameters, onAwarenessUpdateParameters, onCloseParameters, onDisconnectParameters, onMessageParameters, onOpenParameters, onOutgoingMessageParameters, onStatelessParameters, onStatusParameters, onSyncedParameters, onUnsyncedChangesParameters };