@pluv/crdt-yjs 1.0.1 → 2.0.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.
@@ -1,5 +1,5 @@
1
1
 
2
- > @pluv/crdt-yjs@1.0.1 build /home/runner/work/pluv/pluv/packages/crdt-yjs
2
+ > @pluv/crdt-yjs@2.0.0 build /home/runner/work/pluv/pluv/packages/crdt-yjs
3
3
  > tsup src/index.ts --format esm,cjs --dts
4
4
 
5
5
  CLI Building entry: src/index.ts
@@ -8,11 +8,11 @@
8
8
  CLI Target: es6
9
9
  ESM Build start
10
10
  CJS Build start
11
- ESM dist/index.mjs 11.13 KB
12
- ESM ⚡️ Build success in 95ms
13
- CJS dist/index.js 12.00 KB
14
- CJS ⚡️ Build success in 95ms
11
+ CJS dist/index.js 16.33 KB
12
+ CJS ⚡️ Build success in 121ms
13
+ ESM dist/index.mjs 15.47 KB
14
+ ESM ⚡️ Build success in 123ms
15
15
  DTS Build start
16
- DTS ⚡️ Build success in 2852ms
17
- DTS dist/index.d.mts 3.96 KB
18
- DTS dist/index.d.ts 3.96 KB
16
+ DTS ⚡️ Build success in 4131ms
17
+ DTS dist/index.d.mts 5.14 KB
18
+ DTS dist/index.d.ts 5.14 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,56 @@
1
1
  # @pluv/crdt-yjs
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 0b234d1: **Deprecated** Declaring top-level types on your CRDT storage via the `yjs` utility (e.g. `yjs.array`) is now deprecated, to be removed in the next major release (v2). Continuing to use the `yjs` utility to declare top-level types will log a warning to your console while in development mode (i.e. when `process.env.NODE_ENV === "development"`). To declare top-level types, you should now use the builder type exposed in the storage factory function. See the example below:
8
+
9
+ ```ts
10
+ import { yjs } from "@pluv/crdt-yjs";
11
+
12
+ // Before
13
+ yjs.doc(() => ({
14
+ // Using the `yjs` utility (in this case `yjs.map`) when declaring
15
+ // top-level types is now deprecated
16
+ topType: yjs.map([
17
+ ["key1", yjs.text("")],
18
+ ["key2", yjs.text("")],
19
+ ]),
20
+ }));
21
+
22
+ // After
23
+ yjs.doc((t) => ({
24
+ // Top-level properties must now use the builder (in this case `t`).
25
+ // This effectively calls `yjs.getMap("topType")` to instantiate the type on
26
+ // the root document.
27
+ // This simply returns the native Yjs shared-types (e.g. Y.Map), which
28
+ // allows you operate on your yjs shared-typess in a more native way.
29
+ topType: t.map("topType", [
30
+ // Declaring nested types should continue to use the `yjs` utilities
31
+ // you've used before
32
+ ["key1", yjs.text("")],
33
+ ["key2", yjs.text("")],
34
+ ]),
35
+ }));
36
+ ```
37
+
38
+ The functions on the builder type calls the native yjs shared-type instantiating methods and returns the native types (e.g. `t.map("topType")` is simply just a `Y.Doc.getMap("topType")`) call under the hood. This allows you to declare your type in a more yjs-native and predictable way, and enables declaring more complex initial storage states if needed.
39
+
40
+ ### Patch Changes
41
+
42
+ - 0b234d1: Fixed `Y.XmlText` types transforming into `Y.Text` types on the initial initializaion of storage states.
43
+ - Updated dependencies [047a1d8]
44
+ - @pluv/types@2.0.0
45
+ - @pluv/crdt@2.0.0
46
+
47
+ ## 1.0.2
48
+
49
+ ### Patch Changes
50
+
51
+ - @pluv/crdt@1.0.2
52
+ - @pluv/types@1.0.2
53
+
3
54
  ## 1.0.1
4
55
 
5
56
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Array, Doc, Map, Text, XmlElement, XmlText, XmlFragment } from 'yjs';
2
- import { CrdtType, AbstractCrdtDoc, DocApplyEncodedStateParams, DocBatchApplyEncodedStateParams, DocSubscribeCallbackParams, InferCrdtJson, AbstractCrdtDocFactory } from '@pluv/crdt';
2
+ import { CrdtType, DocApplyEncodedStateParams, DocBatchApplyEncodedStateParams, DocSubscribeCallbackParams, InferCrdtJson, AbstractCrdtDocFactory } from '@pluv/crdt';
3
+ import { CrdtDocLike } from '@pluv/types';
3
4
 
