@pluv/crdt-yjs 0.15.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.eslintrc.js +2 -2
  2. package/.turbo/turbo-build.log +9 -9
  3. package/CHANGELOG.md +38 -37
  4. package/README.md +13 -29
  5. package/dist/index.d.mts +152 -55
  6. package/dist/index.d.ts +152 -55
  7. package/dist/index.js +433 -107
  8. package/dist/index.mjs +445 -101
  9. package/package.json +9 -8
  10. package/src/array/CrdtYjsArray.ts +55 -0
  11. package/src/array/array.ts +7 -0
  12. package/src/array/index.ts +2 -0
  13. package/src/doc/CrdtYjsDoc.ts +274 -0
  14. package/src/doc/CrdtYjsDocFactory.ts +83 -0
  15. package/src/doc/doc.ts +10 -0
  16. package/src/doc/index.ts +3 -0
  17. package/src/index.ts +1 -20
  18. package/src/map/CrdtYjsMap.ts +43 -0
  19. package/src/map/index.ts +2 -0
  20. package/src/{map.ts → map/map.ts} +3 -3
  21. package/src/object/CrdtYjsObject.ts +32 -0
  22. package/src/object/index.ts +2 -0
  23. package/src/object/object.ts +7 -0
  24. package/src/shared/index.ts +2 -0
  25. package/src/shared/isWrapper.ts +25 -0
  26. package/src/shared/toYjsValue.ts +5 -0
  27. package/src/text/CrdtYjsText.ts +34 -0
  28. package/src/text/index.ts +2 -0
  29. package/src/text/text.ts +5 -0
  30. package/src/types.ts +54 -35
  31. package/src/xmlElement/CrdtYjsXmlElement.ts +60 -0
  32. package/src/xmlElement/index.ts +2 -0
  33. package/src/xmlElement/xmlElement.ts +9 -0
  34. package/src/xmlFragment/CrdtYjsXmlFragment.ts +56 -0
  35. package/src/xmlFragment/index.ts +2 -0
  36. package/src/xmlFragment/xmlFragment.ts +9 -0
  37. package/src/xmlText/CrdtYjsXmlText.ts +38 -0
  38. package/src/xmlText/index.ts +2 -0
  39. package/src/xmlText/xmlText.ts +5 -0
  40. package/src/yjs.ts +9 -0
  41. package/src/array.ts +0 -11
  42. package/src/doc.ts +0 -160
  43. package/src/object.ts +0 -16
  44. package/src/text.ts +0 -5
  45. package/src/xmlElement.ts +0 -19
  46. package/src/xmlFragment.ts +0 -16
  47. package/src/xmlText.ts +0 -5
