Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@blocksuite/store

Package Overview
Dependencies
Maintainers
5
Versions
1256
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@blocksuite/store - npm Package Compare versions

Comparing version 0.4.0-20230113184550-93ac0f4 to 0.4.0-20230114095726-16babb2

2

dist/__tests__/test-utils-dom.d.ts

@@ -16,3 +16,3 @@ import type { Workspace } from '../workspace/workspace.js';

export declare function runOnce(): Promise<void>;
export declare function assertExists<T>(val: T | null | undefined): asserts val is T;
export { assertExists } from '@blocksuite/global/utils';
export declare function nextFrame(): Promise<unknown>;

@@ -19,0 +19,0 @@ export declare function loadTestImageBlob(name: string): Promise<Blob>;

@@ -39,7 +39,3 @@ const testResult = {

}
export function assertExists(val) {
if (val === null || val === undefined) {
throw new Error('val does not exist');
}
}
export { assertExists } from '@blocksuite/global/utils';
export async function nextFrame() {

@@ -46,0 +42,0 @@ return new Promise(resolve => requestAnimationFrame(resolve));

@@ -16,2 +16,11 @@ /// <reference types="@blocksuite/global" />

}
type Request<Flags extends Record<string, unknown> = BlockSuiteFlags, Key extends keyof Flags = keyof Flags> = {
id: string;
clientId: number;
field: Key;
value: Flags[Key];
};
type Response = {
id: string;
};
interface AwarenessState<Flags extends Record<string, unknown> = BlockSuiteFlags> {

@@ -21,2 +30,4 @@ cursor?: SelectionRange;

flags: Flags;
request?: Request<Flags>[];
response?: Response[];
}

