@kyneta/yjs-schema 1.0.0 → 1.1.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/src/substrate.ts CHANGED
@@ -8,25 +8,26 @@
8
8
  // The event bridge contract: wrapping a Y.Doc in a kyneta substrate
9
9
  // means subscribing to the kyneta doc observes ALL mutations to the
10
10
  // underlying Y.Doc, regardless of source (local kyneta writes,
11
- // importDelta, external Y.applyUpdate, external raw Yjs API mutations).
11
+ // merge, external Y.applyUpdate, external raw Yjs API mutations).
12
12
 
13
13
  import type {
14
14
  ChangeBase,
15
15
  Path,
16
+ Reader,
17
+ Replica,
18
+ ReplicaFactory,
16
19
  Schema as SchemaNode,
17
- StoreReader,
18
20
  Substrate,
19
21
  SubstrateFactory,
20
22
  SubstratePayload,
21
23
  WritableContext,
22
24
  } from "@kyneta/schema"
23
- import { buildWritableContext, executeBatch } from "@kyneta/schema"
25
+ import { BACKING_DOC, buildWritableContext, executeBatch } from "@kyneta/schema"
24
26
  import * as Y from "yjs"
25
27
  import { applyChangeToYjs, eventsToOps } from "./change-mapping.js"
26
28
  import { ensureContainers } from "./populate.js"
27
- import { yjsStoreReader } from "./store-reader.js"
29
+ import { yjsReader } from "./reader.js"
28
30
  import { YjsVersion } from "./version.js"
29
- import { registerYjsSubstrate } from "./yjs-escape.js"
30
31
 
31
32
  // ---------------------------------------------------------------------------
32
33
  // Origin tag — used to suppress echo from our own transactions
@@ -44,11 +45,11 @@ const KYNETA_ORIGIN = "kyneta-prepare"
44
45
  * This is the "bring your own doc" entry point. The user creates and
45
46
  * manages the Y.Doc (possibly via a Yjs provider); this function wraps
46
47
  * it with a schema-aware overlay providing typed reads, writes,
47
- * versioning, and export/import through the standard Substrate interface.
48
+ * versioning, and export/merge through the standard Substrate interface.
48
49
  *
49
50
  * **Event bridge contract:** A persistent `observeDeep` handler is
50
51
  * registered on the root Y.Map at construction time. All non-kyneta
51
- * mutations to the Y.Doc (imports, external local writes) are bridged
52
+ * mutations to the Y.Doc (merges, external local writes) are bridged
52
53
  * to the kyneta changefeed. Subscribing to the kyneta doc observes all
53
54
  * mutations regardless of source.
54
55
  *
