json-patch-to-crdt 0.0.0 → 0.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/README.md +66 -78
- package/dist/index.d.mts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -23
- package/dist/index.mjs +2 -2
- package/dist/internals.d.mts +80 -2
- package/dist/internals.d.ts +80 -2
- package/dist/internals.js +10 -1
- package/dist/internals.mjs +2 -2
- package/dist/{merge-DikOFBWc.mjs → merge-BqROEw61.mjs} +491 -162
- package/dist/{merge-BpAUNaPe.d.mts → merge-BrNGGkXj.d.mts} +124 -98
- package/dist/{merge-B1BFMhJJ.js → merge-CtJfKEt1.js} +544 -161
- package/dist/{merge-QmPXxE6_.d.ts → merge-DW1-p9Hj.d.ts} +124 -98
- package/package.json +4 -1
|
@@ -166,28 +166,70 @@ type ApplyPatchAsActorResult = {
|
|
|
166
166
|
/** Updated CRDT state for the actor that produced this patch. */state: CrdtState; /** Updated version vector after applying the patch. */
|
|
167
167
|
vv: VersionVector;
|
|
168
168
|
};
|
|
169
|
-
/**
|
|
169
|
+
/** Options for internals-only `applyPatchAsActor`. */
|
|
170
|
+
type ApplyPatchAsActorOptions = {
|
|
171
|
+
base?: Doc;
|
|
172
|
+
testAgainst?: "head" | "base";
|
|
173
|
+
semantics?: PatchSemantics;
|
|
174
|
+
};
|
|
175
|
+
/** Typed failure reason used across patch/merge helpers. */
|
|
176
|
+
type PatchErrorReason = "INVALID_PATCH" | "INVALID_POINTER" | "MISSING_PARENT" | "MISSING_TARGET" | "INVALID_TARGET" | "OUT_OF_BOUNDS" | "TEST_FAILED" | "INVALID_MOVE" | "LINEAGE_MISMATCH";
|
|
177
|
+
/** Structured conflict payload used by non-throwing APIs. */
|
|
178
|
+
type ApplyError = {
|
|
179
|
+
ok: false; /** HTTP-friendly status code for conflict-style failures. */
|
|
180
|
+
code: 409; /** Machine-readable reason for branching logic. */
|
|
181
|
+
reason: PatchErrorReason; /** Human-readable description of the failure. */
|
|
182
|
+
message: string; /** Optional pointer/path context when available. */
|
|
183
|
+
path?: string; /** Optional patch operation index when available. */
|
|
184
|
+
opIndex?: number;
|
|
185
|
+
};
|
|
186
|
+
/** Result of applying a patch: success or structured conflict details. */
|
|
170
187
|
type ApplyResult = {
|
|
171
188
|
ok: true;
|
|
172
|
-
} |
|
|
173
|
-
ok: false;
|
|
174
|
-
code: 409;
|
|
175
|
-
message: string;
|
|
176
|
-
};
|
|
189
|
+
} | ApplyError;
|
|
177
190
|
/** How JSON Patch operations are interpreted during application. */
|
|
178
191
|
type PatchSemantics = "base" | "sequential";
|
|
192
|
+
/** Options for compile/validation helpers. */
|
|
193
|
+
type CompilePatchOptions = {
|
|
194
|
+
semantics?: PatchSemantics;
|
|
195
|
+
};
|
|
179
196
|
/**
|
|
180
|
-
* Options for `applyPatch` / `
|
|
181
|
-
* - `semantics: "
|
|
182
|
-
* - `semantics: "
|
|
183
|
-
* - `
|
|
197
|
+
* Options for immutable patch application (`applyPatch` / `tryApplyPatch`).
|
|
198
|
+
* - `semantics: "sequential"` applies operations one-by-one against the evolving head (default).
|
|
199
|
+
* - `semantics: "base"` maps array indices against a fixed snapshot.
|
|
200
|
+
* - `base` should be a previously observed state snapshot from the same document lineage.
|
|
184
201
|
*/
|
|
185
202
|
type ApplyPatchOptions = {
|
|
186
|
-
base?:
|
|
203
|
+
base?: CrdtState;
|
|
187
204
|
testAgainst?: "head" | "base";
|
|
188
205
|
semantics?: PatchSemantics;
|
|
206
|
+
};
|
|
207
|
+
/** Options for in-place patch application (`applyPatchInPlace` / `tryApplyPatchInPlace`). */
|
|
208
|
+
type ApplyPatchInPlaceOptions = ApplyPatchOptions & {
|
|
189
209
|
atomic?: boolean;
|
|
190
210
|
};
|
|
211
|
+
/** Non-throwing result for immutable patch application. */
|
|
212
|
+
type TryApplyPatchResult = {
|
|
213
|
+
ok: true;
|
|
214
|
+
state: CrdtState;
|
|
215
|
+
} | {
|
|
216
|
+
ok: false;
|
|
217
|
+
error: ApplyError;
|
|
218
|
+
};
|
|
219
|
+
/** Non-throwing result for in-place patch application. */
|
|
220
|
+
type TryApplyPatchInPlaceResult = {
|
|
221
|
+
ok: true;
|
|
222
|
+
} | {
|
|
223
|
+
ok: false;
|
|
224
|
+
error: ApplyError;
|
|
225
|
+
};
|
|
226
|
+
/** Non-throwing result for patch validation preflight. */
|
|
227
|
+
type ValidatePatchResult = {
|
|
228
|
+
ok: true;
|
|
229
|
+
} | {
|
|
230
|
+
ok: false;
|
|
231
|
+
error: ApplyError;
|
|
232
|
+
};
|
|
191
233
|
/** Options for `mergeState`. */
|
|
192
234
|
type MergeStateOptions = {
|
|
193
235
|
/**
|
|
@@ -209,6 +251,32 @@ type MergeDocOptions = {
|
|
|
209
251
|
*/
|
|
210
252
|
requireSharedOrigin?: boolean;
|
|
211
253
|
};
|
|
254
|
+
/** Non-throwing result for `mergeDoc`. */
|
|
255
|
+
type TryMergeDocResult = {
|
|
256
|
+
ok: true;
|
|
257
|
+
doc: Doc;
|
|
258
|
+
} | {
|
|
259
|
+
ok: false;
|
|
260
|
+
error: ApplyError;
|
|
261
|
+
};
|
|
262
|
+
/** Non-throwing result for `mergeState`. */
|
|
263
|
+
type TryMergeStateResult = {
|
|
264
|
+
ok: true;
|
|
265
|
+
state: CrdtState;
|
|
266
|
+
} | {
|
|
267
|
+
ok: false;
|
|
268
|
+
error: ApplyError;
|
|
269
|
+
};
|
|
270
|
+
/** Options-object overload shape for low-level JSON Patch -> CRDT conversion. */
|
|
271
|
+
type JsonPatchToCrdtOptions = {
|
|
272
|
+
base: Doc;
|
|
273
|
+
head: Doc;
|
|
274
|
+
patch: JsonPatchOp[];
|
|
275
|
+
newDot: () => Dot;
|
|
276
|
+
evalTestAgainst?: "head" | "base";
|
|
277
|
+
bumpCounterAbove?: (ctr: number) => void;
|
|
278
|
+
semantics?: PatchSemantics;
|
|
279
|
+
};
|
|
212
280
|
/** Options for `crdtToJsonPatch` and `diffJsonPatch`. */
|
|
213
281
|
type DiffOptions = {
|
|
214
282
|
arrayStrategy?: "atomic" | "lcs";
|
|
@@ -220,10 +288,14 @@ type DiffOptions = {
|
|
|
220
288
|
declare const ROOT_KEY = "@@crdt/root";
|
|
221
289
|
//#endregion
|
|
222
290
|
//#region src/state.d.ts
|
|
223
|
-
/** Error thrown when a JSON Patch cannot be applied. Includes
|
|
291
|
+
/** Error thrown when a JSON Patch cannot be applied. Includes structured conflict metadata. */
|
|
224
292
|
declare class PatchError extends Error {
|
|
225
|
-
readonly code:
|
|
226
|
-
|
|
293
|
+
readonly code: 409;
|
|
294
|
+
readonly reason: PatchErrorReason;
|
|
295
|
+
readonly path?: string;
|
|
296
|
+
readonly opIndex?: number;
|
|
297
|
+
constructor(error: ApplyError);
|
|
298
|
+
constructor(message: string, code?: 409, reason?: PatchErrorReason);
|
|
227
299
|
}
|
|
228
300
|
/**
|
|
229
301
|
* Create a new CRDT state from an initial JSON value.
|
|
@@ -235,6 +307,11 @@ declare function createState(initial: JsonValue, options: {
|
|
|
235
307
|
actor: ActorId;
|
|
236
308
|
start?: number;
|
|
237
309
|
}): CrdtState;
|
|
310
|
+
/**
|
|
311
|
+
* Fork a replica from a shared origin state while assigning a new local actor ID.
|
|
312
|
+
* The forked state has an independent document clone and clock.
|
|
313
|
+
*/
|
|
314
|
+
declare function forkState(origin: CrdtState, actor: ActorId): CrdtState;
|
|
238
315
|
/**
|
|
239
316
|
* Materialize a CRDT document or state back to a plain JSON value.
|
|
240
317
|
* @param target - A `Doc` or `CrdtState` to materialize.
|
|
@@ -246,7 +323,7 @@ declare function toJson(target: Doc | CrdtState): JsonValue;
|
|
|
246
323
|
* Throws `PatchError` on conflict (e.g. out-of-bounds index, failed test op).
|
|
247
324
|
* @param state - The current CRDT state.
|
|
248
325
|
* @param patch - Array of RFC 6902 JSON Patch operations.
|
|
249
|
-
* @param options - Optional base
|
|
326
|
+
* @param options - Optional base state snapshot and patch semantics.
|
|
250
327
|
* @returns A new `CrdtState` with the patch applied.
|
|
251
328
|
*/
|
|
252
329
|
declare function applyPatch(state: CrdtState, patch: JsonPatchOp[], options?: ApplyPatchOptions): CrdtState;
|
|
@@ -255,90 +332,32 @@ declare function applyPatch(state: CrdtState, patch: JsonPatchOp[], options?: Ap
|
|
|
255
332
|
* Throws `PatchError` on conflict.
|
|
256
333
|
* @param state - The CRDT state to mutate.
|
|
257
334
|
* @param patch - Array of RFC 6902 JSON Patch operations.
|
|
258
|
-
* @param options - Optional base
|
|
259
|
-
*/
|
|
260
|
-
declare function applyPatchInPlace(state: CrdtState, patch: JsonPatchOp[], options?: ApplyPatchOptions): void;
|
|
261
|
-
/**
|
|
262
|
-
* Apply a JSON Patch as a specific actor while maintaining an external version vector.
|
|
263
|
-
* Returns the updated state and a new version vector snapshot.
|
|
264
|
-
*/
|
|
265
|
-
declare function applyPatchAsActor(doc: Doc, vv: VersionVector, actor: ActorId, patch: JsonPatchOp[], options?: ApplyPatchOptions): ApplyPatchAsActorResult;
|
|
266
|
-
//#endregion
|
|
267
|
-
//#region src/clock.d.ts
|
|
268
|
-
/**
|
|
269
|
-
* Create a new clock for the given actor. Each call to `clock.next()` yields a fresh `Dot`.
|
|
270
|
-
* @param actor - Unique identifier for this peer.
|
|
271
|
-
* @param start - Initial counter value (defaults to 0).
|
|
335
|
+
* @param options - Optional base state snapshot, patch semantics, and atomicity.
|
|
272
336
|
*/
|
|
273
|
-
declare function
|
|
274
|
-
/**
|
|
275
|
-
declare function
|
|
337
|
+
declare function applyPatchInPlace(state: CrdtState, patch: JsonPatchOp[], options?: ApplyPatchInPlaceOptions): void;
|
|
338
|
+
/** Non-throwing immutable patch application variant. */
|
|
339
|
+
declare function tryApplyPatch(state: CrdtState, patch: JsonPatchOp[], options?: ApplyPatchOptions): TryApplyPatchResult;
|
|
340
|
+
/** Non-throwing in-place patch application variant. */
|
|
341
|
+
declare function tryApplyPatchInPlace(state: CrdtState, patch: JsonPatchOp[], options?: ApplyPatchInPlaceOptions): TryApplyPatchInPlaceResult;
|
|
276
342
|
/**
|
|
277
|
-
*
|
|
278
|
-
*
|
|
343
|
+
* Validate whether a patch is applicable against a JSON base value under the chosen options.
|
|
344
|
+
* Does not mutate caller-provided values.
|
|
279
345
|
*/
|
|
280
|
-
declare function
|
|
281
|
-
/** Record an observed dot in a version vector. */
|
|
282
|
-
declare function observeDot(vv: VersionVector, dot: Dot): void;
|
|
283
|
-
//#endregion
|
|
284
|
-
//#region src/doc.d.ts
|
|
285
|
-
/**
|
|
286
|
-
* Create a CRDT document from a JSON value, using fresh dots for each node.
|
|
287
|
-
* @param value - The JSON value to convert.
|
|
288
|
-
* @param nextDot - A function that generates a unique `Dot` on each call.
|
|
289
|
-
* @returns A new CRDT `Doc`.
|
|
290
|
-
*/
|
|
291
|
-
declare function docFromJson(value: JsonValue, nextDot: () => Dot): Doc;
|
|
346
|
+
declare function validateJsonPatch(base: JsonValue, patch: JsonPatchOp[], options?: ApplyPatchOptions): ValidatePatchResult;
|
|
292
347
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*/
|
|
296
|
-
declare function docFromJsonWithDot(value: JsonValue, dot: Dot): Doc;
|
|
297
|
-
/** Deep-clone a CRDT document. The clone is fully independent of the original. */
|
|
298
|
-
declare function cloneDoc(doc: Doc): Doc;
|
|
299
|
-
/**
|
|
300
|
-
* Apply compiled intent operations to a CRDT document.
|
|
301
|
-
* Array indices are resolved against the base document.
|
|
302
|
-
* @param base - The base document snapshot used for index mapping and test evaluation.
|
|
303
|
-
* @param head - The target document to mutate.
|
|
304
|
-
* @param intents - Compiled intent operations from `compileJsonPatchToIntent`.
|
|
305
|
-
* @param newDot - A function that generates a unique `Dot` per mutation.
|
|
306
|
-
* @param evalTestAgainst - Whether `test` ops are evaluated against `"head"` or `"base"`.
|
|
307
|
-
* @param bumpCounterAbove - Optional hook that can fast-forward the underlying counter before inserts.
|
|
308
|
-
* @returns `{ ok: true }` on success, or `{ ok: false, code: 409, message }` on conflict.
|
|
309
|
-
*/
|
|
310
|
-
declare function applyIntentsToCrdt(base: Doc, head: Doc, intents: IntentOp[], newDot: () => Dot, evalTestAgainst?: "head" | "base", bumpCounterAbove?: (ctr: number) => void): ApplyResult;
|
|
311
|
-
/**
|
|
312
|
-
* Convenience wrapper: compile a JSON Patch and apply it to a CRDT document.
|
|
313
|
-
* @param base - The base document for index resolution.
|
|
314
|
-
* @param head - The target document to mutate.
|
|
315
|
-
* @param patch - Array of RFC 6902 JSON Patch operations.
|
|
316
|
-
* @param newDot - A function that generates a unique `Dot` per mutation.
|
|
317
|
-
* @param evalTestAgainst - Whether `test` ops evaluate against `"head"` or `"base"`.
|
|
318
|
-
* @param bumpCounterAbove - Optional hook that can fast-forward the underlying counter before inserts.
|
|
319
|
-
* @returns `{ ok: true }` on success, or `{ ok: false, code: 409, message }` on conflict.
|
|
320
|
-
*/
|
|
321
|
-
declare function jsonPatchToCrdt(base: Doc, head: Doc, patch: JsonPatchOp[], newDot: () => Dot, evalTestAgainst?: "head" | "base", bumpCounterAbove?: (ctr: number) => void): ApplyResult;
|
|
322
|
-
/**
|
|
323
|
-
* Safe wrapper around `jsonPatchToCrdt` that converts compile-time errors into `409` results.
|
|
324
|
-
* This function never throws for malformed/invalid patch paths.
|
|
325
|
-
*/
|
|
326
|
-
declare function jsonPatchToCrdtSafe(base: Doc, head: Doc, patch: JsonPatchOp[], newDot: () => Dot, evalTestAgainst?: "head" | "base", bumpCounterAbove?: (ctr: number) => void): ApplyResult;
|
|
327
|
-
/**
|
|
328
|
-
* Generate a JSON Patch delta between two CRDT documents.
|
|
329
|
-
* @param base - The base document snapshot.
|
|
330
|
-
* @param head - The current document state.
|
|
331
|
-
* @param options - Diff options (e.g. `{ arrayStrategy: "lcs" }`).
|
|
332
|
-
* @returns An array of JSON Patch operations that transform base into head.
|
|
333
|
-
*/
|
|
334
|
-
declare function crdtToJsonPatch(base: Doc, head: Doc, options?: DiffOptions): JsonPatchOp[];
|
|
335
|
-
/**
|
|
336
|
-
* Emit a single root `replace` patch representing the full document state.
|
|
337
|
-
* Use `crdtToJsonPatch(base, head)` for delta patches instead.
|
|
348
|
+
* Apply a JSON Patch as a specific actor while maintaining an external version vector.
|
|
349
|
+
* Returns the updated state and a new version vector snapshot.
|
|
338
350
|
*/
|
|
339
|
-
declare function
|
|
351
|
+
declare function applyPatchAsActor(doc: Doc, vv: VersionVector, actor: ActorId, patch: JsonPatchOp[], options?: ApplyPatchAsActorOptions): ApplyPatchAsActorResult;
|
|
340
352
|
//#endregion
|
|
341
353
|
//#region src/patch.d.ts
|
|
354
|
+
/** Structured compile error used to map patch validation failures to typed reasons. */
|
|
355
|
+
declare class PatchCompileError extends Error {
|
|
356
|
+
readonly reason: PatchErrorReason;
|
|
357
|
+
readonly path?: string;
|
|
358
|
+
readonly opIndex?: number;
|
|
359
|
+
constructor(reason: PatchErrorReason, message: string, path?: string, opIndex?: number);
|
|
360
|
+
}
|
|
342
361
|
/**
|
|
343
362
|
* Parse an RFC 6901 JSON Pointer into a path array, unescaping `~1` and `~0`.
|
|
344
363
|
* @param ptr - A JSON Pointer string (e.g. `"/a/b"` or `""`).
|
|
@@ -360,7 +379,7 @@ declare function getAtJson(base: JsonValue, path: string[]): JsonValue;
|
|
|
360
379
|
* @param patch - Array of JSON Patch operations.
|
|
361
380
|
* @returns An array of `IntentOp` ready for `applyIntentsToCrdt`.
|
|
362
381
|
*/
|
|
363
|
-
declare function compileJsonPatchToIntent(baseJson: JsonValue, patch: JsonPatchOp[]): IntentOp[];
|
|
382
|
+
declare function compileJsonPatchToIntent(baseJson: JsonValue, patch: JsonPatchOp[], options?: CompilePatchOptions): IntentOp[];
|
|
364
383
|
/**
|
|
365
384
|
* Compute a JSON Patch delta between two JSON values.
|
|
366
385
|
* By default arrays use a deterministic LCS strategy.
|
|
@@ -384,11 +403,14 @@ declare function serializeState(state: CrdtState): SerializedState;
|
|
|
384
403
|
/** Reconstruct a full CRDT state from its serialized form, restoring the clock. */
|
|
385
404
|
declare function deserializeState(data: SerializedState): CrdtState;
|
|
386
405
|
//#endregion
|
|
387
|
-
//#region src/materialize.d.ts
|
|
388
|
-
/** Recursively convert a CRDT node graph into a plain JSON value. */
|
|
389
|
-
declare function materialize(node: Node): JsonValue;
|
|
390
|
-
//#endregion
|
|
391
406
|
//#region src/merge.d.ts
|
|
407
|
+
/** Error thrown by throwing merge helpers (`mergeDoc` / `mergeState`). */
|
|
408
|
+
declare class MergeError extends Error {
|
|
409
|
+
readonly code: 409;
|
|
410
|
+
readonly reason: "LINEAGE_MISMATCH";
|
|
411
|
+
readonly path?: string;
|
|
412
|
+
constructor(error: ApplyError);
|
|
413
|
+
}
|
|
392
414
|
/**
|
|
393
415
|
* Merge two CRDT documents from different peers into one.
|
|
394
416
|
* By default this requires shared array lineage for non-empty sequences.
|
|
@@ -403,6 +425,8 @@ declare function materialize(node: Node): JsonValue;
|
|
|
403
425
|
* - **Kind mismatch**: the node with the higher "representative dot" wins and replaces the other entirely.
|
|
404
426
|
*/
|
|
405
427
|
declare function mergeDoc(a: Doc, b: Doc, options?: MergeDocOptions): Doc;
|
|
428
|
+
/** Non-throwing `mergeDoc` variant with structured conflict details. */
|
|
429
|
+
declare function tryMergeDoc(a: Doc, b: Doc, options?: MergeDocOptions): TryMergeDocResult;
|
|
406
430
|
/**
|
|
407
431
|
* Merge two CRDT states.
|
|
408
432
|
*
|
|
@@ -415,5 +439,7 @@ declare function mergeDoc(a: Doc, b: Doc, options?: MergeDocOptions): Doc;
|
|
|
415
439
|
* that actor across both input clocks and the merged document dots.
|
|
416
440
|
*/
|
|
417
441
|
declare function mergeState(a: CrdtState, b: CrdtState, options?: MergeStateOptions): CrdtState;
|
|
442
|
+
/** Non-throwing `mergeState` variant with structured conflict details. */
|
|
443
|
+
declare function tryMergeState(a: CrdtState, b: CrdtState, options?: MergeStateOptions): TryMergeStateResult;
|
|
418
444
|
//#endregion
|
|
419
|
-
export {
|
|
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 };
|