From 39cb1afedb53ad548027e863a526e160125bb2b7 Mon Sep 17 00:00:00 2001 From: fengmk2 Date: Thu, 29 May 2025 05:32:31 +0000 Subject: [PATCH] fix(server): limit rootDoc snapshot size (#12625) close CLOUD-225 ## Summary by CodeRabbit - **New Features** - Added support for reading document blocks without requiring a workspace or root document snapshot. - **Bug Fixes** - Improved handling of large workspace snapshots by skipping them when they exceed 10MB. - **Tests** - Introduced new test cases to cover scenarios where root or workspace snapshots are absent. - Expanded snapshot tests for document block reading. - **Refactor** - Updated several function signatures to make root and workspace snapshot parameters optional for greater flexibility. --- .../__snapshots__/blocksute.spec.ts.md | 631 ++++++ .../__snapshots__/blocksute.spec.ts.snap | Bin 6255 -> 6692 bytes .../core/utils/__tests__/blocksute.spec.ts | 18 +- .../server/src/core/utils/blocksuite.ts | 13 +- .../server/src/plugins/indexer/service.ts | 7 +- .../__snapshots__/reader.spec.ts.snap | 1688 +++++++++++++++++ .../common/reader/__tests__/reader.spec.ts | 12 + packages/common/reader/src/reader.ts | 12 +- 8 files changed, 2367 insertions(+), 14 deletions(-) diff --git a/packages/backend/server/src/core/utils/__tests__/__snapshots__/blocksute.spec.ts.md b/packages/backend/server/src/core/utils/__tests__/__snapshots__/blocksute.spec.ts.md index a263260663..b10017f90e 100644 --- a/packages/backend/server/src/core/utils/__tests__/__snapshots__/blocksute.spec.ts.md +++ b/packages/backend/server/src/core/utils/__tests__/__snapshots__/blocksute.spec.ts.md @@ -642,3 +642,634 @@ Generated by [AVA](https://avajs.dev). summary: 'AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. You own your data, with no compromisesLocal-first & Real-time collaborativeWe love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.Blocks that assemble your next docs, tasks kanban or whiteboardThere is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. ', title: 'Write, Draw, Plan all at Once.', } + +## can read all blocks from doc snapshot without workspace snapshot + +> Snapshot 1 + + { + blocks: [ + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blockId: 'TnUgtVg7Eu', + content: 'Write, Draw, Plan all at Once.', + docId: 'doc-0', + flavour: 'affine:page', + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'FoPQcAyV_m', + content: 'AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. ', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'oz48nn_zp8', + content: '', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'g8a-D9-jXS', + content: 'You own your data, with no compromises', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'J8lHN1GR_5', + content: 'Local-first & Real-time collaborative', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'xCuWdM0VLz', + content: 'We love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'zElMi0tViK', + content: 'AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'RX4CG2zsBk', + }, + blockId: 'Z4rK0OF9Wk', + content: '', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'RX4CG2zsBk', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'S1mkc8zUoU', + }, + blockId: 'DQ0Ryb-SpW', + content: 'Blocks that assemble your next docs, tasks kanban or whiteboard', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'S1mkc8zUoU', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'yGlBdshAqN', + }, + blockId: 'HAZC3URZp_', + content: 'There is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. ', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'yGlBdshAqN', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'yGlBdshAqN', + }, + blockId: '0H87ypiuv8', + content: 'We are building AFFiNE to be a fundamental open source platform that contains all the building blocks for docs, task management and visual collaboration, hoping you can shape your next workflow with us that can make your life better and also connect others, too.', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'yGlBdshAqN', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'yGlBdshAqN', + }, + blockId: 'Sp4G1KD0Wn', + content: 'If you want to learn more about the product design of AFFiNE, here goes the concepts:', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'yGlBdshAqN', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'yGlBdshAqN', + }, + blockId: 'RsUhDuEqXa', + content: 'To Shape, not to adapt. AFFiNE is built for individuals & teams who care about their data, who refuse vendor lock-in, and who want to have control over their essential tools.', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'yGlBdshAqN', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'Z2HibKzAr-', + content: 'A true canvas for blocks in any form', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'UwvWddamzM', + content: 'Many editor apps claimed to be a canvas for productivity. Since the Mother of All Demos, Douglas Engelbart, a creative and programable digital workspace has been a pursuit and an ultimate mission for generations of tool makers. ', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'g9xKUjhJj1', + content: '', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'wDTn4YJ4pm', + content: '"We shape our tools and thereafter our tools shape us”. A lot of pioneers have inspired us a long the way, e.g.:', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'xFrrdiP3-V', + content: 'Quip & Notion with their great concept of "everything is a block"', + docId: 'doc-0', + flavour: 'affine:list', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'Tp9xyN4Okl', + content: 'Trello with their Kanban', + docId: 'doc-0', + flavour: 'affine:list', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'K_4hUzKZFQ', + content: 'Airtable & Miro with their no-code programable datasheets', + docId: 'doc-0', + flavour: 'affine:list', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'QwMzON2s7x', + content: 'Miro & Whimiscal with their edgeless visual whiteboard', + docId: 'doc-0', + flavour: 'affine:list', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: '6lDiuDqZGL', + }, + blockId: 'FFVmit6u1T', + content: 'Remnote & Capacities with their object-based tag system', + docId: 'doc-0', + flavour: 'affine:list', + parentBlockId: '6lDiuDqZGL', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'cauvaHOQmh', + }, + blockId: 'YqnG5O6AE6', + content: 'For more details, please refer to our RoadMap', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'cauvaHOQmh', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'cauvaHOQmh', + }, + blockId: 'sbDTmZMZcq', + content: 'Self Host', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'cauvaHOQmh', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'cauvaHOQmh', + }, + blockId: 'QVvitesfbj', + content: 'Self host AFFiNE', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'cauvaHOQmh', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'U_GoHFD9At', + content: [ + 'Learning From', + 'Title', + 'Tag', + 'Reference', + 'Developers', + 'AFFiNE', + ], + docId: 'doc-0', + flavour: 'affine:database', + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'tpyOZbPc1P', + content: 'Affine Development', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'VMx9lHw3TR', + content: 'For developers or installations guides, please go to AFFiNE Doc', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'Q6LnVyKoGS', + content: 'Quip & Notion with their great concept of "everything is a block"', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'EkFHpB-mJi', + content: 'Trello with their Kanban', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: '3aMlphe2lp', + content: 'Airtable & Miro with their no-code programable datasheets', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'MiZtUig-fL', + content: 'Miro & Whimiscal with their edgeless visual whiteboard', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: 'Learning From', + displayMode: 'page', + noteBlockId: '2jwCeO8Yot', + }, + blockId: 'erYE2C7cc5', + content: 'Remnote & Capacities with their object-based tag system', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'U_GoHFD9At', + parentFlavour: 'affine:database', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'c9MF_JiRgx', + }, + blockId: 'NyHXrMX3R1', + content: 'Affine Development', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'c9MF_JiRgx', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'c9MF_JiRgx', + }, + blockId: '9-K49otbCv', + content: 'For developer or installation guides, please go to AFFiNE Development', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'c9MF_JiRgx', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + databaseName: undefined, + displayMode: 'page', + noteBlockId: 'c9MF_JiRgx', + }, + blockId: 'faFteK9eG-', + content: '', + docId: 'doc-0', + flavour: 'affine:paragraph', + parentBlockId: 'c9MF_JiRgx', + parentFlavour: 'affine:note', + ref: [], + refDocId: [], + }, + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blockId: '6x7ALjUDjj', + content: [ + 'What is AFFiNE', + 'Related Articles', + ' ', + 'Self-host', + '', + 'AFFiNE ', + 'Development', + 'You can check these URLs to learn about AFFiNE', + 'Database Reference', + ], + docId: 'doc-0', + flavour: 'affine:surface', + parentBlockId: 'TnUgtVg7Eu', + parentFlavour: 'affine:page', + }, + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blockId: 'ECrtbvW6xx', + docId: 'doc-0', + flavour: 'affine:bookmark', + }, + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blockId: '5W--UQLN11', + docId: 'doc-0', + flavour: 'affine:bookmark', + }, + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blob: [ + 'BFZk3c2ERp-sliRvA7MQ_p3NdkdCLt2Ze0DQ9i21dpA=', + ], + blockId: 'lcZphIJe63', + docId: 'doc-0', + flavour: 'affine:image', + parentBlockId: '6x7ALjUDjj', + parentFlavour: 'affine:surface', + }, + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blob: [ + 'HWvCItS78DzPGbwcuaGcfkpVDUvL98IvH5SIK8-AcL8=', + ], + blockId: 'JlgVJdWU12', + docId: 'doc-0', + flavour: 'affine:image', + parentBlockId: '6x7ALjUDjj', + parentFlavour: 'affine:surface', + }, + { + additional: { + displayMode: 'edgeless', + noteBlockId: undefined, + }, + blob: [ + 'ZRKpsBoC88qEMmeiXKXqywfA1rLvWoLa5rpEh9x9Oj0=', + ], + blockId: 'lht7AqBqnF', + docId: 'doc-0', + flavour: 'affine:image', + parentBlockId: '6x7ALjUDjj', + parentFlavour: 'affine:surface', + }, + ], + summary: 'AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. You own your data, with no compromisesLocal-first & Real-time collaborativeWe love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.Blocks that assemble your next docs, tasks kanban or whiteboardThere is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. ', + title: 'Write, Draw, Plan all at Once.', + } diff --git a/packages/backend/server/src/core/utils/__tests__/__snapshots__/blocksute.spec.ts.snap b/packages/backend/server/src/core/utils/__tests__/__snapshots__/blocksute.spec.ts.snap index 06ec55a74f57afad4eca109cc10010b69fcf7a6a..676184bedb5896d2c137aad8a78b089b172c81af 100644 GIT binary patch literal 6692 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 R7rU>xh%tYuK?pZ){1*%9KEVJ0 literal 6255 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 ZR$0mBSlyYr-m$Vn{~zHBGqYcK002xAaHjwO diff --git a/packages/backend/server/src/core/utils/__tests__/blocksute.spec.ts b/packages/backend/server/src/core/utils/__tests__/blocksute.spec.ts index f760d51acc..d5c56449c7 100644 --- a/packages/backend/server/src/core/utils/__tests__/blocksute.spec.ts +++ b/packages/backend/server/src/core/utils/__tests__/blocksute.spec.ts @@ -45,7 +45,23 @@ test('can read all blocks from doc snapshot', async t => { const result = await readAllBlocksFromDocSnapshot( workspace.id, - rootDoc!.blob, + 'doc-0', + docSnapshot.blob, + rootDoc!.blob + ); + + t.snapshot({ + ...result, + blocks: result!.blocks.map(block => omit(block, ['yblock'])), + }); +}); + +test('can read all blocks from doc snapshot without workspace snapshot', async t => { + const doc = await models.doc.get(workspace.id, docSnapshot.id); + t.truthy(doc); + + const result = await readAllBlocksFromDocSnapshot( + workspace.id, 'doc-0', docSnapshot.blob ); diff --git a/packages/backend/server/src/core/utils/blocksuite.ts b/packages/backend/server/src/core/utils/blocksuite.ts index 22ee899023..82c627d12d 100644 --- a/packages/backend/server/src/core/utils/blocksuite.ts +++ b/packages/backend/server/src/core/utils/blocksuite.ts @@ -173,15 +173,18 @@ export function readAllDocIdsFromWorkspaceSnapshot(snapshot: Uint8Array) { export async function readAllBlocksFromDocSnapshot( workspaceId: string, - workspaceSnapshot: Uint8Array, docId: string, docSnapshot: Uint8Array, + workspaceSnapshot?: Uint8Array, maxSummaryLength?: number ) { - const rootYDoc = new YDoc({ - guid: workspaceId, - }); - applyUpdate(rootYDoc, workspaceSnapshot); + let rootYDoc: YDoc | undefined; + if (workspaceSnapshot) { + rootYDoc = new YDoc({ + guid: workspaceId, + }); + applyUpdate(rootYDoc, workspaceSnapshot); + } const ydoc = new YDoc({ guid: docId, }); diff --git a/packages/backend/server/src/plugins/indexer/service.ts b/packages/backend/server/src/plugins/indexer/service.ts index c231fbffa0..64d5e6e3ce 100644 --- a/packages/backend/server/src/plugins/indexer/service.ts +++ b/packages/backend/server/src/plugins/indexer/service.ts @@ -226,11 +226,14 @@ export class IndexerService { this.logger.debug(`doc ${workspaceId}/${docId} is empty, skip indexing`); return; } + const MAX_WORKSPACE_SNAPSHOT_SIZE = 1024 * 1024 * 10; // 10MB const result = await readAllBlocksFromDocSnapshot( workspaceId, - workspaceSnapshot.blob, docId, - docSnapshot.blob + docSnapshot.blob, + workspaceSnapshot.blob.length < MAX_WORKSPACE_SNAPSHOT_SIZE + ? workspaceSnapshot.blob + : undefined ); if (!result) { this.logger.warn( diff --git a/packages/common/reader/__tests__/__snapshots__/reader.spec.ts.snap b/packages/common/reader/__tests__/__snapshots__/reader.spec.ts.snap index fcea084a15..89c5d6d8b8 100644 --- a/packages/common/reader/__tests__/__snapshots__/reader.spec.ts.snap +++ b/packages/common/reader/__tests__/__snapshots__/reader.spec.ts.snap @@ -1756,3 +1756,1691 @@ exports[`should read doc blocks work 1`] = ` "title": "Write, Draw, Plan all at Once.", } `; + +exports[`should read doc blocks work without root doc 1`] = ` +{ + "blocks": [ + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blockId": "TnUgtVg7Eu", + "content": "Write, Draw, Plan all at Once.", + "docId": "test-doc", + "flavour": "affine:page", + "yblock": { + "prop:title": "Write, Draw, Plan all at Once.", + "sys:children": [ + "RX4CG2zsBk", + "S1mkc8zUoU", + "yGlBdshAqN", + "6lDiuDqZGL", + "cauvaHOQmh", + "2jwCeO8Yot", + "c9MF_JiRgx", + "6x7ALjUDjj", + ], + "sys:flavour": "affine:page", + "sys:id": "TnUgtVg7Eu", + "sys:version": 2, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "FoPQcAyV_m", + "content": "AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. ", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. ", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "FoPQcAyV_m", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "oz48nn_zp8", + "content": "", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "oz48nn_zp8", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "g8a-D9-jXS", + "content": "You own your data, with no compromises", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "You own your data, with no compromises", + "prop:type": "h1", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "g8a-D9-jXS", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "J8lHN1GR_5", + "content": "Local-first & Real-time collaborative", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Local-first & Real-time collaborative", + "prop:type": "h2", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "J8lHN1GR_5", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "xCuWdM0VLz", + "content": "We love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "We love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "xCuWdM0VLz", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "zElMi0tViK", + "content": "AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "zElMi0tViK", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "RX4CG2zsBk", + }, + "blockId": "Z4rK0OF9Wk", + "content": "", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "RX4CG2zsBk", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "Z4rK0OF9Wk", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "S1mkc8zUoU", + }, + "blockId": "DQ0Ryb-SpW", + "content": "Blocks that assemble your next docs, tasks kanban or whiteboard", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "S1mkc8zUoU", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Blocks that assemble your next docs, tasks kanban or whiteboard", + "prop:type": "h3", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "DQ0Ryb-SpW", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "yGlBdshAqN", + }, + "blockId": "HAZC3URZp_", + "content": "There is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. ", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "yGlBdshAqN", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "There is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. ", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "HAZC3URZp_", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "yGlBdshAqN", + }, + "blockId": "0H87ypiuv8", + "content": "We are building AFFiNE to be a fundamental open source platform that contains all the building blocks for docs, task management and visual collaboration, hoping you can shape your next workflow with us that can make your life better and also connect others, too.", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "yGlBdshAqN", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "We are building AFFiNE to be a fundamental open source platform that contains all the building blocks for docs, task management and visual collaboration, hoping you can shape your next workflow with us that can make your life better and also connect others, too.", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "0H87ypiuv8", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "yGlBdshAqN", + }, + "blockId": "Sp4G1KD0Wn", + "content": "If you want to learn more about the product design of AFFiNE, here goes the concepts:", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "yGlBdshAqN", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "If you want to learn more about the product design of AFFiNE, here goes the concepts:", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "Sp4G1KD0Wn", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "yGlBdshAqN", + }, + "blockId": "RsUhDuEqXa", + "content": "To Shape, not to adapt. AFFiNE is built for individuals & teams who care about their data, who refuse vendor lock-in, and who want to have control over their essential tools.", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "yGlBdshAqN", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "To Shape, not to adapt. AFFiNE is built for individuals & teams who care about their data, who refuse vendor lock-in, and who want to have control over their essential tools.", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "RsUhDuEqXa", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "Z2HibKzAr-", + "content": "A true canvas for blocks in any form", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "A true canvas for blocks in any form", + "prop:type": "h2", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "Z2HibKzAr-", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "UwvWddamzM", + "content": "Many editor apps claimed to be a canvas for productivity. Since the Mother of All Demos, Douglas Engelbart, a creative and programable digital workspace has been a pursuit and an ultimate mission for generations of tool makers. ", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Many editor apps claimed to be a canvas for productivity. Since the Mother of All Demos, Douglas Engelbart, a creative and programable digital workspace has been a pursuit and an ultimate mission for generations of tool makers. ", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "UwvWddamzM", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "g9xKUjhJj1", + "content": "", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "g9xKUjhJj1", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "wDTn4YJ4pm", + "content": ""We shape our tools and thereafter our tools shape us”. A lot of pioneers have inspired us a long the way, e.g.:", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": ""We shape our tools and thereafter our tools shape us”. A lot of pioneers have inspired us a long the way, e.g.:", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "wDTn4YJ4pm", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "xFrrdiP3-V", + "content": "Quip & Notion with their great concept of "everything is a block"", + "docId": "test-doc", + "flavour": "affine:list", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:checked": false, + "prop:collapsed": false, + "prop:order": null, + "prop:text": "Quip & Notion with their great concept of "everything is a block"", + "prop:type": "bulleted", + "sys:children": [], + "sys:flavour": "affine:list", + "sys:id": "xFrrdiP3-V", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "Tp9xyN4Okl", + "content": "Trello with their Kanban", + "docId": "test-doc", + "flavour": "affine:list", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:checked": false, + "prop:collapsed": false, + "prop:order": null, + "prop:text": "Trello with their Kanban", + "prop:type": "bulleted", + "sys:children": [], + "sys:flavour": "affine:list", + "sys:id": "Tp9xyN4Okl", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "K_4hUzKZFQ", + "content": "Airtable & Miro with their no-code programable datasheets", + "docId": "test-doc", + "flavour": "affine:list", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:checked": false, + "prop:collapsed": false, + "prop:order": null, + "prop:text": "Airtable & Miro with their no-code programable datasheets", + "prop:type": "bulleted", + "sys:children": [], + "sys:flavour": "affine:list", + "sys:id": "K_4hUzKZFQ", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "QwMzON2s7x", + "content": "Miro & Whimiscal with their edgeless visual whiteboard", + "docId": "test-doc", + "flavour": "affine:list", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:checked": false, + "prop:collapsed": false, + "prop:order": null, + "prop:text": "Miro & Whimiscal with their edgeless visual whiteboard", + "prop:type": "bulleted", + "sys:children": [], + "sys:flavour": "affine:list", + "sys:id": "QwMzON2s7x", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "6lDiuDqZGL", + }, + "blockId": "FFVmit6u1T", + "content": "Remnote & Capacities with their object-based tag system", + "docId": "test-doc", + "flavour": "affine:list", + "parentBlockId": "6lDiuDqZGL", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:checked": false, + "prop:collapsed": false, + "prop:order": null, + "prop:text": "Remnote & Capacities with their object-based tag system", + "prop:type": "bulleted", + "sys:children": [], + "sys:flavour": "affine:list", + "sys:id": "FFVmit6u1T", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "cauvaHOQmh", + }, + "blockId": "YqnG5O6AE6", + "content": "For more details, please refer to our RoadMap", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "cauvaHOQmh", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "For more details, please refer to our RoadMap", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "YqnG5O6AE6", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "cauvaHOQmh", + }, + "blockId": "sbDTmZMZcq", + "content": "Self Host", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "cauvaHOQmh", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Self Host", + "prop:type": "h2", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "sbDTmZMZcq", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "cauvaHOQmh", + }, + "blockId": "QVvitesfbj", + "content": "Self host AFFiNE", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "cauvaHOQmh", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Self host AFFiNE", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "QVvitesfbj", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "U_GoHFD9At", + "content": [ + "Learning From", + "Title", + "Tag", + "Reference", + "Developers", + "AFFiNE", + ], + "docId": "test-doc", + "flavour": "affine:database", + "yblock": { + "prop:cells": { + "3aMlphe2lp": { + "sC99IAB2x_QM0zaPEj2ow": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "value": [ + "HgHsKOUINZ", + ], + }, + }, + "EkFHpB-mJi": { + "sC99IAB2x_QM0zaPEj2ow": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "value": [ + "HgHsKOUINZ", + ], + }, + }, + "MiZtUig-fL": { + "sC99IAB2x_QM0zaPEj2ow": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "value": [ + "HgHsKOUINZ", + ], + }, + }, + "Q6LnVyKoGS": { + "sC99IAB2x_QM0zaPEj2ow": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "value": [ + "HgHsKOUINZ", + ], + }, + }, + "VMx9lHw3TR": { + "sC99IAB2x_QM0zaPEj2ow": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "value": [ + "0jh9gNw4Yl", + ], + }, + }, + "tpyOZbPc1P": { + "sC99IAB2x_QM0zaPEj2ow": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "value": [ + "AxSe-53xjX", + ], + }, + }, + }, + "prop:columns": [ + { + "data": {}, + "id": "clNriIlPoh", + "type": "title", + }, + { + "data": {}, + "id": "tEvV9x-oBP3m4MwVyFH1Z", + "name": "Title", + "type": "title", + }, + { + "data": { + "options": [ + { + "color": "var(--affine-tag-blue)", + "id": "HgHsKOUINZ", + "value": "Reference", + }, + { + "color": "var(--affine-tag-orange)", + "id": "0jh9gNw4Yl", + "value": "Developers", + }, + { + "color": "var(--affine-tag-pink)", + "id": "AxSe-53xjX", + "value": "AFFiNE", + }, + ], + }, + "id": "sC99IAB2x_QM0zaPEj2ow", + "name": "Tag", + "type": "multi-select", + }, + ], + "prop:title": "Learning From", + "prop:views": [ + { + "columns": [ + { + "id": "clNriIlPoh", + }, + ], + "filter": { + "conditions": [], + "op": "and", + "type": "group", + }, + "header": { + "iconColumn": "type", + "titleColumn": "tEvV9x-oBP3m4MwVyFH1Z", + }, + "id": "Gt8Hbz0vBy33WSl58VH2Y", + "mode": "table", + "name": "Table View", + }, + { + "columns": [ + { + "hide": false, + "id": "tEvV9x-oBP3m4MwVyFH1Z", + }, + { + "hide": false, + "id": "sC99IAB2x_QM0zaPEj2ow", + }, + ], + "filter": { + "conditions": [], + "op": "and", + "type": "group", + }, + "groupBy": { + "columnId": "sC99IAB2x_QM0zaPEj2ow", + "name": "multi-select", + "type": "groupBy", + }, + "groupProperties": [], + "header": { + "iconColumn": "type", + "titleColumn": "tEvV9x-oBP3m4MwVyFH1Z", + }, + "id": "43eIk3skKQWFlamyg8IIn", + "mode": "kanban", + "name": "Kanban View", + }, + ], + "sys:children": [ + "tpyOZbPc1P", + "VMx9lHw3TR", + "Q6LnVyKoGS", + "EkFHpB-mJi", + "3aMlphe2lp", + "MiZtUig-fL", + "erYE2C7cc5", + ], + "sys:flavour": "affine:database", + "sys:id": "U_GoHFD9At", + "sys:version": 3, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "tpyOZbPc1P", + "content": "Affine Development", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Affine Development", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "tpyOZbPc1P", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "VMx9lHw3TR", + "content": "For developers or installations guides, please go to AFFiNE Doc", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "For developers or installations guides, please go to AFFiNE Doc", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "VMx9lHw3TR", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "Q6LnVyKoGS", + "content": "Quip & Notion with their great concept of "everything is a block"", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Quip & Notion with their great concept of "everything is a block"", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "Q6LnVyKoGS", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "EkFHpB-mJi", + "content": "Trello with their Kanban", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Trello with their Kanban", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "EkFHpB-mJi", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "3aMlphe2lp", + "content": "Airtable & Miro with their no-code programable datasheets", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Airtable & Miro with their no-code programable datasheets", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "3aMlphe2lp", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "MiZtUig-fL", + "content": "Miro & Whimiscal with their edgeless visual whiteboard", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Miro & Whimiscal with their edgeless visual whiteboard", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "MiZtUig-fL", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": "Learning From", + "displayMode": "page", + "noteBlockId": "2jwCeO8Yot", + }, + "blockId": "erYE2C7cc5", + "content": "Remnote & Capacities with their object-based tag system", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "U_GoHFD9At", + "parentFlavour": "affine:database", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Remnote & Capacities with their object-based tag system", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "erYE2C7cc5", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "c9MF_JiRgx", + }, + "blockId": "NyHXrMX3R1", + "content": "Affine Development", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "c9MF_JiRgx", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "Affine Development", + "prop:type": "h2", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "NyHXrMX3R1", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "c9MF_JiRgx", + }, + "blockId": "9-K49otbCv", + "content": "For developer or installation guides, please go to AFFiNE Development", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "c9MF_JiRgx", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "For developer or installation guides, please go to AFFiNE Development", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "9-K49otbCv", + "sys:version": 1, + }, + }, + { + "additional": { + "databaseName": undefined, + "displayMode": "page", + "noteBlockId": "c9MF_JiRgx", + }, + "blockId": "faFteK9eG-", + "content": "", + "docId": "test-doc", + "flavour": "affine:paragraph", + "parentBlockId": "c9MF_JiRgx", + "parentFlavour": "affine:note", + "ref": [], + "refDocId": [], + "yblock": { + "prop:collapsed": false, + "prop:text": "", + "prop:type": "text", + "sys:children": [], + "sys:flavour": "affine:paragraph", + "sys:id": "faFteK9eG-", + "sys:version": 1, + }, + }, + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blockId": "6x7ALjUDjj", + "content": [ + "What is AFFiNE", + "Related Articles", + " ", + "Self-host", + "", + "AFFiNE ", + "Development", + "You can check these URLs to learn about AFFiNE", + "Database Reference", + ], + "docId": "test-doc", + "flavour": "affine:surface", + "parentBlockId": "TnUgtVg7Eu", + "parentFlavour": "affine:page", + "yblock": { + "prop:elements": { + "type": "$blocksuite:internal:native$", + "value": { + "EkqQL1MU5m": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:OrelegaOne", + "fontSize": 120, + "fontStyle": "normal", + "fontWeight": "400", + "hasMaxWidth": true, + "id": "EkqQL1MU5m", + "index": "aXd", + "rotate": 0, + "seed": 1588752895, + "text": "Self-host", + "textAlign": "left", + "type": "text", + "xywh": "[988.4153663986212,-181.71961053807448,563,168.75]", + }, + "F-GXtb8ubm": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:Lora", + "fontSize": 72, + "fontStyle": "normal", + "fontWeight": "600", + "hasMaxWidth": true, + "id": "F-GXtb8ubm", + "index": "ag", + "rotate": 0, + "seed": 1394803222, + "text": "Database Reference", + "textAlign": "left", + "type": "text", + "xywh": "[-183.35234372014293,-333.83661977719123,744.8157214875225,92]", + }, + "GVPdqrq6T6": { + "children": { + "JlgVJdWU12": true, + "R2MK4ZzUb3": true, + }, + "id": "GVPdqrq6T6", + "index": "a0", + "seed": 771020267, + "title": "Group 6", + "type": "group", + "xywh": "[126.65897893082821,-2338.7483936405356,2375.5289713541665,722.5748697916665]", + }, + "Gwb4ZjdyMJ": { + "children": { + "6lDiuDqZGL": true, + "RX4CG2zsBk": true, + "istDk5DOMO": true, + "saGXC7nPOk": true, + "yGlBdshAqN": true, + }, + "id": "Gwb4ZjdyMJ", + "index": "aN", + "seed": 242073567, + "title": "Group 3", + "type": "group", + }, + "LHh9XjyG9P": { + "controllers": [], + "frontEndpointStyle": "None", + "id": "LHh9XjyG9P", + "index": "ae", + "mode": 2, + "rearEndpointStyle": "Arrow", + "rough": false, + "roughness": 1.4, + "seed": 962796410, + "source": { + "id": "istDk5DOMO", + "position": [ + -6.164088349722365e-17, + 0.5, + ], + }, + "stroke": "--affine-palette-line-grey", + "strokeStyle": "solid", + "strokeWidth": 8, + "target": { + "id": "ECrtbvW6xx", + "position": [ + 1, + 0.5000000000000001, + ], + }, + "type": "connector", + }, + "Nb_9OXyIT3": { + "fillColor": "--affine-palette-shape-yellow", + "filled": true, + "id": "Nb_9OXyIT3", + "index": "a0", + "radius": 0, + "rotate": 0, + "roughness": 1.4, + "seed": 97408177, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-line-yellow", + "strokeStyle": "solid", + "strokeWidth": 4, + "type": "shape", + "xywh": "[2403.9004515323168,57.24116579067933,955.1393577008388,542.1082071559455]", + }, + "R2MK4ZzUb3": { + "color": "--affine-palette-line-black", + "fillColor": "--affine-palette-shape-white", + "filled": true, + "id": "R2MK4ZzUb3", + "index": "a0", + "radius": 0, + "rotate": 0, + "roughness": 1.4, + "seed": 1558899337, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-transparent", + "strokeStyle": "solid", + "strokeWidth": 2, + "type": "shape", + "xywh": "[126.65897893082821,-2338.7483936405356,2375.5289713541665,722.5748697916666]", + }, + "TRRWjtvWJm": { + "children": { + "5W--UQLN11": true, + "lcZphIJe63": true, + }, + "id": "TRRWjtvWJm", + "index": "a4", + "seed": 1624205143, + "title": "Group 1", + "type": "group", + "xywh": "[-1043.6169874048903,-641.7901035486665,622.6248931928226,667.0980998494529]", + }, + "UloPoCxt6P": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:OrelegaOne", + "fontSize": 128, + "fontStyle": "normal", + "fontWeight": "400", + "hasMaxWidth": false, + "id": "UloPoCxt6P", + "index": "aTl", + "rotate": 0, + "seed": 606071663, + "text": " ", + "textAlign": "left", + "type": "text", + "xywh": "[2522.7441912768363,-1310.8328787672467,35,128]", + }, + "XWYKw-kpYn": { + "children": { + "EkqQL1MU5m": true, + "cauvaHOQmh": true, + "qRCk-vrGXw": true, + }, + "id": "XWYKw-kpYn", + "index": "aZ", + "seed": 1740232717, + "title": "Group 4", + "type": "group", + }, + "YWOfr8Pprg": { + "children": { + "2jwCeO8Yot": true, + "F-GXtb8ubm": true, + }, + "id": "YWOfr8Pprg", + "index": "aj", + "seed": 484840749, + "title": "Group 5", + "type": "group", + }, + "Z7D3qrSurD": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:OrelegaOne", + "fontSize": 120, + "fontStyle": "normal", + "fontWeight": "400", + "hasMaxWidth": false, + "id": "Z7D3qrSurD", + "index": "aTV", + "rotate": 0, + "seed": 2100869690, + "text": "Related Articles", + "textAlign": "left", + "type": "text", + "xywh": "[2478.972284676839,-1231.0379248118952,879.4798583984375,168.75]", + }, + "_nC65-wkSP": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:OrelegaOne", + "fontSize": 128, + "fontStyle": "normal", + "fontWeight": "400", + "hasMaxWidth": true, + "id": "_nC65-wkSP", + "index": "aa", + "rotate": 0, + "seed": 994394416, + "text": "AFFiNE ", + "textAlign": "left", + "type": "text", + "xywh": "[2459.953125798208,88.108859492537,779,147]", + }, + "f3x6HbuyUQ": { + "controllers": [], + "frontEndpointStyle": "None", + "id": "f3x6HbuyUQ", + "index": "aY", + "mode": 2, + "rearEndpointStyle": "Arrow", + "rough": false, + "roughness": 1.4, + "seed": 668321843, + "source": { + "id": "uzfdAcEDxu", + "position": [ + 0.4999999999993948, + 1.0000000000000002, + ], + }, + "stroke": "--affine-palette-line-grey", + "strokeStyle": "solid", + "strokeWidth": 8, + "target": { + "id": "qRCk-vrGXw", + "position": [ + 1.0000000000000002, + 0.5, + ], + }, + "type": "connector", + }, + "gPvT0nfbcw": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:OrelegaOne", + "fontSize": 128, + "fontStyle": "normal", + "fontWeight": "400", + "hasMaxWidth": true, + "id": "gPvT0nfbcw", + "index": "ab", + "rotate": 0, + "seed": 183687274, + "text": "Development", + "textAlign": "left", + "type": "text", + "xywh": "[2459.953125798208,208.4260321250699,779,147]", + }, + "hLAqby4WpD": { + "color": "--affine-palette-line-black", + "fillColor": "--affine-palette-shape-white", + "filled": true, + "id": "hLAqby4WpD", + "index": "Zz", + "radius": 0, + "rotate": 0, + "roughness": 1.4, + "seed": 2025695507, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-transparent", + "strokeStyle": "solid", + "strokeWidth": 2, + "type": "shape", + "xywh": "[-259.87318248973133,-371.99627945163166,948.0569720935435,876.3267415022492]", + }, + "istDk5DOMO": { + "color": "--affine-palette-line-black", + "fillColor": "--affine-palette-shape-blue", + "filled": true, + "id": "istDk5DOMO", + "index": "aI", + "radius": 0, + "rotate": 0, + "roughness": 1.4, + "seed": 858601929, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-transparent", + "strokeStyle": "solid", + "strokeWidth": 4, + "type": "shape", + "xywh": "[353.84627540373367,-1532.740227539313,1844.3414706529402,1139.4642574172829]", + }, + "laVEftUZ5b": { + "children": { + "47g7sBvNVTS0tJaSnY3n2": true, + "Nb_9OXyIT3": true, + "_nC65-wkSP": true, + "gPvT0nfbcw": true, + }, + "id": "laVEftUZ5b", + "index": "ac", + "seed": 1549109555, + "title": "Group 5", + "type": "group", + }, + "mK-9EA5g4c": { + "controllers": [], + "frontEndpointStyle": "None", + "id": "mK-9EA5g4c", + "index": "ai", + "mode": 2, + "rearEndpointStyle": "Arrow", + "rough": false, + "roughness": 1.4, + "seed": 1095574431, + "source": { + "id": "qRCk-vrGXw", + "position": [ + 0, + 0.5, + ], + }, + "stroke": "--affine-palette-line-grey", + "strokeStyle": "solid", + "strokeWidth": 8, + "target": { + "id": "2jwCeO8Yot", + }, + "type": "connector", + }, + "qRCk-vrGXw": { + "color": "--affine-palette-line-black", + "fillColor": "--affine-palette-shape-magenta", + "filled": true, + "fontFamily": "blocksuite:surface:Inter", + "id": "qRCk-vrGXw", + "index": "aXG", + "radius": 0, + "rotate": 0, + "roughness": 1.4, + "seed": 2015167989, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-transparent", + "strokeStyle": "solid", + "strokeWidth": 4, + "text": "", + "type": "shape", + "xywh": "[928.4478756397534,-248.78447101666404,943.70584160216,514.081347775151]", + }, + "sNDFCBEYzR": { + "controllers": [], + "frontEndpointStyle": "None", + "id": "sNDFCBEYzR", + "index": "af", + "mode": 2, + "rearEndpointStyle": "Arrow", + "rough": false, + "roughness": 1.4, + "seed": 524593855, + "source": { + "id": "istDk5DOMO", + "position": [ + -6.164088349722365e-17, + 0.5, + ], + }, + "stroke": "--affine-palette-line-grey", + "strokeStyle": "solid", + "strokeWidth": 8, + "target": { + "id": "5W--UQLN11", + }, + "type": "connector", + }, + "saGXC7nPOk": { + "color": "--affine-palette-line-black", + "fontFamily": "blocksuite:surface:OrelegaOne", + "fontSize": 128, + "fontStyle": "normal", + "fontWeight": "400", + "hasMaxWidth": false, + "id": "saGXC7nPOk", + "index": "aJ", + "rotate": 0, + "seed": 93054478, + "text": "What is AFFiNE", + "textAlign": "left", + "type": "text", + "xywh": "[438.73809335123497,-1467.165331669401,913.75,128]", + }, + "t3Rt_B2IAr": { + "controllers": [], + "frontEndpointStyle": "None", + "id": "t3Rt_B2IAr", + "index": "ad", + "mode": 2, + "rearEndpointStyle": "Arrow", + "rough": false, + "roughness": 1.4, + "seed": 306364128, + "source": { + "id": "qRCk-vrGXw", + "position": [ + 1, + 0.5, + ], + }, + "stroke": "--affine-palette-line-grey", + "strokeStyle": "solid", + "strokeWidth": 8, + "target": { + "id": "Nb_9OXyIT3", + }, + "type": "connector", + }, + "tCpJR12_hu": { + "controllers": [], + "frontEndpointStyle": "None", + "id": "tCpJR12_hu", + "index": "aW", + "mode": 2, + "rearEndpointStyle": "Arrow", + "rough": false, + "roughness": 1.4, + "seed": 1310217918, + "source": { + "id": "istDk5DOMO", + "position": [ + 0.9999999999999999, + 0.5, + ], + }, + "stroke": "--affine-palette-line-grey", + "strokeStyle": "solid", + "strokeWidth": 8, + "target": { + "id": "uzfdAcEDxu", + }, + "type": "connector", + }, + "uzfdAcEDxu": { + "color": "--affine-palette-line-black", + "fillColor": "--affine-palette-shape-purple", + "filled": true, + "id": "uzfdAcEDxu", + "index": "aTG", + "radius": 0, + "rotate": 0.062196392871315495, + "roughness": 1.4, + "seed": 462401908, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-transparent", + "strokeStyle": "solid", + "strokeWidth": 4, + "type": "shape", + "xywh": "[2421.751354148884,-1283.6175127158676,1085.7995880501803,519.0294552479265]", + }, + "w86OKmzMtn": { + "color": "--affine-palette-line-black", + "fillColor": "--affine-palette-shape-tangerine", + "filled": true, + "fontFamily": "blocksuite:surface:Poppins", + "fontSize": 36, + "fontStyle": "normal", + "fontWeight": "600", + "id": "w86OKmzMtn", + "index": "ad", + "radius": 0, + "rotate": 0, + "roughness": 1.4, + "seed": 1298533711, + "shapeStyle": "General", + "shapeType": "rect", + "strokeColor": "--affine-palette-transparent", + "strokeStyle": "solid", + "strokeWidth": 4, + "text": "You can check these URLs to learn about AFFiNE", + "textAlign": "left", + "type": "shape", + "xywh": "[-1055.7017064945487,-981.0008617000956,702.1470991695091,295.7649942194072]", + }, + }, + }, + "sys:children": [ + "ECrtbvW6xx", + "5W--UQLN11", + "lcZphIJe63", + "JlgVJdWU12", + "lht7AqBqnF", + ], + "sys:flavour": "affine:surface", + "sys:id": "6x7ALjUDjj", + "sys:version": 5, + }, + }, + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blockId": "ECrtbvW6xx", + "docId": "test-doc", + "flavour": "affine:bookmark", + "yblock": { + "prop:caption": null, + "prop:description": "The universal editor that lets you work, play, present or create just about anything.", + "prop:icon": "/favicon-96.png", + "prop:image": "https://affine.pro/og.png", + "prop:index": "a1", + "prop:lockedBySelf": false, + "prop:rotate": 0, + "prop:style": "vertical", + "prop:title": "AFFiNE - All In One KnowledgeOS", + "prop:url": "https://affine.pro/", + "prop:xywh": "[-605.1053721621553,-1497.696057920688,606.4771127476911,649.7969065153833]", + "sys:children": [], + "sys:flavour": "affine:bookmark", + "sys:id": "ECrtbvW6xx", + "sys:version": 1, + }, + }, + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blockId": "5W--UQLN11", + "docId": "test-doc", + "flavour": "affine:bookmark", + "yblock": { + "prop:caption": null, + "prop:description": "AFFiNE is the all-in-one workspace where you can write, draw and plan just about anything - Blend the power of Notion and Miro to enable dynamic note-taking, wikis, tasks, visualized mindmaps and presentations. All you need for productivity and creativity is here! +", + "prop:icon": "https://www.youtube.com/s/desktop/8b6c1f4c/img/favicon_32x32.png", + "prop:image": "https://yt3.googleusercontent.com/H9-Rol_TUq4UmR8cdy-LhxFmWdmz5LIm_KTYoVP2D81I-w9T12ttJHfME6kWUnEresNVo4c8dA=s900-c-k-c0x00ffffff-no-rj", + "prop:index": "a2", + "prop:lockedBySelf": false, + "prop:rotate": 0, + "prop:style": "vertical", + "prop:title": "AFFiNE", + "prop:url": "https://www.youtube.com/@affinepro", + "prop:xywh": "[-1043.6169874048903,-641.7901035486665,622.6248931928226,667.0980998494529]", + "sys:children": [], + "sys:flavour": "affine:bookmark", + "sys:id": "5W--UQLN11", + "sys:version": 1, + }, + }, + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blob": [ + "BFZk3c2ERp-sliRvA7MQ_p3NdkdCLt2Ze0DQ9i21dpA=", + ], + "blockId": "lcZphIJe63", + "docId": "test-doc", + "flavour": "affine:image", + "parentBlockId": "6x7ALjUDjj", + "parentFlavour": "affine:surface", + "yblock": { + "prop:caption": "", + "prop:height": 728, + "prop:index": "a3", + "prop:lockedBySelf": false, + "prop:rotate": 0, + "prop:size": 115416, + "prop:sourceId": "BFZk3c2ERp-sliRvA7MQ_p3NdkdCLt2Ze0DQ9i21dpA=", + "prop:width": 1302, + "prop:xywh": "[-991.0766514037751,-616.4591370809392,505.45950210093383,282.62251730374794]", + "sys:children": [], + "sys:flavour": "affine:image", + "sys:id": "lcZphIJe63", + "sys:version": 1, + }, + }, + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blob": [ + "HWvCItS78DzPGbwcuaGcfkpVDUvL98IvH5SIK8-AcL8=", + ], + "blockId": "JlgVJdWU12", + "docId": "test-doc", + "flavour": "affine:image", + "parentBlockId": "6x7ALjUDjj", + "parentFlavour": "affine:surface", + "yblock": { + "prop:caption": "", + "prop:height": 374, + "prop:index": "aj", + "prop:lockedBySelf": false, + "prop:rotate": 0, + "prop:size": 50651, + "prop:sourceId": "HWvCItS78DzPGbwcuaGcfkpVDUvL98IvH5SIK8-AcL8=", + "prop:width": 1463, + "prop:xywh": "[281.13294520744034,-2242.095913253297,2001.7110026018645,511.7155946501006]", + "sys:children": [], + "sys:flavour": "affine:image", + "sys:id": "JlgVJdWU12", + "sys:version": 1, + }, + }, + { + "additional": { + "displayMode": "edgeless", + "noteBlockId": undefined, + }, + "blob": [ + "ZRKpsBoC88qEMmeiXKXqywfA1rLvWoLa5rpEh9x9Oj0=", + ], + "blockId": "lht7AqBqnF", + "docId": "test-doc", + "flavour": "affine:image", + "parentBlockId": "6x7ALjUDjj", + "parentFlavour": "affine:surface", + "yblock": { + "prop:caption": "", + "prop:height": 1388, + "prop:index": "acV", + "prop:lockedBySelf": false, + "prop:rotate": 10.938230891828395, + "prop:size": 71614, + "prop:sourceId": "ZRKpsBoC88qEMmeiXKXqywfA1rLvWoLa5rpEh9x9Oj0=", + "prop:width": 862, + "prop:xywh": "[3446.6044934637607,-1339.9783466050073,122.45568062094182,197.1792165914935]", + "sys:children": [], + "sys:flavour": "affine:image", + "sys:id": "lht7AqBqnF", + "sys:version": 1, + }, + }, + ], + "summary": "AFFiNE is an open source all in one workspace, an operating system for all the building blocks of your team wiki, knowledge management and digital assets and a better alternative to Notion and Miro. You own your data, with no compromisesLocal-first & Real-time collaborativeWe love the idea proposed by Ink & Switch in the famous article about you owning your data, despite the cloud. Furthermore, AFFiNE is the first all-in-one workspace that keeps your data ownership with no compromises on real-time collaboration and editing experience.AFFiNE is a local-first application upon CRDTs with real-time collaboration support. Your data is always stored locally while multiple nodes remain synced in real-time.Blocks that assemble your next docs, tasks kanban or whiteboardThere is a large overlap of their atomic "building blocks" between these apps. They are neither open source nor have a plugin system like VS Code for contributors to customize. We want to have something that contains all the features we love and goes one step further. ", + "title": "Write, Draw, Plan all at Once.", +} +`; diff --git a/packages/common/reader/__tests__/reader.spec.ts b/packages/common/reader/__tests__/reader.spec.ts index bdfa56d7f5..7a91ce122a 100644 --- a/packages/common/reader/__tests__/reader.spec.ts +++ b/packages/common/reader/__tests__/reader.spec.ts @@ -35,6 +35,18 @@ test('should read doc blocks work', async () => { expect(result).toMatchSnapshot(); }); +test('should read doc blocks work without root doc', async () => { + const doc = new YDoc({ + guid: 'test-doc', + }); + applyUpdate(doc, docSnapshot); + const result = await readAllBlocksFromDoc({ + ydoc: doc, + spaceId: 'test-space', + }); + expect(result).toMatchSnapshot(); +}); + test('should get all docs from root doc work', async () => { const rootDoc = new YDoc({ guid: 'test-root-doc', diff --git a/packages/common/reader/src/reader.ts b/packages/common/reader/src/reader.ts index 888125289e..dd2973f754 100644 --- a/packages/common/reader/src/reader.ts +++ b/packages/common/reader/src/reader.ts @@ -59,9 +59,9 @@ const bookmarkFlavours = new Set([ ]); function generateMarkdownPreviewBuilder( - yRootDoc: YDoc, workspaceId: string, - blocks: BlockDocumentInfo[] + blocks: BlockDocumentInfo[], + yRootDoc?: YDoc ) { function yblockToDraftModal(yblock: YBlock): DraftModel | null { const flavour = yblock.get('sys:flavour') as string; @@ -91,7 +91,7 @@ function generateMarkdownPreviewBuilder( } const titleMiddleware: TransformerMiddleware = ({ adapterConfigs }) => { - const pages = yRootDoc.getMap('meta').get('pages'); + const pages = yRootDoc?.getMap('meta').get('pages'); if (!(pages instanceof YArray)) { return; } @@ -442,7 +442,7 @@ export async function readAllBlocksFromDoc({ maxSummaryLength, }: { ydoc: YDoc; - rootYDoc: YDoc; + rootYDoc?: YDoc; spaceId: string; maxSummaryLength?: number; }): Promise< @@ -459,9 +459,9 @@ export async function readAllBlocksFromDoc({ const blockDocuments: BlockDocumentInfo[] = []; const generateMarkdownPreview = generateMarkdownPreviewBuilder( - rootYDoc, spaceId, - blockDocuments + blockDocuments, + rootYDoc ); const blocks = ydoc.getMap('blocks');