@kyneta/yjs-schema 1.1.0 → 1.2.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.
- package/dist/index.d.ts +34 -74
- package/dist/index.js +181 -132
- package/dist/index.js.map +1 -1
- package/package.json +5 -3
- package/src/__tests__/bind-constraints.test.ts +333 -0
- package/src/__tests__/bind-yjs.test.ts +38 -40
- package/src/__tests__/create.test.ts +10 -11
- package/src/__tests__/reader.test.ts +38 -61
- package/src/__tests__/record-text-spike.test.ts +9 -10
- package/src/__tests__/structural-merge.test.ts +18 -18
- package/src/__tests__/substrate.test.ts +18 -21
- package/src/__tests__/version.test.ts +75 -0
- package/src/bind-yjs.ts +72 -42
- package/src/change-mapping.ts +46 -55
- package/src/create.ts +2 -2
- package/src/index.ts +12 -25
- package/src/populate.ts +50 -83
- package/src/substrate.ts +52 -7
- package/src/version.ts +55 -0
- package/src/yjs-resolve.ts +1 -11
- package/src/yjs-escape.ts +0 -84
package/dist/index.js
CHANGED
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
|
|
10
10
|
// src/create.ts
|
|
11
11
|
import {
|
|
12
|
-
changefeed,
|
|
13
12
|
interpret,
|
|
13
|
+
observation,
|
|
14
14
|
readable,
|
|
15
15
|
registerSubstrate,
|
|
16
16
|
writable
|
|
@@ -21,7 +21,7 @@ import { BACKING_DOC, buildWritableContext, executeBatch } from "@kyneta/schema"
|
|
|
21
21
|
import * as Y5 from "yjs";
|
|
22
22
|
|
|
23
23
|
// src/change-mapping.ts
|
|
24
|
-
import { advanceSchema as advanceSchema2, expandMapOpsToLeaves, RawPath } from "@kyneta/schema";
|
|
24
|
+
import { advanceSchema as advanceSchema2, expandMapOpsToLeaves, KIND as KIND2, RawPath } from "@kyneta/schema";
|
|
25
25
|
import * as Y2 from "yjs";
|
|
26
26
|
|
|
27
27
|
// src/yjs-resolve.ts
|
|
@@ -43,10 +43,6 @@ function stepIntoYjs(current, segment) {
|
|
|
43
43
|
function resolveYjsType(rootMap, rootSchema, path) {
|
|
44
44
|
let current = rootMap;
|
|
45
45
|
let schema = rootSchema;
|
|
46
|
-
let rootProduct = rootSchema;
|
|
47
|
-
while (rootProduct._kind === "annotated" && rootProduct.schema !== void 0) {
|
|
48
|
-
rootProduct = rootProduct.schema;
|
|
49
|
-
}
|
|
50
46
|
for (let i = 0; i < path.length; i++) {
|
|
51
47
|
const seg = path.segments[i];
|
|
52
48
|
const nextSchema = advanceSchema(schema, seg);
|
|
@@ -73,11 +69,11 @@ function applyChangeToYjs(rootMap, rootSchema, path, change2) {
|
|
|
73
69
|
return;
|
|
74
70
|
case "increment":
|
|
75
71
|
throw new Error(
|
|
76
|
-
`Yjs substrate does not support
|
|
72
|
+
`Yjs substrate does not support "${change2.type}" changes. Counter requires a CRDT backend that supports counters (e.g. Loro). Attempted IncrementChange with amount=${change2.amount} at path [${pathToString(path)}].`
|
|
77
73
|
);
|
|
78
74
|
case "tree":
|
|
79
75
|
throw new Error(
|
|
80
|
-
`Yjs substrate does not support
|
|
76
|
+
`Yjs substrate does not support "${change2.type}" changes. Tree requires a CRDT backend that supports trees (e.g. Loro). Attempted TreeChange at path [${pathToString(path)}].`
|
|
81
77
|
);
|
|
82
78
|
default:
|
|
83
79
|
throw new Error(
|
|
@@ -167,29 +163,25 @@ function applyReplaceChange(rootMap, rootSchema, path, change2) {
|
|
|
167
163
|
}
|
|
168
164
|
function maybeCreateSharedType(value, schema) {
|
|
169
165
|
if (schema === void 0) return value;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
166
|
+
switch (schema[KIND2]) {
|
|
167
|
+
// First-class text → Y.Text
|
|
168
|
+
case "text": {
|
|
169
|
+
const text = new Y2.Text();
|
|
170
|
+
if (typeof value === "string" && value.length > 0) {
|
|
171
|
+
text.insert(0, value);
|
|
172
|
+
}
|
|
173
|
+
return text;
|
|
176
174
|
}
|
|
177
|
-
return text2;
|
|
178
|
-
}
|
|
179
|
-
if (tag === "counter" || tag === "movable" || tag === "tree") {
|
|
180
|
-
throw new Error(`Yjs substrate does not support "${tag}" annotations.`);
|
|
181
|
-
}
|
|
182
|
-
switch (structural._kind) {
|
|
183
175
|
case "product": {
|
|
184
176
|
if (value === null || value === void 0 || typeof value !== "object" || Array.isArray(value)) {
|
|
185
177
|
return value;
|
|
186
178
|
}
|
|
187
|
-
return createStructuredMap(value,
|
|
179
|
+
return createStructuredMap(value, schema);
|
|
188
180
|
}
|
|
189
181
|
case "sequence": {
|
|
190
182
|
if (!Array.isArray(value)) return value;
|
|
191
183
|
const arr = new Y2.Array();
|
|
192
|
-
const itemSchema =
|
|
184
|
+
const itemSchema = schema.item;
|
|
193
185
|
const items = value.map(
|
|
194
186
|
(item) => maybeCreateSharedType(item, itemSchema)
|
|
195
187
|
);
|
|
@@ -201,20 +193,28 @@ function maybeCreateSharedType(value, schema) {
|
|
|
201
193
|
return value;
|
|
202
194
|
}
|
|
203
195
|
const map = new Y2.Map();
|
|
204
|
-
const valueSchema =
|
|
196
|
+
const valueSchema = schema.item;
|
|
205
197
|
for (const [k, v] of Object.entries(value)) {
|
|
206
198
|
map.set(k, maybeCreateSharedType(v, valueSchema));
|
|
207
199
|
}
|
|
208
200
|
return map;
|
|
209
201
|
}
|
|
202
|
+
// Unsupported first-class CRDT types — should not reach here
|
|
203
|
+
// (rejected at bind time by caps check)
|
|
204
|
+
case "counter":
|
|
205
|
+
case "set":
|
|
206
|
+
case "tree":
|
|
207
|
+
case "movable":
|
|
208
|
+
throw new Error(
|
|
209
|
+
`Yjs substrate does not support [KIND]="${schema[KIND2]}". This should have been caught at bind() time.`
|
|
210
|
+
);
|
|
210
211
|
default:
|
|
211
212
|
return value;
|
|
212
213
|
}
|
|
213
214
|
}
|
|
214
215
|
function createStructuredMap(obj, productSchema) {
|
|
215
216
|
const map = new Y2.Map();
|
|
216
|
-
|
|
217
|
-
if (structural._kind !== "product") {
|
|
217
|
+
if (productSchema[KIND2] !== "product") {
|
|
218
218
|
for (const [key, val] of Object.entries(obj)) {
|
|
219
219
|
map.set(key, val);
|
|
220
220
|
}
|
|
@@ -222,22 +222,21 @@ function createStructuredMap(obj, productSchema) {
|
|
|
222
222
|
}
|
|
223
223
|
for (const [key, val] of Object.entries(obj)) {
|
|
224
224
|
if (val === void 0) continue;
|
|
225
|
-
const fieldSchema =
|
|
225
|
+
const fieldSchema = productSchema.fields[key];
|
|
226
226
|
const yjsVal = fieldSchema ? maybeCreateSharedType(val, fieldSchema) : val;
|
|
227
227
|
map.set(key, yjsVal);
|
|
228
228
|
}
|
|
229
229
|
for (const [key, fieldSchema] of Object.entries(
|
|
230
|
-
|
|
230
|
+
productSchema.fields
|
|
231
231
|
)) {
|
|
232
232
|
if (key in obj) continue;
|
|
233
|
-
|
|
234
|
-
if (tag === "text") {
|
|
233
|
+
if (fieldSchema[KIND2] === "text") {
|
|
235
234
|
map.set(key, new Y2.Text());
|
|
236
235
|
}
|
|
237
236
|
}
|
|
238
237
|
return map;
|
|
239
238
|
}
|
|
240
|
-
function eventsToOps(events) {
|
|
239
|
+
function eventsToOps(events, schema) {
|
|
241
240
|
const ops = [];
|
|
242
241
|
for (const event of events) {
|
|
243
242
|
const kynetaPath = yjsPathToKynetaPath(event.path);
|
|
@@ -246,7 +245,7 @@ function eventsToOps(events) {
|
|
|
246
245
|
ops.push({ path: kynetaPath, change: change2 });
|
|
247
246
|
}
|
|
248
247
|
}
|
|
249
|
-
return expandMapOpsToLeaves(ops);
|
|
248
|
+
return expandMapOpsToLeaves(ops, schema);
|
|
250
249
|
}
|
|
251
250
|
function yjsPathToKynetaPath(yjsPath) {
|
|
252
251
|
let path = RawPath.empty;
|
|
@@ -329,13 +328,6 @@ function extractEventValue(value) {
|
|
|
329
328
|
if (value instanceof Y2.Text) return value.toJSON();
|
|
330
329
|
return value;
|
|
331
330
|
}
|
|
332
|
-
function unwrapAnnotations(schema) {
|
|
333
|
-
let s = schema;
|
|
334
|
-
while (s._kind === "annotated" && s.schema !== void 0) {
|
|
335
|
-
s = s.schema;
|
|
336
|
-
}
|
|
337
|
-
return s;
|
|
338
|
-
}
|
|
339
331
|
function resolveSchemaAtPath(rootSchema, path) {
|
|
340
332
|
let schema = rootSchema;
|
|
341
333
|
for (const seg of path.segments) {
|
|
@@ -344,16 +336,19 @@ function resolveSchemaAtPath(rootSchema, path) {
|
|
|
344
336
|
return schema;
|
|
345
337
|
}
|
|
346
338
|
function getItemSchema(schema) {
|
|
347
|
-
|
|
348
|
-
|
|
339
|
+
if (schema[KIND2] === "sequence") return schema.item;
|
|
340
|
+
if (schema[KIND2] === "movable") return schema.item;
|
|
341
|
+
return void 0;
|
|
349
342
|
}
|
|
350
343
|
function getFieldSchema(schema, key) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
344
|
+
if (schema[KIND2] === "product") {
|
|
345
|
+
return schema.fields[key];
|
|
346
|
+
}
|
|
347
|
+
if (schema[KIND2] === "map") {
|
|
348
|
+
return schema.item;
|
|
354
349
|
}
|
|
355
|
-
if (
|
|
356
|
-
return
|
|
350
|
+
if (schema[KIND2] === "set") {
|
|
351
|
+
return schema.item;
|
|
357
352
|
}
|
|
358
353
|
return void 0;
|
|
359
354
|
}
|
|
@@ -362,22 +357,18 @@ function pathToString(path) {
|
|
|
362
357
|
}
|
|
363
358
|
|
|
364
359
|
// src/populate.ts
|
|
365
|
-
import { STRUCTURAL_YJS_CLIENT_ID, Zero } from "@kyneta/schema";
|
|
360
|
+
import { KIND as KIND3, STRUCTURAL_YJS_CLIENT_ID, Zero } from "@kyneta/schema";
|
|
366
361
|
import * as Y3 from "yjs";
|
|
367
362
|
function ensureContainers(doc, schema, conditional = false) {
|
|
368
363
|
const rootMap = doc.getMap("root");
|
|
369
|
-
|
|
370
|
-
while (rootProduct._kind === "annotated" && rootProduct.schema !== void 0) {
|
|
371
|
-
rootProduct = rootProduct.schema;
|
|
372
|
-
}
|
|
373
|
-
if (rootProduct._kind !== "product") {
|
|
364
|
+
if (schema[KIND3] !== "product") {
|
|
374
365
|
return;
|
|
375
366
|
}
|
|
376
367
|
const savedClientID = doc.clientID;
|
|
377
368
|
doc.clientID = STRUCTURAL_YJS_CLIENT_ID;
|
|
378
369
|
try {
|
|
379
370
|
doc.transact(() => {
|
|
380
|
-
for (const [key, fieldSchema] of Object.entries(
|
|
371
|
+
for (const [key, fieldSchema] of Object.entries(schema.fields).sort(
|
|
381
372
|
([a], [b]) => a.localeCompare(b)
|
|
382
373
|
)) {
|
|
383
374
|
if (conditional && rootMap.has(key)) continue;
|
|
@@ -389,28 +380,12 @@ function ensureContainers(doc, schema, conditional = false) {
|
|
|
389
380
|
}
|
|
390
381
|
}
|
|
391
382
|
function ensureRootField(rootMap, key, fieldSchema) {
|
|
392
|
-
|
|
393
|
-
switch (tag) {
|
|
383
|
+
switch (fieldSchema[KIND3]) {
|
|
394
384
|
case "text":
|
|
395
385
|
rootMap.set(key, new Y3.Text());
|
|
396
386
|
return;
|
|
397
|
-
case "counter":
|
|
398
|
-
throw new Error(
|
|
399
|
-
`Yjs substrate does not support counter annotations. Use Schema.number() with ReplaceChange instead. Encountered counter annotation at root field "${key}".`
|
|
400
|
-
);
|
|
401
|
-
case "movable":
|
|
402
|
-
throw new Error(
|
|
403
|
-
`Yjs substrate does not support movable list annotations. Yjs has no native movable list type. Encountered movable annotation at root field "${key}".`
|
|
404
|
-
);
|
|
405
|
-
case "tree":
|
|
406
|
-
throw new Error(
|
|
407
|
-
`Yjs substrate does not support tree annotations. Yjs has no native tree type. Encountered tree annotation at root field "${key}".`
|
|
408
|
-
);
|
|
409
|
-
}
|
|
410
|
-
const structural = unwrapAnnotations2(fieldSchema);
|
|
411
|
-
switch (structural._kind) {
|
|
412
387
|
case "product":
|
|
413
|
-
rootMap.set(key, ensureMapContainers(
|
|
388
|
+
rootMap.set(key, ensureMapContainers(fieldSchema));
|
|
414
389
|
return;
|
|
415
390
|
case "sequence":
|
|
416
391
|
rootMap.set(key, new Y3.Array());
|
|
@@ -426,22 +401,25 @@ function ensureRootField(rootMap, key, fieldSchema) {
|
|
|
426
401
|
}
|
|
427
402
|
return;
|
|
428
403
|
}
|
|
404
|
+
case "counter":
|
|
405
|
+
case "set":
|
|
406
|
+
case "tree":
|
|
407
|
+
case "movable":
|
|
408
|
+
throw new Error(
|
|
409
|
+
`Yjs substrate does not support [KIND]="${fieldSchema[KIND3]}". Supported kinds: text, product, sequence, map, scalar, sum. Encountered unsupported kind at root field "${key}".`
|
|
410
|
+
);
|
|
429
411
|
}
|
|
430
412
|
}
|
|
431
413
|
function ensureMapContainers(schema) {
|
|
432
414
|
const map = new Y3.Map();
|
|
433
|
-
|
|
434
|
-
if (structural._kind !== "product") return map;
|
|
415
|
+
if (schema[KIND3] !== "product") return map;
|
|
435
416
|
for (const [key, fieldSchema] of Object.entries(
|
|
436
|
-
|
|
417
|
+
schema.fields
|
|
437
418
|
).sort(([a], [b]) => a.localeCompare(b))) {
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
}
|
|
443
|
-
const fs = unwrapAnnotations2(fieldSchema);
|
|
444
|
-
switch (fs._kind) {
|
|
419
|
+
switch (fieldSchema[KIND3]) {
|
|
420
|
+
case "text":
|
|
421
|
+
map.set(key, new Y3.Text());
|
|
422
|
+
break;
|
|
445
423
|
case "product":
|
|
446
424
|
map.set(key, ensureMapContainers(fieldSchema));
|
|
447
425
|
break;
|
|
@@ -459,17 +437,17 @@ function ensureMapContainers(schema) {
|
|
|
459
437
|
}
|
|
460
438
|
break;
|
|
461
439
|
}
|
|
440
|
+
case "counter":
|
|
441
|
+
case "set":
|
|
442
|
+
case "tree":
|
|
443
|
+
case "movable":
|
|
444
|
+
throw new Error(
|
|
445
|
+
`Yjs substrate does not support [KIND]="${fieldSchema[KIND3]}". Supported kinds: text, product, sequence, map, scalar, sum. Encountered unsupported kind at nested field "${key}".`
|
|
446
|
+
);
|
|
462
447
|
}
|
|
463
448
|
}
|
|
464
449
|
return map;
|
|
465
450
|
}
|
|
466
|
-
function unwrapAnnotations2(schema) {
|
|
467
|
-
let s = schema;
|
|
468
|
-
while (s._kind === "annotated" && s.schema !== void 0) {
|
|
469
|
-
s = s.schema;
|
|
470
|
-
}
|
|
471
|
-
return s;
|
|
472
|
-
}
|
|
473
451
|
|
|
474
452
|
// src/reader.ts
|
|
475
453
|
import * as Y4 from "yjs";
|
|
@@ -529,6 +507,7 @@ function yjsReader(doc, schema) {
|
|
|
529
507
|
}
|
|
530
508
|
|
|
531
509
|
// src/version.ts
|
|
510
|
+
import { versionVectorMeet } from "@kyneta/schema";
|
|
532
511
|
import { decodeStateVector } from "yjs";
|
|
533
512
|
function uint8ArrayToBase64(bytes) {
|
|
534
513
|
let binary = "";
|
|
@@ -545,6 +524,22 @@ function base64ToUint8Array(base64) {
|
|
|
545
524
|
}
|
|
546
525
|
return bytes;
|
|
547
526
|
}
|
|
527
|
+
function encodeStateVector(map) {
|
|
528
|
+
const bytes = [];
|
|
529
|
+
function writeVarUint(value) {
|
|
530
|
+
while (value > 127) {
|
|
531
|
+
bytes.push(value & 127 | 128);
|
|
532
|
+
value >>>= 7;
|
|
533
|
+
}
|
|
534
|
+
bytes.push(value & 127);
|
|
535
|
+
}
|
|
536
|
+
writeVarUint(map.size);
|
|
537
|
+
for (const [clientId, clock] of map) {
|
|
538
|
+
writeVarUint(clientId);
|
|
539
|
+
writeVarUint(clock);
|
|
540
|
+
}
|
|
541
|
+
return new Uint8Array(bytes);
|
|
542
|
+
}
|
|
548
543
|
var YjsVersion = class _YjsVersion {
|
|
549
544
|
sv;
|
|
550
545
|
constructor(sv) {
|
|
@@ -602,6 +597,26 @@ var YjsVersion = class _YjsVersion {
|
|
|
602
597
|
if (hasGreater && !hasLess) return "ahead";
|
|
603
598
|
return "equal";
|
|
604
599
|
}
|
|
600
|
+
/**
|
|
601
|
+
* Greatest lower bound (lattice meet) of two Yjs versions.
|
|
602
|
+
*
|
|
603
|
+
* Decodes both state vectors, computes the component-wise minimum
|
|
604
|
+
* via the shared `versionVectorMeet` utility, and encodes the result
|
|
605
|
+
* back to a Yjs state vector.
|
|
606
|
+
*
|
|
607
|
+
* @throws If `other` is not a `YjsVersion`.
|
|
608
|
+
*/
|
|
609
|
+
meet(other) {
|
|
610
|
+
if (!(other instanceof _YjsVersion)) {
|
|
611
|
+
throw new Error(
|
|
612
|
+
"YjsVersion can only be meet'd with another YjsVersion"
|
|
613
|
+
);
|
|
614
|
+
}
|
|
615
|
+
const thisMap = decodeStateVector(this.sv);
|
|
616
|
+
const otherMap = decodeStateVector(other.sv);
|
|
617
|
+
const result = versionVectorMeet(thisMap, otherMap);
|
|
618
|
+
return new _YjsVersion(encodeStateVector(result));
|
|
619
|
+
}
|
|
605
620
|
/**
|
|
606
621
|
* Parse a serialized YjsVersion string back into a YjsVersion.
|
|
607
622
|
*
|
|
@@ -633,7 +648,7 @@ function createYjsSubstrate(doc, schema) {
|
|
|
633
648
|
pendingChanges.push({ path, change: change2 });
|
|
634
649
|
}
|
|
635
650
|
},
|
|
636
|
-
onFlush(
|
|
651
|
+
onFlush(_origin) {
|
|
637
652
|
if (!inOurTransaction && pendingChanges.length > 0) {
|
|
638
653
|
inOurTransaction = true;
|
|
639
654
|
try {
|
|
@@ -657,6 +672,14 @@ function createYjsSubstrate(doc, schema) {
|
|
|
657
672
|
version() {
|
|
658
673
|
return new YjsVersion(Y5.encodeStateVector(doc));
|
|
659
674
|
},
|
|
675
|
+
baseVersion() {
|
|
676
|
+
return new YjsVersion(new Uint8Array([0]));
|
|
677
|
+
},
|
|
678
|
+
advance(_to) {
|
|
679
|
+
throw new Error(
|
|
680
|
+
"advance() on a live Yjs substrate is not yet supported. Use advance() on a YjsReplica instead."
|
|
681
|
+
);
|
|
682
|
+
},
|
|
660
683
|
exportEntirety() {
|
|
661
684
|
return {
|
|
662
685
|
kind: "entirety",
|
|
@@ -690,7 +713,7 @@ function createYjsSubstrate(doc, schema) {
|
|
|
690
713
|
if (transaction.origin === KYNETA_ORIGIN) {
|
|
691
714
|
return;
|
|
692
715
|
}
|
|
693
|
-
const ops = eventsToOps(events);
|
|
716
|
+
const ops = eventsToOps(events, schema);
|
|
694
717
|
if (ops.length === 0) {
|
|
695
718
|
return;
|
|
696
719
|
}
|
|
@@ -706,21 +729,46 @@ function createYjsSubstrate(doc, schema) {
|
|
|
706
729
|
return substrate;
|
|
707
730
|
}
|
|
708
731
|
function createYjsReplica(doc) {
|
|
732
|
+
let currentDoc = doc;
|
|
733
|
+
let currentBase = new YjsVersion(
|
|
734
|
+
Y5.encodeStateVector(new Y5.Doc())
|
|
735
|
+
);
|
|
709
736
|
return {
|
|
710
|
-
[BACKING_DOC]
|
|
737
|
+
get [BACKING_DOC]() {
|
|
738
|
+
return currentDoc;
|
|
739
|
+
},
|
|
711
740
|
version() {
|
|
712
|
-
return new YjsVersion(Y5.encodeStateVector(
|
|
741
|
+
return new YjsVersion(Y5.encodeStateVector(currentDoc));
|
|
742
|
+
},
|
|
743
|
+
baseVersion() {
|
|
744
|
+
return currentBase;
|
|
745
|
+
},
|
|
746
|
+
advance(to) {
|
|
747
|
+
const baseCmp = currentBase.compare(to);
|
|
748
|
+
if (baseCmp === "ahead") {
|
|
749
|
+
throw new Error("advance(): target is behind base version");
|
|
750
|
+
}
|
|
751
|
+
const currentCmp = to.compare(this.version());
|
|
752
|
+
if (currentCmp === "ahead") {
|
|
753
|
+
throw new Error("advance(): target is ahead of current version");
|
|
754
|
+
}
|
|
755
|
+
if (currentCmp !== "equal") return;
|
|
756
|
+
const update = Y5.encodeStateAsUpdate(currentDoc);
|
|
757
|
+
const newDoc = new Y5.Doc();
|
|
758
|
+
Y5.applyUpdate(newDoc, update);
|
|
759
|
+
currentDoc = newDoc;
|
|
760
|
+
currentBase = new YjsVersion(Y5.encodeStateVector(currentDoc));
|
|
713
761
|
},
|
|
714
762
|
exportEntirety() {
|
|
715
763
|
return {
|
|
716
764
|
kind: "entirety",
|
|
717
765
|
encoding: "binary",
|
|
718
|
-
data: Y5.encodeStateAsUpdate(
|
|
766
|
+
data: Y5.encodeStateAsUpdate(currentDoc)
|
|
719
767
|
};
|
|
720
768
|
},
|
|
721
769
|
exportSince(since) {
|
|
722
770
|
try {
|
|
723
|
-
const bytes = Y5.encodeStateAsUpdate(
|
|
771
|
+
const bytes = Y5.encodeStateAsUpdate(currentDoc, since.sv);
|
|
724
772
|
return { kind: "since", encoding: "binary", data: bytes };
|
|
725
773
|
} catch {
|
|
726
774
|
return null;
|
|
@@ -732,7 +780,7 @@ function createYjsReplica(doc) {
|
|
|
732
780
|
"YjsReplica.merge expects binary-encoded payloads. If you recently switched CRDT backends, stale clients may be sending incompatible data."
|
|
733
781
|
);
|
|
734
782
|
}
|
|
735
|
-
Y5.applyUpdate(
|
|
783
|
+
Y5.applyUpdate(currentDoc, payload.data);
|
|
736
784
|
}
|
|
737
785
|
};
|
|
738
786
|
}
|
|
@@ -792,7 +840,7 @@ function getSubstrate(doc) {
|
|
|
792
840
|
return s;
|
|
793
841
|
}
|
|
794
842
|
function registerDoc(schema, substrate) {
|
|
795
|
-
const doc = interpret(schema, substrate.context()).with(readable).with(writable).with(
|
|
843
|
+
const doc = interpret(schema, substrate.context()).with(readable).with(writable).with(observation).done();
|
|
796
844
|
substrates.set(doc, substrate);
|
|
797
845
|
registerSubstrate(doc, substrate);
|
|
798
846
|
return doc;
|
|
@@ -823,11 +871,13 @@ function merge(doc, payload, origin) {
|
|
|
823
871
|
getSubstrate(doc).merge(payload, origin);
|
|
824
872
|
}
|
|
825
873
|
|
|
826
|
-
// src/index.ts
|
|
827
|
-
import { Schema as Schema2 } from "@kyneta/schema";
|
|
828
|
-
|
|
829
874
|
// src/bind-yjs.ts
|
|
830
|
-
import {
|
|
875
|
+
import {
|
|
876
|
+
BACKING_DOC as BACKING_DOC2,
|
|
877
|
+
createSubstrateNamespace,
|
|
878
|
+
STRUCTURAL_YJS_CLIENT_ID as STRUCTURAL_YJS_CLIENT_ID2,
|
|
879
|
+
unwrap
|
|
880
|
+
} from "@kyneta/schema";
|
|
831
881
|
import * as Y6 from "yjs";
|
|
832
882
|
function hashPeerId(peerId) {
|
|
833
883
|
let hash = 2166136261;
|
|
@@ -867,44 +917,43 @@ function createYjsFactory(peerId) {
|
|
|
867
917
|
}
|
|
868
918
|
};
|
|
869
919
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
920
|
+
var yjs = {
|
|
921
|
+
...createSubstrateNamespace({
|
|
922
|
+
strategies: {
|
|
923
|
+
collaborative: {
|
|
924
|
+
factory: (ctx) => createYjsFactory(ctx.peerId),
|
|
925
|
+
replicaFactory: yjsReplicaFactory
|
|
926
|
+
},
|
|
927
|
+
ephemeral: {
|
|
928
|
+
factory: (ctx) => createYjsFactory(ctx.peerId),
|
|
929
|
+
replicaFactory: yjsReplicaFactory
|
|
930
|
+
}
|
|
931
|
+
},
|
|
932
|
+
defaultStrategy: "collaborative"
|
|
933
|
+
}),
|
|
934
|
+
unwrap(ref) {
|
|
935
|
+
let substrate;
|
|
936
|
+
try {
|
|
937
|
+
substrate = unwrap(ref);
|
|
938
|
+
} catch {
|
|
939
|
+
throw new Error(
|
|
940
|
+
"yjs.unwrap() requires a ref backed by a Yjs substrate. Use a doc created by exchange.get() with a yjs.bind() schema, or by createYjsDoc()."
|
|
941
|
+
);
|
|
942
|
+
}
|
|
943
|
+
const doc = substrate[BACKING_DOC2];
|
|
944
|
+
if (!doc || typeof doc !== "object" || typeof doc.getMap !== "function" || typeof doc.clientID !== "number") {
|
|
945
|
+
throw new Error(
|
|
946
|
+
"yjs.unwrap() requires a ref backed by a Yjs substrate. The ref has a substrate but it is not a Yjs substrate. Use a doc created with a yjs.bind() schema or createYjsDoc()."
|
|
947
|
+
);
|
|
948
|
+
}
|
|
949
|
+
return doc;
|
|
894
950
|
}
|
|
895
|
-
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// src/index.ts
|
|
899
|
-
function text() {
|
|
900
|
-
return Schema2.annotated("text");
|
|
901
|
-
}
|
|
951
|
+
};
|
|
902
952
|
export {
|
|
903
953
|
Schema,
|
|
904
954
|
YjsVersion,
|
|
905
955
|
applyChangeToYjs,
|
|
906
956
|
applyChanges,
|
|
907
|
-
bindYjs,
|
|
908
957
|
change,
|
|
909
958
|
createYjsDoc,
|
|
910
959
|
createYjsDocFromEntirety,
|
|
@@ -918,10 +967,10 @@ export {
|
|
|
918
967
|
stepIntoYjs,
|
|
919
968
|
subscribe,
|
|
920
969
|
subscribeNode,
|
|
921
|
-
text,
|
|
922
970
|
version,
|
|
923
971
|
yjs,
|
|
924
972
|
yjsReader,
|
|
973
|
+
yjsReplicaFactory,
|
|
925
974
|
yjsSubstrateFactory
|
|
926
975
|
};
|
|
927
976
|
//# sourceMappingURL=index.js.map
|