From 6df2676c8807916110fb77d0cc29df69ae265089 Mon Sep 17 00:00:00 2001 From: DarkSky Date: Tue, 23 Aug 2022 17:07:16 +0800 Subject: [PATCH] refactor: jwt internal version migration --- libs/datasource/jwt/package.json | 2 +- libs/datasource/jwt/src/block/abstract.ts | 35 +++--- libs/datasource/jwt/src/block/base.ts | 38 +++--- libs/datasource/jwt/src/block/indexer.ts | 33 +++-- libs/datasource/jwt/src/index.ts | 117 +++++++++++------- libs/datasource/jwt/src/types/block.ts | 6 +- libs/datasource/jwt/src/utils/event-bus.ts | 2 +- libs/datasource/jwt/src/utils/index.ts | 4 +- .../jwt/src/{adapter => }/yjs/binary.ts | 6 +- .../jwt/src/{adapter => }/yjs/block.ts | 17 +-- .../jwt/src/{adapter => }/yjs/gatekeeper.ts | 2 +- .../jwt/src/{adapter => }/yjs/history.ts | 5 +- .../jwt/src/{adapter => }/yjs/index.ts | 42 ++++--- .../jwt/src/{adapter => }/yjs/listener.ts | 3 +- .../jwt/src/{adapter => }/yjs/operation.ts | 38 ++++-- .../jwt/src/{adapter => }/yjs/provider.ts | 6 +- .../src/{adapter/index.ts => yjs/types.ts} | 6 +- pnpm-lock.yaml | 57 ++++++++- 18 files changed, 274 insertions(+), 145 deletions(-) rename libs/datasource/jwt/src/{adapter => }/yjs/binary.ts (96%) rename libs/datasource/jwt/src/{adapter => }/yjs/block.ts (95%) rename libs/datasource/jwt/src/{adapter => }/yjs/gatekeeper.ts (95%) rename libs/datasource/jwt/src/{adapter => }/yjs/history.ts (95%) rename libs/datasource/jwt/src/{adapter => }/yjs/index.ts (95%) rename libs/datasource/jwt/src/{adapter => }/yjs/listener.ts (98%) rename libs/datasource/jwt/src/{adapter => }/yjs/operation.ts (93%) rename libs/datasource/jwt/src/{adapter => }/yjs/provider.ts (97%) rename libs/datasource/jwt/src/{adapter/index.ts => yjs/types.ts} (97%) 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==}