@pluv/crdt-yjs 0.0.0-canary-20261027014949
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.
- package/LICENSE +21 -0
- package/README.md +18 -0
- package/dist/index.d.mts +182 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +691 -0
- package/dist/index.mjs.map +1 -0
- package/dist/rolldown-runtime-D8jQpDG7.mjs +12 -0
- package/package.json +55 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Shoubhit Dash
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
## `@pluv/crdt-yjs`
|
|
2
|
+
|
|
3
|
+
> Yjs adapter for [@pluv/client](https://www.npmjs.com/package/@pluv/client) and [@pluv/io](https://www.npmjs.com/package/@pluv/io).
|
|
4
|
+
|
|
5
|
+
**👉 See full documentation on [docs.pluv.io](https://docs.pluv.io/docs). 👈**
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# npm
|
|
11
|
+
npm install @pluv/crdt-yjs yjs
|
|
12
|
+
|
|
13
|
+
# yarn
|
|
14
|
+
yarn add @pluv/crdt-yjs yjs
|
|
15
|
+
|
|
16
|
+
# pnpm
|
|
17
|
+
pnpm add @pluv/crdt-yjs yjs
|
|
18
|
+
```
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { Array, Doc, Map as Map$1, Text, XmlElement, XmlFragment, XmlText } from "yjs";
|
|
2
|
+
import { ObservableV2 } from "lib0/observable";
|
|
3
|
+
import { AbstractCrdtDocFactory, AnySchemaNode, DocApplyEncodedStateParams, DocBatchApplyEncodedStateParams, DocSubscribeCallbackParams, InferNodeJson, InferNodeSeed, InferNodeStorage, InferShapeJson, InferShapeSeed, InferShapeStorage, SchemaAst, SchemaNode } from "@pluv/crdt";
|
|
4
|
+
import { CrdtDocLike, IOLike, RoomLike } from "@pluv/types";
|
|
5
|
+
declare const array: <T extends unknown>(value?: T[] | readonly T[]) => Array<T>;
|
|
6
|
+
type YjsAwarenessUpdate = {
|
|
7
|
+
added: number[];
|
|
8
|
+
updated: number[];
|
|
9
|
+
removed: number[];
|
|
10
|
+
};
|
|
11
|
+
type YjsProviderStatus = "connecting" | "connected" | "disconnected";
|
|
12
|
+
interface MetaClientState {
|
|
13
|
+
clock: number;
|
|
14
|
+
lastUpdated: number;
|
|
15
|
+
}
|
|
16
|
+
type AwarenessPresence<TPresence extends Record<string, any>, TField extends keyof TPresence | null> = TField extends null ? TPresence : TField extends keyof TPresence ? TPresence[TField] : never;
|
|
17
|
+
interface PluvYjsAwarenessParams<TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, any>, TField extends keyof TPresence | null = null> {
|
|
18
|
+
presenceField?: TField;
|
|
19
|
+
room: RoomLike<TIO, Doc, TPresence, TStorage>;
|
|
20
|
+
}
|
|
21
|
+
declare class PluvYjsAwareness<TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, any>, TField extends keyof TPresence | null = null> extends ObservableV2<{
|
|
22
|
+
change: (updates: YjsAwarenessUpdate, kind: "presence") => void;
|
|
23
|
+
destroy: (awareness: PluvYjsAwareness<TIO, TPresence, TStorage, TField>) => void;
|
|
24
|
+
update: (updates: YjsAwarenessUpdate, kind: "local" | "presence") => void;
|
|
25
|
+
}> {
|
|
26
|
+
readonly doc: Doc;
|
|
27
|
+
private readonly _field;
|
|
28
|
+
private readonly _idMap;
|
|
29
|
+
private readonly _room;
|
|
30
|
+
private readonly _unsubscribe;
|
|
31
|
+
get clientID(): number;
|
|
32
|
+
get states(): Map<number, TPresence>;
|
|
33
|
+
constructor(params: PluvYjsAwarenessParams<TIO, TPresence, TStorage, TField>);
|
|
34
|
+
destroy(): void;
|
|
35
|
+
getLocalState(): AwarenessPresence<TPresence, TField>;
|
|
36
|
+
setLocalState(state: AwarenessPresence<TPresence, TField>): void;
|
|
37
|
+
setLocalStateField<TLocalField extends keyof AwarenessPresence<TPresence, TField>>(field: TLocalField, value: AwarenessPresence<TPresence, TField>[TLocalField]): void;
|
|
38
|
+
/**
|
|
39
|
+
* !HACK
|
|
40
|
+
* @description We're building the awareness presences from the states stored on the room's
|
|
41
|
+
* presense instead of using the map defined in the awareness interface.
|
|
42
|
+
* @see https://github.com/yjs/y-protocols/blob/master/awareness.js
|
|
43
|
+
* @date May 13, 2025
|
|
44
|
+
*/
|
|
45
|
+
getStates(): Map<number, AwarenessPresence<TPresence, TField>>;
|
|
46
|
+
private _adaptPresence;
|
|
47
|
+
private _deriveUpdates;
|
|
48
|
+
private _resetIdMap;
|
|
49
|
+
/**
|
|
50
|
+
* !HACK
|
|
51
|
+
* @description We dgaf about these. We're just mirroring the fields that exist in the
|
|
52
|
+
* og awareness to make sure everything aligns.
|
|
53
|
+
* @see https://github.com/yjs/y-protocols/blob/master/awareness.js
|
|
54
|
+
* @date May 13, 2025
|
|
55
|
+
*/
|
|
56
|
+
readonly meta: Map<any, MetaClientState>;
|
|
57
|
+
readonly _checkInterval: number;
|
|
58
|
+
}
|
|
59
|
+
declare const awareness: <TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, any>, TField extends keyof TPresence | null = null>(params: PluvYjsAwarenessParams<TIO, TPresence, TStorage, TField>) => PluvYjsAwareness<TIO, TPresence, TStorage, TField>;
|
|
60
|
+
declare class YjsSchema<TShape extends Record<string, AnySchemaNode> = Record<string, AnySchemaNode>> extends AbstractCrdtDocFactory<Doc, InferShapeStorage<TShape>, InferShapeJson<TShape>, InferShapeSeed<TShape>> {
|
|
61
|
+
readonly kind: "y.doc";
|
|
62
|
+
readonly shape: TShape;
|
|
63
|
+
readonly _seed?: InferShapeSeed<TShape>;
|
|
64
|
+
constructor(shape: TShape, seed?: InferShapeSeed<TShape>);
|
|
65
|
+
toJSON(): {
|
|
66
|
+
kind: "y.doc";
|
|
67
|
+
shape: Record<string, unknown>;
|
|
68
|
+
};
|
|
69
|
+
getEmpty(): CrdtYjsDoc<YjsSchema<TShape>>;
|
|
70
|
+
getFactory(seed?: InferShapeSeed<TShape>): YjsSchema<TShape>;
|
|
71
|
+
getInitialized(seed?: InferShapeSeed<TShape>): CrdtYjsDoc<YjsSchema<TShape>>;
|
|
72
|
+
}
|
|
73
|
+
type InferYjsStorage<TSchema extends YjsSchema<any>> = InferShapeStorage<TSchema["shape"]>;
|
|
74
|
+
type InferYjsJson<TSchema extends YjsSchema<any>> = InferShapeJson<TSchema["shape"]>;
|
|
75
|
+
declare function schema<TShape extends Record<string, AnySchemaNode>>(shape: TShape): YjsSchema<TShape>;
|
|
76
|
+
declare namespace schema {
|
|
77
|
+
var fromJSON: (ast: SchemaAst) => YjsSchema;
|
|
78
|
+
}
|
|
79
|
+
declare class CrdtYjsDoc<TSchema extends YjsSchema = YjsSchema> implements CrdtDocLike<Doc, InferYjsStorage<TSchema>, InferYjsJson<TSchema>> {
|
|
80
|
+
#private;
|
|
81
|
+
value: Doc;
|
|
82
|
+
constructor(schema: TSchema, seed?: Record<string, unknown>, hydrate?: boolean);
|
|
83
|
+
applyEncodedState(params: DocApplyEncodedStateParams): this;
|
|
84
|
+
batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this;
|
|
85
|
+
captureUpdate(fn: () => void): string | null;
|
|
86
|
+
canRedo(): boolean;
|
|
87
|
+
canUndo(): boolean;
|
|
88
|
+
destroy(): void;
|
|
89
|
+
get(key?: undefined): InferYjsStorage<TSchema>;
|
|
90
|
+
get<TKey extends keyof InferYjsStorage<TSchema>>(type: TKey): InferYjsStorage<TSchema>[TKey];
|
|
91
|
+
encodeDiff(stateVector: string): string;
|
|
92
|
+
getEncodedState(): string;
|
|
93
|
+
getStateVector(): string;
|
|
94
|
+
readStateVersion(encoded: string): readonly (readonly [string, number])[];
|
|
95
|
+
readUpdateVersion(update: string): readonly (readonly [string, number])[];
|
|
96
|
+
containsUpdate(update: string): boolean;
|
|
97
|
+
hasPending(): boolean;
|
|
98
|
+
/**
|
|
99
|
+
* @description Yjs keeps updates that could not be applied on `store.pendingStructs`
|
|
100
|
+
* and `store.pendingDs`. A missing field means this check cannot tell.
|
|
101
|
+
*/
|
|
102
|
+
canDetectPending(): boolean;
|
|
103
|
+
isDirty(): boolean;
|
|
104
|
+
isEmpty(): boolean;
|
|
105
|
+
rebuildStorage(): this;
|
|
106
|
+
redo(): this;
|
|
107
|
+
subscribe(listener: (params: DocSubscribeCallbackParams<Doc, InferYjsStorage<TSchema>, InferYjsJson<TSchema>>) => void): () => void;
|
|
108
|
+
track(): this;
|
|
109
|
+
transact(fn: () => void): this;
|
|
110
|
+
toJson(): InferYjsJson<TSchema>;
|
|
111
|
+
toJson<TKey extends keyof InferYjsJson<TSchema>>(type: TKey): InferYjsJson<TSchema>[TKey];
|
|
112
|
+
undo(): this;
|
|
113
|
+
}
|
|
114
|
+
declare const doc: (_value?: any) => YjsSchema;
|
|
115
|
+
declare const map: <T extends unknown>(value?: readonly (readonly [key: string, value: T])[]) => Map$1<T>;
|
|
116
|
+
interface PluvYjsProviderParams<TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, any>, TField extends keyof TPresence | null = null> {
|
|
117
|
+
presenceField?: TField;
|
|
118
|
+
room: RoomLike<TIO, Doc, TPresence, TStorage>;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* !HACK
|
|
122
|
+
* @description This doesn't really do anything but emit states in a Yjs.Provider compatible way.
|
|
123
|
+
* Connections and document syncing are handled by the PluvRoom already.
|
|
124
|
+
* @date May 13, 2025
|
|
125
|
+
*/
|
|
126
|
+
declare class PluvYjsProvider<TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, any>, TField extends keyof TPresence | null = null> extends ObservableV2<{
|
|
127
|
+
"connection-close": (event: CloseEvent | null, provider: PluvYjsProvider<TIO, TPresence, TStorage, TField>) => void;
|
|
128
|
+
"connection-error": (event: Event, provider: PluvYjsProvider<TIO, TPresence, TStorage, TField>) => void;
|
|
129
|
+
status: (event: {
|
|
130
|
+
status: YjsProviderStatus;
|
|
131
|
+
}) => void;
|
|
132
|
+
sync: (state: boolean) => void;
|
|
133
|
+
synced: (state: boolean) => void;
|
|
134
|
+
}> {
|
|
135
|
+
readonly awareness: PluvYjsAwareness<TIO, TPresence, TStorage, TField>;
|
|
136
|
+
private readonly _room;
|
|
137
|
+
private readonly _unsubscribe;
|
|
138
|
+
private _synced;
|
|
139
|
+
get doc(): Doc;
|
|
140
|
+
constructor(params: PluvYjsProviderParams<TIO, TPresence, TStorage, TField>);
|
|
141
|
+
get synced(): boolean;
|
|
142
|
+
set synced(state: boolean);
|
|
143
|
+
destroy(): void;
|
|
144
|
+
private _toProviderStatus;
|
|
145
|
+
/**
|
|
146
|
+
* !HACK
|
|
147
|
+
* @description We dgaf about these, since the room manages these already. We're just mirroring
|
|
148
|
+
* the fields that exist in the og provider to make sure everything aligns.
|
|
149
|
+
* @see https://github.com/yjs/y-websocket/blob/master/src/y-websocket.js
|
|
150
|
+
* @date May 13, 2025
|
|
151
|
+
*/
|
|
152
|
+
connect(): void;
|
|
153
|
+
disconnect(): void;
|
|
154
|
+
}
|
|
155
|
+
declare const provider: <TIO extends IOLike, TPresence extends Record<string, any>, TStorage extends Record<string, any>, TField extends keyof TPresence | null = null>(params: PluvYjsProviderParams<TIO, TPresence, TStorage, TField>) => PluvYjsProvider<TIO, TPresence, TStorage, TField>;
|
|
156
|
+
type YjsArrayNode<TItem extends AnySchemaNode> = SchemaNode<"yArray", Array<InferNodeStorage<TItem>>, InferNodeJson<TItem>[], InferNodeSeed<TItem>[]> & {
|
|
157
|
+
readonly item: TItem;
|
|
158
|
+
};
|
|
159
|
+
type YjsMapNode<TValue extends AnySchemaNode> = SchemaNode<"yMap", Map$1<InferNodeStorage<TValue>>, Record<string, InferNodeJson<TValue>>, Record<string, InferNodeSeed<TValue>>> & {
|
|
160
|
+
readonly value: TValue;
|
|
161
|
+
};
|
|
162
|
+
type YjsTextNode = SchemaNode<"yText", Text, string, string>;
|
|
163
|
+
type YjsXmlTextNode = SchemaNode<"yXmlText", XmlText, string, never>;
|
|
164
|
+
type YjsXmlElementNode = SchemaNode<"yXmlElement", XmlElement, string, never>;
|
|
165
|
+
type YjsXmlFragmentNode = SchemaNode<"yXmlFragment", XmlFragment, string, never>;
|
|
166
|
+
declare const yArray: <TItem extends AnySchemaNode>(item: TItem) => YjsArrayNode<TItem>;
|
|
167
|
+
declare const yMap: <TValue extends AnySchemaNode>(value: TValue) => YjsMapNode<TValue>;
|
|
168
|
+
declare const yText: () => YjsTextNode;
|
|
169
|
+
declare const yXmlText: () => YjsXmlTextNode;
|
|
170
|
+
declare const yXmlElement: () => YjsXmlElementNode;
|
|
171
|
+
declare const yXmlFragment: () => YjsXmlFragmentNode;
|
|
172
|
+
declare const text: (value?: string) => Text;
|
|
173
|
+
declare const xmlElement: <T extends Record<string, any> = Record<string, any>>(name: string, children?: (XmlElement | XmlText)[] | readonly (XmlElement | XmlText)[]) => XmlElement<T>;
|
|
174
|
+
declare const xmlFragment: (children?: (XmlElement | XmlText)[] | readonly (XmlElement | XmlText)[]) => XmlFragment;
|
|
175
|
+
declare const xmlText: () => XmlText;
|
|
176
|
+
declare namespace yjs_d_exports {
|
|
177
|
+
export { array, awareness, doc, kind, map, provider, schema, text, xmlElement, xmlFragment, xmlText, yArray, yMap, yText, yXmlElement, yXmlFragment, yXmlText };
|
|
178
|
+
}
|
|
179
|
+
declare const kind: "yjs";
|
|
180
|
+
export type YjsLibraryType = typeof yjs_d_exports;
|
|
181
|
+
export { yjs_d_exports as yjs };
|
|
182
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":["YArray","YDoc","YDoc","YDoc","YMap","YDoc","YArray","YMap","YText","YXmlText","YXmlElement","YXmlFragment","YText","YXmlElement","YXmlText","YXmlElement","YXmlText","YXmlFragment","YXmlText","yjs"],"sources":["../src/array/array.ts","../src/types.ts","../src/awareness/PluvYjsAwareness.ts","../src/awareness/awareness.ts","../src/doc/YjsSchema.ts","../src/schema/schema.ts","../src/doc/CrdtYjsDoc.ts","../src/doc/doc.ts","../src/map/map.ts","../src/provider/PluvYjsProvider.ts","../src/provider/provider.ts","../src/schema/nodes.ts","../src/text/text.ts","../src/xmlElement/xmlElement.ts","../src/xmlFragment/xmlFragment.ts","../src/xmlText/xmlText.ts","../src/yjs.ts","../src/index.ts"],"mappings":"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"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,691 @@
|
|
|
1
|
+
import { t as __exportAll } from "./rolldown-runtime-D8jQpDG7.mjs";
|
|
2
|
+
import { Array as Array$1, ContentEmbed, ContentFormat, ContentString, Doc, Map as Map$1, Text, UndoManager, XmlElement, XmlFragment, XmlText, applyUpdate, decodeStateVector, encodeStateAsUpdate, encodeStateVector, mergeUpdates, parseUpdateMeta, snapshot, snapshotContainsUpdate } from "yjs";
|
|
3
|
+
import { ObservableV2 } from "lib0/observable";
|
|
4
|
+
import { fromUint8Array, toUint8Array } from "js-base64";
|
|
5
|
+
import { AbstractCrdtDocFactory, CrdtSchemaError, assertJsonValue, assertNotOptional, createSchemaNode, flattenObjectShape, fromJSON, isJsonKind, isLoroCrdtKind, isSchemaNode, isUnseedableKind, isYjsCrdtKind, pickUnionOption, unwrapOptional } from "@pluv/crdt";
|
|
6
|
+
import { StorageState } from "@pluv/types";
|
|
7
|
+
// src/array/array.ts
|
|
8
|
+
const array = (value = []) => {
|
|
9
|
+
const shared = new Array$1();
|
|
10
|
+
if (value.length) shared.insert(0, value);
|
|
11
|
+
return shared;
|
|
12
|
+
};
|
|
13
|
+
// src/constants.ts
|
|
14
|
+
const PLUV_PRESENCE_META_KEY = "__pluv";
|
|
15
|
+
const PLUV_PRESENCE_Y_ID_KEY = "__y_clientid";
|
|
16
|
+
// src/awareness/PluvYjsAwareness.ts
|
|
17
|
+
var PluvYjsAwareness = class extends ObservableV2 {
|
|
18
|
+
doc;
|
|
19
|
+
_field = null;
|
|
20
|
+
_idMap = /* @__PURE__ */ new Map();
|
|
21
|
+
_room;
|
|
22
|
+
_unsubscribe;
|
|
23
|
+
get clientID() {
|
|
24
|
+
return this.doc.clientID;
|
|
25
|
+
}
|
|
26
|
+
get states() {
|
|
27
|
+
return this.getStates();
|
|
28
|
+
}
|
|
29
|
+
constructor(params) {
|
|
30
|
+
super();
|
|
31
|
+
const { presenceField, room } = params;
|
|
32
|
+
this.doc = room.getDoc().value;
|
|
33
|
+
this._room = room;
|
|
34
|
+
if (!!presenceField) this._field = presenceField;
|
|
35
|
+
const myMeta = this._room.getMyPresence()?.["__pluv"] || {};
|
|
36
|
+
this._room.updateMyPresence({ [PLUV_PRESENCE_META_KEY]: {
|
|
37
|
+
...myMeta,
|
|
38
|
+
[PLUV_PRESENCE_Y_ID_KEY]: this.clientID
|
|
39
|
+
} });
|
|
40
|
+
this._unsubscribe = this._room.subscribe.others((others, event) => {
|
|
41
|
+
const updates = this._deriveUpdates(others, event);
|
|
42
|
+
if (!updates) return;
|
|
43
|
+
this.emit("change", [updates, "presence"]);
|
|
44
|
+
this.emit("update", [updates, "presence"]);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
destroy() {
|
|
48
|
+
this.emit("destroy", [this]);
|
|
49
|
+
this._unsubscribe();
|
|
50
|
+
super.destroy();
|
|
51
|
+
}
|
|
52
|
+
getLocalState() {
|
|
53
|
+
return this._adaptPresence(this._room.getMyPresence());
|
|
54
|
+
}
|
|
55
|
+
setLocalState(state) {
|
|
56
|
+
const patch = !!this._field ? { [this._field]: state } : state;
|
|
57
|
+
this._room.updateMyPresence(patch);
|
|
58
|
+
this.emit("update", [{
|
|
59
|
+
added: [],
|
|
60
|
+
updated: [this.clientID],
|
|
61
|
+
removed: []
|
|
62
|
+
}, "local"]);
|
|
63
|
+
}
|
|
64
|
+
setLocalStateField(field, value) {
|
|
65
|
+
/**
|
|
66
|
+
* !HACK
|
|
67
|
+
* @description Cast to unknown first, because field loses its type of TField when set in
|
|
68
|
+
* an object.
|
|
69
|
+
* @date May 14, 2025
|
|
70
|
+
*/
|
|
71
|
+
const patch = !!this._field ? { [this._field]: {
|
|
72
|
+
...this.getLocalState(),
|
|
73
|
+
[field]: value
|
|
74
|
+
} } : { [field]: value };
|
|
75
|
+
this._room.updateMyPresence(patch);
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* !HACK
|
|
79
|
+
* @description We're building the awareness presences from the states stored on the room's
|
|
80
|
+
* presense instead of using the map defined in the awareness interface.
|
|
81
|
+
* @see https://github.com/yjs/y-protocols/blob/master/awareness.js
|
|
82
|
+
* @date May 13, 2025
|
|
83
|
+
*/
|
|
84
|
+
getStates() {
|
|
85
|
+
const states = this._room.getOthers().reduce((map, other) => {
|
|
86
|
+
const presence = this._adaptPresence(other.presence);
|
|
87
|
+
const clientID = (other.presence?.["__pluv"] || {})[PLUV_PRESENCE_Y_ID_KEY];
|
|
88
|
+
return typeof presence !== "undefined" && typeof clientID !== "undefined" ? map.set(clientID, presence) : map;
|
|
89
|
+
}, /* @__PURE__ */ new Map());
|
|
90
|
+
const myPresence = this.getLocalState();
|
|
91
|
+
if (typeof myPresence !== "undefined") states.set(this.clientID, myPresence);
|
|
92
|
+
return states;
|
|
93
|
+
}
|
|
94
|
+
_adaptPresence(presence) {
|
|
95
|
+
return !!this._field ? presence[this._field] : presence;
|
|
96
|
+
}
|
|
97
|
+
_deriveUpdates(others, event) {
|
|
98
|
+
switch (event.kind) {
|
|
99
|
+
case "clear":
|
|
100
|
+
this._idMap.clear();
|
|
101
|
+
return null;
|
|
102
|
+
case "enter": {
|
|
103
|
+
const clientID = this._resetIdMap(others).get(event.user.data.id);
|
|
104
|
+
return {
|
|
105
|
+
added: typeof clientID !== "undefined" ? [clientID] : [],
|
|
106
|
+
updated: [],
|
|
107
|
+
removed: []
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
case "leave": {
|
|
111
|
+
const clientID = this._idMap.get(event.user.data.id);
|
|
112
|
+
this._resetIdMap(others);
|
|
113
|
+
return {
|
|
114
|
+
added: [],
|
|
115
|
+
updated: [],
|
|
116
|
+
removed: typeof clientID !== "undefined" ? [clientID] : []
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
case "sync":
|
|
120
|
+
this._resetIdMap(others);
|
|
121
|
+
return null;
|
|
122
|
+
case "update": {
|
|
123
|
+
const clientID = this._resetIdMap(others).get(event.user.data.id);
|
|
124
|
+
return {
|
|
125
|
+
added: [],
|
|
126
|
+
updated: typeof clientID !== "undefined" ? [clientID] : [],
|
|
127
|
+
removed: []
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
default: return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
_resetIdMap(others) {
|
|
134
|
+
this._idMap.clear();
|
|
135
|
+
return others.reduce((map, other) => {
|
|
136
|
+
const clientID = other.presence[PLUV_PRESENCE_META_KEY]?.[PLUV_PRESENCE_Y_ID_KEY];
|
|
137
|
+
if (typeof clientID === "undefined") return map;
|
|
138
|
+
if (typeof other.data.id !== "string") return map;
|
|
139
|
+
return map.set(other.data.id, clientID);
|
|
140
|
+
}, this._idMap);
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* !HACK
|
|
144
|
+
* @description We dgaf about these. We're just mirroring the fields that exist in the
|
|
145
|
+
* og awareness to make sure everything aligns.
|
|
146
|
+
* @see https://github.com/yjs/y-protocols/blob/master/awareness.js
|
|
147
|
+
* @date May 13, 2025
|
|
148
|
+
*/
|
|
149
|
+
meta = /* @__PURE__ */ new Map();
|
|
150
|
+
_checkInterval = 0;
|
|
151
|
+
};
|
|
152
|
+
// src/awareness/awareness.ts
|
|
153
|
+
const awareness = (params) => {
|
|
154
|
+
return new PluvYjsAwareness(params);
|
|
155
|
+
};
|
|
156
|
+
// src/schema/hydrate.ts
|
|
157
|
+
const isPlainObject = (value) => {
|
|
158
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
159
|
+
};
|
|
160
|
+
const getYjsShare = (doc, key, kind) => {
|
|
161
|
+
switch (kind) {
|
|
162
|
+
case "yArray": return doc.getArray(key);
|
|
163
|
+
case "yMap": return doc.getMap(key);
|
|
164
|
+
case "yText": return doc.getText(key);
|
|
165
|
+
case "yXmlElement": return doc.getXmlElement(key);
|
|
166
|
+
case "yXmlFragment": return doc.getXmlFragment(key);
|
|
167
|
+
case "yXmlText": return doc.get(key, XmlText);
|
|
168
|
+
default: throw new CrdtSchemaError(`Cannot bind Yjs share for kind "${kind}"`);
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
const hydrateValue = (node, json) => {
|
|
172
|
+
const current = unwrapOptional(node);
|
|
173
|
+
if (current.kind === "union" || current.kind === "discriminatedUnion") {
|
|
174
|
+
const option = pickUnionOption(current, json);
|
|
175
|
+
if (!option) throw new CrdtSchemaError(`No ${current.kind} option matched`);
|
|
176
|
+
return hydrateValue(option, json);
|
|
177
|
+
}
|
|
178
|
+
if (current.kind === "intersection") {
|
|
179
|
+
const shape = flattenObjectShape(current);
|
|
180
|
+
return hydrateValue({
|
|
181
|
+
...current,
|
|
182
|
+
kind: "object",
|
|
183
|
+
shape
|
|
184
|
+
}, json);
|
|
185
|
+
}
|
|
186
|
+
if (current.kind === "object") {
|
|
187
|
+
assertJsonValue(current, json, "JSON object");
|
|
188
|
+
const shape = current.shape;
|
|
189
|
+
const source = json;
|
|
190
|
+
return Object.entries(shape).reduce((acc, [key, field]) => {
|
|
191
|
+
if (!(key in source)) return acc;
|
|
192
|
+
acc[key] = hydrateValue(unwrapOptional(field), source[key]);
|
|
193
|
+
return acc;
|
|
194
|
+
}, {});
|
|
195
|
+
}
|
|
196
|
+
if (current.kind === "array") {
|
|
197
|
+
assertJsonValue(current, json, "JSON array");
|
|
198
|
+
const item = current.item;
|
|
199
|
+
return json.map((entry) => hydrateValue(item, entry));
|
|
200
|
+
}
|
|
201
|
+
if (current.kind === "record") {
|
|
202
|
+
assertJsonValue(current, json, "JSON record");
|
|
203
|
+
const value = current.value;
|
|
204
|
+
return Object.entries(json).reduce((acc, [key, entry]) => {
|
|
205
|
+
acc[key] = hydrateValue(value, entry);
|
|
206
|
+
return acc;
|
|
207
|
+
}, {});
|
|
208
|
+
}
|
|
209
|
+
if (isJsonKind(current.kind)) {
|
|
210
|
+
assertJsonValue(current, json, `JSON ${current.kind}`);
|
|
211
|
+
return json;
|
|
212
|
+
}
|
|
213
|
+
switch (current.kind) {
|
|
214
|
+
case "yArray": {
|
|
215
|
+
if (!Array.isArray(json)) throw new CrdtSchemaError("Expected an array to hydrate yArray");
|
|
216
|
+
const item = current.item;
|
|
217
|
+
const array = new Array$1();
|
|
218
|
+
json.forEach((entry, index) => {
|
|
219
|
+
array.insert(index, [hydrateValue(item, entry)]);
|
|
220
|
+
});
|
|
221
|
+
return array;
|
|
222
|
+
}
|
|
223
|
+
case "yMap": {
|
|
224
|
+
if (!isPlainObject(json)) throw new CrdtSchemaError("Expected an object to hydrate yMap");
|
|
225
|
+
const value = current.value;
|
|
226
|
+
const map = new Map$1();
|
|
227
|
+
Object.entries(json).forEach(([key, entry]) => {
|
|
228
|
+
map.set(key, hydrateValue(value, entry));
|
|
229
|
+
});
|
|
230
|
+
return map;
|
|
231
|
+
}
|
|
232
|
+
case "yText": {
|
|
233
|
+
if (typeof json !== "string") throw new CrdtSchemaError("Expected a string to hydrate yText");
|
|
234
|
+
const text = new Text();
|
|
235
|
+
if (json) text.insert(0, json);
|
|
236
|
+
return text;
|
|
237
|
+
}
|
|
238
|
+
default: throw new CrdtSchemaError(`Cannot hydrate schema kind "${current.kind}" from JSON`);
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
const fillShare = (share, node, json) => {
|
|
242
|
+
switch (node.kind) {
|
|
243
|
+
case "yArray": {
|
|
244
|
+
if (!Array.isArray(json)) throw new CrdtSchemaError("Expected an array to seed yArray");
|
|
245
|
+
const item = node.item;
|
|
246
|
+
const array = share;
|
|
247
|
+
json.forEach((entry, index) => {
|
|
248
|
+
array.insert(index, [hydrateValue(item, entry)]);
|
|
249
|
+
});
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
case "yMap": {
|
|
253
|
+
if (!isPlainObject(json)) throw new CrdtSchemaError("Expected an object to seed yMap");
|
|
254
|
+
const value = node.value;
|
|
255
|
+
const map = share;
|
|
256
|
+
Object.entries(json).forEach(([key, entry]) => {
|
|
257
|
+
map.set(key, hydrateValue(value, entry));
|
|
258
|
+
});
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
261
|
+
case "yText": {
|
|
262
|
+
if (typeof json !== "string") throw new CrdtSchemaError("Expected a string to seed yText");
|
|
263
|
+
const text = share;
|
|
264
|
+
if (json) text.insert(0, json);
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
default: throw new CrdtSchemaError(`Cannot seed kind "${node.kind}"`);
|
|
268
|
+
}
|
|
269
|
+
};
|
|
270
|
+
const hydrateTopLevel = (doc, schema, seed) => {
|
|
271
|
+
if (seed) {
|
|
272
|
+
const extra = Object.keys(seed).filter((key) => !(key in schema.shape));
|
|
273
|
+
if (extra.length) throw new CrdtSchemaError(`Unexpected seed keys: ${extra.join(", ")}`);
|
|
274
|
+
}
|
|
275
|
+
return Object.entries(schema.shape).reduce((acc, [key, node]) => {
|
|
276
|
+
const share = getYjsShare(doc, key, node.kind);
|
|
277
|
+
const value = seed?.[key];
|
|
278
|
+
if (value !== void 0) {
|
|
279
|
+
if (isUnseedableKind(node.kind)) throw new CrdtSchemaError(`Cannot JSON-seed "${key}" (${node.kind})`);
|
|
280
|
+
fillShare(share, node, value);
|
|
281
|
+
}
|
|
282
|
+
acc[key] = share;
|
|
283
|
+
return acc;
|
|
284
|
+
}, {});
|
|
285
|
+
};
|
|
286
|
+
// src/doc/CrdtYjsDoc.ts
|
|
287
|
+
const MERGE_INTERVAL_MS = 1e3;
|
|
288
|
+
const PLUV_ID_FIELD = "__$pluv";
|
|
289
|
+
const clocksFromVector = (clocks) => [...clocks].map(([id, clock]) => [String(id), clock]).sort((left, right) => left[0] < right[0] ? -1 : left[0] > right[0] ? 1 : 0);
|
|
290
|
+
var CrdtYjsDoc = class {
|
|
291
|
+
value = new Doc();
|
|
292
|
+
#_schema;
|
|
293
|
+
#_storage;
|
|
294
|
+
#_undoManager = null;
|
|
295
|
+
constructor(schema, seed, hydrate = false) {
|
|
296
|
+
this.#_schema = schema;
|
|
297
|
+
if (hydrate) {
|
|
298
|
+
this.#_storage = hydrateTopLevel(this.value, schema, seed);
|
|
299
|
+
if (Object.keys(schema.shape).length) this.#_setPluvId();
|
|
300
|
+
} else this.#_storage = {};
|
|
301
|
+
}
|
|
302
|
+
applyEncodedState(params) {
|
|
303
|
+
const { origin, update } = params;
|
|
304
|
+
if (update === null || typeof update === "undefined") return this;
|
|
305
|
+
const uint8Update = typeof update === "string" ? toUint8Array(update) : update;
|
|
306
|
+
applyUpdate(this.value, uint8Update, origin);
|
|
307
|
+
return this;
|
|
308
|
+
}
|
|
309
|
+
batchApplyEncodedState(params) {
|
|
310
|
+
const { origin } = params;
|
|
311
|
+
const filtered = (params.updates ?? []).reduce((acc, update) => {
|
|
312
|
+
if (!update) return acc;
|
|
313
|
+
if (typeof update === "string") {
|
|
314
|
+
acc.push(toUint8Array(update));
|
|
315
|
+
return acc;
|
|
316
|
+
}
|
|
317
|
+
if (typeof update === "object") {
|
|
318
|
+
acc.push(update);
|
|
319
|
+
return acc;
|
|
320
|
+
}
|
|
321
|
+
return acc;
|
|
322
|
+
}, []);
|
|
323
|
+
if (!filtered.length) return this;
|
|
324
|
+
const merged = mergeUpdates(filtered);
|
|
325
|
+
return this.applyEncodedState({
|
|
326
|
+
origin,
|
|
327
|
+
update: merged
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
captureUpdate(fn) {
|
|
331
|
+
const updates = [];
|
|
332
|
+
const onUpdate = (update) => {
|
|
333
|
+
updates.push(update);
|
|
334
|
+
};
|
|
335
|
+
this.value.on("update", onUpdate);
|
|
336
|
+
try {
|
|
337
|
+
fn();
|
|
338
|
+
} finally {
|
|
339
|
+
this.value.off("update", onUpdate);
|
|
340
|
+
}
|
|
341
|
+
const [first] = updates;
|
|
342
|
+
if (!first) return null;
|
|
343
|
+
const update = updates.length === 1 ? fromUint8Array(first) : fromUint8Array(mergeUpdates(updates));
|
|
344
|
+
return update === "" ? null : update;
|
|
345
|
+
}
|
|
346
|
+
canRedo() {
|
|
347
|
+
return !!this.#_undoManager?.canRedo();
|
|
348
|
+
}
|
|
349
|
+
canUndo() {
|
|
350
|
+
return !!this.#_undoManager?.canUndo();
|
|
351
|
+
}
|
|
352
|
+
destroy() {
|
|
353
|
+
this.#_undoManager?.destroy();
|
|
354
|
+
this.value.destroy();
|
|
355
|
+
}
|
|
356
|
+
get(type) {
|
|
357
|
+
if (typeof type === "undefined") return this.#_storage;
|
|
358
|
+
return this.#_storage[type];
|
|
359
|
+
}
|
|
360
|
+
encodeDiff(stateVector) {
|
|
361
|
+
if (!stateVector) return this.getEncodedState();
|
|
362
|
+
return fromUint8Array(encodeStateAsUpdate(this.value, toUint8Array(stateVector)));
|
|
363
|
+
}
|
|
364
|
+
getEncodedState() {
|
|
365
|
+
return fromUint8Array(encodeStateAsUpdate(this.value));
|
|
366
|
+
}
|
|
367
|
+
getStateVector() {
|
|
368
|
+
return fromUint8Array(encodeStateVector(this.value));
|
|
369
|
+
}
|
|
370
|
+
readStateVersion(encoded) {
|
|
371
|
+
return clocksFromVector(encoded ? decodeStateVector(toUint8Array(encoded)) : /* @__PURE__ */ new Map());
|
|
372
|
+
}
|
|
373
|
+
readUpdateVersion(update) {
|
|
374
|
+
if (!update) return [];
|
|
375
|
+
return clocksFromVector(parseUpdateMeta(toUint8Array(update)).to);
|
|
376
|
+
}
|
|
377
|
+
containsUpdate(update) {
|
|
378
|
+
if (!update) return true;
|
|
379
|
+
return snapshotContainsUpdate(snapshot(this.value), toUint8Array(update));
|
|
380
|
+
}
|
|
381
|
+
hasPending() {
|
|
382
|
+
if (!this.canDetectPending()) return true;
|
|
383
|
+
return this.value.store.pendingStructs !== null || this.value.store.pendingDs !== null;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* @description Yjs keeps updates that could not be applied on `store.pendingStructs`
|
|
387
|
+
* and `store.pendingDs`. A missing field means this check cannot tell.
|
|
388
|
+
*/
|
|
389
|
+
canDetectPending() {
|
|
390
|
+
const store = this.value.store;
|
|
391
|
+
return !!store && "pendingStructs" in store && "pendingDs" in store;
|
|
392
|
+
}
|
|
393
|
+
isDirty() {
|
|
394
|
+
return !!this.value.store.clients.size;
|
|
395
|
+
}
|
|
396
|
+
isEmpty() {
|
|
397
|
+
return !this.value.share.size;
|
|
398
|
+
}
|
|
399
|
+
rebuildStorage() {
|
|
400
|
+
if (!!Object.keys(this.#_storage).length) {
|
|
401
|
+
console.warn("Attempted to rebuild storage multiple times");
|
|
402
|
+
return this;
|
|
403
|
+
}
|
|
404
|
+
this.#_storage = Object.entries(this.#_schema.shape).reduce((acc, [key, node]) => {
|
|
405
|
+
Object.assign(acc, { [key]: getYjsShare(this.value, key, node.kind) });
|
|
406
|
+
return acc;
|
|
407
|
+
}, {});
|
|
408
|
+
return this.track();
|
|
409
|
+
}
|
|
410
|
+
redo() {
|
|
411
|
+
this.#_undoManager?.redo();
|
|
412
|
+
return this;
|
|
413
|
+
}
|
|
414
|
+
subscribe(listener) {
|
|
415
|
+
const fn = (update, origin, _doc) => {
|
|
416
|
+
listener({
|
|
417
|
+
doc: this,
|
|
418
|
+
local: origin === null || typeof origin === "undefined",
|
|
419
|
+
origin: origin ? String(origin) : null,
|
|
420
|
+
update: fromUint8Array(update)
|
|
421
|
+
});
|
|
422
|
+
};
|
|
423
|
+
this.value.on("update", fn);
|
|
424
|
+
return () => {
|
|
425
|
+
this.value.off("update", fn);
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
track() {
|
|
429
|
+
if (this.#_undoManager) this.#_undoManager.destroy();
|
|
430
|
+
const sharedTypes = Object.values(this.#_storage).reduce((acc, type) => {
|
|
431
|
+
if (type instanceof Array$1 || type instanceof Map$1 || type instanceof Text || type instanceof XmlElement || type instanceof XmlFragment || type instanceof XmlText) acc.push(type);
|
|
432
|
+
return acc;
|
|
433
|
+
}, []);
|
|
434
|
+
if (!sharedTypes.length) {
|
|
435
|
+
this.#_undoManager?.destroy();
|
|
436
|
+
this.#_undoManager = null;
|
|
437
|
+
return this;
|
|
438
|
+
}
|
|
439
|
+
this.#_undoManager = new UndoManager(sharedTypes, { captureTimeout: MERGE_INTERVAL_MS });
|
|
440
|
+
return this;
|
|
441
|
+
}
|
|
442
|
+
transact(fn) {
|
|
443
|
+
this.value.transact(fn);
|
|
444
|
+
return this;
|
|
445
|
+
}
|
|
446
|
+
toJson(type) {
|
|
447
|
+
if (typeof type === "string") {
|
|
448
|
+
const shared = this.#_storage[type];
|
|
449
|
+
if (shared && typeof shared.toJSON === "function") return shared.toJSON();
|
|
450
|
+
const fromDoc = this.value.share.get(type);
|
|
451
|
+
return this.#_toJsonFromShare(type, fromDoc) ?? null;
|
|
452
|
+
}
|
|
453
|
+
return this.#_toJsonFromDoc();
|
|
454
|
+
}
|
|
455
|
+
undo() {
|
|
456
|
+
this.#_undoManager?.undo();
|
|
457
|
+
return this;
|
|
458
|
+
}
|
|
459
|
+
#_setPluvId() {
|
|
460
|
+
const text = this.value.getText(PLUV_ID_FIELD);
|
|
461
|
+
const id = typeof crypto !== "undefined" ? crypto.randomUUID() : Math.random().toString();
|
|
462
|
+
text.insert(0, id);
|
|
463
|
+
}
|
|
464
|
+
#_toJsonFromDoc() {
|
|
465
|
+
const json = {};
|
|
466
|
+
this.value.share.forEach((sharedType, key) => {
|
|
467
|
+
if (key === PLUV_ID_FIELD) return;
|
|
468
|
+
Object.assign(json, { [key]: this.#_toJsonFromShare(key, sharedType) });
|
|
469
|
+
});
|
|
470
|
+
return json;
|
|
471
|
+
}
|
|
472
|
+
#_toJsonFromShare(key, sharedType) {
|
|
473
|
+
if (!sharedType) return null;
|
|
474
|
+
if (sharedType instanceof XmlElement || sharedType instanceof XmlFragment || sharedType instanceof XmlText || sharedType instanceof Text || sharedType instanceof Array$1 || sharedType instanceof Map$1) return sharedType.toJSON();
|
|
475
|
+
const start = sharedType._start;
|
|
476
|
+
const map = sharedType._map;
|
|
477
|
+
const content = start?.content ?? null;
|
|
478
|
+
if (content instanceof ContentString || content instanceof ContentEmbed || content instanceof ContentFormat) return this.value.getText(key).toJSON();
|
|
479
|
+
if (map && map.size > 0 && start) return this.value.getXmlElement(key).toJSON();
|
|
480
|
+
if (start) return this.value.getArray(key).toJSON();
|
|
481
|
+
if (map && map.size > 0) return this.value.getMap(key).toJSON();
|
|
482
|
+
return {};
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
// src/doc/YjsSchema.ts
|
|
486
|
+
var YjsSchema = class YjsSchema extends AbstractCrdtDocFactory {
|
|
487
|
+
kind = "y.doc";
|
|
488
|
+
shape;
|
|
489
|
+
_seed;
|
|
490
|
+
constructor(shape, seed) {
|
|
491
|
+
super();
|
|
492
|
+
this.shape = shape;
|
|
493
|
+
this._seed = seed;
|
|
494
|
+
}
|
|
495
|
+
toJSON() {
|
|
496
|
+
return createSchemaNode("y.doc", { shape: this.shape }).toJSON();
|
|
497
|
+
}
|
|
498
|
+
getEmpty() {
|
|
499
|
+
return new CrdtYjsDoc(this);
|
|
500
|
+
}
|
|
501
|
+
getFactory(seed) {
|
|
502
|
+
return new YjsSchema(this.shape, seed ?? this._seed);
|
|
503
|
+
}
|
|
504
|
+
getInitialized(seed) {
|
|
505
|
+
return new CrdtYjsDoc(this, seed ?? this._seed, true);
|
|
506
|
+
}
|
|
507
|
+
};
|
|
508
|
+
// src/schema/nodes.ts
|
|
509
|
+
const yArray = (item) => {
|
|
510
|
+
assertNotOptional(item, "yjs.yArray item");
|
|
511
|
+
return createSchemaNode("yArray", { item });
|
|
512
|
+
};
|
|
513
|
+
const yMap = (value) => {
|
|
514
|
+
assertNotOptional(value, "yjs.yMap value");
|
|
515
|
+
return createSchemaNode("yMap", { value });
|
|
516
|
+
};
|
|
517
|
+
const yText = () => {
|
|
518
|
+
return createSchemaNode("yText", {});
|
|
519
|
+
};
|
|
520
|
+
const yXmlText = () => {
|
|
521
|
+
return createSchemaNode("yXmlText", {});
|
|
522
|
+
};
|
|
523
|
+
const yXmlElement = () => {
|
|
524
|
+
return createSchemaNode("yXmlElement", {});
|
|
525
|
+
};
|
|
526
|
+
const yXmlFragment = () => {
|
|
527
|
+
return createSchemaNode("yXmlFragment", {});
|
|
528
|
+
};
|
|
529
|
+
// src/schema/fromJSON.ts
|
|
530
|
+
const fromJSON$1 = (ast) => {
|
|
531
|
+
switch (ast.kind) {
|
|
532
|
+
case "yArray": return yArray(fromJSON$1(ast.item));
|
|
533
|
+
case "yMap": return yMap(fromJSON$1(ast.value));
|
|
534
|
+
case "yText": return yText();
|
|
535
|
+
case "yXmlText": return yXmlText();
|
|
536
|
+
case "yXmlElement": return yXmlElement();
|
|
537
|
+
case "yXmlFragment": return yXmlFragment();
|
|
538
|
+
default:
|
|
539
|
+
if (isYjsCrdtKind(ast.kind)) throw new CrdtSchemaError(`Unhandled Yjs schema kind "${ast.kind}"`);
|
|
540
|
+
return fromJSON(ast);
|
|
541
|
+
}
|
|
542
|
+
};
|
|
543
|
+
// src/schema/schema.ts
|
|
544
|
+
const schema = (shape) => {
|
|
545
|
+
Object.entries(shape).forEach(([key, node]) => {
|
|
546
|
+
if (!isSchemaNode(node)) throw new CrdtSchemaError(`yjs.schema field "${key}" must be a schema node`);
|
|
547
|
+
if (isLoroCrdtKind(node.kind)) throw new CrdtSchemaError(`yjs.schema field "${key}" cannot be a Loro node`);
|
|
548
|
+
if (!isYjsCrdtKind(node.kind)) throw new CrdtSchemaError(`yjs.schema field "${key}" must be a Yjs CRDT node`);
|
|
549
|
+
});
|
|
550
|
+
return new YjsSchema(shape);
|
|
551
|
+
};
|
|
552
|
+
schema.fromJSON = (ast) => {
|
|
553
|
+
if (ast.kind !== "y.doc") throw new CrdtSchemaError(`Expected kind "y.doc", received "${ast.kind}"`);
|
|
554
|
+
const shapeAst = ast.shape ?? {};
|
|
555
|
+
const shape = Object.entries(shapeAst).reduce((acc, [key, value]) => {
|
|
556
|
+
acc[key] = fromJSON$1(value);
|
|
557
|
+
return acc;
|
|
558
|
+
}, {});
|
|
559
|
+
return schema(shape);
|
|
560
|
+
};
|
|
561
|
+
// src/doc/doc.ts
|
|
562
|
+
const doc = (_value) => {
|
|
563
|
+
return schema({});
|
|
564
|
+
};
|
|
565
|
+
// src/map/map.ts
|
|
566
|
+
const map = (value = []) => {
|
|
567
|
+
return new Map$1(value);
|
|
568
|
+
};
|
|
569
|
+
// src/provider/PluvYjsProvider.ts
|
|
570
|
+
/**
|
|
571
|
+
* !HACK
|
|
572
|
+
* @description This doesn't really do anything but emit states in a Yjs.Provider compatible way.
|
|
573
|
+
* Connections and document syncing are handled by the PluvRoom already.
|
|
574
|
+
* @date May 13, 2025
|
|
575
|
+
*/
|
|
576
|
+
var PluvYjsProvider = class extends ObservableV2 {
|
|
577
|
+
awareness;
|
|
578
|
+
_room;
|
|
579
|
+
_unsubscribe;
|
|
580
|
+
_synced = false;
|
|
581
|
+
get doc() {
|
|
582
|
+
return this._room.getDoc().value;
|
|
583
|
+
}
|
|
584
|
+
constructor(params) {
|
|
585
|
+
super();
|
|
586
|
+
const { presenceField, room } = params;
|
|
587
|
+
this.awareness = awareness({
|
|
588
|
+
presenceField,
|
|
589
|
+
room
|
|
590
|
+
});
|
|
591
|
+
this._room = room;
|
|
592
|
+
const subscriptions = [
|
|
593
|
+
this._room.subscribe.connection(({ storage }) => {
|
|
594
|
+
const status = this._toProviderStatus(storage.state);
|
|
595
|
+
if (!status) return;
|
|
596
|
+
this.emit("status", [{ status }]);
|
|
597
|
+
}),
|
|
598
|
+
this._room.addEventListener("close", (event) => {
|
|
599
|
+
this.emit("connection-close", [event, this]);
|
|
600
|
+
}),
|
|
601
|
+
this._room.addEventListener("error", (event) => {
|
|
602
|
+
this.emit("connection-error", [event, this]);
|
|
603
|
+
})
|
|
604
|
+
];
|
|
605
|
+
this._unsubscribe = subscriptions.reduce((fn, unsubscribe) => () => {
|
|
606
|
+
fn();
|
|
607
|
+
unsubscribe();
|
|
608
|
+
}, () => void 0);
|
|
609
|
+
}
|
|
610
|
+
get synced() {
|
|
611
|
+
return this._synced;
|
|
612
|
+
}
|
|
613
|
+
set synced(state) {
|
|
614
|
+
if (this._synced === state) return;
|
|
615
|
+
this._synced = state;
|
|
616
|
+
this.emit("sync", [state]);
|
|
617
|
+
this.emit("synced", [state]);
|
|
618
|
+
}
|
|
619
|
+
destroy() {
|
|
620
|
+
this.awareness.destroy();
|
|
621
|
+
this._unsubscribe();
|
|
622
|
+
super.destroy();
|
|
623
|
+
}
|
|
624
|
+
_toProviderStatus(state) {
|
|
625
|
+
switch (state) {
|
|
626
|
+
case StorageState.Loading: return "connecting";
|
|
627
|
+
case StorageState.Unavailable: return "disconnected";
|
|
628
|
+
case StorageState.Offline:
|
|
629
|
+
case StorageState.Synced: return "connected";
|
|
630
|
+
default: return null;
|
|
631
|
+
}
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* !HACK
|
|
635
|
+
* @description We dgaf about these, since the room manages these already. We're just mirroring
|
|
636
|
+
* the fields that exist in the og provider to make sure everything aligns.
|
|
637
|
+
* @see https://github.com/yjs/y-websocket/blob/master/src/y-websocket.js
|
|
638
|
+
* @date May 13, 2025
|
|
639
|
+
*/
|
|
640
|
+
connect() {}
|
|
641
|
+
disconnect() {}
|
|
642
|
+
};
|
|
643
|
+
// src/provider/provider.ts
|
|
644
|
+
const provider = (params) => {
|
|
645
|
+
return new PluvYjsProvider(params);
|
|
646
|
+
};
|
|
647
|
+
// src/text/text.ts
|
|
648
|
+
const text = (value = "") => {
|
|
649
|
+
const shared = new Text();
|
|
650
|
+
if (value) shared.insert(0, value);
|
|
651
|
+
return shared;
|
|
652
|
+
};
|
|
653
|
+
// src/xmlElement/xmlElement.ts
|
|
654
|
+
const xmlElement = (name, children = []) => {
|
|
655
|
+
const shared = new XmlElement(name);
|
|
656
|
+
if (children.length) shared.insert(0, children);
|
|
657
|
+
return shared;
|
|
658
|
+
};
|
|
659
|
+
// src/xmlFragment/xmlFragment.ts
|
|
660
|
+
const xmlFragment = (children = []) => {
|
|
661
|
+
const shared = new XmlFragment();
|
|
662
|
+
if (children.length) shared.insert(0, children);
|
|
663
|
+
return shared;
|
|
664
|
+
};
|
|
665
|
+
// src/xmlText/xmlText.ts
|
|
666
|
+
const xmlText = () => {
|
|
667
|
+
return new XmlText();
|
|
668
|
+
};
|
|
669
|
+
// src/yjs.ts
|
|
670
|
+
var yjs_exports = /* @__PURE__ */ __exportAll({
|
|
671
|
+
array: () => array,
|
|
672
|
+
awareness: () => awareness,
|
|
673
|
+
doc: () => doc,
|
|
674
|
+
kind: () => "yjs",
|
|
675
|
+
map: () => map,
|
|
676
|
+
provider: () => provider,
|
|
677
|
+
schema: () => schema,
|
|
678
|
+
text: () => text,
|
|
679
|
+
xmlElement: () => xmlElement,
|
|
680
|
+
xmlFragment: () => xmlFragment,
|
|
681
|
+
xmlText: () => xmlText,
|
|
682
|
+
yArray: () => yArray,
|
|
683
|
+
yMap: () => yMap,
|
|
684
|
+
yText: () => yText,
|
|
685
|
+
yXmlElement: () => yXmlElement,
|
|
686
|
+
yXmlFragment: () => yXmlFragment,
|
|
687
|
+
yXmlText: () => yXmlText
|
|
688
|
+
});
|
|
689
|
+
export { yjs_exports as yjs };
|
|
690
|
+
|
|
691
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["YArray","YXmlText","YArray","YMap","YText","YDoc","YArray","YMap","YText","YXmlElement","YXmlFragment","YXmlText","fromJSON","fromJsonSchema","fromJsonNode","YMap","YText","XmlElementCtor","YXmlFragment","YXmlText"],"sources":["../src/array/array.ts","../src/constants.ts","../src/awareness/PluvYjsAwareness.ts","../src/awareness/awareness.ts","../src/schema/hydrate.ts","../src/doc/CrdtYjsDoc.ts","../src/doc/YjsSchema.ts","../src/schema/nodes.ts","../src/schema/fromJSON.ts","../src/schema/schema.ts","../src/doc/doc.ts","../src/map/map.ts","../src/provider/PluvYjsProvider.ts","../src/provider/provider.ts","../src/text/text.ts","../src/xmlElement/xmlElement.ts","../src/xmlFragment/xmlFragment.ts","../src/xmlText/xmlText.ts","../src/yjs.ts"],"sourcesContent":["import { Array as YArray } from \"yjs\";\n\nexport const array = <T extends unknown>(value: T[] | readonly T[] = []): YArray<T> => {\n const shared = new YArray<T>();\n\n if (value.length) shared.insert(0, value as T[]);\n\n return shared;\n};\n","export const PLUV_PRESENCE_META_KEY = \"__pluv\";\nexport const PLUV_PRESENCE_Y_ID_KEY = \"__y_clientid\";\n","import type { IOLike, OthersSubscriptionEvent, RoomLike, UserInfo } from \"@pluv/types\";\nimport { ObservableV2 } from \"lib0/observable\";\nimport type { Doc as YDoc } from \"yjs\";\nimport { PLUV_PRESENCE_META_KEY, PLUV_PRESENCE_Y_ID_KEY } from \"../constants\";\nimport type { AwarenessPresence, MetaClientState, YjsAwarenessUpdate } from \"../types\";\n\nexport interface PluvYjsAwarenessParams<\n TIO extends IOLike,\n TPresence extends Record<string, any>,\n TStorage extends Record<string, any>,\n TField extends keyof TPresence | null = null,\n> {\n presenceField?: TField;\n room: RoomLike<TIO, YDoc, TPresence, TStorage>;\n}\n\nexport class PluvYjsAwareness<\n TIO extends IOLike,\n TPresence extends Record<string, any>,\n TStorage extends Record<string, any>,\n TField extends keyof TPresence | null = null,\n> extends ObservableV2<{\n change: (updates: YjsAwarenessUpdate, kind: \"presence\") => void;\n destroy: (awareness: PluvYjsAwareness<TIO, TPresence, TStorage, TField>) => void;\n update: (updates: YjsAwarenessUpdate, kind: \"local\" | \"presence\") => void;\n}> {\n public readonly doc: YDoc;\n\n private readonly _field: TField = null as TField;\n private readonly _idMap = new Map<[userId: string][0], [clientID: number][0]>();\n private readonly _room: RoomLike<TIO, YDoc, TPresence, TStorage>;\n private readonly _unsubscribe: () => void;\n\n public get clientID(): number {\n return this.doc.clientID;\n }\n\n public get states(): Map<number, TPresence> {\n return this.getStates();\n }\n\n constructor(params: PluvYjsAwarenessParams<TIO, TPresence, TStorage, TField>) {\n super();\n\n const { presenceField, room } = params;\n\n this.doc = room.getDoc().value;\n this._room = room;\n\n if (!!presenceField) this._field = presenceField;\n\n const myPresence: any = this._room.getMyPresence();\n const myMeta = myPresence?.[PLUV_PRESENCE_META_KEY] || {};\n\n this._room.updateMyPresence({\n [PLUV_PRESENCE_META_KEY]: {\n ...myMeta,\n [PLUV_PRESENCE_Y_ID_KEY]: this.clientID,\n },\n } as any);\n\n this._unsubscribe = this._room.subscribe.others((others, event) => {\n const updates = this._deriveUpdates(others, event);\n\n if (!updates) return;\n\n this.emit(\"change\", [updates, \"presence\"]);\n this.emit(\"update\", [updates, \"presence\"]);\n });\n }\n\n public destroy(): void {\n this.emit(\"destroy\", [this]);\n this._unsubscribe();\n super.destroy();\n }\n\n public getLocalState(): AwarenessPresence<TPresence, TField> {\n return this._adaptPresence(this._room.getMyPresence());\n }\n\n public setLocalState(state: AwarenessPresence<TPresence, TField>): void {\n const patch = (!!this._field\n ? { [this._field]: state }\n : state) as unknown as Partial<TPresence>;\n\n this._room.updateMyPresence(patch);\n\n this.emit(\"update\", [{ added: [], updated: [this.clientID], removed: [] }, \"local\"]);\n }\n\n public setLocalStateField<TLocalField extends keyof AwarenessPresence<TPresence, TField>>(\n field: TLocalField,\n value: AwarenessPresence<TPresence, TField>[TLocalField],\n ): void {\n /**\n * !HACK\n * @description Cast to unknown first, because field loses its type of TField when set in\n * an object.\n * @date May 14, 2025\n */\n const patch = (!!this._field\n ? { [this._field]: { ...this.getLocalState(), [field]: value } }\n : { [field]: value }) as unknown as Partial<TPresence>;\n\n this._room.updateMyPresence(patch);\n }\n\n /**\n * !HACK\n * @description We're building the awareness presences from the states stored on the room's\n * presense instead of using the map defined in the awareness interface.\n * @see https://github.com/yjs/y-protocols/blob/master/awareness.js\n * @date May 13, 2025\n */\n public getStates(): Map<number, AwarenessPresence<TPresence, TField>> {\n const others = this._room.getOthers();\n\n const states = others.reduce((map, other) => {\n const presence = this._adaptPresence(other.presence);\n const meta = other.presence?.[PLUV_PRESENCE_META_KEY] || {};\n const clientID: number | undefined = meta[PLUV_PRESENCE_Y_ID_KEY];\n\n return typeof presence !== \"undefined\" && typeof clientID !== \"undefined\"\n ? map.set(clientID, presence)\n : map;\n }, new Map<number, AwarenessPresence<TPresence, TField>>());\n\n const myPresence = this.getLocalState();\n\n if (typeof myPresence !== \"undefined\") states.set(this.clientID, myPresence);\n\n return states;\n }\n\n private _adaptPresence(presence: TPresence): AwarenessPresence<TPresence, TField> {\n return (!!this._field ? presence[this._field] : presence) as AwarenessPresence<\n TPresence,\n TField\n >;\n }\n\n private _deriveUpdates(\n others: readonly UserInfo<any, any>[],\n event: OthersSubscriptionEvent<any, any>,\n ): YjsAwarenessUpdate | null {\n switch (event.kind) {\n case \"clear\": {\n this._idMap.clear();\n return null;\n }\n case \"enter\": {\n const clientID = this._resetIdMap(others).get(event.user.data.id);\n\n return {\n added: typeof clientID !== \"undefined\" ? [clientID] : [],\n updated: [],\n removed: [],\n };\n }\n case \"leave\": {\n const clientID = this._idMap.get(event.user.data.id);\n\n this._resetIdMap(others);\n\n return {\n added: [],\n updated: [],\n removed: typeof clientID !== \"undefined\" ? [clientID] : [],\n };\n }\n case \"sync\": {\n this._resetIdMap(others);\n return null;\n }\n case \"update\": {\n const clientID = this._resetIdMap(others).get(event.user.data.id);\n\n return {\n added: [],\n updated: typeof clientID !== \"undefined\" ? [clientID] : [],\n removed: [],\n };\n }\n default:\n return null;\n }\n }\n\n private _resetIdMap(others: readonly UserInfo<any, any>[]): Map<string, number> {\n this._idMap.clear();\n\n return others.reduce((map, other) => {\n const clientID = other.presence[PLUV_PRESENCE_META_KEY]?.[PLUV_PRESENCE_Y_ID_KEY];\n\n if (typeof clientID === \"undefined\") return map;\n if (typeof other.data.id !== \"string\") return map;\n\n return map.set(other.data.id, clientID);\n }, this._idMap);\n }\n\n /**\n * !HACK\n * @description We dgaf about these. We're just mirroring the fields that exist in the\n * og awareness to make sure everything aligns.\n * @see https://github.com/yjs/y-protocols/blob/master/awareness.js\n * @date May 13, 2025\n */\n public readonly meta = new Map<any, MetaClientState>();\n public readonly _checkInterval: number = 0;\n}\n","import type { IOLike } from \"@pluv/types\";\nimport type { PluvYjsAwarenessParams } from \"./PluvYjsAwareness\";\nimport { PluvYjsAwareness } from \"./PluvYjsAwareness\";\n\nexport const awareness = <\n TIO extends IOLike,\n TPresence extends Record<string, any>,\n TStorage extends Record<string, any>,\n TField extends keyof TPresence | null = null,\n>(\n params: PluvYjsAwarenessParams<TIO, TPresence, TStorage, TField>,\n): PluvYjsAwareness<TIO, TPresence, TStorage, TField> => {\n return new PluvYjsAwareness(params);\n};\n","import {\n CrdtSchemaError,\n assertJsonValue,\n flattenObjectShape,\n isJsonKind,\n isUnseedableKind,\n pickUnionOption,\n unwrapOptional,\n type AnySchemaNode,\n} from \"@pluv/crdt\";\nimport { Array as YArray, Doc as YDoc, Map as YMap, Text as YText, XmlText as YXmlText } from \"yjs\";\nimport type { YjsSchema } from \"../doc/YjsSchema\";\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> => {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n};\n\nexport const getYjsShare = (doc: YDoc, key: string, kind: string) => {\n switch (kind) {\n case \"yArray\":\n return doc.getArray(key);\n case \"yMap\":\n return doc.getMap(key);\n case \"yText\":\n return doc.getText(key);\n case \"yXmlElement\":\n return doc.getXmlElement(key);\n case \"yXmlFragment\":\n return doc.getXmlFragment(key);\n case \"yXmlText\":\n return doc.get(key, YXmlText);\n default:\n throw new CrdtSchemaError(`Cannot bind Yjs share for kind \"${kind}\"`);\n }\n};\n\nexport const hydrateValue = (node: AnySchemaNode, json: unknown): unknown => {\n const current = unwrapOptional(node);\n\n if (current.kind === \"union\" || current.kind === \"discriminatedUnion\") {\n const option = pickUnionOption(current, json);\n\n if (!option) {\n throw new CrdtSchemaError(`No ${current.kind} option matched`);\n }\n\n return hydrateValue(option, json);\n }\n\n if (current.kind === \"intersection\") {\n const shape = flattenObjectShape(current);\n return hydrateValue({ ...current, kind: \"object\", shape } as AnySchemaNode, json);\n }\n\n if (current.kind === \"object\") {\n assertJsonValue(current, json, \"JSON object\");\n const shape = (current as AnySchemaNode & { shape: Record<string, AnySchemaNode> }).shape;\n const source = json as Record<string, unknown>;\n\n return Object.entries(shape).reduce<Record<string, unknown>>((acc, [key, field]) => {\n if (!(key in source)) return acc;\n acc[key] = hydrateValue(unwrapOptional(field), source[key]);\n return acc;\n }, {});\n }\n\n if (current.kind === \"array\") {\n assertJsonValue(current, json, \"JSON array\");\n const item = (current as AnySchemaNode & { item: AnySchemaNode }).item;\n return (json as unknown[]).map((entry) => hydrateValue(item, entry));\n }\n\n if (current.kind === \"record\") {\n assertJsonValue(current, json, \"JSON record\");\n const value = (current as AnySchemaNode & { value: AnySchemaNode }).value;\n return Object.entries(json as Record<string, unknown>).reduce<Record<string, unknown>>(\n (acc, [key, entry]) => {\n acc[key] = hydrateValue(value, entry);\n return acc;\n },\n {},\n );\n }\n\n if (isJsonKind(current.kind)) {\n assertJsonValue(current, json, `JSON ${current.kind}`);\n return json;\n }\n\n switch (current.kind) {\n case \"yArray\": {\n if (!Array.isArray(json)) {\n throw new CrdtSchemaError(\"Expected an array to hydrate yArray\");\n }\n\n const item = (current as AnySchemaNode & { item: AnySchemaNode }).item;\n const array = new YArray();\n\n json.forEach((entry, index) => {\n array.insert(index, [hydrateValue(item, entry)]);\n });\n\n return array;\n }\n case \"yMap\": {\n if (!isPlainObject(json)) {\n throw new CrdtSchemaError(\"Expected an object to hydrate yMap\");\n }\n\n const value = (current as AnySchemaNode & { value: AnySchemaNode }).value;\n const map = new YMap();\n\n Object.entries(json).forEach(([key, entry]) => {\n map.set(key, hydrateValue(value, entry));\n });\n\n return map;\n }\n case \"yText\": {\n if (typeof json !== \"string\") {\n throw new CrdtSchemaError(\"Expected a string to hydrate yText\");\n }\n\n const text = new YText();\n if (json) text.insert(0, json);\n return text;\n }\n default:\n throw new CrdtSchemaError(`Cannot hydrate schema kind \"${current.kind}\" from JSON`);\n }\n};\n\nconst fillShare = (share: unknown, node: AnySchemaNode, json: unknown): void => {\n switch (node.kind) {\n case \"yArray\": {\n if (!Array.isArray(json)) {\n throw new CrdtSchemaError(\"Expected an array to seed yArray\");\n }\n\n const item = (node as AnySchemaNode & { item: AnySchemaNode }).item;\n const array = share as YArray<unknown>;\n\n json.forEach((entry, index) => {\n array.insert(index, [hydrateValue(item, entry)]);\n });\n return;\n }\n case \"yMap\": {\n if (!isPlainObject(json)) {\n throw new CrdtSchemaError(\"Expected an object to seed yMap\");\n }\n\n const value = (node as AnySchemaNode & { value: AnySchemaNode }).value;\n const map = share as YMap<unknown>;\n\n Object.entries(json).forEach(([key, entry]) => {\n map.set(key, hydrateValue(value, entry));\n });\n return;\n }\n case \"yText\": {\n if (typeof json !== \"string\") {\n throw new CrdtSchemaError(\"Expected a string to seed yText\");\n }\n\n const text = share as YText;\n if (json) text.insert(0, json);\n return;\n }\n default:\n throw new CrdtSchemaError(`Cannot seed kind \"${node.kind}\"`);\n }\n};\n\nexport const hydrateTopLevel = (\n doc: YDoc,\n schema: YjsSchema,\n seed?: Record<string, unknown>,\n): Record<string, unknown> => {\n if (seed) {\n const extra = Object.keys(seed).filter((key) => !(key in schema.shape));\n\n if (extra.length) {\n throw new CrdtSchemaError(`Unexpected seed keys: ${extra.join(\", \")}`);\n }\n }\n\n return Object.entries(schema.shape).reduce<Record<string, unknown>>((acc, [key, node]) => {\n const share = getYjsShare(doc, key, node.kind);\n const value = seed?.[key];\n\n if (value !== undefined) {\n if (isUnseedableKind(node.kind)) {\n throw new CrdtSchemaError(`Cannot JSON-seed \"${key}\" (${node.kind})`);\n }\n\n fillShare(share, node, value);\n }\n\n acc[key] = share;\n return acc;\n }, {});\n};\n","import type {\n DocApplyEncodedStateParams,\n DocBatchApplyEncodedStateParams,\n DocSubscribeCallbackParams,\n} from \"@pluv/crdt\";\nimport type { CrdtDocLike } from \"@pluv/types\";\nimport { fromUint8Array, toUint8Array } from \"js-base64\";\nimport {\n AbstractType,\n ContentEmbed,\n ContentFormat,\n ContentString,\n UndoManager,\n Array as YArray,\n Doc as YDoc,\n Map as YMap,\n Text as YText,\n XmlElement as YXmlElement,\n XmlFragment as YXmlFragment,\n XmlText as YXmlText,\n applyUpdate,\n decodeStateVector,\n encodeStateAsUpdate,\n encodeStateVector,\n mergeUpdates,\n parseUpdateMeta,\n snapshot,\n snapshotContainsUpdate,\n} from \"yjs\";\nimport { getYjsShare, hydrateTopLevel } from \"../schema/hydrate\";\nimport type { InferYjsJson, InferYjsStorage } from \"../schema/schema\";\nimport type { YjsSchema } from \"./YjsSchema\";\n\nconst MERGE_INTERVAL_MS = 1_000;\nconst PLUV_ID_FIELD = \"__$pluv\";\n\nconst clocksFromVector = (\n clocks: Iterable<readonly [unknown, number]>,\n): readonly (readonly [string, number])[] =>\n [...clocks]\n .map(([id, clock]) => [String(id), clock] as const)\n // oxlint-disable-next-line unicorn/no-array-sort -- the map already returned a new array\n .sort((left, right) => (left[0] < right[0] ? -1 : left[0] > right[0] ? 1 : 0));\n\nexport class CrdtYjsDoc<TSchema extends YjsSchema = YjsSchema> implements CrdtDocLike<\n YDoc,\n InferYjsStorage<TSchema>,\n InferYjsJson<TSchema>\n> {\n public value: YDoc = new YDoc();\n\n #_schema: TSchema;\n #_storage: InferYjsStorage<TSchema>;\n #_undoManager: UndoManager | null = null;\n\n constructor(schema: TSchema, seed?: Record<string, unknown>, hydrate: boolean = false) {\n this.#_schema = schema;\n\n if (hydrate) {\n this.#_storage = hydrateTopLevel(this.value, schema, seed) as InferYjsStorage<TSchema>;\n if (Object.keys(schema.shape).length) this.#_setPluvId();\n } else {\n this.#_storage = {} as InferYjsStorage<TSchema>;\n }\n }\n\n public applyEncodedState(params: DocApplyEncodedStateParams): this {\n const { origin, update } = params;\n\n if (update === null || typeof update === \"undefined\") return this;\n\n const uint8Update = typeof update === \"string\" ? toUint8Array(update) : update;\n\n applyUpdate(this.value, uint8Update, origin);\n\n return this;\n }\n\n public batchApplyEncodedState(params: DocBatchApplyEncodedStateParams): this {\n const { origin } = params;\n const updates = params.updates ?? [];\n\n const filtered = updates.reduce<Uint8Array[]>((acc, update) => {\n if (!update) return acc;\n\n if (typeof update === \"string\") {\n acc.push(toUint8Array(update));\n return acc;\n }\n\n if (typeof update === \"object\") {\n acc.push(update);\n return acc;\n }\n\n return acc;\n }, []);\n\n if (!filtered.length) return this;\n\n const merged = mergeUpdates(filtered);\n\n return this.applyEncodedState({ origin, update: merged });\n }\n\n public captureUpdate(fn: () => void): string | null {\n const updates: Uint8Array[] = [];\n const onUpdate = (update: Uint8Array) => {\n updates.push(update);\n };\n\n this.value.on(\"update\", onUpdate);\n\n try {\n fn();\n } finally {\n this.value.off(\"update\", onUpdate);\n }\n\n const [first] = updates;\n\n if (!first) return null;\n\n const update =\n updates.length === 1 ? fromUint8Array(first) : fromUint8Array(mergeUpdates(updates));\n\n return update === \"\" ? null : update;\n }\n\n public canRedo(): boolean {\n return !!this.#_undoManager?.canRedo();\n }\n\n public canUndo(): boolean {\n return !!this.#_undoManager?.canUndo();\n }\n\n public destroy(): void {\n this.#_undoManager?.destroy();\n this.value.destroy();\n }\n\n public get(key?: undefined): InferYjsStorage<TSchema>;\n public get<TKey extends keyof InferYjsStorage<TSchema>>(\n type: TKey,\n ): InferYjsStorage<TSchema>[TKey];\n public get<TKey extends keyof InferYjsStorage<TSchema>>(\n type?: TKey,\n ): InferYjsStorage<TSchema> | InferYjsStorage<TSchema>[TKey] {\n if (typeof type === \"undefined\") return this.#_storage;\n\n return this.#_storage[type as TKey];\n }\n\n public encodeDiff(stateVector: string): string {\n if (!stateVector) return this.getEncodedState();\n\n // encodeStateAsUpdate decodes the vector itself.\n return fromUint8Array(encodeStateAsUpdate(this.value, toUint8Array(stateVector)));\n }\n\n public getEncodedState(): string {\n return fromUint8Array(encodeStateAsUpdate(this.value));\n }\n\n public getStateVector(): string {\n return fromUint8Array(encodeStateVector(this.value));\n }\n\n public readStateVersion(encoded: string): readonly (readonly [string, number])[] {\n return clocksFromVector(encoded ? decodeStateVector(toUint8Array(encoded)) : new Map());\n }\n\n public readUpdateVersion(update: string): readonly (readonly [string, number])[] {\n if (!update) return [];\n\n // `to` is the clock after these bytes. The state vector of an update drops\n // that clock when the bytes depend on an earlier change from the same client.\n return clocksFromVector(parseUpdateMeta(toUint8Array(update)).to);\n }\n\n public containsUpdate(update: string): boolean {\n if (!update) return true;\n\n // Deletes live in the snapshot, not the state vector. The update is contained\n // when merging its deletes leaves that snapshot unchanged.\n return snapshotContainsUpdate(snapshot(this.value), toUint8Array(update));\n }\n\n public hasPending(): boolean {\n if (!this.canDetectPending()) return true;\n\n return this.value.store.pendingStructs !== null || this.value.store.pendingDs !== null;\n }\n\n /**\n * @description Yjs keeps updates that could not be applied on `store.pendingStructs`\n * and `store.pendingDs`. A missing field means this check cannot tell.\n */\n public canDetectPending(): boolean {\n const store = this.value.store;\n\n return !!store && \"pendingStructs\" in store && \"pendingDs\" in store;\n }\n\n public isDirty(): boolean {\n return !!this.value.store.clients.size;\n }\n\n public isEmpty(): boolean {\n return !this.value.share.size;\n }\n\n public rebuildStorage(): this {\n const isBuilt = !!Object.keys(this.#_storage).length;\n\n if (isBuilt) {\n console.warn(\"Attempted to rebuild storage multiple times\");\n return this;\n }\n\n this.#_storage = Object.entries(this.#_schema.shape).reduce((acc, [key, node]) => {\n Object.assign(acc, { [key]: getYjsShare(this.value, key, node.kind) });\n return acc;\n }, {} as InferYjsStorage<TSchema>);\n\n return this.track();\n }\n\n public redo(): this {\n this.#_undoManager?.redo();\n\n return this;\n }\n\n public subscribe(\n listener: (\n params: DocSubscribeCallbackParams<\n YDoc,\n InferYjsStorage<TSchema>,\n InferYjsJson<TSchema>\n >,\n ) => void,\n ): () => void {\n const fn = (update: Uint8Array, origin: any, _doc: YDoc) => {\n listener({\n doc: this,\n local: origin === null || typeof origin === \"undefined\",\n origin: origin ? String(origin) : null,\n update: fromUint8Array(update),\n });\n };\n\n this.value.on(\"update\", fn);\n\n return () => {\n this.value.off(\"update\", fn);\n };\n }\n\n public track(): this {\n if (this.#_undoManager) this.#_undoManager.destroy();\n\n const sharedTypes = Object.values(this.#_storage).reduce<AbstractType<any>[]>(\n (acc, type) => {\n if (\n type instanceof YArray ||\n type instanceof YMap ||\n type instanceof YText ||\n type instanceof YXmlElement ||\n type instanceof YXmlFragment ||\n type instanceof YXmlText\n ) {\n acc.push(type);\n }\n\n return acc;\n },\n [],\n );\n\n if (!sharedTypes.length) {\n this.#_undoManager?.destroy();\n this.#_undoManager = null;\n\n return this;\n }\n\n this.#_undoManager = new UndoManager(sharedTypes, { captureTimeout: MERGE_INTERVAL_MS });\n\n return this;\n }\n\n public transact(fn: () => void): this {\n this.value.transact(fn);\n\n return this;\n }\n\n public toJson(): InferYjsJson<TSchema>;\n public toJson<TKey extends keyof InferYjsJson<TSchema>>(\n type: TKey,\n ): InferYjsJson<TSchema>[TKey];\n public toJson<TKey extends keyof InferYjsJson<TSchema>>(type?: TKey) {\n if (typeof type === \"string\") {\n const shared = this.#_storage[type];\n\n if (shared && typeof (shared as { toJSON?: () => unknown }).toJSON === \"function\") {\n return (shared as { toJSON: () => unknown }).toJSON();\n }\n\n const fromDoc = this.value.share.get(type);\n\n return (this.#_toJsonFromShare(type, fromDoc) ?? null) as InferYjsJson<TSchema>[TKey];\n }\n\n return this.#_toJsonFromDoc();\n }\n\n public undo(): this {\n this.#_undoManager?.undo();\n\n return this;\n }\n\n #_setPluvId() {\n const text = this.value.getText(PLUV_ID_FIELD);\n const id = typeof crypto !== \"undefined\" ? crypto.randomUUID() : Math.random().toString();\n\n text.insert(0, id);\n }\n\n #_toJsonFromDoc(): InferYjsJson<TSchema> {\n const json = {} as InferYjsJson<TSchema>;\n\n this.value.share.forEach((sharedType, key) => {\n if (key === PLUV_ID_FIELD) return;\n\n Object.assign(json, { [key]: this.#_toJsonFromShare(key, sharedType) });\n });\n\n return json;\n }\n\n #_toJsonFromShare(key: string, sharedType: AbstractType<any> | undefined): unknown {\n if (!sharedType) return null;\n\n if (\n sharedType instanceof YXmlElement ||\n sharedType instanceof YXmlFragment ||\n sharedType instanceof YXmlText ||\n sharedType instanceof YText ||\n sharedType instanceof YArray ||\n sharedType instanceof YMap\n ) {\n return sharedType.toJSON();\n }\n\n const start = (\n sharedType as AbstractType<any> & {\n _start?: { content?: object } | null;\n _map?: Map<string, unknown>;\n }\n )._start;\n const map = (\n sharedType as AbstractType<any> & {\n _map?: Map<string, unknown>;\n }\n )._map;\n const content = start?.content ?? null;\n\n if (\n content instanceof ContentString ||\n content instanceof ContentEmbed ||\n content instanceof ContentFormat\n ) {\n return this.value.getText(key).toJSON();\n }\n\n if (map && map.size > 0 && start) {\n return this.value.getXmlElement(key).toJSON();\n }\n\n if (start) {\n return this.value.getArray(key).toJSON();\n }\n\n if (map && map.size > 0) {\n return this.value.getMap(key).toJSON();\n }\n\n return {};\n }\n}\n","import {\n AbstractCrdtDocFactory,\n createSchemaNode,\n type AnySchemaNode,\n type InferShapeJson,\n type InferShapeSeed,\n type InferShapeStorage,\n} from \"@pluv/crdt\";\nimport type { Doc as YDoc } from \"yjs\";\nimport { CrdtYjsDoc } from \"./CrdtYjsDoc\";\n\nexport class YjsSchema<\n TShape extends Record<string, AnySchemaNode> = Record<string, AnySchemaNode>,\n> extends AbstractCrdtDocFactory<\n YDoc,\n InferShapeStorage<TShape>,\n InferShapeJson<TShape>,\n InferShapeSeed<TShape>\n> {\n public readonly kind = \"y.doc\" as const;\n public readonly shape: TShape;\n public readonly _seed?: InferShapeSeed<TShape>;\n\n constructor(shape: TShape, seed?: InferShapeSeed<TShape>) {\n super();\n\n this.shape = shape;\n this._seed = seed;\n }\n\n public toJSON(): { kind: \"y.doc\"; shape: Record<string, unknown> } {\n return createSchemaNode(\"y.doc\", { shape: this.shape }).toJSON() as {\n kind: \"y.doc\";\n shape: Record<string, unknown>;\n };\n }\n\n public getEmpty(): CrdtYjsDoc<YjsSchema<TShape>> {\n return new CrdtYjsDoc<YjsSchema<TShape>>(this);\n }\n\n public getFactory(seed?: InferShapeSeed<TShape>): YjsSchema<TShape> {\n return new YjsSchema<TShape>(this.shape, seed ?? this._seed);\n }\n\n public getInitialized(seed?: InferShapeSeed<TShape>): CrdtYjsDoc<YjsSchema<TShape>> {\n return new CrdtYjsDoc<YjsSchema<TShape>>(\n this,\n (seed ?? this._seed) as Record<string, unknown> | undefined,\n true,\n );\n }\n}\n","import {\n assertNotOptional,\n createSchemaNode,\n type AnySchemaNode,\n type InferNodeJson,\n type InferNodeSeed,\n type InferNodeStorage,\n type SchemaNode,\n} from \"@pluv/crdt\";\nimport {\n Array as YArray,\n Map as YMap,\n Text as YText,\n XmlElement as YXmlElement,\n XmlFragment as YXmlFragment,\n XmlText as YXmlText,\n} from \"yjs\";\n\nexport type YjsArrayNode<TItem extends AnySchemaNode> = SchemaNode<\n \"yArray\",\n YArray<InferNodeStorage<TItem>>,\n InferNodeJson<TItem>[],\n InferNodeSeed<TItem>[]\n> & { readonly item: TItem };\n\nexport type YjsMapNode<TValue extends AnySchemaNode> = SchemaNode<\n \"yMap\",\n YMap<InferNodeStorage<TValue>>,\n Record<string, InferNodeJson<TValue>>,\n Record<string, InferNodeSeed<TValue>>\n> & { readonly value: TValue };\n\nexport type YjsTextNode = SchemaNode<\"yText\", YText, string, string>;\nexport type YjsXmlTextNode = SchemaNode<\"yXmlText\", YXmlText, string, never>;\nexport type YjsXmlElementNode = SchemaNode<\"yXmlElement\", YXmlElement, string, never>;\nexport type YjsXmlFragmentNode = SchemaNode<\"yXmlFragment\", YXmlFragment, string, never>;\n\nexport const yArray = <TItem extends AnySchemaNode>(item: TItem): YjsArrayNode<TItem> => {\n assertNotOptional(item, \"yjs.yArray item\");\n\n return createSchemaNode(\"yArray\", { item }) as YjsArrayNode<TItem>;\n};\n\nexport const yMap = <TValue extends AnySchemaNode>(value: TValue): YjsMapNode<TValue> => {\n assertNotOptional(value, \"yjs.yMap value\");\n\n return createSchemaNode(\"yMap\", { value }) as YjsMapNode<TValue>;\n};\n\nexport const yText = (): YjsTextNode => {\n return createSchemaNode(\"yText\", {}) as YjsTextNode;\n};\n\nexport const yXmlText = (): YjsXmlTextNode => {\n return createSchemaNode(\"yXmlText\", {}) as YjsXmlTextNode;\n};\n\nexport const yXmlElement = (): YjsXmlElementNode => {\n return createSchemaNode(\"yXmlElement\", {}) as YjsXmlElementNode;\n};\n\nexport const yXmlFragment = (): YjsXmlFragmentNode => {\n return createSchemaNode(\"yXmlFragment\", {}) as YjsXmlFragmentNode;\n};\n","import {\n CrdtSchemaError,\n fromJSON as fromJsonSchema,\n isYjsCrdtKind,\n type AnySchemaNode,\n type SchemaAst,\n} from \"@pluv/crdt\";\nimport { yArray, yMap, yText, yXmlElement, yXmlFragment, yXmlText } from \"./nodes\";\n\nexport const fromJSON = (ast: SchemaAst): AnySchemaNode => {\n switch (ast.kind) {\n case \"yArray\":\n return yArray(fromJSON(ast.item as SchemaAst));\n case \"yMap\":\n return yMap(fromJSON(ast.value as SchemaAst));\n case \"yText\":\n return yText();\n case \"yXmlText\":\n return yXmlText();\n case \"yXmlElement\":\n return yXmlElement();\n case \"yXmlFragment\":\n return yXmlFragment();\n default:\n if (isYjsCrdtKind(ast.kind)) {\n throw new CrdtSchemaError(`Unhandled Yjs schema kind \"${ast.kind}\"`);\n }\n\n return fromJsonSchema(ast);\n }\n};\n","import {\n CrdtSchemaError,\n isLoroCrdtKind,\n isSchemaNode,\n isYjsCrdtKind,\n type AnySchemaNode,\n type InferShapeJson,\n type InferShapeSeed,\n type InferShapeStorage,\n type SchemaAst,\n} from \"@pluv/crdt\";\nimport { YjsSchema } from \"../doc/YjsSchema\";\nimport { fromJSON as fromJsonNode } from \"./fromJSON\";\n\nexport type InferYjsStorage<TSchema extends YjsSchema<any>> = InferShapeStorage<TSchema[\"shape\"]>;\nexport type InferYjsJson<TSchema extends YjsSchema<any>> = InferShapeJson<TSchema[\"shape\"]>;\nexport type InferYjsSeed<TSchema extends YjsSchema<any>> = InferShapeSeed<TSchema[\"shape\"]>;\n\nexport const isYjsSchema = (value: unknown): value is YjsSchema => {\n return value instanceof YjsSchema;\n};\n\nexport const schema = <TShape extends Record<string, AnySchemaNode>>(\n shape: TShape,\n): YjsSchema<TShape> => {\n Object.entries(shape).forEach(([key, node]) => {\n if (!isSchemaNode(node)) {\n throw new CrdtSchemaError(`yjs.schema field \"${key}\" must be a schema node`);\n }\n\n if (isLoroCrdtKind(node.kind)) {\n throw new CrdtSchemaError(`yjs.schema field \"${key}\" cannot be a Loro node`);\n }\n\n if (!isYjsCrdtKind(node.kind)) {\n throw new CrdtSchemaError(`yjs.schema field \"${key}\" must be a Yjs CRDT node`);\n }\n });\n\n return new YjsSchema(shape);\n};\n\nschema.fromJSON = (ast: SchemaAst): YjsSchema => {\n if (ast.kind !== \"y.doc\") {\n throw new CrdtSchemaError(`Expected kind \"y.doc\", received \"${ast.kind}\"`);\n }\n\n const shapeAst = (ast.shape ?? {}) as Record<string, SchemaAst>;\n const shape = Object.entries(shapeAst).reduce<Record<string, AnySchemaNode>>(\n (acc, [key, value]) => {\n acc[key] = fromJsonNode(value);\n return acc;\n },\n {},\n );\n\n return schema(shape);\n};\n","import { schema } from \"../schema/schema\";\nimport { YjsSchema } from \"./YjsSchema\";\n\nexport const doc = (_value?: any): YjsSchema => {\n return schema({});\n};\n","import { Map as YMap } from \"yjs\";\n\nexport const map = <T extends unknown>(\n value: readonly (readonly [key: string, value: T])[] = [],\n): YMap<T> => {\n const shared = new YMap<T>(value);\n\n return shared;\n};\n","import type { IOLike, RoomLike } from \"@pluv/types\";\nimport { StorageState } from \"@pluv/types\";\nimport { ObservableV2 } from \"lib0/observable\";\nimport type { Doc as YDoc } from \"yjs\";\nimport type { PluvYjsAwareness } from \"../awareness\";\nimport { awareness } from \"../awareness\";\nimport type { YjsProviderStatus } from \"../types\";\n\nexport interface PluvYjsProviderParams<\n TIO extends IOLike,\n TPresence extends Record<string, any>,\n TStorage extends Record<string, any>,\n TField extends keyof TPresence | null = null,\n> {\n presenceField?: TField;\n room: RoomLike<TIO, YDoc, TPresence, TStorage>;\n}\n\n/**\n * !HACK\n * @description This doesn't really do anything but emit states in a Yjs.Provider compatible way.\n * Connections and document syncing are handled by the PluvRoom already.\n * @date May 13, 2025\n */\nexport class PluvYjsProvider<\n TIO extends IOLike,\n TPresence extends Record<string, any>,\n TStorage extends Record<string, any>,\n TField extends keyof TPresence | null = null,\n> extends ObservableV2<{\n \"connection-close\": (\n event: CloseEvent | null,\n provider: PluvYjsProvider<TIO, TPresence, TStorage, TField>,\n ) => void;\n \"connection-error\": (\n event: Event,\n provider: PluvYjsProvider<TIO, TPresence, TStorage, TField>,\n ) => void;\n status: (event: { status: YjsProviderStatus }) => void;\n sync: (state: boolean) => void;\n synced: (state: boolean) => void;\n}> {\n public readonly awareness: PluvYjsAwareness<TIO, TPresence, TStorage, TField>;\n\n private readonly _room: RoomLike<TIO, YDoc, TPresence, TStorage>;\n private readonly _unsubscribe: () => void;\n\n private _synced: boolean = false;\n\n // Always read the live doc. The room may replace it after destroy/re-init.\n public get doc(): YDoc {\n return this._room.getDoc().value;\n }\n\n constructor(params: PluvYjsProviderParams<TIO, TPresence, TStorage, TField>) {\n super();\n\n const { presenceField, room } = params;\n\n this.awareness = awareness({ presenceField, room });\n this._room = room;\n\n const subscriptions = [\n this._room.subscribe.connection(({ storage }) => {\n const status = this._toProviderStatus(storage.state);\n\n if (!status) return;\n\n this.emit(\"status\", [{ status }]);\n }),\n this._room.addEventListener(\"close\", (event) => {\n this.emit(\"connection-close\", [event, this]);\n }),\n this._room.addEventListener(\"error\", (event) => {\n this.emit(\"connection-error\", [event, this]);\n }),\n ];\n\n this._unsubscribe = subscriptions.reduce(\n (fn, unsubscribe) => () => {\n fn();\n unsubscribe();\n },\n () => undefined,\n );\n }\n\n public get synced(): boolean {\n return this._synced;\n }\n\n public set synced(state: boolean) {\n if (this._synced === state) return;\n\n this._synced = state;\n this.emit(\"sync\", [state]);\n this.emit(\"synced\", [state]);\n }\n\n public destroy(): void {\n this.awareness.destroy();\n this._unsubscribe();\n super.destroy();\n }\n\n private _toProviderStatus(state: StorageState): YjsProviderStatus | null {\n switch (state) {\n case StorageState.Loading: {\n return \"connecting\";\n }\n case StorageState.Unavailable: {\n return \"disconnected\";\n }\n case StorageState.Offline:\n case StorageState.Synced: {\n return \"connected\";\n }\n default:\n return null;\n }\n }\n\n /**\n * !HACK\n * @description We dgaf about these, since the room manages these already. We're just mirroring\n * the fields that exist in the og provider to make sure everything aligns.\n * @see https://github.com/yjs/y-websocket/blob/master/src/y-websocket.js\n * @date May 13, 2025\n */\n public connect(): void {}\n public disconnect(): void {}\n}\n","import type { IOLike } from \"@pluv/types\";\nimport type { PluvYjsProviderParams } from \"./PluvYjsProvider\";\nimport { PluvYjsProvider } from \"./PluvYjsProvider\";\n\nexport const provider = <\n TIO extends IOLike,\n TPresence extends Record<string, any>,\n TStorage extends Record<string, any>,\n TField extends keyof TPresence | null = null,\n>(\n params: PluvYjsProviderParams<TIO, TPresence, TStorage, TField>,\n) => {\n return new PluvYjsProvider(params);\n};\n","import { Text as YText } from \"yjs\";\n\nexport const text = (value: string = \"\"): YText => {\n const shared = new YText();\n\n if (value) shared.insert(0, value);\n\n return shared;\n};\n","import type { XmlElement as YXmlElement, XmlText as YXmlText } from \"yjs\";\nimport { XmlElement as XmlElementCtor } from \"yjs\";\n\nexport const xmlElement = <T extends Record<string, any> = Record<string, any>>(\n name: string,\n children: (YXmlElement | YXmlText)[] | readonly (YXmlElement | YXmlText)[] = [],\n): YXmlElement<T> => {\n const shared = new XmlElementCtor<T>(name);\n\n if (children.length) shared.insert(0, children as (YXmlElement | YXmlText)[]);\n\n return shared;\n};\n","import type { XmlElement as YXmlElement, XmlText as YXmlText } from \"yjs\";\nimport { XmlFragment as YXmlFragment } from \"yjs\";\n\nexport const xmlFragment = (\n children: (YXmlElement | YXmlText)[] | readonly (YXmlElement | YXmlText)[] = [],\n): YXmlFragment => {\n const shared = new YXmlFragment();\n\n if (children.length) shared.insert(0, children as (YXmlElement | YXmlText)[]);\n\n return shared;\n};\n","import { XmlText as YXmlText } from \"yjs\";\n\nexport const xmlText = (): YXmlText => {\n return new YXmlText();\n};\n","export { array } from \"./array\";\nexport { awareness } from \"./awareness\";\nexport { doc } from \"./doc\";\nexport { map } from \"./map\";\nexport { provider } from \"./provider\";\nexport { schema, yArray, yMap, yText, yXmlElement, yXmlFragment, yXmlText } from \"./schema\";\nexport { text } from \"./text\";\nexport { xmlElement } from \"./xmlElement\";\nexport { xmlFragment } from \"./xmlFragment\";\nexport { xmlText } from \"./xmlText\";\nexport const kind = \"yjs\" as const;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// \0rolldown/runtime.js
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __exportAll = (all, no_symbols) => {
|
|
4
|
+
let target = {};
|
|
5
|
+
for (var name in all) __defProp(target, name, {
|
|
6
|
+
get: all[name],
|
|
7
|
+
enumerable: true
|
|
8
|
+
});
|
|
9
|
+
if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
|
|
10
|
+
return target;
|
|
11
|
+
};
|
|
12
|
+
export { __exportAll as t };
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@pluv/crdt-yjs",
|
|
3
|
+
"version": "0.0.0-canary-20261027014949",
|
|
4
|
+
"description": "yjs for @pluv/io",
|
|
5
|
+
"author": {
|
|
6
|
+
"email": "david@pluv.io",
|
|
7
|
+
"name": "i3dly",
|
|
8
|
+
"url": "https://github.com/i3dly"
|
|
9
|
+
},
|
|
10
|
+
"license": "MIT",
|
|
11
|
+
"homepage": "https://github.com/pluv-io/pluv",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "git+https://github.com/pluv-io/pluv.git",
|
|
15
|
+
"directory": "packages/crdt-yjs"
|
|
16
|
+
},
|
|
17
|
+
"type": "module",
|
|
18
|
+
"types": "./dist/index.d.mts",
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@pluv/crdt": "^0.0.0-canary-20261027014949",
|
|
27
|
+
"@pluv/types": "^0.0.0-canary-20261027014949",
|
|
28
|
+
"@types/node": "^26.6.5",
|
|
29
|
+
"js-base64": "^3.9.4",
|
|
30
|
+
"lib0": "^0.2.119"
|
|
31
|
+
},
|
|
32
|
+
"peerDependencies": {
|
|
33
|
+
"yjs": "^13.0.0"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@pluv/tsconfig": "^0.0.0-canary-20261027014949",
|
|
37
|
+
"tsdown": "^0.23.2",
|
|
38
|
+
"typescript": "7.1.0-beta",
|
|
39
|
+
"vitest": "^5.0.5",
|
|
40
|
+
"yjs": "^13.6.33"
|
|
41
|
+
},
|
|
42
|
+
"exports": {
|
|
43
|
+
".": "./dist/index.mjs",
|
|
44
|
+
"./rolldown-runtime-D8jQpDG7": "./dist/rolldown-runtime-D8jQpDG7.mjs",
|
|
45
|
+
"./*": "./*"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsdown",
|
|
49
|
+
"dev": "tsdown --watch",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:watch": "vitest",
|
|
53
|
+
"clean": "rm -rf .turbo && rm -rf node_modules && rm -rf dist"
|
|
54
|
+
}
|
|
55
|
+
}
|