package/src/types.ts CHANGED
@@ -1,5 +1,5 @@
1
+ import type { Json } from "@pluv/types";
1
2
  import type {
2
- AbstractType,
3
3
  Array as YArray,
4
4
  Map as YMap,
5
5
  Text as YText,
@@ -7,39 +7,58 @@ import type {
7
7
  XmlFragment as YXmlFragment,
8
8
  XmlText as YXmlText,
9
9
  } from "yjs";
10
- import type { YjsDoc } from "./doc";
11
- import type { YObject } from "./object";
10
+ import type { CrdtYjsArray } from "./array";
11
+ import type { CrdtYjsMap } from "./map";
12
+ import type { CrdtYjsObject } from "./object";
13
+ import type { CrdtYjsText } from "./text";
14
+ import type { CrdtYjsXmlElement } from "./xmlElement";
15
+ import type { CrdtYjsXmlFragment } from "./xmlFragment";
16
+ import type { CrdtYjsXmlText } from "./xmlText";
12
17
 
13
- export type InferYjsDocJson<TDoc extends YjsDoc<any>> = TDoc extends YjsDoc<
14
- infer ITypes
15
- >
16
- ? { [P in keyof ITypes]: InferYjsSharedTypeJson<ITypes[P]> }
17
- : never;
18
+ export type InferYjsType<T extends unknown> =
19
+ T extends CrdtYjsArray<infer IType>
20
+ ? YArray<IType>
21
+ : T extends CrdtYjsMap<infer IType>
22
+ ? YMap<IType>
23
+ : T extends CrdtYjsObject<infer IType>
24
+ ? YMap<IType[keyof IType]>
25
+ : T extends CrdtYjsText
26
+ ? YText
27
+ : T extends CrdtYjsXmlElement
28
+ ? YXmlElement
29
+ : T extends CrdtYjsXmlFragment
30
+ ? YXmlFragment
31
+ : T extends CrdtYjsXmlText
32
+ ? YXmlText
33
+ : T extends Json
34
+ ? T
35
+ : never;
18
36
 
19
- export type InferYjsDocSharedType<
20
- TDoc extends YjsDoc<any>,
21
- TKey extends
22
- keyof InferYjsDocSharedTypes<TDoc> = keyof InferYjsDocSharedTypes<TDoc>,
23
- > = InferYjsDocSharedTypes<TDoc>[TKey];
24
-
25
- export type InferYjsDocSharedTypeJson<
26
- TDoc extends YjsDoc<any>,
27
- TKey extends
28
- keyof InferYjsDocSharedTypes<TDoc> = keyof InferYjsDocSharedTypes<TDoc>,
29
- > = InferYjsSharedTypeJson<InferYjsDocSharedTypes<TDoc>[TKey]>;
30
-
31
- export type InferYjsDocSharedTypes<TDoc extends YjsDoc<any>> =
32
- TDoc extends YjsDoc<infer ITypes> ? ITypes : never;
33
-
34
- export type InferYjsSharedTypeJson<TShared extends unknown> =
35
- TShared extends AbstractType<any>
36
- ? TShared extends YArray<infer IItem>
37
- ? readonly InferYjsSharedTypeJson<IItem>[]
38
- : TShared extends YObject<infer IObject>
39
- ? { [P in keyof IObject]: InferYjsSharedTypeJson<IObject[P]> }
40
- : TShared extends YMap<infer IItem>
41
- ? Record<string, InferYjsSharedTypeJson<IItem>>
42
- : TShared extends YText | YXmlElement | YXmlFragment | YXmlText
43
- ? string
44
- : never
45
- : TShared;
37
+ export type InferYjsJson<T extends unknown> =
38
+ T extends CrdtYjsArray<infer IType>
39
+ ? InferYjsJson<IType>[]
40
+ : T extends CrdtYjsMap<infer IType>
41
+ ? Record<string, InferYjsJson<IType>>
42
+ : T extends CrdtYjsObject<infer IType>
43
+ ? { [P in keyof IType]: InferYjsJson<IType[P]> }
44
+ : T extends
45
+ | CrdtYjsText
46
+ | CrdtYjsXmlElement
47
+ | CrdtYjsXmlFragment
48
+ | CrdtYjsXmlText
49
+ | YText
50
+ | YXmlElement
51
+ | YXmlFragment
52
+ | YXmlText
53
+ ? string
54
+ : T extends YArray<infer IType>
55
+ ? InferYjsJson<IType>[]
56
+ : T extends YMap<infer IType>
57
+ ? Record<string, InferYjsJson<IType>>
58
+ : T extends (infer IType)[]
59
+ ? InferYjsJson<IType>[]
60
+ : T extends Record<any, any>
61
+ ? { [P in keyof T]: InferYjsJson<T[P]> }
62
+ : T extends Json
63
+ ? T
64
+ : never;
@@ -0,0 +1,60 @@
1
+ import { AbstractCrdtType } from "@pluv/crdt";
2
+ import type { XmlText as YXmlText } from "yjs";
3
+ import { XmlElement as YXmlElement } from "yjs";
4
+ import { toYjsValue } from "../shared";
5
+ import type { CrdtYjsXmlText } from "../xmlText/CrdtYjsXmlText";
6
+
7
+ export class CrdtYjsXmlElement extends AbstractCrdtType<YXmlElement, string> {
8
+ public readonly initialValue: readonly (YXmlElement | YXmlText)[];
9
+ public readonly name: string;
10
+ public value: YXmlElement;
11
+
12
+ constructor(
13
+ name: string,
14
+ children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[],
15
+ ) {
16
+ super();
17
+
18
+ this.initialValue = children.map((item) => item.value);
19
+ this.name = name;
20
+ this.value = new YXmlElement(name);
21
+ this.push(...children);
22
+ }
23
+
24
+ public get length(): number {
25
+ return this.value.length;
26
+ }
27
+
28
+ public delete(index: number, length: number = 1): this {
29
+ this.value.delete(index, length);
30
+
31
+ return this;
32
+ }
33
+
34
+ public insert(
35
+ index: number,
36
+ ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]
37
+ ): this {
38
+ const converted = children.map((child) => toYjsValue(child));
39
+
40
+ this.value.insert(index, converted);
41
+
42
+ return this;
43
+ }
44
+
45
+ public push(
46
+ ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]
47
+ ): this {
48
+ return this.insert(this.length, ...children);
49
+ }
50
+
51
+ public unshift(
52
+ ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]
53
+ ): this {
54
+ return this.insert(0, ...children);
55
+ }
56
+
57
+ public toJson(): string {
58
+ return this.value.toJSON();
59
+ }
60
+ }
@@ -0,0 +1,2 @@
1
+ export { CrdtYjsXmlElement } from "./CrdtYjsXmlElement";
2
+ export { xmlElement } from "./xmlElement";
@@ -0,0 +1,9 @@
1
+ import type { CrdtYjsXmlText } from "../xmlText";
2
+ import { CrdtYjsXmlElement } from "./CrdtYjsXmlElement";
3
+
4
+ export const xmlElement = (
5
+ name: string,
6
+ children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[],
7
+ ): CrdtYjsXmlElement => {
8
+ return new CrdtYjsXmlElement(name, children);
9
+ };
@@ -0,0 +1,56 @@
1
+ import { AbstractCrdtType } from "@pluv/crdt";
2
+ import type { XmlElement as YXmlElement, XmlText as YXmlText } from "yjs";
3
+ import { XmlFragment as YXmlFragment } from "yjs";
4
+ import { toYjsValue } from "../shared";
5
+ import type { CrdtYjsXmlElement } from "../xmlElement/CrdtYjsXmlElement";
6
+ import type { CrdtYjsXmlText } from "../xmlText/CrdtYjsXmlText";
7
+
8
+ export class CrdtYjsXmlFragment extends AbstractCrdtType<YXmlFragment, string> {
9
+ public readonly initialValue: readonly (YXmlElement | YXmlText)[];
10
+ public value: YXmlFragment;
11
+
12
+ constructor(children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]) {
13
+ super();
14
+
15
+ this.initialValue = children.map((item) => item.value);
16
+ this.value = new YXmlFragment();
17
+ this.push(...children);
18
+ }
19
+
20
+ public get length(): number {
21
+ return this.value.length;
22
+ }
23
+
24
+ public delete(index: number, length: number = 1): this {
25
+ this.value.delete(index, length);
26
+
27
+ return this;
28
+ }
29
+
30
+ public insert(
31
+ index: number,
32
+ ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]
33
+ ): this {
34
+ const converted = children.map((child) => toYjsValue(child));
35
+
36
+ this.value.insert(index, converted);
37
+
38
+ return this;
39
+ }
40
+
41
+ public push(
42
+ ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]
43
+ ): this {
44
+ return this.insert(this.length, ...children);
45
+ }
46
+
47
+ public unshift(
48
+ ...children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[]
49
+ ): this {
50
+ return this.insert(0, ...children);
51
+ }
52
+
53
+ public toJson(): string {
54
+ return this.value.toJSON();
55
+ }
56
+ }
@@ -0,0 +1,2 @@
1
+ export { CrdtYjsXmlFragment } from "./CrdtYjsXmlFragment";
2
+ export { xmlFragment } from "./xmlFragment";
@@ -0,0 +1,9 @@
1
+ import type { CrdtYjsXmlElement } from "../xmlElement";
2
+ import type { CrdtYjsXmlText } from "../xmlText";
3
+ import { CrdtYjsXmlFragment } from "./CrdtYjsXmlFragment";
4
+
5
+ export const xmlFragment = (
6
+ children: readonly (CrdtYjsXmlElement | CrdtYjsXmlText)[],
7
+ ): CrdtYjsXmlFragment => {
8
+ return new CrdtYjsXmlFragment(children);
9
+ };
@@ -0,0 +1,38 @@
1
+ import { AbstractCrdtType } from "@pluv/crdt";
2
+ import { XmlText as YXmlText } from "yjs";
3
+
4
+ export class CrdtYjsXmlText extends AbstractCrdtType<YXmlText, string> {
5
+ public readonly initialValue: string;
6
+ public value: YXmlText;
7
+
8
+ constructor(value: string = "") {
9
+ super();
10
+
11
+ this.initialValue = value;
12
+ this.value = new YXmlText(value);
13
+ }
14
+
15
+ public get length(): number {
16
+ return this.value.length;
17
+ }
18
+
19
+ public delete(index: number, length: number = 1): this {
20
+ this.value.delete(index, length);
21
+
22
+ return this;
23
+ }
24
+
25
+ public insert(
26
+ index: number,
27
+ text: string,
28
+ attributes?: Record<string, string>,
29
+ ): this {
30
+ this.value.insert(index, text, attributes);
31
+
32
+ return this;
33
+ }
34
+
35
+ public toJson(): string {
36
+ return this.value.toJSON();
37
+ }
38
+ }
@@ -0,0 +1,2 @@
1
+ export { CrdtYjsXmlText } from "./CrdtYjsXmlText";
2
+ export { xmlText } from "./xmlText";
@@ -0,0 +1,5 @@
1
+ import { CrdtYjsXmlText } from "./CrdtYjsXmlText";
2
+
3
+ export const xmlText = (value: string = ""): CrdtYjsXmlText => {
4
+ return new CrdtYjsXmlText(value);
5
+ };
package/src/yjs.ts ADDED
@@ -0,0 +1,9 @@
1
+ export { CrdtYjsArray, array } from "./array";
2
+ export { CrdtYjsDoc, doc } from "./doc";
3
+ export { CrdtYjsMap, map } from "./map";
4
+ export { CrdtYjsObject, object } from "./object";
5
+ export { CrdtYjsText } from "./text";
6
+ export type { InferYjsJson, InferYjsType } from "./types";
7
+ export { CrdtYjsXmlElement, xmlElement } from "./xmlElement";
8
+ export { CrdtYjsXmlFragment, xmlFragment } from "./xmlFragment";
9
+ export { CrdtYjsXmlText, xmlText } from "./xmlText";
package/src/array.ts DELETED
@@ -1,11 +0,0 @@
1
- import { Array as YArray } from "yjs";
2
-
3
- export const array = <T extends unknown>(
4
- value: readonly T[] = [],
5
- ): YArray<T> => {
6
- const yarray = new YArray<T>();
7
-
8
- yarray.push(value.slice());
9
-
10
- return yarray;
11
- };
package/src/doc.ts DELETED
@@ -1,160 +0,0 @@
1
- import { fromUint8Array, toUint8Array } from "js-base64";
2
- import {
3
- AbstractType,
4
- Transaction,
5
- UndoManager,
6
- Doc as YDoc,
7
- Map as YMap,
8
- applyUpdate,
9
- encodeStateAsUpdate,
10
- } from "yjs";
11
- import type { InferYjsDocJson } from "./types";
12
-
13
- export interface TrackOriginOptions {
14
- captureTimeout?: number;
15
- trackedOrigins?: readonly string[];
16
- }
17
-
18
- export class YjsDoc<T extends Record<string, AbstractType<any>> = {}> {
19
- public value: YDoc = new YDoc();
20
- private _undoManager: UndoManager | null = null;
21
-
22
- public get storage(): T {
23
- const storage = this._storage;
24
-
25
- const keys = Array.from(storage.keys());
26
-
27
- return keys.reduce<T>(
28
- (acc, key) => ({ ...acc, [key]: storage.get(key) }),
29
- {} as T,
30
- );
31
- }
32
-
33
- private get _storage(): YMap<any> {
34
- return this.value.getMap("storage");
35
- }
36
-
37
- constructor(value?: T) {
38
- if (!value) return;
39
-
40
- const storage = this.value.getMap("storage");
41
-
42
- Object.entries(value).forEach(([key, node]) => {
43
- storage.set(key, node);
44
- });
45
- }
46
-
47
- public applyUpdate(
48
- update?: string | Uint8Array | null,
49
- origin?: string,
50
- ): this {
51
- if (update === null || typeof update === "undefined") return this;
52
-
53
- const uint8Update =
54
- typeof update === "string" ? toUint8Array(update) : update;
55
-
56
- applyUpdate(this.value, uint8Update, origin);
57
-
58
- return this;
59
- }
60
-
61
- public canRedo(): boolean {
62
- return !!this._undoManager?.canRedo();
63
- }
64
-
65
- public canUndo(): boolean {
66
- return !!this._undoManager?.canUndo();
67
- }
68
-
69
- public destroy(): void {
70
- this._undoManager?.destroy();
71
- this.value.destroy();
72
- }
73
-
74
- public encodeStateAsUpdate(): string {
75
- return fromUint8Array(encodeStateAsUpdate(this.value));
76
- }
77
-
78
- public get<TKey extends keyof T>(key: TKey): T[TKey] {
79
- return this._storage.get(key.toString());
80
- }
81
-
82
- public getSharedTypes(): T {
83
- return Array.from(this._storage.keys()).reduce(
84
- (acc, key) => ({ ...acc, [key]: this._storage.get(key) }),
85
- {} as T,
86
- );
87
- }
88
-
89
- public redo(): void {
90
- this._undoManager?.redo();
91
- }
92
-
93
- public subscribe(
94
- fn: (
95
- update: string,
96
- origin: any,
97
- doc: YDoc,
98
- transaction: Transaction,
99
- ) => void,
100
- ): () => void {
101
- const _fn = (
102
- update: Uint8Array,
103
- origin: any,
104
- doc: YDoc,
105
- transaction: Transaction,
106
- ) => fn(YjsDoc.fromUint8Array(update), origin, doc, transaction);
107
-
108
- this.value.on("update", _fn);
109
-
110
- return () => {
111
- this.value.off("update", _fn);
112
- };
113
- }
114
-
115
- public toJSON(): InferYjsDocJson<this> {
116
- return this._storage.toJSON() as InferYjsDocJson<this>;
117
- }
118
-
119
- public trackOrigins(options: TrackOriginOptions): void {
120
- const { captureTimeout, trackedOrigins } = options;
121
-
122
- if (this._undoManager) {
123
- this._undoManager.destroy();
124
- }
125
-
126
- this._undoManager = new UndoManager(this._storage, {
127
- captureTimeout,
128
- trackedOrigins: trackedOrigins
129
- ? new Set<string>(trackedOrigins)
130
- : undefined,
131
- });
132
- }
133
-
134
- public transact(
135
- fn: (transaction: Transaction) => void,
136
- origin?: any,
137
- ): void {
138
- this.value.transact((tx) => {
139
- fn(tx);
140
- }, origin);
141
- }
142
-
143
- public static fromUint8Array(u8a: Uint8Array): string {
144
- return fromUint8Array(u8a);
145
- }
146
-
147
- public static toUint8Array(str: string): Uint8Array {
148
- return toUint8Array(str);
149
- }
150
-
151
- public undo(): void {
152
- this._undoManager?.undo();
153
- }
154
- }
155
-
156
- export const doc = <T extends Record<string, AbstractType<any>> = {}>(
157
- value?: T,
158
- ): YjsDoc<T> => {
159
- return new YjsDoc(value);
160
- };
package/src/object.ts DELETED
@@ -1,16 +0,0 @@
1
- import type { JsonPrimitive } from "@pluv/types";
2
- import type { AbstractType } from "yjs";
3
- import { Map as YMap } from "yjs";
4
-
5
- export type YObjectValue = Record<
6
- string,
7
- NonNullable<JsonPrimitive> | AbstractType<any>
8
- >;
9
-
10
- export type YObject<T extends YObjectValue> = YMap<T[keyof T]> & {
11
- __$type: T;
12
- };
13
-
14
- export const object = <T extends YObjectValue = {}>(value: T): YObject<T> => {
15
- return new YMap(Object.entries(value)) as YObject<T>;
16
- };
package/src/text.ts DELETED
@@ -1,5 +0,0 @@
1
- import { Text as YText } from "yjs";
2
-
3
- export const text = (value: string = ""): YText => {
4
- return new YText(value);
5
- };
package/src/xmlElement.ts DELETED
@@ -1,19 +0,0 @@
1
- import type { XmlText as YXmlText } from "yjs";
2
- import { XmlElement as YXmlElement } from "yjs";
3
-
4
- export interface XmlElementParams {
5
- children?: readonly (YXmlElement | YXmlText)[];
6
- }
7
-
8
- export const xmlElement = (
9
- name: string,
10
- params: XmlElementParams = {},
11
- ): YXmlElement => {
12
- const { children = [] } = params;
13
-
14
- const element = new YXmlElement(name);
15
-
16
- element.push(children.slice());
17
-
18
- return element;
19
- };
@@ -1,16 +0,0 @@
1
- import type { XmlElement as YXmlElement, XmlText as YXmlText } from "yjs";
2
- import { XmlFragment as YXmlFragment } from "yjs";
3
-
4
- export interface XmlFragmentParams {
5
- children?: readonly (YXmlElement | YXmlText)[];
6
- }
7
-
8
- export const xmlFragment = (params: XmlFragmentParams = {}): YXmlFragment => {
9
- const { children = [] } = params;
10
-
11
- const fragment = new YXmlFragment();
12
-
13
- fragment.push(children.slice());
14
-
15
- return fragment;
16
- };
package/src/xmlText.ts DELETED
@@ -1,5 +0,0 @@
1
- import { XmlText as YXmlText } from "yjs";
2
-
3
- export const xmlText = (value: string = ""): YXmlText => {
4
- return new YXmlText(value);
5
- };