From 55feadef105475a4854b1d26e018b6121b9179d5 Mon Sep 17 00:00:00 2001 From: gohabereg Date: Tue, 19 May 2026 00:51:30 +0100 Subject: [PATCH 1/2] Support user id in API methods --- packages/core/src/api/BlocksAPI.ts | 34 ++++++++++++-------- packages/core/src/api/TextAPI.ts | 20 +++++++----- packages/core/src/components/BlockManager.ts | 27 ++++++++++------ packages/sdk/src/api/BlocksAPI.ts | 20 ++++++++++++ packages/sdk/src/api/TextAPI.ts | 22 ++++++++++--- 5 files changed, 89 insertions(+), 34 deletions(-) diff --git a/packages/core/src/api/BlocksAPI.ts b/packages/core/src/api/BlocksAPI.ts index 33511cc2..eeb8ac34 100644 --- a/packages/core/src/api/BlocksAPI.ts +++ b/packages/core/src/api/BlocksAPI.ts @@ -71,9 +71,10 @@ export class BlocksAPI implements BlocksApiInterface { * Removes Block by index or id, or current block if params are not passed * @param params - delete parameters * @param params.block - index or id of a block to delete + * @param params.userId - user id to attribute the change to */ - public delete({ block }: NonNullable[0]> = {}): void { - return this.#blocksManager.deleteBlock(block); + public delete({ block, userId = this.#config.userId }: NonNullable[0]> = {}): void { + return this.#blocksManager.deleteBlock(block, userId); } /** @@ -81,9 +82,10 @@ export class BlocksAPI implements BlocksApiInterface { * @param params - move parameters * @param params.toIndex - index where the block is moved to * @param [params.fromIndex] - block to move. Current block if not passed + * @param [params.userId] - user id to attribute the change to */ - public move({ toIndex, fromIndex }: Parameters[0]): void { - return this.#blocksManager.move(toIndex, fromIndex); + public move({ toIndex, fromIndex, userId = this.#config.userId }: Parameters[0]): void { + return this.#blocksManager.move(toIndex, fromIndex, userId); } /** @@ -98,9 +100,10 @@ export class BlocksAPI implements BlocksApiInterface { * @param params - insertMany parameters * @param params.blocks - array of blocks to insert * @param [params.index] - index to insert blocks at. If undefined, inserts at the end + * @param [params.userId] - user id to attribute the change to */ - public insertMany({ blocks, index }: Parameters[0]): void { - return this.#blocksManager.insertMany(blocks, index); + public insertMany({ blocks, index, userId = this.#config.userId }: Parameters[0]): void { + return this.#blocksManager.insertMany(blocks, index, userId); } /** @@ -111,8 +114,9 @@ export class BlocksAPI implements BlocksApiInterface { * @param [params.index] - index to insert block at * @param [params.focus] - flag indicates if new block should be focused @todo implement * @param [params.replace] - flag indicates if block at index should be replaced @todo implement + * @param [params.userId] - user id to attribute the change to */ - public insert({ type, data, index, focus, replace }: NonNullable[0]> = {}): void { + public insert({ type, data, index, focus, replace, userId = this.#config.userId }: NonNullable[0]> = {}): void { const blockType = type ?? this.#config.defaultBlock; const blockData = data ?? {}; @@ -122,6 +126,7 @@ export class BlocksAPI implements BlocksApiInterface { index, replace, focus, + userId, }); }; @@ -157,10 +162,11 @@ export class BlocksAPI implements BlocksApiInterface { * @param params.block - index or id of the block * @param params.key - data key of the new data node * @param [params.initialData] - optional initial data + * @param [params.userId] - user id to attribute the change to */ - public createData({ block, key, initialData }: Parameters[0]): void { + public createData({ block, key, initialData, userId = this.#config.userId }: Parameters[0]): void { this.#model.createDataNode( - this.#config.userId, + userId, block as BlockIndexOrId, key, initialData @@ -172,9 +178,10 @@ export class BlocksAPI implements BlocksApiInterface { * @param params - removeData parameters * @param params.block - index or identifier of the block * @param params.key - data key of the node to remove + * @param [params.userId] - user id to attribute the change to */ - public removeData({ block, key }: Parameters[0]): void { - this.#model.removeDataNode(this.#config.userId, block as BlockIndexOrId, key); + public removeData({ block, key, userId = this.#config.userId }: Parameters[0]): void { + this.#model.removeDataNode(userId, block as BlockIndexOrId, key); } /** @@ -183,8 +190,9 @@ export class BlocksAPI implements BlocksApiInterface { * @param params.block - index or identifier of the block * @param params.key - key of the data node to update * @param params.value - new value + * @param [params.userId] - user id to attribute the change to */ - public updateValue({ block, key, value }: Parameters[0]): void { - this.#model.updateValue(this.#config.userId, block as BlockIndexOrId, createDataKey(key), value); + public updateValue({ block, key, value, userId = this.#config.userId }: Parameters[0]): void { + this.#model.updateValue(userId, block as BlockIndexOrId, createDataKey(key), value); } } diff --git a/packages/core/src/api/TextAPI.ts b/packages/core/src/api/TextAPI.ts index 1e51d74e..c4214556 100644 --- a/packages/core/src/api/TextAPI.ts +++ b/packages/core/src/api/TextAPI.ts @@ -45,10 +45,11 @@ export class TextAPI implements TextAPIInterface { * @param params.block - block index or identifier * @param params.key - data key of the text node * @param params.start - start offset + * @param [params.userId] - user id to attribute the change to */ - public insert({ text, block, key, start }: Parameters[0]): void { + public insert({ text, block, key, start, userId = this.#config.userId }: Parameters[0]): void { this.#model.insertText( - this.#config.userId, + userId, block as BlockIndexOrId, createDataKey(key), text, @@ -63,10 +64,11 @@ export class TextAPI implements TextAPIInterface { * @param params.key - data key of the text node * @param params.start - range start * @param params.end - range end + * @param [params.userId] - user id to attribute the change to */ - public remove({ block, key, start, end }: Parameters[0]): string { + public remove({ block, key, start, end, userId = this.#config.userId }: Parameters[0]): string { return this.#model.removeText( - this.#config.userId, + userId, block as BlockIndexOrId, createDataKey(key), start, @@ -83,10 +85,11 @@ export class TextAPI implements TextAPIInterface { * @param params.start - range start * @param params.end - range end * @param params.data - optional tool's data + * @param [params.userId] - user id to attribute the change to */ - public format({ tool, block, key, start, end, data }: Parameters[0]): void { + public format({ tool, block, key, start, end, data, userId = this.#config.userId }: Parameters[0]): void { this.#model.format( - this.#config.userId, + userId, block as BlockIndexOrId, createDataKey(key), createInlineToolName(tool), @@ -104,10 +107,11 @@ export class TextAPI implements TextAPIInterface { * @param params.key - data key of the text node * @param params.start - range start * @param params.end - range end + * @param [params.userId] - user id to attribute the change to */ - public unformat({ tool, block, key, start, end }: Parameters[0]): void { + public unformat({ tool, block, key, start, end, userId = this.#config.userId }: Parameters[0]): void { this.#model.unformat( - this.#config.userId, + userId, block as BlockIndexOrId, createDataKey(key), createInlineToolName(tool), diff --git a/packages/core/src/components/BlockManager.ts b/packages/core/src/components/BlockManager.ts index 710a40d8..21583791 100644 --- a/packages/core/src/components/BlockManager.ts +++ b/packages/core/src/components/BlockManager.ts @@ -45,6 +45,10 @@ interface InsertBlockParameters { */ focus?: boolean; // tunes?: {[name: string]: BlockTuneData}; + /** + * User id to attribute the change to + */ + userId?: string | number; } /** @@ -113,6 +117,7 @@ export class BlocksManager { * @param parameters.index - index to insert block at // * @param parameters.needToFocus - flag indicates if caret should be set to block after insert * @param parameters.replace - flag indicates if block at index should be replaced + * @param parameters.userId - user id to attribute the change to */ public insert({ id = undefined, @@ -121,6 +126,7 @@ export class BlocksManager { index, focus = false, replace = false, + userId = this.#config.userId, // tunes = {}, }: InsertBlockParameters = {}): void { let newIndex = index; @@ -130,10 +136,10 @@ export class BlocksManager { } if (replace) { - this.#model.removeBlock(this.#config.userId, newIndex); + this.#model.removeBlock(userId, newIndex); } - this.#model.addBlock(this.#config.userId, { + this.#model.addBlock(userId, { ...data, id, name: type, @@ -150,9 +156,10 @@ export class BlocksManager { * Inserts several Blocks to specified index * @param blocks - array of blocks to insert * @param [index] - index to insert blocks at. If undefined, inserts at the end + * @param [userId] - user id to attribute the change to */ - public insertMany(blocks: BlockNodeInit[], index: number = this.#model.length): void { - blocks.forEach((block, i) => this.#model.addBlock(this.#config.userId, block, index + i)); + public insertMany(blocks: BlockNodeInit[], index: number = this.#model.length, userId: string | number = this.#config.userId): void { + blocks.forEach((block, i) => this.#model.addBlock(userId, block, index + i)); } /** @@ -173,8 +180,9 @@ export class BlocksManager { /** * Removes Block by index, or current block if index is not passed * @param indexOrId - index or identifier of a block to delete + * @param [userId] - user id to attribute the change to */ - public deleteBlock(indexOrId: number | string | undefined = this.#getCurrentBlockIndex()): void { + public deleteBlock(indexOrId: number | string | undefined = this.#getCurrentBlockIndex(), userId: string | number = this.#config.userId): void { if (indexOrId === undefined) { /** * @todo see what happens in legacy @@ -182,15 +190,16 @@ export class BlocksManager { throw new Error('No block selected to delete'); } - this.#model.removeBlock(this.#config.userId, indexOrId as BlockIndexOrId); + this.#model.removeBlock(userId, indexOrId as BlockIndexOrId); } /** * Moves a block to a new index * @param toIndex - index where the block is moved to * @param [fromIndex] - block to move. Current block if not passed + * @param [userId] - user id to attribute the change to */ - public move(toIndex: number, fromIndex: number | undefined = this.#getCurrentBlockIndex()): void { + public move(toIndex: number, fromIndex: number | undefined = this.#getCurrentBlockIndex(), userId: string | number = this.#config.userId): void { if (fromIndex === undefined) { throw new Error('No block selected to move'); } @@ -204,8 +213,8 @@ export class BlocksManager { const block = this.#model.getBlockSerialized(fromIndex); - this.#model.removeBlock(this.#config.userId, fromIndex); - this.#model.addBlock(this.#config.userId, block, toIndex); + this.#model.removeBlock(userId, fromIndex); + this.#model.addBlock(userId, block, toIndex); } /** diff --git a/packages/sdk/src/api/BlocksAPI.ts b/packages/sdk/src/api/BlocksAPI.ts index 81d2ef28..09bf8457 100644 --- a/packages/sdk/src/api/BlocksAPI.ts +++ b/packages/sdk/src/api/BlocksAPI.ts @@ -36,6 +36,8 @@ export interface BlocksAPI { replace?: boolean; /** Id of the inserted block */ id?: string; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** @@ -60,10 +62,13 @@ export interface BlocksAPI { * Removes Block by index or id, or current block if params are not passed * @param [params] - optional delete parameters * @param [params.block] - index or id of a block to delete + * @param [params.userId] - user id. Defaults to the current user id from the config */ delete(params?: { /** Index or id of a block to delete */ block?: number | string; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** @@ -71,12 +76,15 @@ export interface BlocksAPI { * @param params - move parameters * @param params.toIndex - index where the block is moved to * @param [params.fromIndex] - block to move. Current block if not passed + * @param [params.userId] - user id. Defaults to the current user id from the config */ move(params: { /** Index where the block is moved to */ toIndex: number; /** Block to move. Current block if not passed */ fromIndex?: number; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** @@ -118,12 +126,15 @@ export interface BlocksAPI { * @param params - insertMany parameters * @param params.blocks - array of blocks to insert * @param [params.index] - index to insert blocks at. If undefined, inserts at the end + * @param [params.userId] - user id. Defaults to the current user id from the config */ insertMany(params: { /** Array of blocks to insert */ blocks: BlockNodeInit[]; /** Index to insert blocks at. If undefined, inserts at the end */ index?: number; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** @@ -156,12 +167,15 @@ export interface BlocksAPI { * @param params - removeData parameters * @param params.block - index or id of the block * @param params.key - data key to remove + * @param [params.userId] - user id. Defaults to the current user id from the config */ removeData(params: { /** Index or id of the block */ block: number | string; /** Data key to remove */ key: string; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** @@ -170,6 +184,7 @@ export interface BlocksAPI { * @param params.block - index or id of the block * @param params.key - data key to create * @param [params.initialData] - optional initial data + * @param [params.userId] - user id. Defaults to the current user id from the config */ createData(params: { /** Index or id of the block */ @@ -178,6 +193,8 @@ export interface BlocksAPI { key: string; /** Optional initial data */ initialData?: TextNodeSerialized | ValueSerialized; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** @@ -186,6 +203,7 @@ export interface BlocksAPI { * @param params.block - index or id of the block * @param params.key - data key to update * @param params.value - new value + * @param [params.userId] - user id. Defaults to the current user id from the config */ updateValue(params: { /** Index or id of the block */ @@ -194,6 +212,8 @@ export interface BlocksAPI { key: string; /** New value */ value: V; + /** User id. Defaults to the current user id from the config */ + userId?: string | number; }): void; /** diff --git a/packages/sdk/src/api/TextAPI.ts b/packages/sdk/src/api/TextAPI.ts index fe3bc6b5..bf8e4861 100644 --- a/packages/sdk/src/api/TextAPI.ts +++ b/packages/sdk/src/api/TextAPI.ts @@ -48,6 +48,16 @@ interface InlineToolData { data?: Record; } +/** + * Optional user id parameter for mutating operations + */ +interface UserIdParam { + /** + * User id. Defaults to the current user id from the config + */ + userId?: string | number; +} + /** * Editor's TextAPI to work with text content of the document */ @@ -58,8 +68,9 @@ export interface TextAPI { * @param params.block - block index or identifier * @param params.key - data key of the text node * @param [params.start] - start offset + * @param [params.userId] - user id. Defaults to the current user id from the config */ - insert(params: TextContent & Omit): void; + insert(params: TextContent & Omit & UserIdParam): void; /** * Removes text from a given range @@ -67,8 +78,9 @@ export interface TextAPI { * @param params.key - data key of the text node * @param [params.start] - range start * @param [params.end] - range end + * @param [params.userId] - user id. Defaults to the current user id from the config */ - remove(params: TextPosition): string; + remove(params: TextPosition & UserIdParam): string; /** * Formats the given range @@ -78,8 +90,9 @@ export interface TextAPI { * @param params.start - range start * @param params.end - range end * @param [params.data] - optional tool's data + * @param [params.userId] - user id. Defaults to the current user id from the config */ - format(params: InlineToolData & Required): void; + format(params: InlineToolData & Required & UserIdParam): void; /** * Unformats the given range @@ -88,8 +101,9 @@ export interface TextAPI { * @param params.key - data key of the text node * @param params.start - range start * @param params.end - range end + * @param [params.userId] - user id. Defaults to the current user id from the config */ - unformat(params: Pick & Required): void; + unformat(params: Pick & Required & UserIdParam): void; /** * Returns applied inline fragments for a given range From a5d2c360e41c4a187a9c61db7ee532ff3e1ef8e3 Mon Sep 17 00:00:00 2001 From: gohabereg Date: Tue, 19 May 2026 18:19:35 +0100 Subject: [PATCH 2/2] Fix core tests --- packages/core/src/api/BlocksAPI.spec.ts | 41 +++++++++++++++++-------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/core/src/api/BlocksAPI.spec.ts b/packages/core/src/api/BlocksAPI.spec.ts index e0b56e8a..42499fad 100644 --- a/packages/core/src/api/BlocksAPI.spec.ts +++ b/packages/core/src/api/BlocksAPI.spec.ts @@ -68,25 +68,31 @@ describe('BlocksAPI', () => { it('should pass explicit index to blocksManager.deleteBlock', () => { const api = new BlocksAPI( blocksManager, - { defaultBlock } as CoreConfigValidated, + { + defaultBlock, + userId: 'userId', + } as CoreConfigValidated, new EditorJSModel('userId', { identifier: 'docId' }) ); api.delete({ block: 2 }); - expect(blocksManager.deleteBlock).toHaveBeenCalledWith(2); + expect(blocksManager.deleteBlock).toHaveBeenCalledWith(2, 'userId'); }); it('should pass undefined when index is omitted', () => { const api = new BlocksAPI( blocksManager, - { defaultBlock } as CoreConfigValidated, + { + defaultBlock, + userId: 'userId', + } as CoreConfigValidated, new EditorJSModel('userId', { identifier: 'docId' }) ); api.delete(); - expect(blocksManager.deleteBlock).toHaveBeenCalledWith(undefined); + expect(blocksManager.deleteBlock).toHaveBeenCalledWith(undefined, 'userId'); }); }); @@ -94,14 +100,19 @@ describe('BlocksAPI', () => { it('should call blocksManager.move with toIndex and fromIndex', () => { const api = new BlocksAPI( blocksManager, - { defaultBlock } as CoreConfigValidated, + { + defaultBlock, + userId: 'userId', + } as CoreConfigValidated, new EditorJSModel('userId', { identifier: 'docId' }) ); - api.move({ toIndex: 3, - fromIndex: 1 }); + api.move({ + toIndex: 3, + fromIndex: 1, + }); - expect(blocksManager.move).toHaveBeenCalledWith(3, 1); + expect(blocksManager.move).toHaveBeenCalledWith(3, 1, 'userId'); }); }); @@ -124,7 +135,10 @@ describe('BlocksAPI', () => { it('should pass blocks and index to blocksManager.insertMany', () => { const api = new BlocksAPI( blocksManager, - { defaultBlock } as CoreConfigValidated, + { + defaultBlock, + userId: 'userId', + } as CoreConfigValidated, new EditorJSModel('userId', { identifier: 'docId' }) ); @@ -138,13 +152,16 @@ describe('BlocksAPI', () => { index: 4, }); - expect(blocksManager.insertMany).toHaveBeenCalledWith(blocks, 4); + expect(blocksManager.insertMany).toHaveBeenCalledWith(blocks, 4, 'userId'); }); it('should pass undefined index to blocksManager.insertMany when omitted', () => { const api = new BlocksAPI( blocksManager, - { defaultBlock } as CoreConfigValidated, + { + defaultBlock, + userId: 'userId', + } as CoreConfigValidated, new EditorJSModel('userId', { identifier: 'docId' }) ); @@ -155,7 +172,7 @@ describe('BlocksAPI', () => { api.insertMany({ blocks }); - expect(blocksManager.insertMany).toHaveBeenCalledWith(blocks, undefined); + expect(blocksManager.insertMany).toHaveBeenCalledWith(blocks, undefined, 'userId'); }); });