@kyneta/yjs-schema 1.3.0 → 1.4.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/README.md CHANGED
@@ -8,19 +8,20 @@ Wraps a `Y.Doc` with schema-aware typed reads, writes, versioning, and export/im
8
8
 
9
9
  ```ts
10
10
  import {
11
- createYjsDoc,
11
+ createDoc,
12
12
  change,
13
13
  subscribe,
14
14
  Schema,
15
15
  text,
16
+ yjs,
16
17
  version,
17
18
  exportSnapshot,
18
19
  exportSince,
19
20
  importDelta,
20
21
  } from "@kyneta/yjs-schema"
21
22
 
22
- // Define a schema
23
- const TodoDoc = Schema.struct({
23
+ // Define a schema and bind to Yjs substrate
24
+ const TodoDoc = yjs.bind(Schema.struct({
24
25
  title: text(),
25
26
  items: Schema.list(
26
27
  Schema.struct({
@@ -28,10 +29,10 @@ const TodoDoc = Schema.struct({
28
29
  done: Schema.boolean(),
29
30
  }),
30
31
  ),
31
- })
32
+ }))
32
33
 
33
34
  // Create a document with optional seed values
34
- const doc = createYjsDoc(TodoDoc, {
35
+ const doc = createDoc(TodoDoc, {
35
36
  title: "My Todos",
36
37
  items: [{ name: "Buy milk", done: false }],
37
38
  })
@@ -66,16 +67,16 @@ subscribe(doc, (changeset) => {
66
67
 
67
68
  ### Unsupported
68
69
 
69
- - **`Schema.annotated("counter")`** — Yjs has no native counter type. Use `Schema.number()` with `ReplaceChange` instead. Attempting to use a counter annotation will throw at construction time.
70
- - **`Schema.annotated("movable")`** — Yjs has no native movable list. Will throw at construction time.
71
- - **`Schema.annotated("tree")`** — Yjs has no native tree type. Will throw at construction time.
70
+ - **`Schema.counter()`** — Yjs has no native counter type. Use `Schema.number()` with `ReplaceChange` instead. Attempting to use a counter annotation will throw at construction time.
71
+ - **`Schema.movableList()`** — Yjs has no native movable list. Will throw at construction time.
72
+ - **`Schema.tree()`** — Yjs has no native tree type. Will throw at construction time.
72
73
 
73
74
  ## Sync
74
75
 
75
76
  ```ts
