@verdant-web/common 1.11.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/LICENSE +21 -0
- package/dist/cjs/EventSubscriber.d.ts +17 -0
- package/dist/cjs/EventSubscriber.js +67 -0
- package/dist/cjs/EventSubscriber.js.map +1 -0
- package/dist/cjs/baseline.d.ts +5 -0
- package/dist/cjs/baseline.js +3 -0
- package/dist/cjs/baseline.js.map +1 -0
- package/dist/cjs/batching.d.ts +41 -0
- package/dist/cjs/batching.js +89 -0
- package/dist/cjs/batching.js.map +1 -0
- package/dist/cjs/files.d.ts +19 -0
- package/dist/cjs/files.js +19 -0
- package/dist/cjs/files.js.map +1 -0
- package/dist/cjs/files.test.d.ts +1 -0
- package/dist/cjs/files.test.js +81 -0
- package/dist/cjs/files.test.js.map +1 -0
- package/dist/cjs/index.d.ts +18 -0
- package/dist/cjs/index.js +36 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/indexes.d.ts +14 -0
- package/dist/cjs/indexes.js +116 -0
- package/dist/cjs/indexes.js.map +1 -0
- package/dist/cjs/indexes.test.d.ts +1 -0
- package/dist/cjs/indexes.test.js +128 -0
- package/dist/cjs/indexes.test.js.map +1 -0
- package/dist/cjs/migration.d.ts +98 -0
- package/dist/cjs/migration.js +128 -0
- package/dist/cjs/migration.js.map +1 -0
- package/dist/cjs/oids.d.ts +87 -0
- package/dist/cjs/oids.js +375 -0
- package/dist/cjs/oids.js.map +1 -0
- package/dist/cjs/oids.test.d.ts +1 -0
- package/dist/cjs/oids.test.js +282 -0
- package/dist/cjs/oids.test.js.map +1 -0
- package/dist/cjs/operation.d.ts +139 -0
- package/dist/cjs/operation.js +533 -0
- package/dist/cjs/operation.js.map +1 -0
- package/dist/cjs/operation.test.d.ts +1 -0
- package/dist/cjs/operation.test.js +827 -0
- package/dist/cjs/operation.test.js.map +1 -0
- package/dist/cjs/patch.d.ts +26 -0
- package/dist/cjs/patch.js +227 -0
- package/dist/cjs/patch.js.map +1 -0
- package/dist/cjs/presence.d.ts +27 -0
- package/dist/cjs/presence.js +3 -0
- package/dist/cjs/presence.js.map +1 -0
- package/dist/cjs/protocol.d.ts +145 -0
- package/dist/cjs/protocol.js +4 -0
- package/dist/cjs/protocol.js.map +1 -0
- package/dist/cjs/refs.d.ts +5 -0
- package/dist/cjs/refs.js +22 -0
- package/dist/cjs/refs.js.map +1 -0
- package/dist/cjs/replica.d.ts +28 -0
- package/dist/cjs/replica.js +29 -0
- package/dist/cjs/replica.js.map +1 -0
- package/dist/cjs/schema/defaults.d.ts +4 -0
- package/dist/cjs/schema/defaults.js +72 -0
- package/dist/cjs/schema/defaults.js.map +1 -0
- package/dist/cjs/schema/defaults.test.d.ts +1 -0
- package/dist/cjs/schema/defaults.test.js +21 -0
- package/dist/cjs/schema/defaults.test.js.map +1 -0
- package/dist/cjs/schema/index.d.ts +8 -0
- package/dist/cjs/schema/index.js +29 -0
- package/dist/cjs/schema/index.js.map +1 -0
- package/dist/cjs/schema/indexFilters.d.ts +6 -0
- package/dist/cjs/schema/indexFilters.js +31 -0
- package/dist/cjs/schema/indexFilters.js.map +1 -0
- package/dist/cjs/schema/types/collection.d.ts +51 -0
- package/dist/cjs/schema/types/collection.js +3 -0
- package/dist/cjs/schema/types/collection.js.map +1 -0
- package/dist/cjs/schema/types/compounds.d.ts +12 -0
- package/dist/cjs/schema/types/compounds.js +3 -0
- package/dist/cjs/schema/types/compounds.js.map +1 -0
- package/dist/cjs/schema/types/fields.d.ts +59 -0
- package/dist/cjs/schema/types/fields.js +3 -0
- package/dist/cjs/schema/types/fields.js.map +1 -0
- package/dist/cjs/schema/types/filters.d.ts +29 -0
- package/dist/cjs/schema/types/filters.js +3 -0
- package/dist/cjs/schema/types/filters.js.map +1 -0
- package/dist/cjs/schema/types/shapes.d.ts +21 -0
- package/dist/cjs/schema/types/shapes.js +3 -0
- package/dist/cjs/schema/types/shapes.js.map +1 -0
- package/dist/cjs/schema/types/synthetics.d.ts +28 -0
- package/dist/cjs/schema/types/synthetics.js +3 -0
- package/dist/cjs/schema/types/synthetics.js.map +1 -0
- package/dist/cjs/schema/types.d.ts +18 -0
- package/dist/cjs/schema/types.js +23 -0
- package/dist/cjs/schema/types.js.map +1 -0
- package/dist/cjs/timestamp.d.ts +48 -0
- package/dist/cjs/timestamp.js +244 -0
- package/dist/cjs/timestamp.js.map +1 -0
- package/dist/cjs/timestamp.test.d.ts +1 -0
- package/dist/cjs/timestamp.test.js +94 -0
- package/dist/cjs/timestamp.test.js.map +1 -0
- package/dist/cjs/undo.d.ts +3 -0
- package/dist/cjs/undo.js +199 -0
- package/dist/cjs/undo.js.map +1 -0
- package/dist/cjs/utils.d.ts +15 -0
- package/dist/cjs/utils.js +128 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/cjs/utils.test.d.ts +1 -0
- package/dist/cjs/utils.test.js +37 -0
- package/dist/cjs/utils.test.js.map +1 -0
- package/dist/esm/EventSubscriber.d.ts +17 -0
- package/dist/esm/EventSubscriber.js +63 -0
- package/dist/esm/EventSubscriber.js.map +1 -0
- package/dist/esm/baseline.d.ts +5 -0
- package/dist/esm/baseline.js +2 -0
- package/dist/esm/baseline.js.map +1 -0
- package/dist/esm/batching.d.ts +41 -0
- package/dist/esm/batching.js +84 -0
- package/dist/esm/batching.js.map +1 -0
- package/dist/esm/files.d.ts +19 -0
- package/dist/esm/files.js +13 -0
- package/dist/esm/files.js.map +1 -0
- package/dist/esm/files.test.d.ts +1 -0
- package/dist/esm/files.test.js +79 -0
- package/dist/esm/files.test.js.map +1 -0
- package/dist/esm/index.d.ts +18 -0
- package/dist/esm/index.js +16 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/indexes.d.ts +14 -0
- package/dist/esm/indexes.js +106 -0
- package/dist/esm/indexes.js.map +1 -0
- package/dist/esm/indexes.test.d.ts +1 -0
- package/dist/esm/indexes.test.js +126 -0
- package/dist/esm/indexes.test.js.map +1 -0
- package/dist/esm/migration.d.ts +98 -0
- package/dist/esm/migration.js +122 -0
- package/dist/esm/migration.js.map +1 -0
- package/dist/esm/oids.d.ts +87 -0
- package/dist/esm/oids.js +348 -0
- package/dist/esm/oids.js.map +1 -0
- package/dist/esm/oids.test.d.ts +1 -0
- package/dist/esm/oids.test.js +280 -0
- package/dist/esm/oids.test.js.map +1 -0
- package/dist/esm/operation.d.ts +139 -0
- package/dist/esm/operation.js +518 -0
- package/dist/esm/operation.js.map +1 -0
- package/dist/esm/operation.test.d.ts +1 -0
- package/dist/esm/operation.test.js +825 -0
- package/dist/esm/operation.test.js.map +1 -0
- package/dist/esm/patch.d.ts +26 -0
- package/dist/esm/patch.js +223 -0
- package/dist/esm/patch.js.map +1 -0
- package/dist/esm/presence.d.ts +27 -0
- package/dist/esm/presence.js +2 -0
- package/dist/esm/presence.js.map +1 -0
- package/dist/esm/protocol.d.ts +145 -0
- package/dist/esm/protocol.js +3 -0
- package/dist/esm/protocol.js.map +1 -0
- package/dist/esm/refs.d.ts +5 -0
- package/dist/esm/refs.js +17 -0
- package/dist/esm/refs.js.map +1 -0
- package/dist/esm/replica.d.ts +28 -0
- package/dist/esm/replica.js +26 -0
- package/dist/esm/replica.js.map +1 -0
- package/dist/esm/schema/defaults.d.ts +4 -0
- package/dist/esm/schema/defaults.js +66 -0
- package/dist/esm/schema/defaults.js.map +1 -0
- package/dist/esm/schema/defaults.test.d.ts +1 -0
- package/dist/esm/schema/defaults.test.js +19 -0
- package/dist/esm/schema/defaults.test.js.map +1 -0
- package/dist/esm/schema/index.d.ts +8 -0
- package/dist/esm/schema/index.js +10 -0
- package/dist/esm/schema/index.js.map +1 -0
- package/dist/esm/schema/indexFilters.d.ts +6 -0
- package/dist/esm/schema/indexFilters.js +23 -0
- package/dist/esm/schema/indexFilters.js.map +1 -0
- package/dist/esm/schema/types/collection.d.ts +51 -0
- package/dist/esm/schema/types/collection.js +2 -0
- package/dist/esm/schema/types/collection.js.map +1 -0
- package/dist/esm/schema/types/compounds.d.ts +12 -0
- package/dist/esm/schema/types/compounds.js +2 -0
- package/dist/esm/schema/types/compounds.js.map +1 -0
- package/dist/esm/schema/types/fields.d.ts +59 -0
- package/dist/esm/schema/types/fields.js +2 -0
- package/dist/esm/schema/types/fields.js.map +1 -0
- package/dist/esm/schema/types/filters.d.ts +29 -0
- package/dist/esm/schema/types/filters.js +2 -0
- package/dist/esm/schema/types/filters.js.map +1 -0
- package/dist/esm/schema/types/shapes.d.ts +21 -0
- package/dist/esm/schema/types/shapes.js +2 -0
- package/dist/esm/schema/types/shapes.js.map +1 -0
- package/dist/esm/schema/types/synthetics.d.ts +28 -0
- package/dist/esm/schema/types/synthetics.js +2 -0
- package/dist/esm/schema/types/synthetics.js.map +1 -0
- package/dist/esm/schema/types.d.ts +18 -0
- package/dist/esm/schema/types.js +7 -0
- package/dist/esm/schema/types.js.map +1 -0
- package/dist/esm/timestamp.d.ts +48 -0
- package/dist/esm/timestamp.js +229 -0
- package/dist/esm/timestamp.js.map +1 -0
- package/dist/esm/timestamp.test.d.ts +1 -0
- package/dist/esm/timestamp.test.js +92 -0
- package/dist/esm/timestamp.test.js.map +1 -0
- package/dist/esm/undo.d.ts +3 -0
- package/dist/esm/undo.js +195 -0
- package/dist/esm/undo.js.map +1 -0
- package/dist/esm/utils.d.ts +15 -0
- package/dist/esm/utils.js +114 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/esm/utils.test.d.ts +1 -0
- package/dist/esm/utils.test.js +35 -0
- package/dist/esm/utils.test.js.map +1 -0
- package/dist/tsconfig-cjs.tsbuildinfo +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +38 -0
- package/src/EventSubscriber.ts +81 -0
- package/src/baseline.ts +9 -0
- package/src/batching.ts +135 -0
- package/src/files.ts +34 -0
- package/src/index.ts +26 -0
- package/src/indexes.test.ts +158 -0
- package/src/indexes.ts +151 -0
- package/src/migration.ts +391 -0
- package/src/oids.test.ts +395 -0
- package/src/oids.ts +442 -0
- package/src/operation.test.ts +966 -0
- package/src/operation.ts +755 -0
- package/src/patch.ts +277 -0
- package/src/presence.ts +29 -0
- package/src/protocol.ts +184 -0
- package/src/refs.ts +16 -0
- package/src/replica.ts +29 -0
- package/src/schema/defaults.test.ts +19 -0
- package/src/schema/defaults.ts +72 -0
- package/src/schema/index.ts +28 -0
- package/src/schema/indexFilters.ts +49 -0
- package/src/schema/types/collection.ts +133 -0
- package/src/schema/types/compounds.ts +33 -0
- package/src/schema/types/fields.ts +85 -0
- package/src/schema/types/filters.ts +39 -0
- package/src/schema/types/shapes.ts +83 -0
- package/src/schema/types/synthetics.ts +45 -0
- package/src/schema/types.ts +28 -0
- package/src/timestamp.test.ts +113 -0
- package/src/timestamp.ts +284 -0
- package/src/undo.ts +205 -0
- package/src/utils.test.ts +38 -0
- package/src/utils.ts +137 -0
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import cuid from 'cuid';
|
|
2
|
+
const VERSION_BLOCK_LENGTH = 4;
|
|
3
|
+
const ENCODING_NUMBER_RADIX = 36;
|
|
4
|
+
export function encodeVersion(version) {
|
|
5
|
+
return version
|
|
6
|
+
.toString(ENCODING_NUMBER_RADIX)
|
|
7
|
+
.padStart(VERSION_BLOCK_LENGTH, '0');
|
|
8
|
+
}
|
|
9
|
+
export function OLD_encodeVersion(version) {
|
|
10
|
+
return version.toString().padStart(6, '0');
|
|
11
|
+
}
|
|
12
|
+
export class NaiveTimestampProvider {
|
|
13
|
+
constructor() {
|
|
14
|
+
this.counter = 0;
|
|
15
|
+
this.now = (version) => {
|
|
16
|
+
return (encodeVersion(version) + Date.now().toString() + '-' + this.counter++);
|
|
17
|
+
};
|
|
18
|
+
this.update = () => {
|
|
19
|
+
this.counter = 0;
|
|
20
|
+
};
|
|
21
|
+
this.zero = (version) => {
|
|
22
|
+
return encodeVersion(version) + '0' + '-' + this.counter++;
|
|
23
|
+
};
|
|
24
|
+
this.getWallClockTime = (timestamp) => {
|
|
25
|
+
return parseInt(timestamp.slice(VERSION_BLOCK_LENGTH).split('-')[0], 10);
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export class HybridLogicalClockTimestampProvider {
|
|
30
|
+
constructor() {
|
|
31
|
+
this.latest = {
|
|
32
|
+
time: Date.now(),
|
|
33
|
+
counter: 0,
|
|
34
|
+
node: generateNodeId(),
|
|
35
|
+
};
|
|
36
|
+
this.zeroCounter = 0;
|
|
37
|
+
this.now = (version) => {
|
|
38
|
+
this.latest = getHlcNow(this.latest);
|
|
39
|
+
return this.get(version, this.latest);
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @deprecated - use now() instead and update to latest format
|
|
43
|
+
*/
|
|
44
|
+
this.OLD_now = (version) => {
|
|
45
|
+
this.latest = getHlcNow(this.latest);
|
|
46
|
+
return OLD_encodeVersion(version) + OLD_serializeHlcTimestamp(this.latest);
|
|
47
|
+
};
|
|
48
|
+
/** Get the current timer state. Does not increment counter. */
|
|
49
|
+
this.timerState = () => {
|
|
50
|
+
return this.latest;
|
|
51
|
+
};
|
|
52
|
+
this.update = (remoteTimestamp) => {
|
|
53
|
+
// strip version from remote timestamp
|
|
54
|
+
const hlcString = remoteTimestamp.slice(VERSION_BLOCK_LENGTH);
|
|
55
|
+
this.latest = updateFromRemote(this.latest, deserializeHlcTimestamp(hlcString));
|
|
56
|
+
};
|
|
57
|
+
this.get = (version, raw) => {
|
|
58
|
+
return encodeVersion(version) + serializeHlcTimestamp(raw);
|
|
59
|
+
};
|
|
60
|
+
this.zero = (version) => {
|
|
61
|
+
return (encodeVersion(version) +
|
|
62
|
+
serializeHlcTimestamp({
|
|
63
|
+
time: 0,
|
|
64
|
+
// to keep zero timestamps unique, we use a counter here as well
|
|
65
|
+
counter: this.zeroCounter++,
|
|
66
|
+
node: this.latest.node,
|
|
67
|
+
}));
|
|
68
|
+
};
|
|
69
|
+
this.getWallClockTime = (timestamp) => {
|
|
70
|
+
return deserializeHlcTimestamp(timestamp.slice(VERSION_BLOCK_LENGTH)).time;
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
class ClockDriftError extends Error {
|
|
75
|
+
constructor(...args) {
|
|
76
|
+
super();
|
|
77
|
+
this.type = 'ClockDriftError';
|
|
78
|
+
this.message = ['maximum clock drift exceeded'].concat(args).join(' ');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
class OverflowError extends Error {
|
|
82
|
+
constructor() {
|
|
83
|
+
super();
|
|
84
|
+
this.type = 'OverflowError';
|
|
85
|
+
this.message = 'timestamp counter overflow';
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const COUNTER_BLOCK_LENGTH = 4;
|
|
89
|
+
const NODE_BLOCK_LENGTH = 7;
|
|
90
|
+
const MAX_CLOCK_DRIFT = 60 * 1000;
|
|
91
|
+
// 9 base36 characters should last until the year 5000
|
|
92
|
+
// when encoding a unix MS timestamp
|
|
93
|
+
const TIME_BLOCK_LENGTH = 9;
|
|
94
|
+
function generateNodeId() {
|
|
95
|
+
return cuid
|
|
96
|
+
.slug()
|
|
97
|
+
.padStart(NODE_BLOCK_LENGTH, '0')
|
|
98
|
+
.slice(0, NODE_BLOCK_LENGTH);
|
|
99
|
+
}
|
|
100
|
+
export function serializeHlcTimestamp(ts) {
|
|
101
|
+
// string representation of the time
|
|
102
|
+
const dateString = new Date(ts.time)
|
|
103
|
+
.getTime()
|
|
104
|
+
.toString(ENCODING_NUMBER_RADIX)
|
|
105
|
+
.padStart(TIME_BLOCK_LENGTH, '0');
|
|
106
|
+
// counter, 336, padded to 4 characters
|
|
107
|
+
const counter = ts.counter
|
|
108
|
+
.toString(ENCODING_NUMBER_RADIX)
|
|
109
|
+
.padStart(COUNTER_BLOCK_LENGTH, '0');
|
|
110
|
+
// node id padded to 16 characters
|
|
111
|
+
const node = ts.node.padStart(NODE_BLOCK_LENGTH, '0');
|
|
112
|
+
return `${dateString}${counter}${node}`;
|
|
113
|
+
}
|
|
114
|
+
function getHlcNow(prev) {
|
|
115
|
+
const wallTime = Date.now();
|
|
116
|
+
// pick prev's time if it's later than our local device
|
|
117
|
+
const newWallTime = Math.max(prev.time, wallTime);
|
|
118
|
+
// reset counter if wall time changed
|
|
119
|
+
const newCounter = prev.time === newWallTime ? prev.counter + 1 : 0;
|
|
120
|
+
// check for drift
|
|
121
|
+
if (newWallTime - wallTime > MAX_CLOCK_DRIFT) {
|
|
122
|
+
throw new ClockDriftError(newWallTime, wallTime, MAX_CLOCK_DRIFT);
|
|
123
|
+
}
|
|
124
|
+
// check for counter overflow (max is 4 bytes)
|
|
125
|
+
if (newCounter > 65535) {
|
|
126
|
+
throw new OverflowError();
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
time: newWallTime,
|
|
130
|
+
counter: newCounter,
|
|
131
|
+
node: prev.node,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
function updateFromRemote(local, remote) {
|
|
135
|
+
const wallTime = Date.now();
|
|
136
|
+
// pick remote's time if it's later than our local device
|
|
137
|
+
const newTime = Math.max(wallTime, Math.max(local.time, remote.time));
|
|
138
|
+
const maxCounter = Math.max(local.counter, remote.counter);
|
|
139
|
+
let newCounter;
|
|
140
|
+
// if all clocks are the same, increment the counter
|
|
141
|
+
if (local.time === newTime && remote.time === newTime) {
|
|
142
|
+
newCounter = maxCounter + 1;
|
|
143
|
+
}
|
|
144
|
+
// if local time is the same as new time, increment our local counter
|
|
145
|
+
else if (local.time === newTime) {
|
|
146
|
+
newCounter = local.counter + 1;
|
|
147
|
+
}
|
|
148
|
+
// if remote time is the same as new time, increment remote counter
|
|
149
|
+
else if (remote.time === newTime) {
|
|
150
|
+
newCounter = remote.counter + 1;
|
|
151
|
+
}
|
|
152
|
+
// otherwise, reset the counter
|
|
153
|
+
else {
|
|
154
|
+
newCounter = 0;
|
|
155
|
+
}
|
|
156
|
+
// check for drift
|
|
157
|
+
if (newTime - wallTime > MAX_CLOCK_DRIFT) {
|
|
158
|
+
throw new ClockDriftError(newTime, wallTime, MAX_CLOCK_DRIFT);
|
|
159
|
+
}
|
|
160
|
+
if (newCounter > 65535) {
|
|
161
|
+
throw new OverflowError();
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
time: newTime,
|
|
165
|
+
counter: newCounter,
|
|
166
|
+
node: local.node,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
export function deserializeHlcTimestamp(clock) {
|
|
170
|
+
const dateString = clock.slice(0, TIME_BLOCK_LENGTH);
|
|
171
|
+
const counter = clock.slice(TIME_BLOCK_LENGTH, TIME_BLOCK_LENGTH + COUNTER_BLOCK_LENGTH);
|
|
172
|
+
const node = clock.slice(TIME_BLOCK_LENGTH + COUNTER_BLOCK_LENGTH);
|
|
173
|
+
const time = parseInt(dateString, ENCODING_NUMBER_RADIX);
|
|
174
|
+
const counterNum = parseInt(counter, ENCODING_NUMBER_RADIX);
|
|
175
|
+
if (isNaN(time) || isNaN(counterNum)) {
|
|
176
|
+
throw new Error('invalid clock format');
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
time,
|
|
180
|
+
counter: counterNum,
|
|
181
|
+
node,
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function removeLeadingZeroes(str) {
|
|
185
|
+
return str.replace(/^0+/, '');
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Below, converters for old-style timestamps are defined.
|
|
189
|
+
* These are for migrating older clients to the new format.
|
|
190
|
+
*/
|
|
191
|
+
/**
|
|
192
|
+
* Converts a timestamp from the old format to the new format.
|
|
193
|
+
*/
|
|
194
|
+
export function convertOldHlcTimestamp(ts) {
|
|
195
|
+
const versionBlock = ts.slice(0, 6);
|
|
196
|
+
// no jokes please
|
|
197
|
+
const clockBlock = ts.slice(6);
|
|
198
|
+
const deserialized = OLD_deserializeHlcTimestamp(clockBlock);
|
|
199
|
+
// version was base 10 and now is base 36
|
|
200
|
+
const versionNumber = parseInt(versionBlock, 10);
|
|
201
|
+
const encodedVersion = encodeVersion(versionNumber);
|
|
202
|
+
return encodedVersion + serializeHlcTimestamp(deserialized);
|
|
203
|
+
}
|
|
204
|
+
export function OLD_serializeHlcTimestamp(ts) {
|
|
205
|
+
// ISO string representation of the time
|
|
206
|
+
const dateString = new Date(ts.time).toISOString();
|
|
207
|
+
// counter, base16, padded to 4 characters
|
|
208
|
+
const counter = ts.counter.toString(16).toUpperCase().padStart(4, '0');
|
|
209
|
+
// node id padded to 16 characters
|
|
210
|
+
const node = ts.node.padStart(16, '0');
|
|
211
|
+
return `${dateString}-${counter}-${node}`;
|
|
212
|
+
}
|
|
213
|
+
export function OLD_deserializeHlcTimestamp(clock) {
|
|
214
|
+
// ISO string representation of the time
|
|
215
|
+
const dateString = clock.slice(0, 24);
|
|
216
|
+
const counter = clock.slice(25, 25 + 4);
|
|
217
|
+
const node = clock.slice(25 + 4 + 1);
|
|
218
|
+
const time = new Date(dateString).getTime();
|
|
219
|
+
const counterNum = parseInt(counter, 16);
|
|
220
|
+
if (isNaN(time) || isNaN(counterNum)) {
|
|
221
|
+
throw new Error('invalid clock format');
|
|
222
|
+
}
|
|
223
|
+
return {
|
|
224
|
+
time,
|
|
225
|
+
counter: counterNum,
|
|
226
|
+
node: node.slice(node.length - 7),
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=timestamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestamp.js","sourceRoot":"","sources":["../../src/timestamp.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { describe, expect, it, vitest } from 'vitest';
|
|
2
|
+
import { convertOldHlcTimestamp, HybridLogicalClockTimestampProvider, OLD_encodeVersion, OLD_serializeHlcTimestamp, } from './timestamp.js';
|
|
3
|
+
describe('the hybrid logical clock', () => {
|
|
4
|
+
it('always produces incrementing timestamps', async () => {
|
|
5
|
+
const clock = new HybridLogicalClockTimestampProvider();
|
|
6
|
+
let prev = clock.now(1);
|
|
7
|
+
clock.update(prev);
|
|
8
|
+
let now;
|
|
9
|
+
for (let i = 0; i < 1000; i++) {
|
|
10
|
+
now = clock.now(1);
|
|
11
|
+
expect(now > prev, `${now} not later than ${prev}`).toBe(true);
|
|
12
|
+
clock.update(now);
|
|
13
|
+
prev = now;
|
|
14
|
+
}
|
|
15
|
+
let time = new Date().getTime();
|
|
16
|
+
for (let i = 0; i < 1000; i++) {
|
|
17
|
+
vitest.setSystemTime(time++);
|
|
18
|
+
now = clock.now(1);
|
|
19
|
+
expect(now > prev, `${now} not later than ${prev}`).toBe(true);
|
|
20
|
+
clock.update(now);
|
|
21
|
+
prev = now;
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
it('groups blocks of time by version', () => {
|
|
25
|
+
const clock = new HybridLogicalClockTimestampProvider();
|
|
26
|
+
let prev = clock.now(1);
|
|
27
|
+
clock.update(prev);
|
|
28
|
+
let now;
|
|
29
|
+
for (let i = 0; i < 10; i++) {
|
|
30
|
+
now = clock.now(1);
|
|
31
|
+
expect(now > prev, `${now} not later than ${prev}`).toBe(true);
|
|
32
|
+
clock.update(now);
|
|
33
|
+
prev = now;
|
|
34
|
+
}
|
|
35
|
+
for (let i = 0; i < 10; i++) {
|
|
36
|
+
now = clock.now(2);
|
|
37
|
+
expect(now > prev, `${now} not later than ${prev}`).toBe(true);
|
|
38
|
+
clock.update(now);
|
|
39
|
+
prev = now;
|
|
40
|
+
}
|
|
41
|
+
const startOfVersion2 = now;
|
|
42
|
+
// jump back to 1
|
|
43
|
+
prev = clock.now(1);
|
|
44
|
+
clock.update(prev);
|
|
45
|
+
for (let i = 0; i < 10; i++) {
|
|
46
|
+
now = clock.now(1);
|
|
47
|
+
expect(now > prev, `${now} not later than ${prev}`).toBe(true);
|
|
48
|
+
expect(now < startOfVersion2, `${now} not earlier than ${startOfVersion2}`).toBe(true);
|
|
49
|
+
clock.update(now);
|
|
50
|
+
prev = now;
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
it('is shorter than the previous format', () => {
|
|
54
|
+
const clock = new HybridLogicalClockTimestampProvider();
|
|
55
|
+
expect(clock.now(1).length).toBeLessThan(clock.OLD_now(1).length);
|
|
56
|
+
});
|
|
57
|
+
it('correctly converts old to new format', () => {
|
|
58
|
+
const clock = new HybridLogicalClockTimestampProvider();
|
|
59
|
+
const oldFormat = clock.OLD_now(1);
|
|
60
|
+
const value = clock.timerState();
|
|
61
|
+
const converted = convertOldHlcTimestamp(oldFormat);
|
|
62
|
+
const newFormat = clock.get(1, value);
|
|
63
|
+
expect(converted).toEqual(newFormat);
|
|
64
|
+
});
|
|
65
|
+
// this is mostly to verify as I move to the new format.
|
|
66
|
+
// instead of attempting a distributed migration of timestamps, it
|
|
67
|
+
// will be easier that the new format just acts as always in the
|
|
68
|
+
// future of the old one. this will only mess with offline clients,
|
|
69
|
+
// but nobody is using verdant but me yet at time of this change (2022-12-19)
|
|
70
|
+
// which is kind of why I'm doing it now anyway.
|
|
71
|
+
it('old format always comes before new format', () => {
|
|
72
|
+
const clock = new HybridLogicalClockTimestampProvider();
|
|
73
|
+
const newFormat = clock.now(1);
|
|
74
|
+
const oldFormat = clock.OLD_now(1);
|
|
75
|
+
expect(oldFormat < newFormat).toBe(true);
|
|
76
|
+
// even far-future old timestamps are before new timestamps
|
|
77
|
+
const oldFormat2 = OLD_serializeHlcTimestamp({
|
|
78
|
+
counter: 999,
|
|
79
|
+
node: '9876543210',
|
|
80
|
+
time: new Date(3000, 1, 1).getTime(),
|
|
81
|
+
});
|
|
82
|
+
expect(OLD_encodeVersion(1) + oldFormat2 < newFormat).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
it('decodes timestamps', () => {
|
|
85
|
+
const time = new Date();
|
|
86
|
+
vitest.setSystemTime(time);
|
|
87
|
+
const clock = new HybridLogicalClockTimestampProvider();
|
|
88
|
+
const now = clock.now(1);
|
|
89
|
+
expect(clock.getWallClockTime(now)).toEqual(time.getTime());
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
//# sourceMappingURL=timestamp.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"timestamp.test.js","sourceRoot":"","sources":["../../src/timestamp.test.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/undo.js
ADDED
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { applyPatch } from './operation.js';
|
|
2
|
+
import { cloneDeep } from './utils.js';
|
|
3
|
+
export function getUndoOperations(oid, initial, operations, getNow) {
|
|
4
|
+
if (initial === undefined) {
|
|
5
|
+
// if the initial state is nothing, then the undo is to delete everything.
|
|
6
|
+
// there's nothing else to worry about!
|
|
7
|
+
return [
|
|
8
|
+
{
|
|
9
|
+
oid,
|
|
10
|
+
timestamp: getNow(),
|
|
11
|
+
data: {
|
|
12
|
+
op: 'delete',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
}
|
|
17
|
+
// otherwise, traverse the operations one by one,
|
|
18
|
+
// applying them, and using the prior state to determine
|
|
19
|
+
// what the undo operation is.
|
|
20
|
+
let state = cloneDeep(initial);
|
|
21
|
+
const undoOperations = [];
|
|
22
|
+
for (const operation of operations) {
|
|
23
|
+
const undo = getUndoOperation(oid, state, operation, getNow);
|
|
24
|
+
undoOperations.unshift(...undo);
|
|
25
|
+
applyPatch(state, operation.data);
|
|
26
|
+
}
|
|
27
|
+
return undoOperations;
|
|
28
|
+
}
|
|
29
|
+
function getUndoOperation(oid, initial, operation, getNow) {
|
|
30
|
+
const data = operation.data;
|
|
31
|
+
switch (data.op) {
|
|
32
|
+
case 'set':
|
|
33
|
+
case 'remove':
|
|
34
|
+
return [
|
|
35
|
+
{
|
|
36
|
+
oid,
|
|
37
|
+
timestamp: getNow(),
|
|
38
|
+
data: {
|
|
39
|
+
op: 'set',
|
|
40
|
+
name: data.name,
|
|
41
|
+
value: initial[data.name],
|
|
42
|
+
},
|
|
43
|
+
},
|
|
44
|
+
];
|
|
45
|
+
case 'list-insert':
|
|
46
|
+
return [
|
|
47
|
+
{
|
|
48
|
+
oid,
|
|
49
|
+
timestamp: getNow(),
|
|
50
|
+
data: {
|
|
51
|
+
op: 'list-delete',
|
|
52
|
+
index: data.index,
|
|
53
|
+
count: 1,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
];
|
|
57
|
+
case 'list-delete':
|
|
58
|
+
return [
|
|
59
|
+
{
|
|
60
|
+
oid,
|
|
61
|
+
timestamp: getNow(),
|
|
62
|
+
data: {
|
|
63
|
+
op: 'list-insert',
|
|
64
|
+
index: data.index,
|
|
65
|
+
values: initial.slice(data.index, data.count),
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
case 'list-move-by-ref':
|
|
70
|
+
return [
|
|
71
|
+
{
|
|
72
|
+
oid,
|
|
73
|
+
timestamp: getNow(),
|
|
74
|
+
data: {
|
|
75
|
+
op: 'list-move-by-ref',
|
|
76
|
+
value: data.value,
|
|
77
|
+
index: initial.indexOf(data.value),
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
case 'list-move-by-index':
|
|
82
|
+
return [
|
|
83
|
+
{
|
|
84
|
+
oid,
|
|
85
|
+
timestamp: getNow(),
|
|
86
|
+
data: {
|
|
87
|
+
op: 'list-move-by-index',
|
|
88
|
+
from: data.to,
|
|
89
|
+
to: data.from,
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
];
|
|
93
|
+
case 'delete':
|
|
94
|
+
return [
|
|
95
|
+
{
|
|
96
|
+
oid,
|
|
97
|
+
timestamp: getNow(),
|
|
98
|
+
data: {
|
|
99
|
+
op: 'initialize',
|
|
100
|
+
value: initial,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
];
|
|
104
|
+
case 'list-push':
|
|
105
|
+
return [
|
|
106
|
+
{
|
|
107
|
+
oid,
|
|
108
|
+
timestamp: getNow(),
|
|
109
|
+
data: {
|
|
110
|
+
op: 'list-remove',
|
|
111
|
+
value: data.value,
|
|
112
|
+
// best heuristic here - remove the last instance of the item.
|
|
113
|
+
only: 'last',
|
|
114
|
+
},
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
case 'list-remove':
|
|
118
|
+
if (data.only === 'last') {
|
|
119
|
+
const index = initial.lastIndexOf(data.value);
|
|
120
|
+
return [
|
|
121
|
+
{
|
|
122
|
+
oid,
|
|
123
|
+
timestamp: getNow(),
|
|
124
|
+
data: {
|
|
125
|
+
op: 'list-insert',
|
|
126
|
+
index,
|
|
127
|
+
values: [data.value],
|
|
128
|
+
},
|
|
129
|
+
},
|
|
130
|
+
];
|
|
131
|
+
}
|
|
132
|
+
else if (data.only === 'first') {
|
|
133
|
+
const index = initial.indexOf(data.value);
|
|
134
|
+
return [
|
|
135
|
+
{
|
|
136
|
+
oid,
|
|
137
|
+
timestamp: getNow(),
|
|
138
|
+
data: {
|
|
139
|
+
op: 'list-insert',
|
|
140
|
+
index,
|
|
141
|
+
values: [data.value],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
];
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
// find all instances of value and restore them at their
|
|
148
|
+
// original index
|
|
149
|
+
const indexesOfValue = [];
|
|
150
|
+
let index = initial.indexOf(data.value);
|
|
151
|
+
while (index !== -1) {
|
|
152
|
+
indexesOfValue.push(index);
|
|
153
|
+
index = initial.indexOf(data.value, index + 1);
|
|
154
|
+
}
|
|
155
|
+
return indexesOfValue.map((index) => ({
|
|
156
|
+
oid,
|
|
157
|
+
timestamp: getNow(),
|
|
158
|
+
data: {
|
|
159
|
+
op: 'list-insert',
|
|
160
|
+
index,
|
|
161
|
+
value: data.value,
|
|
162
|
+
},
|
|
163
|
+
}));
|
|
164
|
+
}
|
|
165
|
+
case 'list-add':
|
|
166
|
+
// this one is kind of ambiguous. in theory the set may have
|
|
167
|
+
// already included the value and so no change happened. but
|
|
168
|
+
// basically we infer the intent is to remove what was meant
|
|
169
|
+
// to be added by this change.
|
|
170
|
+
return [
|
|
171
|
+
{
|
|
172
|
+
oid,
|
|
173
|
+
timestamp: getNow(),
|
|
174
|
+
data: {
|
|
175
|
+
op: 'list-remove',
|
|
176
|
+
value: data.value,
|
|
177
|
+
only: 'last',
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
];
|
|
181
|
+
case 'initialize':
|
|
182
|
+
return [
|
|
183
|
+
{
|
|
184
|
+
oid,
|
|
185
|
+
timestamp: getNow(),
|
|
186
|
+
data: {
|
|
187
|
+
op: 'delete',
|
|
188
|
+
},
|
|
189
|
+
},
|
|
190
|
+
];
|
|
191
|
+
default:
|
|
192
|
+
throw new Error(`Cannot undo operation type: ${data.op}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=undo.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"undo.js","sourceRoot":"","sources":["../../src/undo.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export declare function take<T extends object, Keys extends keyof T>(obj: T, keys: Keys[]): Pick<T, Keys>;
|
|
2
|
+
export declare function omit<T extends object, Keys extends keyof T>(obj: T, keys: Keys[]): Omit<T, Keys>;
|
|
3
|
+
export declare function getSortedIndex<T>(array: T[], insert: T, compare: (a: T, b: T) => number): number;
|
|
4
|
+
/**
|
|
5
|
+
* Consistently stringifies an object regardless
|
|
6
|
+
* of key insertion order
|
|
7
|
+
*/
|
|
8
|
+
export declare function stableStringify(obj: any): string;
|
|
9
|
+
export declare function cloneDeep<T>(obj: T): T;
|
|
10
|
+
export declare function hashObject(obj: any): string;
|
|
11
|
+
export declare function isObject(obj: any): any;
|
|
12
|
+
export declare function roughSizeOfObject(object: any): number;
|
|
13
|
+
export declare function assert(condition: any, message?: string): asserts condition;
|
|
14
|
+
export declare function generateId(length?: number): string;
|
|
15
|
+
export declare function findLastIndex<T>(array: T[], predicate: (item: T) => boolean): number;
|