@@ -71,8 +72,8 @@ export function createYjsSubstrate(
71
72
  // to be), and onFlush() skips transact/commit.
72
73
  let inOurTransaction = false
73
74
 
74
- // Stashed origin from importDelta for the event bridge to pick up.
75
- let pendingImportOrigin: string | undefined
75
+ // Stashed origin from merge for the event bridge to pick up.
76
+ let pendingMergeOrigin: string | undefined
76
77
 
77
78
  // Lazy-built WritableContext (same pattern as PlainSubstrate / LoroSubstrate).
78
79
  let cachedCtx: WritableContext | undefined
@@ -80,13 +81,15 @@ export function createYjsSubstrate(
80
81
  // The root Y.Map — all schema fields are children of this single map.
81
82
  const rootMap = doc.getMap("root")
82
83
 
83
- // The StoreReader — live view over the Yjs shared type tree.
84
- const reader: StoreReader = yjsStoreReader(doc, schema)
84
+ // The Reader — live view over the Yjs shared type tree.
85
+ const reader: Reader = yjsReader(doc, schema)
85
86
 
86
87
  // --- Substrate object ---
87
88
 
88
- const substrate: Substrate<YjsVersion> = {
89
- store: reader,
89
+ const substrate = {
90
+ [BACKING_DOC]: doc,
91
+
92
+ reader: reader,
90
93
 
91
94
  prepare(path: Path, change: ChangeBase): void {
92
95
  if (!inOurTransaction) {
@@ -129,8 +132,9 @@ export function createYjsSubstrate(
129
132
  return new YjsVersion(Y.encodeStateVector(doc))
130
133
  },
131
134
 
132
- exportSnapshot(): SubstratePayload {
135
+ exportEntirety(): SubstratePayload {
133
136
  return {
137
+ kind: "entirety",
134
138
  encoding: "binary",
135
139
  data: Y.encodeStateAsUpdate(doc),
136
140
  }
@@ -139,27 +143,28 @@ export function createYjsSubstrate(
139
143
  exportSince(since: YjsVersion): SubstratePayload | null {
140
144
  try {
141
145
  const bytes = Y.encodeStateAsUpdate(doc, since.sv)
142
- return { encoding: "binary", data: bytes }
146
+ return { kind: "since", encoding: "binary", data: bytes }
143
147
  } catch {
144
148
  return null
145
149
  }
146
150
  },
147
151
 
148
- importDelta(payload: SubstratePayload, origin?: string): void {
152
+ merge(payload: SubstratePayload, origin?: string): void {
149
153
  if (
150
154
  payload.encoding !== "binary" ||
151
155
  !(payload.data instanceof Uint8Array)
152
156
  ) {
153
157
  throw new Error(
154
- "YjsSubstrate.importDelta only supports binary-encoded payloads",
158
+ "YjsSubstrate.merge expects binary-encoded payloads. " +
159
+ "If you recently switched CRDT backends, stale clients may be sending incompatible data.",
155
160
  )
156
161
  }
157
162
  // Stash origin for the event bridge to pick up
158
- pendingImportOrigin = origin
163
+ pendingMergeOrigin = origin
159
164
  try {
160
165
  Y.applyUpdate(doc, payload.data, origin ?? "remote")
161
166
  } finally {
162
- pendingImportOrigin = undefined
167
+ pendingMergeOrigin = undefined
163
168
  }
164
169
  // That's it — the observeDeep handler bridges events to the
165
170
  // changefeed via executeBatch.
@@ -180,13 +185,11 @@ export function createYjsSubstrate(
180
185
  return
181
186
  }
182
187
 
183
- // Determine origin: prefer stashed kyneta origin (from importDelta),
188
+ // Determine origin: prefer stashed kyneta origin (from merge),
184
189
  // fall back to the transaction's origin if it's a string.
185
190
  const origin =
186
- pendingImportOrigin ??
187
- (typeof transaction.origin === "string"
188
- ? transaction.origin
189
- : undefined)
191
+ pendingMergeOrigin ??
192
+ (typeof transaction.origin === "string" ? transaction.origin : undefined)
190
193
 
191
194
  // Lazily ensure the context is built
192
195
  const ctx = substrate.context()
@@ -202,10 +205,7 @@ export function createYjsSubstrate(
202
205
  }
203
206
  })
204
207
 
205
- // Register for the yjs() escape hatch
206
- registerYjsSubstrate(substrate, doc)
207
-
208
- return substrate
208
+ return substrate as Substrate<YjsVersion>
209
209
  }
210
210
 
211
211
  // ---------------------------------------------------------------------------
@@ -218,35 +218,134 @@ export function createYjsSubstrate(
218
218
  * - `create(schema)` — creates a fresh Y.Doc with empty containers
219
219
  * matching the schema structure. No seed data — initial content
220
220
  * should be applied via `change()` after construction.
221
- * - `fromSnapshot(payload, schema)` — creates a Y.Doc from a snapshot
221
+ * - `fromEntirety(payload, schema)` — creates a Y.Doc from an entirety
222
222
  * payload, returns a substrate.
223
223
  * - `parseVersion(serialized)` — deserializes a YjsVersion.
224
224
  */
225
- export const yjsSubstrateFactory: SubstrateFactory<YjsVersion> = {
226
- create(schema: SchemaNode): Substrate<YjsVersion> {
227
- const doc = new Y.Doc()
228
- ensureContainers(doc, schema)
229
- return createYjsSubstrate(doc, schema)
225
+ // ---------------------------------------------------------------------------
226
+ // yjsReplicaFactory — ReplicaFactory<YjsVersion>
227
+ // ---------------------------------------------------------------------------
228
+
229
+ /**
230
+ * Schema-free replica factory for Yjs substrates.
231
+ *
232
+ * Constructs headless `Replica<YjsVersion>` instances backed by bare
233
+ * `Y.Doc`s — no schema walking, no container initialization, no
234
+ * Reader, no event bridge, no changefeed. Just the CRDT runtime
235
+ * with version tracking and export/merge.
236
+ *
237
+ * Used by conduit participants (stores, routing servers)
238
+ * that need to accumulate state, compute per-peer deltas, and compact
239
+ * storage without ever interpreting document fields.
240
+ */
241
+ export function createYjsReplica(doc: Y.Doc): Replica<YjsVersion> {
242
+ return {
243
+ [BACKING_DOC]: doc,
244
+
245
+ version(): YjsVersion {
246
+ return new YjsVersion(Y.encodeStateVector(doc))
247
+ },
248
+
249
+ exportEntirety(): SubstratePayload {
250
+ return {
251
+ kind: "entirety",
252
+ encoding: "binary",
253
+ data: Y.encodeStateAsUpdate(doc),
254
+ }
255
+ },
256
+
257
+ exportSince(since: YjsVersion): SubstratePayload | null {
258
+ try {
259
+ const bytes = Y.encodeStateAsUpdate(doc, since.sv)
260
+ return { kind: "since", encoding: "binary", data: bytes }
261
+ } catch {
262
+ return null
263
+ }
264
+ },
265
+
266
+ merge(payload: SubstratePayload, _origin?: string): void {
267
+ if (
268
+ payload.encoding !== "binary" ||
269
+ !(payload.data instanceof Uint8Array)
270
+ ) {
271
+ throw new Error(
272
+ "YjsReplica.merge expects binary-encoded payloads. " +
273
+ "If you recently switched CRDT backends, stale clients may be sending incompatible data.",
274
+ )
275
+ }
276
+ Y.applyUpdate(doc, payload.data)
277
+ },
278
+ } as Replica<YjsVersion>
279
+ }
280
+
281
+ export const yjsReplicaFactory: ReplicaFactory<YjsVersion> = {
282
+ replicaType: ["yjs", 1, 0] as const,
283
+
284
+ createEmpty(): Replica<YjsVersion> {
285
+ return createYjsReplica(new Y.Doc())
230
286
  },
231
287
 
232
- fromSnapshot(
233
- payload: SubstratePayload,
234
- schema: SchemaNode,
235
- ): Substrate<YjsVersion> {
288
+ fromEntirety(payload: SubstratePayload): Replica<YjsVersion> {
236
289
  if (
237
290
  payload.encoding !== "binary" ||
238
291
  !(payload.data instanceof Uint8Array)
239
292
  ) {
240
293
  throw new Error(
241
- "YjsSubstrateFactory.fromSnapshot only supports binary-encoded payloads",
294
+ "YjsReplicaFactory.fromEntirety only supports binary-encoded payloads",
242
295
  )
243
296
  }
244
297
  const doc = new Y.Doc()
245
298
  Y.applyUpdate(doc, payload.data)
299
+ return createYjsReplica(doc)
300
+ },
301
+
302
+ parseVersion(serialized: string): YjsVersion {
303
+ return YjsVersion.parse(serialized)
304
+ },
305
+ }
306
+
307
+ // ---------------------------------------------------------------------------
308
+ // yjsSubstrateFactory — SubstrateFactory<YjsVersion>
309
+ // ---------------------------------------------------------------------------
310
+
311
+ export const yjsSubstrateFactory: SubstrateFactory<YjsVersion> = {
312
+ replica: yjsReplicaFactory,
313
+
314
+ createReplica(): Replica<YjsVersion> {
315
+ // Default random clientID — safe for hydration (no local writes).
316
+ return createYjsReplica(new Y.Doc())
317
+ },
318
+
319
+ upgrade(
320
+ replica: Replica<YjsVersion>,
321
+ schema: SchemaNode,
322
+ ): Substrate<YjsVersion> {
323
+ const doc = (replica as any)[BACKING_DOC] as Y.Doc
324
+ // No identity injection for the standalone factory (no peerId).
325
+ // Conditional ensureContainers: skip fields that already exist
326
+ // from hydrated state.
327
+ ensureContainers(doc, schema, true)
246
328
  return createYjsSubstrate(doc, schema)
247
329
  },
248
330
 
331
+ create(schema: SchemaNode): Substrate<YjsVersion> {
332
+ // Fresh doc — unconditional ensureContainers (nothing to conflict with).
333
+ const doc = new Y.Doc()
334
+ ensureContainers(doc, schema)
335
+ return createYjsSubstrate(doc, schema)
336
+ },
337
+
338
+ fromEntirety(
339
+ payload: SubstratePayload,
340
+ schema: SchemaNode,
341
+ ): Substrate<YjsVersion> {
342
+ // Two-phase path: createReplica → merge → upgrade
343
+ const replica = this.createReplica()
344
+ replica.merge(payload)
345
+ return this.upgrade(replica, schema)
346
+ },
347
+
249
348
  parseVersion(serialized: string): YjsVersion {
250
349
  return YjsVersion.parse(serialized)
251
350
  },
252
- }
351
+ }
package/src/sync.ts CHANGED
@@ -1,17 +1,17 @@
1
1
  // sync — sync primitives for YjsSubstrate-backed documents.
2
2
  //
3
- // These functions provide version tracking, snapshot export, and delta
4
- // import for documents created via `createYjsDoc` or
5
- // `createYjsDocFromSnapshot`. They discover the substrate via the
3
+ // These functions provide version tracking, entirety export, and merge
4
+ // for documents created via `createYjsDoc` or
5
+ // `createYjsDocFromEntirety`. They discover the substrate via the
6
6
  // module-scoped WeakMap in `create.ts`.
7
7
  //
8
8
  // Unlike PlainSubstrate's sync (which returns Op[] for deltas),
9
- // YjsSubstrate's sync uses binary SubstratePayload for both snapshots
9
+ // YjsSubstrate's sync uses binary SubstratePayload for both entireties
10
10
  // and deltas — these are Yjs's native state-as-update bytes.
11
11
 
12
12
  import type { SubstratePayload } from "@kyneta/schema"
13
- import { YjsVersion } from "./version.js"
14
13
  import { getSubstrate } from "./create.js"
14
+ import type { YjsVersion } from "./version.js"
15
15
 
16
16
  // ---------------------------------------------------------------------------
17
17
  // version — current YjsVersion
@@ -23,28 +23,28 @@ import { getSubstrate } from "./create.js"
23
23
  * Use `.serialize()` to get a text-safe string for embedding in HTML
24
24
  * meta tags, URL parameters, etc.
25
25
  *
26
- * @param doc - A document created by `createYjsDoc` or `createYjsDocFromSnapshot`.
27
- * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromSnapshot`.
26
+ * @param doc - A document created by `createYjsDoc` or `createYjsDocFromEntirety`.
27
+ * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromEntirety`.
28
28
  */
29
29
  export function version(doc: object): YjsVersion {
30
30
  return getSubstrate(doc).version()
31
31
  }
32
32
 
33
33
  // ---------------------------------------------------------------------------
34
- // exportSnapshot — full state for reconstruction
34
+ // exportEntirety — full state for reconstruction
35
35
  // ---------------------------------------------------------------------------
36
36
 
37
37
  /**
38
- * Export the full substrate snapshot — sufficient for a new peer to
39
- * reconstruct an equivalent document via `createYjsDocFromSnapshot()`.
38
+ * Export the full substrate entirety — sufficient for a new peer to
39
+ * reconstruct an equivalent document via `createYjsDocFromEntirety()`.
40
40
  *
41
41
  * Returns a binary `SubstratePayload` (Yjs state-as-update bytes).
42
42
  *
43
- * @param doc - A document created by `createYjsDoc` or `createYjsDocFromSnapshot`.
44
- * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromSnapshot`.
43
+ * @param doc - A document created by `createYjsDoc` or `createYjsDocFromEntirety`.
44
+ * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromEntirety`.
45
45
  */
46
- export function exportSnapshot(doc: object): SubstratePayload {
47
- return getSubstrate(doc).exportSnapshot()
46
+ export function exportEntirety(doc: object): SubstratePayload {
47
+ return getSubstrate(doc).exportEntirety()
48
48
  }
49
49
 
50
50
  // ---------------------------------------------------------------------------
@@ -61,12 +61,12 @@ export function exportSnapshot(doc: object): SubstratePayload {
61
61
  * const v0 = version(docA)
62
62
  * change(docA, d => d.title.insert(0, "Hi"))
63
63
  * const delta = exportSince(docA, v0)
64
- * importDelta(docB, delta!)
64
+ * merge(docB, delta!)
65
65
  * ```
66
66
  *
67
- * @param doc - A document created by `createYjsDoc` or `createYjsDocFromSnapshot`.
67
+ * @param doc - A document created by `createYjsDoc` or `createYjsDocFromEntirety`.
68
68
  * @param since - The version to diff from.
69
- * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromSnapshot`.
69
+ * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromEntirety`.
70
70
  */
71
71
  export function exportSince(
72
72
  doc: object,
@@ -76,32 +76,32 @@ export function exportSince(
76
76
  }
77
77
 
78
78
  // ---------------------------------------------------------------------------
79
- // importDelta — apply a delta from another peer
79
+ // merge — apply a delta from another peer
80
80
  // ---------------------------------------------------------------------------
81
81
 
82
82
  /**
83
83
  * Import a delta payload into a live document.
84
84
  *
85
85
  * The payload must have been produced by `exportSince()` or
86
- * `exportSnapshot()` on a compatible document.
86
+ * `exportEntirety()` on a compatible document.
87
87
  *
88
88
  * After import, the changefeed fires for all subscribers — the event
89
89
  * bridge handles this automatically.
90
90
  *
91
91
  * ```ts
92
92
  * const delta = exportSince(docA, sinceVersion)
93
- * importDelta(docB, delta!, "sync")
93
+ * merge(docB, delta!, "sync")
94
94
  * ```
95
95
  *
96
- * @param doc - A document created by `createYjsDoc` or `createYjsDocFromSnapshot`.
97
- * @param payload - The delta or snapshot payload to import.
96
+ * @param doc - A document created by `createYjsDoc` or `createYjsDocFromEntirety`.
97
+ * @param payload - The delta or entirety payload to merge.
98
98
  * @param origin - Optional provenance tag for the changeset.
99
- * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromSnapshot`.
99
+ * @throws If `doc` was not created by `createYjsDoc` / `createYjsDocFromEntirety`.
100
100
  */
101
- export function importDelta(
101
+ export function merge(
102
102
  doc: object,
103
103
  payload: SubstratePayload,
104
104
  origin?: string,
105
105
  ): void {
106
- getSubstrate(doc).importDelta(payload, origin)
107
- }
106
+ getSubstrate(doc).merge(payload, origin)
107
+ }
package/src/version.ts CHANGED
@@ -85,9 +85,7 @@ export class YjsVersion implements Version {
85
85
  */
86
86
  compare(other: Version): "behind" | "equal" | "ahead" | "concurrent" {
87
87
  if (!(other instanceof YjsVersion)) {
88
- throw new Error(
89
- "YjsVersion can only be compared with another YjsVersion",
90
- )
88
+ throw new Error("YjsVersion can only be compared with another YjsVersion")
91
89
  }
92
90
 
93
91
  const thisMap = decodeStateVector(this.sv)
@@ -135,4 +133,4 @@ export class YjsVersion implements Version {
135
133
  const bytes = base64ToUint8Array(serialized)
136
134
  return new YjsVersion(bytes)
137
135
  }
138
- }
136
+ }
package/src/yjs-escape.ts CHANGED
@@ -3,15 +3,16 @@
3
3
  //
4
4
  // `yjs(ref)` returns the `Y.Doc` backing a root document ref.
5
5
  //
6
- // The mapping is maintained via a WeakMap from Substrate → Y.Doc,
7
- // populated by `registerYjsSubstrate()` (called during substrate
8
- // creation). The `yjs()` function uses `unwrap()` from `@kyneta/schema`
9
- // to get the substrate, then looks up the Y.Doc.
6
+ // The substrate exposes its backing Y.Doc via the `BACKING_DOC` symbol
7
+ // (from `@kyneta/schema`). The `yjs()` function uses `unwrap()` to get
8
+ // the substrate, then reads `[BACKING_DOC]` to get the Y.Doc.
10
9
  //
11
10
  // This two-step approach (ref → substrate → Y.Doc) avoids duplicating
12
11
  // the ref-tracking WeakMap and composes cleanly with the general
13
12
  // `unwrap()` escape hatch.
14
13
  //
14
+ // Context: jj:smmulzkm (BACKING_DOC replaces WeakMap + registerYjsSubstrate)
15
+ //
15
16
  // Usage:
16
17
  // import { yjs } from "@kyneta/yjs-schema"
17
18
  //
@@ -19,33 +20,8 @@
19
20
  // const yjsDoc = yjs(doc) // Y.Doc
20
21
  // yjsDoc.getMap("root").toJSON() // raw Yjs inspection
21
22
 
23
+ import { BACKING_DOC, unwrap } from "@kyneta/schema"
22
24
  import type { Doc as YDoc } from "yjs"
23
- import type { Substrate } from "@kyneta/schema"
24
- import { unwrap } from "@kyneta/schema"
25
-
26
- // ---------------------------------------------------------------------------
27
- // Substrate → Y.Doc mapping
28
- // ---------------------------------------------------------------------------
29
-
30
- const substrateToYjsDoc = new WeakMap<Substrate<any>, YDoc>()
31
-
32
- // ---------------------------------------------------------------------------
33
- // registerYjsSubstrate — called during substrate creation
34
- // ---------------------------------------------------------------------------
35
-
36
- /**
37
- * Register the Y.Doc backing a Yjs substrate.
38
- *
39
- * Called by `createYjsSubstrate()` and by `bindYjs`'s factory builder
40
- * to enable the `yjs()` escape hatch. Must be called once per substrate
41
- * at construction time.
42
- */
43
- export function registerYjsSubstrate(
44
- substrate: Substrate<any>,
45
- doc: YDoc,
46
- ): void {
47
- substrateToYjsDoc.set(substrate, doc)
48
- }
49
25
 
50
26
  // ---------------------------------------------------------------------------
51
27
  // yjs — Yjs-specific escape hatch
@@ -77,7 +53,7 @@ export function registerYjsSubstrate(
77
53
  * ```
78
54
  */
79
55
  export function yjs(ref: object): YDoc {
80
- let substrate: Substrate<any>
56
+ let substrate: any
81
57
  try {
82
58
  substrate = unwrap(ref)
83
59
  } catch {
@@ -88,13 +64,21 @@ export function yjs(ref: object): YDoc {
88
64
  )
89
65
  }
90
66
 
91
- const doc = substrateToYjsDoc.get(substrate)
92
- if (!doc) {
67
+ const doc = substrate[BACKING_DOC]
68
+ // Duck-type check: Y.Doc has getMap, encodeStateVector-compatible API,
69
+ // and a numeric clientID. A PlainState (plain object) or LoroDoc would
70
+ // not have getMap as a function.
71
+ if (
72
+ !doc ||
73
+ typeof doc !== "object" ||
74
+ typeof (doc as any).getMap !== "function" ||
75
+ typeof (doc as any).clientID !== "number"
76
+ ) {
93
77
  throw new Error(
94
78
  "yjs() requires a ref backed by a Yjs substrate. " +
95
79
  "The ref has a substrate but it is not a Yjs substrate. " +
96
80
  "Use a doc created with a bindYjs() schema or createYjsDoc().",
97
81
  )
98
82
  }
99
- return doc
100
- }
83
+ return doc as YDoc
84
+ }
@@ -14,9 +14,8 @@
14
14
  // Using a single root Y.Map enables one `observeDeep` call that
15
15
  // captures all mutations with correct relative paths.
16
16
 
17
+ import type { Path, Schema as SchemaNode, Segment } from "@kyneta/schema"
17
18
  import { advanceSchema } from "@kyneta/schema"
18
- import type { Path, Segment } from "@kyneta/schema"
19
- import type { Schema as SchemaNode } from "@kyneta/schema"
20
19
  import * as Y from "yjs"
21
20
 
22
21
  // ---------------------------------------------------------------------------
@@ -35,10 +34,7 @@ import * as Y from "yjs"
35
34
  * @param current - The current position (a Yjs shared type or plain value)
36
35
  * @param segment - The path segment to follow
37
36
  */
38
- export function stepIntoYjs(
39
- current: unknown,
40
- segment: Segment,
41
- ): unknown {
37
+ export function stepIntoYjs(current: unknown, segment: Segment): unknown {
42
38
  const resolved = segment.resolve()
43
39
 
44
40
  if (current instanceof Y.Map) {
@@ -50,9 +46,7 @@ export function stepIntoYjs(
50
46
  }
51
47
 
52
48
  if (current instanceof Y.Text) {
53
- throw new Error(
54
- `yjs-resolve: cannot step into Y.Text`,
55
- )
49
+ throw new Error(`yjs-resolve: cannot step into Y.Text`)
56
50
  }
57
51
 
58
52
  // Plain value — terminal, cannot step further
@@ -105,4 +99,4 @@ export function resolveYjsType(
105
99
  }
106
100
 
107
101
  return current
108
- }
102
+ }