76
77
  import {
77
- createYjsDoc,
78
- createYjsDocFromSnapshot,
78
+ createDoc,
79
+ yjs,
79
80
  version,
80
81
  exportSnapshot,
81
82
  exportSince,
@@ -83,12 +84,14 @@ import {
83
84
  change,
84
85
  } from "@kyneta/yjs-schema"
85
86
 
87
+ const MyDoc = yjs.bind(MySchema)
88
+
86
89
  // Peer A creates a doc
87
- const docA = createYjsDoc(MySchema, { title: "Draft" })
90
+ const docA = createDoc(MyDoc, { title: "Draft" })
88
91
 
89
92
  // Peer B bootstraps from a full snapshot
90
93
  const snapshot = exportSnapshot(docA)
91
- const docB = createYjsDocFromSnapshot(MySchema, snapshot)
94
+ const docB = createDoc(MyDoc, snapshot)
92
95
 
93
96
  // After mutations on A, sync incrementally
94
97
  const vBefore = version(docB)
@@ -102,10 +105,10 @@ importDelta(docB, delta!)
102
105
  ## Exchange Integration
103
106
 
104
107
  ```ts
105
- import { bindYjs } from "@kyneta/yjs-schema"
108
+ import { yjs } from "@kyneta/yjs-schema"
106
109
  import { Schema, text } from "@kyneta/yjs-schema"
107
110
 
108
- const TodoDoc = bindYjs(Schema.struct({
111
+ const TodoDoc = yjs.bind(Schema.struct({
109
112
  title: text(),
110
113
  items: Schema.list(Schema.struct({
111
114
  name: Schema.string(),
@@ -117,16 +120,17 @@ const TodoDoc = bindYjs(Schema.struct({
117
120
  const doc = exchange.get("my-todos", TodoDoc)
118
121
  ```
119
122
 
120
- `bindYjs` produces a `BoundSchema` with `strategy: "causal"`, which the exchange uses for bidirectional CRDT sync.
123
+ `yjs.bind()` produces a `BoundSchema` with the collaborative `SyncProtocol`, which the exchange uses for bidirectional CRDT sync.
121
124
 
122
125
  ## Escape Hatch
123
126
 
124
127
  Access the underlying `Y.Doc` for direct Yjs API usage:
125
128
 
126
129
  ```ts
127
- import { yjs } from "@kyneta/yjs-schema"
130
+ import { yjs, createDoc } from "@kyneta/yjs-schema"
128
131
 
129
- const doc = createYjsDoc(MySchema)
132
+ const MyDoc = yjs.bind(MySchema)
133
+ const doc = createDoc(MyDoc)
130
134
  const yjsDoc = yjs(doc)
131
135
 
132
136
  // Use with Yjs ecosystem
@@ -152,28 +156,27 @@ Because `yjs(doc)` returns a standard `Y.Doc`, the entire Yjs provider ecosystem
152
156
 
153
157
  | Export | Description |
154
158
  |---|---|
155
- | `createYjsDoc(schema, docOrSeed?)` | Create a live Yjs-backed document |
156
- | `createYjsDocFromSnapshot(schema, payload)` | Reconstruct from snapshot |
159
+ | `createDoc(schema, docOrSeed?)` | Create a live Yjs-backed document *(re-exported from `@kyneta/schema`)* |
157
160
  | `version(doc)` | Current `YjsVersion` |
158
- | `exportSnapshot(doc)` | Full state as `SubstratePayload` |
161
+ | `exportEntirety(doc)` | Full state as `SubstratePayload` |
159
162
  | `exportSince(doc, since)` | Delta since version |
160
- | `importDelta(doc, payload, origin?)` | Apply delta from peer |
163
+ | `merge(doc, payload, origin?)` | Apply delta from peer |
161
164
  | `change(doc, fn)` | Transactional mutation |
162
165
  | `subscribe(doc, callback)` | Observe changes |
163
- | `bindYjs(schema)` | Bind schema for exchange use |
166
+ | `yjs.bind(schema)` | Bind schema for exchange use |
164
167
  | `yjs(ref)` | Escape hatch → `Y.Doc` |
165
- | `text()` | `Schema.annotated("text")` convenience |
168
+ | `text()` | `Schema.text()` convenience — collaborative text schema kind |
166
169
 
167
170
  ### Low-level primitives (power users)
168
171
 
169
172
  | Export | Description |
170
173
  |---|---|
171
174
  | `YjsVersion` | Version class wrapping Yjs state vectors |
172
- | `yjsStoreReader(doc, schema)` | Live `StoreReader` over Yjs types |
175
+ | `yjsReader(doc, schema)` | Live `StoreReader` over Yjs types |
173
176
  | `resolveYjsType(rootMap, schema, path)` | Path resolution |
174
177
  | `applyChangeToYjs(rootMap, schema, path, change)` | kyneta → Yjs |
175
178
  | `eventsToOps(events)` | Yjs → kyneta |
176
- | `populateRoot(doc, schema, seed)` | Root container population |
179
+ | `ensureContainers(doc, schema, seed)` | Root container population |
177
180
  | `createYjsSubstrate(doc, schema)` | Low-level substrate construction |
178
181
  | `yjsSubstrateFactory` | `SubstrateFactory<YjsVersion>` |
179
182
 
package/dist/index.d.ts CHANGED
@@ -1,8 +1,9 @@
1
- export { Changeset } from '@kyneta/changefeed';
2
- import { NativeMap, SubstrateNamespace, CrdtStrategy, Schema, Path, ChangeBase, Op, Reader, Version, Substrate, ReplicaFactory, SubstrateFactory, Segment } from '@kyneta/schema';
3
- export { DocRef, NATIVE, Op, Ref, Schema, SubstratePayload, applyChanges, change, createDoc, createRef, exportEntirety, exportSince, merge, subscribe, subscribeNode, unwrap, version } from '@kyneta/schema';
4
- import * as Y from 'yjs';
1
+ import { BindingTarget, ChangeBase, DocRef, Instruction, NATIVE, NativeMap, Op, Op as Op$1, Path, Position, Reader, Ref, ReplicaFactory, Schema, Schema as Schema$1, SchemaBinding, Segment, Side, Substrate, SubstrateFactory, SubstratePayload, Version, applyChanges, change, createDoc, createRef, exportEntirety, exportSince, merge, subscribe, subscribeNode, unwrap, version } from "@kyneta/schema";
2
+ import * as Y from "yjs";
3
+ import { Doc } from "yjs";
4
+ import { Changeset } from "@kyneta/changefeed";
5
5
 
6
+ //#region src/native-map.d.ts
6
7
  /**
7
8
  * NativeMap for the Yjs CRDT substrate.
8
9
  *
@@ -20,36 +21,41 @@ import * as Y from 'yjs';
20
21
  * - `sum → undefined` (no container; stored in parent map)
21
22
  */
22
23
  interface YjsNativeMap extends NativeMap {
23
- readonly root: Y.Doc;
24
- readonly text: Y.Text;
25
- readonly counter: undefined;
26
- readonly list: Y.Array<unknown>;
27
- readonly movableList: undefined;
28
- readonly struct: Y.Map<unknown>;
29
- readonly map: Y.Map<unknown>;
30
- readonly tree: undefined;
31
- readonly set: undefined;
32
- readonly scalar: undefined;
33
- readonly sum: undefined;
24
+ readonly root: Y.Doc;
25
+ readonly text: Y.Text;
26
+ readonly counter: undefined;
27
+ readonly list: Y.Array<unknown>;
28
+ readonly movableList: undefined;
29
+ readonly struct: Y.Map<unknown>;
30
+ readonly map: Y.Map<unknown>;
31
+ readonly tree: undefined;
32
+ readonly set: undefined;
33
+ readonly scalar: undefined;
34
+ readonly sum: undefined;
34
35
  }
35
-
36
+ //#endregion
37
+ //#region src/bind-yjs.d.ts
38
+ /**
39
+ * Yjs composition-law tags — the set of concurrent composition laws
40
+ * that the Yjs substrate faithfully implements.
41
+ */
42
+ type YjsLaws = "lww" | "positional-ot" | "lww-per-key" | "lww-tag-replaced";
36
43
  /**
37
- * The Yjs CRDT substrate namespace.
44
+ * The Yjs CRDT binding target.
38
45
  *
39
- * - `yjs.bind(schema)` — collaborative sync (default)
40
- * - `yjs.bind(schema, "ephemeral")` — ephemeral/presence broadcast
41
- * - `yjs.replica()` — collaborative replication (default)
42
- * - `yjs.replica("ephemeral")` — ephemeral replication
46
+ * - `yjs.bind(schema)` — bind a schema to Yjs with collaborative sync
47
+ * - `yjs.replica()` — create a collaborative replica
43
48
  *
44
- * Strategy is constrained to `CrdtStrategy` (`"collaborative" | "ephemeral"`).
45
- * Passing `"authoritative"` is a compile error.
49
+ * Laws are constrained to `YjsLaws` schemas requiring composition laws
50
+ * outside this set (e.g. `"additive"` from `Schema.counter()`,
51
+ * `"positional-ot-move"` from `Schema.movableList()`) are rejected at
52
+ * compile time.
46
53
  *
47
54
  * To access the underlying Y.Doc, use `unwrap(ref)` from `@kyneta/schema`.
48
55
  */
49
- /** The closed set of capability tags that the Yjs substrate supports. */
50
- type YjsCaps = "text" | "json";
51
- declare const yjs: SubstrateNamespace<CrdtStrategy, YjsCaps, YjsNativeMap>;
52
-
56
+ declare const yjs: BindingTarget<YjsLaws, YjsNativeMap>;
57
+ //#endregion
58
+ //#region src/change-mapping.d.ts
53
59
  /**
54
60
  * Apply a kyneta Change to the Yjs shared type tree imperatively.
55
61
  *
@@ -62,7 +68,7 @@ declare const yjs: SubstrateNamespace<CrdtStrategy, YjsCaps, YjsNativeMap>;
62
68
  * @param path - The path to the target
63
69
  * @param change - The kyneta Change to apply
64
70
  */
65
- declare function applyChangeToYjs(rootMap: Y.Map<any>, rootSchema: Schema, path: Path, change: ChangeBase): void;
71
+ declare function applyChangeToYjs(rootMap: Y.Map<any>, rootSchema: Schema$1, path: Path, change: ChangeBase, binding?: SchemaBinding): void;
66
72
  /**
67
73
  * Convert `observeDeep` events into kyneta `Op[]` for changefeed delivery.
68
74
  *
@@ -76,8 +82,9 @@ declare function applyChangeToYjs(rootMap: Y.Map<any>, rootSchema: Schema, path:
76
82
  *
77
83
  * @param events - The events from the `observeDeep` callback
78
84
  */
79
- declare function eventsToOps(events: Y.YEvent<any>[], schema: Schema): Op[];
80
-
85
+ declare function eventsToOps(events: Y.YEvent<any>[], schema: Schema$1, binding?: SchemaBinding): Op$1[];
86
+ //#endregion
87
+ //#region src/populate.d.ts
81
88
  /**
82
89
  * Ensure that a Y.Doc's root map contains the correct Yjs shared types
83
90
  * matching the schema structure.
@@ -100,13 +107,35 @@ declare function eventsToOps(events: Y.YEvent<any>[], schema: Schema): Op[];
100
107
  * then restores the caller's clientID. This produces byte-identical
101
108
  * structural ops across all peers, enabling Yjs deduplication on merge.
102
109
  *
110
+ * **Identity-keying:** When a `binding` is provided, each root field's
111
+ * key in the root Y.Map is the identity hash from `binding.forward`
112
+ * instead of the field name. Nested product fields are similarly keyed
113
+ * via `ensureMapContainers`.
114
+ *
103
115
  * @param doc - The Y.Doc to prepare
104
116
  * @param schema - The root document schema (a ProductSchema)
105
117
  * @param conditional - If true, skip fields that already exist in the root map.
106
118
  * Context: jj:smmulzkm (two-phase substrate construction)
119
+ * @param binding - Optional SchemaBinding for identity-keyed containers.
107
120
  */
108
- declare function ensureContainers(doc: Y.Doc, schema: Schema, conditional?: boolean): void;
109
-
121
+ declare function ensureContainers(doc: Y.Doc, schema: Schema$1, conditional?: boolean, binding?: SchemaBinding): void;
122
+ //#endregion
123
+ //#region src/position.d.ts
124
+ /** Map kyneta Side to Yjs assoc. Left → -1 (left-sticky), Right → 0 (right-sticky). */
125
+ declare function toYjsAssoc(side: Side): number;
126
+ /** Map Yjs assoc to kyneta Side. Negative → left, non-negative → right. */
127
+ declare function fromYjsAssoc(assoc: number): Side;
128
+ declare class YjsPosition implements Position {
129
+ private readonly rpos;
130
+ private readonly doc;
131
+ readonly side: Side;
132
+ constructor(rpos: Y.RelativePosition, doc: Y.Doc);
133
+ resolve(): number | null;
134
+ encode(): Uint8Array;
135
+ transform(_instructions: readonly Instruction[]): void;
136
+ }
137
+ //#endregion
138
+ //#region src/reader.d.ts
110
139
  /**
111
140
  * Creates a Reader that navigates the Yjs shared type tree live,
112
141
  * using the schema as a type witness to determine navigation at each
@@ -120,58 +149,106 @@ declare function ensureContainers(doc: Y.Doc, schema: Schema, conditional?: bool
120
149
  *
121
150
  * @param doc - The Y.Doc to read from.
122
151
  * @param schema - The root schema for the document.
152
+ * @param binding - Optional SchemaBinding for identity-keyed navigation.
123
153
  */
124
- declare function yjsReader(doc: Y.Doc, schema: Schema): Reader;
125
-
154
+ declare function yjsReader(doc: Y.Doc, schema: Schema$1, binding?: SchemaBinding): Reader;
155
+ //#endregion
156
+ //#region src/version.d.ts
126
157
  /**
127
- * A Version wrapping a Yjs state vector.
158
+ * A Version wrapping a Yjs snapshot (state vector + delete set).
128
159
  *
129
- * State vectors track the complete peer state which operations from
130
- * each client have been observed. This is the right abstraction for sync
131
- * diffing: `exportSince(version)` uses the state vector to compute the
132
- * minimal update payload via `Y.encodeStateAsUpdate(doc, sv)`.
160
+ * The state vector tracks which insertions from each client have been
161
+ * observed. The delete set tracks which of those items have been
162
+ * tombstoned. Together they fully describe a Yjs document's state.
133
163
  *
134
- * `serialize()` encodes to base64 for text-safe embedding.
135
- * `compare()` decodes both state vectors and performs standard
136
- * version-vector partial-order comparison over the client-clock maps.
164
+ * - `sv` is used by `exportSince()` to compute the minimal update payload
165
+ * via `Y.encodeStateAsUpdate(doc, sv)`.
166
+ * - `snapshotBytes` is the encoded Yjs `Snapshot` (SV + delete set),
167
+ * used for equality comparison: two documents are "equal" only when
168
+ * both their inserts and deletes match.
169
+ *
170
+ * `compare()` first performs standard version-vector partial-order
171
+ * comparison on the state vectors. If the SVs are equal, it falls
172
+ * through to a byte-level comparison of the snapshot bytes — if they
173
+ * differ (same inserts, different deletes), the result is "concurrent",
174
+ * ensuring the sync protocol pushes the divergent deletes.
137
175
  */
138
176
  declare class YjsVersion implements Version {
139
- readonly sv: Uint8Array;
140
- constructor(sv: Uint8Array);
141
- /**
142
- * Serialize the state vector to a base64 string.
143
- *
144
- * The encoding is: raw state vector bytes → base64.
145
- * This is text-safe for embedding in HTML meta tags, URL parameters, etc.
146
- */
147
- serialize(): string;
148
- /**
149
- * Compare with another version using version-vector partial order.
150
- *
151
- * Delegates to the shared `versionVectorCompare` utility after decoding
152
- * both state vectors via `Y.decodeStateVector()`.
153
- *
154
- * @throws If `other` is not a `YjsVersion`.
155
- */
156
- compare(other: Version): "behind" | "equal" | "ahead" | "concurrent";
157
- /**
158
- * Greatest lower bound (lattice meet) of two Yjs versions.
159
- *
160
- * Decodes both state vectors, computes the component-wise minimum
161
- * via the shared `versionVectorMeet` utility, and encodes the result
162
- * back to a Yjs state vector.
163
- *
164
- * @throws If `other` is not a `YjsVersion`.
165
- */
166
- meet(other: Version): YjsVersion;
167
- /**
168
- * Parse a serialized YjsVersion string back into a YjsVersion.
169
- *
170
- * The inverse of `serialize()`: base64 → `Uint8Array`.
171
- */
172
- static parse(serialized: string): YjsVersion;
177
+ /** Encoded state vector — used by exportSince(). */
178
+ readonly sv: Uint8Array;
179
+ /**
180
+ * Encoded Yjs snapshot (state vector + delete set) — used for equality
181
+ * comparison. Two documents are "equal" only if both their inserts
182
+ * (state vector) and deletes (delete set) match.
183
+ */
184
+ readonly snapshotBytes: Uint8Array;
185
+ constructor(sv: Uint8Array, snapshotBytes?: Uint8Array);
186
+ /**
187
+ * Construct a version from a live `Y.Doc` by snapshotting its full state.
188
+ *
189
+ * Walks the struct store to derive the delete set O(n) in the number
190
+ * of items. Use {@link fromDeleteSet} for the incremental path.
191
+ */
192
+ static fromDoc(doc: Doc): YjsVersion;
193
+ /**
194
+ * Construct a version from a `Y.Doc`'s state vector and an externally
195
+ * maintained delete set — the incremental path that avoids a struct
196
+ * store walk.
197
+ *
198
+ * @param doc The live Y.Doc (for the state vector).
199
+ * @param ds An accumulated delete set, kept in sync by merging
200
+ * `transaction.deleteSet` on each transaction.
201
+ */
202
+ static fromDeleteSet(doc: Doc, ds: ReturnType<typeof Y.createDeleteSet>): YjsVersion;
203
+ /**
204
+ * Serialize to a text-safe string.
205
+ *
206
+ * Format: `base64(sv) + "." + base64(snapshotBytes)`.
207
+ * The "." separator is unambiguous since base64 never contains ".".
208
+ */
209
+ serialize(): string;
210
+ /**
211
+ * Compare with another version using version-vector partial order,
212
+ * extended with delete-set equality checking.
213
+ *
214
+ * 1. Decode both state vectors and compare via `versionVectorCompare`.
215
+ * 2. If the SV comparison yields anything other than "equal", return it.
216
+ * 3. If the SVs are equal, compare snapshot bytes for byte equality.
217
+ * If they differ (same inserts, different deletes), return "concurrent"
218
+ * — both sides may have tombstones the other lacks.
219
+ * 4. "equal" is returned only when BOTH the state vector AND the
220
+ * delete set match.
221
+ *
222
+ * @throws If `other` is not a `YjsVersion`.
223
+ */
224
+ compare(other: Version): "behind" | "equal" | "ahead" | "concurrent";
225
+ /**
226
+ * Greatest lower bound (lattice meet) of two Yjs versions.
227
+ *
228
+ * Decodes both state vectors, computes the component-wise minimum
229
+ * via `versionVectorMeet`, and encodes the result back to a Yjs
230
+ * state vector.
231
+ *
232
+ * The meet snapshot uses the meet SV with no delete-set information
233
+ * (conservative lower bound). meet() feeds into advance(), which Yjs
234
+ * does not support incrementally, so this is safe.
235
+ *
236
+ * @throws If `other` is not a `YjsVersion`.
237
+ */
238
+ meet(other: Version): YjsVersion;
239
+ /**
240
+ * Parse a serialized YjsVersion string back into a YjsVersion.
241
+ *
242
+ * New format: `base64(sv) + "." + base64(snapshotBytes)`.
243
+ * Legacy format (no "."): `base64(sv)` only — constructed with
244
+ * `snapshotBytes` equal to the SV bytes. When compared against a
245
+ * new-format version with matching SVs, the differing snapshot bytes
246
+ * yield "concurrent", triggering a safe redundant sync push.
247
+ */
248
+ static parse(serialized: string): YjsVersion;
173
249
  }
174
-
250
+ //#endregion
251
+ //#region src/substrate.d.ts
175
252
  /**
176
253
  * Creates a `Substrate<YjsVersion>` wrapping a user-provided Y.Doc.
177
254
  *
@@ -189,37 +266,59 @@ declare class YjsVersion implements Version {
189
266
  * @param doc - The Y.Doc to wrap. The substrate does NOT own the doc;
190
267
  * the caller is responsible for its lifecycle.
191
268
  * @param schema - The root schema for the document.
269
+ * @param binding - Optional SchemaBinding for identity-keyed containers.
192
270
  */
193
- declare function createYjsSubstrate(doc: Y.Doc, schema: Schema): Substrate<YjsVersion>;
271
+ declare function createYjsSubstrate(doc: Y.Doc, schema: Schema$1, binding?: SchemaBinding): Substrate<YjsVersion>;
194
272
  declare const yjsReplicaFactory: ReplicaFactory<YjsVersion>;
195
273
  declare const yjsSubstrateFactory: SubstrateFactory<YjsVersion>;
196
-
274
+ //#endregion
275
+ //#region src/yjs-resolve.d.ts
197
276
  /**
198
277
  * Navigate one step deeper into the Yjs shared type tree.
199
278
  *
200
279
  * Uses `instanceof` for runtime type discrimination:
201
- * - `Y.Map` → `.get(key)`
280
+ * - `Y.Map` → `.get(key)` — uses the identity hash when provided
202
281
  * - `Y.Array` → `.get(index)`
203
282
  * - `Y.Text` → terminal (cannot step further)
204
283
  * - Plain value → terminal (return `undefined`)
205
284
  *
206
285
  * @param current - The current position (a Yjs shared type or plain value)
207
286
  * @param segment - The path segment to follow
287
+ * @param identity - Optional identity hash to use instead of the segment's resolved value
208
288
  */
209
- declare function stepIntoYjs(current: unknown, segment: Segment): unknown;
289
+ declare function stepIntoYjs(current: unknown, segment: Segment, identity?: string): unknown;
290
+ /**
291
+ * Result of resolving a Yjs shared type at a path.
292
+ *
293
+ * Includes both the resolved Yjs value and the schema at that position,
294
+ * enabling callers to distinguish between schema kinds that map to the
295
+ * same Yjs type (e.g. "text" vs "richtext" both use Y.Text).
296
+ */
297
+ interface ResolvedYjs {
298
+ readonly resolved: unknown;
299
+ readonly schema: Schema$1;
300
+ }
210
301
  /**
211
302
  * Resolve a Yjs shared type (or plain value) at the given path.
212
303
  *
213
304
  * Left-folds over path segments using `advanceSchema` for pure schema
214
305
  * descent and `stepIntoYjs` for Yjs-specific navigation.
215
306
  *
216
- * Returns the Yjs shared type or plain value at the terminal position.
217
- * For an empty path, returns the root map itself.
307
+ * When a `binding` is provided, each step computes the absolute schema
308
+ * path and looks up the identity hash from `binding.forward`. This
309
+ * identity hash is used instead of the field name at every product-field
310
+ * boundary (root and nested).
311
+ *
312
+ * Returns both the Yjs shared type (or plain value) and the schema at
313
+ * the terminal position. For an empty path, returns the root map and
314
+ * root schema.
218
315
  *
219
316
  * @param rootMap - The root `Y.Map` obtained via `doc.getMap("root")`
220
317
  * @param rootSchema - The root document schema
221
318
  * @param path - The path to resolve
319
+ * @param binding - Optional SchemaBinding for identity-keyed navigation.
222
320
  */
223
- declare function resolveYjsType(rootMap: Y.Map<any>, rootSchema: Schema, path: Path): unknown;
224
-
225
- export { type YjsCaps, type YjsNativeMap, YjsVersion, applyChangeToYjs, createYjsSubstrate, ensureContainers, eventsToOps, resolveYjsType, stepIntoYjs, yjs, yjsReader, yjsReplicaFactory, yjsSubstrateFactory };
321
+ declare function resolveYjsType(rootMap: Y.Map<any>, rootSchema: Schema$1, path: Path, binding?: SchemaBinding): ResolvedYjs;
322
+ //#endregion
323
+ export { type Changeset, type DocRef, NATIVE, type Op, type Ref, Schema, type SubstratePayload, type YjsLaws, type YjsNativeMap, YjsPosition, YjsVersion, applyChangeToYjs, applyChanges, change, createDoc, createRef, createYjsSubstrate, ensureContainers, eventsToOps, exportEntirety, exportSince, fromYjsAssoc, merge, resolveYjsType, stepIntoYjs, subscribe, subscribeNode, toYjsAssoc, unwrap, version, yjs, yjsReader, yjsReplicaFactory, yjsSubstrateFactory };
324
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/native-map.ts","../src/bind-yjs.ts","../src/change-mapping.ts","../src/populate.ts","../src/position.ts","../src/reader.ts","../src/version.ts","../src/substrate.ts","../src/yjs-resolve.ts"],"mappings":"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"}