import type { ReactElement } from 'react'; import type { SerializedStyles } from '@emotion/react'; import type { BatchAttrsStep, OverrideDocumentStepJSON as OverrideDocumentStep } from '@atlaskit/adf-schema/steps'; import type { JSONDocNode } from '@atlaskit/editor-json-transformer'; import type { Node as PMNode, Slice } from '@atlaskit/editor-prosemirror/model'; import type { EditorState, ReadonlyTransaction, Transaction } from '@atlaskit/editor-prosemirror/state'; import type { Step } from '@atlaskit/editor-prosemirror/transform'; import { token } from '@atlaskit/tokens'; import type { Providers } from '../provider-factory'; import type { GetResolvedEditorStateReason } from '../types'; export type NewCollabSyncUpErrorAttributes = { clientId?: number | string; lengthOfUnconfirmedSteps?: number; maxRetries: number; tries: number; version: number; }; export type ResolvedEditorState = { content: JSONDocNode | T; stepVersion: number; title: string | null; }; export declare enum PROVIDER_ERROR_CODE { NO_PERMISSION_ERROR = "NO_PERMISSION_ERROR", INVALID_USER_TOKEN = "INVALID_USER_TOKEN", DOCUMENT_NOT_FOUND = "DOCUMENT_NOT_FOUND", LOCKED = "LOCKED", FAIL_TO_SAVE = "FAIL_TO_SAVE", DOCUMENT_RESTORE_ERROR = "DOCUMENT_RESTORE_ERROR", INITIALISATION_ERROR = "INITIALISATION_ERROR", NETWORK_ISSUE = "NETWORK_ISSUE", INVALID_PROVIDER_CONFIGURATION = "INVALID_PROVIDER_CONFIGURATION", INTERNAL_SERVICE_ERROR = "INTERNAL_SERVICE_ERROR", DOCUMENT_UPDATE_ERROR = "DOCUMENT_UPDATE_ERROR" } /** * This occurs when the provided user token is considered invalid for the given document ARI. * It happens during initialisation of the provider. * It could mean the document has been deleted (hence not found). * @message Message returned to editor, i.e User does not have permissions to access this document or document is not found * @recoverable It is recoverable, as we will try to refresh the token. */ type InsufficientEditingPermission = { code: PROVIDER_ERROR_CODE.NO_PERMISSION_ERROR; message: string; reason?: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * Similar to InsufficientEditingPermission, but the user token is invalid because it has expired or been revoked. * It may also be an invalid token format. * This error is given to the provider by NCS. * @message Message returned to editor, i.e. The user token was invalid * @recoverable It is recoverable, as we will try to refresh the token. */ type InvalidUserToken = { code: PROVIDER_ERROR_CODE.INVALID_USER_TOKEN; message: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * Document not found error, thrown when the provider is unable to find a document with the given ARI and user token. * It occurs during fetchCatchup, a function that fetches the latest document state during catchup. * We need to recieve a 404 from the document service to throw this error. * @message Message returned to editor, i.e. The requested document is not found * @recoverable It is recoverable, as the provider can try again later. */ type DocumentNotFound = { code: PROVIDER_ERROR_CODE.DOCUMENT_NOT_FOUND; message: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * This error is thrown when the document is locked by another user. * The error is passed to us by NCS. * @message Message returned to editor, i.e. The document is currently not available, please try again later * @recoverable It is recoverable, as the provider can try again later. */ type Locked = { code: PROVIDER_ERROR_CODE.LOCKED; message: string; recoverable: boolean; status?: number; }; /** * This error is thrown when the provider is unable to save the document. * This can happen when the connection to dynamoDB is lost, or when we do not have sufficient permissions (DYNAMO ERROR). * This error is given to us by NCS. * @message Message returned to editor, i.e. Collab service is not able to save changes * @recoverable It is not recoverable, as we don't want the user to continue editing a document that is not being saved. */ type FailToSave = { code: PROVIDER_ERROR_CODE.FAIL_TO_SAVE; message: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * This error is thrown when the provider is unable to restore the document. * It occurs during onRestore, a function that restores the document to a previous version and reapplies unconfirmed steps. * onRestore is called when page recovery has emitted an 'init' event on a page client is currently connected to. * It could mean we failed to update the page metadata, or we failed to reapply unconfirmed steps. * @message Message returned to editor, i.e. Collab service unable to restore document * @recoverable It is not recoverable, as the provider has no further options after this. * The user will need to refresh the page to try again. */ type DocumentNotRestore = { code: PROVIDER_ERROR_CODE.DOCUMENT_RESTORE_ERROR; message: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * The initial document couldn't be loaded from the collab service. * This error is given to us by NCS. * It could indicate either a network issue, or an internal service error in NCS. * @message Message returned to editor, i.e. The initial document couldn't be loaded from the collab service * @recoverable It is not recoverable, as the provider cannot do anything to fix it. * The user will need to refresh the page to try again. */ type InitialisationError = { code: PROVIDER_ERROR_CODE.INITIALISATION_ERROR; message: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * Couldn't reconnect to the collab service (NCS) due to network issues. * NCS could be down, or the user could be offline. It's also possible the url is incorrect, or the user is behind a proxy blocking the connection. * Fired upon a reconnection attempt error (from Socket.IO Manager) * @message Message returned to editor, i.e. Couldn't reconnect to the collab service due to network issues * @recoverable It is recoverable, as the provider will try to reconnect. */ type NetworkIssue = { code: PROVIDER_ERROR_CODE.NETWORK_ISSUE; message: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * This error is thrown when the provider has an invalid configuration. * It could happen due to these errors from NCS: * NAMESPACE_INVALID INVALID_ACTIVATION_ID INVALID_DOCUMENT_ARI INVALID_CLOUD_ID * @message Message returned to editor, i.e. Invalid provider configuration * @recoverable It is not recoverable, as the provider cannot do anything to fix it. * The service using the provider will need to fix the configuration. */ type InvalidProviderConfiguration = { code: PROVIDER_ERROR_CODE.INVALID_PROVIDER_CONFIGURATION; message: string; reason: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * This error is thrown when the provider encounters an internal service error, not otherwise accounted for. * @message Message returned to editor, i.e. Collab Provider experienced an unrecoverable error * @recoverable It is not recoverable, as the provider cannot do anything to fix it. */ type InternalServiceError = { code: PROVIDER_ERROR_CODE.INTERNAL_SERVICE_ERROR; message: string; reason: string; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; type ProviderDocumentUpdateError = { code: PROVIDER_ERROR_CODE.DOCUMENT_UPDATE_ERROR; message: 'The provider failed to apply changes to the editor'; recoverable: boolean; /** * @deprecated switch to using either the error code or the recoverable flag */ status?: number; }; /** * A union of all possible provider errors that can be emitted back to the editor. */ export type ProviderError = InsufficientEditingPermission | InvalidUserToken | DocumentNotFound | Locked | FailToSave | DocumentNotRestore | InitialisationError | NetworkIssue | InvalidProviderConfiguration | InternalServiceError | ProviderDocumentUpdateError; export interface Metadata { [key: string]: string | number | boolean; } export type CollabMetadataPayload = Metadata; export interface CollabEventInitData { doc?: any; json?: any; reserveCursor?: boolean; sid?: string; version?: number; } export interface CollabInitPayload extends CollabEventInitData { caller?: string; doc: any; metadata?: Metadata; reserveCursor?: boolean; targetClientId?: string; version: number; } export interface CollabEventConnectionData { initial: boolean; sid: string; } export type CollabConnectedPayload = CollabEventConnectionData; export declare enum DisconnectReason { CLIENT_DISCONNECT = "CLIENT_DISCONNECT", SERVER_DISCONNECT = "SERVER_DISCONNECT", SOCKET_CLOSED = "SOCKET_CLOSED", SOCKET_ERROR = "SOCKET_ERROR", SOCKET_TIMEOUT = "SOCKET_TIMEOUT", UNKNOWN_DISCONNECT = "UNKNOWN_DISCONNECT" } export interface CollabDisconnectedPayload { reason: DisconnectReason; sid: string; } export interface CollabNamespaceLockCheckPayload { isLocked: boolean; } export interface CollabEventRemoteData { json?: any; newState?: EditorState; userIds?: (number | string)[]; } type MarkJson = { attrs: { [key: string]: any; }; type: string; }; export type NodeJson = { attrs: { [key: string]: any; }; content: NodeJson[]; marks: MarkJson[]; text?: string; type: string; }; type SliceJson = { content: NodeJson[]; openEnd: number; openStart: number; }; export interface StepMetadata { metadata?: { createdOffline?: boolean; prevStepId?: string; rebased?: boolean; reqId?: string; schemaVersion?: string; source?: string; stepId?: string; traceId?: string; unconfirmedStepAfterRecovery?: boolean; }; } export interface BaseStepPM extends StepMetadata { clientId: number | string; from?: number; slice?: SliceJson; stepType: string; to?: number; userId: string; } export interface ReplaceStepPM extends BaseStepPM { from: number; slice: SliceJson; structure?: boolean; to: number; } export interface ReplaceAroundStepPM extends BaseStepPM { from: number; gapFrom: number; gapTo: number; insert: number; slice: SliceJson; structure?: boolean; to: number; } export type InlineCommentStepPM = InlineCommentAddMarkStepPM | InlineCommentAddNodeMarkStepPM; interface InlineCommentAddMarkStepPM extends BaseStepPM { from: number; mark?: { attrs?: { annotationType?: 'inlineComment'; id?: string; }; type?: 'annotation'; }; stepType: 'addMark'; to: number; } export interface InlineCommentAddNodeMarkStepPM extends BaseStepPM { mark?: { attrs?: { annotationType?: 'inlineComment'; id?: string; }; type?: 'annotation'; }; pos: number; stepType: 'addNodeMark'; } export interface SetAttrsStepPM extends BaseStepPM { attrs: Record; pos: number; stepType: 'setAttrs'; } export type BatchAttrsStepPM = BaseStepPM & BatchAttrsStep; export type OverrideDocumentStepPM = BaseStepPM & OverrideDocumentStep; export type StepJson = OverrideDocumentStepPM | ReplaceAroundStepPM | ReplaceStepPM | InlineCommentStepPM | SetAttrsStepPM; export interface CollabDataPayload extends CollabEventRemoteData { json: StepJson[]; userIds: (number | string)[]; version: number; } export interface CollabSendableSelection { anchor?: number | string; head?: number | string; type: 'textSelection' | 'nodeSelection'; } export type PresenceActivity = 'viewer' | 'editor'; export type CollabActivityAIProviderChangedPayload = { action: 'add' | 'remove'; providerId?: string; type: 'ai-provider:change'; }; export type CollabPresenceActivityChangePayload = { activity?: PresenceActivity; type: 'participant:activity'; }; export interface CollabEventTelepointerData { selection: CollabSendableSelection; sessionId: string; type: 'telepointer'; } export type CollabTelepointerPayload = CollabEventTelepointerData; type ProviderParticipantPermitLevel = { isPermittedToComment?: boolean; isPermittedToEdit?: boolean; isPermittedToView?: boolean; }; export interface CollabParticipant { avatar: string; cursorPos?: number; isGuest?: boolean; isHydrated?: boolean; lastActive: number; name: string; permit?: ProviderParticipantPermitLevel; presenceActivity?: PresenceActivity; presenceId?: string; sessionId: string; } export type ProviderParticipant = CollabParticipant & { clientId: number | string; email: string; userId: string; }; export interface CollabEventPresenceData { joined?: ProviderParticipant[]; left?: { sessionId: string; }[]; } export type CollabPresencePayload = CollabEventPresenceData; export type CollabLocalStepsPayload = { steps: readonly Step[]; }; export interface CollabEventConnectingData { initial: boolean; } export type CollabConnectingPayload = CollabEventConnectingData; export type CollabCommitStatusEventPayload = { status: 'attempt' | 'success' | 'failure'; version: number; }; export type UserPermitType = { isPermittedToComment: boolean; isPermittedToEdit: boolean; isPermittedToView: boolean; }; export type CollabPermissionEventPayload = UserPermitType; export type ConflictChange = { from: number; local: Slice; remote: Slice; to: number; }; export type ConflictChanges = { deleted: ConflictChange[]; inserted: ConflictChange[]; }; export interface CollabEventConflictPayload extends ConflictChanges { offlineDoc: PMNode; } export interface CollabEvents { 'commit-status': CollabCommitStatusEventPayload; connected: CollabConnectedPayload; connecting: CollabConnectingPayload; data: CollabDataPayload; 'data:conflict': CollabEventConflictPayload; disconnected: CollabDisconnectedPayload; entity: any; error: ProviderError; init: CollabInitPayload; 'local-steps': CollabLocalStepsPayload; 'metadata:changed': Metadata; 'namespace-lock:check': CollabNamespaceLockCheckPayload; permission: CollabPermissionEventPayload; presence: CollabPresencePayload; 'presence:changed': CollabPresenceActivityChangePayload; telepointer: CollabTelepointerPayload; } export type SyncUpErrorFunction = (attributes: NewCollabSyncUpErrorAttributes) => void; export interface CollabEditProvider { getFinalAcknowledgedState: (reason: GetResolvedEditorStateReason) => Promise; getIsNamespaceLocked: () => boolean; initialize: (getState: () => any, createStep: (json: object) => Step) => this; off: (evt: keyof Events, handler: (...args: any) => void) => this; on: (evt: keyof Events, handler: (...args: any) => void) => this; send: (tr: Transaction, oldState: EditorState, newState: EditorState) => void; sendMessage: (data: { type: K; } & Events[K]) => void; setup: (props: { editorApi?: any; getState?: () => EditorState; onSyncUpError?: SyncUpErrorFunction; }) => this; unsubscribeAll: (evt: keyof Events) => this; } export type CollabEditOptions = { provider?: Providers['collabEditProvider']; useNativePlugin?: boolean; userId?: string; } & CollabInviteToEditProps & CollabAnalyticsProps; export type InviteToEditButtonProps = { onClick: (event: React.MouseEvent) => void; selected: boolean; }; export type InviteToEditComponentProps = { children: ReactElement; }; export interface CollabInviteToEditProps { inviteToEditComponent?: React.ComponentType>; inviteToEditHandler?: (event: React.MouseEvent) => void; isInviteToEditButtonSelected?: boolean; } export interface CollabAnalyticsProps { /** * @description Control whether Synchrony entity error events are tracked */ EXPERIMENTAL_allowInternalErrorAnalytics?: boolean; } export interface CollabEventLocalStepData { steps: Array; } export type Color = ReturnType; export declare const TELEPOINTER_DIM_CLASS = "telepointer-dim"; export declare const TELEPOINTER_PULSE_CLASS = "telepointer-pulse-animate"; export declare const TELEPOINTER_PULSE_DURING_TR_CLASS = "telepointer-pulse-during-tr"; export declare const TELEPOINTER_PULSE_DURING_TR_DURATION_MS = 7500; export declare const TELEPOINTER_DATA_SESSION_ID_ATTR = "data-telepointer-sessionid"; export declare const telepointerStyle: SerializedStyles; export declare const isDirtyTransaction: (tr: Transaction | ReadonlyTransaction) => boolean; export declare const tintDirtyTransaction: (tr: Transaction) => void; export {};