@dabble/patches 0.4.5 → 0.4.7
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/algorithms/client/applyCommittedChanges.d.ts +8 -2
- package/dist/algorithms/client/applyCommittedChanges.js +30 -38
- package/dist/algorithms/client/batching.d.ts +8 -2
- package/dist/algorithms/client/batching.js +38 -37
- package/dist/algorithms/client/breakChange.d.ts +8 -2
- package/dist/algorithms/client/breakChange.js +191 -240
- package/dist/algorithms/client/createStateFromSnapshot.d.ts +8 -2
- package/dist/algorithms/client/createStateFromSnapshot.js +7 -8
- package/dist/algorithms/client/getJSONByteSize.d.ts +3 -1
- package/dist/algorithms/client/getJSONByteSize.js +12 -11
- package/dist/algorithms/client/makeChange.d.ts +8 -2
- package/dist/algorithms/client/makeChange.js +28 -36
- package/dist/algorithms/server/commitChanges.d.ts +9 -3
- package/dist/algorithms/server/commitChanges.js +69 -78
- package/dist/algorithms/server/createVersion.d.ts +9 -3
- package/dist/algorithms/server/createVersion.js +21 -27
- package/dist/algorithms/server/getSnapshotAtRevision.d.ts +9 -3
- package/dist/algorithms/server/getSnapshotAtRevision.js +27 -28
- package/dist/algorithms/server/getStateAtRevision.d.ts +9 -3
- package/dist/algorithms/server/getStateAtRevision.js +13 -17
- package/dist/algorithms/server/handleOfflineSessionsAndBatches.d.ts +9 -3
- package/dist/algorithms/server/handleOfflineSessionsAndBatches.js +60 -77
- package/dist/algorithms/server/transformIncomingChanges.d.ts +8 -2
- package/dist/algorithms/server/transformIncomingChanges.js +27 -39
- package/dist/algorithms/shared/applyChanges.d.ts +8 -2
- package/dist/algorithms/shared/applyChanges.js +11 -16
- package/dist/algorithms/shared/rebaseChanges.d.ts +8 -2
- package/dist/algorithms/shared/rebaseChanges.js +30 -49
- package/dist/chunk-IZ2YBCUP.js +56 -0
- package/dist/client/InMemoryStore.d.ts +9 -3
- package/dist/client/InMemoryStore.js +92 -101
- package/dist/client/IndexedDBStore.d.ts +9 -3
- package/dist/client/IndexedDBStore.js +378 -491
- package/dist/client/Patches.d.ts +18 -13
- package/dist/client/Patches.js +152 -207
- package/dist/client/PatchesDoc.d.ts +14 -8
- package/dist/client/PatchesDoc.js +147 -154
- package/dist/client/PatchesHistoryClient.d.ts +12 -5
- package/dist/client/PatchesHistoryClient.js +110 -117
- package/dist/client/PatchesStore.d.ts +9 -3
- package/dist/client/PatchesStore.js +0 -1
- package/dist/client/index.d.ts +12 -6
- package/dist/client/index.js +5 -5
- package/dist/data/change.d.ts +9 -3
- package/dist/data/change.js +23 -15
- package/dist/data/version.d.ts +9 -3
- package/dist/data/version.js +11 -15
- package/dist/event-signal.d.ts +7 -6
- package/dist/event-signal.js +24 -39
- package/dist/index-CvQws3AB.d.ts +36 -0
- package/dist/index.d.ts +27 -5
- package/dist/index.js +10 -4
- package/dist/json-patch/JSONPatch.d.ts +9 -5
- package/dist/json-patch/JSONPatch.js +175 -183
- package/dist/json-patch/applyPatch.d.ts +5 -2
- package/dist/json-patch/applyPatch.js +27 -35
- package/dist/json-patch/composePatch.d.ts +5 -2
- package/dist/json-patch/composePatch.js +34 -34
- package/dist/json-patch/createJSONPatch.d.ts +7 -2
- package/dist/json-patch/createJSONPatch.js +11 -38
- package/dist/json-patch/index.d.ts +14 -6
- package/dist/json-patch/index.js +20 -9
- package/dist/json-patch/invertPatch.d.ts +5 -2
- package/dist/json-patch/invertPatch.js +31 -30
- package/dist/json-patch/ops/add.d.ts +5 -2
- package/dist/json-patch/ops/add.js +53 -51
- package/dist/json-patch/ops/bitmask.d.ts +8 -5
- package/dist/json-patch/ops/bitmask.js +41 -44
- package/dist/json-patch/ops/copy.d.ts +5 -2
- package/dist/json-patch/ops/copy.js +32 -33
- package/dist/json-patch/ops/increment.d.ts +5 -2
- package/dist/json-patch/ops/increment.js +21 -20
- package/dist/json-patch/ops/index.d.ts +10 -21
- package/dist/json-patch/ops/index.js +34 -24
- package/dist/json-patch/ops/move.d.ts +5 -2
- package/dist/json-patch/ops/move.js +132 -198
- package/dist/json-patch/ops/remove.d.ts +5 -2
- package/dist/json-patch/ops/remove.js +33 -30
- package/dist/json-patch/ops/replace.d.ts +5 -2
- package/dist/json-patch/ops/replace.js +45 -43
- package/dist/json-patch/ops/test.d.ts +5 -2
- package/dist/json-patch/ops/test.js +25 -21
- package/dist/json-patch/ops/text.d.ts +5 -2
- package/dist/json-patch/ops/text.js +54 -54
- package/dist/json-patch/pathProxy.d.ts +9 -3
- package/dist/json-patch/pathProxy.js +27 -48
- package/dist/json-patch/state.d.ts +5 -2
- package/dist/json-patch/state.js +11 -7
- package/dist/json-patch/transformPatch.d.ts +6 -2
- package/dist/json-patch/transformPatch.js +21 -24
- package/dist/json-patch/types.d.ts +9 -7
- package/dist/json-patch/types.js +0 -1
- package/dist/json-patch/utils/deepEqual.d.ts +3 -1
- package/dist/json-patch/utils/deepEqual.js +32 -28
- package/dist/json-patch/utils/exit.d.ts +5 -2
- package/dist/json-patch/utils/exit.js +7 -3
- package/dist/json-patch/utils/get.d.ts +5 -2
- package/dist/json-patch/utils/get.js +8 -4
- package/dist/json-patch/utils/getOpData.d.ts +5 -2
- package/dist/json-patch/utils/getOpData.js +12 -9
- package/dist/json-patch/utils/getType.d.ts +6 -3
- package/dist/json-patch/utils/getType.js +9 -4
- package/dist/json-patch/utils/index.d.ts +15 -14
- package/dist/json-patch/utils/index.js +14 -14
- package/dist/json-patch/utils/log.d.ts +4 -5
- package/dist/json-patch/utils/log.js +8 -3
- package/dist/json-patch/utils/ops.d.ts +8 -5
- package/dist/json-patch/utils/ops.js +83 -100
- package/dist/json-patch/utils/paths.d.ts +12 -9
- package/dist/json-patch/utils/paths.js +54 -51
- package/dist/json-patch/utils/pluck.d.ts +8 -5
- package/dist/json-patch/utils/pluck.js +32 -26
- package/dist/json-patch/utils/shallowCopy.d.ts +3 -1
- package/dist/json-patch/utils/shallowCopy.js +22 -18
- package/dist/json-patch/utils/softWrites.d.ts +6 -3
- package/dist/json-patch/utils/softWrites.js +17 -16
- package/dist/json-patch/utils/toArrayIndex.d.ts +3 -1
- package/dist/json-patch/utils/toArrayIndex.js +14 -10
- package/dist/json-patch/utils/toKeys.d.ts +3 -1
- package/dist/json-patch/utils/toKeys.js +15 -11
- package/dist/json-patch/utils/updateArrayIndexes.d.ts +5 -2
- package/dist/json-patch/utils/updateArrayIndexes.js +33 -37
- package/dist/json-patch/utils/updateArrayPath.d.ts +5 -2
- package/dist/json-patch/utils/updateArrayPath.js +29 -42
- package/dist/net/PatchesClient.d.ts +128 -0
- package/dist/net/PatchesClient.js +161 -0
- package/dist/net/PatchesSync.d.ts +19 -9
- package/dist/net/PatchesSync.js +291 -386
- package/dist/net/error.d.ts +3 -1
- package/dist/net/error.js +9 -6
- package/dist/net/http/FetchTransport.d.ts +21 -0
- package/dist/net/http/FetchTransport.js +34 -0
- package/dist/net/index.d.ts +26 -12
- package/dist/net/index.js +12 -10
- package/dist/net/protocol/JSONRPCClient.d.ts +11 -4
- package/dist/net/protocol/JSONRPCClient.js +95 -103
- package/dist/net/protocol/JSONRPCServer.d.ts +15 -8
- package/dist/net/protocol/JSONRPCServer.js +101 -123
- package/dist/net/protocol/types.d.ts +21 -15
- package/dist/net/protocol/types.js +0 -1
- package/dist/net/protocol/utils.d.ts +12 -0
- package/dist/net/protocol/utils.js +15 -0
- package/dist/net/types.d.ts +4 -2
- package/dist/net/types.js +0 -1
- package/dist/net/webrtc/WebRTCAwareness.d.ts +14 -4
- package/dist/net/webrtc/WebRTCAwareness.js +111 -120
- package/dist/net/webrtc/WebRTCTransport.d.ts +16 -8
- package/dist/net/webrtc/WebRTCTransport.js +149 -157
- package/dist/net/webrtc/index.d.ts +10 -2
- package/dist/net/webrtc/index.js +2 -2
- package/dist/net/websocket/AuthorizationProvider.d.ts +7 -5
- package/dist/net/websocket/AuthorizationProvider.js +12 -17
- package/dist/net/websocket/PatchesWebSocket.d.ts +14 -109
- package/dist/net/websocket/PatchesWebSocket.js +37 -184
- package/dist/net/websocket/RPCServer.d.ts +19 -10
- package/dist/net/websocket/RPCServer.js +190 -192
- package/dist/net/websocket/SignalingService.d.ts +12 -32
- package/dist/net/websocket/SignalingService.js +126 -133
- package/dist/net/websocket/WebSocketServer.d.ts +17 -4
- package/dist/net/websocket/WebSocketServer.js +64 -72
- package/dist/net/websocket/WebSocketTransport.d.ts +13 -5
- package/dist/net/websocket/WebSocketTransport.js +178 -207
- package/dist/net/websocket/onlineState.d.ts +6 -3
- package/dist/net/websocket/onlineState.js +25 -21
- package/dist/server/PatchesBranchManager.d.ts +12 -5
- package/dist/server/PatchesBranchManager.js +132 -142
- package/dist/server/PatchesHistoryManager.d.ts +11 -3
- package/dist/server/PatchesHistoryManager.js +81 -84
- package/dist/server/PatchesServer.d.ts +16 -10
- package/dist/server/PatchesServer.js +131 -137
- package/dist/server/index.d.ts +7 -2
- package/dist/server/index.js +9 -3
- package/dist/server/types.d.ts +9 -3
- package/dist/server/types.js +0 -1
- package/dist/types.d.ts +38 -19
- package/dist/types.js +1 -1
- package/dist/utils/concurrency.d.ts +7 -5
- package/dist/utils/concurrency.js +43 -53
- package/dist/utils/deferred.d.ts +4 -2
- package/dist/utils/deferred.js +25 -21
- package/package.json +13 -15
|
@@ -1,144 +1,138 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
1
|
+
import "../chunk-IZ2YBCUP.js";
|
|
2
|
+
import { commitChanges } from "../algorithms/server/commitChanges.js";
|
|
3
|
+
import { createVersion } from "../algorithms/server/createVersion.js";
|
|
4
|
+
import { getSnapshotAtRevision } from "../algorithms/server/getSnapshotAtRevision.js";
|
|
5
|
+
import { getStateAtRevision } from "../algorithms/server/getStateAtRevision.js";
|
|
6
|
+
import { applyChanges } from "../algorithms/shared/applyChanges.js";
|
|
7
|
+
import { createChange } from "../data/change.js";
|
|
8
|
+
import { signal } from "../event-signal.js";
|
|
9
|
+
import { createJSONPatch } from "../json-patch/createJSONPatch.js";
|
|
10
|
+
class PatchesServer {
|
|
11
|
+
constructor(store, options = {}) {
|
|
12
|
+
this.store = store;
|
|
13
|
+
this.sessionTimeoutMillis = (options.sessionTimeoutMinutes ?? 30) * 60 * 1e3;
|
|
14
|
+
}
|
|
15
|
+
sessionTimeoutMillis;
|
|
16
|
+
/** Notifies listeners whenever a batch of changes is *successfully* committed. */
|
|
17
|
+
onChangesCommitted = signal();
|
|
18
|
+
/** Notifies listeners when a document is deleted. */
|
|
19
|
+
onDocDeleted = signal();
|
|
20
|
+
/**
|
|
21
|
+
* Get the state of a document at a specific revision (or the latest state if no revision is provided).
|
|
22
|
+
* @param docId - The ID of the document.
|
|
23
|
+
* @param rev - The revision number.
|
|
24
|
+
* @returns The state of the document at the specified revision.
|
|
25
|
+
*/
|
|
26
|
+
async getDoc(docId, atRev) {
|
|
27
|
+
return getStateAtRevision(this.store, docId, atRev);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the state of a document at a specific revision.
|
|
31
|
+
* @param docId - The ID of the document.
|
|
32
|
+
* @param rev - The revision number.
|
|
33
|
+
* @returns The state of the document at the specified revision.
|
|
34
|
+
*/
|
|
35
|
+
async getStateAtRevision(docId, atRev) {
|
|
36
|
+
return getStateAtRevision(this.store, docId, atRev);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Get changes that occurred after a specific revision.
|
|
40
|
+
* @param docId - The ID of the document.
|
|
41
|
+
* @param rev - The revision number.
|
|
42
|
+
* @returns The changes that occurred after the specified revision.
|
|
43
|
+
*/
|
|
44
|
+
getChangesSince(docId, rev) {
|
|
45
|
+
return this.store.listChanges(docId, { startAfter: rev });
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Commits a set of changes to a document, applying operational transformation as needed.
|
|
49
|
+
* @param docId - The ID of the document.
|
|
50
|
+
* @param changes - The changes to commit.
|
|
51
|
+
* @param originClientId - The ID of the client that initiated the commit.
|
|
52
|
+
* @returns A tuple of [committedChanges, transformedChanges] where:
|
|
53
|
+
* - committedChanges: Changes that were already committed to the server after the client's base revision
|
|
54
|
+
* - transformedChanges: The client's changes after being transformed against concurrent changes
|
|
55
|
+
*/
|
|
56
|
+
async commitChanges(docId, changes, originClientId) {
|
|
57
|
+
const [committedChanges, transformedChanges] = await commitChanges(
|
|
58
|
+
this.store,
|
|
59
|
+
docId,
|
|
60
|
+
changes,
|
|
61
|
+
this.sessionTimeoutMillis
|
|
62
|
+
);
|
|
63
|
+
if (transformedChanges.length > 0) {
|
|
64
|
+
try {
|
|
65
|
+
await this.onChangesCommitted.emit(docId, transformedChanges, originClientId);
|
|
66
|
+
} catch (error) {
|
|
67
|
+
console.error(`Failed to notify clients about committed changes for doc ${docId}:`, error);
|
|
68
|
+
}
|
|
24
69
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
70
|
+
return [committedChanges, transformedChanges];
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Make a server-side change to a document.
|
|
74
|
+
* @param mutator
|
|
75
|
+
* @returns
|
|
76
|
+
*/
|
|
77
|
+
async change(docId, mutator, metadata) {
|
|
78
|
+
const { state, rev } = await this.getDoc(docId);
|
|
79
|
+
const patch = createJSONPatch(mutator);
|
|
80
|
+
if (patch.ops.length === 0) {
|
|
81
|
+
return null;
|
|
33
82
|
}
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
// Persist and notify about newly transformed changes atomically
|
|
64
|
-
if (transformedChanges.length > 0) {
|
|
65
|
-
try {
|
|
66
|
-
// Fire event for realtime transports (WebSocket, etc.)
|
|
67
|
-
await this.onChangesCommitted.emit(docId, transformedChanges, originClientId);
|
|
68
|
-
}
|
|
69
|
-
catch (error) {
|
|
70
|
-
// If notification fails after saving, log error but don't fail the operation
|
|
71
|
-
// The changes are already committed to storage, so we can't roll back
|
|
72
|
-
console.error(`Failed to notify clients about committed changes for doc ${docId}:`, error);
|
|
73
|
-
// Consider implementing a retry mechanism or dead letter queue here
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
// Return committed changes and newly transformed changes separately
|
|
77
|
-
return [committedChanges, transformedChanges];
|
|
78
|
-
}
|
|
79
|
-
/**
|
|
80
|
-
* Make a server-side change to a document.
|
|
81
|
-
* @param mutator
|
|
82
|
-
* @returns
|
|
83
|
-
*/
|
|
84
|
-
async change(docId, mutator, metadata) {
|
|
85
|
-
const { state, rev } = await this.getDoc(docId);
|
|
86
|
-
const patch = createJSONPatch(mutator);
|
|
87
|
-
if (patch.ops.length === 0) {
|
|
88
|
-
return null;
|
|
89
|
-
}
|
|
90
|
-
// It's the baseRev that matters for sending.
|
|
91
|
-
const change = createChange(rev, rev + 1, patch.ops, metadata);
|
|
92
|
-
// Apply to local state to ensure no errors are thrown
|
|
93
|
-
patch.apply(state);
|
|
94
|
-
await this.commitChanges(docId, [change]);
|
|
95
|
-
return change;
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* Deletes a document.
|
|
99
|
-
* @param docId The document ID.
|
|
100
|
-
* @param originClientId - The ID of the client that initiated the delete operation.
|
|
101
|
-
*/
|
|
102
|
-
async deleteDoc(docId, originClientId) {
|
|
103
|
-
await this.store.deleteDoc(docId);
|
|
104
|
-
await this.onDocDeleted.emit(docId, originClientId);
|
|
105
|
-
}
|
|
106
|
-
// === Version Operations ===
|
|
107
|
-
/**
|
|
108
|
-
* Captures the current state of a document as a new version.
|
|
109
|
-
* @param docId The document ID.
|
|
110
|
-
* @param metadata Optional metadata for the version.
|
|
111
|
-
* @returns The ID of the created version.
|
|
112
|
-
*/
|
|
113
|
-
async captureCurrentVersion(docId, metadata) {
|
|
114
|
-
assertVersionMetadata(metadata);
|
|
115
|
-
const { state: initialState, changes } = await getSnapshotAtRevision(this.store, docId);
|
|
116
|
-
let state = initialState;
|
|
117
|
-
state = applyChanges(state, changes);
|
|
118
|
-
const version = await createVersion(this.store, docId, state, changes, metadata);
|
|
119
|
-
if (!version) {
|
|
120
|
-
throw new Error(`No changes to create a version for doc ${docId}.`);
|
|
121
|
-
}
|
|
122
|
-
return version.id;
|
|
83
|
+
const change = createChange(rev, rev + 1, patch.ops, metadata);
|
|
84
|
+
patch.apply(state);
|
|
85
|
+
await this.commitChanges(docId, [change]);
|
|
86
|
+
return change;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Deletes a document.
|
|
90
|
+
* @param docId The document ID.
|
|
91
|
+
* @param originClientId - The ID of the client that initiated the delete operation.
|
|
92
|
+
*/
|
|
93
|
+
async deleteDoc(docId, originClientId) {
|
|
94
|
+
await this.store.deleteDoc(docId);
|
|
95
|
+
await this.onDocDeleted.emit(docId, originClientId);
|
|
96
|
+
}
|
|
97
|
+
// === Version Operations ===
|
|
98
|
+
/**
|
|
99
|
+
* Captures the current state of a document as a new version.
|
|
100
|
+
* @param docId The document ID.
|
|
101
|
+
* @param metadata Optional metadata for the version.
|
|
102
|
+
* @returns The ID of the created version.
|
|
103
|
+
*/
|
|
104
|
+
async captureCurrentVersion(docId, metadata) {
|
|
105
|
+
assertVersionMetadata(metadata);
|
|
106
|
+
const { state: initialState, changes } = await getSnapshotAtRevision(this.store, docId);
|
|
107
|
+
let state = initialState;
|
|
108
|
+
state = applyChanges(state, changes);
|
|
109
|
+
const version = await createVersion(this.store, docId, state, changes, metadata);
|
|
110
|
+
if (!version) {
|
|
111
|
+
throw new Error(`No changes to create a version for doc ${docId}.`);
|
|
123
112
|
}
|
|
113
|
+
return version.id;
|
|
114
|
+
}
|
|
124
115
|
}
|
|
125
|
-
const nonModifiableMetadataFields = new Set([
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
116
|
+
const nonModifiableMetadataFields = /* @__PURE__ */ new Set([
|
|
117
|
+
"id",
|
|
118
|
+
"parentId",
|
|
119
|
+
"groupId",
|
|
120
|
+
"origin",
|
|
121
|
+
"branchName",
|
|
122
|
+
"startDate",
|
|
123
|
+
"endDate",
|
|
124
|
+
"rev",
|
|
125
|
+
"baseRev"
|
|
135
126
|
]);
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
throw new Error(`Cannot modify version field ${key}`);
|
|
142
|
-
}
|
|
127
|
+
function assertVersionMetadata(metadata) {
|
|
128
|
+
if (!metadata) return;
|
|
129
|
+
for (const key in metadata) {
|
|
130
|
+
if (nonModifiableMetadataFields.has(key)) {
|
|
131
|
+
throw new Error(`Cannot modify version field ${key}`);
|
|
143
132
|
}
|
|
133
|
+
}
|
|
144
134
|
}
|
|
135
|
+
export {
|
|
136
|
+
PatchesServer,
|
|
137
|
+
assertVersionMetadata
|
|
138
|
+
};
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
export { PatchesBranchManager } from './PatchesBranchManager.js';
|
|
2
2
|
export { PatchesHistoryManager } from './PatchesHistoryManager.js';
|
|
3
|
-
export { PatchesServer } from './PatchesServer.js';
|
|
4
|
-
export
|
|
3
|
+
export { PatchesServer, PatchesServerOptions } from './PatchesServer.js';
|
|
4
|
+
export { BranchingStoreBackend, PatchesStoreBackend } from './types.js';
|
|
5
|
+
import '../types.js';
|
|
6
|
+
import '../json-patch/JSONPatch.js';
|
|
7
|
+
import '@dabble/delta';
|
|
8
|
+
import '../json-patch/types.js';
|
|
9
|
+
import '../event-signal.js';
|
package/dist/server/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import "../chunk-IZ2YBCUP.js";
|
|
2
|
+
import { PatchesBranchManager } from "./PatchesBranchManager.js";
|
|
3
|
+
import { PatchesHistoryManager } from "./PatchesHistoryManager.js";
|
|
4
|
+
import { PatchesServer } from "./PatchesServer.js";
|
|
5
|
+
export {
|
|
6
|
+
PatchesBranchManager,
|
|
7
|
+
PatchesHistoryManager,
|
|
8
|
+
PatchesServer
|
|
9
|
+
};
|
package/dist/server/types.d.ts
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { Change, ListChangesOptions, PatchesState, VersionMetadata, EditableVersionMetadata, ListVersionsOptions, Branch } from '../types.js';
|
|
2
|
+
import '../json-patch/JSONPatch.js';
|
|
3
|
+
import '@dabble/delta';
|
|
4
|
+
import '../json-patch/types.js';
|
|
5
|
+
|
|
2
6
|
/**
|
|
3
7
|
* Interface for a backend storage system for patch synchronization.
|
|
4
8
|
* Defines methods needed by PatchesServer, PatchesHistoryManager, etc.
|
|
5
9
|
*/
|
|
6
|
-
|
|
10
|
+
interface PatchesStoreBackend {
|
|
7
11
|
/** Saves a batch of committed server changes. */
|
|
8
12
|
saveChanges(docId: string, changes: Change[]): Promise<void>;
|
|
9
13
|
/** Lists committed server changes based on revision numbers. */
|
|
@@ -31,7 +35,7 @@ export interface PatchesStoreBackend {
|
|
|
31
35
|
/**
|
|
32
36
|
* Extends PatchesStoreBackend with methods specifically for managing branches.
|
|
33
37
|
*/
|
|
34
|
-
|
|
38
|
+
interface BranchingStoreBackend extends PatchesStoreBackend {
|
|
35
39
|
/** Lists metadata records for branches originating from a document. */
|
|
36
40
|
listBranches(docId: string): Promise<Branch[]>;
|
|
37
41
|
/** Loads the metadata record for a specific branch ID. */
|
|
@@ -46,3 +50,5 @@ export interface BranchingStoreBackend extends PatchesStoreBackend {
|
|
|
46
50
|
*/
|
|
47
51
|
closeBranch(branchId: string): Promise<void>;
|
|
48
52
|
}
|
|
53
|
+
|
|
54
|
+
export type { BranchingStoreBackend, PatchesStoreBackend };
|
package/dist/server/types.js
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
package/dist/types.d.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
1
|
import { JSONPatch } from './json-patch/JSONPatch.js';
|
|
2
|
-
import
|
|
3
|
-
|
|
2
|
+
import { JSONPatchOp } from './json-patch/types.js';
|
|
3
|
+
import '@dabble/delta';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A change being submitted to the server. Unlike committed Change, rev and baseRev are optional.
|
|
7
|
+
* If omitted, the server fills them in using the current latest revision (apply to latest).
|
|
8
|
+
* This is useful for server-to-server operations like migrations so that you don't need to
|
|
9
|
+
* fetch the document just to get its revision number.
|
|
10
|
+
*/
|
|
11
|
+
interface ChangeInput {
|
|
4
12
|
/** Unique identifier for the change, generated client-side. */
|
|
5
13
|
id: string;
|
|
6
14
|
/** The patch operations. */
|
|
7
15
|
ops: JSONPatchOp[];
|
|
8
|
-
/**
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
|
|
16
|
+
/** Optional base revision. If omitted, server uses current revision (apply to latest). */
|
|
17
|
+
baseRev?: number;
|
|
18
|
+
/** Optional revision number. If omitted, server assigns based on current state. */
|
|
19
|
+
rev?: number;
|
|
12
20
|
/** Client-side timestamp when the change was created. */
|
|
13
21
|
created: number;
|
|
14
22
|
/** Optional batch identifier for grouping changes that belong to the same client batch (for multi-batch offline/large edits). */
|
|
@@ -16,12 +24,22 @@ export interface Change {
|
|
|
16
24
|
/** Optional arbitrary metadata associated with the change. */
|
|
17
25
|
[metadata: string]: any;
|
|
18
26
|
}
|
|
27
|
+
/**
|
|
28
|
+
* A change that has been committed to the server with assigned revision numbers.
|
|
29
|
+
* This is the canonical form of changes stored and returned by the server.
|
|
30
|
+
*/
|
|
31
|
+
interface Change extends ChangeInput {
|
|
32
|
+
/** The server revision this change was based on. */
|
|
33
|
+
baseRev: number;
|
|
34
|
+
/** The revision number assigned by the server after commit. */
|
|
35
|
+
rev: number;
|
|
36
|
+
}
|
|
19
37
|
/**
|
|
20
38
|
* Represents the state of a document in the OT protocol.
|
|
21
39
|
* @property state - The state of the document.
|
|
22
40
|
* @property rev - The revision number of the state.
|
|
23
41
|
*/
|
|
24
|
-
|
|
42
|
+
interface PatchesState<T = any> {
|
|
25
43
|
state: T;
|
|
26
44
|
rev: number;
|
|
27
45
|
}
|
|
@@ -31,7 +49,7 @@ export interface PatchesState<T = any> {
|
|
|
31
49
|
* @property rev - The revision number of the state.
|
|
32
50
|
* @property changes - Any unapplied changes since `rev` that may be applied to the `state` to get the latest state.
|
|
33
51
|
*/
|
|
34
|
-
|
|
52
|
+
interface PatchesSnapshot<T = any> extends PatchesState<T> {
|
|
35
53
|
changes: Change[];
|
|
36
54
|
}
|
|
37
55
|
/**
|
|
@@ -41,10 +59,10 @@ export interface PatchesSnapshot<T = any> extends PatchesState<T> {
|
|
|
41
59
|
* @property null - The document is not syncing.
|
|
42
60
|
* @property Error - The document is syncing with an error.
|
|
43
61
|
*/
|
|
44
|
-
|
|
62
|
+
type SyncingState = 'initial' | 'updating' | null | Error;
|
|
45
63
|
/** Status options for a branch */
|
|
46
|
-
|
|
47
|
-
|
|
64
|
+
type BranchStatus = 'open' | 'closed' | 'merged' | 'archived' | 'abandoned';
|
|
65
|
+
interface Branch {
|
|
48
66
|
/** The ID of the branch document. */
|
|
49
67
|
id: string;
|
|
50
68
|
/** The ID of the document this document was branched from. */
|
|
@@ -60,11 +78,11 @@ export interface Branch {
|
|
|
60
78
|
/** Optional arbitrary metadata associated with the branch record. */
|
|
61
79
|
[metadata: string]: any;
|
|
62
80
|
}
|
|
63
|
-
|
|
81
|
+
type EditableBranchMetadata = Disallowed<Branch, 'id' | 'branchedFromId' | 'branchedRev' | 'created' | 'status'>;
|
|
64
82
|
/**
|
|
65
83
|
* Metadata, state snapshot, and included changes for a specific version.
|
|
66
84
|
*/
|
|
67
|
-
|
|
85
|
+
interface VersionMetadata {
|
|
68
86
|
/** Unique identifier (UUID) for this version record. */
|
|
69
87
|
id: string;
|
|
70
88
|
name?: string;
|
|
@@ -90,11 +108,11 @@ export interface VersionMetadata {
|
|
|
90
108
|
type Disallowed<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>> & {
|
|
91
109
|
[P in K]?: never;
|
|
92
110
|
};
|
|
93
|
-
|
|
111
|
+
type EditableVersionMetadata = Disallowed<VersionMetadata, 'id' | 'parentId' | 'groupId' | 'origin' | 'branchName' | 'startDate' | 'endDate' | 'rev' | 'baseRev'>;
|
|
94
112
|
/**
|
|
95
113
|
* Options for listing committed server changes. *Always* ordered by revision number.
|
|
96
114
|
*/
|
|
97
|
-
|
|
115
|
+
interface ListChangesOptions {
|
|
98
116
|
/** List changes committed strictly *after* this revision number. */
|
|
99
117
|
startAfter?: number;
|
|
100
118
|
/** List changes committed strictly *before* this revision number. */
|
|
@@ -109,7 +127,7 @@ export interface ListChangesOptions {
|
|
|
109
127
|
/**
|
|
110
128
|
* Options for listing version metadata.
|
|
111
129
|
*/
|
|
112
|
-
|
|
130
|
+
interface ListVersionsOptions {
|
|
113
131
|
/** List versions whose orderBy field is *after* this value. */
|
|
114
132
|
startAfter?: number;
|
|
115
133
|
/** List versions whose orderBy field is strictly *before* this value. */
|
|
@@ -141,7 +159,7 @@ type DeepPathProxy = {
|
|
|
141
159
|
* Defaults to `any`, which returns a `DeepPathProxy` allowing arbitrary deep property access.
|
|
142
160
|
* When a specific type is provided, returns a strictly typed proxy.
|
|
143
161
|
*/
|
|
144
|
-
|
|
162
|
+
type PathProxy<T = any> = IsAny<T> extends true ? DeepPathProxy : {
|
|
145
163
|
[P in keyof T]-?: NonNullable<T[P]> extends object ? PathProxy<NonNullable<T[P]>> : {
|
|
146
164
|
toString: () => string;
|
|
147
165
|
};
|
|
@@ -153,5 +171,6 @@ export type PathProxy<T = any> = IsAny<T> extends true ? DeepPathProxy : {
|
|
|
153
171
|
* The mutator receives a JSONPatch instance and a PathProxy for type-safe path creation.
|
|
154
172
|
* All modifications must be done through explicit patch operations.
|
|
155
173
|
*/
|
|
156
|
-
|
|
157
|
-
|
|
174
|
+
type ChangeMutator<T> = (patch: JSONPatch, root: PathProxy<T>) => void;
|
|
175
|
+
|
|
176
|
+
export type { Branch, BranchStatus, Change, ChangeInput, ChangeMutator, EditableBranchMetadata, EditableVersionMetadata, ListChangesOptions, ListVersionsOptions, PatchesSnapshot, PatchesState, PathProxy, SyncingState, VersionMetadata };
|
package/dist/types.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import { JSONPatch } from
|
|
1
|
+
import { JSONPatch } from "./json-patch/JSONPatch.js";
|
|
@@ -2,17 +2,17 @@
|
|
|
2
2
|
* Wrap a function which is blockable for a document.
|
|
3
3
|
* Also, a Typescript decorator for functions which are blockable.
|
|
4
4
|
*/
|
|
5
|
-
|
|
5
|
+
declare function blockable<T extends (docId: string, ...args: any[]) => Promise<any>>(target: T): T;
|
|
6
6
|
/**
|
|
7
7
|
* Wrap a function which blocks on a document.
|
|
8
8
|
* Also, a Typescript decorator for functions which block.
|
|
9
9
|
*/
|
|
10
|
-
|
|
10
|
+
declare function blocking<T extends (docId: string, ...args: any[]) => Promise<any>>(target: T): T;
|
|
11
11
|
/**
|
|
12
12
|
* Wrap a function which returns a response which is blockable for a document (e.g. fetch).
|
|
13
13
|
* Also, a Typescript decorator for functions whose response should be blocked when needed.
|
|
14
14
|
*/
|
|
15
|
-
|
|
15
|
+
declare function blockableResponse<T extends (docId: string, ...args: any[]) => Promise<any>>(target: T): T;
|
|
16
16
|
/**
|
|
17
17
|
* Wrap a function to only return the result of the first call.
|
|
18
18
|
*
|
|
@@ -22,5 +22,7 @@ export declare function blockableResponse<T extends (docId: string, ...args: any
|
|
|
22
22
|
* ...
|
|
23
23
|
* });
|
|
24
24
|
*/
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
declare function singleInvocation<T extends (...args: any[]) => Promise<any>>(target: T): T;
|
|
26
|
+
declare function singleInvocation<T extends (...args: any[]) => Promise<any>>(matchOnFirstArg: boolean): (target: T) => T;
|
|
27
|
+
|
|
28
|
+
export { blockable, blockableResponse, blocking, singleInvocation };
|
|
@@ -1,60 +1,50 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
* Make the concurrency be per-path to allow multiple records to be loaded and updated at the same time, keeping only
|
|
5
|
-
* the record's operations sequential with respect to other operations on the same record.
|
|
6
|
-
*/
|
|
1
|
+
import "../chunk-IZ2YBCUP.js";
|
|
2
|
+
import { simplifiedConcurrency } from "simplified-concurrency";
|
|
3
|
+
const docIds = /* @__PURE__ */ new Map();
|
|
7
4
|
function concurrency(docId) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
let concurrency2 = docIds.get(docId);
|
|
6
|
+
if (!concurrency2) {
|
|
7
|
+
concurrency2 = simplifiedConcurrency();
|
|
8
|
+
docIds.set(docId, concurrency2);
|
|
9
|
+
}
|
|
10
|
+
return concurrency2;
|
|
14
11
|
}
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export function blockable(target) {
|
|
20
|
-
return function (...args) {
|
|
21
|
-
return concurrency(args[0]).blockFunction(target, args, this);
|
|
22
|
-
};
|
|
12
|
+
function blockable(target) {
|
|
13
|
+
return function(...args) {
|
|
14
|
+
return concurrency(args[0]).blockFunction(target, args, this);
|
|
15
|
+
};
|
|
23
16
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
export function blocking(target) {
|
|
29
|
-
return function (...args) {
|
|
30
|
-
return concurrency(args[0]).blockWhile(target.apply(this, args));
|
|
31
|
-
};
|
|
17
|
+
function blocking(target) {
|
|
18
|
+
return function(...args) {
|
|
19
|
+
return concurrency(args[0]).blockWhile(target.apply(this, args));
|
|
20
|
+
};
|
|
32
21
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
export function blockableResponse(target) {
|
|
38
|
-
return function (...args) {
|
|
39
|
-
return concurrency(args[0]).blockResponse(target.apply(this, args));
|
|
40
|
-
};
|
|
22
|
+
function blockableResponse(target) {
|
|
23
|
+
return function(...args) {
|
|
24
|
+
return concurrency(args[0]).blockResponse(target.apply(this, args));
|
|
25
|
+
};
|
|
41
26
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
return promise;
|
|
58
|
-
};
|
|
27
|
+
function singleInvocation(matchOnFirstArgOrTarget) {
|
|
28
|
+
if (typeof matchOnFirstArgOrTarget === "function") {
|
|
29
|
+
return singleInvocation(false)(matchOnFirstArgOrTarget);
|
|
30
|
+
}
|
|
31
|
+
return function(target) {
|
|
32
|
+
const promises = /* @__PURE__ */ new Map();
|
|
33
|
+
return function(...args) {
|
|
34
|
+
const key = matchOnFirstArgOrTarget ? args[0] : 1;
|
|
35
|
+
if (promises.has(key)) return promises.get(key);
|
|
36
|
+
const promise = target.apply(this, args);
|
|
37
|
+
promises.set(key, promise);
|
|
38
|
+
promise.finally(() => {
|
|
39
|
+
promises.delete(key);
|
|
40
|
+
});
|
|
41
|
+
return promise;
|
|
59
42
|
};
|
|
43
|
+
};
|
|
60
44
|
}
|
|
45
|
+
export {
|
|
46
|
+
blockable,
|
|
47
|
+
blockableResponse,
|
|
48
|
+
blocking,
|
|
49
|
+
singleInvocation
|
|
50
|
+
};
|
package/dist/utils/deferred.d.ts
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
interface Deferred<T = void> {
|
|
2
2
|
promise: Promise<T>;
|
|
3
3
|
resolve: (value: T) => void;
|
|
4
4
|
reject: (reason?: any) => void;
|
|
5
5
|
status: 'pending' | 'fulfilled' | 'rejected';
|
|
6
6
|
}
|
|
7
|
-
|
|
7
|
+
declare function deferred<T = void>(): Deferred<T>;
|
|
8
|
+
|
|
9
|
+
export { type Deferred, deferred };
|