@kyneta/yjs-schema 1.2.0 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,8 +1,20 @@
1
- import { change, RawPath, Schema } from "@kyneta/schema"
1
+ import {
2
+ change,
3
+ createRef,
4
+ exportEntirety,
5
+ RawPath,
6
+ Schema,
7
+ unwrap,
8
+ } from "@kyneta/schema"
2
9
  import { describe, expect, it } from "vitest"
3
10
  import * as Y from "yjs"
4
11
  import { yjs } from "../bind-yjs.js"
5
- import { createYjsDoc } from "../create.js"
12
+
13
+ // ===========================================================================
14
+ // Helper — createDoc using the generic API
15
+ // ===========================================================================
16
+
17
+ import { createDoc } from "@kyneta/schema"
6
18
 
7
19
  // ===========================================================================
8
20
  // Schemas used across tests
@@ -83,8 +95,7 @@ describe("yjs.bind", () => {
83
95
  d.title.insert(0, "Snap")
84
96
  d.count.set(42)
85
97
  })
86
- const substrate1 = (unwrap as any)(doc1)
87
- const snapshot = substrate1.exportEntirety()
98
+ const snapshot = exportEntirety(doc1)
88
99
 
89
100
  // Restore
90
101
  const substrate2 = factory.fromEntirety(snapshot, SimpleSchema)
@@ -117,8 +128,12 @@ describe("yjs.bind", () => {
117
128
  const _s2 = factory.create(SimpleSchema)
118
129
 
119
130
  // Both docs should have the same clientID
120
- const doc1 = yjs.unwrap(createYjsDocFromFactory(factory, SimpleSchema))
121
- const doc2 = yjs.unwrap(createYjsDocFromFactory(factory, SimpleSchema))
131
+ const doc1 = unwrap(
132
+ createYjsDocFromFactory(factory, SimpleSchema),
133
+ ) as Y.Doc
134
+ const doc2 = unwrap(
135
+ createYjsDocFromFactory(factory, SimpleSchema),
136
+ ) as Y.Doc
122
137
 
123
138
  expect(doc1.clientID).toBe(doc2.clientID)
124
139
  })
@@ -128,8 +143,12 @@ describe("yjs.bind", () => {
128
143
  const factory1 = bound.factory({ peerId: "peer-alpha" })
129
144
  const factory2 = bound.factory({ peerId: "peer-beta" })
130
145
 
131
- const doc1 = yjs.unwrap(createYjsDocFromFactory(factory1, SimpleSchema))
132
- const doc2 = yjs.unwrap(createYjsDocFromFactory(factory2, SimpleSchema))
146
+ const doc1 = unwrap(
147
+ createYjsDocFromFactory(factory1, SimpleSchema),
148
+ ) as Y.Doc
149
+ const doc2 = unwrap(
150
+ createYjsDocFromFactory(factory2, SimpleSchema),
151
+ ) as Y.Doc
133
152
 
134
153
  expect(doc1.clientID).not.toBe(doc2.clientID)
135
154
  })
