@dabble/patches 0.7.6 → 0.7.8
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/{BaseDoc-DkP3tUhT.d.ts → BaseDoc-_Rsau70J.d.ts} +9 -9
- package/dist/algorithms/lww/consolidateOps.d.ts +1 -1
- package/dist/algorithms/lww/consolidateOps.js +42 -0
- package/dist/client/BaseDoc.d.ts +1 -1
- package/dist/client/BaseDoc.js +2 -2
- package/dist/client/ClientAlgorithm.d.ts +1 -1
- package/dist/client/IndexedDBStore.d.ts +11 -11
- package/dist/client/IndexedDBStore.js +14 -14
- package/dist/client/LWWAlgorithm.d.ts +1 -1
- package/dist/client/LWWDoc.d.ts +3 -3
- package/dist/client/LWWIndexedDBStore.d.ts +1 -1
- package/dist/client/OTAlgorithm.d.ts +1 -1
- package/dist/client/OTDoc.d.ts +1 -1
- package/dist/client/OTIndexedDBStore.d.ts +1 -1
- package/dist/client/Patches.d.ts +12 -6
- package/dist/client/PatchesDoc.d.ts +1 -1
- package/dist/client/factories.d.ts +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/net/PatchesClient.d.ts +1 -1
- package/dist/net/PatchesClient.js +2 -2
- package/dist/net/PatchesSync.d.ts +1 -1
- package/dist/net/index.d.ts +1 -1
- package/dist/net/protocol/JSONRPCClient.js +2 -0
- package/dist/net/protocol/JSONRPCServer.js +7 -1
- package/dist/net/protocol/types.d.ts +1 -1
- package/dist/net/websocket/WebSocketServer.d.ts +4 -10
- package/dist/net/websocket/WebSocketServer.js +5 -9
- package/dist/server/LWWBranchManager.d.ts +2 -2
- package/dist/server/LWWBranchManager.js +3 -3
- package/dist/server/OTBranchManager.d.ts +1 -1
- package/dist/server/OTBranchManager.js +2 -2
- package/dist/server/branchUtils.d.ts +1 -1
- package/dist/server/branchUtils.js +2 -2
- package/dist/shared/doc-manager.d.ts +3 -3
- package/dist/shared/doc-manager.js +2 -2
- package/dist/solid/context.d.ts +1 -1
- package/dist/solid/doc-manager.d.ts +1 -1
- package/dist/solid/index.d.ts +1 -1
- package/dist/solid/primitives.d.ts +10 -5
- package/dist/solid/primitives.js +80 -132
- package/dist/vue/composables.d.ts +9 -4
- package/dist/vue/composables.js +93 -148
- package/dist/vue/doc-manager.d.ts +1 -1
- package/dist/vue/index.d.ts +1 -1
- package/dist/vue/managed-docs.d.ts +10 -1
- package/dist/vue/managed-docs.js +3 -2
- package/dist/vue/provider.d.ts +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import { Change, PatchesSnapshot, SyncingState, ChangeMutator } from './types.js
|
|
|
8
8
|
* for handling concurrent edits.
|
|
9
9
|
*
|
|
10
10
|
* The `change()` method (inherited from BaseDoc) captures ops and emits them
|
|
11
|
-
* via `onChange` - it does NOT apply locally. The
|
|
11
|
+
* via `onChange` - it does NOT apply locally. The OTAlgorithm handles packaging
|
|
12
12
|
* ops into Changes, persisting them, and calling `applyChanges()` to update state.
|
|
13
13
|
*
|
|
14
14
|
* ## State Model
|
|
@@ -90,7 +90,7 @@ interface PatchesDocOptions {
|
|
|
90
90
|
* Interface for a document synchronized using JSON patches.
|
|
91
91
|
*
|
|
92
92
|
* This is the app-facing interface. The doc captures user changes as JSON Patch
|
|
93
|
-
* ops and emits them via onChange. The
|
|
93
|
+
* ops and emits them via onChange. The algorithm handles packaging ops into Changes,
|
|
94
94
|
* persisting them, and updating the doc's state.
|
|
95
95
|
*
|
|
96
96
|
* This interface is implemented by both OTDoc (Operational Transformation)
|
|
@@ -112,7 +112,7 @@ interface PatchesDoc<T extends object = object> {
|
|
|
112
112
|
/**
|
|
113
113
|
* Subscribe to be notified when the user makes local changes.
|
|
114
114
|
* Emits the JSON Patch ops captured from the change() call.
|
|
115
|
-
* The
|
|
115
|
+
* The algorithm handles packaging these into Changes.
|
|
116
116
|
*/
|
|
117
117
|
readonly onChange: Signal<(ops: JSONPatchOp[]) => void>;
|
|
118
118
|
/** Subscribe to be notified whenever state changes from any source. */
|
|
@@ -123,7 +123,7 @@ interface PatchesDoc<T extends object = object> {
|
|
|
123
123
|
subscribe(onUpdate: (newValue: T) => void): Unsubscriber;
|
|
124
124
|
/**
|
|
125
125
|
* Captures an update to the document, emitting JSON Patch ops via onChange.
|
|
126
|
-
* Does NOT apply locally - the
|
|
126
|
+
* Does NOT apply locally - the algorithm handles state updates.
|
|
127
127
|
* @param mutator Function that uses JSONPatch methods with type-safe paths.
|
|
128
128
|
*/
|
|
129
129
|
change(mutator: ChangeMutator<T>): void;
|
|
@@ -134,11 +134,11 @@ interface PatchesDoc<T extends object = object> {
|
|
|
134
134
|
* Contains shared state and methods used by both OTDoc and LWWDoc.
|
|
135
135
|
*
|
|
136
136
|
* The `change()` method captures ops and emits them via `onChange` - it does NOT
|
|
137
|
-
* apply locally. The
|
|
137
|
+
* apply locally. The algorithm handles packaging ops, persisting them, and updating
|
|
138
138
|
* the doc's state via `applyChanges()`.
|
|
139
139
|
*
|
|
140
140
|
* Internal methods (updateSyncing, applyChanges, import) are on this class but not
|
|
141
|
-
* on the PatchesDoc interface, as they're only used by
|
|
141
|
+
* on the PatchesDoc interface, as they're only used by Algorithm and PatchesSync.
|
|
142
142
|
*/
|
|
143
143
|
declare abstract class BaseDoc<T extends object = object> implements PatchesDoc<T> {
|
|
144
144
|
protected _id: string;
|
|
@@ -147,7 +147,7 @@ declare abstract class BaseDoc<T extends object = object> implements PatchesDoc<
|
|
|
147
147
|
/**
|
|
148
148
|
* Subscribe to be notified when the user makes local changes.
|
|
149
149
|
* Emits the JSON Patch ops captured from the change() call.
|
|
150
|
-
* The
|
|
150
|
+
* The algorithm handles packaging these into Changes.
|
|
151
151
|
*/
|
|
152
152
|
readonly onChange: Signal<(ops: JSONPatchOp[]) => void>;
|
|
153
153
|
/** Subscribe to be notified whenever state changes from any source. */
|
|
@@ -174,7 +174,7 @@ declare abstract class BaseDoc<T extends object = object> implements PatchesDoc<
|
|
|
174
174
|
subscribe(onUpdate: (newValue: T) => void): Unsubscriber;
|
|
175
175
|
/**
|
|
176
176
|
* Captures an update to the document, emitting JSON Patch ops via onChange.
|
|
177
|
-
* Does NOT apply locally - the
|
|
177
|
+
* Does NOT apply locally - the algorithm handles state updates via applyChanges.
|
|
178
178
|
* @param mutator Function that uses JSONPatch methods with type-safe paths.
|
|
179
179
|
*/
|
|
180
180
|
change(mutator: ChangeMutator<T>): void;
|
|
@@ -186,7 +186,7 @@ declare abstract class BaseDoc<T extends object = object> implements PatchesDoc<
|
|
|
186
186
|
updateSyncing(newSyncing: SyncingState): void;
|
|
187
187
|
/**
|
|
188
188
|
* Applies changes to the document state.
|
|
189
|
-
* Called by
|
|
189
|
+
* Called by Algorithm for local changes and broadcasts - not part of PatchesDoc interface.
|
|
190
190
|
*
|
|
191
191
|
* For OT: Distinguishes committed (committedAt > 0) vs pending (committedAt === 0) changes.
|
|
192
192
|
* For LWW: Applies all ops from changes and updates metadata.
|
|
@@ -33,7 +33,7 @@ declare function consolidateOps(existingOps: JSONPatchOp[], newOps: JSONPatchOp[
|
|
|
33
33
|
opsToReturn: JSONPatchOp[];
|
|
34
34
|
};
|
|
35
35
|
/**
|
|
36
|
-
* Any delta ops that aren't combined in consolidateOps need to be converted to replace ops.
|
|
36
|
+
* Any delta ops that aren't combined in consolidateOps need to be converted to replace/remove ops.
|
|
37
37
|
*/
|
|
38
38
|
declare function convertDeltaOps(ops: JSONPatchOp[]): JSONPatchOp[];
|
|
39
39
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import "../../chunk-IZ2YBCUP.js";
|
|
2
2
|
import { applyBitmask, combineBitmasks } from "../../json-patch/ops/bitmask.js";
|
|
3
|
+
import { isEmptyContainer } from "../../json-patch/utils/softWrites.js";
|
|
3
4
|
const combinableOps = {
|
|
4
5
|
"@inc": {
|
|
5
6
|
apply: (a, b) => a + b,
|
|
@@ -33,6 +34,9 @@ function consolidateFieldOp(existing, incoming) {
|
|
|
33
34
|
}
|
|
34
35
|
return { ...incoming, op, value };
|
|
35
36
|
}
|
|
37
|
+
if (isSoftOp(incoming)) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
36
40
|
if (isExistingNewer(existing.ts, incoming.ts)) {
|
|
37
41
|
return null;
|
|
38
42
|
}
|
|
@@ -58,6 +62,19 @@ function consolidateOps(existingOps, newOps) {
|
|
|
58
62
|
opsToSave.push(consolidated);
|
|
59
63
|
}
|
|
60
64
|
} else {
|
|
65
|
+
if (isSoftOp(newOp)) {
|
|
66
|
+
let dataExists = false;
|
|
67
|
+
for (const existingPath of existingByPath.keys()) {
|
|
68
|
+
if (existingPath.startsWith(newOp.path + "/")) {
|
|
69
|
+
dataExists = true;
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
if (!dataExists) {
|
|
74
|
+
dataExists = pathExistsInParentOp(newOp.path, existingByPath);
|
|
75
|
+
}
|
|
76
|
+
if (dataExists) continue;
|
|
77
|
+
}
|
|
61
78
|
for (const existingPath of existingByPath.keys()) {
|
|
62
79
|
if (existingPath.startsWith(newOp.path + "/")) {
|
|
63
80
|
pathsToDelete.add(existingPath);
|
|
@@ -70,6 +87,7 @@ function consolidateOps(existingOps, newOps) {
|
|
|
70
87
|
}
|
|
71
88
|
function convertDeltaOps(ops) {
|
|
72
89
|
return ops.map((op) => {
|
|
90
|
+
if (op.op === "remove") return op;
|
|
73
91
|
const combiner = combinableOps[op.op];
|
|
74
92
|
const value = typeof op.value === "string" ? "" : 0;
|
|
75
93
|
if (combiner) return { ...op, op: "replace", value: combiner.apply(value, op.value) };
|
|
@@ -92,6 +110,30 @@ function parentFixes(path, existing) {
|
|
|
92
110
|
}
|
|
93
111
|
return pathsToDelete;
|
|
94
112
|
}
|
|
113
|
+
function pathExistsInParentOp(path, existingByPath) {
|
|
114
|
+
let parent = path;
|
|
115
|
+
while (parent.lastIndexOf("/") > 0) {
|
|
116
|
+
parent = parent.substring(0, parent.lastIndexOf("/"));
|
|
117
|
+
const parentOp = existingByPath.get(parent);
|
|
118
|
+
if (parentOp && isObject(parentOp.value)) {
|
|
119
|
+
const remainingKeys = path.substring(parent.length + 1).split("/");
|
|
120
|
+
let current = parentOp.value;
|
|
121
|
+
let found = true;
|
|
122
|
+
for (const key of remainingKeys) {
|
|
123
|
+
if (!isObject(current) || !(key in current)) {
|
|
124
|
+
found = false;
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
current = current[key];
|
|
128
|
+
}
|
|
129
|
+
if (found) return true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
function isSoftOp(op) {
|
|
135
|
+
return op.soft === true || op.op === "add" && isEmptyContainer(op.value);
|
|
136
|
+
}
|
|
95
137
|
function isObject(value) {
|
|
96
138
|
return value !== null && typeof value === "object";
|
|
97
139
|
}
|
package/dist/client/BaseDoc.d.ts
CHANGED
package/dist/client/BaseDoc.js
CHANGED
|
@@ -8,7 +8,7 @@ class BaseDoc {
|
|
|
8
8
|
/**
|
|
9
9
|
* Subscribe to be notified when the user makes local changes.
|
|
10
10
|
* Emits the JSON Patch ops captured from the change() call.
|
|
11
|
-
* The
|
|
11
|
+
* The algorithm handles packaging these into Changes.
|
|
12
12
|
*/
|
|
13
13
|
onChange = signal();
|
|
14
14
|
/** Subscribe to be notified whenever state changes from any source. */
|
|
@@ -44,7 +44,7 @@ class BaseDoc {
|
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
46
|
* Captures an update to the document, emitting JSON Patch ops via onChange.
|
|
47
|
-
* Does NOT apply locally - the
|
|
47
|
+
* Does NOT apply locally - the algorithm handles state updates via applyChanges.
|
|
48
48
|
* @param mutator Function that uses JSONPatch methods with type-safe paths.
|
|
49
49
|
*/
|
|
50
50
|
change(mutator) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { JSONPatchOp } from '../json-patch/types.js';
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
|
-
import { a as PatchesDoc } from '../BaseDoc-
|
|
3
|
+
import { a as PatchesDoc } from '../BaseDoc-_Rsau70J.js';
|
|
4
4
|
import { PatchesStore, TrackedDoc } from './PatchesStore.js';
|
|
5
5
|
import '../json-patch/JSONPatch.js';
|
|
6
6
|
import '@dabble/delta';
|
|
@@ -7,10 +7,10 @@ import '@dabble/delta';
|
|
|
7
7
|
import '../json-patch/types.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* IndexedDB store providing common database operations for all sync
|
|
10
|
+
* IndexedDB store providing common database operations for all sync algorithms.
|
|
11
11
|
*
|
|
12
12
|
* Can be used as a standalone store or as a shared database connection
|
|
13
|
-
* for multiple
|
|
13
|
+
* for multiple algorithm-specific stores (OT, LWW).
|
|
14
14
|
*
|
|
15
15
|
* Provides:
|
|
16
16
|
* - Database lifecycle management (open, close, delete)
|
|
@@ -18,7 +18,7 @@ import '../json-patch/types.js';
|
|
|
18
18
|
* - Document tracking (listDocs, trackDocs, untrackDocs)
|
|
19
19
|
* - Basic document operations (deleteDoc, confirmDeleteDoc)
|
|
20
20
|
* - Revision tracking
|
|
21
|
-
* - Extensibility via onUpgrade signal for
|
|
21
|
+
* - Extensibility via onUpgrade signal for algorithm-specific stores
|
|
22
22
|
*/
|
|
23
23
|
declare class IndexedDBStore implements PatchesStore {
|
|
24
24
|
private static readonly DB_VERSION;
|
|
@@ -26,13 +26,13 @@ declare class IndexedDBStore implements PatchesStore {
|
|
|
26
26
|
protected dbName?: string;
|
|
27
27
|
protected dbPromise: Deferred<IDBDatabase>;
|
|
28
28
|
/**
|
|
29
|
-
* Signal emitted during database upgrade, allowing
|
|
29
|
+
* Signal emitted during database upgrade, allowing algorithm-specific stores
|
|
30
30
|
* to create their object stores.
|
|
31
31
|
*/
|
|
32
32
|
readonly onUpgrade: Signal<(db: IDBDatabase, oldVersion: number, transaction: IDBTransaction) => void>;
|
|
33
33
|
constructor(dbName?: string);
|
|
34
34
|
/**
|
|
35
|
-
* Creates shared object stores used by all sync
|
|
35
|
+
* Creates shared object stores used by all sync algorithms.
|
|
36
36
|
*/
|
|
37
37
|
protected createSharedStores(db: IDBDatabase, _oldVersion: number, _transaction: IDBTransaction): void;
|
|
38
38
|
protected initDB(): Promise<void>;
|
|
@@ -52,19 +52,19 @@ declare class IndexedDBStore implements PatchesStore {
|
|
|
52
52
|
transaction(storeNames: string[], mode: IDBTransactionMode): Promise<[IDBTransactionWrapper, ...IDBStoreWrapper[]]>;
|
|
53
53
|
/**
|
|
54
54
|
* Retrieves the current document snapshot from storage.
|
|
55
|
-
* Implementation varies by sync
|
|
56
|
-
* This base implementation throws an error - override in
|
|
55
|
+
* Implementation varies by sync algorithm (OT vs LWW).
|
|
56
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
57
57
|
*/
|
|
58
58
|
getDoc(_docId: string): Promise<PatchesSnapshot | undefined>;
|
|
59
59
|
/**
|
|
60
60
|
* Saves the current document state to persistent storage.
|
|
61
|
-
* Implementation varies by sync
|
|
62
|
-
* This base implementation throws an error - override in
|
|
61
|
+
* Implementation varies by sync algorithm.
|
|
62
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
63
63
|
*/
|
|
64
64
|
saveDoc(_docId: string, _docState: PatchesState): Promise<void>;
|
|
65
65
|
/**
|
|
66
66
|
* Completely remove all data for this docId and mark it as deleted (tombstone).
|
|
67
|
-
* This base implementation throws an error - override in
|
|
67
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
68
68
|
*/
|
|
69
69
|
deleteDoc(_docId: string): Promise<void>;
|
|
70
70
|
/**
|
|
@@ -88,7 +88,7 @@ declare class IndexedDBStore implements PatchesStore {
|
|
|
88
88
|
/**
|
|
89
89
|
* Untrack a document.
|
|
90
90
|
* @param docIds - The IDs of the documents to untrack.
|
|
91
|
-
* This base implementation throws an error - override in
|
|
91
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
92
92
|
*/
|
|
93
93
|
untrackDocs(_docIds: string[]): Promise<void>;
|
|
94
94
|
/**
|
|
@@ -7,7 +7,7 @@ class IndexedDBStore {
|
|
|
7
7
|
dbName;
|
|
8
8
|
dbPromise;
|
|
9
9
|
/**
|
|
10
|
-
* Signal emitted during database upgrade, allowing
|
|
10
|
+
* Signal emitted during database upgrade, allowing algorithm-specific stores
|
|
11
11
|
* to create their object stores.
|
|
12
12
|
*/
|
|
13
13
|
onUpgrade = signal();
|
|
@@ -22,7 +22,7 @@ class IndexedDBStore {
|
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Creates shared object stores used by all sync
|
|
25
|
+
* Creates shared object stores used by all sync algorithms.
|
|
26
26
|
*/
|
|
27
27
|
createSharedStores(db, _oldVersion, _transaction) {
|
|
28
28
|
if (!db.objectStoreNames.contains("docs")) {
|
|
@@ -94,30 +94,30 @@ class IndexedDBStore {
|
|
|
94
94
|
const stores = storeNames.map((name) => tx.getStore(name));
|
|
95
95
|
return [tx, ...stores];
|
|
96
96
|
}
|
|
97
|
-
// ───
|
|
98
|
-
// These are implemented by
|
|
97
|
+
// ─── Algorithm-Specific Methods ──────────────────────────────────────────
|
|
98
|
+
// These are implemented by algorithm-specific stores (OT, LWW)
|
|
99
99
|
/**
|
|
100
100
|
* Retrieves the current document snapshot from storage.
|
|
101
|
-
* Implementation varies by sync
|
|
102
|
-
* This base implementation throws an error - override in
|
|
101
|
+
* Implementation varies by sync algorithm (OT vs LWW).
|
|
102
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
103
103
|
*/
|
|
104
104
|
async getDoc(_docId) {
|
|
105
|
-
throw new Error("getDoc must be implemented by
|
|
105
|
+
throw new Error("getDoc must be implemented by algorithm-specific store");
|
|
106
106
|
}
|
|
107
107
|
/**
|
|
108
108
|
* Saves the current document state to persistent storage.
|
|
109
|
-
* Implementation varies by sync
|
|
110
|
-
* This base implementation throws an error - override in
|
|
109
|
+
* Implementation varies by sync algorithm.
|
|
110
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
111
111
|
*/
|
|
112
112
|
async saveDoc(_docId, _docState) {
|
|
113
|
-
throw new Error("saveDoc must be implemented by
|
|
113
|
+
throw new Error("saveDoc must be implemented by algorithm-specific store");
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* Completely remove all data for this docId and mark it as deleted (tombstone).
|
|
117
|
-
* This base implementation throws an error - override in
|
|
117
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
118
118
|
*/
|
|
119
119
|
async deleteDoc(_docId) {
|
|
120
|
-
throw new Error("deleteDoc must be implemented by
|
|
120
|
+
throw new Error("deleteDoc must be implemented by algorithm-specific store");
|
|
121
121
|
}
|
|
122
122
|
/**
|
|
123
123
|
* Confirm the deletion of a document.
|
|
@@ -180,10 +180,10 @@ class IndexedDBStore {
|
|
|
180
180
|
/**
|
|
181
181
|
* Untrack a document.
|
|
182
182
|
* @param docIds - The IDs of the documents to untrack.
|
|
183
|
-
* This base implementation throws an error - override in
|
|
183
|
+
* This base implementation throws an error - override in algorithm-specific stores.
|
|
184
184
|
*/
|
|
185
185
|
async untrackDocs(_docIds) {
|
|
186
|
-
throw new Error("untrackDocs must be implemented by
|
|
186
|
+
throw new Error("untrackDocs must be implemented by algorithm-specific store");
|
|
187
187
|
}
|
|
188
188
|
/**
|
|
189
189
|
* Returns the last committed revision for a document.
|
|
@@ -2,7 +2,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
|
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
3
|
import { ClientAlgorithm } from './ClientAlgorithm.js';
|
|
4
4
|
import { LWWClientStore } from './LWWClientStore.js';
|
|
5
|
-
import { a as PatchesDoc } from '../BaseDoc-
|
|
5
|
+
import { a as PatchesDoc } from '../BaseDoc-_Rsau70J.js';
|
|
6
6
|
import { TrackedDoc } from './PatchesStore.js';
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
package/dist/client/LWWDoc.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
2
|
-
import { B as BaseDoc } from '../BaseDoc-
|
|
2
|
+
import { B as BaseDoc } from '../BaseDoc-_Rsau70J.js';
|
|
3
3
|
import '../json-patch/JSONPatch.js';
|
|
4
4
|
import '@dabble/delta';
|
|
5
5
|
import '../json-patch/types.js';
|
|
@@ -9,13 +9,13 @@ import '../event-signal.js';
|
|
|
9
9
|
* LWW (Last-Write-Wins) document implementation.
|
|
10
10
|
*
|
|
11
11
|
* The `change()` method (inherited from BaseDoc) captures ops and emits them
|
|
12
|
-
* via `onChange` - it does NOT apply locally. The
|
|
12
|
+
* via `onChange` - it does NOT apply locally. The LWWAlgorithm handles:
|
|
13
13
|
* - Packaging ops with timestamps
|
|
14
14
|
* - Merging with pending fields
|
|
15
15
|
* - Updating the doc's state via `applyChanges()`
|
|
16
16
|
*
|
|
17
17
|
* Unlike OTDoc, LWWDoc doesn't need to track committed vs pending state
|
|
18
|
-
* separately - the
|
|
18
|
+
* separately - the algorithm handles all conflict resolution by timestamp.
|
|
19
19
|
*
|
|
20
20
|
* ## Wire Efficiency
|
|
21
21
|
* For Worker-Tab communication, `applyChanges()` sends only changes over the wire,
|
|
@@ -9,7 +9,7 @@ import '../event-signal.js';
|
|
|
9
9
|
import '../utils/deferred.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* IndexedDB store implementation for Last-Writer-Wins (LWW) sync
|
|
12
|
+
* IndexedDB store implementation for Last-Writer-Wins (LWW) sync algorithm.
|
|
13
13
|
*
|
|
14
14
|
* Creates stores:
|
|
15
15
|
* - docs<{ docId: string; committedRev: number; deleted?: boolean }> (primary key: docId) [shared with OT]
|
|
@@ -2,7 +2,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
|
|
|
2
2
|
import { PatchesSnapshot, Change } from '../types.js';
|
|
3
3
|
import { ClientAlgorithm } from './ClientAlgorithm.js';
|
|
4
4
|
import { OTClientStore } from './OTClientStore.js';
|
|
5
|
-
import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-
|
|
5
|
+
import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-_Rsau70J.js';
|
|
6
6
|
import { TrackedDoc } from './PatchesStore.js';
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
package/dist/client/OTDoc.d.ts
CHANGED
|
@@ -9,7 +9,7 @@ import '../event-signal.js';
|
|
|
9
9
|
import '../utils/deferred.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* IndexedDB store implementation for Operational Transformation (OT) sync
|
|
12
|
+
* IndexedDB store implementation for Operational Transformation (OT) sync algorithm.
|
|
13
13
|
*
|
|
14
14
|
* Creates stores:
|
|
15
15
|
* - snapshots<{ docId: string; rev: number; state: any }> (primary key: docId) [shared]
|
package/dist/client/Patches.d.ts
CHANGED
|
@@ -2,11 +2,20 @@ import { Unsubscriber, Signal } from '../event-signal.js';
|
|
|
2
2
|
import { JSONPatchOp } from '../json-patch/types.js';
|
|
3
3
|
import { Change } from '../types.js';
|
|
4
4
|
import { ClientAlgorithm } from './ClientAlgorithm.js';
|
|
5
|
-
import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-
|
|
5
|
+
import { P as PatchesDocOptions, a as PatchesDoc } from '../BaseDoc-_Rsau70J.js';
|
|
6
6
|
import { AlgorithmName } from './PatchesStore.js';
|
|
7
7
|
import '../json-patch/JSONPatch.js';
|
|
8
8
|
import '@dabble/delta';
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Options for opening a document, passed through to `patches.openDoc()`.
|
|
12
|
+
*/
|
|
13
|
+
interface OpenDocOptions {
|
|
14
|
+
/** Optional metadata to attach to the document. */
|
|
15
|
+
metadata?: Record<string, any>;
|
|
16
|
+
/** Override the algorithm for this document (defaults to the Patches instance default). */
|
|
17
|
+
algorithm?: AlgorithmName;
|
|
18
|
+
}
|
|
10
19
|
/**
|
|
11
20
|
* Options for creating a Patches instance.
|
|
12
21
|
* Provides algorithms map and optional default algorithm.
|
|
@@ -85,10 +94,7 @@ declare class Patches {
|
|
|
85
94
|
* @param opts - Optional metadata and algorithm override.
|
|
86
95
|
* @returns The opened PatchesDoc instance.
|
|
87
96
|
*/
|
|
88
|
-
openDoc<T extends object>(docId: string, opts?:
|
|
89
|
-
metadata?: Record<string, any>;
|
|
90
|
-
algorithm?: AlgorithmName;
|
|
91
|
-
}): Promise<PatchesDoc<T>>;
|
|
97
|
+
openDoc<T extends object>(docId: string, opts?: OpenDocOptions): Promise<PatchesDoc<T>>;
|
|
92
98
|
/**
|
|
93
99
|
* Closes an open document by ID, removing listeners and optionally untracking it.
|
|
94
100
|
* @param docId - The document ID to close.
|
|
@@ -122,4 +128,4 @@ declare class Patches {
|
|
|
122
128
|
protected _handleDocChange<T extends object>(docId: string, ops: JSONPatchOp[], doc: PatchesDoc<T>, algorithm: ClientAlgorithm, metadata: Record<string, any>): Promise<void>;
|
|
123
129
|
}
|
|
124
130
|
|
|
125
|
-
export { Patches, type PatchesOptions };
|
|
131
|
+
export { type OpenDocOptions, Patches, type PatchesOptions };
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import '../event-signal.js';
|
|
2
2
|
import '../json-patch/types.js';
|
|
3
3
|
import '../types.js';
|
|
4
|
-
export { O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-
|
|
4
|
+
export { O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-_Rsau70J.js';
|
|
5
5
|
import '../json-patch/JSONPatch.js';
|
|
6
6
|
import '@dabble/delta';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { AlgorithmName } from './PatchesStore.js';
|
|
2
2
|
import { Patches } from './Patches.js';
|
|
3
|
-
import { P as PatchesDocOptions } from '../BaseDoc-
|
|
3
|
+
import { P as PatchesDocOptions } from '../BaseDoc-_Rsau70J.js';
|
|
4
4
|
import '../types.js';
|
|
5
5
|
import '../json-patch/JSONPatch.js';
|
|
6
6
|
import '@dabble/delta';
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-
|
|
1
|
+
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-_Rsau70J.js';
|
|
2
2
|
export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createLWWIndexedDBPatches, createLWWPatches, createMultiAlgorithmIndexedDBPatches, createMultiAlgorithmPatches, createOTIndexedDBPatches, createOTPatches } from './factories.js';
|
|
3
3
|
export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './IndexedDBStore.js';
|
|
4
4
|
export { OTIndexedDBStore } from './OTIndexedDBStore.js';
|
|
@@ -9,7 +9,7 @@ export { LWWDoc } from './LWWDoc.js';
|
|
|
9
9
|
export { LWWAlgorithm } from './LWWAlgorithm.js';
|
|
10
10
|
export { LWWBatcher } from './LWWBatcher.js';
|
|
11
11
|
export { OTAlgorithm } from './OTAlgorithm.js';
|
|
12
|
-
export { Patches, PatchesOptions } from './Patches.js';
|
|
12
|
+
export { OpenDocOptions, Patches, PatchesOptions } from './Patches.js';
|
|
13
13
|
export { PatchesHistoryClient } from './PatchesHistoryClient.js';
|
|
14
14
|
export { AlgorithmName, PatchesStore, TrackedDoc } from './PatchesStore.js';
|
|
15
15
|
export { OTClientStore } from './OTClientStore.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { Delta } from '@dabble/delta';
|
|
2
|
-
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from './BaseDoc-
|
|
2
|
+
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from './BaseDoc-_Rsau70J.js';
|
|
3
3
|
export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createLWWIndexedDBPatches, createLWWPatches, createMultiAlgorithmIndexedDBPatches, createMultiAlgorithmPatches, createOTIndexedDBPatches, createOTPatches } from './client/factories.js';
|
|
4
4
|
export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './client/IndexedDBStore.js';
|
|
5
5
|
export { OTIndexedDBStore } from './client/OTIndexedDBStore.js';
|
|
@@ -10,7 +10,7 @@ export { LWWDoc } from './client/LWWDoc.js';
|
|
|
10
10
|
export { LWWAlgorithm } from './client/LWWAlgorithm.js';
|
|
11
11
|
export { LWWBatcher } from './client/LWWBatcher.js';
|
|
12
12
|
export { OTAlgorithm } from './client/OTAlgorithm.js';
|
|
13
|
-
export { Patches, PatchesOptions } from './client/Patches.js';
|
|
13
|
+
export { OpenDocOptions, Patches, PatchesOptions } from './client/Patches.js';
|
|
14
14
|
export { PatchesHistoryClient } from './client/PatchesHistoryClient.js';
|
|
15
15
|
export { AlgorithmName, PatchesStore, TrackedDoc } from './client/PatchesStore.js';
|
|
16
16
|
export { OTClientStore } from './client/OTClientStore.js';
|
|
@@ -42,7 +42,7 @@ declare class PatchesClient implements PatchesAPI {
|
|
|
42
42
|
* @param docId - The ID of the document.
|
|
43
43
|
* @returns A promise resolving with the document snapshot.
|
|
44
44
|
*/
|
|
45
|
-
getDoc<T = any>(docId: string
|
|
45
|
+
getDoc<T = any>(docId: string): Promise<PatchesState<T>>;
|
|
46
46
|
/**
|
|
47
47
|
* Gets changes that occurred for a document after a specific revision number.
|
|
48
48
|
* @param docId - The ID of the document.
|
|
@@ -49,8 +49,8 @@ class PatchesClient {
|
|
|
49
49
|
* @param docId - The ID of the document.
|
|
50
50
|
* @returns A promise resolving with the document snapshot.
|
|
51
51
|
*/
|
|
52
|
-
async getDoc(docId
|
|
53
|
-
return this.rpc.call("getDoc", docId
|
|
52
|
+
async getDoc(docId) {
|
|
53
|
+
return this.rpc.call("getDoc", docId);
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Gets changes that occurred for a document after a specific revision number.
|
package/dist/net/index.d.ts
CHANGED
|
@@ -18,7 +18,7 @@ import '../algorithms/ot/shared/changeBatching.js';
|
|
|
18
18
|
import '../client/Patches.js';
|
|
19
19
|
import '../json-patch/types.js';
|
|
20
20
|
import '../client/ClientAlgorithm.js';
|
|
21
|
-
import '../BaseDoc-
|
|
21
|
+
import '../BaseDoc-_Rsau70J.js';
|
|
22
22
|
import '../client/PatchesStore.js';
|
|
23
23
|
import '../server/types.js';
|
|
24
24
|
import '../utils/deferred.js';
|
|
@@ -24,6 +24,7 @@ class JSONRPCClient {
|
|
|
24
24
|
*/
|
|
25
25
|
async call(method, ...args) {
|
|
26
26
|
const id = this.nextId++;
|
|
27
|
+
while (args.length > 0 && args[args.length - 1] === void 0) args.pop();
|
|
27
28
|
const params = args.length > 0 ? args : void 0;
|
|
28
29
|
const message = { jsonrpc: "2.0", id, method, params };
|
|
29
30
|
return new Promise((resolve, reject) => {
|
|
@@ -38,6 +39,7 @@ class JSONRPCClient {
|
|
|
38
39
|
* @param args - The arguments to pass to the remote procedure (sent as array)
|
|
39
40
|
*/
|
|
40
41
|
notify(method, ...args) {
|
|
42
|
+
while (args.length > 0 && args[args.length - 1] === void 0) args.pop();
|
|
41
43
|
const params = args.length > 0 ? args : void 0;
|
|
42
44
|
const message = { jsonrpc: "2.0", method, params };
|
|
43
45
|
this.transport.send(JSON.stringify(message));
|
|
@@ -52,6 +52,10 @@ class JSONRPCServer {
|
|
|
52
52
|
throw new Error(`Method '${method}' not found on object`);
|
|
53
53
|
}
|
|
54
54
|
this.registerMethod(method, async (...args) => {
|
|
55
|
+
const docId = args[0];
|
|
56
|
+
if (typeof docId !== "string" || !docId) {
|
|
57
|
+
throw new StatusError(400, `INVALID_REQUEST: docId is required (got ${docId === "" ? "empty string" : String(docId)})`);
|
|
58
|
+
}
|
|
55
59
|
const ctx = getAuthContext();
|
|
56
60
|
await this.assertAccess(access, ctx, method, args);
|
|
57
61
|
return obj[method](...args);
|
|
@@ -132,7 +136,9 @@ class JSONRPCServer {
|
|
|
132
136
|
async assertAccess(access, ctx, method, args) {
|
|
133
137
|
if (!this.auth) return;
|
|
134
138
|
const docId = args?.[0];
|
|
135
|
-
if (typeof docId !== "string")
|
|
139
|
+
if (typeof docId !== "string" || !docId) {
|
|
140
|
+
throw new StatusError(400, `INVALID_REQUEST: docId is required (got ${docId === "" ? "empty string" : String(docId)})`);
|
|
141
|
+
}
|
|
136
142
|
const ok = await this.auth.canAccess(ctx, docId, access, method);
|
|
137
143
|
if (!ok) {
|
|
138
144
|
throw new StatusError(401, `${access.toUpperCase()}_FORBIDDEN:${docId}`);
|
|
@@ -119,7 +119,7 @@ interface PatchesAPI {
|
|
|
119
119
|
*/
|
|
120
120
|
unsubscribe(ids: string | string[]): Promise<void>;
|
|
121
121
|
/** Get the latest version of a document and changes since the last version. */
|
|
122
|
-
getDoc(docId: string
|
|
122
|
+
getDoc(docId: string): Promise<PatchesState>;
|
|
123
123
|
/** Get changes that occurred after a specific revision. */
|
|
124
124
|
getChangesSince(docId: string, rev: number): Promise<Change[]>;
|
|
125
125
|
/** Apply a set of changes from the client to a document. Returns the committed changes. */
|
|
@@ -42,20 +42,14 @@ declare class WebSocketServer {
|
|
|
42
42
|
/**
|
|
43
43
|
* Subscribes the client to one or more documents to receive real-time updates.
|
|
44
44
|
* If a document has been deleted (tombstone exists), sends immediate docDeleted notification.
|
|
45
|
-
* @param
|
|
46
|
-
* @param params.ids - Document ID or IDs to subscribe to
|
|
45
|
+
* @param ids - Document ID or IDs to subscribe to
|
|
47
46
|
*/
|
|
48
|
-
subscribe(
|
|
49
|
-
ids: string | string[];
|
|
50
|
-
}): Promise<string[]>;
|
|
47
|
+
subscribe(ids: string | string[]): Promise<string[]>;
|
|
51
48
|
/**
|
|
52
49
|
* Unsubscribes the client from one or more documents.
|
|
53
|
-
* @param
|
|
54
|
-
* @param params.ids - Document ID or IDs to unsubscribe from
|
|
50
|
+
* @param ids - Document ID or IDs to unsubscribe from
|
|
55
51
|
*/
|
|
56
|
-
unsubscribe(
|
|
57
|
-
ids: string | string[];
|
|
58
|
-
}): Promise<string[]>;
|
|
52
|
+
unsubscribe(ids: string | string[]): Promise<string[]>;
|
|
59
53
|
}
|
|
60
54
|
|
|
61
55
|
export { WebSocketServer, type WebSocketServerOptions };
|