@dabble/patches 0.4.4 → 0.4.6

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.
Files changed (181) hide show
  1. package/dist/algorithms/client/applyCommittedChanges.d.ts +8 -2
  2. package/dist/algorithms/client/applyCommittedChanges.js +30 -38
  3. package/dist/algorithms/client/batching.d.ts +8 -2
  4. package/dist/algorithms/client/batching.js +38 -37
  5. package/dist/algorithms/client/breakChange.d.ts +8 -2
  6. package/dist/algorithms/client/breakChange.js +191 -240
  7. package/dist/algorithms/client/createStateFromSnapshot.d.ts +8 -2
  8. package/dist/algorithms/client/createStateFromSnapshot.js +7 -8
  9. package/dist/algorithms/client/getJSONByteSize.d.ts +3 -1
  10. package/dist/algorithms/client/getJSONByteSize.js +12 -11
  11. package/dist/algorithms/client/makeChange.d.ts +8 -2
  12. package/dist/algorithms/client/makeChange.js +28 -36
  13. package/dist/algorithms/server/commitChanges.d.ts +9 -3
  14. package/dist/algorithms/server/commitChanges.js +69 -78
  15. package/dist/algorithms/server/createVersion.d.ts +9 -3
  16. package/dist/algorithms/server/createVersion.js +21 -27
  17. package/dist/algorithms/server/getSnapshotAtRevision.d.ts +9 -3
  18. package/dist/algorithms/server/getSnapshotAtRevision.js +27 -28
  19. package/dist/algorithms/server/getStateAtRevision.d.ts +9 -3
  20. package/dist/algorithms/server/getStateAtRevision.js +13 -17
  21. package/dist/algorithms/server/handleOfflineSessionsAndBatches.d.ts +9 -3
  22. package/dist/algorithms/server/handleOfflineSessionsAndBatches.js +60 -77
  23. package/dist/algorithms/server/transformIncomingChanges.d.ts +8 -2
  24. package/dist/algorithms/server/transformIncomingChanges.js +27 -39
  25. package/dist/algorithms/shared/applyChanges.d.ts +8 -2
  26. package/dist/algorithms/shared/applyChanges.js +11 -16
  27. package/dist/algorithms/shared/rebaseChanges.d.ts +8 -2
  28. package/dist/algorithms/shared/rebaseChanges.js +30 -49
  29. package/dist/chunk-IZ2YBCUP.js +56 -0
  30. package/dist/client/InMemoryStore.d.ts +9 -3
  31. package/dist/client/InMemoryStore.js +92 -101
  32. package/dist/client/IndexedDBStore.d.ts +9 -3
  33. package/dist/client/IndexedDBStore.js +378 -491
  34. package/dist/client/Patches.d.ts +18 -13
  35. package/dist/client/Patches.js +152 -207
  36. package/dist/client/PatchesDoc.d.ts +14 -8
  37. package/dist/client/PatchesDoc.js +147 -154
  38. package/dist/client/PatchesHistoryClient.d.ts +12 -5
  39. package/dist/client/PatchesHistoryClient.js +110 -117
  40. package/dist/client/PatchesStore.d.ts +9 -3
  41. package/dist/client/PatchesStore.js +0 -1
  42. package/dist/client/index.d.ts +12 -6
  43. package/dist/client/index.js +5 -5
  44. package/dist/data/change.d.ts +9 -3
  45. package/dist/data/change.js +23 -15
  46. package/dist/data/version.d.ts +9 -3
  47. package/dist/data/version.js +11 -15
  48. package/dist/event-signal.d.ts +7 -6
  49. package/dist/event-signal.js +24 -39
  50. package/dist/index-CvQws3AB.d.ts +36 -0
  51. package/dist/index.d.ts +27 -5
  52. package/dist/index.js +10 -4
  53. package/dist/json-patch/JSONPatch.d.ts +9 -5
  54. package/dist/json-patch/JSONPatch.js +175 -183
  55. package/dist/json-patch/applyPatch.d.ts +5 -2
  56. package/dist/json-patch/applyPatch.js +27 -35
  57. package/dist/json-patch/composePatch.d.ts +5 -2
  58. package/dist/json-patch/composePatch.js +34 -34
  59. package/dist/json-patch/createJSONPatch.d.ts +7 -2
  60. package/dist/json-patch/createJSONPatch.js +11 -38
  61. package/dist/json-patch/index.d.ts +14 -6
  62. package/dist/json-patch/index.js +20 -9
  63. package/dist/json-patch/invertPatch.d.ts +5 -2
  64. package/dist/json-patch/invertPatch.js +31 -30
  65. package/dist/json-patch/ops/add.d.ts +5 -2
  66. package/dist/json-patch/ops/add.js +53 -51
  67. package/dist/json-patch/ops/bitmask.d.ts +8 -5
  68. package/dist/json-patch/ops/bitmask.js +41 -44
  69. package/dist/json-patch/ops/copy.d.ts +5 -2
  70. package/dist/json-patch/ops/copy.js +32 -33
  71. package/dist/json-patch/ops/increment.d.ts +5 -2
  72. package/dist/json-patch/ops/increment.js +21 -20
  73. package/dist/json-patch/ops/index.d.ts +10 -21
  74. package/dist/json-patch/ops/index.js +34 -24
  75. package/dist/json-patch/ops/move.d.ts +5 -2
  76. package/dist/json-patch/ops/move.js +132 -198
  77. package/dist/json-patch/ops/remove.d.ts +5 -2
  78. package/dist/json-patch/ops/remove.js +33 -30
  79. package/dist/json-patch/ops/replace.d.ts +5 -2
  80. package/dist/json-patch/ops/replace.js +45 -43
  81. package/dist/json-patch/ops/test.d.ts +5 -2
  82. package/dist/json-patch/ops/test.js +25 -21
  83. package/dist/json-patch/ops/text.d.ts +5 -2
  84. package/dist/json-patch/ops/text.js +54 -54
  85. package/dist/json-patch/pathProxy.d.ts +9 -3
  86. package/dist/json-patch/pathProxy.js +27 -48
  87. package/dist/json-patch/state.d.ts +5 -2
  88. package/dist/json-patch/state.js +11 -7
  89. package/dist/json-patch/transformPatch.d.ts +6 -2
  90. package/dist/json-patch/transformPatch.js +21 -24
  91. package/dist/json-patch/types.d.ts +9 -7
  92. package/dist/json-patch/types.js +0 -1
  93. package/dist/json-patch/utils/deepEqual.d.ts +3 -1
  94. package/dist/json-patch/utils/deepEqual.js +32 -28
  95. package/dist/json-patch/utils/exit.d.ts +5 -2
  96. package/dist/json-patch/utils/exit.js +7 -3
  97. package/dist/json-patch/utils/get.d.ts +5 -2
  98. package/dist/json-patch/utils/get.js +8 -4
  99. package/dist/json-patch/utils/getOpData.d.ts +5 -2
  100. package/dist/json-patch/utils/getOpData.js +12 -9
  101. package/dist/json-patch/utils/getType.d.ts +6 -3
  102. package/dist/json-patch/utils/getType.js +9 -4
  103. package/dist/json-patch/utils/index.d.ts +15 -14
  104. package/dist/json-patch/utils/index.js +14 -14
  105. package/dist/json-patch/utils/log.d.ts +4 -2
  106. package/dist/json-patch/utils/log.js +8 -3
  107. package/dist/json-patch/utils/ops.d.ts +8 -5
  108. package/dist/json-patch/utils/ops.js +83 -100
  109. package/dist/json-patch/utils/paths.d.ts +12 -9
  110. package/dist/json-patch/utils/paths.js +54 -51
  111. package/dist/json-patch/utils/pluck.d.ts +8 -5
  112. package/dist/json-patch/utils/pluck.js +32 -26
  113. package/dist/json-patch/utils/shallowCopy.d.ts +3 -1
  114. package/dist/json-patch/utils/shallowCopy.js +22 -18
  115. package/dist/json-patch/utils/softWrites.d.ts +6 -3
  116. package/dist/json-patch/utils/softWrites.js +17 -16
  117. package/dist/json-patch/utils/toArrayIndex.d.ts +3 -1
  118. package/dist/json-patch/utils/toArrayIndex.js +14 -10
  119. package/dist/json-patch/utils/toKeys.d.ts +3 -1
  120. package/dist/json-patch/utils/toKeys.js +15 -11
  121. package/dist/json-patch/utils/updateArrayIndexes.d.ts +5 -2
  122. package/dist/json-patch/utils/updateArrayIndexes.js +33 -37
  123. package/dist/json-patch/utils/updateArrayPath.d.ts +5 -2
  124. package/dist/json-patch/utils/updateArrayPath.js +29 -42
  125. package/dist/net/PatchesClient.d.ts +128 -0
  126. package/dist/net/PatchesClient.js +161 -0
  127. package/dist/net/PatchesSync.d.ts +19 -9
  128. package/dist/net/PatchesSync.js +291 -386
  129. package/dist/net/error.d.ts +3 -1
  130. package/dist/net/error.js +9 -6
  131. package/dist/net/http/FetchTransport.d.ts +21 -0
  132. package/dist/net/http/FetchTransport.js +34 -0
  133. package/dist/net/index.d.ts +26 -12
  134. package/dist/net/index.js +12 -10
  135. package/dist/net/protocol/JSONRPCClient.d.ts +11 -4
  136. package/dist/net/protocol/JSONRPCClient.js +95 -103
  137. package/dist/net/protocol/JSONRPCServer.d.ts +15 -8
  138. package/dist/net/protocol/JSONRPCServer.js +101 -123
  139. package/dist/net/protocol/types.d.ts +21 -15
  140. package/dist/net/protocol/types.js +0 -1
  141. package/dist/net/protocol/utils.d.ts +12 -0
  142. package/dist/net/protocol/utils.js +15 -0
  143. package/dist/net/types.d.ts +4 -2
  144. package/dist/net/types.js +0 -1
  145. package/dist/net/webrtc/WebRTCAwareness.d.ts +14 -4
  146. package/dist/net/webrtc/WebRTCAwareness.js +111 -120
  147. package/dist/net/webrtc/WebRTCTransport.d.ts +16 -8
  148. package/dist/net/webrtc/WebRTCTransport.js +149 -157
  149. package/dist/net/webrtc/index.d.ts +10 -2
  150. package/dist/net/webrtc/index.js +2 -2
  151. package/dist/net/websocket/AuthorizationProvider.d.ts +7 -5
  152. package/dist/net/websocket/AuthorizationProvider.js +12 -17
  153. package/dist/net/websocket/PatchesWebSocket.d.ts +14 -109
  154. package/dist/net/websocket/PatchesWebSocket.js +37 -184
  155. package/dist/net/websocket/RPCServer.d.ts +19 -10
  156. package/dist/net/websocket/RPCServer.js +190 -192
  157. package/dist/net/websocket/SignalingService.d.ts +12 -32
  158. package/dist/net/websocket/SignalingService.js +126 -133
  159. package/dist/net/websocket/WebSocketServer.d.ts +17 -4
  160. package/dist/net/websocket/WebSocketServer.js +64 -72
  161. package/dist/net/websocket/WebSocketTransport.d.ts +13 -5
  162. package/dist/net/websocket/WebSocketTransport.js +178 -207
  163. package/dist/net/websocket/onlineState.d.ts +6 -3
  164. package/dist/net/websocket/onlineState.js +25 -21
  165. package/dist/server/PatchesBranchManager.d.ts +12 -5
  166. package/dist/server/PatchesBranchManager.js +132 -142
  167. package/dist/server/PatchesHistoryManager.d.ts +11 -3
  168. package/dist/server/PatchesHistoryManager.js +81 -84
  169. package/dist/server/PatchesServer.d.ts +16 -10
  170. package/dist/server/PatchesServer.js +131 -137
  171. package/dist/server/index.d.ts +7 -2
  172. package/dist/server/index.js +9 -3
  173. package/dist/server/types.d.ts +9 -3
  174. package/dist/server/types.js +0 -1
  175. package/dist/types.d.ts +49 -19
  176. package/dist/types.js +1 -1
  177. package/dist/utils/concurrency.d.ts +7 -5
  178. package/dist/utils/concurrency.js +43 -53
  179. package/dist/utils/deferred.d.ts +4 -2
  180. package/dist/utils/deferred.js +25 -21
  181. package/package.json +5 -7
