json-patch-to-crdt 0.1.0 → 0.1.1

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
@@ -64,6 +64,7 @@ import { applyPatch, createState, forkState, mergeState, toJson } from "json-pat
64
64
  const origin = createState({ count: 0, items: ["a"] }, { actor: "origin" });
65
65
 
66
66
  // Fork shared-origin replicas with local actor identities.
67
+ // Actor IDs must be unique per live peer (same-actor reuse is rejected by default).
67
68
  const peerA = forkState(origin, "A");
68
69
  const peerB = forkState(origin, "B");
69
70
 
@@ -315,7 +316,7 @@ Internals helpers like `jsonPatchToCrdtSafe` and `tryMergeDoc` return the same s
315
316
  ### State helpers
316
317
 
317
318
  - `createState(initial, { actor, start? })` - Create a new CRDT state from JSON.
318
- - `forkState(origin, actor)` - Fork a shared-origin replica with a new local actor ID.
319
+ - `forkState(origin, actor, options?)` - Fork a shared-origin replica with a new local actor ID. Reusing `origin` actor IDs is rejected by default (`options.allowActorReuse: true` to opt in explicitly).
319
320
  - `applyPatch(state, patch, options?)` - Apply a patch immutably, returning a new state (`semantics: "sequential"` by default).
320
321
  - `applyPatchInPlace(state, patch, options?)` - Apply a patch by mutating state in place (`atomic: true` by default).
321
322
  - `tryApplyPatch(state, patch, options?)` - Non-throwing immutable apply (`{ ok: true, state }` or `{ ok: false, error }`).
@@ -394,6 +395,9 @@ No. It is deterministic and usually compact, but not guaranteed to be minimal.
394
395
  **How do I merge states from two peers?**
395
396
  Use `forkState(origin, actor)` to create each peer from the same origin, then `mergeState(local, remote, { actor: localActorId })`. Each peer should keep a stable unique actor ID across merges. See the [Multi-Peer Sync](#multi-peer-sync) example above.
396
397
 
398
+ **Why did `forkState` throw about actor uniqueness?**
399
+ By default, `forkState` blocks reusing `origin.clock.actor` because same-actor forks can mint duplicate dots and produce order-dependent merges. If you intentionally need same-actor cloning, pass `forkState(origin, actor, { allowActorReuse: true })`.
400
+
397
401
  **Why can my local counter jump after a merge?**
398
402
  Array inserts that target an existing predecessor may need to outrank sibling insert dots for deterministic ordering. The library can fast-forward the local counter in constant time to avoid expensive loops, but the resulting counter value may still jump upward when merging with peers that already have high counters.
399
403
 
package/dist/index.d.mts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as PatchErrorReason, C as toJson, D as ActorId, E as validateJsonPatch, G as JsonPrimitive, H as JsonPatch, I as CrdtState, K as JsonValue, L as DiffOptions, M as ApplyPatchOptions, O as ApplyError, S as forkState, T as tryApplyPatchInPlace, U as JsonPatchOp, Y as MergeStateOptions, _ as PatchError, a as tryMergeState, b as applyPatchInPlace, ct as SerializedState, et as PatchSemantics, f as diffJsonPatch, ft as TryMergeStateResult, j as ApplyPatchInPlaceOptions, l as serializeState, lt as TryApplyPatchInPlaceResult, pt as ValidatePatchResult, r as mergeState, s as deserializeState, t as MergeError, ut as TryApplyPatchResult, v as applyPatch, w as tryApplyPatch, x as createState } from "./merge-BrNGGkXj.mjs";
2
- export { type ActorId, type ApplyError, type ApplyPatchInPlaceOptions, type ApplyPatchOptions, type CrdtState, type DiffOptions, type JsonPatch, type JsonPatchOp, type JsonPrimitive, type JsonValue, MergeError, type MergeStateOptions, PatchError, type PatchErrorReason, type PatchSemantics, type SerializedState, type TryApplyPatchInPlaceResult, type TryApplyPatchResult, type TryMergeStateResult, type ValidatePatchResult, applyPatch, applyPatchInPlace, createState, deserializeState, diffJsonPatch, forkState, mergeState, serializeState, toJson, tryApplyPatch, tryApplyPatchInPlace, tryMergeState, validateJsonPatch };
1
+ import { C as toJson, D as ActorId, E as validateJsonPatch, I as CrdtState, K as JsonPrimitive, L as DiffOptions, M as ApplyPatchOptions, O as ApplyError, S as forkState, T as tryApplyPatchInPlace, U as JsonPatch, V as ForkStateOptions, W as JsonPatchOp, X as MergeStateOptions, _ as PatchError, a as tryMergeState, b as applyPatchInPlace, dt as TryApplyPatchResult, et as PatchErrorReason, f as diffJsonPatch, j as ApplyPatchInPlaceOptions, l as serializeState, lt as SerializedState, mt as ValidatePatchResult, pt as TryMergeStateResult, q as JsonValue, r as mergeState, s as deserializeState, t as MergeError, tt as PatchSemantics, ut as TryApplyPatchInPlaceResult, v as applyPatch, w as tryApplyPatch, x as createState } from "./merge-DQ_KDtnE.mjs";
2
+ export { type ActorId, type ApplyError, type ApplyPatchInPlaceOptions, type ApplyPatchOptions, type CrdtState, type DiffOptions, type ForkStateOptions, type JsonPatch, type JsonPatchOp, type JsonPrimitive, type JsonValue, MergeError, type MergeStateOptions, PatchError, type PatchErrorReason, type PatchSemantics, type SerializedState, type TryApplyPatchInPlaceResult, type TryApplyPatchResult, type TryMergeStateResult, type ValidatePatchResult, applyPatch, applyPatchInPlace, createState, deserializeState, diffJsonPatch, forkState, mergeState, serializeState, toJson, tryApplyPatch, tryApplyPatchInPlace, tryMergeState, validateJsonPatch };
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as PatchErrorReason, C as toJson, D as ActorId, E as validateJsonPatch, G as JsonPrimitive, H as JsonPatch, I as CrdtState, K as JsonValue, L as DiffOptions, M as ApplyPatchOptions, O as ApplyError, S as forkState, T as tryApplyPatchInPlace, U as JsonPatchOp, Y as MergeStateOptions, _ as PatchError, a as tryMergeState, b as applyPatchInPlace, ct as SerializedState, et as PatchSemantics, f as diffJsonPatch, ft as TryMergeStateResult, j as ApplyPatchInPlaceOptions, l as serializeState, lt as TryApplyPatchInPlaceResult, pt as ValidatePatchResult, r as mergeState, s as deserializeState, t as MergeError, ut as TryApplyPatchResult, v as applyPatch, w as tryApplyPatch, x as createState } from "./merge-DW1-p9Hj.js";
2
- export { type ActorId, type ApplyError, type ApplyPatchInPlaceOptions, type ApplyPatchOptions, type CrdtState, type DiffOptions, type JsonPatch, type JsonPatchOp, type JsonPrimitive, type JsonValue, MergeError, type MergeStateOptions, PatchError, type PatchErrorReason, type PatchSemantics, type SerializedState, type TryApplyPatchInPlaceResult, type TryApplyPatchResult, type TryMergeStateResult, type ValidatePatchResult, applyPatch, applyPatchInPlace, createState, deserializeState, diffJsonPatch, forkState, mergeState, serializeState, toJson, tryApplyPatch, tryApplyPatchInPlace, tryMergeState, validateJsonPatch };
1
+ import { C as toJson, D as ActorId, E as validateJsonPatch, I as CrdtState, K as JsonPrimitive, L as DiffOptions, M as ApplyPatchOptions, O as ApplyError, S as forkState, T as tryApplyPatchInPlace, U as JsonPatch, V as ForkStateOptions, W as JsonPatchOp, X as MergeStateOptions, _ as PatchError, a as tryMergeState, b as applyPatchInPlace, dt as TryApplyPatchResult, et as PatchErrorReason, f as diffJsonPatch, j as ApplyPatchInPlaceOptions, l as serializeState, lt as SerializedState, mt as ValidatePatchResult, pt as TryMergeStateResult, q as JsonValue, r as mergeState, s as deserializeState, t as MergeError, tt as PatchSemantics, ut as TryApplyPatchInPlaceResult, v as applyPatch, w as tryApplyPatch, x as createState } from "./merge-B8nmGV-o.js";
2
+ export { type ActorId, type ApplyError, type ApplyPatchInPlaceOptions, type ApplyPatchOptions, type CrdtState, type DiffOptions, type ForkStateOptions, type JsonPatch, type JsonPatchOp, type JsonPrimitive, type JsonValue, MergeError, type MergeStateOptions, PatchError, type PatchErrorReason, type PatchSemantics, type SerializedState, type TryApplyPatchInPlaceResult, type TryApplyPatchResult, type TryMergeStateResult, type ValidatePatchResult, applyPatch, applyPatchInPlace, createState, deserializeState, diffJsonPatch, forkState, mergeState, serializeState, toJson, tryApplyPatch, tryApplyPatchInPlace, tryMergeState, validateJsonPatch };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_merge = require('./merge-CtJfKEt1.js');
2
+ const require_merge = require('./merge-BAfuC6bf.js');
3
3
 
4
4
  exports.MergeError = require_merge.MergeError;
5
5
  exports.PatchError = require_merge.PatchError;
