diff --git a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts index 772acc47cf..d69e864bdb 100644 --- a/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts +++ b/blocksuite/framework/store/src/__tests__/collection.unit.spec.ts @@ -2,7 +2,7 @@ import type { Slot } from '@blocksuite/global/utils'; import { assert, beforeEach, describe, expect, it, vi } from 'vitest'; -import { applyUpdate, encodeStateAsUpdate } from 'yjs'; +import { applyUpdate, type Doc, encodeStateAsUpdate } from 'yjs'; import { COLLECTION_VERSION, PAGE_VERSION } from '../consts.js'; import type { BlockModel, Blocks, BlockSchemaType } from '../index.js'; @@ -11,7 +11,6 @@ import { Text } from '../reactive/text.js'; import type { DocMeta } from '../store/workspace.js'; import { TestWorkspace } from '../test/test-workspace.js'; import { createAutoIncrementIdGenerator } from '../utils/id-generator.js'; -import type { BlockSuiteDoc } from '../yjs/index.js'; import { NoteBlockSchema, ParagraphBlockSchema, @@ -36,9 +35,9 @@ const defaultDocId = 'doc:home'; const spaceId = defaultDocId; const spaceMetaId = 'meta'; -function serializCollection(doc: BlockSuiteDoc): Record { +function serializCollection(doc: Doc): Record { const spaces = {}; - doc.spaces.forEach((subDoc, key) => { + doc.getMap('spaces').forEach((subDoc, key) => { // @ts-expect-error ignore spaces[key] = subDoc.toJSON(); }); @@ -200,7 +199,7 @@ describe('basic', () => { expect(collection2.docs.size).toBe(0); const update = encodeStateAsUpdate(collection.doc); applyUpdate(collection2.doc, update); - expect(collection2.doc.toJSON()['spaces']).toEqual({ + expect(serializCollection(collection2.doc)['spaces']).toEqual({ 'space:0': { blocks: {}, }, @@ -215,7 +214,7 @@ describe('basic', () => { const doc2 = collection2.getDoc('space:0'); assertExists(doc2); applyUpdate(doc2.spaceDoc, update); - expect(collection2.doc.toJSON()['spaces']).toEqual({ + expect(serializCollection(collection2.doc)['spaces']).toEqual({ 'space:0': { blocks: { '0': { diff --git a/blocksuite/framework/store/src/store/meta.ts b/blocksuite/framework/store/src/store/meta.ts index 8eac6dd2d5..4d51760b15 100644 --- a/blocksuite/framework/store/src/store/meta.ts +++ b/blocksuite/framework/store/src/store/meta.ts @@ -2,7 +2,7 @@ import { Slot } from '@blocksuite/global/utils'; import type * as Y from 'yjs'; import { COLLECTION_VERSION, PAGE_VERSION } from '../consts.js'; -import type { BlockSuiteDoc } from '../yjs/index.js'; +import { createYProxy } from '../reactive/proxy.js'; import type { DocMeta, DocsPropertiesMeta, @@ -52,7 +52,7 @@ export class DocCollectionMeta implements WorkspaceMeta { commonFieldsUpdated = new Slot(); - readonly doc: BlockSuiteDoc; + readonly doc: Y.Doc; docMetaAdded = new Slot(); @@ -116,10 +116,13 @@ export class DocCollectionMeta implements WorkspaceMeta { return this._yMap.get('pages') as unknown as Y.Array; } - constructor(doc: BlockSuiteDoc) { + constructor(doc: Y.Doc) { this.doc = doc; - this._yMap = doc.getMap(this.id); - this._proxy = doc.getMapProxy(this.id); + const map = doc.getMap(this.id) as Y.Map< + DocCollectionMetaState[keyof DocCollectionMetaState] + >; + this._yMap = map; + this._proxy = createYProxy(map); this._yMap.observeDeep(this._handleDocCollectionMetaEvents); } diff --git a/blocksuite/framework/store/src/store/workspace.ts b/blocksuite/framework/store/src/store/workspace.ts index 0bbfc82a12..59e3fdedec 100644 --- a/blocksuite/framework/store/src/store/workspace.ts +++ b/blocksuite/framework/store/src/store/workspace.ts @@ -6,7 +6,6 @@ import type { BlockModel } from '../schema/base.js'; import type { Schema } from '../schema/schema.js'; import type { IdGenerator } from '../utils/id-generator.js'; import type { AwarenessStore } from '../yjs/awareness.js'; -import type { BlockSuiteDoc } from '../yjs/doc.js'; import type { YBlock } from './doc/block/types.js'; import type { Blocks } from './doc/doc.js'; import type { Query } from './doc/query.js'; @@ -76,7 +75,7 @@ export interface Workspace { readonly awarenessStore: AwarenessStore; get schema(): Schema; - get doc(): BlockSuiteDoc; + get doc(): Y.Doc; get docs(): Map; slots: { @@ -136,7 +135,7 @@ export interface Doc { get workspace(): Workspace; - get rootDoc(): BlockSuiteDoc; + get rootDoc(): Y.Doc; get spaceDoc(): Y.Doc; get yBlocks(): Y.Map; } diff --git a/blocksuite/framework/store/src/test/test-doc.ts b/blocksuite/framework/store/src/test/test-doc.ts index 18bd1c68a9..6a72073618 100644 --- a/blocksuite/framework/store/src/test/test-doc.ts +++ b/blocksuite/framework/store/src/test/test-doc.ts @@ -6,12 +6,12 @@ import { Blocks } from '../store/doc/doc.js'; import type { YBlock } from '../store/doc/index.js'; import type { Query } from '../store/doc/query.js'; import type { Doc, GetBlocksOptions, Workspace } from '../store/workspace.js'; -import type { AwarenessStore, BlockSuiteDoc } from '../yjs/index.js'; +import type { AwarenessStore } from '../yjs/index.js'; type DocOptions = { id: string; collection: Workspace; - doc: BlockSuiteDoc; + doc: Y.Doc; awarenessStore: AwarenessStore; }; @@ -43,12 +43,12 @@ export class TestDoc implements Doc { }; private readonly _initSubDoc = () => { - let subDoc = this.rootDoc.spaces.get(this.id); + let subDoc = this.rootDoc.getMap('spaces').get(this.id); if (!subDoc) { subDoc = new Y.Doc({ guid: this.id, }); - this.rootDoc.spaces.set(this.id, subDoc); + this.rootDoc.getMap('spaces').set(this.id, subDoc); this._loaded = true; this._onLoadSlot.emit(); } else { @@ -107,7 +107,7 @@ export class TestDoc implements Doc { readonly id: string; - readonly rootDoc: BlockSuiteDoc; + readonly rootDoc: Y.Doc; readonly slots = { historyUpdated: new Slot(), @@ -192,7 +192,7 @@ export class TestDoc implements Doc { this.rootDoc = doc; this.awarenessStore = awarenessStore; - this._ySpaceDoc = this._initSubDoc(); + this._ySpaceDoc = this._initSubDoc() as Y.Doc; this._yBlocks = this._ySpaceDoc.getMap('blocks'); this._collection = collection; @@ -353,7 +353,7 @@ export class TestDoc implements Doc { remove() { this._destroy(); - this.rootDoc.spaces.delete(this.id); + this.rootDoc.getMap('spaces').delete(this.id); } resetHistory() { diff --git a/blocksuite/framework/store/src/test/test-workspace.ts b/blocksuite/framework/store/src/test/test-workspace.ts index 83ac564ae3..2c3899c953 100644 --- a/blocksuite/framework/store/src/test/test-workspace.ts +++ b/blocksuite/framework/store/src/test/test-workspace.ts @@ -14,6 +14,7 @@ import { import clonedeep from 'lodash.clonedeep'; import merge from 'lodash.merge'; import { Awareness } from 'y-protocols/awareness.js'; +import * as Y from 'yjs'; import type { Schema } from '../schema/index.js'; import { @@ -25,11 +26,7 @@ import { type WorkspaceMeta, } from '../store/index.js'; import { type IdGenerator, nanoid } from '../utils/id-generator.js'; -import { - AwarenessStore, - BlockSuiteDoc, - type RawAwarenessState, -} from '../yjs/index.js'; +import { AwarenessStore, type RawAwarenessState } from '../yjs/index.js'; import { TestDoc } from './test-doc.js'; export type DocCollectionOptions = { @@ -83,7 +80,7 @@ export class TestWorkspace implements Workspace { readonly blockCollections = new Map(); - readonly doc: BlockSuiteDoc; + readonly doc: Y.Doc; readonly docSync: DocEngine; @@ -123,7 +120,7 @@ export class TestWorkspace implements Workspace { this._schema = schema; this.id = id || ''; - this.doc = new BlockSuiteDoc({ guid: id }); + this.doc = new Y.Doc({ guid: id }); this.awarenessStore = new AwarenessStore( new Awareness(this.doc), merge(clonedeep(FLAGS_PRESET), defaultFlags) diff --git a/blocksuite/framework/store/src/yjs/doc.ts b/blocksuite/framework/store/src/yjs/doc.ts deleted file mode 100644 index 9abb9731b5..0000000000 --- a/blocksuite/framework/store/src/yjs/doc.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { Transaction } from 'yjs'; -import * as Y from 'yjs'; - -import { createYProxy } from '../reactive/proxy.js'; - -export type BlockSuiteDocAllowedValue = - | Record - | unknown[] - | Y.Text; -export type BlockSuiteDocData = Record; - -export class BlockSuiteDoc extends Y.Doc { - private readonly _spaces: Y.Map = this.getMap('spaces'); - - get spaces() { - return this._spaces; - } - - getArrayProxy< - Key extends keyof BlockSuiteDocData & string, - Value extends unknown[] = BlockSuiteDocData[Key] extends unknown[] - ? BlockSuiteDocData[Key] - : never, - >(key: Key): Value { - const array = super.getArray(key); - return createYProxy(array) as Value; - } - - getMapProxy< - Key extends keyof BlockSuiteDocData & string, - Value extends Record< - string, - unknown - > = BlockSuiteDocData[Key] extends Record - ? BlockSuiteDocData[Key] - : never, - >(key: Key): Value { - const map = super.getMap(key); - return createYProxy(map); - } - - override toJSON(): Record { - const json = super.toJSON(); - delete json.spaces; - const spaces: Record = {}; - this.spaces.forEach((doc, key) => { - spaces[key] = doc.toJSON(); - }); - return { - ...json, - spaces, - }; - } - - override transact(f: (arg0: Transaction) => T, origin?: number | string) { - return super.transact(f, origin); - } -} diff --git a/blocksuite/framework/store/src/yjs/index.ts b/blocksuite/framework/store/src/yjs/index.ts index f85bac772b..f305676250 100644 --- a/blocksuite/framework/store/src/yjs/index.ts +++ b/blocksuite/framework/store/src/yjs/index.ts @@ -1,3 +1,2 @@ export * from './awareness.js'; -export * from './doc.js'; export * from './utils.js'; diff --git a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx index 5366ff099a..678d325cf5 100644 --- a/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx +++ b/packages/frontend/core/src/components/affine/page-history-modal/history-modal.tsx @@ -11,10 +11,7 @@ import { WorkspaceService } from '@affine/core/modules/workspace'; import { i18nTime, Trans, useI18n } from '@affine/i18n'; import { track } from '@affine/track'; import type { DocMode } from '@blocksuite/affine/blocks'; -import type { - Blocks as BlockSuiteDoc, - Workspace, -} from '@blocksuite/affine/store'; +import type { Blocks, Workspace } from '@blocksuite/affine/store'; import { CloseIcon, ToggleCollapseIcon } from '@blocksuite/icons/rc'; import * as Collapsible from '@radix-ui/react-collapsible'; import type { DialogContentProps } from '@radix-ui/react-dialog'; @@ -90,7 +87,7 @@ const ModalContainer = ({ interface HistoryEditorPreviewProps { ts?: string; historyList: HistoryList; - snapshotPage?: BlockSuiteDoc; + snapshotPage?: Blocks; mode: DocMode; onModeChange: (mode: DocMode) => void; title: string; diff --git a/packages/frontend/core/src/components/blocksuite/block-suite-editor/no-page-error.ts b/packages/frontend/core/src/components/blocksuite/block-suite-editor/no-page-error.ts index 0724a18794..b2ea293a14 100644 --- a/packages/frontend/core/src/components/blocksuite/block-suite-editor/no-page-error.ts +++ b/packages/frontend/core/src/components/blocksuite/block-suite-editor/no-page-error.ts @@ -1,5 +1,5 @@ import type { Blocks } from '@blocksuite/affine/store'; -import type { Map as YMap } from 'yjs'; +import type { Doc as YDoc, Map as YMap } from 'yjs'; /** * TODO(@eyhn): Define error to unexpected state together in the future. @@ -9,9 +9,9 @@ export class NoPageRootError extends Error { super('Page root not found when render editor!'); // Log info to let sentry collect more message - const hasExpectSpace = Array.from(page.rootDoc.spaces.values()).some( - doc => page.spaceDoc.guid === doc.guid - ); + const hasExpectSpace = Array.from( + page.rootDoc.getMap('spaces').values() + ).some(doc => page.spaceDoc.guid === doc.guid); const blocks = page.spaceDoc.getMap('blocks') as YMap>; const havePageBlock = Array.from(blocks.values()).some( block => block.get('sys:flavour') === 'affine:page' diff --git a/packages/frontend/core/src/modules/doc/scopes/doc.ts b/packages/frontend/core/src/modules/doc/scopes/doc.ts index 36812ad1e8..4b06fe3fe3 100644 --- a/packages/frontend/core/src/modules/doc/scopes/doc.ts +++ b/packages/frontend/core/src/modules/doc/scopes/doc.ts @@ -1,4 +1,4 @@ -import type { Blocks as BlockSuiteDoc } from '@blocksuite/affine/store'; +import type { Blocks } from '@blocksuite/affine/store'; import { Scope } from '@toeverything/infra'; import type { DocRecord } from '../entities/record'; @@ -6,5 +6,5 @@ import type { DocRecord } from '../entities/record'; export class DocScope extends Scope<{ docId: string; record: DocRecord; - blockSuiteDoc: BlockSuiteDoc; + blockSuiteDoc: Blocks; }> {} diff --git a/packages/frontend/core/src/modules/workspace/impls/doc.ts b/packages/frontend/core/src/modules/workspace/impls/doc.ts index ff3fd409c8..9dd42a73f2 100644 --- a/packages/frontend/core/src/modules/workspace/impls/doc.ts +++ b/packages/frontend/core/src/modules/workspace/impls/doc.ts @@ -2,7 +2,6 @@ import { type Disposable, Slot } from '@blocksuite/affine/global/utils'; import { type AwarenessStore, Blocks, - type BlockSuiteDoc, type Doc, type GetBlocksOptions, type Query, @@ -15,7 +14,7 @@ import * as Y from 'yjs'; type DocOptions = { id: string; collection: Workspace; - doc: BlockSuiteDoc; + doc: Y.Doc; awarenessStore: AwarenessStore; }; @@ -47,12 +46,12 @@ export class DocImpl implements Doc { }; private readonly _initSubDoc = () => { - let subDoc = this.rootDoc.spaces.get(this.id); + let subDoc = this.rootDoc.getMap('spaces').get(this.id); if (!subDoc) { subDoc = new Y.Doc({ guid: this.id, }); - this.rootDoc.spaces.set(this.id, subDoc); + this.rootDoc.getMap('spaces').set(this.id, subDoc); this._loaded = true; this._onLoadSlot.emit(); } else { @@ -111,7 +110,7 @@ export class DocImpl implements Doc { readonly id: string; - readonly rootDoc: BlockSuiteDoc; + readonly rootDoc: Y.Doc; readonly slots = { historyUpdated: new Slot(), @@ -188,7 +187,7 @@ export class DocImpl implements Doc { this.rootDoc = doc; this.awarenessStore = awarenessStore; - this._ySpaceDoc = this._initSubDoc(); + this._ySpaceDoc = this._initSubDoc() as Y.Doc; this._yBlocks = this._ySpaceDoc.getMap('blocks'); this._collection = collection; @@ -349,7 +348,7 @@ export class DocImpl implements Doc { remove() { this._destroy(); - this.rootDoc.spaces.delete(this.id); + this.rootDoc.getMap('spaces').delete(this.id); } resetHistory() { diff --git a/packages/frontend/core/src/modules/workspace/impls/workspace.ts b/packages/frontend/core/src/modules/workspace/impls/workspace.ts index ed45527611..1b410b72c6 100644 --- a/packages/frontend/core/src/modules/workspace/impls/workspace.ts +++ b/packages/frontend/core/src/modules/workspace/impls/workspace.ts @@ -7,7 +7,6 @@ import { NoopLogger, Slot } from '@blocksuite/affine/global/utils'; import { AwarenessStore, type Blocks, - BlockSuiteDoc, type CreateBlocksOptions, type Doc, DocCollectionMeta, @@ -27,6 +26,7 @@ import { NoopDocSource, } from '@blocksuite/affine/sync'; import { Awareness } from 'y-protocols/awareness.js'; +import * as Y from 'yjs'; import { DocImpl } from './doc'; @@ -67,7 +67,7 @@ export class WorkspaceImpl implements Workspace { readonly blockCollections = new Map(); - readonly doc: BlockSuiteDoc; + readonly doc: Y.Doc; readonly docSync: DocEngine; @@ -95,7 +95,7 @@ export class WorkspaceImpl implements Workspace { this._schema = schema; this.id = id || ''; - this.doc = new BlockSuiteDoc({ guid: id }); + this.doc = new Y.Doc({ guid: id }); this.awarenessStore = new AwarenessStore(new Awareness(this.doc), { ...FLAGS_PRESET, readonly: {},