@@ -1,7 +1,13 @@
1
- import type { PatchesSnapshot } from '../../types.js';
1
+ import { PatchesSnapshot } from '../../types.js';
2
+ import '../../json-patch/JSONPatch.js';
3
+ import '@dabble/delta';
4
+ import '../../json-patch/types.js';
5
+
2
6
  /**
3
7
  * Creates the in-memory state from a snapshot.
4
8
  * @param snapshot The snapshot to create a state from.
5
9
  * @returns The new state.
6
10
  */
7
- export declare function createStateFromSnapshot<T = any>(snapshot: PatchesSnapshot<T>): T;
11
+ declare function createStateFromSnapshot<T = any>(snapshot: PatchesSnapshot<T>): T;
12
+
13
+ export { createStateFromSnapshot };
@@ -1,9 +1,8 @@
1
- import { applyChanges } from '../shared/applyChanges.js';
2
- /**
3
- * Creates the in-memory state from a snapshot.
4
- * @param snapshot The snapshot to create a state from.
5
- * @returns The new state.
6
- */
7
- export function createStateFromSnapshot(snapshot) {
8
- return applyChanges(snapshot.state, snapshot.changes);
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ import { applyChanges } from "../shared/applyChanges.js";
3
+ function createStateFromSnapshot(snapshot) {
4
+ return applyChanges(snapshot.state, snapshot.changes);
9
5
  }
6
+ export {
7
+ createStateFromSnapshot
8
+ };
@@ -1,2 +1,4 @@
1
1
  /** Estimate JSON string byte size. */
2
- export declare function getJSONByteSize(data: any): number;
2
+ declare function getJSONByteSize(data: any): number;
3
+
4
+ export { getJSONByteSize };
@@ -1,12 +1,13 @@
1
- /** Estimate JSON string byte size. */
2
- export function getJSONByteSize(data) {
3
- try {
4
- const stringified = JSON.stringify(data);
5
- return stringified ? new TextEncoder().encode(stringified).length : 0;
6
- }
7
- catch (e) {
8
- // Handle circular structures (from JSON.stringify) or other errors.
9
- console.error('Error calculating JSON size:', e);
10
- throw new Error('Error calculating JSON size: ' + e);
11
- }
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ function getJSONByteSize(data) {
3
+ try {
4
+ const stringified = JSON.stringify(data);
5
+ return stringified ? new TextEncoder().encode(stringified).length : 0;
6
+ } catch (e) {
7
+ console.error("Error calculating JSON size:", e);
8
+ throw new Error("Error calculating JSON size: " + e);
9
+ }
12
10
  }
11
+ export {
12
+ getJSONByteSize
13
+ };
@@ -1,2 +1,8 @@
1
- import type { Change, ChangeMutator, PatchesSnapshot } from '../../types.js';
2
- export declare function makeChange<T = any>(snapshot: PatchesSnapshot<T>, mutator: ChangeMutator<T>, changeMetadata?: Record<string, any>, maxPayloadBytes?: number): Change[];
1
+ import { PatchesSnapshot, ChangeMutator, Change } from '../../types.js';
2
+ import '../../json-patch/JSONPatch.js';
3
+ import '@dabble/delta';
4
+ import '../../json-patch/types.js';
5
+
6
+ declare function makeChange<T = any>(snapshot: PatchesSnapshot<T>, mutator: ChangeMutator<T>, changeMetadata?: Record<string, any>, maxPayloadBytes?: number): Change[];
7
+
8
+ export { makeChange };
@@ -1,37 +1,29 @@
1
- import { createChange } from '../../data/change.js';
2
- import { createJSONPatch } from '../../json-patch/createJSONPatch.js';
3
- import { breakChange } from './breakChange.js';
4
- import { createStateFromSnapshot } from './createStateFromSnapshot.js';
5
- export function makeChange(snapshot, mutator, changeMetadata, maxPayloadBytes) {
6
- const pendingChanges = snapshot.changes;
7
- const pendingRev = pendingChanges[pendingChanges.length - 1]?.rev ?? snapshot.rev;
8
- const state = createStateFromSnapshot(snapshot); // Current state including pending
9
- const patch = createJSONPatch(mutator);
10
- if (patch.ops.length === 0) {
11
- return [];
12
- }
13
- // Optimistic rev for local sorting, based on the latest known rev (committed or pending)
14
- const rev = pendingRev + 1;
15
- // Create the initial change. BaseRev is always the last *committed* revision from the snapshot.
16
- let newChangesArray = [createChange(snapshot.rev, rev, patch.ops, changeMetadata)];
17
- // Optimistically apply the patch to the current state (which includes pending changes)
18
- // This state is temporary for validation/splitting and not stored back directly in PatchesDoc from here.
19
- try {
20
- // Note: The 'state' variable here is the one derived from createStateFromSnapshot (committed + pending).
21
- // Applying the new patch to it is for the purpose of creating the correct Change object(s).
22
- // PatchesDoc.change will apply these returned changes to its own _state later.
23
- patch.apply(state); // This line primarily serves to ensure the patch is valid against the current view.
24
- }
25
- catch (error) {
26
- console.error('Failed to apply change to state during makeChange:', error);
27
- throw new Error(`Failed to apply change to state during makeChange: ${error}`);
28
- }
29
- if (maxPayloadBytes) {
30
- // If the single change (or its parts) exceed maxPayloadBytes, break it down.
31
- // breakChange will handle creating multiple Change objects if necessary,
32
- // maintaining the original baseRev but incrementing revs for the pieces.
33
- newChangesArray = breakChange(newChangesArray[0], maxPayloadBytes);
34
- }
35
- // PatchesDoc.change will take this returned array and push its contents onto its internal snapshot.
36
- return newChangesArray;
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ import { createChange } from "../../data/change.js";
3
+ import { createJSONPatch } from "../../json-patch/createJSONPatch.js";
4
+ import { breakChange } from "./breakChange.js";
5
+ import { createStateFromSnapshot } from "./createStateFromSnapshot.js";
6
+ function makeChange(snapshot, mutator, changeMetadata, maxPayloadBytes) {
7
+ const pendingChanges = snapshot.changes;
8
+ const pendingRev = pendingChanges[pendingChanges.length - 1]?.rev ?? snapshot.rev;
9
+ const state = createStateFromSnapshot(snapshot);
10
+ const patch = createJSONPatch(mutator);
11
+ if (patch.ops.length === 0) {
12
+ return [];
13
+ }
14
+ const rev = pendingRev + 1;
15
+ let newChangesArray = [createChange(snapshot.rev, rev, patch.ops, changeMetadata)];
16
+ try {
17
+ patch.apply(state);
18
+ } catch (error) {
19
+ console.error("Failed to apply change to state during makeChange:", error);
20
+ throw new Error(`Failed to apply change to state during makeChange: ${error}`);
21
+ }
22
+ if (maxPayloadBytes) {
23
+ newChangesArray = breakChange(newChangesArray[0], maxPayloadBytes);
24
+ }
25
+ return newChangesArray;
37
26
  }
27
+ export {
28
+ makeChange
29
+ };
@@ -1,5 +1,9 @@
1
- import type { PatchesStoreBackend } from '../../server/types.js';
2
- import type { Change } from '../../types.js';
1
+ import { PatchesStoreBackend } from '../../server/types.js';
2
+ import { ChangeInput, Change } from '../../types.js';
3
+ import '../../json-patch/JSONPatch.js';
4
+ import '@dabble/delta';
5
+ import '../../json-patch/types.js';
6
+
3
7
  /**
4
8
  * Commits a set of changes to a document, applying operational transformation as needed.
5
9
  * @param docId - The ID of the document.
@@ -9,4 +13,6 @@ import type { Change } from '../../types.js';
9
13
  * - committedChanges: Changes that were already committed to the server after the client's base revision
10
14
  * - transformedChanges: The client's changes after being transformed against concurrent changes
11
15
  */
12
- export declare function commitChanges(store: PatchesStoreBackend, docId: string, changes: Change[], sessionTimeoutMillis: number): Promise<[Change[], Change[]]>;
16
+ declare function commitChanges(store: PatchesStoreBackend, docId: string, changes: ChangeInput[], sessionTimeoutMillis: number): Promise<[Change[], Change[]]>;
17
+
18
+ export { commitChanges };
@@ -1,80 +1,71 @@
1
- import { applyChanges } from '../shared/applyChanges.js';
2
- import { createVersion } from './createVersion.js';
3
- import { getSnapshotAtRevision } from './getSnapshotAtRevision.js';
4
- import { getStateAtRevision } from './getStateAtRevision.js';
5
- import { handleOfflineSessionsAndBatches } from './handleOfflineSessionsAndBatches.js';
6
- import { transformIncomingChanges } from './transformIncomingChanges.js';
7
- /**
8
- * Commits a set of changes to a document, applying operational transformation as needed.
9
- * @param docId - The ID of the document.
10
- * @param changes - The changes to commit.
11
- * @param originClientId - The ID of the client that initiated the commit.
12
- * @returns A tuple of [committedChanges, transformedChanges] where:
13
- * - committedChanges: Changes that were already committed to the server after the client's base revision
14
- * - transformedChanges: The client's changes after being transformed against concurrent changes
15
- */
16
- export async function commitChanges(store, docId, changes, sessionTimeoutMillis) {
17
- if (changes.length === 0) {
18
- return [[], []];
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ import { applyChanges } from "../shared/applyChanges.js";
3
+ import { createVersion } from "./createVersion.js";
4
+ import { getSnapshotAtRevision } from "./getSnapshotAtRevision.js";
5
+ import { getStateAtRevision } from "./getStateAtRevision.js";
6
+ import { handleOfflineSessionsAndBatches } from "./handleOfflineSessionsAndBatches.js";
7
+ import { transformIncomingChanges } from "./transformIncomingChanges.js";
8
+ async function commitChanges(store, docId, changes, sessionTimeoutMillis) {
9
+ if (changes.length === 0) {
10
+ return [[], []];
11
+ }
12
+ const batchId = changes[0].batchId;
13
+ const { state: initialState, rev: initialRev, changes: currentChanges } = await getSnapshotAtRevision(store, docId);
14
+ const currentState = applyChanges(initialState, currentChanges);
15
+ const currentRev = currentChanges.at(-1)?.rev ?? initialRev;
16
+ const baseRev = changes[0].baseRev ?? currentRev;
17
+ let rev = baseRev + 1;
18
+ changes.forEach((c) => {
19
+ if (c.baseRev == null) c.baseRev = baseRev;
20
+ else if (c.baseRev !== baseRev) {
21
+ throw new Error(`Client changes must have consistent baseRev in all changes for doc ${docId}.`);
19
22
  }
20
- // Assume all changes share the same baseRev. Client ensures
21
- const batchId = changes[0].batchId;
22
- const baseRev = changes[0].baseRev;
23
- if (baseRev === undefined) {
24
- throw new Error(`Client changes must include baseRev for doc ${docId}.`);
25
- }
26
- // Add check for inconsistent baseRev within the batch if needed
27
- if (changes.some(c => c.baseRev !== baseRev)) {
28
- throw new Error(`Client changes must have consistent baseRev in all changes for doc ${docId}.`);
29
- }
30
- // 1. Load server state details (assuming store methods exist)
31
- const { state: initialState, rev: initialRev, changes: currentChanges } = await getSnapshotAtRevision(store, docId);
32
- const currentState = applyChanges(initialState, currentChanges);
33
- const currentRev = currentChanges.at(-1)?.rev ?? initialRev;
34
- // Basic validation
35
- if (baseRev > currentRev) {
36
- throw new Error(`Client baseRev (${baseRev}) is ahead of server revision (${currentRev}) for doc ${docId}. Client needs to reload the document.`);
37
- }
38
- const partOfInitialBatch = batchId && changes[0].rev > 1;
39
- if (baseRev === 0 && currentRev > 0 && !partOfInitialBatch && changes[0].ops[0].path === '') {
40
- throw new Error(`Client baseRev is 0 but server has already been created for doc ${docId}. Client needs to load the existing document.`);
41
- }
42
- // Ensure all new changes' `created` field is in the past, that each `rev` is correct, and that `baseRev` is set
43
- changes.forEach(c => {
44
- c.created = Math.min(c.created, Date.now());
45
- c.baseRev = baseRev;
46
- });
47
- // 2. Check if we need to create a new version - if the last change was created more than a session ago
48
- const lastChange = currentChanges[currentChanges.length - 1];
49
- if (lastChange && lastChange.created < Date.now() - sessionTimeoutMillis) {
50
- await createVersion(store, docId, currentState, currentChanges);
51
- }
52
- // 3. Load committed changes *after* the client's baseRev for transformation and idempotency checks
53
- const committedChanges = await store.listChanges(docId, {
54
- startAfter: baseRev,
55
- withoutBatchId: batchId,
56
- });
57
- const committedIds = new Set(committedChanges.map(c => c.id));
58
- changes = changes.filter(c => !committedIds.has(c.id));
59
- // If all incoming changes were already committed, return the committed changes found
60
- if (changes.length === 0) {
61
- return [committedChanges, []];
62
- }
63
- // 4. Handle offline-session versioning:
64
- // - batchId present (multi-batch uploads)
65
- // - or the first change is older than the session timeout (single-batch offline)
66
- const isOfflineTimestamp = changes[0].created < Date.now() - sessionTimeoutMillis;
67
- if (isOfflineTimestamp || batchId) {
68
- changes = await handleOfflineSessionsAndBatches(store, sessionTimeoutMillis, docId, changes, baseRev, batchId);
69
- }
70
- // 5. Transform the *entire batch* of incoming (and potentially collapsed offline) changes
71
- // against committed changes that happened *after* the client's baseRev.
72
- // The state used for transformation should be the server state *at the client's baseRev*.
73
- const stateAtBaseRev = (await getStateAtRevision(store, docId, baseRev)).state;
74
- const transformedChanges = transformIncomingChanges(changes, stateAtBaseRev, committedChanges, currentRev);
75
- if (transformedChanges.length > 0) {
76
- await store.saveChanges(docId, transformedChanges);
77
- }
78
- // Return committed changes and newly transformed changes separately
79
- return [committedChanges, transformedChanges];
23
+ if (c.rev == null) c.rev = rev++;
24
+ else rev = c.rev + 1;
25
+ c.created = Math.min(c.created, Date.now());
26
+ });
27
+ if (baseRev > currentRev) {
28
+ throw new Error(
29
+ `Client baseRev (${baseRev}) is ahead of server revision (${currentRev}) for doc ${docId}. Client needs to reload the document.`
30
+ );
31
+ }
32
+ const laterPartOfAnInitialBatch = batchId && changes[0].rev > 1;
33
+ if (baseRev === 0 && currentRev > 0 && !laterPartOfAnInitialBatch && changes[0].ops[0]?.path === "") {
34
+ throw new Error(
35
+ `Document ${docId} already exists at rev ${currentRev}, but client is attempting to create it. Client needs to load the existing document.`
36
+ );
37
+ }
38
+ const lastChange = currentChanges[currentChanges.length - 1];
39
+ if (lastChange && lastChange.created < Date.now() - sessionTimeoutMillis) {
40
+ await createVersion(store, docId, currentState, currentChanges);
41
+ }
42
+ const committedChanges = await store.listChanges(docId, {
43
+ startAfter: baseRev,
44
+ withoutBatchId: batchId
45
+ });
46
+ const committedIds = new Set(committedChanges.map((c) => c.id));
47
+ let incomingChanges = changes.filter((c) => !committedIds.has(c.id));
48
+ if (incomingChanges.length === 0) {
49
+ return [committedChanges, []];
50
+ }
51
+ const isOfflineTimestamp = incomingChanges[0].created < Date.now() - sessionTimeoutMillis;
52
+ if (isOfflineTimestamp || batchId) {
53
+ incomingChanges = await handleOfflineSessionsAndBatches(
54
+ store,
55
+ sessionTimeoutMillis,
56
+ docId,
57
+ incomingChanges,
58
+ baseRev,
59
+ batchId
60
+ );
61
+ }
62
+ const stateAtBaseRev = (await getStateAtRevision(store, docId, baseRev)).state;
63
+ const transformedChanges = transformIncomingChanges(incomingChanges, stateAtBaseRev, committedChanges, currentRev);
64
+ if (transformedChanges.length > 0) {
65
+ await store.saveChanges(docId, transformedChanges);
66
+ }
67
+ return [committedChanges, transformedChanges];
80
68
  }
69
+ export {
70
+ commitChanges
71
+ };
@@ -1,5 +1,9 @@
1
- import type { PatchesStoreBackend } from '../../server/types.js';
2
- import type { Change, EditableVersionMetadata, VersionMetadata } from '../../types.js';
1
+ import { PatchesStoreBackend } from '../../server/types.js';
2
+ import { Change, EditableVersionMetadata, VersionMetadata } from '../../types.js';
3
+ import '../../json-patch/JSONPatch.js';
4
+ import '@dabble/delta';
5
+ import '../../json-patch/types.js';
6
+
3
7
  /**
4
8
  * Creates a new version snapshot of a document's state from changes.
5
9
  * @param store The storage backend to save the version to.
@@ -9,4 +13,6 @@ import type { Change, EditableVersionMetadata, VersionMetadata } from '../../typ
9
13
  * @param metadata Optional additional metadata for the version.
10
14
  * @returns The created version metadata, or undefined if no changes provided.
11
15
  */
12
- export declare function createVersion(store: PatchesStoreBackend, docId: string, state: any, changes: Change[], metadata?: EditableVersionMetadata): Promise<VersionMetadata | undefined>;
16
+ declare function createVersion(store: PatchesStoreBackend, docId: string, state: any, changes: Change[], metadata?: EditableVersionMetadata): Promise<VersionMetadata | undefined>;
17
+
18
+ export { createVersion };
@@ -1,28 +1,22 @@
1
- import { createVersionMetadata } from '../../data/version.js';
2
- /**
3
- * Creates a new version snapshot of a document's state from changes.
4
- * @param store The storage backend to save the version to.
5
- * @param docId The document ID.
6
- * @param state The document state at the time of the version.
7
- * @param changes The changes since the last version that created the state.
8
- * @param metadata Optional additional metadata for the version.
9
- * @returns The created version metadata, or undefined if no changes provided.
10
- */
11
- export async function createVersion(store, docId, state, changes, metadata) {
12
- if (changes.length === 0)
13
- return;
14
- const baseRev = changes[0].baseRev;
15
- if (baseRev === undefined) {
16
- throw new Error(`Client changes must include baseRev for doc ${docId}.`);
17
- }
18
- const sessionMetadata = createVersionMetadata({
19
- origin: 'main',
20
- startDate: changes[0].created,
21
- endDate: changes[changes.length - 1].created,
22
- rev: changes[changes.length - 1].rev,
23
- baseRev,
24
- ...metadata,
25
- });
26
- await store.createVersion(docId, sessionMetadata, state, changes);
27
- return sessionMetadata;
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ import { createVersionMetadata } from "../../data/version.js";
3
+ async function createVersion(store, docId, state, changes, metadata) {
4
+ if (changes.length === 0) return;
5
+ const baseRev = changes[0].baseRev;
6
+ if (baseRev === void 0) {
7
+ throw new Error(`Client changes must include baseRev for doc ${docId}.`);
8
+ }
9
+ const sessionMetadata = createVersionMetadata({
10
+ origin: "main",
11
+ startDate: changes[0].created,
12
+ endDate: changes[changes.length - 1].created,
13
+ rev: changes[changes.length - 1].rev,
14
+ baseRev,
15
+ ...metadata
16
+ });
17
+ await store.createVersion(docId, sessionMetadata, state, changes);
18
+ return sessionMetadata;
28
19
  }
20
+ export {
21
+ createVersion
22
+ };
@@ -1,5 +1,9 @@
1
- import type { PatchesStoreBackend } from '../../server/types.js';
2
- import type { PatchesSnapshot } from '../../types.js';
1
+ import { PatchesStoreBackend } from '../../server/types.js';
2
+ import { PatchesSnapshot } from '../../types.js';
3
+ import '../../json-patch/JSONPatch.js';
4
+ import '@dabble/delta';
5
+ import '../../json-patch/types.js';
6
+
3
7
  /**
4
8
  * Retrieves the document state of the version before the given revision and changes after up to that revision or all
5
9
  * changes since that version.
@@ -7,4 +11,6 @@ import type { PatchesSnapshot } from '../../types.js';
7
11
  * @param rev The revision number. If not provided, the latest state, its revision, and all changes since are returned.
8
12
  * @returns The document state at the last version before the revision, its revision number, and all changes up to the specified revision (or all changes if no revision is provided).
9
13
  */
10
- export declare function getSnapshotAtRevision(store: PatchesStoreBackend, docId: string, rev?: number): Promise<PatchesSnapshot>;
14
+ declare function getSnapshotAtRevision(store: PatchesStoreBackend, docId: string, rev?: number): Promise<PatchesSnapshot>;
15
+
16
+ export { getSnapshotAtRevision };
@@ -1,29 +1,28 @@
1
- /**
2
- * Retrieves the document state of the version before the given revision and changes after up to that revision or all
3
- * changes since that version.
4
- * @param docId The document ID.
5
- * @param rev The revision number. If not provided, the latest state, its revision, and all changes since are returned.
6
- * @returns The document state at the last version before the revision, its revision number, and all changes up to the specified revision (or all changes if no revision is provided).
7
- */
8
- export async function getSnapshotAtRevision(store, docId, rev) {
9
- const versions = await store.listVersions(docId, {
10
- limit: 1,
11
- reverse: true,
12
- startAfter: rev ? rev + 1 : undefined,
13
- origin: 'main',
14
- orderBy: 'rev',
15
- });
16
- const latestMainVersion = versions[0];
17
- const versionState = (latestMainVersion && (await store.loadVersionState(docId, latestMainVersion.id))) || null;
18
- const versionRev = latestMainVersion?.rev ?? 0;
19
- // Get *all* changes since that version up to the target revision (if specified)
20
- const changesSinceVersion = await store.listChanges(docId, {
21
- startAfter: versionRev,
22
- endBefore: rev ? rev + 1 : undefined,
23
- });
24
- return {
25
- state: versionState, // State from the base version
26
- rev: versionRev, // Revision of the base version's state
27
- changes: changesSinceVersion, // Changes that occurred *after* the base version state
28
- };
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ async function getSnapshotAtRevision(store, docId, rev) {
3
+ const versions = await store.listVersions(docId, {
4
+ limit: 1,
5
+ reverse: true,
6
+ startAfter: rev ? rev + 1 : void 0,
7
+ origin: "main",
8
+ orderBy: "rev"
9
+ });
10
+ const latestMainVersion = versions[0];
11
+ const versionState = latestMainVersion && await store.loadVersionState(docId, latestMainVersion.id) || null;
12
+ const versionRev = latestMainVersion?.rev ?? 0;
13
+ const changesSinceVersion = await store.listChanges(docId, {
14
+ startAfter: versionRev,
15
+ endBefore: rev ? rev + 1 : void 0
16
+ });
17
+ return {
18
+ state: versionState,
19
+ // State from the base version
20
+ rev: versionRev,
21
+ // Revision of the base version's state
22
+ changes: changesSinceVersion
23
+ // Changes that occurred *after* the base version state
24
+ };
29
25
  }
26
+ export {
27
+ getSnapshotAtRevision
28
+ };
@@ -1,9 +1,15 @@
1
- import type { PatchesStoreBackend } from '../../server/types.js';
2
- import type { PatchesState } from '../../types.js';
1
+ import { PatchesStoreBackend } from '../../server/types.js';
2
+ import { PatchesState } from '../../types.js';
3
+ import '../../json-patch/JSONPatch.js';
4
+ import '@dabble/delta';
5
+ import '../../json-patch/types.js';
6
+
3
7
  /**
4
8
  * Gets the state at a specific revision.
5
9
  * @param docId The document ID.
6
10
  * @param rev The revision number. If not provided, the latest state and its revision is returned.
7
11
  * @returns The state at the specified revision *and* its revision number.
8
12
  */
9
- export declare function getStateAtRevision(store: PatchesStoreBackend, docId: string, rev?: number): Promise<PatchesState>;
13
+ declare function getStateAtRevision(store: PatchesStoreBackend, docId: string, rev?: number): Promise<PatchesState>;
14
+
15
+ export { getStateAtRevision };
@@ -1,18 +1,14 @@
1
- import { applyChanges } from '../shared/applyChanges.js';
2
- import { getSnapshotAtRevision } from './getSnapshotAtRevision.js';
3
- /**
4
- * Gets the state at a specific revision.
5
- * @param docId The document ID.
6
- * @param rev The revision number. If not provided, the latest state and its revision is returned.
7
- * @returns The state at the specified revision *and* its revision number.
8
- */
9
- export async function getStateAtRevision(store, docId, rev) {
10
- // Note: _getSnapshotAtRevision now returns the state *of the version* and changes *since* it.
11
- // We need to apply the changes to get the state *at* the target revision.
12
- const { state: versionState, rev: snapshotRev, changes } = await getSnapshotAtRevision(store, docId, rev);
13
- return {
14
- // Ensure null is passed if versionState or versionState.state is null/undefined
15
- state: applyChanges(versionState?.state ?? null, changes),
16
- rev: changes.at(-1)?.rev ?? snapshotRev,
17
- };
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ import { applyChanges } from "../shared/applyChanges.js";
3
+ import { getSnapshotAtRevision } from "./getSnapshotAtRevision.js";
4
+ async function getStateAtRevision(store, docId, rev) {
5
+ const { state: versionState, rev: snapshotRev, changes } = await getSnapshotAtRevision(store, docId, rev);
6
+ return {
7
+ // Ensure null is passed if versionState or versionState.state is null/undefined
8
+ state: applyChanges(versionState?.state ?? null, changes),
9
+ rev: changes.at(-1)?.rev ?? snapshotRev
10
+ };
18
11
  }
12
+ export {
13
+ getStateAtRevision
14
+ };
@@ -1,5 +1,9 @@
1
- import type { PatchesStoreBackend } from '../../server/types.js';
2
- import type { Change } from '../../types.js';
1
+ import { PatchesStoreBackend } from '../../server/types.js';
2
+ import { Change } from '../../types.js';
3
+ import '../../json-patch/JSONPatch.js';
4
+ import '@dabble/delta';
5
+ import '../../json-patch/types.js';
6
+
3
7
  /**
4
8
  * Handles offline/large batch versioning logic for multi-batch uploads.
5
9
  * Groups changes into sessions, merges with previous batch if needed, and creates/extends versions.
@@ -9,4 +13,6 @@ import type { Change } from '../../types.js';
9
13
  * @param batchId The batch identifier
10
14
  * @returns The collapsed changes for transformation
11
15
  */
12
- export declare function handleOfflineSessionsAndBatches(store: PatchesStoreBackend, sessionTimeoutMillis: number, docId: string, changes: Change[], baseRev: number, batchId?: string): Promise<Change[]>;
16
+ declare function handleOfflineSessionsAndBatches(store: PatchesStoreBackend, sessionTimeoutMillis: number, docId: string, changes: Change[], baseRev: number, batchId?: string): Promise<Change[]>;
17
+
18
+ export { handleOfflineSessionsAndBatches };