package/dist/index.mjs CHANGED
@@ -1,3 +1,3 @@
1
- import { _ as tryApplyPatch, a as tryMergeState, d as applyPatch, g as toJson, h as forkState, j as diffJsonPatch, l as serializeState, m as createState, p as applyPatchInPlace, r as mergeState, s as deserializeState, t as MergeError, u as PatchError, v as tryApplyPatchInPlace, y as validateJsonPatch } from "./merge-BqROEw61.mjs";
1
+ import { _ as tryApplyPatch, a as tryMergeState, d as applyPatch, g as toJson, h as forkState, j as diffJsonPatch, l as serializeState, m as createState, p as applyPatchInPlace, r as mergeState, s as deserializeState, t as MergeError, u as PatchError, v as tryApplyPatchInPlace, y as validateJsonPatch } from "./merge-CKcP1ZPt.mjs";
2
2
 
3
3
  export { MergeError, PatchError, applyPatch, applyPatchInPlace, createState, deserializeState, diffJsonPatch, forkState, mergeState, serializeState, toJson, tryApplyPatch, tryApplyPatchInPlace, tryMergeState, validateJsonPatch };
@@ -1,4 +1,4 @@
1
- import { $ as PatchErrorReason, A as ApplyPatchAsActorResult, B as ElemId, C as toJson, D as ActorId, E as validateJsonPatch, F as CompilePatchOptions, G as JsonPrimitive, H as JsonPatch, I as CrdtState, J as MergeDocOptions, K as JsonValue, L as DiffOptions, M as ApplyPatchOptions, N as ApplyResult, O as ApplyError, P as Clock, Q as ObjNode, R as Doc, S as forkState, T as tryApplyPatchInPlace, U as JsonPatchOp, V as IntentOp, W as JsonPatchToCrdtOptions, X as Node, Y as MergeStateOptions, Z as ObjEntry, _ as PatchError, a as tryMergeState, at as SerializedDoc, b as applyPatchInPlace, c as serializeDoc, ct as SerializedState, d as compileJsonPatchToIntent, dt as TryMergeDocResult, et as PatchSemantics, f as diffJsonPatch, ft as TryMergeStateResult, g as stringifyJsonPointer, h as parseJsonPointer, i as tryMergeDoc, it as SerializedClock, j as ApplyPatchInPlaceOptions, k as ApplyPatchAsActorOptions, l as serializeState, lt as TryApplyPatchInPlaceResult, m as jsonEquals, mt as VersionVector, n as mergeDoc, nt as RgaElem, o as deserializeDoc, ot as SerializedNode, p as getAtJson, pt as ValidatePatchResult, q as LwwReg, r as mergeState, rt as RgaSeq, s as deserializeState, st as SerializedRgaElem, t as MergeError, tt as ROOT_KEY, u as PatchCompileError, ut as TryApplyPatchResult, v as applyPatch, w as tryApplyPatch, x as createState, y as applyPatchAsActor, z as Dot } from "./merge-BrNGGkXj.mjs";
1
+ import { $ as ObjNode, A as ApplyPatchAsActorResult, B as ElemId, C as toJson, D as ActorId, E as validateJsonPatch, F as CompilePatchOptions, G as JsonPatchToCrdtOptions, H as IntentOp, I as CrdtState, J as LwwReg, K as JsonPrimitive, L as DiffOptions, M as ApplyPatchOptions, N as ApplyResult, O as ApplyError, P as Clock, Q as ObjEntry, R as Doc, S as forkState, T as tryApplyPatchInPlace, U as JsonPatch, V as ForkStateOptions, W as JsonPatchOp, X as MergeStateOptions, Y as MergeDocOptions, Z as Node, _ as PatchError, a as tryMergeState, at as SerializedClock, b as applyPatchInPlace, c as serializeDoc, ct as SerializedRgaElem, d as compileJsonPatchToIntent, dt as TryApplyPatchResult, et as PatchErrorReason, f as diffJsonPatch, ft as TryMergeDocResult, g as stringifyJsonPointer, h as parseJsonPointer, ht as VersionVector, i as tryMergeDoc, it as RgaSeq, j as ApplyPatchInPlaceOptions, k as ApplyPatchAsActorOptions, l as serializeState, lt as SerializedState, m as jsonEquals, mt as ValidatePatchResult, n as mergeDoc, nt as ROOT_KEY, o as deserializeDoc, ot as SerializedDoc, p as getAtJson, pt as TryMergeStateResult, q as JsonValue, r as mergeState, rt as RgaElem, s as deserializeState, st as SerializedNode, t as MergeError, tt as PatchSemantics, u as PatchCompileError, ut as TryApplyPatchInPlaceResult, v as applyPatch, w as tryApplyPatch, x as createState, y as applyPatchAsActor, z as Dot } from "./merge-DQ_KDtnE.mjs";
2
2
 
3
3
  //#region src/clock.d.ts
4
4
  /**
@@ -100,4 +100,4 @@ declare function rgaDelete(seq: RgaSeq, id: ElemId): void;
100
100
  declare function rgaIdAtIndex(seq: RgaSeq, index: number): ElemId | undefined;
101
101
  declare function rgaPrevForInsertAtIndex(seq: RgaSeq, index: number): ElemId;
102
102
  //#endregion
103
- export { ActorId, ApplyError, type ApplyPatchAsActorOptions, type ApplyPatchAsActorResult, ApplyPatchInPlaceOptions, ApplyPatchOptions, type ApplyResult, type Clock, type CompilePatchOptions, CrdtState, DiffOptions, type Doc, type Dot, type ElemId, HEAD, type IntentOp, JsonPatch, JsonPatchOp, type JsonPatchToCrdtOptions, JsonPrimitive, JsonValue, type LwwReg, type MergeDocOptions, MergeError, MergeStateOptions, type Node, type ObjEntry, type ObjNode, PatchCompileError, PatchError, PatchErrorReason, PatchSemantics, ROOT_KEY, type RgaElem, type RgaSeq, type SerializedClock, type SerializedDoc, type SerializedNode, type SerializedRgaElem, SerializedState, TryApplyPatchInPlaceResult, TryApplyPatchResult, type TryMergeDocResult, TryMergeStateResult, ValidatePatchResult, type VersionVector, applyIntentsToCrdt, applyPatch, applyPatchAsActor, applyPatchInPlace, cloneClock, cloneDoc, compareDot, compileJsonPatchToIntent, crdtToFullReplace, crdtToJsonPatch, createClock, createState, deserializeDoc, deserializeState, diffJsonPatch, docFromJson, docFromJsonWithDot, dotToElemId, forkState, getAtJson, jsonEquals, jsonPatchToCrdt, jsonPatchToCrdtSafe, lwwSet, materialize, mergeDoc, mergeState, newObj, newReg, newSeq, nextDotForActor, objRemove, objSet, observeDot, parseJsonPointer, rgaDelete, rgaIdAtIndex, rgaInsertAfter, rgaLinearizeIds, rgaPrevForInsertAtIndex, serializeDoc, serializeState, stringifyJsonPointer, toJson, tryApplyPatch, tryApplyPatchInPlace, tryJsonPatchToCrdt, tryMergeDoc, tryMergeState, validateJsonPatch, vvHasDot, vvMerge };
103
+ export { ActorId, ApplyError, type ApplyPatchAsActorOptions, type ApplyPatchAsActorResult, ApplyPatchInPlaceOptions, ApplyPatchOptions, type ApplyResult, type Clock, type CompilePatchOptions, CrdtState, DiffOptions, type Doc, type Dot, type ElemId, ForkStateOptions, HEAD, type IntentOp, JsonPatch, JsonPatchOp, type JsonPatchToCrdtOptions, JsonPrimitive, JsonValue, type LwwReg, type MergeDocOptions, MergeError, MergeStateOptions, type Node, type ObjEntry, type ObjNode, PatchCompileError, PatchError, PatchErrorReason, PatchSemantics, ROOT_KEY, type RgaElem, type RgaSeq, type SerializedClock, type SerializedDoc, type SerializedNode, type SerializedRgaElem, SerializedState, TryApplyPatchInPlaceResult, TryApplyPatchResult, type TryMergeDocResult, TryMergeStateResult, ValidatePatchResult, type VersionVector, applyIntentsToCrdt, applyPatch, applyPatchAsActor, applyPatchInPlace, cloneClock, cloneDoc, compareDot, compileJsonPatchToIntent, crdtToFullReplace, crdtToJsonPatch, createClock, createState, deserializeDoc, deserializeState, diffJsonPatch, docFromJson, docFromJsonWithDot, dotToElemId, forkState, getAtJson, jsonEquals, jsonPatchToCrdt, jsonPatchToCrdtSafe, lwwSet, materialize, mergeDoc, mergeState, newObj, newReg, newSeq, nextDotForActor, objRemove, objSet, observeDot, parseJsonPointer, rgaDelete, rgaIdAtIndex, rgaInsertAfter, rgaLinearizeIds, rgaPrevForInsertAtIndex, serializeDoc, serializeState, stringifyJsonPointer, toJson, tryApplyPatch, tryApplyPatchInPlace, tryJsonPatchToCrdt, tryMergeDoc, tryMergeState, validateJsonPatch, vvHasDot, vvMerge };
@@ -1,4 +1,4 @@
1
- import { $ as PatchErrorReason, A as ApplyPatchAsActorResult, B as ElemId, C as toJson, D as ActorId, E as validateJsonPatch, F as CompilePatchOptions, G as JsonPrimitive, H as JsonPatch, I as CrdtState, J as MergeDocOptions, K as JsonValue, L as DiffOptions, M as ApplyPatchOptions, N as ApplyResult, O as ApplyError, P as Clock, Q as ObjNode, R as Doc, S as forkState, T as tryApplyPatchInPlace, U as JsonPatchOp, V as IntentOp, W as JsonPatchToCrdtOptions, X as Node, Y as MergeStateOptions, Z as ObjEntry, _ as PatchError, a as tryMergeState, at as SerializedDoc, b as applyPatchInPlace, c as serializeDoc, ct as SerializedState, d as compileJsonPatchToIntent, dt as TryMergeDocResult, et as PatchSemantics, f as diffJsonPatch, ft as TryMergeStateResult, g as stringifyJsonPointer, h as parseJsonPointer, i as tryMergeDoc, it as SerializedClock, j as ApplyPatchInPlaceOptions, k as ApplyPatchAsActorOptions, l as serializeState, lt as TryApplyPatchInPlaceResult, m as jsonEquals, mt as VersionVector, n as mergeDoc, nt as RgaElem, o as deserializeDoc, ot as SerializedNode, p as getAtJson, pt as ValidatePatchResult, q as LwwReg, r as mergeState, rt as RgaSeq, s as deserializeState, st as SerializedRgaElem, t as MergeError, tt as ROOT_KEY, u as PatchCompileError, ut as TryApplyPatchResult, v as applyPatch, w as tryApplyPatch, x as createState, y as applyPatchAsActor, z as Dot } from "./merge-DW1-p9Hj.js";
1
+ import { $ as ObjNode, A as ApplyPatchAsActorResult, B as ElemId, C as toJson, D as ActorId, E as validateJsonPatch, F as CompilePatchOptions, G as JsonPatchToCrdtOptions, H as IntentOp, I as CrdtState, J as LwwReg, K as JsonPrimitive, L as DiffOptions, M as ApplyPatchOptions, N as ApplyResult, O as ApplyError, P as Clock, Q as ObjEntry, R as Doc, S as forkState, T as tryApplyPatchInPlace, U as JsonPatch, V as ForkStateOptions, W as JsonPatchOp, X as MergeStateOptions, Y as MergeDocOptions, Z as Node, _ as PatchError, a as tryMergeState, at as SerializedClock, b as applyPatchInPlace, c as serializeDoc, ct as SerializedRgaElem, d as compileJsonPatchToIntent, dt as TryApplyPatchResult, et as PatchErrorReason, f as diffJsonPatch, ft as TryMergeDocResult, g as stringifyJsonPointer, h as parseJsonPointer, ht as VersionVector, i as tryMergeDoc, it as RgaSeq, j as ApplyPatchInPlaceOptions, k as ApplyPatchAsActorOptions, l as serializeState, lt as SerializedState, m as jsonEquals, mt as ValidatePatchResult, n as mergeDoc, nt as ROOT_KEY, o as deserializeDoc, ot as SerializedDoc, p as getAtJson, pt as TryMergeStateResult, q as JsonValue, r as mergeState, rt as RgaElem, s as deserializeState, st as SerializedNode, t as MergeError, tt as PatchSemantics, u as PatchCompileError, ut as TryApplyPatchInPlaceResult, v as applyPatch, w as tryApplyPatch, x as createState, y as applyPatchAsActor, z as Dot } from "./merge-B8nmGV-o.js";
2
2
 
3
3
  //#region src/clock.d.ts
4
4
  /**
@@ -100,4 +100,4 @@ declare function rgaDelete(seq: RgaSeq, id: ElemId): void;
100
100
  declare function rgaIdAtIndex(seq: RgaSeq, index: number): ElemId | undefined;
101
101
  declare function rgaPrevForInsertAtIndex(seq: RgaSeq, index: number): ElemId;
102
102
  //#endregion
103
- export { ActorId, ApplyError, type ApplyPatchAsActorOptions, type ApplyPatchAsActorResult, ApplyPatchInPlaceOptions, ApplyPatchOptions, type ApplyResult, type Clock, type CompilePatchOptions, CrdtState, DiffOptions, type Doc, type Dot, type ElemId, HEAD, type IntentOp, JsonPatch, JsonPatchOp, type JsonPatchToCrdtOptions, JsonPrimitive, JsonValue, type LwwReg, type MergeDocOptions, MergeError, MergeStateOptions, type Node, type ObjEntry, type ObjNode, PatchCompileError, PatchError, PatchErrorReason, PatchSemantics, ROOT_KEY, type RgaElem, type RgaSeq, type SerializedClock, type SerializedDoc, type SerializedNode, type SerializedRgaElem, SerializedState, TryApplyPatchInPlaceResult, TryApplyPatchResult, type TryMergeDocResult, TryMergeStateResult, ValidatePatchResult, type VersionVector, applyIntentsToCrdt, applyPatch, applyPatchAsActor, applyPatchInPlace, cloneClock, cloneDoc, compareDot, compileJsonPatchToIntent, crdtToFullReplace, crdtToJsonPatch, createClock, createState, deserializeDoc, deserializeState, diffJsonPatch, docFromJson, docFromJsonWithDot, dotToElemId, forkState, getAtJson, jsonEquals, jsonPatchToCrdt, jsonPatchToCrdtSafe, lwwSet, materialize, mergeDoc, mergeState, newObj, newReg, newSeq, nextDotForActor, objRemove, objSet, observeDot, parseJsonPointer, rgaDelete, rgaIdAtIndex, rgaInsertAfter, rgaLinearizeIds, rgaPrevForInsertAtIndex, serializeDoc, serializeState, stringifyJsonPointer, toJson, tryApplyPatch, tryApplyPatchInPlace, tryJsonPatchToCrdt, tryMergeDoc, tryMergeState, validateJsonPatch, vvHasDot, vvMerge };
103
+ export { ActorId, ApplyError, type ApplyPatchAsActorOptions, type ApplyPatchAsActorResult, ApplyPatchInPlaceOptions, ApplyPatchOptions, type ApplyResult, type Clock, type CompilePatchOptions, CrdtState, DiffOptions, type Doc, type Dot, type ElemId, ForkStateOptions, HEAD, type IntentOp, JsonPatch, JsonPatchOp, type JsonPatchToCrdtOptions, JsonPrimitive, JsonValue, type LwwReg, type MergeDocOptions, MergeError, MergeStateOptions, type Node, type ObjEntry, type ObjNode, PatchCompileError, PatchError, PatchErrorReason, PatchSemantics, ROOT_KEY, type RgaElem, type RgaSeq, type SerializedClock, type SerializedDoc, type SerializedNode, type SerializedRgaElem, SerializedState, TryApplyPatchInPlaceResult, TryApplyPatchResult, type TryMergeDocResult, TryMergeStateResult, ValidatePatchResult, type VersionVector, applyIntentsToCrdt, applyPatch, applyPatchAsActor, applyPatchInPlace, cloneClock, cloneDoc, compareDot, compileJsonPatchToIntent, crdtToFullReplace, crdtToJsonPatch, createClock, createState, deserializeDoc, deserializeState, diffJsonPatch, docFromJson, docFromJsonWithDot, dotToElemId, forkState, getAtJson, jsonEquals, jsonPatchToCrdt, jsonPatchToCrdtSafe, lwwSet, materialize, mergeDoc, mergeState, newObj, newReg, newSeq, nextDotForActor, objRemove, objSet, observeDot, parseJsonPointer, rgaDelete, rgaIdAtIndex, rgaInsertAfter, rgaLinearizeIds, rgaPrevForInsertAtIndex, serializeDoc, serializeState, stringifyJsonPointer, toJson, tryApplyPatch, tryApplyPatchInPlace, tryJsonPatchToCrdt, tryMergeDoc, tryMergeState, validateJsonPatch, vvHasDot, vvMerge };
package/dist/internals.js CHANGED
@@ -1,5 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
- const require_merge = require('./merge-CtJfKEt1.js');
2
+ const require_merge = require('./merge-BAfuC6bf.js');
3
3
 
4
4
  exports.HEAD = require_merge.HEAD;
5
5
  exports.MergeError = require_merge.MergeError;
@@ -1,3 +1,3 @@
1
- import { $ as vvMerge, A as compileJsonPatchToIntent, B as newSeq, C as crdtToJsonPatch, D as jsonPatchToCrdtSafe, E as jsonPatchToCrdt, F as stringifyJsonPointer, G as rgaDelete, H as objSet, I as ROOT_KEY, J as rgaLinearizeIds, K as rgaIdAtIndex, L as lwwSet, M as getAtJson, N as jsonEquals, O as tryJsonPatchToCrdt, P as parseJsonPointer, Q as vvHasDot, R as newObj, S as crdtToFullReplace, T as docFromJsonWithDot, U as materialize, V as objRemove, W as HEAD, X as compareDot, Y as rgaPrevForInsertAtIndex, Z as dotToElemId, _ as tryApplyPatch, a as tryMergeState, b as applyIntentsToCrdt, c as serializeDoc, d as applyPatch, et as cloneClock, f as applyPatchAsActor, g as toJson, h as forkState, i as tryMergeDoc, j as diffJsonPatch, k as PatchCompileError, l as serializeState, m as createState, n as mergeDoc, nt as nextDotForActor, o as deserializeDoc, p as applyPatchInPlace, q as rgaInsertAfter, r as mergeState, rt as observeDot, s as deserializeState, t as MergeError, tt as createClock, u as PatchError, v as tryApplyPatchInPlace, w as docFromJson, x as cloneDoc, y as validateJsonPatch, z as newReg } from "./merge-BqROEw61.mjs";
1
+ import { $ as vvMerge, A as compileJsonPatchToIntent, B as newSeq, C as crdtToJsonPatch, D as jsonPatchToCrdtSafe, E as jsonPatchToCrdt, F as stringifyJsonPointer, G as rgaDelete, H as objSet, I as ROOT_KEY, J as rgaLinearizeIds, K as rgaIdAtIndex, L as lwwSet, M as getAtJson, N as jsonEquals, O as tryJsonPatchToCrdt, P as parseJsonPointer, Q as vvHasDot, R as newObj, S as crdtToFullReplace, T as docFromJsonWithDot, U as materialize, V as objRemove, W as HEAD, X as compareDot, Y as rgaPrevForInsertAtIndex, Z as dotToElemId, _ as tryApplyPatch, a as tryMergeState, b as applyIntentsToCrdt, c as serializeDoc, d as applyPatch, et as cloneClock, f as applyPatchAsActor, g as toJson, h as forkState, i as tryMergeDoc, j as diffJsonPatch, k as PatchCompileError, l as serializeState, m as createState, n as mergeDoc, nt as nextDotForActor, o as deserializeDoc, p as applyPatchInPlace, q as rgaInsertAfter, r as mergeState, rt as observeDot, s as deserializeState, t as MergeError, tt as createClock, u as PatchError, v as tryApplyPatchInPlace, w as docFromJson, x as cloneDoc, y as validateJsonPatch, z as newReg } from "./merge-CKcP1ZPt.mjs";
2
2
 
3
3
  export { HEAD, MergeError, PatchCompileError, PatchError, ROOT_KEY, applyIntentsToCrdt, applyPatch, applyPatchAsActor, applyPatchInPlace, cloneClock, cloneDoc, compareDot, compileJsonPatchToIntent, crdtToFullReplace, crdtToJsonPatch, createClock, createState, deserializeDoc, deserializeState, diffJsonPatch, docFromJson, docFromJsonWithDot, dotToElemId, forkState, getAtJson, jsonEquals, jsonPatchToCrdt, jsonPatchToCrdtSafe, lwwSet, materialize, mergeDoc, mergeState, newObj, newReg, newSeq, nextDotForActor, objRemove, objSet, observeDot, parseJsonPointer, rgaDelete, rgaIdAtIndex, rgaInsertAfter, rgaLinearizeIds, rgaPrevForInsertAtIndex, serializeDoc, serializeState, stringifyJsonPointer, toJson, tryApplyPatch, tryApplyPatchInPlace, tryJsonPatchToCrdt, tryMergeDoc, tryMergeState, validateJsonPatch, vvHasDot, vvMerge };
@@ -161,6 +161,14 @@ type CrdtState = {
161
161
  doc: Doc;
162
162
  clock: Clock;
163
163
  };
164
+ /** Options for `forkState`. */
165
+ interface ForkStateOptions {
166
+ /**
167
+ * Allow reusing the origin actor ID when forking.
168
+ * Defaults to `false` to prevent duplicate-dot collisions across replicas.
169
+ */
170
+ allowActorReuse?: boolean;
171
+ }
164
172
  /** Result from applying a patch for a specific actor using a shared version vector. */
165
173
  type ApplyPatchAsActorResult = {
166
174
  /** Updated CRDT state for the actor that produced this patch. */state: CrdtState; /** Updated version vector after applying the patch. */
@@ -310,8 +318,9 @@ declare function createState(initial: JsonValue, options: {
310
318
  /**
311
319
  * Fork a replica from a shared origin state while assigning a new local actor ID.
312
320
  * The forked state has an independent document clone and clock.
321
+ * By default this rejects actor reuse to prevent duplicate-dot collisions across peers.
313
322
  */
314
- declare function forkState(origin: CrdtState, actor: ActorId): CrdtState;
323
+ declare function forkState(origin: CrdtState, actor: ActorId, options?: ForkStateOptions): CrdtState;
315
324
  /**
316
325
  * Materialize a CRDT document or state back to a plain JSON value.
317
326
  * @param target - A `Doc` or `CrdtState` to materialize.
@@ -442,4 +451,4 @@ declare function mergeState(a: CrdtState, b: CrdtState, options?: MergeStateOpti
442
451
  /** Non-throwing `mergeState` variant with structured conflict details. */
443
452
  declare function tryMergeState(a: CrdtState, b: CrdtState, options?: MergeStateOptions): TryMergeStateResult;
444
453
  //#endregion
445
- export { PatchErrorReason as $, ApplyPatchAsActorResult as A, ElemId as B, toJson as C, ActorId as D, validateJsonPatch as E, CompilePatchOptions as F, JsonPrimitive as G, JsonPatch as H, CrdtState as I, MergeDocOptions as J, JsonValue as K, DiffOptions as L, ApplyPatchOptions as M, ApplyResult as N, ApplyError as O, Clock as P, ObjNode as Q, Doc as R, forkState as S, tryApplyPatchInPlace as T, JsonPatchOp as U, IntentOp as V, JsonPatchToCrdtOptions as W, Node as X, MergeStateOptions as Y, ObjEntry as Z, PatchError as _, tryMergeState as a, SerializedDoc as at, applyPatchInPlace as b, serializeDoc as c, SerializedState as ct, compileJsonPatchToIntent as d, TryMergeDocResult as dt, PatchSemantics as et, diffJsonPatch as f, TryMergeStateResult as ft, stringifyJsonPointer as g, parseJsonPointer as h, tryMergeDoc as i, SerializedClock as it, ApplyPatchInPlaceOptions as j, ApplyPatchAsActorOptions as k, serializeState as l, TryApplyPatchInPlaceResult as lt, jsonEquals as m, VersionVector as mt, mergeDoc as n, RgaElem as nt, deserializeDoc as o, SerializedNode as ot, getAtJson as p, ValidatePatchResult as pt, LwwReg as q, mergeState as r, RgaSeq as rt, deserializeState as s, SerializedRgaElem as st, MergeError as t, ROOT_KEY as tt, PatchCompileError as u, TryApplyPatchResult as ut, applyPatch as v, tryApplyPatch as w, createState as x, applyPatchAsActor as y, Dot as z };
454
+ export { ObjNode as $, ApplyPatchAsActorResult as A, ElemId as B, toJson as C, ActorId as D, validateJsonPatch as E, CompilePatchOptions as F, JsonPatchToCrdtOptions as G, IntentOp as H, CrdtState as I, LwwReg as J, JsonPrimitive as K, DiffOptions as L, ApplyPatchOptions as M, ApplyResult as N, ApplyError as O, Clock as P, ObjEntry as Q, Doc as R, forkState as S, tryApplyPatchInPlace as T, JsonPatch as U, ForkStateOptions as V, JsonPatchOp as W, MergeStateOptions as X, MergeDocOptions as Y, Node as Z, PatchError as _, tryMergeState as a, SerializedClock as at, applyPatchInPlace as b, serializeDoc as c, SerializedRgaElem as ct, compileJsonPatchToIntent as d, TryApplyPatchResult as dt, PatchErrorReason as et, diffJsonPatch as f, TryMergeDocResult as ft, stringifyJsonPointer as g, parseJsonPointer as h, VersionVector as ht, tryMergeDoc as i, RgaSeq as it, ApplyPatchInPlaceOptions as j, ApplyPatchAsActorOptions as k, serializeState as l, SerializedState as lt, jsonEquals as m, ValidatePatchResult as mt, mergeDoc as n, ROOT_KEY as nt, deserializeDoc as o, SerializedDoc as ot, getAtJson as p, TryMergeStateResult as pt, JsonValue as q, mergeState as r, RgaElem as rt, deserializeState as s, SerializedNode as st, MergeError as t, PatchSemantics as tt, PatchCompileError as u, TryApplyPatchInPlaceResult as ut, applyPatch as v, tryApplyPatch as w, createState as x, applyPatchAsActor as y, Dot as z };
@@ -216,13 +216,37 @@ var PatchCompileError = class extends Error {
216
216
  function parseJsonPointer(ptr) {
217
217
  if (ptr === "") return [];
218
218
  if (!ptr.startsWith("/")) throw new Error(`Invalid pointer: ${ptr}`);
219
- return ptr.slice(1).split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
219
+ return ptr.slice(1).split("/").map(unescapeJsonPointerToken);
220
220
  }
221
221
  /** Convert a path array back to an RFC 6901 JSON Pointer string. */
222
222
  function stringifyJsonPointer(path) {
223
223
  if (path.length === 0) return "";
224
224
  return `/${path.map(escapeJsonPointer).join("/")}`;
225
225
  }
226
+ function unescapeJsonPointerToken(token) {
227
+ let out = "";
228
+ for (let i = 0; i < token.length; i++) {
229
+ const ch = token[i];
230
+ if (ch !== "~") {
231
+ out += ch;
232
+ continue;
233
+ }
234
+ const esc = token[i + 1];
235
+ if (esc === "0") {
236
+ out += "~";
237
+ i += 1;
238
+ continue;
239
+ }
240
+ if (esc === "1") {
241
+ out += "/";
242
+ i += 1;
243
+ continue;
244
+ }
245
+ const sequence = esc === void 0 ? "~" : `~${esc}`;
246
+ throw new Error(`Invalid pointer escape sequence '${sequence}'`);
247
+ }
248
+ return out;
249
+ }
226
250
  /**
227
251
  * Navigate a JSON value by path and return the value at that location.
228
252
  * Throws if the path is invalid, out of bounds, or traverses a non-container.
@@ -230,8 +254,8 @@ function stringifyJsonPointer(path) {
230
254
  function getAtJson(base, path) {
231
255
  let cur = base;
232
256
  for (const seg of path) if (Array.isArray(cur)) {
233
- const idx = seg === "-" ? cur.length : Number(seg);
234
- if (!Number.isInteger(idx)) throw new Error(`Expected array index, got ${seg}`);
257
+ if (!ARRAY_INDEX_TOKEN_PATTERN.test(seg)) throw new Error(`Expected array index, got ${seg}`);
258
+ const idx = Number(seg);
235
259
  if (idx < 0 || idx >= cur.length) throw new Error(`Index out of bounds at ${seg}`);
236
260
  cur = cur[idx];
237
261
  } else if (cur && typeof cur === "object") {
@@ -255,7 +279,7 @@ function compileJsonPatchToIntent(baseJson, patch, options = {}) {
255
279
  for (let opIndex = 0; opIndex < patch.length; opIndex++) {
256
280
  const op = patch[opIndex];
257
281
  const compileBase = semantics === "sequential" ? workingBase : baseJson;
258
- intents.push(...compileSingleOp(compileBase, op, opIndex));
282
+ intents.push(...compileSingleOp(compileBase, op, opIndex, semantics));
259
283
  if (semantics === "sequential") workingBase = applyPatchOpToJson(workingBase, op, opIndex);
260
284
  }
261
285
  return intents;
@@ -398,6 +422,7 @@ function jsonEquals(a, b) {
398
422
  function isPlainObject(value) {
399
423
  return typeof value === "object" && value !== null && !Array.isArray(value);
400
424
  }
425
+ const ARRAY_INDEX_TOKEN_PATTERN = /^(0|[1-9][0-9]*)$/;
401
426
  function hasOwn(value, key) {
402
427
  return Object.prototype.hasOwnProperty.call(value, key);
403
428
  }
@@ -408,7 +433,7 @@ function pathValueAt(base, path) {
408
433
  function assertNever$1(_value, message) {
409
434
  throw new Error(message);
410
435
  }
411
- function compileSingleOp(baseJson, op, opIndex) {
436
+ function compileSingleOp(baseJson, op, opIndex, semantics) {
412
437
  if (op.op === "test") return [{
413
438
  t: "Test",
414
439
  path: parsePointerOrThrow(op.path, op.path, opIndex),
@@ -419,15 +444,29 @@ function compileSingleOp(baseJson, op, opIndex) {
419
444
  const toPath = parsePointerOrThrow(op.path, op.path, opIndex);
420
445
  if (op.op === "move" && isStrictDescendantPath(fromPath, toPath)) throw compileError("INVALID_MOVE", `cannot move a value into one of its descendants at ${op.path}`, op.path, opIndex);
421
446
  const val = lookupValueOrThrow(baseJson, fromPath, op.from, opIndex);
447
+ if (op.op === "move" && isSamePath(fromPath, toPath)) return [];
448
+ if (op.op === "move" && semantics === "sequential") {
449
+ const removeOp = {
450
+ op: "remove",
451
+ path: op.from
452
+ };
453
+ const addOp = {
454
+ op: "add",
455
+ path: op.path,
456
+ value: val
457
+ };
458
+ const baseAfterRemove = applyPatchOpToJson(baseJson, removeOp, opIndex);
459
+ return [...compileSingleOp(baseJson, removeOp, opIndex, semantics), ...compileSingleOp(baseAfterRemove, addOp, opIndex, semantics)];
460
+ }
422
461
  const out = compileSingleOp(baseJson, {
423
462
  op: "add",
424
463
  path: op.path,
425
464
  value: val
426
- }, opIndex);
465
+ }, opIndex, semantics);
427
466
  if (op.op === "move") out.push(...compileSingleOp(baseJson, {
428
467
  op: "remove",
429
468
  path: op.from
430
- }, opIndex));
469
+ }, opIndex, semantics));
431
470
  return out;
432
471
  }
433
472
  const path = parsePointerOrThrow(op.path, op.path, opIndex);
@@ -563,7 +602,7 @@ function parseArrayIndexToken(token, op, arrLength, path, opIndex) {
563
602
  if (op !== "add") throw compileError("INVALID_POINTER", `'-' index is only valid for add at ${path}`, path, opIndex);
564
603
  return Number.POSITIVE_INFINITY;
565
604
  }
566
- if (!/^[0-9]+$/.test(token)) throw compileError("INVALID_POINTER", `expected array index at ${path}`, path, opIndex);
605
+ if (!ARRAY_INDEX_TOKEN_PATTERN.test(token)) throw compileError("INVALID_POINTER", `expected array index at ${path}`, path, opIndex);
567
606
  const index = Number(token);
568
607
  if (!Number.isSafeInteger(index)) throw compileError("OUT_OF_BOUNDS", `array index is too large at ${path}`, path, opIndex);
569
608
  if (op === "add") {
@@ -572,12 +611,31 @@ function parseArrayIndexToken(token, op, arrLength, path, opIndex) {
572
611
  return index;
573
612
  }
574
613
  function compileErrorFromLookup(error, path, opIndex) {
614
+ const mapped = mapLookupErrorToPatchReason(error);
615
+ return compileError(mapped.reason, mapped.message, path, opIndex);
616
+ }
617
+ function mapLookupErrorToPatchReason(error) {
575
618
  const message = error instanceof Error ? error.message : "invalid path";
576
- if (message.includes("Expected array index")) return compileError("INVALID_POINTER", message, path, opIndex);
577
- if (message.includes("Index out of bounds")) return compileError("OUT_OF_BOUNDS", message, path, opIndex);
578
- if (message.includes("Missing key")) return compileError("MISSING_PARENT", message, path, opIndex);
579
- if (message.includes("Cannot traverse into non-container")) return compileError("INVALID_TARGET", message, path, opIndex);
580
- return compileError("INVALID_PATCH", message, path, opIndex);
619
+ if (message.includes("Expected array index")) return {
620
+ reason: "INVALID_POINTER",
621
+ message
622
+ };
623
+ if (message.includes("Index out of bounds")) return {
624
+ reason: "OUT_OF_BOUNDS",
625
+ message
626
+ };
627
+ if (message.includes("Missing key")) return {
628
+ reason: "MISSING_PARENT",
629
+ message
630
+ };
631
+ if (message.includes("Cannot traverse into non-container")) return {
632
+ reason: "INVALID_TARGET",
633
+ message
634
+ };
635
+ return {
636
+ reason: "INVALID_PATCH",
637
+ message
638
+ };
581
639
  }
582
640
  function compileError(reason, message, path, opIndex) {
583
641
  return new PatchCompileError(reason, message, path, opIndex);
@@ -587,6 +645,11 @@ function isStrictDescendantPath(from, to) {
587
645
  for (let i = 0; i < from.length; i++) if (from[i] !== to[i]) return false;
588
646
  return true;
589
647
  }
648
+ function isSamePath(a, b) {
649
+ if (a.length !== b.length) return false;
650
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
651
+ return true;
652
+ }
590
653
 
591
654
  //#endregion
592
655
  //#region src/doc.ts
@@ -1057,8 +1120,7 @@ function jsonPatchToCrdtInternal(options) {
1057
1120
  const shadowBump = (ctr) => {
1058
1121
  if (shadowCtr < ctr) shadowCtr = ctr;
1059
1122
  };
1060
- for (let opIndex = 0; opIndex < options.patch.length; opIndex++) {
1061
- const op = options.patch[opIndex];
1123
+ const applySequentialOp = (op, opIndex) => {
1062
1124
  const baseJson = materialize(shadowBase.root);
1063
1125
  let intents;
1064
1126
  try {
@@ -1072,6 +1134,42 @@ function jsonPatchToCrdtInternal(options) {
1072
1134
  const shadowStep = applyIntentsToCrdt(shadowBase, shadowBase, intents, shadowDot, "base", shadowBump);
1073
1135
  if (!shadowStep.ok) return withOpIndex(shadowStep, opIndex);
1074
1136
  } else shadowBase = cloneDoc(options.head);
1137
+ return { ok: true };
1138
+ };
1139
+ for (let opIndex = 0; opIndex < options.patch.length; opIndex++) {
1140
+ const op = options.patch[opIndex];
1141
+ if (op.op === "move") {
1142
+ const baseJson = materialize(shadowBase.root);
1143
+ let fromValue;
1144
+ try {
1145
+ fromValue = structuredClone(getAtJson(baseJson, parseJsonPointer(op.from)));
1146
+ } catch {
1147
+ try {
1148
+ compileJsonPatchToIntent(baseJson, [{
1149
+ op: "remove",
1150
+ path: op.from
1151
+ }], { semantics: "sequential" });
1152
+ } catch (error) {
1153
+ return withOpIndex(toApplyError$1(error), opIndex);
1154
+ }
1155
+ return withOpIndex(toApplyError$1(/* @__PURE__ */ new Error(`failed to resolve move source at ${op.from}`)), opIndex);
1156
+ }
1157
+ if (op.from === op.path) continue;
1158
+ const removeStep = applySequentialOp({
1159
+ op: "remove",
1160
+ path: op.from
1161
+ }, opIndex);
1162
+ if (!removeStep.ok) return removeStep;
1163
+ const addStep = applySequentialOp({
1164
+ op: "add",
1165
+ path: op.path,
1166
+ value: fromValue
1167
+ }, opIndex);
1168
+ if (!addStep.ok) return addStep;
1169
+ continue;
1170
+ }
1171
+ const step = applySequentialOp(op, opIndex);
1172
+ if (!step.ok) return step;
1075
1173
  }
