diff --git a/README.md b/README.md
index 19e0db1307..b2507efa5b 100644
--- a/README.md
+++ b/README.md
@@ -2,12 +2,13 @@
AFFiNE.PRO
- The Next-Gen Knowledge Base to Replace Notion & Miro.
+ The Next-Gen Collaborative Knowledge Base
-Planning, Sorting and Creating all Together. Open-source, Privacy-First, and Free to use.
+Open-source and privacy-first.
+A free replacement for Notion & Miro.
@@ -22,9 +23,10 @@ See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066
-[](https://affine.pro)
+[](https://livedemo.affine.pro)
[](https://github.com/toeverything/AFFiNE)
[![All Contributors][all-contributors-badge]](#contributors)
+
[](https://www.typescriptlang.org/)
[](https://www.typescriptlang.org/)
[](https://reactjs.org/)
@@ -35,11 +37,11 @@ See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066
-
+
-
+
-
+
@@ -48,100 +50,53 @@ See https://github.com/all-?/all-contributors/issues/361#issuecomment-637166066

-# Stay Up-to-Date and Support Us
+# :star: Support Us and Keep Updated :star:

-# How to use
+# Getting Started
-
-🥳🥳🥳 Our web live demo is ready! 🥳🥳🥳
-
+[](https://affine.pro) No installation or registration required! Head over to our website and try it out now.
-
-Start to play with AFFiNE web version on our landing page:
-
-
-
-
-
-
-If you have experience in front-end development, you may wish to refer to our [documentation](https://docs.affine.pro/affine/basic-documentation/contribute-to-affine) to learn more about deploying your own version or contributing further to development.
-Also, thanks to Lee who has made a [desktop build with Tauri](https://github.com/m1911star/affine-client) for you to try out.
-Please notice that AFFiNE is still under Alpha stage and is not ready for production use.
-
-# Table of contents
-
-- [Stay Up-to-Date and Support Us](#stay-up-to-date-and-support-us)
-- [How to Use](#how-to-use)
-- [Table of contents](#table-of-contents)
- - [Shape your page](#shape-your-page)
- - [Plan your task](#plan-your-task)
- - [Sort your knowledge](#sort-your-knowledge)
- - [Create your story](#create-your-story)
-- [Documentation](#documentation)
- - [Getting Started with development](#getting-started-with-development)
-- [Roadmap](#roadmap)
-- [Releases](#releases)
-- [Feature requests](#feature-requests)
-- [FAQ](#faq)
-- [The Philosophy of AFFiNE](#the-philosophy-of-affine)
-- [Community](#community)
-- [Contributors](#contributors)
-- [Acknowledgments](#acknowledgments)
-- [License](#license)
-
-## Shape your page
-
-
-
-## Plan your task
-
-
-
-## Sort your knowledge
-
-
+Want to deploy it yourself? AFFiNE can run just about anywhere. Check our
+[documentation](#documentation)
+for more information.
+
+⚠️ Please note that AFFiNE is still under active development and is not yet ready for production use. ⚠️
## Create your story
-We want your data always to be yours, without any sacrifice to your accessibility. Your data is always stored local first, yet we support real-time collaboration on a peer-to-peer basis. We don't think "privacy-first" is a good excuse for not supporting modern web features.
-And when it comes to collaboration, these features are not just necessarily for teams -- you can take and insert pictures on your phone, edit them from your desktop, and then share them with your collaborators.
-Affine is fully built with web technologies to ensure consistency and accessibility on Mac, Windows and Linux. The local file system support will be available when version 0.0.1beta is released.
+There can be more than Notion and Miro. AFFiNE is a next-gen knowledge base that brings planning, sorting and creating all together. Privacy first, open-source, customizable and ready to use, built with web technologies to ensure consistency and accessibility on Mac, Windows and Linux. We want your data always to be yours, without any sacrifice to your accessibility. Your data is always stored local first, with full support for real-time collaboration through peer-to-peer technology. We don't think "privacy-first" is a good excuse for not supporting modern web features.
+And when it comes to collaboration, these features are not just necessarily for teams - you can take and insert pictures on your phone, edit them from your desktop, and then share them with your collaborators.
-# Documentation
+### Shape your page
-AFFiNE is not yet ready for production use. For installation, you may check how to build or deploy AFFiNE from our [quick-start](https://docs.affine.pro/affine/basic-documentation/contribute-to-affine/quick-start) guide. Alternatively, you can view our [full documentation](https://docs.affine.pro/affine/).
+
-## Getting Started with development
+### Plan your task
-Please view the path Contribute-to-AFFiNE/Software-Contributions/Quick-Start in the documentation.
+
-# Roadmap
+### Sort your knowledge
-Yes! Permanent storage, collaboration, stable release is planned! Check it [here](https://github.com/toeverything/AFFiNE/issues/293)
+
-# Releases
+# Useful Links
-Get our latest [release notes](https://github.com/toeverything/AFFiNE/wiki) from here.
+- [AFFiNE Documentation](https://docs.affine.pro/affine/) - More detailed documentation on how to use and develop with AFFiNE
-# Feature requests
+- [Feature Roadmap](https://github.com/toeverything/AFFiNE/issues/293) - Looking for a feature? It might already be planned for release - you can check here
+- [Release Notes](https://github.com/toeverything/AFFiNE/wiki) - Find out what changes we are making and how we are improving AFFiNE
-Please go to [feature requests](https://github.com/toeverything/AFFiNE/issues).
+- [Contributing Guide](/docs/CONTRIBUTING.md) - Want to help improve AFFiNE? You might not even need to write a line of code. Find out how you can contribute.
+- [Code of Conduct](/docs/CODE_OF_CONDUCT.md) - How we promote and maintain a harassment-free experience for everyone in our community.
-# FAQ
-
-Get quick help on [Telegram](https://t.me/affineworkos) or [Discord](https://discord.gg/yz6tGVsf5p) and join our community of developers and contributors.
-
-Our latest news can be found on [Twitter](https://twitter.com/AffineOfficial), [Medium](https://medium.com/@affineworkos) and the [AFFiNE Blog](https://blog.affine.pro/).
+- AFFiNE Communities: [Discord](https://discord.gg/yz6tGVsf5p) | [Telegram](https://t.me/affineworkos) | [Twitter](https://twitter.com/AffineOfficial) |
+ [Medium](https://medium.com/@affineworkos) | [AFFiNE Blog](https://blog.affine.pro)
# Contact Us
-You may contact us by emailing to: contact@toeverything.info
+Feel free to send us an email: contact@toeverything.info
# The Philosophy of AFFiNE
@@ -186,12 +141,6 @@ We would also like to give thanks to open-source projects that make affine possi
Thanks a lot to the community for providing such powerful and simple libraries, so that we can focus more on the implementation of the product logic, and we hope that in the future our projects will also provide a more easy-to-use knowledge base for everyone.
-# Community
-
-For help, discussion about best practices, or any other conversation that would benefit from being searchable:
-
-[Discuss AFFiNE on GitHub](https://github.com/toeverything/AFFiNE/discussions)
-
# Contributors
@@ -250,4 +199,4 @@ For help, discussion about best practices, or any other conversation that would
AFFiNE is distributed under the terms of MIT license.
-See LICENSE for details.
+See [LICENSE](/LICENSE) for details.
diff --git a/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md
similarity index 100%
rename from CODE_OF_CONDUCT.md
rename to docs/CODE_OF_CONDUCT.md
diff --git a/CONTRIBUTING.md b/docs/CONTRIBUTING.md
similarity index 84%
rename from CONTRIBUTING.md
rename to docs/CONTRIBUTING.md
index 7b7b63a1a5..94806e00f8 100644
--- a/CONTRIBUTING.md
+++ b/docs/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-# Welcome to ourcontributing guide
+# Welcome to our contributing guide
Thank you for investing your time in contributing to our project! Any contribution you make will be reflected on our GitHub :sparkles:.
@@ -10,7 +10,7 @@ Use the table of contents icon on the top left corner of this document to get to
## New contributor guide
-To get an overview of the project, read the [README](README.md). Here are some resources to help you get started with open source contributions:
+To get an overview of the project, read the [README](../README.md). Here are some resources to help you get started with open source contributions:
- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github)
- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git)
@@ -19,19 +19,17 @@ To get an overview of the project, read the [README](README.md). Here are some r
## Getting started
-To navigate our codebase with confidence, see [the introduction to working in the docs repository](/contributing/working-in-docs-repository.md) :confetti_ball:. For more information on how we write our markdown files, see [the GitHub Markdown reference](contributing/content-markup-reference.md).
-
-Check to see what [types of contributions](/contributing/types-of-contributions.md) we accept before making changes. Some of them don't even require writing a single line of code :sparkles:.
+Check to see what [types of contributions](types-of-contributions.md) we accept before making changes. Some of them don't even require writing a single line of code :sparkles:.
### Issues
-#### Create a new issue
+#### Create a new issue or feature request
If you spot a problem, [search if an issue already exists](https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests#search-by-the-title-body-or-comments). If a related issue doesn't exist, you can open a new issue using a relevant [issue form](https://github.com/toeverything/AFFiNE/issues/new/choose).
#### Solve an issue
-Scan through our [existing issues](https://github.com/toeverything/AFFiNE/issues) to find one that interests you. You can narrow down the search using `labels` as filters. See [Labels](/contributing/how-to-use-labels.md) for more information. As a general rule, we don’t assign issues to anyone. If you find an issue to work on, you are welcome to open a PR with a fix.
+Scan through our [existing issues](https://github.com/toeverything/AFFiNE/issues) to find one that interests you. You can narrow down the search using `labels` as filters. See our [Labels](https://github.com/toeverything/AFFiNE/labels) for more information. As a general rule, we don’t assign issues to anyone. If you find an issue to work on, you are welcome to open a PR with a fix.
### Make Changes
diff --git a/docs/types-of-contributions.md b/docs/types-of-contributions.md
new file mode 100644
index 0000000000..fd448200e9
--- /dev/null
+++ b/docs/types-of-contributions.md
@@ -0,0 +1,31 @@
+# Types of contributions :memo:
+
+You can contribute to AFFiNE in several ways. This repo is a place to discuss and collaborate on AFFiNE!
+
+### :mega: Discussions
+
+Discussions are where we have conversations.
+
+If you'd like help troubleshooting a docs PR you're working on, have a great new idea, or want to share something amazing you've learned in our docs, join us in [discussions](https://github.com/toeverything/AFFiNE/discussions).
+
+### :lady_beetle: Issues
+
+[Issues](https://docs.github.com/en/github/managing-your-work-on-github/about-issues) are used to track tasks that contributors can help with. If an issue has a triage label, we haven't reviewed it yet, and you shouldn't begin work on it.
+
+If you've found something in the content or the website that should be updated, search open issues to see if someone else has reported the same thing. If it's something new, open an issue using a [template](https://github.com/toeverything/AFFiNE/issues/new/choose). We'll use the issue to have a conversation about the problem you want to fix.
+
+### :hammer_and_wrench: Pull requests
+
+A [pull request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/about-pull-requests) is a way to suggest changes in our repository. When we merge those changes, they should be deployed to the live site within 24 hours. :earth_africa:
+You can [create a new pull request](https://github.com/toeverything/AFFiNE/compare) and view [current pull requests](https://github.com/toeverything/AFFiNE/pulls).
+
+### :question: Support
+
+We are a small team working hard to keep up with the documentation demands of a continuously changing product.
+You may be able to find additional help and information on our social media platforms and groups - the links to these can be found in our [README](../README.md).
+
+### :earth_asia: Translations
+
+AFFiNE is internationalized and available in multiple languages. The source content in this repository is written in English. We integrate with an external localization platform to work with the community in localizing the English content.
+
+**We do not currently offer this feature**, but we hope to in the future.
diff --git a/libs/components/affine-board/src/Board.tsx b/libs/components/affine-board/src/Board.tsx
index af9e8982fe..101d54d37b 100644
--- a/libs/components/affine-board/src/Board.tsx
+++ b/libs/components/affine-board/src/Board.tsx
@@ -134,17 +134,14 @@ const AffineBoard = ({
}
})
);
- let pageBindingsString = (
+ const pageBindingsString = (
await services.api.editorBlock.get({
workspace: workspace,
ids: [rootBlockId],
})
)?.[0].properties.bindings?.value;
- console.log(123123123);
- let pageBindings = JSON.parse(pageBindingsString ?? '{}');
- console.log(pageBindings, 3333, bindings);
+ const pageBindings = JSON.parse(pageBindingsString ?? '{}');
Object.keys(bindings).forEach(bindingsKey => {
- console.log(345345345345345);
if (!bindings[bindingsKey]) {
delete pageBindings[bindingsKey];
} else {
diff --git a/libs/components/board-draw/src/components/tools-panel/LineTools.tsx b/libs/components/board-draw/src/components/tools-panel/LineTools.tsx
index 3ef546ca3c..ce6cb97574 100644
--- a/libs/components/board-draw/src/components/tools-panel/LineTools.tsx
+++ b/libs/components/board-draw/src/components/tools-panel/LineTools.tsx
@@ -35,6 +35,7 @@ const activeToolSelector = (s: TDSnapshot) => s.appState.activeTool;
export const LineTools = ({ app }: { app: TldrawApp }) => {
const activeTool = app.useStore(activeToolSelector);
+ const [visible, setVisible] = useState(false);
const [lastActiveTool, setLastActiveTool] = useState
(
TDShapeType.Line
@@ -51,8 +52,10 @@ export const LineTools = ({ app }: { app: TldrawApp }) => {
return (
setVisible(prev => !prev)}
+ onClickAway={() => setVisible(false)}
content={
{shapes.map(({ type, label, tooltip, icon: Icon }) => (
@@ -60,6 +63,7 @@ export const LineTools = ({ app }: { app: TldrawApp }) => {
{
app.selectTool(type);
+ setVisible(false);
setLastActiveTool(type);
}}
>
diff --git a/libs/components/board-draw/src/components/tools-panel/ShapeTools.tsx b/libs/components/board-draw/src/components/tools-panel/ShapeTools.tsx
index eb2fb5c564..0c04126c95 100644
--- a/libs/components/board-draw/src/components/tools-panel/ShapeTools.tsx
+++ b/libs/components/board-draw/src/components/tools-panel/ShapeTools.tsx
@@ -71,6 +71,7 @@ const activeToolSelector = (s: TDSnapshot) => s.appState.activeTool;
export const ShapeTools = ({ app }: { app: TldrawApp }) => {
const activeTool = app.useStore(activeToolSelector);
+ const [visible, setVisible] = useState(false);
const [lastActiveTool, setLastActiveTool] = useState(
TDShapeType.Rectangle
@@ -87,8 +88,10 @@ export const ShapeTools = ({ app }: { app: TldrawApp }) => {
return (
setVisible(prev => !prev)}
+ onClickAway={() => setVisible(false)}
content={
{shapes.map(({ type, label, tooltip, icon: Icon }) => (
@@ -96,6 +99,7 @@ export const ShapeTools = ({ app }: { app: TldrawApp }) => {
{
app.selectTool(type);
+ setVisible(false);
setLastActiveTool(type);
}}
>
diff --git a/libs/components/board-draw/src/components/tools-panel/ToolsPanel.tsx b/libs/components/board-draw/src/components/tools-panel/ToolsPanel.tsx
index f659fdff1c..82a5315816 100644
--- a/libs/components/board-draw/src/components/tools-panel/ToolsPanel.tsx
+++ b/libs/components/board-draw/src/components/tools-panel/ToolsPanel.tsx
@@ -12,12 +12,12 @@ import {
import {
IconButton,
PopoverContainer,
+ styled,
// MuiIconButton as IconButton,
// MuiTooltip as Tooltip,
Tooltip,
useTheme,
} from '@toeverything/components/ui';
-import style9 from 'style9';
import { TldrawApp } from '@toeverything/components/board-state';
import {
@@ -90,8 +90,8 @@ export const ToolsPanel = ({ app }: { app: TldrawApp }) => {
}}
direction="none"
>
-
-
+
+
{tools.map(
({
type,
@@ -127,24 +127,22 @@ export const ToolsPanel = ({ app }: { app: TldrawApp }) => {
)
)}
-
-
+
+
);
};
-const styles = style9.create({
- container: {
- display: 'flex',
- flexDirection: 'column',
- justifyContent: 'center',
- height: '100%',
- },
- toolBar: {
- display: 'flex',
- flexDirection: 'column',
- backgroundColor: '#ffffff',
- borderRadius: '10px',
- padding: '4px 4px',
- },
+const Container = styled('div')({
+ display: 'flex',
+ flexDirection: 'column',
+ justifyContent: 'center',
+ height: '100%',
+});
+const ToolBar = styled('div')({
+ display: 'flex',
+ flexDirection: 'column',
+ backgroundColor: '#ffffff',
+ borderRadius: '10px',
+ padding: '4px 4px',
});
diff --git a/libs/components/board-draw/src/components/tools-panel/pen-tools/PenTools.tsx b/libs/components/board-draw/src/components/tools-panel/pen-tools/PenTools.tsx
index 0536acfce1..c955afba0d 100644
--- a/libs/components/board-draw/src/components/tools-panel/pen-tools/PenTools.tsx
+++ b/libs/components/board-draw/src/components/tools-panel/pen-tools/PenTools.tsx
@@ -12,7 +12,7 @@ import {
styled,
Tooltip,
} from '@toeverything/components/ui';
-import { ReactElement, type CSSProperties } from 'react';
+import { useState, type CSSProperties, type ReactElement } from 'react';
import { Palette } from '../../palette';
import { Pen } from './Pen';
@@ -106,6 +106,7 @@ const PENCIL_CONFIGS_MAP = PENCIL_CONFIGS.reduce<
export const PenTools = ({ app }: { app: TldrawApp }) => {
const appCurrentTool = app.useStore(state => state.appState.activeTool);
+ const [visible, setVisible] = useState(false);
const chosenPen =
PENCIL_CONFIGS.find(config => config.key === appCurrentTool) ||
PENCIL_CONFIGS[0];
@@ -134,8 +135,10 @@ export const PenTools = ({ app }: { app: TldrawApp }) => {
return (
setVisible(prev => !prev)}
+ onClickAway={() => setVisible(false)}
content={
@@ -153,7 +156,10 @@ export const PenTools = ({ app }: { app: TldrawApp }) => {
name={title}
primaryColor={color_vars['--color-0']}
secondaryColor={color_vars['--color-1']}
- onClick={() => setPen(key)}
+ onClick={() => {
+ setVisible(false);
+ setPen(key);
+ }}
/>
);
}
@@ -163,7 +169,10 @@ export const PenTools = ({ app }: { app: TldrawApp }) => {
setPenColor(color)}
+ onSelect={color => {
+ setVisible(false);
+ setPenColor(color);
+ }}
/>
diff --git a/libs/components/ui/src/cascader/Cascader.tsx b/libs/components/ui/src/cascader/Cascader.tsx
index 1ba44aab6b..7bf43413f2 100644
--- a/libs/components/ui/src/cascader/Cascader.tsx
+++ b/libs/components/ui/src/cascader/Cascader.tsx
@@ -1,5 +1,5 @@
import { ArrowRightIcon } from '@toeverything/components/icons';
-import { ReactElement, useRef, useState } from 'react';
+import { useRef, useState, type ReactElement } from 'react';
import { Divider } from '../divider';
import {
MuiGrow as Grow,
diff --git a/libs/components/ui/src/popper/Popper.tsx b/libs/components/ui/src/popper/Popper.tsx
index 924e3be8fd..55d5692927 100644
--- a/libs/components/ui/src/popper/Popper.tsx
+++ b/libs/components/ui/src/popper/Popper.tsx
@@ -35,6 +35,8 @@ export const Popper = ({
offset = [0, 5],
showArrow = false,
popperHandlerRef,
+ onClick,
+ onClickAway,
...popperProps
}: PopperProps) => {
const [anchorEl, setAnchorEl] = useState(null);
@@ -97,15 +99,20 @@ export const Popper = ({
return (
{
- setVisible(false);
+ if (visibleControlledByParent) {
+ onClickAway?.();
+ } else {
+ setVisible(false);
+ }
}}
>
{isAnchorCustom ? null : (
setAnchorEl(dom)}
- onClick={() => {
+ onClick={e => {
if (!hasClickTrigger || visibleControlledByParent) {
+ onClick?.(e);
return;
}
setVisible(!visible);
diff --git a/libs/components/ui/src/popper/interface.ts b/libs/components/ui/src/popper/interface.ts
index b449eff61f..1f7473ebf4 100644
--- a/libs/components/ui/src/popper/interface.ts
+++ b/libs/components/ui/src/popper/interface.ts
@@ -62,4 +62,6 @@ export type PopperProps = {
showArrow?: boolean;
popperHandlerRef?: Ref
;
+
+ onClickAway?: () => void;
} & Omit;
diff --git a/libs/datasource/jwt/package.json b/libs/datasource/jwt/package.json
index dd8f6f6761..b43942b6ee 100644
--- a/libs/datasource/jwt/package.json
+++ b/libs/datasource/jwt/package.json
@@ -12,7 +12,7 @@
"file-selector": "^0.6.0",
"flexsearch": "^0.7.21",
"lib0": "^0.2.52",
- "lru-cache": "^7.13.2",
+ "lru-cache": "^7.14.0",
"ts-debounce": "^4.0.0"
},
"dependencies": {
diff --git a/libs/datasource/jwt/src/block/abstract.ts b/libs/datasource/jwt/src/block/abstract.ts
index 38ee415e05..55249514b3 100644
--- a/libs/datasource/jwt/src/block/abstract.ts
+++ b/libs/datasource/jwt/src/block/abstract.ts
@@ -1,3 +1,10 @@
+import {
+ BlockFlavorKeys,
+ BlockFlavors,
+ BlockTypeKeys,
+ BlockTypes,
+} from '../types';
+import { getLogger } from '../utils';
import {
BlockInstance,
BlockListener,
@@ -6,14 +13,7 @@ import {
ContentTypes,
HistoryManager,
MapOperation,
-} from '../adapter';
-import {
- BlockFlavorKeys,
- BlockFlavors,
- BlockTypeKeys,
- BlockTypes,
-} from '../types';
-import { getLogger } from '../utils';
+} from '../yjs/types';
declare const JWT_DEV: boolean;
const logger = getLogger('BlockDB:block');
@@ -29,10 +29,10 @@ export class AbstractBlock<
private readonly _id: string;
private readonly _block: BlockInstance;
private readonly _history: HistoryManager;
- private readonly _root?: AbstractBlock;
+ private readonly _root: AbstractBlock | undefined;
private readonly _parentListener: Map;
- private _parent?: AbstractBlock;
+ private _parent: AbstractBlock | undefined;
private _changeParent?: () => void;
constructor(
@@ -48,7 +48,9 @@ export class AbstractBlock<
this._parentListener = new Map();
JWT_DEV && logger_debug(`init: exists ${this._id}`);
- if (parent) this._refreshParent(parent);
+ if (parent) {
+ this._refreshParent(parent);
+ }
}
public get root() {
@@ -146,7 +148,7 @@ export class AbstractBlock<
return new Date(timestamp)
.toISOString()
.split('T')[0]
- .replace(/-/g, '');
+ ?.replace(/-/g, '');
}
// eslint-disable-next-line no-empty
} catch (e) {}
@@ -259,7 +261,7 @@ export class AbstractBlock<
}
/**
- * Insert sub-Block
+ * Insert children block
* @param block Block instance
* @param position Insertion position, if it is empty, it will be inserted at the end. If the block already exists, the position will be moved
* @returns
@@ -270,9 +272,12 @@ export class AbstractBlock<
) {
JWT_DEV && logger(`insertChildren: start`);
- if (block.id === this._id) return; // avoid self-reference
+ if (block.id === this._id) {
+ // avoid self-reference
+ return;
+ }
if (
- this.type !== BlockTypes.block || // binary cannot insert subblocks
+ this.type !== BlockTypes.block || // binary cannot insert children blocks
(block.type !== BlockTypes.block &&
this.flavor !== BlockFlavors.workspace) // binary can only be inserted into workspace
) {
diff --git a/libs/datasource/jwt/src/block/base.ts b/libs/datasource/jwt/src/block/base.ts
index 72183187b1..b5872980db 100644
--- a/libs/datasource/jwt/src/block/base.ts
+++ b/libs/datasource/jwt/src/block/base.ts
@@ -1,3 +1,5 @@
+import { BlockItem } from '../types';
+import { getLogger } from '../utils';
import {
ArrayOperation,
BlockInstance,
@@ -5,9 +7,7 @@ import {
ContentTypes,
InternalPlainObject,
MapOperation,
-} from '../adapter';
-import { BlockItem } from '../types';
-import { getLogger } from '../utils';
+} from '../yjs/types';
import { AbstractBlock } from './abstract';
import { BlockCapability } from './capability';
@@ -23,8 +23,8 @@ export interface Decoration extends InternalPlainObject {
type Validator = (value: T | undefined) => boolean | void;
export type IndexMetadata = Readonly<{
- content?: string;
- reference?: string;
+ content: string | undefined;
+ reference: string | undefined;
tags: string[];
}>;
export type QueryMetadata = Readonly<
@@ -51,7 +51,7 @@ export class BaseBlock<
B extends BlockInstance,
C extends ContentOperation
> extends AbstractBlock {
- private readonly _exporters?: Exporters;
+ private readonly _exporters: Exporters | undefined;
private readonly _contentExportersGetter: () => Map<
string,
ReadableContentExporter
@@ -68,7 +68,7 @@ export class BaseBlock<
ReadableContentExporter
>;
- validators: Map = new Map();
+ private readonly _validators: Map = new Map();
constructor(
block: B,
@@ -157,14 +157,14 @@ export class BaseBlock<
setValidator(key: string, validator?: Validator) {
if (validator) {
- this.validators.set(key, validator);
+ this._validators.set(key, validator);
} else {
- this.validators.delete(key);
+ this._validators.delete(key);
}
}
private validate(key: string, value: unknown): boolean {
- const validate = this.validators.get(key);
+ const validate = this._validators.get(key);
if (validate) {
return validate(value) === false ? false : true;
}
@@ -179,7 +179,7 @@ export class BaseBlock<
}
/**
- * Get an instance of the child Block
+ * Get an instance of the child block
* @param blockId block id
*/
private get_children_instance(blockId?: string): BaseBlock[] {
@@ -201,9 +201,15 @@ export class BaseBlock<
}
try {
const parent_page = this._getParentPage(false);
- if (parent_page) metadata['page'] = parent_page;
- if (this.group) metadata['group'] = this.group.id;
- if (this.parent) metadata['parent'] = this.parent.id;
+ if (parent_page) {
+ metadata['page'] = parent_page;
+ }
+ if (this.group) {
+ metadata['group'] = this.group.id;
+ }
+ if (this.parent) {
+ metadata['parent'] = this.parent.id;
+ }
} catch (e) {
logger(`Failed to export default metadata`, e);
}
@@ -228,7 +234,9 @@ export class BaseBlock<
for (const [name, exporter] of this._contentExportersGetter()) {
try {
const content = exporter(this.getContent());
- if (content) contents.push(content);
+ if (content) {
+ contents.push(content);
+ }
} catch (err) {
logger(`Failed to export content: ${name}`, err);
}
diff --git a/libs/datasource/jwt/src/block/indexer.ts b/libs/datasource/jwt/src/block/indexer.ts
index dfee685b7e..ed57465dbc 100644
--- a/libs/datasource/jwt/src/block/indexer.ts
+++ b/libs/datasource/jwt/src/block/indexer.ts
@@ -7,14 +7,14 @@ import produce from 'immer';
import LRUCache from 'lru-cache';
import sift, { Query } from 'sift';
+import { BlockFlavors } from '../types';
+import { BlockEventBus, getLogger } from '../utils';
import {
AsyncDatabaseAdapter,
BlockInstance,
ChangedStates,
ContentOperation,
-} from '../adapter';
-import { BlockFlavors } from '../types';
-import { BlockEventBus, getLogger } from '../utils';
+} from '../yjs/types';
import { BaseBlock, IndexMetadata, QueryMetadata } from './base';
@@ -315,7 +315,9 @@ export class BlockIndexer<
private _testMetaKey(key: string) {
try {
const metadata = this._blockMetadata.values().next().value;
- if (!metadata || typeof metadata !== 'object') return false;
+ if (!metadata || typeof metadata !== 'object') {
+ return false;
+ }
return !!(key in metadata);
} catch (e) {
return false;
@@ -324,8 +326,11 @@ export class BlockIndexer<
private _getSortedMetadata(sort: string, desc?: boolean) {
const sorter = naturalSort(Array.from(this._blockMetadata.entries()));
- if (desc) return sorter.desc(([, m]) => m[sort]);
- else return sorter.asc(([, m]) => m[sort]);
+ if (desc) {
+ return sorter.desc(([, m]) => m[sort]);
+ } else {
+ return sorter.asc(([, m]) => m[sort]);
+ }
}
public query(query: QueryIndexMetadata) {
@@ -337,15 +342,23 @@ export class BlockIndexer<
if ($sort && this._testMetaKey($sort)) {
const metadata = this._getSortedMetadata($sort, $desc);
metadata.forEach(([key, value]) => {
- if (matches.length > limit) return;
- if (filter(value)) matches.push(key);
+ if (matches.length > limit) {
+ return;
+ }
+ if (filter(value)) {
+ matches.push(key);
+ }
});
return matches;
} else {
this._blockMetadata.forEach((value, key) => {
- if (matches.length > limit) return;
- if (filter(value)) matches.push(key);
+ if (matches.length > limit) {
+ return;
+ }
+ if (filter(value)) {
+ matches.push(key);
+ }
});
return matches;
diff --git a/libs/datasource/jwt/src/index.ts b/libs/datasource/jwt/src/index.ts
index 664e0f21fa..e08bdc1e16 100644
--- a/libs/datasource/jwt/src/index.ts
+++ b/libs/datasource/jwt/src/index.ts
@@ -1,26 +1,7 @@
/* eslint-disable max-lines */
import { DocumentSearchOptions } from 'flexsearch';
import LRUCache from 'lru-cache';
-import {
- AsyncDatabaseAdapter,
- BlockInstance,
- BlockListener,
- ChangedStates,
- Connectivity,
- ContentOperation,
- ContentTypes,
- DataExporter,
- getDataExporter,
- HistoryManager,
- YjsAdapter,
- YjsContentOperation,
- YjsInitOptions,
-} from './adapter';
-import {
- getYjsProviders,
- YjsBlockInstance,
- YjsProviderOptions,
-} from './adapter/yjs';
+
import {
BaseBlock,
BlockIndexer,
@@ -39,6 +20,26 @@ import {
UUID,
} from './types';
import { BlockEventBus, genUUID, getLogger } from './utils';
+import {
+ getYjsProviders,
+ YjsAdapter,
+ YjsBlockInstance,
+ YjsContentOperation,
+ YjsInitOptions,
+ YjsProviderOptions,
+} from './yjs';
+import {
+ AsyncDatabaseAdapter,
+ BlockInstance,
+ BlockListener,
+ ChangedStates,
+ Connectivity,
+ ContentOperation,
+ ContentTypes,
+ DataExporter,
+ getDataExporter,
+ HistoryManager,
+} from './yjs/types';
declare const JWT_DEV: boolean;
@@ -157,8 +158,11 @@ export class BlockClient<
public addBlockListener(tag: string, listener: BlockListener) {
const bus = this._eventBus.topic('updated');
- if (tag !== 'index' || !bus.has(tag)) bus.on(tag, listener);
- else console.error(`block listener ${tag} is reserved or exists`);
+ if (tag !== 'index' || !bus.has(tag)) {
+ bus.on(tag, listener);
+ } else {
+ console.error(`block listener ${tag} is reserved or exists`);
+ }
}
public removeBlockListener(tag: string) {
@@ -170,8 +174,11 @@ export class BlockClient<
listener: BlockListener>
) {
const bus = this._eventBus.topic>>('editing');
- if (tag !== 'index' || !bus.has(tag)) bus.on(tag, listener);
- else console.error(`editing listener ${tag} is reserved or exists`);
+ if (tag !== 'index' || !bus.has(tag)) {
+ bus.on(tag, listener);
+ } else {
+ console.error(`editing listener ${tag} is reserved or exists`);
+ }
}
public removeEditingListener(tag: string) {
@@ -184,15 +191,18 @@ export class BlockClient<
) {
const bus =
this._eventBus.topic>('connectivity');
- if (tag !== 'index' || !bus.has(tag)) bus.on(tag, listener);
- else
+ if (tag !== 'index' || !bus.has(tag)) {
+ bus.on(tag, listener);
+ } else {
console.error(`connectivity listener ${tag} is reserved or exists`);
+ }
}
public removeConnectivityListener(tag: string) {
this._eventBus.topic('connectivity').off(tag);
}
+ // @ts-ignore
private inspector() {
return {
...this._adapter.inspector(),
@@ -220,7 +230,9 @@ export class BlockClient<
this.addBlockListener('index', async states => {
await Promise.allSettled(
Array.from(states.entries()).map(([id, state]) => {
- if (state === 'delete') this._blockCaches.delete(id);
+ if (state === 'delete') {
+ this._blockCaches.delete(id);
+ }
return this._blockIndexer.refreshIndex(id, state);
})
);
@@ -255,7 +267,7 @@ export class BlockClient<
}
/**
- * research all
+ * Full text search
* @param part_of_title_or_content Title or content keyword, support Chinese
* @param part_of_title_or_content.index search range, optional values: title, ttl, content, reference
* @param part_of_title_or_content.tag tag, string or array of strings, supports multiple tags
@@ -295,7 +307,9 @@ export class BlockClient<
this.search(part_of_title_or_content).flatMap(({ result }) =>
result.map(async id => {
const page = this._pageMapping.get(id as string);
- if (page) return page;
+ if (page) {
+ return page;
+ }
const block = await this.get(id as BlockTypeKeys);
return this.set_page(block);
})
@@ -307,9 +321,10 @@ export class BlockClient<
}
return Promise.all(
this._blockIndexer.getMetadata(pages).map(async page => ({
- content: this.get_decoded_content(
- await this._adapter.getBlock(page.id)
- ),
+ content:
+ this.get_decoded_content(
+ await this._adapter.getBlock(page.id)
+ ) || '',
...page,
}))
);
@@ -327,9 +342,10 @@ export class BlockClient<
const ids = this.query(query);
return Promise.all(
this._blockIndexer.getMetadata(ids).map(async page => ({
- content: this.get_decoded_content(
- await this._adapter.getBlock(page.id)
- ),
+ content:
+ this.get_decoded_content(
+ await this._adapter.getBlock(page.id)
+ ) || '',
...page,
}))
);
@@ -378,7 +394,7 @@ export class BlockClient<
private async get_parent(id: string) {
const parents = this._parentMapping.get(id);
- if (parents) {
+ if (parents && parents[0]) {
const parent_block_id = parents[0];
if (!this._blockCaches.has(parent_block_id)) {
this._blockCaches.set(
@@ -405,7 +421,9 @@ export class BlockClient<
private set_page(block: BaseBlock) {
const page = this._pageMapping.get(block.id);
- if (page) return page;
+ if (page) {
+ return page;
+ }
const parent_page = block.parent_page;
if (parent_page) {
this._pageMapping.set(block.id, parent_page);
@@ -472,8 +490,9 @@ export class BlockClient<
matched += 1;
}
}
- if (matched === conditions.length)
+ if (matched === conditions.length) {
exporters.push([name, exporter] as const);
+ }
}
return exporters;
@@ -487,7 +506,9 @@ export class BlockClient<
);
if (exporter) {
const op = block.content.asMap();
- if (op) return exporter[1](op);
+ if (op) {
+ return exporter[1](op);
+ }
}
}
return undefined;
@@ -566,7 +587,9 @@ export class BlockClient<
this.set_page(abstract_block);
abstract_block.on('parent', 'client_hook', state => {
const [parent] = state.keys();
- this.set_parent(parent, abstract_block.id);
+ if (parent) {
+ this.set_parent(parent, abstract_block.id);
+ }
this.set_page(abstract_block);
});
this._blockCaches.set(abstract_block.id, abstract_block);
@@ -650,13 +673,6 @@ export type BlockInitOptions = NonNullable<
Parameters[1]
>;
-export type {
- ArrayOperation,
- ChangedStates,
- Connectivity,
- MapOperation,
- TextOperation,
-} from './adapter';
export type {
BlockSearchItem,
Decoration as BlockDecoration,
@@ -665,4 +681,11 @@ export type {
export { BlockTypes, BucketBackend as BlockBackend } from './types';
export type { BlockTypeKeys } from './types';
export { isBlock } from './utils';
+export type {
+ ArrayOperation,
+ ChangedStates,
+ Connectivity,
+ MapOperation,
+ TextOperation,
+} from './yjs/types';
export type { QueryIndexMetadata };
diff --git a/libs/datasource/jwt/src/types/block.ts b/libs/datasource/jwt/src/types/block.ts
index 3b04dc7830..d1867f1ef9 100644
--- a/libs/datasource/jwt/src/types/block.ts
+++ b/libs/datasource/jwt/src/types/block.ts
@@ -1,4 +1,4 @@
-import { ContentOperation } from '../adapter';
+import { ContentOperation } from '../yjs/types';
import { RefMetadata } from './metadata';
import { UUID } from './uuid';
// base type of block
@@ -60,8 +60,8 @@ export type BlockItem = {
flavor: typeof BlockFlavors[BlockFlavorKeys];
children: string[];
readonly created: number; // creation time, UTC timestamp
- readonly updated?: number; // update time, UTC timestamp
- readonly creator?: string; // creator id
+ readonly updated?: number | undefined; // update time, UTC timestamp
+ readonly creator?: string | undefined; // creator id
content: C; // Essentially what is stored here is either Uint8Array (binary resource) or YDoc (structured resource)
};
diff --git a/libs/datasource/jwt/src/utils/event-bus.ts b/libs/datasource/jwt/src/utils/event-bus.ts
index 50f5363390..85096dd6ed 100644
--- a/libs/datasource/jwt/src/utils/event-bus.ts
+++ b/libs/datasource/jwt/src/utils/event-bus.ts
@@ -81,7 +81,7 @@ class BlockScopedEventBus extends BlockEventBus {
options?: ListenerOptions
) {
if (options?.debounce) {
- const { wait, maxWait } = options.debounce;
+ const { wait, maxWait = 500 } = options.debounce;
const debounced = debounce(listener, wait, { maxWait });
this.on_listener(this._topic, name, e => {
debounced((e as CustomEvent)?.detail);
diff --git a/libs/datasource/jwt/src/utils/index.ts b/libs/datasource/jwt/src/utils/index.ts
index f19e5633a1..3d0d3bb101 100644
--- a/libs/datasource/jwt/src/utils/index.ts
+++ b/libs/datasource/jwt/src/utils/index.ts
@@ -39,7 +39,9 @@ export function getLogger(namespace: string) {
if (JWT_DEV) {
const logger = debug(namespace);
logger.log = console.log.bind(console);
- if (JWT_DEV === ('testing' as any)) logger.enabled = true;
+ if (JWT_DEV === ('testing' as any)) {
+ logger.enabled = true;
+ }
return logger;
} else {
return () => {};
diff --git a/libs/datasource/jwt/src/adapter/yjs/binary.ts b/libs/datasource/jwt/src/yjs/binary.ts
similarity index 96%
rename from libs/datasource/jwt/src/adapter/yjs/binary.ts
rename to libs/datasource/jwt/src/yjs/binary.ts
index 468710ac4a..c156452c78 100644
--- a/libs/datasource/jwt/src/adapter/yjs/binary.ts
+++ b/libs/datasource/jwt/src/yjs/binary.ts
@@ -25,7 +25,7 @@ export class YjsRemoteBinaries {
} else {
// TODO: Remote Load
try {
- const file = await this._remoteStorage?.instance.getBuffData(
+ const file = await this._remoteStorage?.instance?.getBuffData(
name
);
console.log(file);
@@ -44,11 +44,11 @@ export class YjsRemoteBinaries {
this._binaries.set(name, binary);
if (this._remoteStorage) {
// TODO: Remote Save, if there is an object with the same name remotely, the upload is skipped, because the file name is the hash of the file content
- const has_file = this._remoteStorage.instance.exist(name);
+ const has_file = this._remoteStorage.instance?.exist(name);
if (!has_file) {
const upload_file = new File(binary.toArray(), name);
await this._remoteStorage.instance
- .upload(upload_file)
+ ?.upload(upload_file)
.catch(err => {
throw new Error(`${err} upload error`);
});
diff --git a/libs/datasource/jwt/src/adapter/yjs/block.ts b/libs/datasource/jwt/src/yjs/block.ts
similarity index 95%
rename from libs/datasource/jwt/src/adapter/yjs/block.ts
rename to libs/datasource/jwt/src/yjs/block.ts
index 3f2b756799..513016f90e 100644
--- a/libs/datasource/jwt/src/adapter/yjs/block.ts
+++ b/libs/datasource/jwt/src/yjs/block.ts
@@ -5,8 +5,8 @@ import {
transact,
} from 'yjs';
-import { BlockItem, BlockTypes } from '../../types';
-import { BlockInstance, BlockListener, HistoryManager } from '../index';
+import { BlockItem, BlockTypes } from '../types';
+import { BlockInstance, BlockListener, HistoryManager } from './types';
import { YjsHistoryManager } from './history';
import { ChildrenListenerHandler, ContentListenerHandler } from './listener';
@@ -34,7 +34,7 @@ type YjsBlockInstanceProps = {
export class YjsBlockInstance implements BlockInstance {
private readonly _id: string;
private readonly _block: YMap;
- private readonly _binary?: YArray;
+ private readonly _binary: YArray | undefined;
private readonly _children: YArray;
private readonly _setBlock: (
id: string,
@@ -48,8 +48,7 @@ export class YjsBlockInstance implements BlockInstance {
private readonly _childrenListeners: Map;
private readonly _contentListeners: Map;
- // eslint-disable-next-line @typescript-eslint/naming-convention
- _childrenMap: Map;
+ private _childrenMap: Map;
constructor(props: YjsBlockInstanceProps) {
this._id = props.id;
@@ -184,7 +183,9 @@ export class YjsBlockInstance implements BlockInstance {
}
hasChildren(id: string): boolean {
- if (this.children.includes(id)) return true;
+ if (this.children.includes(id)) {
+ return true;
+ }
return this.getChildren().some(block => block.hasChildren(id));
}
@@ -263,7 +264,9 @@ export class YjsBlockInstance implements BlockInstance {
break;
}
}
- if (id) failed.push(id);
+ if (id) {
+ failed.push(id);
+ }
}
this._childrenMap = getMapFromYArray(this._children);
diff --git a/libs/datasource/jwt/src/adapter/yjs/gatekeeper.ts b/libs/datasource/jwt/src/yjs/gatekeeper.ts
similarity index 95%
rename from libs/datasource/jwt/src/adapter/yjs/gatekeeper.ts
rename to libs/datasource/jwt/src/yjs/gatekeeper.ts
index 7e02c5a09e..9acf1becf5 100644
--- a/libs/datasource/jwt/src/adapter/yjs/gatekeeper.ts
+++ b/libs/datasource/jwt/src/yjs/gatekeeper.ts
@@ -32,7 +32,7 @@ export class GateKeeper {
return creator === this._userId || !!this._common.get(block_id);
}
- checkDeleteLists(block_ids: string[]) {
+ checkDeleteLists(block_ids: string[]): [string[], string[]] {
const success = [];
const fail = [];
for (const block_id of block_ids) {
diff --git a/libs/datasource/jwt/src/adapter/yjs/history.ts b/libs/datasource/jwt/src/yjs/history.ts
similarity index 95%
rename from libs/datasource/jwt/src/adapter/yjs/history.ts
rename to libs/datasource/jwt/src/yjs/history.ts
index 6739cf9a50..5c6f5c4001 100644
--- a/libs/datasource/jwt/src/adapter/yjs/history.ts
+++ b/libs/datasource/jwt/src/yjs/history.ts
@@ -1,10 +1,11 @@
import { Map as YMap, UndoManager } from 'yjs';
-import { HistoryCallback, HistoryManager } from '../../adapter';
+import { HistoryCallback, HistoryManager } from './types';
type StackItem = UndoManager['undoStack'][0];
export class YjsHistoryManager implements HistoryManager {
+ // @ts-ignore
private readonly _blocks: YMap;
private readonly _historyManager: UndoManager;
private readonly _pushListeners: Map>;
@@ -56,7 +57,7 @@ export class YjsHistoryManager implements HistoryManager {
}
break(): void {
- // this.#history_manager.
+ // this._historyManager.
}
undo(): Map | undefined {
diff --git a/libs/datasource/jwt/src/adapter/yjs/index.ts b/libs/datasource/jwt/src/yjs/index.ts
similarity index 95%
rename from libs/datasource/jwt/src/adapter/yjs/index.ts
rename to libs/datasource/jwt/src/yjs/index.ts
index ec201c2d84..7d0f30e4e3 100644
--- a/libs/datasource/jwt/src/adapter/yjs/index.ts
+++ b/libs/datasource/jwt/src/yjs/index.ts
@@ -18,15 +18,15 @@ import {
transact,
} from 'yjs';
+import { BlockItem, BlockTypes } from '../types';
+import { getLogger, sha3, sleep } from '../utils';
import {
AsyncDatabaseAdapter,
BlockListener,
ChangedStateKeys,
Connectivity,
HistoryManager,
-} from '../../adapter';
-import { BlockItem, BlockTypes } from '../../types';
-import { getLogger, sha3, sleep } from '../../utils';
+} from './types';
import { YjsRemoteBinaries } from './binary';
import { YjsBlockInstance } from './block';
@@ -40,6 +40,7 @@ import {
import { YjsProvider } from './provider';
declare const JWT_DEV: boolean;
+// @ts-ignore
const logger = getLogger('BlockDB:yjs');
type ConnectivityListener = (
@@ -54,7 +55,7 @@ type YjsProviders = {
gatekeeper: GateKeeper;
connListener: { listeners?: ConnectivityListener };
userId: string;
- remoteToken?: string; // remote storage token
+ remoteToken: string | undefined; // remote storage token
};
const _yjsDatabaseInstance = new Map();
@@ -70,8 +71,8 @@ async function _initYjsDatabase(
workspace: string,
options: {
userId: string;
- token?: string;
- provider?: Record;
+ token?: string | undefined;
+ provider?: Record | undefined;
}
): Promise {
if (_asyncInitLoading.has(workspace)) {
@@ -243,9 +244,10 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
typeof updated === 'number' &&
updated + 1000 * 10 > Date.now()
) {
- if (!editing_mapping[editing])
+ if (!editing_mapping[editing]) {
editing_mapping[editing] = [];
- editing_mapping[editing].push(userId);
+ }
+ editing_mapping[editing]?.push(userId);
}
}
listener(
@@ -338,7 +340,7 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
],
});
const [file] = (await fromEvent(handles)) as File[];
- const binary = await file.arrayBuffer();
+ const binary = await file?.arrayBuffer();
// await this._provider.idb.clearData();
const doc = new Doc({ autoLoad: true, shouldLoad: true });
let updated = 0;
@@ -348,7 +350,9 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
updated += 1;
});
setInterval(() => {
- if (updated > 0) updated -= 1;
+ if (updated > 0) {
+ updated -= 1;
+ }
}, 500);
const update_check = new Promise(resolve => {
@@ -362,8 +366,10 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
});
// await new IndexedDBProvider(this._provider.idb.name, doc)
// .whenSynced;
- applyUpdate(doc, new Uint8Array(binary));
- await update_check;
+ if (binary) {
+ applyUpdate(doc, new Uint8Array(binary));
+ await update_check;
+ }
console.log('load success');
},
parse: () => this._doc.toJSON(),
@@ -409,8 +415,8 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
async createBlock(
options: Pick, 'type' | 'flavor'> & {
- uuid?: string;
- binary?: ArrayBufferLike;
+ uuid: string | undefined;
+ binary: ArrayBufferLike | undefined;
}
): Promise {
const uuid = options.uuid || `affine${nanoid(16)}`;
@@ -481,7 +487,9 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
async getBlock(id: string): Promise {
const block_instance = this.get_block_sync(id);
- if (block_instance) return block_instance;
+ if (block_instance) {
+ return block_instance;
+ }
const block = this._blocks.get(id);
if (block && block.get('type') === BlockTypes.binary) {
const binary = await this._binaries.get(
@@ -540,7 +548,9 @@ export class YjsAdapter implements AsyncDatabaseAdapter {
let uploaded: Promise | undefined;
if (!block.size) {
const content = item.content[INTO_INNER]();
- if (!content) return reject();
+ if (!content) {
+ return reject();
+ }
const children = new YArray();
children.push(item.children);
diff --git a/libs/datasource/jwt/src/adapter/yjs/listener.ts b/libs/datasource/jwt/src/yjs/listener.ts
similarity index 98%
rename from libs/datasource/jwt/src/adapter/yjs/listener.ts
rename to libs/datasource/jwt/src/yjs/listener.ts
index 36c203bbce..a109862b20 100644
--- a/libs/datasource/jwt/src/adapter/yjs/listener.ts
+++ b/libs/datasource/jwt/src/yjs/listener.ts
@@ -1,7 +1,8 @@
import { produce } from 'immer';
import { debounce } from 'ts-debounce';
import { YEvent } from 'yjs';
-import { BlockListener, ChangedStateKeys } from '../index';
+
+import { BlockListener, ChangedStateKeys } from './types';
let listener_suspend = false;
diff --git a/libs/datasource/jwt/src/adapter/yjs/operation.ts b/libs/datasource/jwt/src/yjs/operation.ts
similarity index 93%
rename from libs/datasource/jwt/src/adapter/yjs/operation.ts
rename to libs/datasource/jwt/src/yjs/operation.ts
index a8dfdaffa4..8d1bac4723 100644
--- a/libs/datasource/jwt/src/adapter/yjs/operation.ts
+++ b/libs/datasource/jwt/src/yjs/operation.ts
@@ -6,6 +6,7 @@ import {
Text as YText,
} from 'yjs';
+import { ChildrenListenerHandler, ContentListenerHandler } from './listener';
import {
ArrayOperation,
BaseTypes,
@@ -16,21 +17,29 @@ import {
Operable,
TextOperation,
TextToken,
-} from '../index';
-import { ChildrenListenerHandler, ContentListenerHandler } from './listener';
+} from './types';
const INTO_INNER = Symbol('INTO_INNER');
export const DO_NOT_USE_THIS_OR_YOU_WILL_BE_FIRED_SYMBOL_INTO_INNER: typeof INTO_INNER =
INTO_INNER;
-function auto_get(root: ContentOperation, key: string): unknown | undefined {
+function auto_get(
+ root: ContentOperation,
+ key: string | undefined
+): unknown | undefined {
const array = root.asArray();
- if (array && !Number.isNaN(Number(key))) return array.get(Number(key));
+ if (array && !Number.isNaN(Number(key))) {
+ return array.get(Number(key));
+ }
const map = root.asMap();
- if (map) return map.get(key);
+ if (map && key) {
+ return map.get(key);
+ }
const text = root.asText();
- if (text) return text.toString();
+ if (text) {
+ return text.toString();
+ }
console.error('auto_get unknown root', root, key);
return undefined;
}
@@ -150,7 +159,9 @@ export class YjsContentOperation implements ContentOperation {
if (root instanceof YjsContentOperation) {
if (path.length === 1) {
const [key] = path;
- if (key) return auto_set(root, key, data);
+ if (key) {
+ return auto_set(root, key, data);
+ }
console.error('autoSet unknown path', root, path, data);
return;
}
@@ -191,6 +202,7 @@ export class YjsContentOperation implements ContentOperation {
}
// eslint-disable-next-line @typescript-eslint/naming-convention
+ // @ts-ignore
private toJSON() {
return this._content.toJSON();
}
@@ -283,7 +295,9 @@ class YjsArrayOperation
get(index: number): Operable | undefined {
const content = this._arrayContent.get(index);
- if (content) return this.to_operable(content);
+ if (content) {
+ return this.to_operable(content);
+ }
return undefined;
}
@@ -368,7 +382,9 @@ class YjsMapOperation
set(key: string, value: Operable): void {
if (value instanceof YjsContentOperation) {
const content = value[INTO_INNER]();
- if (content) this._mapContent.set(key, content as unknown as T);
+ if (content) {
+ this._mapContent.set(key, content as unknown as T);
+ }
} else {
this._mapContent.set(key, value as T);
}
@@ -376,7 +392,9 @@ class YjsMapOperation
get(key: string): Operable | undefined {
const content = this._mapContent.get(key);
- if (content) return this.to_operable(content);
+ if (content) {
+ return this.to_operable(content);
+ }
return undefined;
}
diff --git a/libs/datasource/jwt/src/adapter/yjs/provider.ts b/libs/datasource/jwt/src/yjs/provider.ts
similarity index 97%
rename from libs/datasource/jwt/src/adapter/yjs/provider.ts
rename to libs/datasource/jwt/src/yjs/provider.ts
index ba1835cc52..99a09fd69c 100644
--- a/libs/datasource/jwt/src/adapter/yjs/provider.ts
+++ b/libs/datasource/jwt/src/yjs/provider.ts
@@ -7,13 +7,13 @@ import {
WebsocketProvider,
} from '@toeverything/datasource/jwt-rpc';
-import { Connectivity } from '../../adapter';
-import { BucketBackend } from '../../types';
+import { BucketBackend } from '../types';
+import { Connectivity } from './types';
type YjsDefaultInstances = {
awareness: Awareness;
doc: Doc;
- token?: string;
+ token?: string | undefined;
workspace: string;
emitState: (connectivity: Connectivity) => void;
};
diff --git a/libs/datasource/jwt/src/adapter/index.ts b/libs/datasource/jwt/src/yjs/types.ts
similarity index 97%
rename from libs/datasource/jwt/src/adapter/index.ts
rename to libs/datasource/jwt/src/yjs/types.ts
index 2d7176e6be..b23c685e5c 100644
--- a/libs/datasource/jwt/src/adapter/index.ts
+++ b/libs/datasource/jwt/src/yjs/types.ts
@@ -139,8 +139,8 @@ interface AsyncDatabaseAdapter {
reload(): void;
createBlock(
options: Pick, 'type' | 'flavor'> & {
- binary?: ArrayBuffer;
- uuid?: string;
+ binary: ArrayBuffer | undefined;
+ uuid: string | undefined;
}
): Promise>;
getBlock(id: string): Promise | undefined>;
@@ -184,8 +184,6 @@ export const getDataExporter = () => {
return { importData, exportData, hasExporter, installExporter };
};
-export { YjsAdapter } from './yjs';
-export type { YjsContentOperation, YjsInitOptions } from './yjs';
export type {
AsyncDatabaseAdapter,
BlockPosition,
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 802d964374..e9f182f211 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -184,7 +184,7 @@ importers:
yjs: ^13.5.41
dependencies:
authing-js-sdk: 4.23.35
- firebase-admin: 11.0.1_@firebase+app-types@0.7.0
+ firebase-admin: 11.0.1
lib0: 0.2.52
lru-cache: 7.13.2
nanoid: 4.0.0
@@ -566,6 +566,9 @@ importers:
dependencies:
ffc-js-client-side-sdk: 1.1.5
+ libs/datasource/jwst/pkg:
+ specifiers: {}
+
libs/datasource/jwt:
specifiers:
'@types/debug': ^4.1.7
@@ -583,7 +586,7 @@ importers:
idb-keyval: ^6.2.0
immer: ^9.0.15
lib0: ^0.2.52
- lru-cache: ^7.13.2
+ lru-cache: ^7.14.0
nanoid: ^4.0.0
sha3: ^2.1.4
sift: ^16.0.0
@@ -614,7 +617,7 @@ importers:
file-selector: 0.6.0
flexsearch: 0.7.21
lib0: 0.2.52
- lru-cache: 7.13.2
+ lru-cache: 7.14.0
ts-debounce: 4.0.0
libs/datasource/jwt-rpc:
@@ -3180,6 +3183,15 @@ packages:
- utf-8-validate
dev: true
+ /@firebase/auth-interop-types/0.1.6_@firebase+util@1.6.3:
+ resolution: {integrity: sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==}
+ peerDependencies:
+ '@firebase/app-types': 0.x
+ '@firebase/util': 1.x
+ dependencies:
+ '@firebase/util': 1.6.3
+ dev: false
+
/@firebase/auth-interop-types/0.1.6_pbfwexsq7uf6mrzcwnikj3g37m:
resolution: {integrity: sha512-etIi92fW3CctsmR9e3sYM3Uqnoq861M0Id9mdOPF6PWIg38BXL5k4upCNBggGUpLIS0H1grMOvy/wn1xymwe2g==}
peerDependencies:
@@ -3188,6 +3200,7 @@ packages:
dependencies:
'@firebase/app-types': 0.7.0
'@firebase/util': 1.6.3
+ dev: true
/@firebase/auth-types/0.11.0_pbfwexsq7uf6mrzcwnikj3g37m:
resolution: {integrity: sha512-q7Bt6cx+ySj9elQHTsKulwk3+qDezhzRBFC9zlQ1BjgMueUOnGMcvqmU0zuKlQ4RhLSH7MNAdBV2znVaoN3Vxw==}
@@ -3223,6 +3236,19 @@ packages:
'@firebase/util': 1.6.3
tslib: 2.4.0
+ /@firebase/database-compat/0.2.4:
+ resolution: {integrity: sha512-VtsGixO5mTjNMJn6PwxAJEAR70fj+3blCXIdQKel3q+eYGZAfdqxox1+tzZDnf9NWBJpaOgAHPk3JVDxEo9NFQ==}
+ dependencies:
+ '@firebase/component': 0.5.17
+ '@firebase/database': 0.13.4
+ '@firebase/database-types': 0.9.12
+ '@firebase/logger': 0.3.3
+ '@firebase/util': 1.6.3
+ tslib: 2.4.0
+ transitivePeerDependencies:
+ - '@firebase/app-types'
+ dev: false
+
/@firebase/database-compat/0.2.4_@firebase+app-types@0.7.0:
resolution: {integrity: sha512-VtsGixO5mTjNMJn6PwxAJEAR70fj+3blCXIdQKel3q+eYGZAfdqxox1+tzZDnf9NWBJpaOgAHPk3JVDxEo9NFQ==}
dependencies:
@@ -3234,6 +3260,7 @@ packages:
tslib: 2.4.0
transitivePeerDependencies:
- '@firebase/app-types'
+ dev: true
/@firebase/database-types/0.9.10:
resolution: {integrity: sha512-2ji6nXRRsY+7hgU6zRhUtK0RmSjVWM71taI7Flgaw+BnopCo/lDF5HSwxp8z7LtiHlvQqeRA3Ozqx5VhlAbiKg==}
@@ -3248,6 +3275,19 @@ packages:
'@firebase/app-types': 0.7.0
'@firebase/util': 1.6.3
+ /@firebase/database/0.13.4:
+ resolution: {integrity: sha512-NW7bOoiaC4sJCj6DY/m9xHoFNa0CK32YPMCh6FiMweLCDQbOZM8Ql/Kn6yyuxCb7K7ypz9eSbRlCWQJsJRQjhg==}
+ dependencies:
+ '@firebase/auth-interop-types': 0.1.6_@firebase+util@1.6.3
+ '@firebase/component': 0.5.17
+ '@firebase/logger': 0.3.3
+ '@firebase/util': 1.6.3
+ faye-websocket: 0.11.4
+ tslib: 2.4.0
+ transitivePeerDependencies:
+ - '@firebase/app-types'
+ dev: false
+
/@firebase/database/0.13.4_@firebase+app-types@0.7.0:
resolution: {integrity: sha512-NW7bOoiaC4sJCj6DY/m9xHoFNa0CK32YPMCh6FiMweLCDQbOZM8Ql/Kn6yyuxCb7K7ypz9eSbRlCWQJsJRQjhg==}
dependencies:
@@ -3259,6 +3299,7 @@ packages:
tslib: 2.4.0
transitivePeerDependencies:
- '@firebase/app-types'
+ dev: true
/@firebase/firestore-compat/0.1.23_53yvy43rwpg2c45kgeszsxtrca:
resolution: {integrity: sha512-QfcuyMAavp//fQnjSfCEpnbWi7spIdKaXys1kOLu7395fLr+U6ykmto1HUMCSz8Yus9cEr/03Ujdi2SUl2GUAA==}
@@ -10332,12 +10373,12 @@ packages:
semver-regex: 2.0.0
dev: true
- /firebase-admin/11.0.1_@firebase+app-types@0.7.0:
+ /firebase-admin/11.0.1:
resolution: {integrity: sha512-rL3wlZbi2Kb/KJgcmj1YHlD4ZhfmhfgRO2YJialxAllm0tj1IQea878hHuBLGmv4DpbW9t9nLvX9kddNR2Y65Q==}
engines: {node: '>=14'}
dependencies:
'@fastify/busboy': 1.1.0
- '@firebase/database-compat': 0.2.4_@firebase+app-types@0.7.0
+ '@firebase/database-compat': 0.2.4
'@firebase/database-types': 0.9.10
'@types/node': 18.0.1
jsonwebtoken: 8.5.1
@@ -13573,6 +13614,12 @@ packages:
/lru-cache/7.13.2:
resolution: {integrity: sha512-VJL3nIpA79TodY/ctmZEfhASgqekbT574/c4j3jn4bKXbSCnTTCH/KltZyvL2GlV+tGSMtsWyem8DCX7qKTMBA==}
engines: {node: '>=12'}
+ dev: false
+
+ /lru-cache/7.14.0:
+ resolution: {integrity: sha512-EIRtP1GrSJny0dqb50QXRUNBxHJhcpxHC++M5tD7RYbvLLn5KVWKsbyswSSqDuU15UFi3bgTQIY8nhDMeF6aDQ==}
+ engines: {node: '>=12'}
+ dev: true
/lru-memoizer/2.1.4:
resolution: {integrity: sha512-IXAq50s4qwrOBrXJklY+KhgZF+5y98PDaNo0gi/v2KQBFLyWr+JyFvijZXkGKjQj/h9c0OwoE+JZbwUXce76hQ==}