refactor: jwt internal version migration

This commit is contained in:
DarkSky 2022-08-23 17:07:16 +08:00
parent eedb4864df
commit 6df2676c88
18 changed files with 274 additions and 145 deletions

View File

@ -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": {

View File

@ -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<C>;
private readonly _history: HistoryManager;
private readonly _root?: AbstractBlock<B, C>;
private readonly _root: AbstractBlock<B, C> | undefined;
private readonly _parentListener: Map<string, BlockListener>;
private _parent?: AbstractBlock<B, C>;
private _parent: AbstractBlock<B, C> | 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
) {

View File

@ -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 = <T>(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>,
C extends ContentOperation
> extends AbstractBlock<B, C> {
private readonly _exporters?: Exporters;
private readonly _exporters: Exporters | undefined;
private readonly _contentExportersGetter: () => Map<
string,
ReadableContentExporter<string, any>
@ -68,7 +68,7 @@ export class BaseBlock<
ReadableContentExporter<string[], any>
>;
validators: Map<string, Validator> = new Map();
private readonly _validators: Map<string, Validator> = 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<B, C>[] {
@ -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);
}

View File

@ -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;

View File

@ -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<ChangedStates>('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<Set<string>>
) {
const bus = this._eventBus.topic<ChangedStates<Set<string>>>('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<ChangedStates<Connectivity>>('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<B, C>) {
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<typeof BlockClient.init>[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 };

View File

@ -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<C extends ContentOperation> = {
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)
};

View File

@ -81,7 +81,7 @@ class BlockScopedEventBus<T> 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);

View File

@ -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 () => {};

View File

@ -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`);
});

View File

@ -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<YjsContentOperation> {
private readonly _id: string;
private readonly _block: YMap<unknown>;
private readonly _binary?: YArray<ArrayBuffer>;
private readonly _binary: YArray<ArrayBuffer> | undefined;
private readonly _children: YArray<string>;
private readonly _setBlock: (
id: string,
@ -48,8 +48,7 @@ export class YjsBlockInstance implements BlockInstance<YjsContentOperation> {
private readonly _childrenListeners: Map<string, BlockListener>;
private readonly _contentListeners: Map<string, BlockListener>;
// eslint-disable-next-line @typescript-eslint/naming-convention
_childrenMap: Map<string, number>;
private _childrenMap: Map<string, number>;
constructor(props: YjsBlockInstanceProps) {
this._id = props.id;
@ -184,7 +183,9 @@ export class YjsBlockInstance implements BlockInstance<YjsContentOperation> {
}
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<YjsContentOperation> {
break;
}
}
if (id) failed.push(id);
if (id) {
failed.push(id);
}
}
this._childrenMap = getMapFromYArray(this._children);

View File

@ -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) {

View File

@ -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<any>;
private readonly _historyManager: UndoManager;
private readonly _pushListeners: Map<string, HistoryCallback<any>>;
@ -56,7 +57,7 @@ export class YjsHistoryManager implements HistoryManager {
}
break(): void {
// this.#history_manager.
// this._historyManager.
}
undo<T = unknown>(): Map<string, T> | undefined {

View File

@ -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<string, YjsProviders>();
@ -70,8 +71,8 @@ async function _initYjsDatabase(
workspace: string,
options: {
userId: string;
token?: string;
provider?: Record<string, YjsProvider>;
token?: string | undefined;
provider?: Record<string, YjsProvider> | undefined;
}
): Promise<YjsProviders> {
if (_asyncInitLoading.has(workspace)) {
@ -243,9 +244,10 @@ export class YjsAdapter implements AsyncDatabaseAdapter<YjsContentOperation> {
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<YjsContentOperation> {
],
});
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<YjsContentOperation> {
updated += 1;
});
setInterval(() => {
if (updated > 0) updated -= 1;
if (updated > 0) {
updated -= 1;
}
}, 500);
const update_check = new Promise<void>(resolve => {
@ -362,8 +366,10 @@ export class YjsAdapter implements AsyncDatabaseAdapter<YjsContentOperation> {
});
// 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<YjsContentOperation> {
async createBlock(
options: Pick<BlockItem<YjsContentOperation>, 'type' | 'flavor'> & {
uuid?: string;
binary?: ArrayBufferLike;
uuid: string | undefined;
binary: ArrayBufferLike | undefined;
}
): Promise<YjsBlockInstance> {
const uuid = options.uuid || `affine${nanoid(16)}`;
@ -481,7 +487,9 @@ export class YjsAdapter implements AsyncDatabaseAdapter<YjsContentOperation> {
async getBlock(id: string): Promise<YjsBlockInstance | undefined> {
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<YjsContentOperation> {
let uploaded: Promise<void> | 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);

View File

@ -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;

View File

@ -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<T extends ContentTypes>
get(index: number): Operable<T> | 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<T extends ContentTypes>
set(key: string, value: Operable<T>): 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<T extends ContentTypes>
get(key: string): Operable<T> | undefined {
const content = this._mapContent.get(key);
if (content) return this.to_operable(content);
if (content) {
return this.to_operable(content);
}
return undefined;
}

View File

@ -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;
};

View File

@ -139,8 +139,8 @@ interface AsyncDatabaseAdapter<C extends ContentOperation> {
reload(): void;
createBlock(
options: Pick<BlockItem<C>, 'type' | 'flavor'> & {
binary?: ArrayBuffer;
uuid?: string;
binary: ArrayBuffer | undefined;
uuid: string | undefined;
}
): Promise<BlockInstance<C>>;
getBlock(id: string): Promise<BlockInstance<C> | 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,

View File

@ -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==}