@@ -41,9 +52,11 @@ interface AwarenessMessage<Flags extends Record<string, unknown> = BlockSuiteFlags> {

setFlag<Key extends keyof Flags>(field: Key, value: Flags[Key]): void;
getFlag<Key extends keyof Flags>(field: Key): any;
getFlag<Key extends keyof Flags>(field: Key): Flags[Key] | undefined;
setReadonly(value: boolean): void;
isReadonly(): boolean;
setRemoteFlag<Key extends keyof Flags>(clientId: number, field: Key, value: Flags[Key]): void;
getLocalCursor(): SelectionRange | undefined;
getStates(): Map<number, AwarenessState>;
getStates(): Map<number, AwarenessState<Flags>>;
private _onAwarenessChange;
private _onAwarenessMessage;
private _handleRemoteFlags;
private _resetRemoteCursor;

@@ -50,0 +63,0 @@ updateLocalCursor(): void;

import * as Y from 'yjs';
import { Signal } from './utils/signal.js';
import { assertExists } from './utils/utils.js';
import { merge } from 'merge';
import { uuidv4 } from './utils/id-generator.js';
export class AwarenessAdapter {

@@ -43,2 +43,5 @@ constructor(

}
if (this.getFlag('enable_set_remote_flag') === true) {
this._handleRemoteFlags();
}
};

@@ -65,13 +68,37 @@ this.space = space;

getFlag(field) {
const flags = this.awareness.getLocalState()?.flags;
assertExists(flags);
const flags = this.awareness.getLocalState()?.flags ?? {};
return flags[field];
}
setReadonly(value) {
const flags = this.getFlag('readonly');
this.setFlag('readonly', { ...flags, [this.space.prefixedId]: value });
const flags = this.getFlag('readonly') ?? {};
this.setFlag('readonly', {
...flags,
[this.space.prefixedId]: value,
});
}
isReadonly() {
return this.getFlag('readonly')[this.space.prefixedId] ?? false;
const rd = this.getFlag('readonly');
if (rd && typeof rd === 'object') {
return Boolean(rd[this.space.prefixedId]);
}
else {
return false;
}
}
setRemoteFlag(clientId, field, value) {
if (!this.getFlag('enable_set_remote_flag')) {
console.error('set remote flag feature disabled');
return;
}
const oldRequest = this.awareness.getLocalState()?.request ?? [];
this.awareness.setLocalStateField('request', [
...oldRequest,
{
id: uuidv4(),
clientId,
field,
value,
},
]);
}
getLocalCursor() {

@@ -85,2 +112,58 @@ const states = this.awareness.getStates();

}
_handleRemoteFlags() {
const nextTick = [];
const localState = this.awareness.getLocalState();
const request = (localState?.request ?? []);
const selfResponse = [];
const fakeDirtyResponse = [];
if (localState && Array.isArray(localState.response)) {
selfResponse.push(...localState.response);
fakeDirtyResponse.push(...localState.response);
}
const response = [];
for (const [clientId, state] of this.awareness.getStates()) {
if (clientId === this.awareness.clientID) {
continue;
}
if (Array.isArray(state.response)) {
response.push(...state.response);
}
if (Array.isArray(state.request)) {
const remoteRequest = state.request;
selfResponse.forEach((response, idx) => {
if (response === null) {
return;
}
const index = remoteRequest.findIndex(request => request.id === response.id);
if (index === -1) {
fakeDirtyResponse[idx].id = 'remove';
}
});
remoteRequest.forEach(request => {
if (request.clientId === this.awareness.clientID) {
// handle request
nextTick.push(() => {
this.setFlag(request.field, request.value);
});
selfResponse.push({
id: request.id,
});
}
});
}
}
response.forEach(response => {
const idx = request.findIndex(request => request.id === response.id);
if (idx !== -1) {
request.splice(idx, 1);
}
});
nextTick.push(() => {
this.awareness.setLocalStateField('request', request);
this.awareness.setLocalStateField('response', selfResponse.filter((response, idx) => fakeDirtyResponse[idx] ? fakeDirtyResponse[idx].id !== 'remove' : true));
});
setTimeout(() => {
nextTick.forEach(fn => fn());
}, 100);
}
_resetRemoteCursor() {

@@ -87,0 +170,0 @@ this.space.richTextAdapters.forEach(textAdapter => textAdapter.quillCursors.clearCursors());

@@ -1,9 +0,4 @@

/// <reference types="@blocksuite/global" />
import type { BaseBlockModel } from '../base.js';
import type { BlockProps, PrefixedBlockProps, YBlock, YBlocks } from '../workspace/page.js';
import { PrelimText, Text, TextType } from '../text-adapter.js';
import type { Workspace } from '../workspace/index.js';
export declare function assertExists<T>(val: T | null | undefined): asserts val is T;
export declare function assertFlavours(model: BaseBlockModel, allowed: string[]): void;
export declare function matchFlavours<Key extends keyof BlockSuiteInternal.BlockModels & string = keyof BlockSuiteInternal.BlockModels & string>(model: BaseBlockModel, expected: Key[]): boolean;
export declare function assertValidChildren(yBlocks: YBlocks, props: Partial<BlockProps>): void;

@@ -10,0 +5,0 @@ export declare function initSysProps(yBlock: YBlock, props: Partial<BlockProps>): void;

import * as Y from 'yjs';
import { PrelimText, Text } from '../text-adapter.js';
import { fromBase64, toBase64 } from 'lib0/buffer.js';
const SYS_KEYS = new Set(['id', 'flavour', 'children']);
// https://stackoverflow.com/questions/31538010/test-if-a-variable-is-a-primitive-rather-than-an-object
function isPrimitive(a) {
return a !== Object(a);
}
export function assertExists(val) {
if (val === null || val === undefined) {
throw new Error('val does not exist');
}
}
export function assertFlavours(model, allowed) {
if (!allowed.includes(model.flavour)) {
throw new Error(`model flavour ${model.flavour} is not allowed`);
}
}
export function matchFlavours(model, expected) {
return expected.includes(model.flavour);
}
import { isPrimitive, SYS_KEYS } from '@blocksuite/global/utils';
export function assertValidChildren(yBlocks, props) {

@@ -23,0 +6,0 @@ if (!Array.isArray(props.children))

// Test page entry located in playground/examples/workspace/index.html
import { Workspace } from '../workspace.js';
import { testSerial, runOnce, nextFrame, } from '../../__tests__/test-utils-dom.js';
import { assertExists } from '../../utils/utils.js';
import { assertExists } from '@blocksuite/global/utils';
import './test-app';

@@ -6,0 +6,0 @@ let i = 0;

@@ -7,4 +7,5 @@ import * as Y from 'yjs';

import { Signal } from '../utils/signal.js';
import { assertValidChildren, initSysProps, syncBlockProps, trySyncTextProp, toBlockProps, matchFlavours, } from '../utils/utils.js';
import { assertValidChildren, initSysProps, syncBlockProps, trySyncTextProp, toBlockProps, } from '../utils/utils.js';
import { tryMigrate } from './migrations.js';
import { matchFlavours } from '@blocksuite/global/utils';
const isWeb = typeof window !== 'undefined';

@@ -11,0 +12,0 @@ function createChildMap(yChildIds) {

@@ -8,2 +8,3 @@ import * as Y from 'yjs';

import { getBlobStorage } from '../blob/index.js';
import { merge } from 'merge';
class WorkspaceMeta extends Space {

@@ -159,2 +160,3 @@ constructor(id, doc, awareness, defaultFlags) {

const flagsPreset = {
enable_set_remote_flag: true,
enable_drag_handle: true,

@@ -176,6 +178,3 @@ readonly: {},

this.room = options.room;
this.meta = new WorkspaceMeta('space:meta', this.doc, this._store.awareness, {
...flagsPreset,
...options.defaultFlags,
});
this.meta = new WorkspaceMeta('space:meta', this.doc, this._store.awareness, merge(flagsPreset, options.defaultFlags));
this.signals = {

@@ -182,0 +181,0 @@ pagesUpdated: this.meta.pagesUpdated,

{
"name": "@blocksuite/store",
"version": "0.4.0-20230113184550-93ac0f4",
"version": "0.4.0-20230114095726-16babb2",
"description": "BlockSuite data store built for general purpose state management.",

@@ -11,5 +11,4 @@ "main": "dist/index.js",

"dependencies": {
"@blocksuite/global": "0.4.0-20230113184550-93ac0f4",
"@blocksuite/global": "0.4.0-20230114095726-16babb2",
"@types/flexsearch": "^0.7.3",
"@types/quill": "^1.3.7",
"buffer": "^6.0.3",

@@ -16,0 +15,0 @@ "flexsearch": "0.7.21",

@@ -71,7 +71,3 @@ import type { Workspace } from '../workspace/workspace.js';

export function assertExists<T>(val: T | null | undefined): asserts val is T {
if (val === null || val === undefined) {
throw new Error('val does not exist');
}
}
export { assertExists } from '@blocksuite/global/utils';

@@ -78,0 +74,0 @@ export async function nextFrame() {

@@ -20,3 +20,3 @@ /* eslint-disable @typescript-eslint/no-restricted-imports */

import type { PageMeta } from '../workspace/index.js';
import { assertExists } from '../utils/utils.js';
import { assertExists } from './test-utils-dom.js';

@@ -23,0 +23,0 @@ function createTestOptions() {

@@ -6,4 +6,4 @@ import * as Y from 'yjs';

import { Signal } from './utils/signal.js';
import { assertExists } from './utils/utils.js';
import { merge } from 'merge';
import { uuidv4 } from './utils/id-generator.js';

@@ -22,2 +22,16 @@ export interface SelectionRange {

type Request<
Flags extends Record<string, unknown> = BlockSuiteFlags,
Key extends keyof Flags = keyof Flags
> = {
id: string;
clientId: number;
field: Key;
value: Flags[Key];
};
type Response = {
id: string;
};
interface AwarenessState<

@@ -29,2 +43,4 @@ Flags extends Record<string, unknown> = BlockSuiteFlags

flags: Flags;
request?: Request<Flags>[];
response?: Response[];
}

@@ -89,5 +105,4 @@

public getFlag<Key extends keyof Flags>(field: Key) {
const flags = this.awareness.getLocalState()?.flags;
assertExists(flags);
public getFlag<Key extends keyof Flags>(field: Key): Flags[Key] | undefined {
const flags = this.awareness.getLocalState()?.flags ?? {};
return flags[field];

@@ -97,10 +112,39 @@ }

public setReadonly(value: boolean): void {
const flags = this.getFlag('readonly');
this.setFlag('readonly', { ...flags, [this.space.prefixedId]: value });
const flags = this.getFlag('readonly') ?? {};
this.setFlag('readonly', {
...flags,
[this.space.prefixedId]: value,
} as Flags['readonly']);
}
public isReadonly(): boolean {
return this.getFlag('readonly')[this.space.prefixedId] ?? false;
const rd = this.getFlag('readonly');
if (rd && typeof rd === 'object') {
return Boolean((rd as Record<string, boolean>)[this.space.prefixedId]);
} else {
return false;
}
}
setRemoteFlag<Key extends keyof Flags>(
clientId: number,
field: Key,
value: Flags[Key]
) {
if (!this.getFlag('enable_set_remote_flag')) {
console.error('set remote flag feature disabled');
return;
}
const oldRequest = this.awareness.getLocalState()?.request ?? [];
this.awareness.setLocalStateField('request', [
...oldRequest,
{
id: uuidv4(),
clientId,
field,
value,
},
] satisfies Request<Flags>[]);
}
public getLocalCursor(): SelectionRange | undefined {

@@ -112,4 +156,4 @@ const states = this.awareness.getStates();

public getStates(): Map<number, AwarenessState> {
return this.awareness.getStates() as Map<number, AwarenessState>;
public getStates(): Map<number, AwarenessState<Flags>> {
return this.awareness.getStates() as Map<number, AwarenessState<Flags>>;
}

@@ -153,4 +197,72 @@

}
if (this.getFlag('enable_set_remote_flag') === true) {
this._handleRemoteFlags();
}
};
private _handleRemoteFlags() {
const nextTick: (() => void)[] = [];
const localState = this.awareness.getLocalState() as AwarenessState<Flags>;
const request = (localState?.request ?? []) as Request<Flags>[];
const selfResponse = [] as Response[];
const fakeDirtyResponse = [] as Response[];
if (localState && Array.isArray(localState.response)) {
selfResponse.push(...localState.response);
fakeDirtyResponse.push(...localState.response);
}
const response = [] as Response[];
for (const [clientId, state] of this.awareness.getStates()) {
if (clientId === this.awareness.clientID) {
continue;
}
if (Array.isArray(state.response)) {
response.push(...state.response);
}
if (Array.isArray(state.request)) {
const remoteRequest = state.request as Request<Flags>[];
selfResponse.forEach((response, idx) => {
if (response === null) {
return;
}
const index = remoteRequest.findIndex(
request => request.id === response.id
);
if (index === -1) {
fakeDirtyResponse[idx].id = 'remove';
}
});
remoteRequest.forEach(request => {
if (request.clientId === this.awareness.clientID) {
// handle request
nextTick.push(() => {
this.setFlag(request.field, request.value);
});
selfResponse.push({
id: request.id,
});
}
});
}
}
response.forEach(response => {
const idx = request.findIndex(request => request.id === response.id);
if (idx !== -1) {
request.splice(idx, 1);
}
});
nextTick.push(() => {
this.awareness.setLocalStateField('request', request);
this.awareness.setLocalStateField(
'response',
selfResponse.filter((response, idx) =>
fakeDirtyResponse[idx] ? fakeDirtyResponse[idx].id !== 'remove' : true
)
);
});
setTimeout(() => {
nextTick.forEach(fn => fn());
}, 100);
}
private _resetRemoteCursor() {

@@ -157,0 +269,0 @@ this.space.richTextAdapters.forEach(textAdapter =>

// Test page entry located in playground/examples/blob/index.html
import { getBlobStorage } from '..';
import { getBlobStorage } from '../index.js';
import {

@@ -11,3 +11,3 @@ testSerial,

disableButtonsAfterClick,
} from '../../__tests__/test-utils-dom';
} from '../../__tests__/test-utils-dom.js';

@@ -14,0 +14,0 @@ async function testBasic() {

import * as Y from 'yjs';
import type { BaseBlockModel } from '../base.js';
import type {

@@ -12,34 +11,4 @@ BlockProps,

import { fromBase64, toBase64 } from 'lib0/buffer.js';
import { isPrimitive, SYS_KEYS } from '@blocksuite/global/utils';
const SYS_KEYS = new Set(['id', 'flavour', 'children']);
// https://stackoverflow.com/questions/31538010/test-if-a-variable-is-a-primitive-rather-than-an-object
function isPrimitive(
a: unknown
): a is null | undefined | boolean | number | string {
return a !== Object(a);
}
export function assertExists<T>(val: T | null | undefined): asserts val is T {
if (val === null || val === undefined) {
throw new Error('val does not exist');
}
}
export function assertFlavours(model: BaseBlockModel, allowed: string[]) {
if (!allowed.includes(model.flavour)) {
throw new Error(`model flavour ${model.flavour} is not allowed`);
}
}
export function matchFlavours<
Key extends keyof BlockSuiteInternal.BlockModels &
string = keyof BlockSuiteInternal.BlockModels & string
>(
model: BaseBlockModel,
expected: Key[]
): boolean /* model is BlockModels[Key] */ {
return expected.includes(model.flavour as Key);
}
export function assertValidChildren(

@@ -46,0 +15,0 @@ yBlocks: YBlocks,

@@ -9,3 +9,3 @@ // Test page entry located in playground/examples/workspace/index.html

} from '../../__tests__/test-utils-dom.js';
import { assertExists } from '../../utils/utils.js';
import { assertExists } from '@blocksuite/global/utils';
import './test-app';

@@ -12,0 +12,0 @@

@@ -21,3 +21,2 @@ import * as Y from 'yjs';

toBlockProps,
matchFlavours,
} from '../utils/utils.js';

@@ -27,3 +26,3 @@ import type { PageMeta, Workspace } from './workspace.js';

import { tryMigrate } from './migrations.js';
import { matchFlavours } from '@blocksuite/global/utils';
export type YBlock = Y.Map<unknown>;

@@ -30,0 +29,0 @@ export type YBlocks = Y.Map<YBlock>;

@@ -11,2 +11,3 @@ import * as Y from 'yjs';

import type { BlockSuiteDoc } from '../yjs/index.js';
import { merge } from 'merge';

@@ -220,2 +221,3 @@ export interface PageMeta {

const flagsPreset = {
enable_set_remote_flag: true,
enable_drag_handle: true,

@@ -258,6 +260,3 @@ readonly: {},

this._store.awareness,
{
...flagsPreset,
...options.defaultFlags,
}
merge(flagsPreset, options.defaultFlags)
);

@@ -264,0 +263,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc