@dabble/patches 0.5.22 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +221 -208
- package/dist/BaseDoc-DkP3tUhT.d.ts +206 -0
- package/dist/algorithms/client/applyCommittedChanges.d.ts +7 -0
- package/dist/algorithms/client/applyCommittedChanges.js +6 -3
- package/dist/algorithms/lww/consolidateOps.d.ts +40 -0
- package/dist/algorithms/lww/consolidateOps.js +103 -0
- package/dist/algorithms/lww/index.d.ts +2 -0
- package/dist/algorithms/lww/index.js +1 -0
- package/dist/algorithms/lww/mergeServerWithLocal.d.ts +22 -0
- package/dist/algorithms/lww/mergeServerWithLocal.js +32 -0
- package/dist/algorithms/server/commitChanges.d.ts +32 -8
- package/dist/algorithms/server/commitChanges.js +24 -10
- package/dist/algorithms/server/createVersion.d.ts +1 -1
- package/dist/algorithms/server/createVersion.js +2 -4
- package/dist/algorithms/server/getSnapshotAtRevision.d.ts +1 -1
- package/dist/algorithms/server/getStateAtRevision.d.ts +1 -1
- package/dist/algorithms/server/handleOfflineSessionsAndBatches.d.ts +1 -1
- package/dist/algorithms/server/handleOfflineSessionsAndBatches.js +5 -7
- package/dist/client/BaseDoc.d.ts +6 -0
- package/dist/client/BaseDoc.js +70 -0
- package/dist/client/ClientAlgorithm.d.ts +101 -0
- package/dist/client/ClientAlgorithm.js +0 -0
- package/dist/client/InMemoryStore.d.ts +5 -7
- package/dist/client/InMemoryStore.js +6 -35
- package/dist/client/IndexedDBStore.d.ts +39 -73
- package/dist/client/IndexedDBStore.js +17 -220
- package/dist/client/LWWAlgorithm.d.ts +43 -0
- package/dist/client/LWWAlgorithm.js +87 -0
- package/dist/client/LWWClientStore.d.ts +73 -0
- package/dist/client/LWWClientStore.js +0 -0
- package/dist/client/LWWDoc.d.ts +56 -0
- package/dist/client/LWWDoc.js +84 -0
- package/dist/client/LWWInMemoryStore.d.ts +88 -0
- package/dist/client/LWWInMemoryStore.js +208 -0
- package/dist/client/LWWIndexedDBStore.d.ts +91 -0
- package/dist/client/LWWIndexedDBStore.js +275 -0
- package/dist/client/OTAlgorithm.d.ts +42 -0
- package/dist/client/OTAlgorithm.js +113 -0
- package/dist/client/OTClientStore.d.ts +50 -0
- package/dist/client/OTClientStore.js +0 -0
- package/dist/client/OTDoc.d.ts +6 -0
- package/dist/client/OTDoc.js +97 -0
- package/dist/client/OTIndexedDBStore.d.ts +84 -0
- package/dist/client/OTIndexedDBStore.js +163 -0
- package/dist/client/Patches.d.ts +36 -16
- package/dist/client/Patches.js +60 -27
- package/dist/client/PatchesDoc.d.ts +4 -113
- package/dist/client/PatchesDoc.js +3 -153
- package/dist/client/PatchesStore.d.ts +8 -105
- package/dist/client/factories.d.ts +72 -0
- package/dist/client/factories.js +80 -0
- package/dist/client/index.d.ts +14 -5
- package/dist/client/index.js +9 -0
- package/dist/compression/index.d.ts +1 -1
- package/dist/data/change.js +4 -3
- package/dist/fractionalIndex.d.ts +67 -0
- package/dist/fractionalIndex.js +241 -0
- package/dist/index.d.ts +13 -4
- package/dist/index.js +1 -1
- package/dist/json-patch/types.d.ts +2 -0
- package/dist/net/PatchesClient.js +15 -15
- package/dist/net/PatchesSync.d.ts +24 -12
- package/dist/net/PatchesSync.js +56 -64
- package/dist/net/index.d.ts +6 -10
- package/dist/net/index.js +6 -1
- package/dist/net/protocol/JSONRPCClient.d.ts +4 -4
- package/dist/net/protocol/JSONRPCClient.js +6 -4
- package/dist/net/protocol/JSONRPCServer.d.ts +45 -9
- package/dist/net/protocol/JSONRPCServer.js +63 -8
- package/dist/net/serverContext.d.ts +38 -0
- package/dist/net/serverContext.js +20 -0
- package/dist/net/webrtc/WebRTCTransport.js +1 -1
- package/dist/net/websocket/AuthorizationProvider.d.ts +3 -3
- package/dist/net/websocket/WebSocketServer.d.ts +29 -20
- package/dist/net/websocket/WebSocketServer.js +23 -12
- package/dist/server/BranchManager.d.ts +50 -0
- package/dist/server/BranchManager.js +0 -0
- package/dist/server/CompressedStoreBackend.d.ts +8 -6
- package/dist/server/CompressedStoreBackend.js +3 -9
- package/dist/server/LWWBranchManager.d.ts +82 -0
- package/dist/server/LWWBranchManager.js +99 -0
- package/dist/server/LWWMemoryStoreBackend.d.ts +78 -0
- package/dist/server/LWWMemoryStoreBackend.js +191 -0
- package/dist/server/LWWServer.d.ts +130 -0
- package/dist/server/LWWServer.js +207 -0
- package/dist/server/{PatchesBranchManager.d.ts → OTBranchManager.d.ts} +32 -12
- package/dist/server/{PatchesBranchManager.js → OTBranchManager.js} +26 -42
- package/dist/server/OTServer.d.ts +108 -0
- package/dist/server/OTServer.js +141 -0
- package/dist/server/PatchesHistoryManager.d.ts +20 -7
- package/dist/server/PatchesHistoryManager.js +26 -3
- package/dist/server/PatchesServer.d.ts +70 -81
- package/dist/server/PatchesServer.js +0 -176
- package/dist/server/branchUtils.d.ts +82 -0
- package/dist/server/branchUtils.js +66 -0
- package/dist/server/index.d.ts +17 -6
- package/dist/server/index.js +33 -4
- package/dist/server/tombstone.d.ts +29 -0
- package/dist/server/tombstone.js +32 -0
- package/dist/server/types.d.ts +129 -27
- package/dist/server/utils.d.ts +12 -0
- package/dist/server/utils.js +23 -0
- package/dist/solid/context.d.ts +5 -4
- package/dist/solid/doc-manager.d.ts +3 -3
- package/dist/solid/index.d.ts +5 -4
- package/dist/solid/primitives.d.ts +2 -3
- package/dist/types.d.ts +16 -14
- package/dist/vue/composables.d.ts +2 -3
- package/dist/vue/doc-manager.d.ts +3 -3
- package/dist/vue/index.d.ts +5 -4
- package/dist/vue/provider.d.ts +5 -4
- package/package.json +1 -1
- package/dist/algorithms/client/collapsePendingChanges.d.ts +0 -30
- package/dist/algorithms/client/collapsePendingChanges.js +0 -78
- package/dist/net/websocket/RPCServer.d.ts +0 -141
- package/dist/net/websocket/RPCServer.js +0 -204
- package/dist/utils/dates.d.ts +0 -43
- package/dist/utils/dates.js +0 -47
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import "../chunk-IZ2YBCUP.js";
|
|
2
|
+
import { InMemoryStore } from "./InMemoryStore.js";
|
|
3
|
+
import { LWWInMemoryStore } from "./LWWInMemoryStore.js";
|
|
4
|
+
import { LWWIndexedDBStore } from "./LWWIndexedDBStore.js";
|
|
5
|
+
import { LWWAlgorithm } from "./LWWAlgorithm.js";
|
|
6
|
+
import { OTIndexedDBStore } from "./OTIndexedDBStore.js";
|
|
7
|
+
import { OTAlgorithm } from "./OTAlgorithm.js";
|
|
8
|
+
import { Patches } from "./Patches.js";
|
|
9
|
+
function createOTPatches(options = {}) {
|
|
10
|
+
const store = new InMemoryStore();
|
|
11
|
+
const otAlgorithm = new OTAlgorithm(store, options.docOptions);
|
|
12
|
+
return new Patches({
|
|
13
|
+
algorithms: { ot: otAlgorithm },
|
|
14
|
+
defaultAlgorithm: "ot",
|
|
15
|
+
metadata: options.metadata,
|
|
16
|
+
docOptions: options.docOptions
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
function createOTIndexedDBPatches(options) {
|
|
20
|
+
const store = new OTIndexedDBStore(options.dbName);
|
|
21
|
+
const otAlgorithm = new OTAlgorithm(store, options.docOptions);
|
|
22
|
+
return new Patches({
|
|
23
|
+
algorithms: { ot: otAlgorithm },
|
|
24
|
+
defaultAlgorithm: "ot",
|
|
25
|
+
metadata: options.metadata,
|
|
26
|
+
docOptions: options.docOptions
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
function createLWWPatches(options = {}) {
|
|
30
|
+
const store = new LWWInMemoryStore();
|
|
31
|
+
const lwwAlgorithm = new LWWAlgorithm(store);
|
|
32
|
+
return new Patches({
|
|
33
|
+
algorithms: { lww: lwwAlgorithm },
|
|
34
|
+
defaultAlgorithm: "lww",
|
|
35
|
+
metadata: options.metadata,
|
|
36
|
+
docOptions: options.docOptions
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
function createLWWIndexedDBPatches(options) {
|
|
40
|
+
const store = new LWWIndexedDBStore(options.dbName);
|
|
41
|
+
const lwwAlgorithm = new LWWAlgorithm(store);
|
|
42
|
+
return new Patches({
|
|
43
|
+
algorithms: { lww: lwwAlgorithm },
|
|
44
|
+
defaultAlgorithm: "lww",
|
|
45
|
+
metadata: options.metadata,
|
|
46
|
+
docOptions: options.docOptions
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function createAllPatches(options = {}) {
|
|
50
|
+
const otStore = new InMemoryStore();
|
|
51
|
+
const lwwStore = new LWWInMemoryStore();
|
|
52
|
+
const otAlgorithm = new OTAlgorithm(otStore, options.docOptions);
|
|
53
|
+
const lwwAlgorithm = new LWWAlgorithm(lwwStore);
|
|
54
|
+
return new Patches({
|
|
55
|
+
algorithms: { ot: otAlgorithm, lww: lwwAlgorithm },
|
|
56
|
+
defaultAlgorithm: options.defaultAlgorithm ?? "ot",
|
|
57
|
+
metadata: options.metadata,
|
|
58
|
+
docOptions: options.docOptions
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function createAllIndexedDBPatches(options) {
|
|
62
|
+
const otStore = new OTIndexedDBStore(options.dbName);
|
|
63
|
+
const lwwStore = new LWWIndexedDBStore(`${options.dbName}-lww`);
|
|
64
|
+
const otAlgorithm = new OTAlgorithm(otStore, options.docOptions);
|
|
65
|
+
const lwwAlgorithm = new LWWAlgorithm(lwwStore);
|
|
66
|
+
return new Patches({
|
|
67
|
+
algorithms: { ot: otAlgorithm, lww: lwwAlgorithm },
|
|
68
|
+
defaultAlgorithm: options.defaultAlgorithm ?? "ot",
|
|
69
|
+
metadata: options.metadata,
|
|
70
|
+
docOptions: options.docOptions
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
export {
|
|
74
|
+
createAllIndexedDBPatches,
|
|
75
|
+
createAllPatches,
|
|
76
|
+
createLWWIndexedDBPatches,
|
|
77
|
+
createLWWPatches,
|
|
78
|
+
createOTIndexedDBPatches,
|
|
79
|
+
createOTPatches
|
|
80
|
+
};
|
package/dist/client/index.d.ts
CHANGED
|
@@ -1,14 +1,23 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from '../BaseDoc-DkP3tUhT.js';
|
|
2
|
+
export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createAllIndexedDBPatches, createAllPatches, createLWWIndexedDBPatches, createLWWPatches, createOTIndexedDBPatches, createOTPatches } from './factories.js';
|
|
3
|
+
export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './IndexedDBStore.js';
|
|
4
|
+
export { OTIndexedDBStore } from './OTIndexedDBStore.js';
|
|
5
|
+
export { LWWIndexedDBStore } from './LWWIndexedDBStore.js';
|
|
2
6
|
export { InMemoryStore } from './InMemoryStore.js';
|
|
7
|
+
export { LWWInMemoryStore } from './LWWInMemoryStore.js';
|
|
8
|
+
export { LWWDoc } from './LWWDoc.js';
|
|
9
|
+
export { LWWAlgorithm } from './LWWAlgorithm.js';
|
|
10
|
+
export { OTAlgorithm } from './OTAlgorithm.js';
|
|
3
11
|
export { Patches, PatchesOptions } from './Patches.js';
|
|
4
|
-
export { PatchesDoc, PatchesDocOptions } from './PatchesDoc.js';
|
|
5
12
|
export { PatchesHistoryClient } from './PatchesHistoryClient.js';
|
|
6
13
|
export { PatchesStore, TrackedDoc } from './PatchesStore.js';
|
|
14
|
+
export { OTClientStore } from './OTClientStore.js';
|
|
15
|
+
export { LWWClientStore } from './LWWClientStore.js';
|
|
16
|
+
export { AlgorithmName, ClientAlgorithm } from './ClientAlgorithm.js';
|
|
17
|
+
import '../event-signal.js';
|
|
18
|
+
import '../json-patch/types.js';
|
|
7
19
|
import '../types.js';
|
|
8
20
|
import '../json-patch/JSONPatch.js';
|
|
9
21
|
import '@dabble/delta';
|
|
10
|
-
import '../json-patch/types.js';
|
|
11
22
|
import '../utils/deferred.js';
|
|
12
|
-
import '../event-signal.js';
|
|
13
|
-
import '../algorithms/shared/changeBatching.js';
|
|
14
23
|
import '../net/protocol/types.js';
|
package/dist/client/index.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
|
+
export * from "./BaseDoc.js";
|
|
2
|
+
export * from "./factories.js";
|
|
1
3
|
export * from "./IndexedDBStore.js";
|
|
4
|
+
export * from "./OTIndexedDBStore.js";
|
|
5
|
+
export * from "./LWWIndexedDBStore.js";
|
|
2
6
|
export * from "./InMemoryStore.js";
|
|
7
|
+
export * from "./LWWInMemoryStore.js";
|
|
8
|
+
export * from "./LWWDoc.js";
|
|
9
|
+
export * from "./LWWAlgorithm.js";
|
|
10
|
+
export * from "./OTDoc.js";
|
|
11
|
+
export * from "./OTAlgorithm.js";
|
|
3
12
|
export * from "./Patches.js";
|
|
4
13
|
export * from "./PatchesDoc.js";
|
|
5
14
|
export * from "./PatchesHistoryClient.js";
|
|
@@ -12,7 +12,7 @@ import { JSONPatchOp } from '../json-patch/types.js';
|
|
|
12
12
|
* ```typescript
|
|
13
13
|
* import { compressedSizeBase64 } from '@dabble/patches/compression';
|
|
14
14
|
*
|
|
15
|
-
* new
|
|
15
|
+
* new OTDoc(state, {}, {
|
|
16
16
|
* sizeCalculator: compressedSizeBase64,
|
|
17
17
|
* maxStorageBytes: 1_000_000
|
|
18
18
|
* });
|
package/dist/data/change.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import "../chunk-IZ2YBCUP.js";
|
|
2
2
|
import { inc } from "alphacounter";
|
|
3
3
|
import { createId } from "crypto-id";
|
|
4
|
-
import { getLocalISO } from "../utils/dates.js";
|
|
5
4
|
function createChangeId(rev) {
|
|
6
5
|
return inc.from(rev) + createId(4);
|
|
7
6
|
}
|
|
@@ -10,7 +9,7 @@ function createChange(baseRev, rev, ops, metadata) {
|
|
|
10
9
|
return {
|
|
11
10
|
id: createId(8),
|
|
12
11
|
ops: baseRev,
|
|
13
|
-
createdAt:
|
|
12
|
+
createdAt: Date.now(),
|
|
14
13
|
...rev
|
|
15
14
|
};
|
|
16
15
|
} else {
|
|
@@ -19,7 +18,9 @@ function createChange(baseRev, rev, ops, metadata) {
|
|
|
19
18
|
baseRev,
|
|
20
19
|
rev,
|
|
21
20
|
ops,
|
|
22
|
-
createdAt:
|
|
21
|
+
createdAt: Date.now(),
|
|
22
|
+
committedAt: 0,
|
|
23
|
+
// Set to 0 for uncommitted changes; server sets actual timestamp on commit
|
|
23
24
|
...metadata
|
|
24
25
|
};
|
|
25
26
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate a fractional index which is a sortable string(s) between a and b. Use an empty string or null/undefined to
|
|
3
|
+
* represent the start and end of the range.
|
|
4
|
+
*
|
|
5
|
+
* Pass a count to generate N fractional indexes between a and b.
|
|
6
|
+
*
|
|
7
|
+
* See https://www.figma.com/blog/realtime-editing-of-ordered-sequences/#fractional-indexing and
|
|
8
|
+
* https://observablehq.com/@dgreensp/implementing-fractional-indexing for more information.
|
|
9
|
+
*/
|
|
10
|
+
declare function fractionalIndex(a: string | undefined | null, b: string | undefined | null): string;
|
|
11
|
+
declare function fractionalIndex(a: string | undefined | null, b: string | undefined | null, count: number): string[];
|
|
12
|
+
declare namespace fractionalIndex {
|
|
13
|
+
var sort: typeof sortByOrder;
|
|
14
|
+
var heal: typeof healDuplicateOrders;
|
|
15
|
+
}
|
|
16
|
+
/** Order field parameter type: field name, or false when values are order strings directly */
|
|
17
|
+
type OrderFieldParam = string | false;
|
|
18
|
+
/**
|
|
19
|
+
* Sort a map of items by their fractional index order, with key as tiebreaker.
|
|
20
|
+
*
|
|
21
|
+
* @param items - Object keyed by ID. Values can be objects with an order field, or strings (the order itself).
|
|
22
|
+
* @param orderField - The field name containing the order string (default: 'order'). Use false if values ARE the order strings.
|
|
23
|
+
* @returns Array of [key, value] tuples sorted by order, then by key
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* // Objects with 'order' field (default)
|
|
27
|
+
* const sorted = sortByOrder({ b: { order: 'a2' }, a: { order: 'a1' } });
|
|
28
|
+
* // [['a', { order: 'a1' }], ['b', { order: 'a2' }]]
|
|
29
|
+
*
|
|
30
|
+
* @example
|
|
31
|
+
* // Values are the order strings directly
|
|
32
|
+
* const sorted = sortByOrder({ b: 'a2', a: 'a1' }, false);
|
|
33
|
+
* // [['a', 'a1'], ['b', 'a2']]
|
|
34
|
+
*/
|
|
35
|
+
declare function sortByOrder<T extends Record<string, unknown> | string>(items: Record<string, T>, orderField?: OrderFieldParam): Array<[string, T]>;
|
|
36
|
+
/**
|
|
37
|
+
* Detect duplicate `order` values and return fixes. Duplicates can occur when multiple
|
|
38
|
+
* clients generate the same fractional index while offline (e.g., both appending to a list).
|
|
39
|
+
*
|
|
40
|
+
* This function does NOT mutate the input. Apply the returned fixes using your change API.
|
|
41
|
+
*
|
|
42
|
+
* @param items - Object keyed by ID. Values can be objects with an order field, or strings (the order itself).
|
|
43
|
+
* @param orderField - The field name containing the order string (default: 'order'). Use false if values ARE the order strings.
|
|
44
|
+
* @returns Map of key → new order string, or null if no duplicates found
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* // Objects with 'order' field (default)
|
|
48
|
+
* const fixes = healDuplicateOrders({ a: { order: 'a1' }, b: { order: 'a1' } });
|
|
49
|
+
* if (fixes) {
|
|
50
|
+
* doc.change((patch, root) => {
|
|
51
|
+
* for (const [key, newOrder] of Object.entries(fixes)) {
|
|
52
|
+
* patch.replace(root.items[key].order, newOrder);
|
|
53
|
+
* }
|
|
54
|
+
* });
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* @example
|
|
58
|
+
* // Objects with custom field name
|
|
59
|
+
* const fixes = healDuplicateOrders({ a: { sortKey: 'a1' } }, 'sortKey');
|
|
60
|
+
*
|
|
61
|
+
* @example
|
|
62
|
+
* // Values are the order strings directly
|
|
63
|
+
* const fixes = healDuplicateOrders({ a: 'a1', b: 'a1' }, false);
|
|
64
|
+
*/
|
|
65
|
+
declare function healDuplicateOrders<T extends Record<string, unknown> | string>(items: Record<string, T>, orderField?: OrderFieldParam): Record<string, string> | null;
|
|
66
|
+
|
|
67
|
+
export { fractionalIndex, healDuplicateOrders, sortByOrder };
|
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
import "./chunk-IZ2YBCUP.js";
|
|
2
|
+
const digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
|
3
|
+
const INTEGER_ZERO = "a0";
|
|
4
|
+
const SMALLEST_INTEGER = "A00000000000000000000000000";
|
|
5
|
+
const LARGEST_INTEGER = "zzzzzzzzzzzzzzzzzzzzzzzzzzz";
|
|
6
|
+
const ZERO = digits[0];
|
|
7
|
+
fractionalIndex.sort = sortByOrder;
|
|
8
|
+
fractionalIndex.heal = healDuplicateOrders;
|
|
9
|
+
function fractionalIndex(a, b, count) {
|
|
10
|
+
if (count !== void 0) {
|
|
11
|
+
if (count === 0) {
|
|
12
|
+
return [];
|
|
13
|
+
}
|
|
14
|
+
if (count === 1) {
|
|
15
|
+
return [fractionalIndex(a, b)];
|
|
16
|
+
}
|
|
17
|
+
if (!b) {
|
|
18
|
+
let c2 = fractionalIndex(a, b);
|
|
19
|
+
const result = [c2];
|
|
20
|
+
for (let i2 = 0; i2 < count - 1; i2++) {
|
|
21
|
+
c2 = fractionalIndex(c2, b);
|
|
22
|
+
result.push(c2);
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
}
|
|
26
|
+
if (!a) {
|
|
27
|
+
let c2 = fractionalIndex(a, b);
|
|
28
|
+
const result = [c2];
|
|
29
|
+
for (let i2 = 0; i2 < count - 1; i2++) {
|
|
30
|
+
c2 = fractionalIndex(a, c2);
|
|
31
|
+
result.push(c2);
|
|
32
|
+
}
|
|
33
|
+
result.reverse();
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
const mid = Math.floor(count / 2);
|
|
37
|
+
const c = fractionalIndex(a, b);
|
|
38
|
+
return [...fractionalIndex(a, c, mid), c, ...fractionalIndex(c, b, count - mid - 1)];
|
|
39
|
+
}
|
|
40
|
+
if (a && b && a >= b) {
|
|
41
|
+
[a, b] = [b, a];
|
|
42
|
+
}
|
|
43
|
+
if (!a && !b) {
|
|
44
|
+
return INTEGER_ZERO;
|
|
45
|
+
}
|
|
46
|
+
if (a) {
|
|
47
|
+
validatestring(a, true);
|
|
48
|
+
}
|
|
49
|
+
if (b) {
|
|
50
|
+
validatestring(b, false);
|
|
51
|
+
}
|
|
52
|
+
if (!a) {
|
|
53
|
+
const ib2 = getIntegerPart(b);
|
|
54
|
+
const fb2 = b.slice(ib2.length);
|
|
55
|
+
if (ib2 === SMALLEST_INTEGER) {
|
|
56
|
+
return ib2 + midpoint("", fb2);
|
|
57
|
+
}
|
|
58
|
+
return ib2 < b ? ib2 : decrementInteger(ib2);
|
|
59
|
+
}
|
|
60
|
+
if (!b) {
|
|
61
|
+
const ia2 = getIntegerPart(a);
|
|
62
|
+
const fa2 = a.slice(ia2.length);
|
|
63
|
+
const i2 = incrementInteger(ia2);
|
|
64
|
+
return !i2 ? ia2 + midpoint(fa2, null) : i2;
|
|
65
|
+
}
|
|
66
|
+
const ia = getIntegerPart(a);
|
|
67
|
+
const fa = a.slice(ia.length);
|
|
68
|
+
const ib = getIntegerPart(b);
|
|
69
|
+
const fb = b.slice(ib.length);
|
|
70
|
+
if (ia === ib) {
|
|
71
|
+
return ia + midpoint(fa, fb);
|
|
72
|
+
}
|
|
73
|
+
const i = incrementInteger(ia);
|
|
74
|
+
return i < b ? i : ia + midpoint(fa, null);
|
|
75
|
+
}
|
|
76
|
+
function midpoint(a, b) {
|
|
77
|
+
if (a && b && a >= b) {
|
|
78
|
+
[a, b] = [b, a];
|
|
79
|
+
}
|
|
80
|
+
if (a && a.slice(-1) === ZERO || b && b.slice(-1) === ZERO) {
|
|
81
|
+
throw new Error("Trailing zero");
|
|
82
|
+
}
|
|
83
|
+
if (!a) a = "";
|
|
84
|
+
if (b) {
|
|
85
|
+
let n = 0;
|
|
86
|
+
while ((a[n] || ZERO) === b[n]) {
|
|
87
|
+
n++;
|
|
88
|
+
}
|
|
89
|
+
if (n > 0) {
|
|
90
|
+
return b.slice(0, n) + midpoint(a.slice(n), b.slice(n));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const digitA = a ? digits.indexOf(a[0]) : 0;
|
|
94
|
+
const digitB = b ? digits.indexOf(b[0]) : digits.length;
|
|
95
|
+
if (digitB - digitA > 1) {
|
|
96
|
+
const midDigit = Math.round(0.5 * (digitA + digitB));
|
|
97
|
+
return digits[midDigit];
|
|
98
|
+
} else {
|
|
99
|
+
if (b && b.length > 1) {
|
|
100
|
+
return b.slice(0, 1);
|
|
101
|
+
} else {
|
|
102
|
+
return digits[digitA] + midpoint(a?.slice(1), null);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function getIntegerLength(head) {
|
|
107
|
+
if (head >= "a" && head <= "z") {
|
|
108
|
+
return head.charCodeAt(0) - "a".charCodeAt(0) + 2;
|
|
109
|
+
} else if (head >= "A" && head <= "Z") {
|
|
110
|
+
return "Z".charCodeAt(0) - head.charCodeAt(0) + 2;
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error("Invalid order key head: " + head);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
function validateInteger(int) {
|
|
116
|
+
if (int.length !== getIntegerLength(int[0])) {
|
|
117
|
+
throw new Error("Invalid integer part of order key: " + int);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function incrementInteger(x) {
|
|
121
|
+
validateInteger(x);
|
|
122
|
+
const [head, ...digs] = x.split("");
|
|
123
|
+
let carry = true;
|
|
124
|
+
for (let i = digs.length - 1; carry && i >= 0; i--) {
|
|
125
|
+
const d = digits.indexOf(digs[i]) + 1;
|
|
126
|
+
if (d === digits.length) {
|
|
127
|
+
digs[i] = ZERO;
|
|
128
|
+
} else {
|
|
129
|
+
digs[i] = digits[d];
|
|
130
|
+
carry = false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
if (carry) {
|
|
134
|
+
if (head === "Z") {
|
|
135
|
+
return "a0";
|
|
136
|
+
}
|
|
137
|
+
if (head === "z") {
|
|
138
|
+
return "";
|
|
139
|
+
}
|
|
140
|
+
const h = String.fromCharCode(head.charCodeAt(0) + 1);
|
|
141
|
+
if (h > "a") {
|
|
142
|
+
digs.push(ZERO);
|
|
143
|
+
} else {
|
|
144
|
+
digs.pop();
|
|
145
|
+
}
|
|
146
|
+
return h + digs.join("");
|
|
147
|
+
} else {
|
|
148
|
+
return head + digs.join("");
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
function decrementInteger(x) {
|
|
152
|
+
validateInteger(x);
|
|
153
|
+
const [head, ...digs] = x.split("");
|
|
154
|
+
let borrow = true;
|
|
155
|
+
for (let i = digs.length - 1; borrow && i >= 0; i--) {
|
|
156
|
+
const d = digits.indexOf(digs[i]) - 1;
|
|
157
|
+
if (d === -1) {
|
|
158
|
+
digs[i] = digits.slice(-1);
|
|
159
|
+
} else {
|
|
160
|
+
digs[i] = digits[d];
|
|
161
|
+
borrow = false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
if (borrow) {
|
|
165
|
+
if (head === "a") {
|
|
166
|
+
return "Z" + digits.slice(-1);
|
|
167
|
+
}
|
|
168
|
+
if (head === "A") {
|
|
169
|
+
return "";
|
|
170
|
+
}
|
|
171
|
+
const h = String.fromCharCode(head.charCodeAt(0) - 1);
|
|
172
|
+
if (h < "Z") {
|
|
173
|
+
digs.push(digits.slice(-1));
|
|
174
|
+
} else {
|
|
175
|
+
digs.pop();
|
|
176
|
+
}
|
|
177
|
+
return h + digs.join("");
|
|
178
|
+
} else {
|
|
179
|
+
return head + digs.join("");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
function getIntegerPart(key) {
|
|
183
|
+
const integerPartLength = getIntegerLength(key[0]);
|
|
184
|
+
if (integerPartLength > key.length) {
|
|
185
|
+
throw new Error("Invalid order key: " + key);
|
|
186
|
+
}
|
|
187
|
+
return key.slice(0, integerPartLength);
|
|
188
|
+
}
|
|
189
|
+
function validatestring(key, lowValue) {
|
|
190
|
+
if (lowValue && key === LARGEST_INTEGER || !lowValue && key === SMALLEST_INTEGER) {
|
|
191
|
+
throw new Error("Invalid order key: " + key);
|
|
192
|
+
}
|
|
193
|
+
const i = getIntegerPart(key);
|
|
194
|
+
const f = key.slice(i.length);
|
|
195
|
+
if (f.slice(-1) === ZERO) {
|
|
196
|
+
throw new Error("Invalid order key: " + key);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
function createOrderGetter(orderField) {
|
|
200
|
+
return orderField === false ? (value) => value : (value) => value[orderField];
|
|
201
|
+
}
|
|
202
|
+
function sortByOrder(items, orderField = "order") {
|
|
203
|
+
const getOrder = createOrderGetter(orderField);
|
|
204
|
+
return Object.entries(items).sort((a, b) => {
|
|
205
|
+
const orderCmp = getOrder(a[1]).localeCompare(getOrder(b[1]));
|
|
206
|
+
if (orderCmp !== 0) return orderCmp;
|
|
207
|
+
return a[0].localeCompare(b[0]);
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
function healDuplicateOrders(items, orderField = "order") {
|
|
211
|
+
const getOrder = createOrderGetter(orderField);
|
|
212
|
+
const fixes = {};
|
|
213
|
+
const entries = sortByOrder(items, orderField);
|
|
214
|
+
if (entries.length < 2) return null;
|
|
215
|
+
let prevOrder = getOrder(entries[0][1]);
|
|
216
|
+
for (let i = 1; i < entries.length; i++) {
|
|
217
|
+
const [key, item] = entries[i];
|
|
218
|
+
const currentOrder = getOrder(item);
|
|
219
|
+
if (currentOrder <= prevOrder) {
|
|
220
|
+
let nextOrder = null;
|
|
221
|
+
for (let j = i + 1; j < entries.length; j++) {
|
|
222
|
+
const candidateOrder = getOrder(entries[j][1]);
|
|
223
|
+
if (candidateOrder > prevOrder) {
|
|
224
|
+
nextOrder = candidateOrder;
|
|
225
|
+
break;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
const newOrder = fractionalIndex(prevOrder, nextOrder);
|
|
229
|
+
fixes[key] = newOrder;
|
|
230
|
+
prevOrder = newOrder;
|
|
231
|
+
} else {
|
|
232
|
+
prevOrder = currentOrder;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return Object.keys(fixes).length > 0 ? fixes : null;
|
|
236
|
+
}
|
|
237
|
+
export {
|
|
238
|
+
fractionalIndex,
|
|
239
|
+
healDuplicateOrders,
|
|
240
|
+
sortByOrder
|
|
241
|
+
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,24 @@
|
|
|
1
1
|
export { Delta } from '@dabble/delta';
|
|
2
|
-
export {
|
|
2
|
+
export { B as BaseDoc, O as OTDoc, a as PatchesDoc, O as PatchesDocClass, P as PatchesDocOptions } from './BaseDoc-DkP3tUhT.js';
|
|
3
|
+
export { IndexedDBFactoryOptions, MultiAlgorithmFactoryOptions, MultiAlgorithmIndexedDBFactoryOptions, PatchesFactoryOptions, createAllIndexedDBPatches, createAllPatches, createLWWIndexedDBPatches, createLWWPatches, createOTIndexedDBPatches, createOTPatches } from './client/factories.js';
|
|
4
|
+
export { IDBStoreWrapper, IDBTransactionWrapper, IndexedDBStore } from './client/IndexedDBStore.js';
|
|
5
|
+
export { OTIndexedDBStore } from './client/OTIndexedDBStore.js';
|
|
6
|
+
export { LWWIndexedDBStore } from './client/LWWIndexedDBStore.js';
|
|
3
7
|
export { InMemoryStore } from './client/InMemoryStore.js';
|
|
8
|
+
export { LWWInMemoryStore } from './client/LWWInMemoryStore.js';
|
|
9
|
+
export { LWWDoc } from './client/LWWDoc.js';
|
|
10
|
+
export { LWWAlgorithm } from './client/LWWAlgorithm.js';
|
|
11
|
+
export { OTAlgorithm } from './client/OTAlgorithm.js';
|
|
4
12
|
export { Patches, PatchesOptions } from './client/Patches.js';
|
|
5
|
-
export { PatchesDoc, PatchesDocOptions } from './client/PatchesDoc.js';
|
|
6
13
|
export { PatchesHistoryClient } from './client/PatchesHistoryClient.js';
|
|
7
14
|
export { PatchesStore, TrackedDoc } from './client/PatchesStore.js';
|
|
15
|
+
export { OTClientStore } from './client/OTClientStore.js';
|
|
16
|
+
export { LWWClientStore } from './client/LWWClientStore.js';
|
|
17
|
+
export { AlgorithmName, ClientAlgorithm } from './client/ClientAlgorithm.js';
|
|
8
18
|
export { createChange } from './data/change.js';
|
|
9
19
|
export { createVersionId, createVersionMetadata } from './data/version.js';
|
|
10
20
|
export { ErrorSubscriber, Signal, SignalSubscriber, Unsubscriber, signal } from './event-signal.js';
|
|
21
|
+
export { fractionalIndex, healDuplicateOrders, sortByOrder } from './fractionalIndex.js';
|
|
11
22
|
export { applyPatch } from './json-patch/applyPatch.js';
|
|
12
23
|
export { composePatch } from './json-patch/composePatch.js';
|
|
13
24
|
export { invertPatch } from './json-patch/invertPatch.js';
|
|
@@ -18,7 +29,6 @@ export { transformPatch } from './json-patch/transformPatch.js';
|
|
|
18
29
|
export { JSONPatch, PathLike, WriteOptions } from './json-patch/JSONPatch.js';
|
|
19
30
|
export { ApplyJSONPatchOptions, JSONPatchOpHandlerMap as JSONPatchCustomTypes, JSONPatchOp } from './json-patch/types.js';
|
|
20
31
|
export { Branch, BranchStatus, Change, ChangeInput, ChangeMutator, CommitChangesOptions, DeleteDocOptions, DocumentTombstone, EditableBranchMetadata, EditableVersionMetadata, ListChangesOptions, ListVersionsOptions, PatchesSnapshot, PatchesState, PathProxy, SyncingState, VersionMetadata } from './types.js';
|
|
21
|
-
export { clampTimestamp, extractTimezoneOffset, getISO, getLocalISO, getLocalTimezoneOffset, timestampDiff } from './utils/dates.js';
|
|
22
32
|
export { add } from './json-patch/ops/add.js';
|
|
23
33
|
export { copy } from './json-patch/ops/copy.js';
|
|
24
34
|
export { increment } from './json-patch/ops/increment.js';
|
|
@@ -28,5 +38,4 @@ export { remove } from './json-patch/ops/remove.js';
|
|
|
28
38
|
export { replace } from './json-patch/ops/replace.js';
|
|
29
39
|
export { test } from './json-patch/ops/test.js';
|
|
30
40
|
import './utils/deferred.js';
|
|
31
|
-
import './algorithms/shared/changeBatching.js';
|
|
32
41
|
import './net/protocol/types.js';
|
package/dist/index.js
CHANGED
|
@@ -4,8 +4,8 @@ export * from "./client/index.js";
|
|
|
4
4
|
export * from "./data/change.js";
|
|
5
5
|
export * from "./data/version.js";
|
|
6
6
|
export * from "./event-signal.js";
|
|
7
|
+
export * from "./fractionalIndex.js";
|
|
7
8
|
export * from "./json-patch/index.js";
|
|
8
|
-
export * from "./utils/dates.js";
|
|
9
9
|
export {
|
|
10
10
|
Delta
|
|
11
11
|
};
|
|
@@ -33,7 +33,7 @@ class PatchesClient {
|
|
|
33
33
|
* @returns A promise resolving with the list of successfully subscribed document IDs.
|
|
34
34
|
*/
|
|
35
35
|
async subscribe(ids) {
|
|
36
|
-
return this.rpc.call("subscribe",
|
|
36
|
+
return this.rpc.call("subscribe", ids);
|
|
37
37
|
}
|
|
38
38
|
/**
|
|
39
39
|
* Unsubscribes the client from one or more documents.
|
|
@@ -41,7 +41,7 @@ class PatchesClient {
|
|
|
41
41
|
* @returns A promise resolving when the unsubscription is confirmed.
|
|
42
42
|
*/
|
|
43
43
|
async unsubscribe(ids) {
|
|
44
|
-
return this.rpc.call("unsubscribe",
|
|
44
|
+
return this.rpc.call("unsubscribe", ids);
|
|
45
45
|
}
|
|
46
46
|
// === Document Operations ===
|
|
47
47
|
/**
|
|
@@ -50,7 +50,7 @@ class PatchesClient {
|
|
|
50
50
|
* @returns A promise resolving with the document snapshot.
|
|
51
51
|
*/
|
|
52
52
|
async getDoc(docId, atRev) {
|
|
53
|
-
return this.rpc.call("getDoc",
|
|
53
|
+
return this.rpc.call("getDoc", docId, atRev);
|
|
54
54
|
}
|
|
55
55
|
/**
|
|
56
56
|
* Gets changes that occurred for a document after a specific revision number.
|
|
@@ -59,7 +59,7 @@ class PatchesClient {
|
|
|
59
59
|
* @returns A promise resolving with an array of changes.
|
|
60
60
|
*/
|
|
61
61
|
async getChangesSince(docId, rev) {
|
|
62
|
-
return this.rpc.call("getChangesSince",
|
|
62
|
+
return this.rpc.call("getChangesSince", docId, rev);
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
65
|
* Applies a set of client-generated changes to a document on the server.
|
|
@@ -69,7 +69,7 @@ class PatchesClient {
|
|
|
69
69
|
* @returns A promise resolving with the changes as committed by the server (potentially transformed).
|
|
70
70
|
*/
|
|
71
71
|
async commitChanges(docId, changes, options) {
|
|
72
|
-
return this.rpc.call("commitChanges",
|
|
72
|
+
return this.rpc.call("commitChanges", docId, changes, options);
|
|
73
73
|
}
|
|
74
74
|
/**
|
|
75
75
|
* Deletes a document on the server.
|
|
@@ -78,7 +78,7 @@ class PatchesClient {
|
|
|
78
78
|
* @returns A promise resolving when the deletion is confirmed.
|
|
79
79
|
*/
|
|
80
80
|
async deleteDoc(docId, options) {
|
|
81
|
-
return this.rpc.call("deleteDoc",
|
|
81
|
+
return this.rpc.call("deleteDoc", docId, options);
|
|
82
82
|
}
|
|
83
83
|
// === Version Operations ===
|
|
84
84
|
/**
|
|
@@ -88,7 +88,7 @@ class PatchesClient {
|
|
|
88
88
|
* @returns A promise resolving with the unique ID of the newly created version.
|
|
89
89
|
*/
|
|
90
90
|
async createVersion(docId, metadata) {
|
|
91
|
-
return this.rpc.call("createVersion",
|
|
91
|
+
return this.rpc.call("createVersion", docId, metadata);
|
|
92
92
|
}
|
|
93
93
|
/**
|
|
94
94
|
* Lists metadata for saved versions of a document.
|
|
@@ -97,7 +97,7 @@ class PatchesClient {
|
|
|
97
97
|
* @returns A promise resolving with an array of version metadata objects.
|
|
98
98
|
*/
|
|
99
99
|
async listVersions(docId, options) {
|
|
100
|
-
return this.rpc.call("listVersions",
|
|
100
|
+
return this.rpc.call("listVersions", docId, options);
|
|
101
101
|
}
|
|
102
102
|
/**
|
|
103
103
|
* Gets the document state snapshot corresponding to a specific version ID.
|
|
@@ -106,7 +106,7 @@ class PatchesClient {
|
|
|
106
106
|
* @returns A promise resolving with the document snapshot for that version.
|
|
107
107
|
*/
|
|
108
108
|
async getVersionState(docId, versionId) {
|
|
109
|
-
return this.rpc.call("getVersionState",
|
|
109
|
+
return this.rpc.call("getVersionState", docId, versionId);
|
|
110
110
|
}
|
|
111
111
|
/**
|
|
112
112
|
* Gets the original changes associated with a specific version ID.
|
|
@@ -115,7 +115,7 @@ class PatchesClient {
|
|
|
115
115
|
* @returns A promise resolving with an array of changes that constitute that version.
|
|
116
116
|
*/
|
|
117
117
|
async getVersionChanges(docId, versionId) {
|
|
118
|
-
return this.rpc.call("getVersionChanges",
|
|
118
|
+
return this.rpc.call("getVersionChanges", docId, versionId);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
121
|
* Updates the name of a specific version.
|
|
@@ -125,7 +125,7 @@ class PatchesClient {
|
|
|
125
125
|
* @returns A promise resolving when the update is confirmed.
|
|
126
126
|
*/
|
|
127
127
|
async updateVersion(docId, versionId, metadata) {
|
|
128
|
-
return this.rpc.call("updateVersion",
|
|
128
|
+
return this.rpc.call("updateVersion", docId, versionId, metadata);
|
|
129
129
|
}
|
|
130
130
|
// === Branch Operations ===
|
|
131
131
|
/**
|
|
@@ -134,7 +134,7 @@ class PatchesClient {
|
|
|
134
134
|
* @returns A promise resolving with an array of branch metadata objects.
|
|
135
135
|
*/
|
|
136
136
|
async listBranches(docId) {
|
|
137
|
-
return this.rpc.call("listBranches",
|
|
137
|
+
return this.rpc.call("listBranches", docId);
|
|
138
138
|
}
|
|
139
139
|
/**
|
|
140
140
|
* Creates a new branch for a document.
|
|
@@ -144,7 +144,7 @@ class PatchesClient {
|
|
|
144
144
|
* @returns A promise resolving with the unique ID of the newly created branch.
|
|
145
145
|
*/
|
|
146
146
|
async createBranch(docId, rev, metadata) {
|
|
147
|
-
return this.rpc.call("createBranch",
|
|
147
|
+
return this.rpc.call("createBranch", docId, rev, metadata);
|
|
148
148
|
}
|
|
149
149
|
/**
|
|
150
150
|
* Closes a branch on the server.
|
|
@@ -152,7 +152,7 @@ class PatchesClient {
|
|
|
152
152
|
* @returns A promise resolving when the branch is closed.
|
|
153
153
|
*/
|
|
154
154
|
async closeBranch(branchId) {
|
|
155
|
-
return this.rpc.call("closeBranch",
|
|
155
|
+
return this.rpc.call("closeBranch", branchId);
|
|
156
156
|
}
|
|
157
157
|
/**
|
|
158
158
|
* Merges a branch on the server.
|
|
@@ -160,7 +160,7 @@ class PatchesClient {
|
|
|
160
160
|
* @returns A promise resolving when the merge is confirmed.
|
|
161
161
|
*/
|
|
162
162
|
async mergeBranch(branchId) {
|
|
163
|
-
return this.rpc.call("mergeBranch",
|
|
163
|
+
return this.rpc.call("mergeBranch", branchId);
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
166
|
export {
|