@framers/sql-storage-adapter 0.4.2 → 0.5.1
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 +94 -2
- package/dist/adapters/electron/electronMainAdapter.d.ts +241 -0
- package/dist/adapters/electron/electronMainAdapter.d.ts.map +1 -0
- package/dist/adapters/electron/electronMainAdapter.js +442 -0
- package/dist/adapters/electron/electronMainAdapter.js.map +1 -0
- package/dist/adapters/electron/electronRendererAdapter.d.ts +177 -0
- package/dist/adapters/electron/electronRendererAdapter.d.ts.map +1 -0
- package/dist/adapters/electron/electronRendererAdapter.js +339 -0
- package/dist/adapters/electron/electronRendererAdapter.js.map +1 -0
- package/dist/adapters/electron/index.d.ts +74 -0
- package/dist/adapters/electron/index.d.ts.map +1 -0
- package/dist/adapters/electron/index.js +96 -0
- package/dist/adapters/electron/index.js.map +1 -0
- package/dist/adapters/electron/ipc/channels.d.ts +196 -0
- package/dist/adapters/electron/ipc/channels.d.ts.map +1 -0
- package/dist/adapters/electron/ipc/channels.js +121 -0
- package/dist/adapters/electron/ipc/channels.js.map +1 -0
- package/dist/adapters/electron/ipc/index.d.ts +11 -0
- package/dist/adapters/electron/ipc/index.d.ts.map +1 -0
- package/dist/adapters/electron/ipc/index.js +11 -0
- package/dist/adapters/electron/ipc/index.js.map +1 -0
- package/dist/adapters/electron/ipc/protocol.d.ts +78 -0
- package/dist/adapters/electron/ipc/protocol.d.ts.map +1 -0
- package/dist/adapters/electron/ipc/protocol.js +347 -0
- package/dist/adapters/electron/ipc/protocol.js.map +1 -0
- package/dist/adapters/electron/ipc/types.d.ts +248 -0
- package/dist/adapters/electron/ipc/types.d.ts.map +1 -0
- package/dist/adapters/electron/ipc/types.js +8 -0
- package/dist/adapters/electron/ipc/types.js.map +1 -0
- package/dist/adapters/electron/migration/autoMigrator.d.ts +184 -0
- package/dist/adapters/electron/migration/autoMigrator.d.ts.map +1 -0
- package/dist/adapters/electron/migration/autoMigrator.js +478 -0
- package/dist/adapters/electron/migration/autoMigrator.js.map +1 -0
- package/dist/adapters/electron/migration/index.d.ts +9 -0
- package/dist/adapters/electron/migration/index.d.ts.map +1 -0
- package/dist/adapters/electron/migration/index.js +9 -0
- package/dist/adapters/electron/migration/index.js.map +1 -0
- package/dist/adapters/electron/preload.d.ts +126 -0
- package/dist/adapters/electron/preload.d.ts.map +1 -0
- package/dist/adapters/electron/preload.js +254 -0
- package/dist/adapters/electron/preload.js.map +1 -0
- package/dist/adapters/electron/recovery/corruptionDetector.d.ts +214 -0
- package/dist/adapters/electron/recovery/corruptionDetector.d.ts.map +1 -0
- package/dist/adapters/electron/recovery/corruptionDetector.js +410 -0
- package/dist/adapters/electron/recovery/corruptionDetector.js.map +1 -0
- package/dist/adapters/electron/recovery/index.d.ts +11 -0
- package/dist/adapters/electron/recovery/index.d.ts.map +1 -0
- package/dist/adapters/electron/recovery/index.js +11 -0
- package/dist/adapters/electron/recovery/index.js.map +1 -0
- package/dist/adapters/electron/recovery/walCheckpoint.d.ts +186 -0
- package/dist/adapters/electron/recovery/walCheckpoint.d.ts.map +1 -0
- package/dist/adapters/electron/recovery/walCheckpoint.js +302 -0
- package/dist/adapters/electron/recovery/walCheckpoint.js.map +1 -0
- package/dist/adapters/electron/window/index.d.ts +9 -0
- package/dist/adapters/electron/window/index.d.ts.map +1 -0
- package/dist/adapters/electron/window/index.js +9 -0
- package/dist/adapters/electron/window/index.js.map +1 -0
- package/dist/adapters/electron/window/windowManager.d.ts +190 -0
- package/dist/adapters/electron/window/windowManager.d.ts.map +1 -0
- package/dist/adapters/electron/window/windowManager.js +358 -0
- package/dist/adapters/electron/window/windowManager.js.map +1 -0
- package/dist/core/contracts/context.d.ts +2 -2
- package/dist/core/contracts/context.d.ts.map +1 -1
- package/dist/core/database.d.ts +19 -0
- package/dist/core/database.d.ts.map +1 -1
- package/dist/core/database.js +4 -0
- package/dist/core/database.js.map +1 -1
- package/dist/core/resolver.d.ts +3 -0
- package/dist/core/resolver.d.ts.map +1 -1
- package/dist/core/resolver.js +39 -3
- package/dist/core/resolver.js.map +1 -1
- package/dist/features/sync/conflicts/conflictResolver.d.ts +222 -0
- package/dist/features/sync/conflicts/conflictResolver.d.ts.map +1 -0
- package/dist/features/sync/conflicts/conflictResolver.js +396 -0
- package/dist/features/sync/conflicts/conflictResolver.js.map +1 -0
- package/dist/features/sync/conflicts/index.d.ts +9 -0
- package/dist/features/sync/conflicts/index.d.ts.map +1 -0
- package/dist/features/sync/conflicts/index.js +9 -0
- package/dist/features/sync/conflicts/index.js.map +1 -0
- package/dist/features/sync/crossPlatformSync.d.ts +281 -0
- package/dist/features/sync/crossPlatformSync.d.ts.map +1 -0
- package/dist/features/sync/crossPlatformSync.js +623 -0
- package/dist/features/sync/crossPlatformSync.js.map +1 -0
- package/dist/features/sync/devices/deviceManager.d.ts +243 -0
- package/dist/features/sync/devices/deviceManager.d.ts.map +1 -0
- package/dist/features/sync/devices/deviceManager.js +494 -0
- package/dist/features/sync/devices/deviceManager.js.map +1 -0
- package/dist/features/sync/devices/index.d.ts +10 -0
- package/dist/features/sync/devices/index.d.ts.map +1 -0
- package/dist/features/sync/devices/index.js +10 -0
- package/dist/features/sync/devices/index.js.map +1 -0
- package/dist/features/sync/index.d.ts +37 -0
- package/dist/features/sync/index.d.ts.map +1 -0
- package/dist/features/sync/index.js +47 -0
- package/dist/features/sync/index.js.map +1 -0
- package/dist/features/sync/protocol/index.d.ts +11 -0
- package/dist/features/sync/protocol/index.d.ts.map +1 -0
- package/dist/features/sync/protocol/index.js +11 -0
- package/dist/features/sync/protocol/index.js.map +1 -0
- package/dist/features/sync/protocol/messages.d.ts +348 -0
- package/dist/features/sync/protocol/messages.d.ts.map +1 -0
- package/dist/features/sync/protocol/messages.js +216 -0
- package/dist/features/sync/protocol/messages.js.map +1 -0
- package/dist/features/sync/protocol/vectorClock.d.ts +164 -0
- package/dist/features/sync/protocol/vectorClock.d.ts.map +1 -0
- package/dist/features/sync/protocol/vectorClock.js +286 -0
- package/dist/features/sync/protocol/vectorClock.js.map +1 -0
- package/dist/features/sync/tables/index.d.ts +10 -0
- package/dist/features/sync/tables/index.d.ts.map +1 -0
- package/dist/features/sync/tables/index.js +10 -0
- package/dist/features/sync/tables/index.js.map +1 -0
- package/dist/features/sync/tables/syncLogManager.d.ts +216 -0
- package/dist/features/sync/tables/syncLogManager.d.ts.map +1 -0
- package/dist/features/sync/tables/syncLogManager.js +456 -0
- package/dist/features/sync/tables/syncLogManager.js.map +1 -0
- package/dist/features/sync/transport/httpTransport.d.ts +123 -0
- package/dist/features/sync/transport/httpTransport.d.ts.map +1 -0
- package/dist/features/sync/transport/httpTransport.js +380 -0
- package/dist/features/sync/transport/httpTransport.js.map +1 -0
- package/dist/features/sync/transport/index.d.ts +12 -0
- package/dist/features/sync/transport/index.d.ts.map +1 -0
- package/dist/features/sync/transport/index.js +12 -0
- package/dist/features/sync/transport/index.js.map +1 -0
- package/dist/features/sync/transport/transport.d.ts +259 -0
- package/dist/features/sync/transport/transport.d.ts.map +1 -0
- package/dist/features/sync/transport/transport.js +153 -0
- package/dist/features/sync/transport/transport.js.map +1 -0
- package/dist/features/sync/transport/websocketTransport.d.ts +126 -0
- package/dist/features/sync/transport/websocketTransport.d.ts.map +1 -0
- package/dist/features/sync/transport/websocketTransport.js +374 -0
- package/dist/features/sync/transport/websocketTransport.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/package.json +21 -1
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector Clock Implementation for Causality Tracking.
|
|
3
|
+
*
|
|
4
|
+
* Vector clocks track the causal ordering of events across distributed
|
|
5
|
+
* systems. Each device maintains a counter, and comparing clocks reveals
|
|
6
|
+
* whether events happened-before, happened-after, or are concurrent.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const clock = new VectorClock('device-1');
|
|
11
|
+
*
|
|
12
|
+
* // Local write - increment our counter
|
|
13
|
+
* clock.tick();
|
|
14
|
+
*
|
|
15
|
+
* // Received remote update - merge clocks
|
|
16
|
+
* clock.merge(remoteClockData);
|
|
17
|
+
*
|
|
18
|
+
* // Compare causality
|
|
19
|
+
* const relation = clock.compare(otherClock);
|
|
20
|
+
* if (relation === 'concurrent') {
|
|
21
|
+
* // Conflict detected!
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
/**
|
|
26
|
+
* Vector clock data structure.
|
|
27
|
+
* Maps device IDs to their logical clock values.
|
|
28
|
+
*/
|
|
29
|
+
export type VectorClockData = Record<string, number>;
|
|
30
|
+
/**
|
|
31
|
+
* Causal relationship between two vector clocks.
|
|
32
|
+
*/
|
|
33
|
+
export type CausalRelation = 'before' | 'after' | 'concurrent' | 'equal';
|
|
34
|
+
/**
|
|
35
|
+
* Serialized vector clock for transmission.
|
|
36
|
+
*/
|
|
37
|
+
export interface SerializedVectorClock {
|
|
38
|
+
/** Device ID that owns this clock */
|
|
39
|
+
deviceId: string;
|
|
40
|
+
/** Clock values for all known devices */
|
|
41
|
+
values: VectorClockData;
|
|
42
|
+
/** Timestamp when clock was last updated */
|
|
43
|
+
updatedAt: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Vector Clock for distributed causality tracking.
|
|
47
|
+
*
|
|
48
|
+
* Implements Lamport's vector clock algorithm for determining
|
|
49
|
+
* causal ordering of events across multiple devices.
|
|
50
|
+
*/
|
|
51
|
+
export declare class VectorClock {
|
|
52
|
+
private readonly deviceId;
|
|
53
|
+
private values;
|
|
54
|
+
private lastUpdated;
|
|
55
|
+
constructor(deviceId: string);
|
|
56
|
+
/**
|
|
57
|
+
* Increment this device's clock (local event occurred).
|
|
58
|
+
* Call this before sending a message or making a local change.
|
|
59
|
+
*
|
|
60
|
+
* @returns The new clock value for this device
|
|
61
|
+
*/
|
|
62
|
+
tick(): number;
|
|
63
|
+
/**
|
|
64
|
+
* Merge another clock into this one (received remote event).
|
|
65
|
+
* Takes the maximum of each device's counter.
|
|
66
|
+
*
|
|
67
|
+
* @param other - The remote clock to merge
|
|
68
|
+
*/
|
|
69
|
+
merge(other: VectorClockData | VectorClock): void;
|
|
70
|
+
/**
|
|
71
|
+
* Update from received clock without incrementing local counter.
|
|
72
|
+
* Used when just observing, not participating in the event.
|
|
73
|
+
*
|
|
74
|
+
* @param other - The remote clock to observe
|
|
75
|
+
*/
|
|
76
|
+
observe(other: VectorClockData | VectorClock): void;
|
|
77
|
+
/**
|
|
78
|
+
* Compare this clock to another to determine causal relationship.
|
|
79
|
+
*
|
|
80
|
+
* @param other - The clock to compare against
|
|
81
|
+
* @returns The causal relationship
|
|
82
|
+
*/
|
|
83
|
+
compare(other: VectorClockData | VectorClock): CausalRelation;
|
|
84
|
+
/**
|
|
85
|
+
* Check if this clock happened before another.
|
|
86
|
+
*/
|
|
87
|
+
happenedBefore(other: VectorClockData | VectorClock): boolean;
|
|
88
|
+
/**
|
|
89
|
+
* Check if this clock happened after another.
|
|
90
|
+
*/
|
|
91
|
+
happenedAfter(other: VectorClockData | VectorClock): boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Check if this clock is concurrent with another (conflict).
|
|
94
|
+
*/
|
|
95
|
+
isConcurrent(other: VectorClockData | VectorClock): boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Get this device's ID.
|
|
98
|
+
*/
|
|
99
|
+
getDeviceId(): string;
|
|
100
|
+
/**
|
|
101
|
+
* Get this device's current clock value.
|
|
102
|
+
*/
|
|
103
|
+
getValue(): number;
|
|
104
|
+
/**
|
|
105
|
+
* Get clock value for a specific device.
|
|
106
|
+
*/
|
|
107
|
+
getValueFor(deviceId: string): number;
|
|
108
|
+
/**
|
|
109
|
+
* Get all clock values.
|
|
110
|
+
*/
|
|
111
|
+
getValues(): VectorClockData;
|
|
112
|
+
/**
|
|
113
|
+
* Get list of known device IDs.
|
|
114
|
+
*/
|
|
115
|
+
getKnownDevices(): string[];
|
|
116
|
+
/**
|
|
117
|
+
* Get when the clock was last updated.
|
|
118
|
+
*/
|
|
119
|
+
getLastUpdated(): number;
|
|
120
|
+
/**
|
|
121
|
+
* Serialize clock for transmission.
|
|
122
|
+
*/
|
|
123
|
+
serialize(): SerializedVectorClock;
|
|
124
|
+
/**
|
|
125
|
+
* Create a clock from serialized data.
|
|
126
|
+
*/
|
|
127
|
+
static deserialize(data: SerializedVectorClock): VectorClock;
|
|
128
|
+
/**
|
|
129
|
+
* Create a copy of this clock.
|
|
130
|
+
*/
|
|
131
|
+
clone(): VectorClock;
|
|
132
|
+
/**
|
|
133
|
+
* Convert to JSON string.
|
|
134
|
+
*/
|
|
135
|
+
toJSON(): string;
|
|
136
|
+
/**
|
|
137
|
+
* Create from JSON string.
|
|
138
|
+
*/
|
|
139
|
+
static fromJSON(json: string): VectorClock;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Create a new vector clock for a device.
|
|
143
|
+
*
|
|
144
|
+
* @param deviceId - Unique identifier for this device
|
|
145
|
+
* @returns New VectorClock instance
|
|
146
|
+
*/
|
|
147
|
+
export declare function createVectorClock(deviceId: string): VectorClock;
|
|
148
|
+
/**
|
|
149
|
+
* Compare two clock data objects without creating instances.
|
|
150
|
+
*/
|
|
151
|
+
export declare function compareClocks(a: VectorClockData, b: VectorClockData): CausalRelation;
|
|
152
|
+
/**
|
|
153
|
+
* Merge multiple clocks into a new clock.
|
|
154
|
+
*/
|
|
155
|
+
export declare function mergeClocks(deviceId: string, ...clocks: VectorClockData[]): VectorClock;
|
|
156
|
+
/**
|
|
157
|
+
* Check if a clock dominates another (happened strictly after).
|
|
158
|
+
*/
|
|
159
|
+
export declare function dominates(a: VectorClockData, b: VectorClockData): boolean;
|
|
160
|
+
/**
|
|
161
|
+
* Generate a unique device ID.
|
|
162
|
+
*/
|
|
163
|
+
export declare function generateDeviceId(): string;
|
|
164
|
+
//# sourceMappingURL=vectorClock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorClock.d.ts","sourceRoot":"","sources":["../../../../src/features/sync/protocol/vectorClock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAMH;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,cAAc,GACtB,QAAQ,GACR,OAAO,GACP,YAAY,GACZ,OAAO,CAAC;AAEZ;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,qCAAqC;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,yCAAyC;IACzC,MAAM,EAAE,eAAe,CAAC;IACxB,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;CACnB;AAMD;;;;;GAKG;AACH,qBAAa,WAAW;IAIV,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAHrC,OAAO,CAAC,MAAM,CAAuB;IACrC,OAAO,CAAC,WAAW,CAAsB;gBAEZ,QAAQ,EAAE,MAAM;IAS7C;;;;;OAKG;IACI,IAAI,IAAI,MAAM;IAMrB;;;;;OAKG;IACI,KAAK,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,IAAI;IAWxD;;;;;OAKG;IACI,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,IAAI;IAa1D;;;;;OAKG;IACI,OAAO,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,cAAc;IAkCpE;;OAEG;IACI,cAAc,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,OAAO;IAIpE;;OAEG;IACI,aAAa,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,OAAO;IAInE;;OAEG;IACI,YAAY,CAAC,KAAK,EAAE,eAAe,GAAG,WAAW,GAAG,OAAO;IAQlE;;OAEG;IACI,WAAW,IAAI,MAAM;IAI5B;;OAEG;IACI,QAAQ,IAAI,MAAM;IAIzB;;OAEG;IACI,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM;IAI5C;;OAEG;IACI,SAAS,IAAI,eAAe;IAInC;;OAEG;IACI,eAAe,IAAI,MAAM,EAAE;IAIlC;;OAEG;IACI,cAAc,IAAI,MAAM;IAQ/B;;OAEG;IACI,SAAS,IAAI,qBAAqB;IAQzC;;OAEG;WACW,WAAW,CAAC,IAAI,EAAE,qBAAqB,GAAG,WAAW;IAOnE;;OAEG;IACI,KAAK,IAAI,WAAW;IAI3B;;OAEG;IACI,MAAM,IAAI,MAAM;IAIvB;;OAEG;WACW,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW;CAGlD;AAMD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,CAE/D;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAC3B,CAAC,EAAE,eAAe,EAClB,CAAC,EAAE,eAAe,GACjB,cAAc,CAqBhB;AAED;;GAEG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,GAAG,MAAM,EAAE,eAAe,EAAE,GAC3B,WAAW,CAQb;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,eAAe,EAAE,CAAC,EAAE,eAAe,GAAG,OAAO,CAEzE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAIzC"}
|
|
@@ -0,0 +1,286 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vector Clock Implementation for Causality Tracking.
|
|
3
|
+
*
|
|
4
|
+
* Vector clocks track the causal ordering of events across distributed
|
|
5
|
+
* systems. Each device maintains a counter, and comparing clocks reveals
|
|
6
|
+
* whether events happened-before, happened-after, or are concurrent.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* const clock = new VectorClock('device-1');
|
|
11
|
+
*
|
|
12
|
+
* // Local write - increment our counter
|
|
13
|
+
* clock.tick();
|
|
14
|
+
*
|
|
15
|
+
* // Received remote update - merge clocks
|
|
16
|
+
* clock.merge(remoteClockData);
|
|
17
|
+
*
|
|
18
|
+
* // Compare causality
|
|
19
|
+
* const relation = clock.compare(otherClock);
|
|
20
|
+
* if (relation === 'concurrent') {
|
|
21
|
+
* // Conflict detected!
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
// ============================================================================
|
|
26
|
+
// Vector Clock
|
|
27
|
+
// ============================================================================
|
|
28
|
+
/**
|
|
29
|
+
* Vector Clock for distributed causality tracking.
|
|
30
|
+
*
|
|
31
|
+
* Implements Lamport's vector clock algorithm for determining
|
|
32
|
+
* causal ordering of events across multiple devices.
|
|
33
|
+
*/
|
|
34
|
+
export class VectorClock {
|
|
35
|
+
constructor(deviceId) {
|
|
36
|
+
this.deviceId = deviceId;
|
|
37
|
+
this.values = {};
|
|
38
|
+
this.lastUpdated = Date.now();
|
|
39
|
+
// Initialize our own counter
|
|
40
|
+
this.values[deviceId] = 0;
|
|
41
|
+
}
|
|
42
|
+
// ============================================================================
|
|
43
|
+
// Core Operations
|
|
44
|
+
// ============================================================================
|
|
45
|
+
/**
|
|
46
|
+
* Increment this device's clock (local event occurred).
|
|
47
|
+
* Call this before sending a message or making a local change.
|
|
48
|
+
*
|
|
49
|
+
* @returns The new clock value for this device
|
|
50
|
+
*/
|
|
51
|
+
tick() {
|
|
52
|
+
this.values[this.deviceId] = (this.values[this.deviceId] ?? 0) + 1;
|
|
53
|
+
this.lastUpdated = Date.now();
|
|
54
|
+
return this.values[this.deviceId];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Merge another clock into this one (received remote event).
|
|
58
|
+
* Takes the maximum of each device's counter.
|
|
59
|
+
*
|
|
60
|
+
* @param other - The remote clock to merge
|
|
61
|
+
*/
|
|
62
|
+
merge(other) {
|
|
63
|
+
const otherValues = other instanceof VectorClock ? other.values : other;
|
|
64
|
+
for (const [deviceId, value] of Object.entries(otherValues)) {
|
|
65
|
+
this.values[deviceId] = Math.max(this.values[deviceId] ?? 0, value);
|
|
66
|
+
}
|
|
67
|
+
// Increment our own clock after receiving
|
|
68
|
+
this.tick();
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Update from received clock without incrementing local counter.
|
|
72
|
+
* Used when just observing, not participating in the event.
|
|
73
|
+
*
|
|
74
|
+
* @param other - The remote clock to observe
|
|
75
|
+
*/
|
|
76
|
+
observe(other) {
|
|
77
|
+
const otherValues = other instanceof VectorClock ? other.values : other;
|
|
78
|
+
for (const [deviceId, value] of Object.entries(otherValues)) {
|
|
79
|
+
this.values[deviceId] = Math.max(this.values[deviceId] ?? 0, value);
|
|
80
|
+
}
|
|
81
|
+
this.lastUpdated = Date.now();
|
|
82
|
+
}
|
|
83
|
+
// ============================================================================
|
|
84
|
+
// Comparison
|
|
85
|
+
// ============================================================================
|
|
86
|
+
/**
|
|
87
|
+
* Compare this clock to another to determine causal relationship.
|
|
88
|
+
*
|
|
89
|
+
* @param other - The clock to compare against
|
|
90
|
+
* @returns The causal relationship
|
|
91
|
+
*/
|
|
92
|
+
compare(other) {
|
|
93
|
+
const otherValues = other instanceof VectorClock ? other.values : other;
|
|
94
|
+
let thisGreater = false;
|
|
95
|
+
let otherGreater = false;
|
|
96
|
+
// Get all device IDs from both clocks
|
|
97
|
+
const allDevices = new Set([
|
|
98
|
+
...Object.keys(this.values),
|
|
99
|
+
...Object.keys(otherValues),
|
|
100
|
+
]);
|
|
101
|
+
for (const deviceId of allDevices) {
|
|
102
|
+
const thisValue = this.values[deviceId] ?? 0;
|
|
103
|
+
const otherValue = otherValues[deviceId] ?? 0;
|
|
104
|
+
if (thisValue > otherValue) {
|
|
105
|
+
thisGreater = true;
|
|
106
|
+
}
|
|
107
|
+
else if (otherValue > thisValue) {
|
|
108
|
+
otherGreater = true;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
if (thisGreater && otherGreater) {
|
|
112
|
+
return 'concurrent'; // Conflict!
|
|
113
|
+
}
|
|
114
|
+
else if (thisGreater) {
|
|
115
|
+
return 'after';
|
|
116
|
+
}
|
|
117
|
+
else if (otherGreater) {
|
|
118
|
+
return 'before';
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
return 'equal';
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Check if this clock happened before another.
|
|
126
|
+
*/
|
|
127
|
+
happenedBefore(other) {
|
|
128
|
+
return this.compare(other) === 'before';
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Check if this clock happened after another.
|
|
132
|
+
*/
|
|
133
|
+
happenedAfter(other) {
|
|
134
|
+
return this.compare(other) === 'after';
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Check if this clock is concurrent with another (conflict).
|
|
138
|
+
*/
|
|
139
|
+
isConcurrent(other) {
|
|
140
|
+
return this.compare(other) === 'concurrent';
|
|
141
|
+
}
|
|
142
|
+
// ============================================================================
|
|
143
|
+
// Accessors
|
|
144
|
+
// ============================================================================
|
|
145
|
+
/**
|
|
146
|
+
* Get this device's ID.
|
|
147
|
+
*/
|
|
148
|
+
getDeviceId() {
|
|
149
|
+
return this.deviceId;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Get this device's current clock value.
|
|
153
|
+
*/
|
|
154
|
+
getValue() {
|
|
155
|
+
return this.values[this.deviceId] ?? 0;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get clock value for a specific device.
|
|
159
|
+
*/
|
|
160
|
+
getValueFor(deviceId) {
|
|
161
|
+
return this.values[deviceId] ?? 0;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get all clock values.
|
|
165
|
+
*/
|
|
166
|
+
getValues() {
|
|
167
|
+
return { ...this.values };
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Get list of known device IDs.
|
|
171
|
+
*/
|
|
172
|
+
getKnownDevices() {
|
|
173
|
+
return Object.keys(this.values);
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Get when the clock was last updated.
|
|
177
|
+
*/
|
|
178
|
+
getLastUpdated() {
|
|
179
|
+
return this.lastUpdated;
|
|
180
|
+
}
|
|
181
|
+
// ============================================================================
|
|
182
|
+
// Serialization
|
|
183
|
+
// ============================================================================
|
|
184
|
+
/**
|
|
185
|
+
* Serialize clock for transmission.
|
|
186
|
+
*/
|
|
187
|
+
serialize() {
|
|
188
|
+
return {
|
|
189
|
+
deviceId: this.deviceId,
|
|
190
|
+
values: { ...this.values },
|
|
191
|
+
updatedAt: this.lastUpdated,
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
/**
|
|
195
|
+
* Create a clock from serialized data.
|
|
196
|
+
*/
|
|
197
|
+
static deserialize(data) {
|
|
198
|
+
const clock = new VectorClock(data.deviceId);
|
|
199
|
+
clock.values = { ...data.values };
|
|
200
|
+
clock.lastUpdated = data.updatedAt;
|
|
201
|
+
return clock;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Create a copy of this clock.
|
|
205
|
+
*/
|
|
206
|
+
clone() {
|
|
207
|
+
return VectorClock.deserialize(this.serialize());
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Convert to JSON string.
|
|
211
|
+
*/
|
|
212
|
+
toJSON() {
|
|
213
|
+
return JSON.stringify(this.serialize());
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Create from JSON string.
|
|
217
|
+
*/
|
|
218
|
+
static fromJSON(json) {
|
|
219
|
+
return VectorClock.deserialize(JSON.parse(json));
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Factory Function
|
|
224
|
+
// ============================================================================
|
|
225
|
+
/**
|
|
226
|
+
* Create a new vector clock for a device.
|
|
227
|
+
*
|
|
228
|
+
* @param deviceId - Unique identifier for this device
|
|
229
|
+
* @returns New VectorClock instance
|
|
230
|
+
*/
|
|
231
|
+
export function createVectorClock(deviceId) {
|
|
232
|
+
return new VectorClock(deviceId);
|
|
233
|
+
}
|
|
234
|
+
// ============================================================================
|
|
235
|
+
// Utility Functions
|
|
236
|
+
// ============================================================================
|
|
237
|
+
/**
|
|
238
|
+
* Compare two clock data objects without creating instances.
|
|
239
|
+
*/
|
|
240
|
+
export function compareClocks(a, b) {
|
|
241
|
+
let aGreater = false;
|
|
242
|
+
let bGreater = false;
|
|
243
|
+
const allDevices = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
244
|
+
for (const deviceId of allDevices) {
|
|
245
|
+
const aValue = a[deviceId] ?? 0;
|
|
246
|
+
const bValue = b[deviceId] ?? 0;
|
|
247
|
+
if (aValue > bValue) {
|
|
248
|
+
aGreater = true;
|
|
249
|
+
}
|
|
250
|
+
else if (bValue > aValue) {
|
|
251
|
+
bGreater = true;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (aGreater && bGreater)
|
|
255
|
+
return 'concurrent';
|
|
256
|
+
if (aGreater)
|
|
257
|
+
return 'after';
|
|
258
|
+
if (bGreater)
|
|
259
|
+
return 'before';
|
|
260
|
+
return 'equal';
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Merge multiple clocks into a new clock.
|
|
264
|
+
*/
|
|
265
|
+
export function mergeClocks(deviceId, ...clocks) {
|
|
266
|
+
const result = new VectorClock(deviceId);
|
|
267
|
+
for (const clock of clocks) {
|
|
268
|
+
result.observe(clock);
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Check if a clock dominates another (happened strictly after).
|
|
274
|
+
*/
|
|
275
|
+
export function dominates(a, b) {
|
|
276
|
+
return compareClocks(a, b) === 'after';
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Generate a unique device ID.
|
|
280
|
+
*/
|
|
281
|
+
export function generateDeviceId() {
|
|
282
|
+
const timestamp = Date.now().toString(36);
|
|
283
|
+
const random = Math.random().toString(36).substring(2, 10);
|
|
284
|
+
return `device_${timestamp}_${random}`;
|
|
285
|
+
}
|
|
286
|
+
//# sourceMappingURL=vectorClock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"vectorClock.js","sourceRoot":"","sources":["../../../../src/features/sync/protocol/vectorClock.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/features/sync/tables/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/features/sync/tables/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,cAAc,kBAAkB,CAAC"}
|