1076
1174
  return { ok: true };
1077
1175
  }
@@ -1143,8 +1241,10 @@ function createState(initial, options) {
1143
1241
  /**
1144
1242
  * Fork a replica from a shared origin state while assigning a new local actor ID.
1145
1243
  * The forked state has an independent document clone and clock.
1244
+ * By default this rejects actor reuse to prevent duplicate-dot collisions across peers.
1146
1245
  */
1147
- function forkState(origin, actor) {
1246
+ function forkState(origin, actor, options = {}) {
1247
+ if (actor === origin.clock.actor && !options.allowActorReuse) throw new Error(`forkState actor must be unique; refusing to reuse origin actor '${actor}'`);
1148
1248
  return {
1149
1249
  doc: cloneDoc(origin.doc),
1150
1250
  clock: createClock(actor, origin.clock.ctr)
@@ -1262,8 +1362,8 @@ function applyPatchInternal(state, patch, options) {
1262
1362
  doc: cloneDoc(options.base.doc),
1263
1363
  clock: createClock("__base__", 0)
1264
1364
  } : null;
1265
- for (const op of patch) {
1266
- const step = applyPatchOpSequential(state, op, options, explicitBaseState ? explicitBaseState.doc : cloneDoc(state.doc));
1365
+ for (const [opIndex, op] of patch.entries()) {
1366
+ const step = applyPatchOpSequential(state, op, options, explicitBaseState ? explicitBaseState.doc : cloneDoc(state.doc), opIndex);
1267
1367
  if (!step.ok) return step;
1268
1368
  if (explicitBaseState && op.op !== "test") {
1269
1369
  const baseStep = applyPatchInternal(explicitBaseState, [op], {
@@ -1280,10 +1380,12 @@ function applyPatchInternal(state, patch, options) {
1280
1380
  if (!compiled.ok) return compiled;
1281
1381
  return applyIntentsToCrdt(baseDoc, state.doc, compiled.intents, () => state.clock.next(), options.testAgainst ?? "head", (ctr) => bumpClockCounter(state, ctr));
1282
1382
  }
1283
- function applyPatchOpSequential(state, op, options, baseDoc) {
1383
+ function applyPatchOpSequential(state, op, options, baseDoc, opIndex) {
1284
1384
  const baseJson = materialize(baseDoc.root);
1285
1385
  if (op.op === "move") {
1286
- const fromValue = getAtJson(baseJson, parseJsonPointer(op.from));
1386
+ const fromResolved = resolveValueAtPointer(baseJson, op.from, opIndex);
1387
+ if (!fromResolved.ok) return fromResolved;
1388
+ const fromValue = fromResolved.value;
1287
1389
  const removeRes = applySinglePatchOp(state, baseDoc, {
1288
1390
  op: "remove",
1289
1391
  path: op.from
@@ -1296,7 +1398,9 @@ function applyPatchOpSequential(state, op, options, baseDoc) {
1296
1398
  }, options);
1297
1399
  }
1298
1400
  if (op.op === "copy") {
1299
- const fromValue = getAtJson(baseJson, parseJsonPointer(op.from));
1401
+ const fromResolved = resolveValueAtPointer(baseJson, op.from, opIndex);
1402
+ if (!fromResolved.ok) return fromResolved;
1403
+ const fromValue = fromResolved.value;
1300
1404
  return applySinglePatchOp(state, baseDoc, {
1301
1405
  op: "add",
1302
1406
  path: op.path,
@@ -1305,6 +1409,22 @@ function applyPatchOpSequential(state, op, options, baseDoc) {
1305
1409
  }
1306
1410
  return applySinglePatchOp(state, baseDoc, op, options);
1307
1411
  }
1412
+ function resolveValueAtPointer(baseJson, pointer, opIndex) {
1413
+ let path;
1414
+ try {
1415
+ path = parseJsonPointer(pointer);
1416
+ } catch (error) {
1417
+ return toPointerParseApplyError(error, pointer, opIndex);
1418
+ }
1419
+ try {
1420
+ return {
1421
+ ok: true,
1422
+ value: getAtJson(baseJson, path)
1423
+ };
1424
+ } catch (error) {
1425
+ return toPointerLookupApplyError(error, pointer, opIndex);
1426
+ }
1427
+ }
1308
1428
  function applySinglePatchOp(state, baseDoc, op, options) {
1309
1429
  const compiled = compileIntents(materialize(baseDoc.root), [op], "sequential");
1310
1430
  if (!compiled.ok) return compiled;
@@ -1363,6 +1483,27 @@ function toApplyError(error) {
1363
1483
  message: error instanceof Error ? error.message : "failed to compile patch"
1364
1484
  };
1365
1485
  }
1486
+ function toPointerParseApplyError(error, pointer, opIndex) {
1487
+ return {
1488
+ ok: false,
1489
+ code: 409,
1490
+ reason: "INVALID_POINTER",
1491
+ message: error instanceof Error ? error.message : "invalid pointer",
1492
+ path: pointer,
1493
+ opIndex
1494
+ };
1495
+ }
1496
+ function toPointerLookupApplyError(error, pointer, opIndex) {
1497
+ const mapped = mapLookupErrorToPatchReason(error);
1498
+ return {
1499
+ ok: false,
1500
+ code: 409,
1501
+ reason: mapped.reason,
1502
+ message: mapped.message,
1503
+ path: pointer,
1504
+ opIndex
1505
+ };
1506
+ }
1366
1507
 
1367
1508
  //#endregion
1368
1509
  //#region src/serialize.ts
@@ -215,13 +215,37 @@ var PatchCompileError = class extends Error {
215
215
  function parseJsonPointer(ptr) {
216
216
  if (ptr === "") return [];
217
217
  if (!ptr.startsWith("/")) throw new Error(`Invalid pointer: ${ptr}`);
218
- return ptr.slice(1).split("/").map((s) => s.replace(/~1/g, "/").replace(/~0/g, "~"));
218
+ return ptr.slice(1).split("/").map(unescapeJsonPointerToken);
219
219
  }
220
220
  /** Convert a path array back to an RFC 6901 JSON Pointer string. */
221
221
  function stringifyJsonPointer(path) {
222
222
  if (path.length === 0) return "";
223
223
  return `/${path.map(escapeJsonPointer).join("/")}`;
224
224
  }
225
+ function unescapeJsonPointerToken(token) {
226
+ let out = "";
227
+ for (let i = 0; i < token.length; i++) {
228
+ const ch = token[i];
229
+ if (ch !== "~") {
230
+ out += ch;
231
+ continue;
232
+ }
233
+ const esc = token[i + 1];
234
+ if (esc === "0") {
235
+ out += "~";
236
+ i += 1;
237
+ continue;
238
+ }
239
+ if (esc === "1") {
240
+ out += "/";
241
+ i += 1;
242
+ continue;
243
+ }
244
+ const sequence = esc === void 0 ? "~" : `~${esc}`;
245
+ throw new Error(`Invalid pointer escape sequence '${sequence}'`);
246
+ }
247
+ return out;
248
+ }
225
249
  /**
226
250
  * Navigate a JSON value by path and return the value at that location.
227
251
  * Throws if the path is invalid, out of bounds, or traverses a non-container.
@@ -229,8 +253,8 @@ function stringifyJsonPointer(path) {
229
253
  function getAtJson(base, path) {
230
254
  let cur = base;
231
255
  for (const seg of path) if (Array.isArray(cur)) {
232
- const idx = seg === "-" ? cur.length : Number(seg);
233
- if (!Number.isInteger(idx)) throw new Error(`Expected array index, got ${seg}`);
256
+ if (!ARRAY_INDEX_TOKEN_PATTERN.test(seg)) throw new Error(`Expected array index, got ${seg}`);
257
+ const idx = Number(seg);
234
258
  if (idx < 0 || idx >= cur.length) throw new Error(`Index out of bounds at ${seg}`);
235
259
  cur = cur[idx];
236
260
  } else if (cur && typeof cur === "object") {
@@ -254,7 +278,7 @@ function compileJsonPatchToIntent(baseJson, patch, options = {}) {
254
278
  for (let opIndex = 0; opIndex < patch.length; opIndex++) {
255
279
  const op = patch[opIndex];
256
280
  const compileBase = semantics === "sequential" ? workingBase : baseJson;
257
- intents.push(...compileSingleOp(compileBase, op, opIndex));
281
+ intents.push(...compileSingleOp(compileBase, op, opIndex, semantics));
258
282
  if (semantics === "sequential") workingBase = applyPatchOpToJson(workingBase, op, opIndex);
259
283
  }
260
284
  return intents;
@@ -397,6 +421,7 @@ function jsonEquals(a, b) {
397
421
  function isPlainObject(value) {
398
422
  return typeof value === "object" && value !== null && !Array.isArray(value);
399
423
  }
424
+ const ARRAY_INDEX_TOKEN_PATTERN = /^(0|[1-9][0-9]*)$/;
400
425
  function hasOwn(value, key) {
401
426
  return Object.prototype.hasOwnProperty.call(value, key);
402
427
  }
@@ -407,7 +432,7 @@ function pathValueAt(base, path) {
407
432
  function assertNever$1(_value, message) {
408
433
  throw new Error(message);
409
434
  }
410
- function compileSingleOp(baseJson, op, opIndex) {
435
+ function compileSingleOp(baseJson, op, opIndex, semantics) {
411
436
  if (op.op === "test") return [{
412
437
  t: "Test",
413
438
  path: parsePointerOrThrow(op.path, op.path, opIndex),
@@ -418,15 +443,29 @@ function compileSingleOp(baseJson, op, opIndex) {
418
443
  const toPath = parsePointerOrThrow(op.path, op.path, opIndex);
419
444
  if (op.op === "move" && isStrictDescendantPath(fromPath, toPath)) throw compileError("INVALID_MOVE", `cannot move a value into one of its descendants at ${op.path}`, op.path, opIndex);
420
445
  const val = lookupValueOrThrow(baseJson, fromPath, op.from, opIndex);
446
+ if (op.op === "move" && isSamePath(fromPath, toPath)) return [];
447
+ if (op.op === "move" && semantics === "sequential") {
448
+ const removeOp = {
449
+ op: "remove",
450
+ path: op.from
451
+ };
452
+ const addOp = {
453
+ op: "add",
454
+ path: op.path,
455
+ value: val
456
+ };
457
+ const baseAfterRemove = applyPatchOpToJson(baseJson, removeOp, opIndex);
458
+ return [...compileSingleOp(baseJson, removeOp, opIndex, semantics), ...compileSingleOp(baseAfterRemove, addOp, opIndex, semantics)];
459
+ }
421
460
  const out = compileSingleOp(baseJson, {
422
461
  op: "add",
423
462
  path: op.path,
424
463
  value: val
425
- }, opIndex);
464
+ }, opIndex, semantics);
426
465
  if (op.op === "move") out.push(...compileSingleOp(baseJson, {
427
466
  op: "remove",
428
467
  path: op.from
429
- }, opIndex));
468
+ }, opIndex, semantics));
430
469
  return out;
431
470
  }
432
471
  const path = parsePointerOrThrow(op.path, op.path, opIndex);
@@ -562,7 +601,7 @@ function parseArrayIndexToken(token, op, arrLength, path, opIndex) {
562
601
  if (op !== "add") throw compileError("INVALID_POINTER", `'-' index is only valid for add at ${path}`, path, opIndex);
563
602
  return Number.POSITIVE_INFINITY;
564
603
  }
565
- if (!/^[0-9]+$/.test(token)) throw compileError("INVALID_POINTER", `expected array index at ${path}`, path, opIndex);
604
+ if (!ARRAY_INDEX_TOKEN_PATTERN.test(token)) throw compileError("INVALID_POINTER", `expected array index at ${path}`, path, opIndex);
566
605
  const index = Number(token);
567
606
  if (!Number.isSafeInteger(index)) throw compileError("OUT_OF_BOUNDS", `array index is too large at ${path}`, path, opIndex);
568
607
  if (op === "add") {
@@ -571,12 +610,31 @@ function parseArrayIndexToken(token, op, arrLength, path, opIndex) {
571
610
  return index;
572
611
  }
573
612
  function compileErrorFromLookup(error, path, opIndex) {
613
+ const mapped = mapLookupErrorToPatchReason(error);
614
+ return compileError(mapped.reason, mapped.message, path, opIndex);
615
+ }
616
+ function mapLookupErrorToPatchReason(error) {
574
617
  const message = error instanceof Error ? error.message : "invalid path";
575
- if (message.includes("Expected array index")) return compileError("INVALID_POINTER", message, path, opIndex);
576
- if (message.includes("Index out of bounds")) return compileError("OUT_OF_BOUNDS", message, path, opIndex);
577
- if (message.includes("Missing key")) return compileError("MISSING_PARENT", message, path, opIndex);
578
- if (message.includes("Cannot traverse into non-container")) return compileError("INVALID_TARGET", message, path, opIndex);
579
- return compileError("INVALID_PATCH", message, path, opIndex);
618
+ if (message.includes("Expected array index")) return {
619
+ reason: "INVALID_POINTER",
620
+ message
621
+ };
622
+ if (message.includes("Index out of bounds")) return {
623
+ reason: "OUT_OF_BOUNDS",
624
+ message
625
+ };
626
+ if (message.includes("Missing key")) return {
627
+ reason: "MISSING_PARENT",
628
+ message
629
+ };
630
+ if (message.includes("Cannot traverse into non-container")) return {
631
+ reason: "INVALID_TARGET",
632
+ message
633
+ };
634
+ return {
635
+ reason: "INVALID_PATCH",
636
+ message
637
+ };
580
638
  }
581
639
  function compileError(reason, message, path, opIndex) {
582
640
  return new PatchCompileError(reason, message, path, opIndex);
@@ -586,6 +644,11 @@ function isStrictDescendantPath(from, to) {
586
644
  for (let i = 0; i < from.length; i++) if (from[i] !== to[i]) return false;
587
645
  return true;
588
646
  }
647
+ function isSamePath(a, b) {
648
+ if (a.length !== b.length) return false;
649
+ for (let i = 0; i < a.length; i++) if (a[i] !== b[i]) return false;
650
+ return true;
651
+ }
589
652
 
590
653
  //#endregion
591
654
  //#region src/doc.ts
@@ -1056,8 +1119,7 @@ function jsonPatchToCrdtInternal(options) {
1056
1119
  const shadowBump = (ctr) => {
1057
1120
  if (shadowCtr < ctr) shadowCtr = ctr;
1058
1121
  };
1059
- for (let opIndex = 0; opIndex < options.patch.length; opIndex++) {
1060
- const op = options.patch[opIndex];
1122
+ const applySequentialOp = (op, opIndex) => {
1061
1123
  const baseJson = materialize(shadowBase.root);
1062
1124
  let intents;
1063
1125
  try {
@@ -1071,6 +1133,42 @@ function jsonPatchToCrdtInternal(options) {
1071
1133
  const shadowStep = applyIntentsToCrdt(shadowBase, shadowBase, intents, shadowDot, "base", shadowBump);
1072
1134
  if (!shadowStep.ok) return withOpIndex(shadowStep, opIndex);
1073
1135
  } else shadowBase = cloneDoc(options.head);
1136
+ return { ok: true };
1137
+ };
1138
+ for (let opIndex = 0; opIndex < options.patch.length; opIndex++) {
1139
+ const op = options.patch[opIndex];
1140
+ if (op.op === "move") {
1141
+ const baseJson = materialize(shadowBase.root);
1142
+ let fromValue;
1143
+ try {
1144
+ fromValue = structuredClone(getAtJson(baseJson, parseJsonPointer(op.from)));
1145
+ } catch {
1146
+ try {
1147
+ compileJsonPatchToIntent(baseJson, [{
1148
+ op: "remove",
1149
+ path: op.from
1150
+ }], { semantics: "sequential" });
1151
+ } catch (error) {
1152
+ return withOpIndex(toApplyError$1(error), opIndex);
1153
+ }
1154
+ return withOpIndex(toApplyError$1(/* @__PURE__ */ new Error(`failed to resolve move source at ${op.from}`)), opIndex);
1155
+ }
1156
+ if (op.from === op.path) continue;
1157
+ const removeStep = applySequentialOp({
1158
+ op: "remove",
1159
+ path: op.from
1160
+ }, opIndex);
1161
+ if (!removeStep.ok) return removeStep;
1162
+ const addStep = applySequentialOp({
1163
+ op: "add",
1164
+ path: op.path,
1165
+ value: fromValue
1166
+ }, opIndex);
1167
+ if (!addStep.ok) return addStep;
1168
+ continue;
1169
+ }
1170
+ const step = applySequentialOp(op, opIndex);
1171
+ if (!step.ok) return step;
1074
1172
  }
1075
1173
  return { ok: true };
1076
1174
  }
@@ -1142,8 +1240,10 @@ function createState(initial, options) {
1142
1240
  /**
1143
1241
  * Fork a replica from a shared origin state while assigning a new local actor ID.
1144
1242
  * The forked state has an independent document clone and clock.
1243
+ * By default this rejects actor reuse to prevent duplicate-dot collisions across peers.
1145
1244
  */
1146
- function forkState(origin, actor) {
1245
+ function forkState(origin, actor, options = {}) {
1246
+ if (actor === origin.clock.actor && !options.allowActorReuse) throw new Error(`forkState actor must be unique; refusing to reuse origin actor '${actor}'`);
1147
1247
  return {
1148
1248
  doc: cloneDoc(origin.doc),
1149
1249
  clock: createClock(actor, origin.clock.ctr)
@@ -1261,8 +1361,8 @@ function applyPatchInternal(state, patch, options) {
1261
1361
  doc: cloneDoc(options.base.doc),
1262
1362
  clock: createClock("__base__", 0)
1263
1363
  } : null;
1264
- for (const op of patch) {
1265
- const step = applyPatchOpSequential(state, op, options, explicitBaseState ? explicitBaseState.doc : cloneDoc(state.doc));
1364
+ for (const [opIndex, op] of patch.entries()) {
1365
+ const step = applyPatchOpSequential(state, op, options, explicitBaseState ? explicitBaseState.doc : cloneDoc(state.doc), opIndex);
1266
1366
  if (!step.ok) return step;
1267
1367
  if (explicitBaseState && op.op !== "test") {
1268
1368
  const baseStep = applyPatchInternal(explicitBaseState, [op], {
@@ -1279,10 +1379,12 @@ function applyPatchInternal(state, patch, options) {
1279
1379
  if (!compiled.ok) return compiled;
1280
1380
  return applyIntentsToCrdt(baseDoc, state.doc, compiled.intents, () => state.clock.next(), options.testAgainst ?? "head", (ctr) => bumpClockCounter(state, ctr));
1281
1381
  }
1282
- function applyPatchOpSequential(state, op, options, baseDoc) {
1382
+ function applyPatchOpSequential(state, op, options, baseDoc, opIndex) {
1283
1383
  const baseJson = materialize(baseDoc.root);
1284
1384
  if (op.op === "move") {
1285
- const fromValue = getAtJson(baseJson, parseJsonPointer(op.from));
1385
+ const fromResolved = resolveValueAtPointer(baseJson, op.from, opIndex);
1386
+ if (!fromResolved.ok) return fromResolved;
1387
+ const fromValue = fromResolved.value;
1286
1388
  const removeRes = applySinglePatchOp(state, baseDoc, {
1287
1389
  op: "remove",
1288
1390
  path: op.from
@@ -1295,7 +1397,9 @@ function applyPatchOpSequential(state, op, options, baseDoc) {
1295
1397
  }, options);
1296
1398
  }
1297
1399
  if (op.op === "copy") {
1298
- const fromValue = getAtJson(baseJson, parseJsonPointer(op.from));
1400
+ const fromResolved = resolveValueAtPointer(baseJson, op.from, opIndex);
1401
+ if (!fromResolved.ok) return fromResolved;
1402
+ const fromValue = fromResolved.value;
1299
1403
  return applySinglePatchOp(state, baseDoc, {
1300
1404
  op: "add",
1301
1405
  path: op.path,
@@ -1304,6 +1408,22 @@ function applyPatchOpSequential(state, op, options, baseDoc) {
1304
1408
  }
1305
1409
  return applySinglePatchOp(state, baseDoc, op, options);
1306
1410
  }
1411
+ function resolveValueAtPointer(baseJson, pointer, opIndex) {
1412
+ let path;
1413
+ try {
1414
+ path = parseJsonPointer(pointer);
1415
+ } catch (error) {
1416
+ return toPointerParseApplyError(error, pointer, opIndex);
1417
+ }
1418
+ try {
1419
+ return {
1420
+ ok: true,
1421
+ value: getAtJson(baseJson, path)
1422
+ };
1423
+ } catch (error) {
1424
+ return toPointerLookupApplyError(error, pointer, opIndex);
1425
+ }
1426
+ }
1307
1427
  function applySinglePatchOp(state, baseDoc, op, options) {
1308
1428
  const compiled = compileIntents(materialize(baseDoc.root), [op], "sequential");
1309
1429
  if (!compiled.ok) return compiled;
@@ -1362,6 +1482,27 @@ function toApplyError(error) {
1362
1482
  message: error instanceof Error ? error.message : "failed to compile patch"
1363
1483
  };
1364
1484
  }
1485
+ function toPointerParseApplyError(error, pointer, opIndex) {
1486
+ return {
1487
+ ok: false,
1488
+ code: 409,
1489
+ reason: "INVALID_POINTER",
1490
+ message: error instanceof Error ? error.message : "invalid pointer",
1491
+ path: pointer,
1492
+ opIndex
1493
+ };
1494
+ }
1495
+ function toPointerLookupApplyError(error, pointer, opIndex) {
1496
+ const mapped = mapLookupErrorToPatchReason(error);
1497
+ return {
1498
+ ok: false,
1499
+ code: 409,
1500
+ reason: mapped.reason,
1501
+ message: mapped.message,
1502
+ path: pointer,
1503
+ opIndex
1504
+ };
1505
+ }
1365
1506
 
1366
1507
  //#endregion
1367
1508
  //#region src/serialize.ts
@@ -161,6 +161,14 @@ type CrdtState = {
161
161
  doc: Doc;
162
162
  clock: Clock;
163
163
  };
164
+ /** Options for `forkState`. */
165
+ interface ForkStateOptions {
166
+ /**
167
+ * Allow reusing the origin actor ID when forking.
168
+ * Defaults to `false` to prevent duplicate-dot collisions across replicas.
169
+ */
170
+ allowActorReuse?: boolean;
171
+ }
164
172
  /** Result from applying a patch for a specific actor using a shared version vector. */
165
173
  type ApplyPatchAsActorResult = {
166
174
  /** Updated CRDT state for the actor that produced this patch. */state: CrdtState; /** Updated version vector after applying the patch. */
@@ -310,8 +318,9 @@ declare function createState(initial: JsonValue, options: {
310
318
  /**
311
319
  * Fork a replica from a shared origin state while assigning a new local actor ID.
312
320
  * The forked state has an independent document clone and clock.
321
+ * By default this rejects actor reuse to prevent duplicate-dot collisions across peers.
313
322
  */
314
- declare function forkState(origin: CrdtState, actor: ActorId): CrdtState;
323
+ declare function forkState(origin: CrdtState, actor: ActorId, options?: ForkStateOptions): CrdtState;
315
324
  /**
316
325
  * Materialize a CRDT document or state back to a plain JSON value.
317
326
  * @param target - A `Doc` or `CrdtState` to materialize.
@@ -442,4 +451,4 @@ declare function mergeState(a: CrdtState, b: CrdtState, options?: MergeStateOpti
442
451
  /** Non-throwing `mergeState` variant with structured conflict details. */
443
452
  declare function tryMergeState(a: CrdtState, b: CrdtState, options?: MergeStateOptions): TryMergeStateResult;
444
453
  //#endregion
445
- export { PatchErrorReason as $, ApplyPatchAsActorResult as A, ElemId as B, toJson as C, ActorId as D, validateJsonPatch as E, CompilePatchOptions as F, JsonPrimitive as G, JsonPatch as H, CrdtState as I, MergeDocOptions as J, JsonValue as K, DiffOptions as L, ApplyPatchOptions as M, ApplyResult as N, ApplyError as O, Clock as P, ObjNode as Q, Doc as R, forkState as S, tryApplyPatchInPlace as T, JsonPatchOp as U, IntentOp as V, JsonPatchToCrdtOptions as W, Node as X, MergeStateOptions as Y, ObjEntry as Z, PatchError as _, tryMergeState as a, SerializedDoc as at, applyPatchInPlace as b, serializeDoc as c, SerializedState as ct, compileJsonPatchToIntent as d, TryMergeDocResult as dt, PatchSemantics as et, diffJsonPatch as f, TryMergeStateResult as ft, stringifyJsonPointer as g, parseJsonPointer as h, tryMergeDoc as i, SerializedClock as it, ApplyPatchInPlaceOptions as j, ApplyPatchAsActorOptions as k, serializeState as l, TryApplyPatchInPlaceResult as lt, jsonEquals as m, VersionVector as mt, mergeDoc as n, RgaElem as nt, deserializeDoc as o, SerializedNode as ot, getAtJson as p, ValidatePatchResult as pt, LwwReg as q, mergeState as r, RgaSeq as rt, deserializeState as s, SerializedRgaElem as st, MergeError as t, ROOT_KEY as tt, PatchCompileError as u, TryApplyPatchResult as ut, applyPatch as v, tryApplyPatch as w, createState as x, applyPatchAsActor as y, Dot as z };
454
+ export { ObjNode as $, ApplyPatchAsActorResult as A, ElemId as B, toJson as C, ActorId as D, validateJsonPatch as E, CompilePatchOptions as F, JsonPatchToCrdtOptions as G, IntentOp as H, CrdtState as I, LwwReg as J, JsonPrimitive as K, DiffOptions as L, ApplyPatchOptions as M, ApplyResult as N, ApplyError as O, Clock as P, ObjEntry as Q, Doc as R, forkState as S, tryApplyPatchInPlace as T, JsonPatch as U, ForkStateOptions as V, JsonPatchOp as W, MergeStateOptions as X, MergeDocOptions as Y, Node as Z, PatchError as _, tryMergeState as a, SerializedClock as at, applyPatchInPlace as b, serializeDoc as c, SerializedRgaElem as ct, compileJsonPatchToIntent as d, TryApplyPatchResult as dt, PatchErrorReason as et, diffJsonPatch as f, TryMergeDocResult as ft, stringifyJsonPointer as g, parseJsonPointer as h, VersionVector as ht, tryMergeDoc as i, RgaSeq as it, ApplyPatchInPlaceOptions as j, ApplyPatchAsActorOptions as k, serializeState as l, SerializedState as lt, jsonEquals as m, ValidatePatchResult as mt, mergeDoc as n, ROOT_KEY as nt, deserializeDoc as o, SerializedDoc as ot, getAtJson as p, TryMergeStateResult as pt, JsonValue as q, mergeState as r, RgaElem as rt, deserializeState as s, SerializedNode as st, MergeError as t, PatchSemantics as tt, PatchCompileError as u, TryApplyPatchInPlaceResult as ut, applyPatch as v, tryApplyPatch as w, createState as x, applyPatchAsActor as y, Dot as z };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-patch-to-crdt",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Convert JSON Patch (RFC 6902) to and from a CRDT-friendly representation.",
5
5
  "keywords": [
6
6
  "crdt",
@@ -54,8 +54,5 @@
54
54
  },
55
55
  "peerDependencies": {
56
56
  "typescript": "^5"
57
- },
58
- "engines": {
59
- "node": ">=18"
60
57
  }
61
58
  }