4
5
  type YjsType<TValue extends unknown, TJson extends unknown = any> = CrdtType<TValue, TJson> & {
5
6
  initialValue?: any;
@@ -8,11 +9,22 @@ type YjsType<TValue extends unknown, TJson extends unknown = any> = CrdtType<TVa
8
9
 
9
10
  declare const array: <T extends unknown>(value?: T[] | readonly T[]) => YjsType<Array<T>, T[]>;
10
11
 
11
- declare class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>> extends AbstractCrdtDoc<TStorage> {
12
+ type YjsBuilder = ReturnType<typeof builder>;
13
+ declare const builder: (doc: Doc) => {
14
+ array<T extends unknown>(name: string, value?: T[] | readonly T[]): YjsType<Array<T>, T[]>;
15
+ map<T extends unknown>(name: string, value?: readonly (readonly [key: string, value: T])[]): YjsType<Map<T>, Record<string, T>>;
16
+ text(name: string, value?: string): YjsType<Text, string>;
17
+ xmlElement(name: string, children?: (XmlElement | XmlText)[] | readonly (XmlElement | XmlText)[]): YjsType<XmlElement, string>;
18
+ xmlFragment(name: string, children?: (XmlElement | XmlText)[] | readonly (XmlElement | XmlText)[]): YjsType<XmlFragment, string>;
19
+ xmlText(name: string): YjsType<XmlText, string>;
20
+ };
21
+
22
+ type CrdtYjsDocParams<TStorage extends Record<string, YjsType<any, any>>> = (builder: YjsBuilder) => TStorage;
23
+ declare class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>> implements CrdtDocLike<TStorage> {
12
24
  value: Doc;
13
25
  private _storage;
14
26
  private _undoManager;
15
- constructor(value?: TStorage);
27
+ constructor(params?: CrdtYjsDocParams<TStorage>);
16
28
  applyEncodedState(params: DocApplyEncodedStateParams): this;
17
29
  batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this;
18
30
  canRedo(): boolean;
@@ -30,20 +42,26 @@ declare class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>> ext
30
42
  toJson(): InferCrdtJson<TStorage>;
31
43
  toJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]>;
32
44
  undo(): this;
45
+ private _warn;
33
46
  }
34
47
 
35
- declare class CrdtYjsDocFactory<TStorage extends Record<string, YjsType<any, any>>> extends AbstractCrdtDocFactory<TStorage> {
36
- private _initialStorage;
37
- constructor(initialStorage?: () => TStorage);
48
+ declare class CrdtYjsDocFactory<TStorage extends Record<string, YjsType<any, any>> = {}> extends AbstractCrdtDocFactory<TStorage> {
49
+ readonly _initialStorage: (builder: YjsBuilder) => TStorage;
50
+ constructor(initialStorage?: (builder: YjsBuilder) => TStorage);
38
51
  getEmpty(): CrdtYjsDoc<TStorage>;
39
- getFactory(initialStorage?: (() => TStorage) | undefined): CrdtYjsDocFactory<TStorage>;
40
- getInitialized(initialStorage?: () => TStorage): CrdtYjsDoc<TStorage>;
52
+ getFactory(initialStorage: (builder: YjsBuilder) => TStorage): CrdtYjsDocFactory<TStorage>;
53
+ getInitialized(initialStorage?: (builder: YjsBuilder) => TStorage): CrdtYjsDoc<TStorage>;
41
54
  }
42
55
 
43
- declare const doc: <TStorage extends Record<string, YjsType<any, any>>>(value?: () => TStorage) => CrdtYjsDocFactory<TStorage>;
56
+ declare const doc: <TStorage extends Record<string, YjsType<any, any>>>(value?: (buidler: YjsBuilder) => TStorage) => CrdtYjsDocFactory<TStorage>;
44
57
 
45
58
  declare const map: <T extends unknown>(value?: readonly (readonly [key: string, value: T])[]) => YjsType<Map<T>, Record<string, T>>;
46
59
 
60
+ /**
61
+ * @deprecated This will be removed in v2.0.0. Use yjs.map instead
62
+ * @description Creates a Yjs map, but declare it like it's an object
63
+ * @date May 8, 2025
64
+ */
47
65
  declare const object: <T extends Record<string, any>>(value?: T) => YjsType<Map<T[keyof T]>, T>;
48
66
 
49
67
  declare const text: (value?: string) => YjsType<Text, string>;
@@ -68,6 +86,7 @@ declare const xmlText: () => YjsType<XmlText, string>;
68
86
 
69
87
  declare const kind: "yjs";
70
88
 
89
+ type yjs_YjsBuilder = YjsBuilder;
71
90
  type yjs_YjsType<TValue extends unknown, TJson extends unknown = any> = YjsType<TValue, TJson>;
72
91
  declare const yjs_array: typeof array;
73
92
  declare const yjs_doc: typeof doc;
@@ -79,7 +98,7 @@ declare const yjs_xmlElement: typeof xmlElement;
79
98
  declare const yjs_xmlFragment: typeof xmlFragment;
80
99
  declare const yjs_xmlText: typeof xmlText;
81
100
  declare namespace yjs {
82
- export { type yjs_YjsType as YjsType, yjs_array as array, yjs_doc as doc, yjs_kind as kind, yjs_map as map, yjs_object as object, yjs_text as text, yjs_xmlElement as xmlElement, yjs_xmlFragment as xmlFragment, yjs_xmlText as xmlText };
101
+ export { type yjs_YjsBuilder as YjsBuilder, type yjs_YjsType as YjsType, yjs_array as array, yjs_doc as doc, yjs_kind as kind, yjs_map as map, yjs_object as object, yjs_text as text, yjs_xmlElement as xmlElement, yjs_xmlFragment as xmlFragment, yjs_xmlText as xmlText };
83
102
  }
84
103
 
85
104
  export { yjs };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import { Array, Doc, Map, Text, XmlElement, XmlText, XmlFragment } from 'yjs';
2
- import { CrdtType, AbstractCrdtDoc, DocApplyEncodedStateParams, DocBatchApplyEncodedStateParams, DocSubscribeCallbackParams, InferCrdtJson, AbstractCrdtDocFactory } from '@pluv/crdt';
2
+ import { CrdtType, DocApplyEncodedStateParams, DocBatchApplyEncodedStateParams, DocSubscribeCallbackParams, InferCrdtJson, AbstractCrdtDocFactory } from '@pluv/crdt';
3
+ import { CrdtDocLike } from '@pluv/types';
3
4
 
4
5
  type YjsType<TValue extends unknown, TJson extends unknown = any> = CrdtType<TValue, TJson> & {
5
6
  initialValue?: any;
@@ -8,11 +9,22 @@ type YjsType<TValue extends unknown, TJson extends unknown = any> = CrdtType<TVa
8
9
 
9
10
  declare const array: <T extends unknown>(value?: T[] | readonly T[]) => YjsType<Array<T>, T[]>;
10
11
 
11
- declare class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>> extends AbstractCrdtDoc<TStorage> {
12
+ type YjsBuilder = ReturnType<typeof builder>;
13
+ declare const builder: (doc: Doc) => {
14
+ array<T extends unknown>(name: string, value?: T[] | readonly T[]): YjsType<Array<T>, T[]>;
15
+ map<T extends unknown>(name: string, value?: readonly (readonly [key: string, value: T])[]): YjsType<Map<T>, Record<string, T>>;
16
+ text(name: string, value?: string): YjsType<Text, string>;
17
+ xmlElement(name: string, children?: (XmlElement | XmlText)[] | readonly (XmlElement | XmlText)[]): YjsType<XmlElement, string>;
18
+ xmlFragment(name: string, children?: (XmlElement | XmlText)[] | readonly (XmlElement | XmlText)[]): YjsType<XmlFragment, string>;
19
+ xmlText(name: string): YjsType<XmlText, string>;
20
+ };
21
+
22
+ type CrdtYjsDocParams<TStorage extends Record<string, YjsType<any, any>>> = (builder: YjsBuilder) => TStorage;
23
+ declare class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>> implements CrdtDocLike<TStorage> {
12
24
  value: Doc;
13
25
  private _storage;
14
26
  private _undoManager;
15
- constructor(value?: TStorage);
27
+ constructor(params?: CrdtYjsDocParams<TStorage>);
16
28
  applyEncodedState(params: DocApplyEncodedStateParams): this;
17
29
  batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this;
18
30
  canRedo(): boolean;
@@ -30,20 +42,26 @@ declare class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>> ext
30
42
  toJson(): InferCrdtJson<TStorage>;
31
43
  toJson<TKey extends keyof TStorage>(type: TKey): InferCrdtJson<TStorage[TKey]>;
32
44
  undo(): this;
45
+ private _warn;
33
46
  }
34
47
 
35
- declare class CrdtYjsDocFactory<TStorage extends Record<string, YjsType<any, any>>> extends AbstractCrdtDocFactory<TStorage> {
36
- private _initialStorage;
37
- constructor(initialStorage?: () => TStorage);
48
+ declare class CrdtYjsDocFactory<TStorage extends Record<string, YjsType<any, any>> = {}> extends AbstractCrdtDocFactory<TStorage> {
49
+ readonly _initialStorage: (builder: YjsBuilder) => TStorage;
50
+ constructor(initialStorage?: (builder: YjsBuilder) => TStorage);
38
51
  getEmpty(): CrdtYjsDoc<TStorage>;
39
- getFactory(initialStorage?: (() => TStorage) | undefined): CrdtYjsDocFactory<TStorage>;
40
- getInitialized(initialStorage?: () => TStorage): CrdtYjsDoc<TStorage>;
52
+ getFactory(initialStorage: (builder: YjsBuilder) => TStorage): CrdtYjsDocFactory<TStorage>;
53
+ getInitialized(initialStorage?: (builder: YjsBuilder) => TStorage): CrdtYjsDoc<TStorage>;
41
54
  }
42
55
 
43
- declare const doc: <TStorage extends Record<string, YjsType<any, any>>>(value?: () => TStorage) => CrdtYjsDocFactory<TStorage>;
56
+ declare const doc: <TStorage extends Record<string, YjsType<any, any>>>(value?: (buidler: YjsBuilder) => TStorage) => CrdtYjsDocFactory<TStorage>;
44
57
 
45
58
  declare const map: <T extends unknown>(value?: readonly (readonly [key: string, value: T])[]) => YjsType<Map<T>, Record<string, T>>;
46
59
 
60
+ /**
61
+ * @deprecated This will be removed in v2.0.0. Use yjs.map instead
62
+ * @description Creates a Yjs map, but declare it like it's an object
63
+ * @date May 8, 2025
64
+ */
47
65
  declare const object: <T extends Record<string, any>>(value?: T) => YjsType<Map<T[keyof T]>, T>;
48
66
 
49
67
  declare const text: (value?: string) => YjsType<Text, string>;
@@ -68,6 +86,7 @@ declare const xmlText: () => YjsType<XmlText, string>;
68
86
 
69
87
  declare const kind: "yjs";
70
88
 
89
+ type yjs_YjsBuilder = YjsBuilder;
71
90
  type yjs_YjsType<TValue extends unknown, TJson extends unknown = any> = YjsType<TValue, TJson>;
72
91
  declare const yjs_array: typeof array;
73
92
  declare const yjs_doc: typeof doc;
@@ -79,7 +98,7 @@ declare const yjs_xmlElement: typeof xmlElement;
79
98
  declare const yjs_xmlFragment: typeof xmlFragment;
80
99
  declare const yjs_xmlText: typeof xmlText;
81
100
  declare namespace yjs {
82
- export { type yjs_YjsType as YjsType, yjs_array as array, yjs_doc as doc, yjs_kind as kind, yjs_map as map, yjs_object as object, yjs_text as text, yjs_xmlElement as xmlElement, yjs_xmlFragment as xmlFragment, yjs_xmlText as xmlText };
101
+ export { type yjs_YjsBuilder as YjsBuilder, type yjs_YjsType as YjsType, yjs_array as array, yjs_doc as doc, yjs_kind as kind, yjs_map as map, yjs_object as object, yjs_text as text, yjs_xmlElement as xmlElement, yjs_xmlFragment as xmlFragment, yjs_xmlText as xmlText };
83
102
  }
84
103
 
85
104
  export { yjs };
package/dist/index.js CHANGED
@@ -74,9 +74,8 @@ var array = (value = []) => {
74
74
  };
75
75
 
76
76
  // src/doc/CrdtYjsDoc.ts
77
- var import_crdt = require("@pluv/crdt");
78
77
  var import_js_base64 = require("js-base64");
79
- var import_yjs8 = require("yjs");
78
+ var import_yjs9 = require("yjs");
80
79
 
81
80
  // src/map/YjsMap.ts
82
81
  var import_yjs2 = require("yjs");
@@ -114,6 +113,11 @@ var YjsText = class extends import_yjs4.Text {
114
113
  }
115
114
  };
116
115
 
116
+ // src/utils/oneLine.ts
117
+ var oneLine = (strings, ...values) => {
118
+ return strings.map((str) => str.replace(/\s+/g, " ").trim()).reduce((acc, str, i) => acc + str + (i < values.length ? values[i] : ""), "").replace(/\s+/g, " ").trim();
119
+ };
120
+
117
121
  // src/xmlElement/YjsXmlElement.ts
118
122
  var import_yjs5 = require("yjs");
119
123
  var YjsXmlElement = class extends import_yjs5.XmlElement {
@@ -152,57 +156,139 @@ var YjsXmlText = class extends import_yjs7.XmlText {
152
156
  }
153
157
  };
154
158
 
159
+ // src/doc/builder.ts
160
+ var import_yjs8 = require("yjs");
161
+ var builder = (doc2) => {
162
+ return {
163
+ array(name, value = []) {
164
+ const array2 = doc2.getArray(name);
165
+ if (!!value.length) array2.insert(0, value);
166
+ return array2;
167
+ },
168
+ map(name, value = []) {
169
+ const map2 = doc2.getMap(name);
170
+ value.forEach(([k, v]) => {
171
+ map2.set(k, v);
172
+ });
173
+ return map2;
174
+ },
175
+ text(name, value = "") {
176
+ const text2 = doc2.getText(name);
177
+ if (!!value) text2.insert(0, value);
178
+ return text2;
179
+ },
180
+ xmlElement(name, children = []) {
181
+ const xmlElement2 = doc2.getXmlElement(name);
182
+ if (!!children.length) xmlElement2.insert(0, children);
183
+ return xmlElement2;
184
+ },
185
+ xmlFragment(name, children = []) {
186
+ const xmlFragment2 = doc2.getXmlFragment(name);
187
+ if (!!children.length) xmlFragment2.insert(0, children);
188
+ return xmlFragment2;
189
+ },
190
+ xmlText(name) {
191
+ const xmlText2 = doc2.get(name, import_yjs8.XmlText);
192
+ return xmlText2;
193
+ }
194
+ };
195
+ };
196
+
155
197
  // src/doc/CrdtYjsDoc.ts
156
198
  var MERGE_INTERVAL_MS = 1e3;
157
- var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
158
- constructor(value = {}) {
159
- super();
160
- this.value = new import_yjs8.Doc();
199
+ var CrdtYjsDoc = class {
200
+ constructor(params = () => ({})) {
201
+ this.value = new import_yjs9.Doc();
161
202
  this._undoManager = null;
162
- this._storage = Object.entries(value).reduce((acc, [key, node]) => {
203
+ const storage = params(builder(this.value));
204
+ const keys = this.value.share.keys().reduce((set, key) => set.add(key), /* @__PURE__ */ new Set());
205
+ this._storage = Object.entries(storage).reduce((acc, [key, node]) => {
163
206
  var _a, _b, _c, _d, _e, _f, _g, _h;
207
+ if (keys.has(key)) return __spreadProps(__spreadValues({}, acc), { [key]: node });
208
+ if (node instanceof YjsXmlElement) {
209
+ this._warn(oneLine`
210
+ Warning: You are using \`yjs.xmlElement\` to declare top-level storage value \`${key}\`.
211
+ Adding top-level values this way has been deprecated, to be removed in v2.
212
+ Please follow the v2 migration guide to declare top-level types correctly:
213
+ https://pluv.io/docs/migration-guides/v2
214
+ `);
215
+ const yXmlElement = this.value.getXmlElement(key);
216
+ if (!!((_a = node.initialValue) == null ? void 0 : _a.length)) {
217
+ yXmlElement.insert(0, (_b = node.initialValue) == null ? void 0 : _b.slice(0));
218
+ }
219
+ return __spreadProps(__spreadValues({}, acc), { [key]: yXmlElement });
220
+ }
221
+ if (node instanceof YjsXmlFragment) {
222
+ this._warn(oneLine`
223
+ Warning: You are using \`yjs.xmlFragment\` to declare top-level storage value \`${key}\`.
224
+ Adding top-level values this way has been deprecated, to be removed in v2.
225
+ Please follow the v2 migration guide to declare top-level types correctly:
226
+ https://pluv.io/docs/migration-guides/v2
227
+ `);
228
+ const yXmlFragment = this.value.getXmlFragment(key);
229
+ if (!!((_c = node.initialValue) == null ? void 0 : _c.length)) {
230
+ yXmlFragment.insert(0, (_d = node.initialValue) == null ? void 0 : _d.slice(0));
231
+ }
232
+ return __spreadProps(__spreadValues({}, acc), { [key]: yXmlFragment });
233
+ }
234
+ if (node instanceof YjsXmlText) {
235
+ this._warn(oneLine`
236
+ Warning: You are using \`yjs.xmlText\` to declare top-level storage value \`${key}\`.
237
+ Adding top-level values this way has been deprecated, to be removed in v2.
238
+ Please follow the v2 migration guide to declare top-level types correctly:
239
+ https://pluv.io/docs/migration-guides/v2
240
+ `);
241
+ const yXmlText = this.value.get(key, import_yjs9.XmlText);
242
+ return __spreadProps(__spreadValues({}, acc), { [key]: yXmlText });
243
+ }
164
244
  if (node instanceof YjsArray) {
245
+ this._warn(oneLine`
246
+ Warning: You are using \`yjs.array\` to declare top-level storage value \`${key}\`.
247
+ Adding top-level values this way has been deprecated, to be removed in v2.
248
+ Please follow the v2 migration guide to declare top-level types correctly:
249
+ https://pluv.io/docs/migration-guides/v2
250
+ `);
165
251
  const yArray = this.value.getArray(key);
166
- if (!!((_a = node.initialValue) == null ? void 0 : _a.length)) yArray.insert(0, (_b = node.initialValue) == null ? void 0 : _b.slice(0));
252
+ if (!!((_e = node.initialValue) == null ? void 0 : _e.length)) yArray.insert(0, (_f = node.initialValue) == null ? void 0 : _f.slice(0));
167
253
  return __spreadProps(__spreadValues({}, acc), { [key]: yArray });
168
254
  }
169
255
  if (node instanceof YjsMap) {
256
+ this._warn(oneLine`
257
+ Warning: You are using \`yjs.map\` to declare top-level storage value \`${key}\`.
258
+ Adding top-level values this way has been deprecated, to be removed in v2.
259
+ Please follow the v2 migration guide to declare top-level types correctly:
260
+ https://pluv.io/docs/migration-guides/v2
261
+ `);
170
262
  const yMap = this.value.getMap(key);
171
- ((_c = node.initialValue) != null ? _c : []).forEach(([k, v]) => {
263
+ ((_g = node.initialValue) != null ? _g : []).forEach(([k, v]) => {
172
264
  yMap.set(k.toString(), v);
173
265
  });
174
266
  return __spreadProps(__spreadValues({}, acc), { [key]: yMap });
175
267
  }
176
268
  if (node instanceof YjsObject) {
269
+ this._warn(oneLine`
270
+ Warning: You are using \`yjs.object\` to declare top-level storage value \`${key}\`.
271
+ Adding top-level values this way has been deprecated, to be removed in v2.
272
+ Please follow the v2 migration guide to declare top-level types correctly:
273
+ https://pluv.io/docs/migration-guides/v2
274
+ `);
177
275
  const yMap = this.value.getMap(key);
178
- Object.entries((_d = node.initialValue) != null ? _d : {}).forEach(([k, v]) => {
276
+ Object.entries((_h = node.initialValue) != null ? _h : {}).forEach(([k, v]) => {
179
277
  yMap.set(k.toString(), v);
180
278
  });
181
279
  return __spreadProps(__spreadValues({}, acc), { [key]: yMap });
182
280
  }
183
281
  if (node instanceof YjsText) {
282
+ this._warn(oneLine`
283
+ Warning: You are using \`yjs.text\` to declare top-level storage value \`${key}\`.
284
+ Adding top-level values this way has been deprecated, to be removed in v2.
285
+ Please follow the v2 migration guide to declare top-level types correctly:
286
+ https://pluv.io/docs/migration-guides/v2
287
+ `);
184
288
  const yText = this.value.getText(key);
185
289
  if (typeof node.initialValue === "string") yText.insert(0, node.initialValue);
186
290
  return __spreadProps(__spreadValues({}, acc), { [key]: yText });
187
291
  }
188
- if (node instanceof YjsXmlElement) {
189
- const yXmlElement = this.value.getXmlElement(key);
190
- if (!!((_e = node.initialValue) == null ? void 0 : _e.length)) {
191
- yXmlElement.insert(0, (_f = node.initialValue) == null ? void 0 : _f.slice(0));
192
- }
193
- return __spreadProps(__spreadValues({}, acc), { [key]: yXmlElement });
194
- }
195
- if (node instanceof YjsXmlFragment) {
196
- const yXmlFragment = this.value.getXmlFragment(key);
197
- if (!!((_g = node.initialValue) == null ? void 0 : _g.length)) {
198
- yXmlFragment.insert(0, (_h = node.initialValue) == null ? void 0 : _h.slice(0));
199
- }
200
- return __spreadProps(__spreadValues({}, acc), { [key]: yXmlFragment });
201
- }
202
- if (node instanceof YjsXmlText) {
203
- const yXmlText = this.value.get(key, import_yjs8.XmlText);
204
- return __spreadProps(__spreadValues({}, acc), { [key]: yXmlText });
205
- }
206
292
  return acc;
207
293
  }, {});
208
294
  }
@@ -210,7 +296,7 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
210
296
  const { origin, update } = params;
211
297
  if (update === null || typeof update === "undefined") return this;
212
298
  const uint8Update = typeof update === "string" ? (0, import_js_base64.toUint8Array)(update) : update;
213
- (0, import_yjs8.applyUpdate)(this.value, uint8Update, origin);
299
+ (0, import_yjs9.applyUpdate)(this.value, uint8Update, origin);
214
300
  return this;
215
301
  }
216
302
  batchApplyEncodedState(params) {
@@ -230,7 +316,7 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
230
316
  return acc;
231
317
  }, []);
232
318
  if (!filtered.length) return this;
233
- const merged = (0, import_yjs8.mergeUpdates)(filtered);
319
+ const merged = (0, import_yjs9.mergeUpdates)(filtered);
234
320
  return this.applyEncodedState({ origin, update: merged });
235
321
  }
236
322
  canRedo() {
@@ -251,7 +337,7 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
251
337
  return this._storage[type];
252
338
  }
253
339
  getEncodedState() {
254
- return (0, import_js_base64.fromUint8Array)((0, import_yjs8.encodeStateAsUpdate)(this.value));
340
+ return (0, import_js_base64.fromUint8Array)((0, import_yjs9.encodeStateAsUpdate)(this.value));
255
341
  }
256
342
  isEmpty() {
257
343
  return !this.value.share.size;
@@ -263,16 +349,16 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
263
349
  return this;
264
350
  }
265
351
  this._storage = Object.entries(reference).reduce((acc, [key, node]) => {
266
- if (node instanceof import_yjs8.Array) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getArray(key) });
267
- if (node instanceof import_yjs8.Map) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getMap(key) });
268
- if (node instanceof import_yjs8.Text) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getText(key) });
269
- if (node instanceof import_yjs8.XmlElement) {
352
+ if (node instanceof import_yjs9.XmlElement) {
270
353
  return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getXmlElement(key) });
271
354
  }
272
- if (node instanceof import_yjs8.XmlFragment) {
355
+ if (node instanceof import_yjs9.XmlFragment) {
273
356
  return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getXmlFragment(key) });
274
357
  }
275
- if (node instanceof import_yjs8.XmlText) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.get(key, import_yjs8.XmlText) });
358
+ if (node instanceof import_yjs9.XmlText) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.get(key, import_yjs9.XmlText) });
359
+ if (node instanceof import_yjs9.Array) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getArray(key) });
360
+ if (node instanceof import_yjs9.Map) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getMap(key) });
361
+ if (node instanceof import_yjs9.Text) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getText(key) });
276
362
  return acc;
277
363
  }, {});
278
364
  return this.track();
@@ -301,7 +387,7 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
301
387
  if (this._undoManager) this._undoManager.destroy();
302
388
  const sharedTypes = Object.values(this._storage).reduce(
303
389
  (acc, type) => {
304
- if (type instanceof import_yjs8.Array || type instanceof import_yjs8.Map || type instanceof import_yjs8.Text || type instanceof import_yjs8.XmlElement || type instanceof import_yjs8.XmlFragment || type instanceof import_yjs8.XmlText) {
390
+ if (type instanceof import_yjs9.Array || type instanceof import_yjs9.Map || type instanceof import_yjs9.Text || type instanceof import_yjs9.XmlElement || type instanceof import_yjs9.XmlFragment || type instanceof import_yjs9.XmlText) {
305
391
  acc.push(type);
306
392
  }
307
393
  return acc;
@@ -313,7 +399,7 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
313
399
  this._undoManager = null;
314
400
  return this;
315
401
  }
316
- this._undoManager = new import_yjs8.UndoManager(sharedTypes, { captureTimeout: MERGE_INTERVAL_MS });
402
+ this._undoManager = new import_yjs9.UndoManager(sharedTypes, { captureTimeout: MERGE_INTERVAL_MS });
317
403
  return this;
318
404
  }
319
405
  transact(fn) {
@@ -332,13 +418,19 @@ var CrdtYjsDoc = class extends import_crdt.AbstractCrdtDoc {
332
418
  (_a = this._undoManager) == null ? void 0 : _a.undo();
333
419
  return this;
334
420
  }
421
+ _warn(...data) {
422
+ var _a;
423
+ if (typeof process === "undefined") return;
424
+ if (((_a = process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
425
+ console.log(...data);
426
+ }
335
427
  };
336
428
 
337
429
  // src/doc/CrdtYjsDocFactory.ts
338
- var import_crdt2 = require("@pluv/crdt");
339
- var CrdtYjsDocFactory = class _CrdtYjsDocFactory extends import_crdt2.AbstractCrdtDocFactory {
430
+ var import_crdt = require("@pluv/crdt");
431
+ var CrdtYjsDocFactory = class _CrdtYjsDocFactory extends import_crdt.AbstractCrdtDocFactory {
340
432
  constructor(initialStorage = () => ({})) {
341
- super();
433
+ super(initialStorage);
342
434
  this._initialStorage = initialStorage;
343
435
  }
344
436
  getEmpty() {
@@ -348,8 +440,7 @@ var CrdtYjsDocFactory = class _CrdtYjsDocFactory extends import_crdt2.AbstractCr
348
440
  return new _CrdtYjsDocFactory(initialStorage != null ? initialStorage : this._initialStorage);
349
441
  }
350
442
  getInitialized(initialStorage) {
351
- var _a;
352
- return new CrdtYjsDoc((_a = initialStorage == null ? void 0 : initialStorage()) != null ? _a : this._initialStorage());
443
+ return new CrdtYjsDoc(initialStorage != null ? initialStorage : this._initialStorage);
353
444
  }
354
445
  };
355
446
 
package/dist/index.mjs CHANGED
@@ -55,17 +55,16 @@ var array = (value = []) => {
55
55
  };
56
56
 
57
57
  // src/doc/CrdtYjsDoc.ts
58
- import { AbstractCrdtDoc } from "@pluv/crdt";
59
58
  import { fromUint8Array, toUint8Array } from "js-base64";
60
59
  import {
61
60
  UndoManager,
62
- Array as YArray2,
63
- Doc as YDoc,
64
- Map as YMap3,
65
- Text as YText2,
66
- XmlElement as YXmlElement2,
67
- XmlFragment as YXmlFragment2,
68
- XmlText as YXmlText2,
61
+ Array as YArray3,
62
+ Doc as YDoc2,
63
+ Map as YMap4,
64
+ Text as YText3,
65
+ XmlElement as YXmlElement3,
66
+ XmlFragment as YXmlFragment3,
67
+ XmlText as YXmlText3,
69
68
  applyUpdate,
70
69
  encodeStateAsUpdate,
71
70
  mergeUpdates
@@ -107,6 +106,11 @@ var YjsText = class extends YText {
107
106
  }
108
107
  };
109
108
 
109
+ // src/utils/oneLine.ts
110
+ var oneLine = (strings, ...values) => {
111
+ return strings.map((str) => str.replace(/\s+/g, " ").trim()).reduce((acc, str, i) => acc + str + (i < values.length ? values[i] : ""), "").replace(/\s+/g, " ").trim();
112
+ };
113
+
110
114
  // src/xmlElement/YjsXmlElement.ts
111
115
  import { XmlElement as YXmlElement } from "yjs";
112
116
  var YjsXmlElement = class extends YXmlElement {
@@ -145,57 +149,141 @@ var YjsXmlText = class extends YXmlText {
145
149
  }
146
150
  };
147
151
 
152
+ // src/doc/builder.ts
153
+ import {
154
+ XmlText as YXmlText2
155
+ } from "yjs";
156
+ var builder = (doc2) => {
157
+ return {
158
+ array(name, value = []) {
159
+ const array2 = doc2.getArray(name);
160
+ if (!!value.length) array2.insert(0, value);
161
+ return array2;
162
+ },
163
+ map(name, value = []) {
164
+ const map2 = doc2.getMap(name);
165
+ value.forEach(([k, v]) => {
166
+ map2.set(k, v);
167
+ });
168
+ return map2;
169
+ },
170
+ text(name, value = "") {
171
+ const text2 = doc2.getText(name);
172
+ if (!!value) text2.insert(0, value);
173
+ return text2;
174
+ },
175
+ xmlElement(name, children = []) {
176
+ const xmlElement2 = doc2.getXmlElement(name);
177
+ if (!!children.length) xmlElement2.insert(0, children);
178
+ return xmlElement2;
179
+ },
180
+ xmlFragment(name, children = []) {
181
+ const xmlFragment2 = doc2.getXmlFragment(name);
182
+ if (!!children.length) xmlFragment2.insert(0, children);
183
+ return xmlFragment2;
184
+ },
185
+ xmlText(name) {
186
+ const xmlText2 = doc2.get(name, YXmlText2);
187
+ return xmlText2;
188
+ }
189
+ };
190
+ };
191
+
148
192
  // src/doc/CrdtYjsDoc.ts
149
193
  var MERGE_INTERVAL_MS = 1e3;
150
- var CrdtYjsDoc = class extends AbstractCrdtDoc {
151
- constructor(value = {}) {
152
- super();
153
- this.value = new YDoc();
194
+ var CrdtYjsDoc = class {
195
+ constructor(params = () => ({})) {
196
+ this.value = new YDoc2();
154
197
  this._undoManager = null;
155
- this._storage = Object.entries(value).reduce((acc, [key, node]) => {
198
+ const storage = params(builder(this.value));
199
+ const keys = this.value.share.keys().reduce((set, key) => set.add(key), /* @__PURE__ */ new Set());
200
+ this._storage = Object.entries(storage).reduce((acc, [key, node]) => {
156
201
  var _a, _b, _c, _d, _e, _f, _g, _h;
202
+ if (keys.has(key)) return __spreadProps(__spreadValues({}, acc), { [key]: node });
203
+ if (node instanceof YjsXmlElement) {
204
+ this._warn(oneLine`
205
+ Warning: You are using \`yjs.xmlElement\` to declare top-level storage value \`${key}\`.
206
+ Adding top-level values this way has been deprecated, to be removed in v2.
207
+ Please follow the v2 migration guide to declare top-level types correctly:
208
+ https://pluv.io/docs/migration-guides/v2
209
+ `);
210
+ const yXmlElement = this.value.getXmlElement(key);
211
+ if (!!((_a = node.initialValue) == null ? void 0 : _a.length)) {
212
+ yXmlElement.insert(0, (_b = node.initialValue) == null ? void 0 : _b.slice(0));
213
+ }
214
+ return __spreadProps(__spreadValues({}, acc), { [key]: yXmlElement });
215
+ }
216
+ if (node instanceof YjsXmlFragment) {
217
+ this._warn(oneLine`
218
+ Warning: You are using \`yjs.xmlFragment\` to declare top-level storage value \`${key}\`.
219
+ Adding top-level values this way has been deprecated, to be removed in v2.
220
+ Please follow the v2 migration guide to declare top-level types correctly:
221
+ https://pluv.io/docs/migration-guides/v2
222
+ `);
223
+ const yXmlFragment = this.value.getXmlFragment(key);
224
+ if (!!((_c = node.initialValue) == null ? void 0 : _c.length)) {
225
+ yXmlFragment.insert(0, (_d = node.initialValue) == null ? void 0 : _d.slice(0));
226
+ }
227
+ return __spreadProps(__spreadValues({}, acc), { [key]: yXmlFragment });
228
+ }
229
+ if (node instanceof YjsXmlText) {
230
+ this._warn(oneLine`
231
+ Warning: You are using \`yjs.xmlText\` to declare top-level storage value \`${key}\`.
232
+ Adding top-level values this way has been deprecated, to be removed in v2.
233
+ Please follow the v2 migration guide to declare top-level types correctly:
234
+ https://pluv.io/docs/migration-guides/v2
235
+ `);
236
+ const yXmlText = this.value.get(key, YXmlText3);
237
+ return __spreadProps(__spreadValues({}, acc), { [key]: yXmlText });
238
+ }
157
239
  if (node instanceof YjsArray) {
240
+ this._warn(oneLine`
241
+ Warning: You are using \`yjs.array\` to declare top-level storage value \`${key}\`.
242
+ Adding top-level values this way has been deprecated, to be removed in v2.
243
+ Please follow the v2 migration guide to declare top-level types correctly:
244
+ https://pluv.io/docs/migration-guides/v2
245
+ `);
158
246
  const yArray = this.value.getArray(key);
159
- if (!!((_a = node.initialValue) == null ? void 0 : _a.length)) yArray.insert(0, (_b = node.initialValue) == null ? void 0 : _b.slice(0));
247
+ if (!!((_e = node.initialValue) == null ? void 0 : _e.length)) yArray.insert(0, (_f = node.initialValue) == null ? void 0 : _f.slice(0));
160
248
  return __spreadProps(__spreadValues({}, acc), { [key]: yArray });
161
249
  }
162
250
  if (node instanceof YjsMap) {
251
+ this._warn(oneLine`
252
+ Warning: You are using \`yjs.map\` to declare top-level storage value \`${key}\`.
253
+ Adding top-level values this way has been deprecated, to be removed in v2.
254
+ Please follow the v2 migration guide to declare top-level types correctly:
255
+ https://pluv.io/docs/migration-guides/v2
256
+ `);
163
257
  const yMap = this.value.getMap(key);
164
- ((_c = node.initialValue) != null ? _c : []).forEach(([k, v]) => {
258
+ ((_g = node.initialValue) != null ? _g : []).forEach(([k, v]) => {
165
259
  yMap.set(k.toString(), v);
166
260
  });
167
261
  return __spreadProps(__spreadValues({}, acc), { [key]: yMap });
168
262
  }
169
263
  if (node instanceof YjsObject) {
264
+ this._warn(oneLine`
265
+ Warning: You are using \`yjs.object\` to declare top-level storage value \`${key}\`.
266
+ Adding top-level values this way has been deprecated, to be removed in v2.
267
+ Please follow the v2 migration guide to declare top-level types correctly:
268
+ https://pluv.io/docs/migration-guides/v2
269
+ `);
170
270
  const yMap = this.value.getMap(key);
171
- Object.entries((_d = node.initialValue) != null ? _d : {}).forEach(([k, v]) => {
271
+ Object.entries((_h = node.initialValue) != null ? _h : {}).forEach(([k, v]) => {
172
272
  yMap.set(k.toString(), v);
173
273
  });
174
274
  return __spreadProps(__spreadValues({}, acc), { [key]: yMap });
175
275
  }
176
276
  if (node instanceof YjsText) {
277
+ this._warn(oneLine`
278
+ Warning: You are using \`yjs.text\` to declare top-level storage value \`${key}\`.
279
+ Adding top-level values this way has been deprecated, to be removed in v2.
280
+ Please follow the v2 migration guide to declare top-level types correctly:
281
+ https://pluv.io/docs/migration-guides/v2
282
+ `);
177
283
  const yText = this.value.getText(key);
178
284
  if (typeof node.initialValue === "string") yText.insert(0, node.initialValue);
179
285
  return __spreadProps(__spreadValues({}, acc), { [key]: yText });
180
286
  }
181
- if (node instanceof YjsXmlElement) {
182
- const yXmlElement = this.value.getXmlElement(key);
183
- if (!!((_e = node.initialValue) == null ? void 0 : _e.length)) {
184
- yXmlElement.insert(0, (_f = node.initialValue) == null ? void 0 : _f.slice(0));
185
- }
186
- return __spreadProps(__spreadValues({}, acc), { [key]: yXmlElement });
187
- }
188
- if (node instanceof YjsXmlFragment) {
189
- const yXmlFragment = this.value.getXmlFragment(key);
190
- if (!!((_g = node.initialValue) == null ? void 0 : _g.length)) {
191
- yXmlFragment.insert(0, (_h = node.initialValue) == null ? void 0 : _h.slice(0));
192
- }
193
- return __spreadProps(__spreadValues({}, acc), { [key]: yXmlFragment });
194
- }
195
- if (node instanceof YjsXmlText) {
196
- const yXmlText = this.value.get(key, YXmlText2);
197
- return __spreadProps(__spreadValues({}, acc), { [key]: yXmlText });
198
- }
199
287
  return acc;
200
288
  }, {});
201
289
  }
@@ -256,16 +344,16 @@ var CrdtYjsDoc = class extends AbstractCrdtDoc {
256
344
  return this;
257
345
  }
258
346
  this._storage = Object.entries(reference).reduce((acc, [key, node]) => {
259
- if (node instanceof YArray2) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getArray(key) });
260
- if (node instanceof YMap3) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getMap(key) });
261
- if (node instanceof YText2) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getText(key) });
262
- if (node instanceof YXmlElement2) {
347
+ if (node instanceof YXmlElement3) {
263
348
  return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getXmlElement(key) });
264
349
  }
265
- if (node instanceof YXmlFragment2) {
350
+ if (node instanceof YXmlFragment3) {
266
351
  return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getXmlFragment(key) });
267
352
  }
268
- if (node instanceof YXmlText2) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.get(key, YXmlText2) });
353
+ if (node instanceof YXmlText3) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.get(key, YXmlText3) });
354
+ if (node instanceof YArray3) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getArray(key) });
355
+ if (node instanceof YMap4) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getMap(key) });
356
+ if (node instanceof YText3) return __spreadProps(__spreadValues({}, acc), { [key]: this.value.getText(key) });
269
357
  return acc;
270
358
  }, {});
271
359
  return this.track();
@@ -294,7 +382,7 @@ var CrdtYjsDoc = class extends AbstractCrdtDoc {
294
382
  if (this._undoManager) this._undoManager.destroy();
295
383
  const sharedTypes = Object.values(this._storage).reduce(
296
384
  (acc, type) => {
297
- if (type instanceof YArray2 || type instanceof YMap3 || type instanceof YText2 || type instanceof YXmlElement2 || type instanceof YXmlFragment2 || type instanceof YXmlText2) {
385
+ if (type instanceof YArray3 || type instanceof YMap4 || type instanceof YText3 || type instanceof YXmlElement3 || type instanceof YXmlFragment3 || type instanceof YXmlText3) {
298
386
  acc.push(type);
299
387
  }
300
388
  return acc;
@@ -325,13 +413,19 @@ var CrdtYjsDoc = class extends AbstractCrdtDoc {
325
413
  (_a = this._undoManager) == null ? void 0 : _a.undo();
326
414
  return this;
327
415
  }
416
+ _warn(...data) {
417
+ var _a;
418
+ if (typeof process === "undefined") return;
419
+ if (((_a = process.env) == null ? void 0 : _a.NODE_ENV) === "production") return;
420
+ console.log(...data);
421
+ }
328
422
  };
329
423
 
330
424
  // src/doc/CrdtYjsDocFactory.ts
331
425
  import { AbstractCrdtDocFactory } from "@pluv/crdt";
332
426
  var CrdtYjsDocFactory = class _CrdtYjsDocFactory extends AbstractCrdtDocFactory {
333
427
  constructor(initialStorage = () => ({})) {
334
- super();
428
+ super(initialStorage);
335
429
  this._initialStorage = initialStorage;
336
430
  }
337
431
  getEmpty() {
@@ -341,8 +435,7 @@ var CrdtYjsDocFactory = class _CrdtYjsDocFactory extends AbstractCrdtDocFactory
341
435
  return new _CrdtYjsDocFactory(initialStorage != null ? initialStorage : this._initialStorage);
342
436
  }
343
437
  getInitialized(initialStorage) {
344
- var _a;
345
- return new CrdtYjsDoc((_a = initialStorage == null ? void 0 : initialStorage()) != null ? _a : this._initialStorage());
438
+ return new CrdtYjsDoc(initialStorage != null ? initialStorage : this._initialStorage);
346
439
  }
347
440
  };
348
441
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pluv/crdt-yjs",
3
- "version": "1.0.1",
3
+ "version": "2.0.0",
4
4
  "description": "yjs for @pluv/io",
5
5
  "author": "leedavidcs",
6
6
  "license": "MIT",
@@ -18,19 +18,20 @@
18
18
  },
19
19
  "dependencies": {
20
20
  "js-base64": "^3.7.7",
21
- "@pluv/crdt": "^1.0.1",
22
- "@pluv/types": "^1.0.1"
21
+ "@pluv/crdt": "^2.0.0",
22
+ "@pluv/types": "^2.0.0"
23
23
  },
24
24
  "peerDependencies": {
25
25
  "yjs": "^13.0.0"
26
26
  },
27
27
  "devDependencies": {
28
+ "@types/node": "^22.15.3",
28
29
  "eslint": "^9.25.1",
29
30
  "tsup": "^8.4.0",
30
31
  "typescript": "^5.8.3",
31
32
  "yjs": "^13.6.26",
32
- "@pluv/tsconfig": "^1.0.1",
33
- "eslint-config-pluv": "^1.0.1"
33
+ "@pluv/tsconfig": "^2.0.0",
34
+ "eslint-config-pluv": "^2.0.0"
34
35
  },
35
36
  "scripts": {
36
37
  "build": "tsup src/index.ts --format esm,cjs --dts",
@@ -4,7 +4,7 @@ import type {
4
4
  DocSubscribeCallbackParams,
5
5
  InferCrdtJson,
6
6
  } from "@pluv/crdt";
7
- import { AbstractCrdtDoc } from "@pluv/crdt";
7
+ import type { CrdtDocLike } from "@pluv/types";
8
8
  import { fromUint8Array, toUint8Array } from "js-base64";
9
9
  import {
10
10
  AbstractType,
@@ -25,25 +25,100 @@ import { YjsMap } from "../map/YjsMap";
25
25
  import { YjsObject } from "../object/YjsObject";
26
26
  import { YjsText } from "../text/YjsText";
27
27
  import type { YjsType } from "../types";
28
+ import { oneLine } from "../utils";
28
29
  import { YjsXmlElement } from "../xmlElement/YjsXmlElement";
29
30
  import { YjsXmlFragment } from "../xmlFragment/YjsXmlFragment";
30
31
  import { YjsXmlText } from "../xmlText/YjsXmlText";
32
+ import type { YjsBuilder } from "./builder";
33
+ import { builder } from "./builder";
31
34
 
32
35
  const MERGE_INTERVAL_MS = 1_000;
33
36
 
34
- export class CrdtYjsDoc<
35
- TStorage extends Record<string, YjsType<any, any>>,
36
- > extends AbstractCrdtDoc<TStorage> {
37
+ export type CrdtYjsDocParams<TStorage extends Record<string, YjsType<any, any>>> = (
38
+ builder: YjsBuilder,
39
+ ) => TStorage;
40
+
41
+ export class CrdtYjsDoc<TStorage extends Record<string, YjsType<any, any>>>
42
+ implements CrdtDocLike<TStorage>
43
+ {
37
44
  public value: YDoc = new YDoc();
38
45
 
39
46
  private _storage: TStorage;
40
47
  private _undoManager: UndoManager | null = null;
41
48
 
42
- constructor(value: TStorage = {} as TStorage) {
43
- super();
49
+ constructor(params: CrdtYjsDocParams<TStorage> = () => ({}) as TStorage) {
50
+ const storage = params(builder(this.value));
51
+ const keys = this.value.share.keys().reduce((set, key) => set.add(key), new Set<string>());
52
+
53
+ this._storage = Object.entries(storage).reduce((acc, [key, node]) => {
54
+ /**
55
+ * @description These are all shared types that we declared directly on the root
56
+ * document. So we're going to store these on the storage type directly.
57
+ * @date May 8, 2025
58
+ */
59
+ if (keys.has(key)) return { ...acc, [key]: node };
60
+
61
+ /**
62
+ * @description It is important that the XML shared-types be checked before the others
63
+ * because they extend off the non-xml types (thereby you can mistakenly identify the
64
+ * wrong type if checked in the reverse order)
65
+ * @date May 9 ,2025
66
+ */
67
+ if (node instanceof YjsXmlElement) {
68
+ this._warn(oneLine`
69
+ Warning: You are using \`yjs.xmlElement\` to declare top-level storage value \`${key}\`.
70
+ Adding top-level values this way has been deprecated, to be removed in v2.
71
+ Please follow the v2 migration guide to declare top-level types correctly:
72
+ https://pluv.io/docs/migration-guides/v2
73
+ `);
74
+
75
+ const yXmlElement = this.value.getXmlElement(key);
76
+
77
+ if (!!node.initialValue?.length) {
78
+ yXmlElement.insert(0, node.initialValue?.slice(0));
79
+ }
80
+
81
+ return { ...acc, [key]: yXmlElement };
82
+ }
83
+
84
+ if (node instanceof YjsXmlFragment) {
85
+ this._warn(oneLine`
86
+ Warning: You are using \`yjs.xmlFragment\` to declare top-level storage value \`${key}\`.
87
+ Adding top-level values this way has been deprecated, to be removed in v2.
88
+ Please follow the v2 migration guide to declare top-level types correctly:
89
+ https://pluv.io/docs/migration-guides/v2
90
+ `);
91
+
92
+ const yXmlFragment = this.value.getXmlFragment(key);
93
+
94
+ if (!!node.initialValue?.length) {
95
+ yXmlFragment.insert(0, node.initialValue?.slice(0));
96
+ }
97
+
98
+ return { ...acc, [key]: yXmlFragment };
99
+ }
100
+
101
+ if (node instanceof YjsXmlText) {
102
+ this._warn(oneLine`
103
+ Warning: You are using \`yjs.xmlText\` to declare top-level storage value \`${key}\`.
104
+ Adding top-level values this way has been deprecated, to be removed in v2.
105
+ Please follow the v2 migration guide to declare top-level types correctly:
106
+ https://pluv.io/docs/migration-guides/v2
107
+ `);
108
+
109
+ const yXmlText = this.value.get(key, YXmlText) as YXmlText;
110
+
111
+ return { ...acc, [key]: yXmlText };
112
+ }
44
113
 
45
- this._storage = Object.entries(value).reduce((acc, [key, node]) => {
46
114
  if (node instanceof YjsArray) {
115
+ this._warn(oneLine`
116
+ Warning: You are using \`yjs.array\` to declare top-level storage value \`${key}\`.
117
+ Adding top-level values this way has been deprecated, to be removed in v2.
118
+ Please follow the v2 migration guide to declare top-level types correctly:
119
+ https://pluv.io/docs/migration-guides/v2
120
+ `);
121
+
47
122
  const yArray = this.value.getArray(key);
48
123
 
49
124
  if (!!node.initialValue?.length) yArray.insert(0, node.initialValue?.slice(0));
@@ -52,6 +127,13 @@ export class CrdtYjsDoc<
52
127
  }
53
128
 
54
129
  if (node instanceof YjsMap) {
130
+ this._warn(oneLine`
131
+ Warning: You are using \`yjs.map\` to declare top-level storage value \`${key}\`.
132
+ Adding top-level values this way has been deprecated, to be removed in v2.
133
+ Please follow the v2 migration guide to declare top-level types correctly:
134
+ https://pluv.io/docs/migration-guides/v2
135
+ `);
136
+
55
137
  const yMap = this.value.getMap(key);
56
138
 
57
139
  (node.initialValue ?? []).forEach(([k, v]) => {
@@ -62,6 +144,13 @@ export class CrdtYjsDoc<
62
144
  }
63
145
 
64
146
  if (node instanceof YjsObject) {
147
+ this._warn(oneLine`
148
+ Warning: You are using \`yjs.object\` to declare top-level storage value \`${key}\`.
149
+ Adding top-level values this way has been deprecated, to be removed in v2.
150
+ Please follow the v2 migration guide to declare top-level types correctly:
151
+ https://pluv.io/docs/migration-guides/v2
152
+ `);
153
+
65
154
  const yMap = this.value.getMap(key);
66
155
 
67
156
  Object.entries(node.initialValue ?? {}).forEach(([k, v]) => {
@@ -72,6 +161,13 @@ export class CrdtYjsDoc<
72
161
  }
73
162
 
74
163
  if (node instanceof YjsText) {
164
+ this._warn(oneLine`
165
+ Warning: You are using \`yjs.text\` to declare top-level storage value \`${key}\`.
166
+ Adding top-level values this way has been deprecated, to be removed in v2.
167
+ Please follow the v2 migration guide to declare top-level types correctly:
168
+ https://pluv.io/docs/migration-guides/v2
169
+ `);
170
+
75
171
  const yText = this.value.getText(key);
76
172
 
77
173
  if (typeof node.initialValue === "string") yText.insert(0, node.initialValue);
@@ -79,32 +175,6 @@ export class CrdtYjsDoc<
79
175
  return { ...acc, [key]: yText };
80
176
  }
81
177
 
82
- if (node instanceof YjsXmlElement) {
83
- const yXmlElement = this.value.getXmlElement(key);
84
-
85
- if (!!node.initialValue?.length) {
86
- yXmlElement.insert(0, node.initialValue?.slice(0));
87
- }
88
-
89
- return { ...acc, [key]: yXmlElement };
90
- }
91
-
92
- if (node instanceof YjsXmlFragment) {
93
- const yXmlFragment = this.value.getXmlFragment(key);
94
-
95
- if (!!node.initialValue?.length) {
96
- yXmlFragment.insert(0, node.initialValue?.slice(0));
97
- }
98
-
99
- return { ...acc, [key]: yXmlFragment };
100
- }
101
-
102
- if (node instanceof YjsXmlText) {
103
- const yXmlText = this.value.get(key, YXmlText) as YXmlText;
104
-
105
- return { ...acc, [key]: yXmlText };
106
- }
107
-
108
178
  return acc;
109
179
  }, {} as TStorage);
110
180
  }
@@ -186,9 +256,12 @@ export class CrdtYjsDoc<
186
256
  }
187
257
 
188
258
  this._storage = Object.entries(reference).reduce((acc, [key, node]) => {
189
- if (node instanceof YArray) return { ...acc, [key]: this.value.getArray(key) };
190
- if (node instanceof YMap) return { ...acc, [key]: this.value.getMap(key) };
191
- if (node instanceof YText) return { ...acc, [key]: this.value.getText(key) };
259
+ /**
260
+ * @description It is important that the XML shared-types be checked before the others
261
+ * because they extend off the non-xml types (thereby you can mistakenly identify the
262
+ * wrong type if checked in the reverse order)
263
+ * @date May 9 ,2025
264
+ */
192
265
  if (node instanceof YXmlElement) {
193
266
  return { ...acc, [key]: this.value.getXmlElement(key) };
194
267
  }
@@ -196,6 +269,9 @@ export class CrdtYjsDoc<
196
269
  return { ...acc, [key]: this.value.getXmlFragment(key) };
197
270
  }
198
271
  if (node instanceof YXmlText) return { ...acc, [key]: this.value.get(key, YXmlText) };
272
+ if (node instanceof YArray) return { ...acc, [key]: this.value.getArray(key) };
273
+ if (node instanceof YMap) return { ...acc, [key]: this.value.getMap(key) };
274
+ if (node instanceof YText) return { ...acc, [key]: this.value.getText(key) };
199
275
 
200
276
  return acc;
201
277
  }, {} as TStorage);
@@ -281,4 +357,10 @@ export class CrdtYjsDoc<
281
357
 
282
358
  return this;
283
359
  }
360
+
361
+ private _warn(...data: any[]) {
362
+ if (typeof process === "undefined") return;
363
+ if (process.env?.NODE_ENV === "production") return;
364
+ console.log(...data);
365
+ }
284
366
  }
@@ -1,28 +1,15 @@
1
1
  import { AbstractCrdtDocFactory } from "@pluv/crdt";
2
- import { XmlFragment as YXmlFragment } from "yjs";
3
- import { array } from "../array";
4
- import { YjsArray } from "../array/YjsArray";
5
- import { map } from "../map";
6
- import { YjsMap } from "../map/YjsMap";
7
- import { object } from "../object";
8
- import { YjsObject } from "../object/YjsObject";
9
- import { text } from "../text";
10
- import { YjsText } from "../text/YjsText";
11
2
  import type { YjsType } from "../types";
12
- import { xmlElement } from "../xmlElement";
13
- import { YjsXmlElement } from "../xmlElement/YjsXmlElement";
14
- import { xmlFragment } from "../xmlFragment";
15
- import { xmlText } from "../xmlText";
16
- import { YjsXmlText } from "../xmlText/YjsXmlText";
17
3
  import { CrdtYjsDoc } from "./CrdtYjsDoc";
4
+ import type { YjsBuilder } from "./builder";
18
5
 
19
6
  export class CrdtYjsDocFactory<
20
- TStorage extends Record<string, YjsType<any, any>>,
7
+ TStorage extends Record<string, YjsType<any, any>> = {},
21
8
  > extends AbstractCrdtDocFactory<TStorage> {
22
- private _initialStorage: () => TStorage;
9
+ public readonly _initialStorage: (builder: YjsBuilder) => TStorage;
23
10
 
24
- constructor(initialStorage: () => TStorage = () => ({}) as TStorage) {
25
- super();
11
+ constructor(initialStorage: (builder: YjsBuilder) => TStorage = () => ({}) as TStorage) {
12
+ super(initialStorage);
26
13
 
27
14
  this._initialStorage = initialStorage;
28
15
  }
@@ -31,11 +18,15 @@ export class CrdtYjsDocFactory<
31
18
  return new CrdtYjsDoc<TStorage>();
32
19
  }
33
20
 
34
- public getFactory(initialStorage?: (() => TStorage) | undefined): CrdtYjsDocFactory<TStorage> {
21
+ public getFactory(
22
+ initialStorage: (builder: YjsBuilder) => TStorage,
23
+ ): CrdtYjsDocFactory<TStorage> {
35
24
  return new CrdtYjsDocFactory<TStorage>(initialStorage ?? this._initialStorage);
36
25
  }
37
26
 
38
- public getInitialized(initialStorage?: () => TStorage): CrdtYjsDoc<TStorage> {
39
- return new CrdtYjsDoc<TStorage>(initialStorage?.() ?? this._initialStorage());
27
+ public getInitialized(
28
+ initialStorage?: (builder: YjsBuilder) => TStorage,
29
+ ): CrdtYjsDoc<TStorage> {
30
+ return new CrdtYjsDoc<TStorage>(initialStorage ?? this._initialStorage);
40
31
  }
41
32
  }
@@ -0,0 +1,71 @@
1
+ import {
2
+ Array as YArray,
3
+ Doc as YDoc,
4
+ Map as YMap,
5
+ Text as YText,
6
+ XmlElement as YXmlElement,
7
+ XmlFragment as YXmlFragment,
8
+ XmlText as YXmlText,
9
+ } from "yjs";
10
+ import { YjsType } from "../types";
11
+
12
+ export type YjsBuilder = ReturnType<typeof builder>;
13
+
14
+ export const builder = (doc: YDoc) => {
15
+ return {
16
+ array<T extends unknown>(
17
+ name: string,
18
+ value: T[] | readonly T[] = [],
19
+ ): YjsType<YArray<T>, T[]> {
20
+ const array = doc.getArray<T>(name);
21
+
22
+ if (!!value.length) array.insert(0, value as T[]);
23
+
24
+ return array as unknown as YjsType<YArray<T>, T[]>;
25
+ },
26
+ map<T extends unknown>(
27
+ name: string,
28
+ value: readonly (readonly [key: string, value: T])[] = [],
29
+ ): YjsType<YMap<T>, Record<string, T>> {
30
+ const map = doc.getMap(name);
31
+
32
+ value.forEach(([k, v]) => {
33
+ map.set(k, v);
34
+ });
35
+
36
+ return map as unknown as YjsType<YMap<T>, Record<string, T>>;
37
+ },
38
+ text(name: string, value: string = ""): YjsType<YText, string> {
39
+ const text = doc.getText(name);
40
+
41
+ if (!!value) text.insert(0, value);
42
+
43
+ return text as unknown as YjsType<YText, string>;
44
+ },
45
+ xmlElement(
46
+ name: string,
47
+ children: (YXmlElement | YXmlText)[] | readonly (YXmlElement | YXmlText)[] = [],
48
+ ): YjsType<YXmlElement, string> {
49
+ const xmlElement = doc.getXmlElement(name);
50
+
51
+ if (!!children.length) xmlElement.insert(0, children as (YXmlElement | YXmlText)[]);
52
+
53
+ return xmlElement as unknown as YjsType<YXmlElement, string>;
54
+ },
55
+ xmlFragment(
56
+ name: string,
57
+ children: (YXmlElement | YXmlText)[] | readonly (YXmlElement | YXmlText)[] = [],
58
+ ): YjsType<YXmlFragment, string> {
59
+ const xmlFragment = doc.getXmlFragment(name);
60
+
61
+ if (!!children.length) xmlFragment.insert(0, children as (YXmlElement | YXmlText)[]);
62
+
63
+ return xmlFragment as unknown as YjsType<YXmlFragment, string>;
64
+ },
65
+ xmlText(name: string): YjsType<YXmlText, string> {
66
+ const xmlText = doc.get(name, YXmlText);
67
+
68
+ return xmlText as unknown as YjsType<YXmlText, string>;
69
+ },
70
+ };
71
+ };
package/src/doc/doc.ts CHANGED
@@ -1,8 +1,9 @@
1
1
  import type { YjsType } from "../types";
2
+ import type { YjsBuilder } from "./builder";
2
3
  import { CrdtYjsDocFactory } from "./CrdtYjsDocFactory";
3
4
 
4
5
  export const doc = <TStorage extends Record<string, YjsType<any, any>>>(
5
- value: () => TStorage = () => ({}) as TStorage,
6
+ value: (buidler: YjsBuilder) => TStorage = () => ({}) as TStorage,
6
7
  ): CrdtYjsDocFactory<TStorage> => {
7
8
  return new CrdtYjsDocFactory<TStorage>(value);
8
9
  };
package/src/doc/index.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export type { YjsBuilder } from "./builder";
1
2
  export { CrdtYjsDoc } from "./CrdtYjsDoc";
2
3
  export { CrdtYjsDocFactory } from "./CrdtYjsDocFactory";
3
4
  export { doc } from "./doc";
@@ -2,6 +2,11 @@ import type { Map as YMap } from "yjs";
2
2
  import type { YjsType } from "../types";
3
3
  import { YjsObject } from "./YjsObject";
4
4
 
5
+ /**
6
+ * @deprecated This will be removed in v2.0.0. Use yjs.map instead
7
+ * @description Creates a Yjs map, but declare it like it's an object
8
+ * @date May 8, 2025
9
+ */
5
10
  export const object = <T extends Record<string, any>>(
6
11
  value: T = {} as T,
7
12
  ): YjsType<YMap<T[keyof T]>, T> => {
@@ -0,0 +1 @@
1
+ export { oneLine } from "./oneLine";
@@ -0,0 +1,7 @@
1
+ export const oneLine = (strings: TemplateStringsArray, ...values: unknown[]): string => {
2
+ return strings
3
+ .map((str) => str.replace(/\s+/g, " ").trim())
4
+ .reduce((acc, str, i) => acc + str + (i < values.length ? values[i] : ""), "")
5
+ .replace(/\s+/g, " ")
6
+ .trim();
7
+ };
package/src/yjs.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export { array } from "./array";
2
2
  export { doc } from "./doc";
3
+ export type { YjsBuilder } from "./doc";
3
4
  export { map } from "./map";
4
5
  export { object } from "./object";
5
6
  export { text } from "./text";