@dabble/patches 0.8.12 → 0.8.13
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/dist/client/Patches.d.ts
CHANGED
|
@@ -123,12 +123,6 @@ declare class Patches {
|
|
|
123
123
|
* Should be called when shutting down the client.
|
|
124
124
|
*/
|
|
125
125
|
close(): Promise<void>;
|
|
126
|
-
/**
|
|
127
|
-
* Submits ops for a document through the serialized change queue.
|
|
128
|
-
* Used by PatchesBranchClient to merge branch changes without racing
|
|
129
|
-
* against concurrent user edits on the same document.
|
|
130
|
-
*/
|
|
131
|
-
submitDocChange(docId: string, ops: JSONPatchOp[], metadata?: Record<string, any>): Promise<void>;
|
|
132
126
|
/**
|
|
133
127
|
* Internal handler for doc changes. Called when doc.onChange emits ops.
|
|
134
128
|
* Serializes calls per docId to prevent concurrent handleDocChange from
|
package/dist/client/Patches.js
CHANGED
|
@@ -197,17 +197,6 @@ class Patches {
|
|
|
197
197
|
this.onServerCommit.clear();
|
|
198
198
|
this.onError.clear();
|
|
199
199
|
}
|
|
200
|
-
/**
|
|
201
|
-
* Submits ops for a document through the serialized change queue.
|
|
202
|
-
* Used by PatchesBranchClient to merge branch changes without racing
|
|
203
|
-
* against concurrent user edits on the same document.
|
|
204
|
-
*/
|
|
205
|
-
submitDocChange(docId, ops, metadata = {}) {
|
|
206
|
-
const managed = this.docs.get(docId);
|
|
207
|
-
const algorithm = this.getDocAlgorithm(docId) ?? this.algorithms[this.defaultAlgorithm];
|
|
208
|
-
if (!algorithm) throw new Error(`No algorithm found for document ${docId}`);
|
|
209
|
-
return this._handleDocChange(docId, ops, managed?.doc, algorithm, metadata);
|
|
210
|
-
}
|
|
211
200
|
/**
|
|
212
201
|
* Internal handler for doc changes. Called when doc.onChange emits ops.
|
|
213
202
|
* Serializes calls per docId to prevent concurrent handleDocChange from
|
|
@@ -26,8 +26,8 @@ interface PatchesBranchClientOptions {
|
|
|
26
26
|
* (offline-first, local store handles caching/pending/tombstones). The API shape
|
|
27
27
|
* determines merge behavior:
|
|
28
28
|
*
|
|
29
|
-
* - `BranchAPI`
|
|
30
|
-
* - `BranchClientStore`
|
|
29
|
+
* - `BranchAPI` — server performs the merge via `mergeBranch`
|
|
30
|
+
* - `BranchClientStore` — merge is not supported; call the server merge endpoint directly
|
|
31
31
|
*/
|
|
32
32
|
declare class PatchesBranchClient {
|
|
33
33
|
private readonly api;
|
|
@@ -81,16 +81,15 @@ declare class PatchesBranchClient {
|
|
|
81
81
|
/**
|
|
82
82
|
* Merge a branch's changes back into this document.
|
|
83
83
|
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
87
|
-
*
|
|
84
|
+
* Requires a `BranchAPI` (online mode) — the server performs the merge.
|
|
85
|
+
* Throws if the API is a `BranchClientStore` (offline-first mode) because
|
|
86
|
+
* client stores don't maintain full change history needed for correct merging.
|
|
87
|
+
* Offline-first consumers should call the server merge endpoint directly.
|
|
88
88
|
*/
|
|
89
89
|
mergeBranch(branchId: string): Promise<void>;
|
|
90
90
|
/** Clear state */
|
|
91
91
|
clear(): void;
|
|
92
92
|
private _createBranchOffline;
|
|
93
|
-
private _mergeBranchLocally;
|
|
94
93
|
}
|
|
95
94
|
|
|
96
95
|
export { PatchesBranchClient, type PatchesBranchClientOptions };
|
|
@@ -2,6 +2,7 @@ import "../chunk-IZ2YBCUP.js";
|
|
|
2
2
|
import { store } from "easy-signal";
|
|
3
3
|
import { breakChanges } from "../algorithms/ot/shared/changeBatching.js";
|
|
4
4
|
import { createChange } from "../data/change.js";
|
|
5
|
+
const OFFLINE_MERGE_ERROR = "Branch merging requires a server connection. Use a BranchAPI or call the server merge endpoint directly.";
|
|
5
6
|
class PatchesBranchClient {
|
|
6
7
|
constructor(id, api, patches, options) {
|
|
7
8
|
this.api = api;
|
|
@@ -87,18 +88,17 @@ class PatchesBranchClient {
|
|
|
87
88
|
/**
|
|
88
89
|
* Merge a branch's changes back into this document.
|
|
89
90
|
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
*
|
|
91
|
+
* Requires a `BranchAPI` (online mode) — the server performs the merge.
|
|
92
|
+
* Throws if the API is a `BranchClientStore` (offline-first mode) because
|
|
93
|
+
* client stores don't maintain full change history needed for correct merging.
|
|
94
|
+
* Offline-first consumers should call the server merge endpoint directly.
|
|
94
95
|
*/
|
|
95
96
|
async mergeBranch(branchId) {
|
|
96
|
-
if (
|
|
97
|
-
|
|
98
|
-
await this.listBranches();
|
|
99
|
-
return;
|
|
97
|
+
if (this.isOffline) {
|
|
98
|
+
throw new Error(OFFLINE_MERGE_ERROR);
|
|
100
99
|
}
|
|
101
|
-
await this.
|
|
100
|
+
await this.api.mergeBranch(branchId);
|
|
101
|
+
await this.listBranches();
|
|
102
102
|
}
|
|
103
103
|
/** Clear state */
|
|
104
104
|
clear() {
|
|
@@ -148,29 +148,6 @@ class PatchesBranchClient {
|
|
|
148
148
|
this.patches.onChange.emit(branchDocId);
|
|
149
149
|
return branchDocId;
|
|
150
150
|
}
|
|
151
|
-
async _mergeBranchLocally(branchId) {
|
|
152
|
-
const offlineApi = this.api;
|
|
153
|
-
const branch = this.branches.state.find((b) => b.id === branchId);
|
|
154
|
-
if (!branch) throw new Error(`Branch ${branchId} not found`);
|
|
155
|
-
const sourceDocId = branch.docId;
|
|
156
|
-
const algorithmName = this.options?.algorithm ?? this.patches.defaultAlgorithm;
|
|
157
|
-
const algorithm = this.patches.algorithms[algorithmName];
|
|
158
|
-
if (!algorithm?.listChanges) {
|
|
159
|
-
throw new Error("Offline merge requires an algorithm with listChanges support");
|
|
160
|
-
}
|
|
161
|
-
const startAfter = branch.lastMergedRev ?? (branch.contentStartRev ?? 2) - 1;
|
|
162
|
-
const branchChanges = await algorithm.listChanges(branchId, { startAfter });
|
|
163
|
-
if (branchChanges.length === 0) return;
|
|
164
|
-
const lastBranchRev = branchChanges[branchChanges.length - 1].rev;
|
|
165
|
-
for (const change of branchChanges) {
|
|
166
|
-
await this.patches.submitDocChange(sourceDocId, change.ops, { batchId: branchId });
|
|
167
|
-
}
|
|
168
|
-
await offlineApi.updateBranch(branchId, { lastMergedRev: lastBranchRev });
|
|
169
|
-
this.patches.onChange.emit(sourceDocId);
|
|
170
|
-
this.branches.state = this.branches.state.map(
|
|
171
|
-
(b) => b.id === branchId ? { ...b, lastMergedRev: lastBranchRev } : b
|
|
172
|
-
);
|
|
173
|
-
}
|
|
174
151
|
}
|
|
175
152
|
export {
|
|
176
153
|
PatchesBranchClient
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dabble/patches",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.13",
|
|
4
4
|
"description": "Immutable JSON Patch implementation based on RFC 6902 supporting operational transformation and last-writer-wins",
|
|
5
5
|
"author": "Jacob Wright <jacwright@gmail.com>",
|
|
6
6
|
"bugs": {
|