@@ -137,7 +156,9 @@ describe("yjs.bind", () => {
137
156
  it("clientID is a valid uint32", () => {
138
157
  const bound = yjs.bind(SimpleSchema)
139
158
  const factory = bound.factory({ peerId: "test-peer-id-12345" })
140
- const doc = yjs.unwrap(createYjsDocFromFactory(factory, SimpleSchema))
159
+ const doc = unwrap(
160
+ createYjsDocFromFactory(factory, SimpleSchema),
161
+ ) as Y.Doc
141
162
 
142
163
  expect(typeof doc.clientID).toBe("number")
143
164
  expect(doc.clientID).toBeGreaterThanOrEqual(0)
@@ -151,61 +172,70 @@ describe("yjs.bind", () => {
151
172
  // Simulate two separate "sessions" — both should hash to the same value
152
173
  const bound1 = yjs.bind(SimpleSchema)
153
174
  const factory1 = bound1.factory({ peerId })
154
- const doc1 = yjs.unwrap(createYjsDocFromFactory(factory1, SimpleSchema))
175
+ const doc1 = unwrap(
176
+ createYjsDocFromFactory(factory1, SimpleSchema),
177
+ ) as Y.Doc
155
178
 
156
179
  const bound2 = yjs.bind(SimpleSchema)
157
180
  const factory2 = bound2.factory({ peerId })
158
- const doc2 = yjs.unwrap(createYjsDocFromFactory(factory2, SimpleSchema))
181
+ const doc2 = unwrap(
182
+ createYjsDocFromFactory(factory2, SimpleSchema),
183
+ ) as Y.Doc
159
184
 
160
185
  expect(doc1.clientID).toBe(doc2.clientID)
161
186
  })
162
187
  })
163
188
 
164
189
  // -------------------------------------------------------------------------
165
- // yjs() escape hatch
190
+ // unwrap() escape hatch
166
191
  // -------------------------------------------------------------------------
167
192
 
168
- describe("yjs.unwrap() escape hatch", () => {
169
- it("returns the underlying Y.Doc from a createYjsDoc ref", () => {
170
- const doc = createYjsDoc(SimpleSchema)
193
+ describe("unwrap() escape hatch", () => {
194
+ it("returns the underlying Y.Doc from a createDoc ref", () => {
195
+ const doc = createDoc(yjs.bind(SimpleSchema))
171
196
  change(doc, (d: any) => {
172
197
  d.title.insert(0, "Escape")
173
198
  d.count.set(0)
174
199
  })
175
- const yjsDoc = yjs.unwrap(doc)
200
+ const yjsDoc = unwrap(doc) as Y.Doc
176
201
 
177
202
  expect(yjsDoc).toBeInstanceOf(Y.Doc)
178
203
  expect(yjsDoc.getMap("root").get("count")).toBe(0)
179
204
  })
180
205
 
181
206
  it("returns a Y.Doc with the correct root map state", () => {
182
- const doc = createYjsDoc(SimpleSchema)
207
+ const doc = createDoc(yjs.bind(SimpleSchema))
183
208
  change(doc, (d: any) => {
184
209
  d.title.insert(0, "Hello")
185
210
  d.count.set(42)
186
211
  })
187
- const yjsDoc = yjs.unwrap(doc)
212
+ const yjsDoc = unwrap(doc) as Y.Doc
188
213
  const rootMap = yjsDoc.getMap("root")
189
214
 
190
215
  expect((rootMap.get("title") as Y.Text).toJSON()).toBe("Hello")
191
216
  expect(rootMap.get("count")).toBe(42)
192
217
  })
193
218
 
194
- it("throws for non-Yjs refs (plain object)", () => {
195
- expect(() => yjs.unwrap({})).toThrow("yjs.unwrap() requires a ref")
219
+ it("returns undefined for non-refs (plain object)", () => {
220
+ expect(unwrap({} as any)).toBeUndefined()
196
221
  })
197
222
 
198
- it("throws for non-Yjs refs (random object with properties)", () => {
223
+ it("returns undefined for non-refs (random object with properties)", () => {
199
224
  const fake = {
200
225
  title: () => "fake",
201
226
  count: () => 0,
202
227
  }
203
- expect(() => yjs.unwrap(fake)).toThrow("yjs.unwrap() requires a ref")
228
+ expect(unwrap(fake as any)).toBeUndefined()
229
+ })
230
+
231
+ it("throws for primitives", () => {
232
+ expect(() => unwrap(null as any)).toThrow("unwrap() requires a ref")
233
+ expect(() => unwrap(undefined as any)).toThrow("unwrap() requires a ref")
204
234
  })
205
235
 
206
236
  it("mutations through escape hatch are visible via kyneta ref", () => {
207
- const doc = createYjsDoc(SimpleSchema)
208
- const yjsDoc = yjs.unwrap(doc)
237
+ const doc = createDoc(yjs.bind(SimpleSchema))
238
+ const yjsDoc = unwrap(doc) as Y.Doc
209
239
 
210
240
  // Mutate via raw Yjs
211
241
  yjsDoc.getMap("root").set("count", 99)
@@ -213,11 +243,11 @@ describe("yjs.bind", () => {
213
243
  })
214
244
 
215
245
  it("text mutations through escape hatch are visible", () => {
216
- const doc = createYjsDoc(SimpleSchema)
246
+ const doc = createDoc(yjs.bind(SimpleSchema))
217
247
  change(doc, (d: any) => {
218
248
  d.title.insert(0, "Hello")
219
249
  })
220
- const yjsDoc = yjs.unwrap(doc)
250
+ const yjsDoc = unwrap(doc) as Y.Doc
221
251
 
222
252
  const text = yjsDoc.getMap("root").get("title") as Y.Text
223
253
  text.insert(5, " World")
@@ -231,14 +261,6 @@ describe("yjs.bind", () => {
231
261
  // ===========================================================================
232
262
 
233
263
  import type { Schema as SchemaType, SubstrateFactory } from "@kyneta/schema"
234
- import {
235
- interpret,
236
- observation,
237
- readable,
238
- registerSubstrate,
239
- unwrap,
240
- writable,
241
- } from "@kyneta/schema"
242
264
 
243
265
  /**
244
266
  * Helper to create a kyneta ref from a factory (mimicking what exchange.get does).
@@ -249,16 +271,5 @@ function createYjsDocFromFactory(
249
271
  schema: SchemaType,
250
272
  ): any {
251
273
  const substrate = factory.create(schema)
252
- const doc: any = (interpret as any)(schema, substrate.context())
253
- .with(readable)
254
- .with(writable)
255
- .with(observation)
256
- .done()
257
-
258
- // Register for escape hatch — createYjsSubstrate already registered
259
- // substrate → Y.Doc internally, but we also need ref → substrate
260
- // for unwrap() (used by the yjs() escape hatch).
261
- registerSubstrate(doc, substrate)
262
-
263
- return doc
274
+ return createRef(schema, substrate)
264
275
  }
@@ -1,10 +1,17 @@
1
- import { change, Schema, subscribe } from "@kyneta/schema"
1
+ import {
2
+ change,
3
+ createDoc,
4
+ createRef,
5
+ Schema,
6
+ subscribe,
7
+ unwrap,
8
+ } from "@kyneta/schema"
2
9
  import { describe, expect, it } from "vitest"
3
10
  import * as Y from "yjs"
4
11
  import { yjs } from "../bind-yjs.js"
5
- import { createYjsDoc, createYjsDocFromEntirety } from "../create.js"
12
+ import { exportEntirety, exportSince, merge, version } from "../index.js"
6
13
  import { ensureContainers } from "../populate.js"
7
- import { exportEntirety, exportSince, merge, version } from "../sync.js"
14
+ import { createYjsSubstrate } from "../substrate.js"
8
15
  import { YjsVersion } from "../version.js"
9
16
 
10
17
  // ===========================================================================
@@ -35,18 +42,26 @@ const NestedSchema = Schema.struct({
35
42
  labels: Schema.record(Schema.string()),
36
43
  })
37
44
 
45
+ // ===========================================================================
46
+ // Helpers
47
+ // ===========================================================================
48
+
49
+ const boundSimple = yjs.bind(SimpleSchema)
50
+ const boundStructList = yjs.bind(StructListSchema)
51
+ const boundNested = yjs.bind(NestedSchema)
52
+
38
53
  // ===========================================================================
39
54
  // Tests
40
55
  // ===========================================================================
41
56
 
42
- describe("createYjsDoc", () => {
57
+ describe("createDoc", () => {
43
58
  // -------------------------------------------------------------------------
44
59
  // Default values
45
60
  // -------------------------------------------------------------------------
46
61
 
47
62
  describe("with defaults", () => {
48
63
  it("creates a doc with empty containers for shared types", () => {
49
- const doc = createYjsDoc(SimpleSchema)
64
+ const doc = createDoc(boundSimple)
50
65
  // Text annotation returns "" (empty Y.Text)
51
66
  expect(doc.title()).toBe("")
52
67
  // Plain scalars return structural zeros
@@ -56,7 +71,7 @@ describe("createYjsDoc", () => {
56
71
  })
57
72
 
58
73
  it("creates a doc with nested struct empty containers", () => {
59
- const doc = createYjsDoc(NestedSchema)
74
+ const doc = createDoc(boundNested)
60
75
  expect(doc.title()).toBe("")
61
76
  // Plain scalar inside struct returns structural zero
62
77
  expect(doc.meta.author()).toBe("")
@@ -65,7 +80,7 @@ describe("createYjsDoc", () => {
65
80
  })
66
81
 
67
82
  it("creates a doc with struct list defaults", () => {
68
- const doc = createYjsDoc(StructListSchema)
83
+ const doc = createDoc(boundStructList)
69
84
  expect(doc.tasks()).toEqual([])
70
85
  expect(doc.tasks.length).toBe(0)
71
86
  })
@@ -77,7 +92,7 @@ describe("createYjsDoc", () => {
77
92
 
78
93
  describe("with seeds", () => {
79
94
  it("creates a doc with scalar seed values", () => {
80
- const doc = createYjsDoc(SimpleSchema)
95
+ const doc = createDoc(boundSimple)
81
96
  change(doc, (d: any) => {
82
97
  d.title.insert(0, "Hello")
83
98
  d.count.set(42)
@@ -93,7 +108,7 @@ describe("createYjsDoc", () => {
93
108
  })
94
109
 
95
110
  it("creates a doc with partial seed (defaults fill gaps)", () => {
96
- const doc = createYjsDoc(SimpleSchema)
111
+ const doc = createDoc(boundSimple)
97
112
  change(doc, (d: any) => {
98
113
  d.title.insert(0, "Partial")
99
114
  })
@@ -103,7 +118,7 @@ describe("createYjsDoc", () => {
103
118
  })
104
119
 
105
120
  it("creates a doc with nested struct seed", () => {
106
- const doc = createYjsDoc(NestedSchema)
121
+ const doc = createDoc(boundNested)
107
122
  change(doc, (d: any) => {
108
123
  d.title.insert(0, "Doc")
109
124
  d.meta.author.set("Alice")
@@ -118,7 +133,7 @@ describe("createYjsDoc", () => {
118
133
  })
119
134
 
120
135
  it("creates a doc with struct list seed items", () => {
121
- const doc = createYjsDoc(StructListSchema)
136
+ const doc = createDoc(boundStructList)
122
137
  // Separate change() calls for list pushes to preserve order
123
138
  change(doc, (d: any) => d.tasks.push({ name: "Task 1", done: false }))
124
139
  change(doc, (d: any) => d.tasks.push({ name: "Task 2", done: true }))
@@ -145,7 +160,10 @@ describe("createYjsDoc", () => {
145
160
  ;(rootMap.get("items") as Y.Array<string>).push(["x"])
146
161
  })
147
162
 
148
- const doc = createYjsDoc(SimpleSchema, yjsDoc)
163
+ const doc = createRef(
164
+ SimpleSchema,
165
+ createYjsSubstrate(yjsDoc, SimpleSchema),
166
+ )
149
167
  expect(doc.title()).toBe("External")
150
168
  expect(doc.count()).toBe(99)
151
169
  expect(doc.items()).toEqual(["x"])
@@ -155,7 +173,10 @@ describe("createYjsDoc", () => {
155
173
  const yjsDoc = new Y.Doc()
156
174
  ensureContainers(yjsDoc, SimpleSchema)
157
175
 
158
- const doc = createYjsDoc(SimpleSchema, yjsDoc)
176
+ const doc = createRef(
177
+ SimpleSchema,
178
+ createYjsSubstrate(yjsDoc, SimpleSchema),
179
+ )
159
180
  change(doc, (d: any) => {
160
181
  d.title.insert(0, "Hello")
161
182
  d.count.set(42)
@@ -170,7 +191,10 @@ describe("createYjsDoc", () => {
170
191
  const yjsDoc = new Y.Doc()
171
192
  ensureContainers(yjsDoc, SimpleSchema)
172
193
 
173
- const doc = createYjsDoc(SimpleSchema, yjsDoc)
194
+ const doc = createRef(
195
+ SimpleSchema,
196
+ createYjsSubstrate(yjsDoc, SimpleSchema),
197
+ )
174
198
 
175
199
  const rootMap = yjsDoc.getMap("root")
176
200
  rootMap.set("count", 77)
@@ -178,12 +202,15 @@ describe("createYjsDoc", () => {
178
202
  expect(doc.count()).toBe(77)
179
203
  })
180
204
 
181
- it("yjs.unwrap() escape hatch returns the same Y.Doc", () => {
205
+ it("unwrap() escape hatch returns the same Y.Doc", () => {
182
206
  const yjsDoc = new Y.Doc()
183
207
  ensureContainers(yjsDoc, SimpleSchema)
184
208
 
185
- const doc = createYjsDoc(SimpleSchema, yjsDoc)
186
- const escaped = yjs.unwrap(doc)
209
+ const doc = createRef(
210
+ SimpleSchema,
211
+ createYjsSubstrate(yjsDoc, SimpleSchema),
212
+ )
213
+ const escaped = unwrap(doc)
187
214
 
188
215
  expect(escaped).toBe(yjsDoc)
189
216
  })
@@ -191,12 +218,12 @@ describe("createYjsDoc", () => {
191
218
  })
192
219
 
193
220
  // ===========================================================================
194
- // createYjsDocFromEntirety
221
+ // createDoc with payload (fromEntirety)
195
222
  // ===========================================================================
196
223
 
197
- describe("createYjsDocFromEntirety", () => {
224
+ describe("createDoc with payload", () => {
198
225
  it("reconstructs state from a snapshot", () => {
199
- const doc1 = createYjsDoc(SimpleSchema)
226
+ const doc1 = createDoc(boundSimple)
200
227
  change(doc1, (d: any) => {
201
228
  d.title.insert(0, "Snapshot")
202
229
  d.count.set(42)
@@ -205,7 +232,7 @@ describe("createYjsDocFromEntirety", () => {
205
232
  change(doc1, (d: any) => d.items.push("b"))
206
233
 
207
234
  const payload = exportEntirety(doc1)
208
- const doc2 = createYjsDocFromEntirety(SimpleSchema, payload)
235
+ const doc2 = createDoc(boundSimple, payload)
209
236
 
210
237
  expect(doc2.title()).toBe("Snapshot")
211
238
  expect(doc2.count()).toBe(42)
@@ -213,7 +240,7 @@ describe("createYjsDocFromEntirety", () => {
213
240
  })
214
241
 
215
242
  it("reconstructs state after mutations", () => {
216
- const doc1 = createYjsDoc(SimpleSchema)
243
+ const doc1 = createDoc(boundSimple)
217
244
  change(doc1, (d: any) => {
218
245
  d.title.insert(0, "Start")
219
246
  })
@@ -225,7 +252,7 @@ describe("createYjsDocFromEntirety", () => {
225
252
  })
226
253
 
227
254
  const payload = exportEntirety(doc1)
228
- const doc2 = createYjsDocFromEntirety(SimpleSchema, payload)
255
+ const doc2 = createDoc(boundSimple, payload)
229
256
 
230
257
  expect(doc2.title()).toBe("Start End")
231
258
  expect(doc2.count()).toBe(99)
@@ -233,7 +260,7 @@ describe("createYjsDocFromEntirety", () => {
233
260
  })
234
261
 
235
262
  it("reconstructs nested struct state from snapshot", () => {
236
- const doc1 = createYjsDoc(NestedSchema)
263
+ const doc1 = createDoc(boundNested)
237
264
  change(doc1, (d: any) => {
238
265
  d.title.insert(0, "Nested")
239
266
  d.meta.author.set("Alice")
@@ -243,7 +270,7 @@ describe("createYjsDocFromEntirety", () => {
243
270
  change(doc1, (d: any) => d.meta.tags.push("v2"))
244
271
 
245
272
  const payload = exportEntirety(doc1)
246
- const doc2 = createYjsDocFromEntirety(NestedSchema, payload)
273
+ const doc2 = createDoc(boundNested, payload)
247
274
 
248
275
  expect(doc2.title()).toBe("Nested")
249
276
  expect(doc2.meta.author()).toBe("Alice")
@@ -253,12 +280,12 @@ describe("createYjsDocFromEntirety", () => {
253
280
  })
254
281
 
255
282
  it("reconstructs struct list state from snapshot", () => {
256
- const doc1 = createYjsDoc(StructListSchema)
283
+ const doc1 = createDoc(boundStructList)
257
284
  change(doc1, (d: any) => d.tasks.push({ name: "Task A", done: false }))
258
285
  change(doc1, (d: any) => d.tasks.push({ name: "Task B", done: true }))
259
286
 
260
287
  const payload = exportEntirety(doc1)
261
- const doc2 = createYjsDocFromEntirety(StructListSchema, payload)
288
+ const doc2 = createDoc(boundStructList, payload)
262
289
 
263
290
  expect(doc2.tasks.length).toBe(2)
264
291
  expect((doc2.tasks.at(0) as any).name()).toBe("Task A")
@@ -266,12 +293,12 @@ describe("createYjsDocFromEntirety", () => {
266
293
  })
267
294
 
268
295
  it("is writable after reconstruction", () => {
269
- const doc1 = createYjsDoc(SimpleSchema)
296
+ const doc1 = createDoc(boundSimple)
270
297
  change(doc1, (d: any) => {
271
298
  d.title.insert(0, "Original")
272
299
  })
273
300
  const payload = exportEntirety(doc1)
274
- const doc2 = createYjsDocFromEntirety(SimpleSchema, payload)
301
+ const doc2 = createDoc(boundSimple, payload)
275
302
 
276
303
  change(doc2, (d: any) => {
277
304
  d.title.insert(8, " Copy")
@@ -283,12 +310,12 @@ describe("createYjsDocFromEntirety", () => {
283
310
  })
284
311
 
285
312
  it("is observable after reconstruction", () => {
286
- const doc1 = createYjsDoc(SimpleSchema)
313
+ const doc1 = createDoc(boundSimple)
287
314
  change(doc1, (d: any) => {
288
315
  d.title.insert(0, "Original")
289
316
  })
290
317
  const payload = exportEntirety(doc1)
291
- const doc2 = createYjsDocFromEntirety(SimpleSchema, payload)
318
+ const doc2 = createDoc(boundSimple, payload)
292
319
 
293
320
  const received: any[] = []
294
321
  subscribe(doc2, (changeset: any) => {
@@ -310,13 +337,13 @@ describe("createYjsDocFromEntirety", () => {
310
337
  describe("sync primitives", () => {
311
338
  describe("version", () => {
312
339
  it("returns a YjsVersion", () => {
313
- const doc = createYjsDoc(SimpleSchema)
340
+ const doc = createDoc(boundSimple)
314
341
  const v = version(doc)
315
342
  expect(v).toBeInstanceOf(YjsVersion)
316
343
  })
317
344
 
318
345
  it("advances after mutations", () => {
319
- const doc = createYjsDoc(SimpleSchema)
346
+ const doc = createDoc(boundSimple)
320
347
  const v1 = version(doc)
321
348
 
322
349
  change(doc, (d: any) => {
@@ -328,7 +355,7 @@ describe("sync primitives", () => {
328
355
  })
329
356
 
330
357
  it("serialize/parse round-trips", () => {
331
- const doc = createYjsDoc(SimpleSchema)
358
+ const doc = createDoc(boundSimple)
332
359
  change(doc, (d: any) => {
333
360
  d.title.insert(0, "Test")
334
361
  })
@@ -341,7 +368,7 @@ describe("sync primitives", () => {
341
368
 
342
369
  describe("exportEntirety", () => {
343
370
  it("returns a binary payload", () => {
344
- const doc = createYjsDoc(SimpleSchema)
371
+ const doc = createDoc(boundSimple)
345
372
  change(doc, (d: any) => {
346
373
  d.title.insert(0, "Snap")
347
374
  })
@@ -354,11 +381,11 @@ describe("sync primitives", () => {
354
381
 
355
382
  describe("exportSince + merge", () => {
356
383
  it("syncs incremental changes between two docs", () => {
357
- const doc1 = createYjsDoc(SimpleSchema)
384
+ const doc1 = createDoc(boundSimple)
358
385
  change(doc1, (d: any) => {
359
386
  d.title.insert(0, "Start")
360
387
  })
361
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
388
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
362
389
 
363
390
  const v2Before = version(doc2)
364
391
 
@@ -382,8 +409,8 @@ describe("sync primitives", () => {
382
409
  })
383
410
 
384
411
  it("syncs multiple incremental deltas", () => {
385
- const doc1 = createYjsDoc(SimpleSchema)
386
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
412
+ const doc1 = createDoc(boundSimple)
413
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
387
414
 
388
415
  // First round
389
416
  let vBefore = version(doc2)
@@ -411,11 +438,11 @@ describe("sync primitives", () => {
411
438
  })
412
439
 
413
440
  it("changefeed fires on merge", () => {
414
- const doc1 = createYjsDoc(SimpleSchema)
441
+ const doc1 = createDoc(boundSimple)
415
442
  change(doc1, (d: any) => {
416
443
  d.title.insert(0, "Source")
417
444
  })
418
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
445
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
419
446
 
420
447
  const v2Before = version(doc2)
421
448
 
@@ -437,8 +464,8 @@ describe("sync primitives", () => {
437
464
  })
438
465
 
439
466
  it("merge passes origin to changefeed", () => {
440
- const doc1 = createYjsDoc(SimpleSchema)
441
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
467
+ const doc1 = createDoc(boundSimple)
468
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
442
469
 
443
470
  const v2Before = version(doc2)
444
471
  change(doc1, (d: any) => {
@@ -458,7 +485,7 @@ describe("sync primitives", () => {
458
485
 
459
486
  describe("versions equal after sync", () => {
460
487
  it("versions equal after full snapshot sync", () => {
461
- const doc1 = createYjsDoc(SimpleSchema)
488
+ const doc1 = createDoc(boundSimple)
462
489
  change(doc1, (d: any) => {
463
490
  d.title.insert(0, "Same")
464
491
  })
@@ -466,14 +493,14 @@ describe("sync primitives", () => {
466
493
  d.count.set(42)
467
494
  })
468
495
 
469
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
496
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
470
497
 
471
498
  expect(version(doc1).compare(version(doc2))).toBe("equal")
472
499
  })
473
500
 
474
501
  it("versions equal after bidirectional delta sync", () => {
475
- const doc1 = createYjsDoc(SimpleSchema)
476
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
502
+ const doc1 = createDoc(boundSimple)
503
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
477
504
 
478
505
  const v1Before = version(doc1)
479
506
  const v2Before = version(doc2)
@@ -504,11 +531,8 @@ describe("sync primitives", () => {
504
531
  describe("full workflow", () => {
505
532
  it("create → mutate → sync → observe", () => {
506
533
  // 1. Create two docs
507
- const doc1 = createYjsDoc(StructListSchema)
508
- const doc2 = createYjsDocFromEntirety(
509
- StructListSchema,
510
- exportEntirety(doc1),
511
- )
534
+ const doc1 = createDoc(boundStructList)
535
+ const doc2 = createDoc(boundStructList, exportEntirety(doc1))
512
536
 
513
537
  // 2. Set up observer on doc2
514
538
  const changes: any[] = []
@@ -559,7 +583,7 @@ describe("full workflow", () => {
559
583
 
560
584
  it("create → mutate → snapshot → reconstruct → continue", () => {
561
585
  // 1. Create and mutate
562
- const doc1 = createYjsDoc(SimpleSchema)
586
+ const doc1 = createDoc(boundSimple)
563
587
  change(doc1, (d: any) => {
564
588
  d.title.insert(0, "Start")
565
589
  })
@@ -573,7 +597,7 @@ describe("full workflow", () => {
573
597
  const snapshot = exportEntirety(doc1)
574
598
 
575
599
  // 3. Reconstruct
576
- const doc2 = createYjsDocFromEntirety(SimpleSchema, snapshot)
600
+ const doc2 = createDoc(boundSimple, snapshot)
577
601
  expect(doc2.title()).toBe("Start Middle")
578
602
  expect(doc2.count()).toBe(10)
579
603
  expect(doc2.items()).toEqual(["first"])
@@ -598,8 +622,8 @@ describe("full workflow", () => {
598
622
 
599
623
  it("concurrent edits converge correctly", () => {
600
624
  // 1. Create two peers from the same initial state
601
- const doc1 = createYjsDoc(SimpleSchema)
602
- const doc2 = createYjsDocFromEntirety(SimpleSchema, exportEntirety(doc1))
625
+ const doc1 = createDoc(boundSimple)
626
+ const doc2 = createDoc(boundSimple, exportEntirety(doc1))
603
627
 
604
628
  const v1Before = version(doc1)
605
629
  const v2Before = version(doc2)
@@ -15,10 +15,7 @@ import { yjsReader } from "../reader.js"
15
15
  * After `ensureContainers` the doc has the correct shared types but no
16
16
  * values. We populate values via raw Yjs API within a single transact.
17
17
  */
18
- function setup(
19
- schema: any,
20
- seed?: Record<string, unknown>,
21
- ) {
18
+ function setup(schema: any, seed?: Record<string, unknown>) {
22
19
  const doc = new Y.Doc()
23
20
  ensureContainers(doc, schema)
24
21
  if (seed) {
@@ -166,15 +163,9 @@ function buildStructMap(
166
163
  if (Array.isArray(value)) {
167
164
  for (const item of value) {
168
165
  const itemSchema = fieldSchema.item
169
- if (
170
- itemSchema &&
171
- itemSchema[KIND] === "product"
172
- ) {
166
+ if (itemSchema && itemSchema[KIND] === "product") {
173
167
  arr.push([
174
- buildStructMap(
175
- itemSchema,
176
- item as Record<string, unknown>,
177
- ),
168
+ buildStructMap(itemSchema, item as Record<string, unknown>),
178
169
  ])
179
170
  } else {
180
171
  arr.push([item])
@@ -204,8 +195,6 @@ function buildStructMap(
204
195
  return map
205
196
  }
206
197
 
207
-
208
-
209
198
  /** Build a RawPath from variadic key/index segments. */
210
199
  function p(...segs: (string | number)[]): RawPath {
211
200
  let path = RawPath.empty