@quereus/plugin-sync 0.3.1 → 0.3.3
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 +2 -1
- package/package.json +4 -4
- package/dist/src/clock/hlc.d.ts +0 -105
- package/dist/src/clock/hlc.d.ts.map +0 -1
- package/dist/src/clock/hlc.js +0 -251
- package/dist/src/clock/hlc.js.map +0 -1
- package/dist/src/clock/index.d.ts +0 -6
- package/dist/src/clock/index.d.ts.map +0 -1
- package/dist/src/clock/index.js +0 -6
- package/dist/src/clock/index.js.map +0 -1
- package/dist/src/clock/site.d.ts +0 -58
- package/dist/src/clock/site.d.ts.map +0 -1
- package/dist/src/clock/site.js +0 -137
- package/dist/src/clock/site.js.map +0 -1
- package/dist/src/create-sync-module.d.ts +0 -85
- package/dist/src/create-sync-module.d.ts.map +0 -1
- package/dist/src/create-sync-module.js +0 -54
- package/dist/src/create-sync-module.js.map +0 -1
- package/dist/src/index.d.ts +0 -31
- package/dist/src/index.d.ts.map +0 -1
- package/dist/src/index.js +0 -42
- package/dist/src/index.js.map +0 -1
- package/dist/src/metadata/change-log.d.ts +0 -67
- package/dist/src/metadata/change-log.d.ts.map +0 -1
- package/dist/src/metadata/change-log.js +0 -107
- package/dist/src/metadata/change-log.js.map +0 -1
- package/dist/src/metadata/column-version.d.ts +0 -58
- package/dist/src/metadata/column-version.d.ts.map +0 -1
- package/dist/src/metadata/column-version.js +0 -100
- package/dist/src/metadata/column-version.js.map +0 -1
- package/dist/src/metadata/index.d.ts +0 -11
- package/dist/src/metadata/index.d.ts.map +0 -1
- package/dist/src/metadata/index.js +0 -11
- package/dist/src/metadata/index.js.map +0 -1
- package/dist/src/metadata/keys.d.ts +0 -180
- package/dist/src/metadata/keys.d.ts.map +0 -1
- package/dist/src/metadata/keys.js +0 -390
- package/dist/src/metadata/keys.js.map +0 -1
- package/dist/src/metadata/peer-state.d.ts +0 -52
- package/dist/src/metadata/peer-state.d.ts.map +0 -1
- package/dist/src/metadata/peer-state.js +0 -87
- package/dist/src/metadata/peer-state.js.map +0 -1
- package/dist/src/metadata/schema-migration.d.ts +0 -60
- package/dist/src/metadata/schema-migration.d.ts.map +0 -1
- package/dist/src/metadata/schema-migration.js +0 -126
- package/dist/src/metadata/schema-migration.js.map +0 -1
- package/dist/src/metadata/schema-version.d.ts +0 -163
- package/dist/src/metadata/schema-version.d.ts.map +0 -1
- package/dist/src/metadata/schema-version.js +0 -307
- package/dist/src/metadata/schema-version.js.map +0 -1
- package/dist/src/metadata/tombstones.d.ts +0 -67
- package/dist/src/metadata/tombstones.d.ts.map +0 -1
- package/dist/src/metadata/tombstones.js +0 -125
- package/dist/src/metadata/tombstones.js.map +0 -1
- package/dist/src/sync/events.d.ts +0 -117
- package/dist/src/sync/events.d.ts.map +0 -1
- package/dist/src/sync/events.js +0 -56
- package/dist/src/sync/events.js.map +0 -1
- package/dist/src/sync/index.d.ts +0 -8
- package/dist/src/sync/index.d.ts.map +0 -1
- package/dist/src/sync/index.js +0 -8
- package/dist/src/sync/index.js.map +0 -1
- package/dist/src/sync/manager.d.ts +0 -146
- package/dist/src/sync/manager.d.ts.map +0 -1
- package/dist/src/sync/manager.js +0 -8
- package/dist/src/sync/manager.js.map +0 -1
- package/dist/src/sync/protocol.d.ts +0 -282
- package/dist/src/sync/protocol.d.ts.map +0 -1
- package/dist/src/sync/protocol.js +0 -16
- package/dist/src/sync/protocol.js.map +0 -1
- package/dist/src/sync/store-adapter.d.ts +0 -42
- package/dist/src/sync/store-adapter.d.ts.map +0 -1
- package/dist/src/sync/store-adapter.js +0 -232
- package/dist/src/sync/store-adapter.js.map +0 -1
- package/dist/src/sync/sync-manager-impl.d.ts +0 -91
- package/dist/src/sync/sync-manager-impl.d.ts.map +0 -1
- package/dist/src/sync/sync-manager-impl.js +0 -1123
- package/dist/src/sync/sync-manager-impl.js.map +0 -1
package/README.md
CHANGED
|
@@ -145,7 +145,8 @@ This means concurrent updates to *different* columns of the same row both apply,
|
|
|
145
145
|
|
|
146
146
|
## Related Packages
|
|
147
147
|
|
|
148
|
-
- [`@quereus/
|
|
148
|
+
- [`@quereus/store`](../quereus-store/) - Storage base layer (required)
|
|
149
|
+
- [`@quereus/sync-client`](../quereus-sync-client/) - WebSocket sync client (handles connection, reconnection, batching)
|
|
149
150
|
- [`@quereus/sync-coordinator`](../sync-coordinator/) - Server-side coordinator
|
|
150
151
|
|
|
151
152
|
## License
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quereus/plugin-sync",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Multi-master CRDT replication for Quereus - automatic sync with conflict resolution",
|
|
6
6
|
"keywords": [
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"test:single": "cd ../.. && node --import ./packages/quereus-plugin-sync/register.mjs node_modules/mocha/bin/mocha.js --bail"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@quereus/
|
|
46
|
-
"@quereus/
|
|
45
|
+
"@quereus/quereus": "*",
|
|
46
|
+
"@quereus/store": "*"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@quereus/plugin-store": "*",
|
|
50
49
|
"@quereus/quereus": "*",
|
|
50
|
+
"@quereus/store": "*",
|
|
51
51
|
"@types/mocha": "^10.0.10",
|
|
52
52
|
"@types/node": "^22.15.29",
|
|
53
53
|
"chai": "^5.2.0",
|
package/dist/src/clock/hlc.d.ts
DELETED
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hybrid Logical Clock (HLC) implementation.
|
|
3
|
-
*
|
|
4
|
-
* HLC combines physical time with a logical counter to provide:
|
|
5
|
-
* - Monotonically increasing timestamps
|
|
6
|
-
* - Causality tracking across distributed nodes
|
|
7
|
-
* - Bounded clock drift tolerance
|
|
8
|
-
*
|
|
9
|
-
* Ordering: (wallTime, counter, siteId) compared lexicographically
|
|
10
|
-
*/
|
|
11
|
-
import type { SiteId } from './site.js';
|
|
12
|
-
/**
|
|
13
|
-
* Hybrid Logical Clock timestamp.
|
|
14
|
-
*/
|
|
15
|
-
export interface HLC {
|
|
16
|
-
/** Physical wall time in milliseconds since epoch */
|
|
17
|
-
readonly wallTime: bigint;
|
|
18
|
-
/** Logical counter for events in the same millisecond (0-65535) */
|
|
19
|
-
readonly counter: number;
|
|
20
|
-
/** 16-byte UUID identifying the replica */
|
|
21
|
-
readonly siteId: SiteId;
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Compare two HLCs for ordering.
|
|
25
|
-
* Returns negative if a < b, positive if a > b, zero if equal.
|
|
26
|
-
*/
|
|
27
|
-
export declare function compareHLC(a: HLC, b: HLC): number;
|
|
28
|
-
/**
|
|
29
|
-
* Check if two HLCs are equal.
|
|
30
|
-
*/
|
|
31
|
-
export declare function hlcEquals(a: HLC, b: HLC): boolean;
|
|
32
|
-
/**
|
|
33
|
-
* Create a new HLC with the given values.
|
|
34
|
-
*/
|
|
35
|
-
export declare function createHLC(wallTime: bigint, counter: number, siteId: SiteId): HLC;
|
|
36
|
-
/**
|
|
37
|
-
* Serialize HLC to a Uint8Array for storage.
|
|
38
|
-
* Format: 8 bytes wallTime (BE) + 2 bytes counter (BE) + 16 bytes siteId = 26 bytes
|
|
39
|
-
*/
|
|
40
|
-
export declare function serializeHLC(hlc: HLC): Uint8Array;
|
|
41
|
-
/**
|
|
42
|
-
* Deserialize HLC from a Uint8Array.
|
|
43
|
-
*/
|
|
44
|
-
export declare function deserializeHLC(buffer: Uint8Array): HLC;
|
|
45
|
-
/**
|
|
46
|
-
* JSON-serializable representation of an HLC.
|
|
47
|
-
* Uses strings for bigint and base64url for binary data.
|
|
48
|
-
*/
|
|
49
|
-
export interface SerializedHLC {
|
|
50
|
-
/** Wall time in milliseconds (string to preserve bigint precision) */
|
|
51
|
-
wallTime: string;
|
|
52
|
-
/** Logical counter (0-65535) */
|
|
53
|
-
counter: number;
|
|
54
|
-
/** Site ID as 22-character base64url string */
|
|
55
|
-
siteId: string;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Convert HLC to a JSON-serializable object.
|
|
59
|
-
* Useful for schema seeds, HTTP transport, or debugging.
|
|
60
|
-
*/
|
|
61
|
-
export declare function hlcToJson(hlc: HLC): SerializedHLC;
|
|
62
|
-
/**
|
|
63
|
-
* Parse HLC from a JSON-serializable object.
|
|
64
|
-
*/
|
|
65
|
-
export declare function hlcFromJson(json: SerializedHLC): HLC;
|
|
66
|
-
/**
|
|
67
|
-
* HLC Manager - maintains clock state for a single replica.
|
|
68
|
-
*/
|
|
69
|
-
export declare class HLCManager {
|
|
70
|
-
private wallTime;
|
|
71
|
-
private counter;
|
|
72
|
-
private readonly siteId;
|
|
73
|
-
constructor(siteId: SiteId, initialState?: {
|
|
74
|
-
wallTime: bigint;
|
|
75
|
-
counter: number;
|
|
76
|
-
});
|
|
77
|
-
/**
|
|
78
|
-
* Get the current site ID.
|
|
79
|
-
*/
|
|
80
|
-
getSiteId(): SiteId;
|
|
81
|
-
/**
|
|
82
|
-
* Get current clock state (for persistence).
|
|
83
|
-
*/
|
|
84
|
-
getState(): {
|
|
85
|
-
wallTime: bigint;
|
|
86
|
-
counter: number;
|
|
87
|
-
};
|
|
88
|
-
/**
|
|
89
|
-
* Generate a new HLC for a local event.
|
|
90
|
-
* Advances the clock and returns the new timestamp.
|
|
91
|
-
*/
|
|
92
|
-
tick(): HLC;
|
|
93
|
-
/**
|
|
94
|
-
* Update clock state upon receiving a remote HLC.
|
|
95
|
-
* Ensures our clock is always >= received clock.
|
|
96
|
-
* Returns a new HLC for the local receive event.
|
|
97
|
-
*/
|
|
98
|
-
receive(remote: HLC): HLC;
|
|
99
|
-
/**
|
|
100
|
-
* Create an HLC at the current clock state without advancing.
|
|
101
|
-
* Useful for read operations.
|
|
102
|
-
*/
|
|
103
|
-
now(): HLC;
|
|
104
|
-
}
|
|
105
|
-
//# sourceMappingURL=hlc.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hlc.d.ts","sourceRoot":"","sources":["../../../src/clock/hlc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAExC;;GAEG;AACH,MAAM,WAAW,GAAG;IAClB,qDAAqD;IACrD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,mEAAmE;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAaD;;;GAGG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,MAAM,CAWjD;AAcD;;GAEG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,GAAG,OAAO,CAEjD;AAED;;GAEG;AACH,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,CAEhF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU,CAcjD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,GAAG,CAYtD;AAMD;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,sEAAsE;IACtE,QAAQ,EAAE,MAAM,CAAC;IACjB,gCAAgC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,+CAA+C;IAC/C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,GAAG,GAAG,aAAa,CAMjD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,aAAa,GAAG,GAAG,CAMpD;AAkDD;;GAEG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEpB,MAAM,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAMhF;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;OAEG;IACH,QAAQ,IAAI;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE;IAIjD;;;OAGG;IACH,IAAI,IAAI,GAAG;IAoBX;;;;OAIG;IACH,OAAO,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG;IAuCzB;;;OAGG;IACH,GAAG,IAAI,GAAG;CAGX"}
|
package/dist/src/clock/hlc.js
DELETED
|
@@ -1,251 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Hybrid Logical Clock (HLC) implementation.
|
|
3
|
-
*
|
|
4
|
-
* HLC combines physical time with a logical counter to provide:
|
|
5
|
-
* - Monotonically increasing timestamps
|
|
6
|
-
* - Causality tracking across distributed nodes
|
|
7
|
-
* - Bounded clock drift tolerance
|
|
8
|
-
*
|
|
9
|
-
* Ordering: (wallTime, counter, siteId) compared lexicographically
|
|
10
|
-
*/
|
|
11
|
-
/**
|
|
12
|
-
* Maximum counter value before forcing time advancement.
|
|
13
|
-
*/
|
|
14
|
-
const MAX_COUNTER = 0xFFFF;
|
|
15
|
-
/**
|
|
16
|
-
* Maximum allowed clock drift in milliseconds (1 minute).
|
|
17
|
-
* Rejects remote timestamps that are too far in the future.
|
|
18
|
-
*/
|
|
19
|
-
const MAX_DRIFT_MS = 60000n;
|
|
20
|
-
/**
|
|
21
|
-
* Compare two HLCs for ordering.
|
|
22
|
-
* Returns negative if a < b, positive if a > b, zero if equal.
|
|
23
|
-
*/
|
|
24
|
-
export function compareHLC(a, b) {
|
|
25
|
-
// First compare wall time
|
|
26
|
-
if (a.wallTime < b.wallTime)
|
|
27
|
-
return -1;
|
|
28
|
-
if (a.wallTime > b.wallTime)
|
|
29
|
-
return 1;
|
|
30
|
-
// Same wall time: compare counter
|
|
31
|
-
if (a.counter < b.counter)
|
|
32
|
-
return -1;
|
|
33
|
-
if (a.counter > b.counter)
|
|
34
|
-
return 1;
|
|
35
|
-
// Same counter: compare site ID lexicographically
|
|
36
|
-
return compareSiteIds(a.siteId, b.siteId);
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Compare two site IDs lexicographically.
|
|
40
|
-
*/
|
|
41
|
-
function compareSiteIds(a, b) {
|
|
42
|
-
const len = Math.min(a.length, b.length);
|
|
43
|
-
for (let i = 0; i < len; i++) {
|
|
44
|
-
if (a[i] < b[i])
|
|
45
|
-
return -1;
|
|
46
|
-
if (a[i] > b[i])
|
|
47
|
-
return 1;
|
|
48
|
-
}
|
|
49
|
-
return a.length - b.length;
|
|
50
|
-
}
|
|
51
|
-
/**
|
|
52
|
-
* Check if two HLCs are equal.
|
|
53
|
-
*/
|
|
54
|
-
export function hlcEquals(a, b) {
|
|
55
|
-
return compareHLC(a, b) === 0;
|
|
56
|
-
}
|
|
57
|
-
/**
|
|
58
|
-
* Create a new HLC with the given values.
|
|
59
|
-
*/
|
|
60
|
-
export function createHLC(wallTime, counter, siteId) {
|
|
61
|
-
return Object.freeze({ wallTime, counter, siteId });
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Serialize HLC to a Uint8Array for storage.
|
|
65
|
-
* Format: 8 bytes wallTime (BE) + 2 bytes counter (BE) + 16 bytes siteId = 26 bytes
|
|
66
|
-
*/
|
|
67
|
-
export function serializeHLC(hlc) {
|
|
68
|
-
const buffer = new Uint8Array(26);
|
|
69
|
-
const view = new DataView(buffer.buffer);
|
|
70
|
-
// Wall time as big-endian 64-bit
|
|
71
|
-
view.setBigUint64(0, hlc.wallTime, false);
|
|
72
|
-
// Counter as big-endian 16-bit
|
|
73
|
-
view.setUint16(8, hlc.counter, false);
|
|
74
|
-
// Site ID (16 bytes)
|
|
75
|
-
buffer.set(hlc.siteId, 10);
|
|
76
|
-
return buffer;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Deserialize HLC from a Uint8Array.
|
|
80
|
-
*/
|
|
81
|
-
export function deserializeHLC(buffer) {
|
|
82
|
-
if (buffer.length !== 26) {
|
|
83
|
-
throw new Error(`Invalid HLC buffer length: ${buffer.length}, expected 26`);
|
|
84
|
-
}
|
|
85
|
-
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
86
|
-
const wallTime = view.getBigUint64(0, false);
|
|
87
|
-
const counter = view.getUint16(8, false);
|
|
88
|
-
const siteId = new Uint8Array(buffer.slice(10, 26));
|
|
89
|
-
return createHLC(wallTime, counter, siteId);
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Convert HLC to a JSON-serializable object.
|
|
93
|
-
* Useful for schema seeds, HTTP transport, or debugging.
|
|
94
|
-
*/
|
|
95
|
-
export function hlcToJson(hlc) {
|
|
96
|
-
return {
|
|
97
|
-
wallTime: hlc.wallTime.toString(),
|
|
98
|
-
counter: hlc.counter,
|
|
99
|
-
siteId: siteIdToBase64Local(hlc.siteId),
|
|
100
|
-
};
|
|
101
|
-
}
|
|
102
|
-
/**
|
|
103
|
-
* Parse HLC from a JSON-serializable object.
|
|
104
|
-
*/
|
|
105
|
-
export function hlcFromJson(json) {
|
|
106
|
-
return createHLC(BigInt(json.wallTime), json.counter, siteIdFromBase64Local(json.siteId));
|
|
107
|
-
}
|
|
108
|
-
// Base64url alphabet (RFC 4648 Section 5)
|
|
109
|
-
const BASE64URL_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
110
|
-
/**
|
|
111
|
-
* Convert site ID to base64url string (local helper to avoid circular import).
|
|
112
|
-
*/
|
|
113
|
-
function siteIdToBase64Local(siteId) {
|
|
114
|
-
let result = '';
|
|
115
|
-
for (let i = 0; i < siteId.length; i += 3) {
|
|
116
|
-
const byte1 = siteId[i];
|
|
117
|
-
const byte2 = i + 1 < siteId.length ? siteId[i + 1] : 0;
|
|
118
|
-
const byte3 = i + 2 < siteId.length ? siteId[i + 2] : 0;
|
|
119
|
-
const triplet = (byte1 << 16) | (byte2 << 8) | byte3;
|
|
120
|
-
result += BASE64URL_CHARS[(triplet >>> 18) & 0x3f];
|
|
121
|
-
result += BASE64URL_CHARS[(triplet >>> 12) & 0x3f];
|
|
122
|
-
if (i + 1 < siteId.length)
|
|
123
|
-
result += BASE64URL_CHARS[(triplet >>> 6) & 0x3f];
|
|
124
|
-
if (i + 2 < siteId.length)
|
|
125
|
-
result += BASE64URL_CHARS[triplet & 0x3f];
|
|
126
|
-
}
|
|
127
|
-
return result;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Parse site ID from base64url string (local helper to avoid circular import).
|
|
131
|
-
*/
|
|
132
|
-
function siteIdFromBase64Local(base64) {
|
|
133
|
-
if (base64.length !== 22) {
|
|
134
|
-
throw new Error(`Invalid site ID base64 length: ${base64.length}, expected 22`);
|
|
135
|
-
}
|
|
136
|
-
// Build reverse lookup table
|
|
137
|
-
const lookup = {};
|
|
138
|
-
for (let i = 0; i < BASE64URL_CHARS.length; i++) {
|
|
139
|
-
lookup[BASE64URL_CHARS[i]] = i;
|
|
140
|
-
}
|
|
141
|
-
const result = new Uint8Array(16);
|
|
142
|
-
let writePos = 0;
|
|
143
|
-
for (let i = 0; i < base64.length; i += 4) {
|
|
144
|
-
const c1 = lookup[base64[i]] ?? 0;
|
|
145
|
-
const c2 = lookup[base64[i + 1]] ?? 0;
|
|
146
|
-
const c3 = i + 2 < base64.length ? lookup[base64[i + 2]] ?? 0 : 0;
|
|
147
|
-
const c4 = i + 3 < base64.length ? lookup[base64[i + 3]] ?? 0 : 0;
|
|
148
|
-
const triplet = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
|
|
149
|
-
if (writePos < 16)
|
|
150
|
-
result[writePos++] = (triplet >>> 16) & 0xff;
|
|
151
|
-
if (writePos < 16)
|
|
152
|
-
result[writePos++] = (triplet >>> 8) & 0xff;
|
|
153
|
-
if (writePos < 16)
|
|
154
|
-
result[writePos++] = triplet & 0xff;
|
|
155
|
-
}
|
|
156
|
-
return result;
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* HLC Manager - maintains clock state for a single replica.
|
|
160
|
-
*/
|
|
161
|
-
export class HLCManager {
|
|
162
|
-
wallTime;
|
|
163
|
-
counter;
|
|
164
|
-
siteId;
|
|
165
|
-
constructor(siteId, initialState) {
|
|
166
|
-
this.siteId = siteId;
|
|
167
|
-
this.wallTime = initialState?.wallTime ?? 0n;
|
|
168
|
-
this.counter = initialState?.counter ?? 0;
|
|
169
|
-
}
|
|
170
|
-
/**
|
|
171
|
-
* Get the current site ID.
|
|
172
|
-
*/
|
|
173
|
-
getSiteId() {
|
|
174
|
-
return this.siteId;
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Get current clock state (for persistence).
|
|
178
|
-
*/
|
|
179
|
-
getState() {
|
|
180
|
-
return { wallTime: this.wallTime, counter: this.counter };
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Generate a new HLC for a local event.
|
|
184
|
-
* Advances the clock and returns the new timestamp.
|
|
185
|
-
*/
|
|
186
|
-
tick() {
|
|
187
|
-
const now = BigInt(Date.now());
|
|
188
|
-
if (now > this.wallTime) {
|
|
189
|
-
// Physical time has advanced
|
|
190
|
-
this.wallTime = now;
|
|
191
|
-
this.counter = 0;
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
// Same or earlier physical time, increment counter
|
|
195
|
-
this.counter++;
|
|
196
|
-
if (this.counter > MAX_COUNTER) {
|
|
197
|
-
// Counter overflow: force time advancement
|
|
198
|
-
this.wallTime++;
|
|
199
|
-
this.counter = 0;
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
return createHLC(this.wallTime, this.counter, this.siteId);
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* Update clock state upon receiving a remote HLC.
|
|
206
|
-
* Ensures our clock is always >= received clock.
|
|
207
|
-
* Returns a new HLC for the local receive event.
|
|
208
|
-
*/
|
|
209
|
-
receive(remote) {
|
|
210
|
-
const now = BigInt(Date.now());
|
|
211
|
-
// Check for excessive drift
|
|
212
|
-
if (remote.wallTime > now + MAX_DRIFT_MS) {
|
|
213
|
-
throw new Error(`Remote clock too far in future: ${remote.wallTime - now}ms ahead (max ${MAX_DRIFT_MS}ms)`);
|
|
214
|
-
}
|
|
215
|
-
// Merge: take max of local, remote, and now
|
|
216
|
-
const maxWall = now > this.wallTime
|
|
217
|
-
? (now > remote.wallTime ? now : remote.wallTime)
|
|
218
|
-
: (this.wallTime > remote.wallTime ? this.wallTime : remote.wallTime);
|
|
219
|
-
if (maxWall === this.wallTime && maxWall === remote.wallTime) {
|
|
220
|
-
// All three are equal: take max counter + 1
|
|
221
|
-
this.counter = Math.max(this.counter, remote.counter) + 1;
|
|
222
|
-
}
|
|
223
|
-
else if (maxWall === this.wallTime) {
|
|
224
|
-
// Local wins: increment local counter
|
|
225
|
-
this.counter++;
|
|
226
|
-
}
|
|
227
|
-
else if (maxWall === remote.wallTime) {
|
|
228
|
-
// Remote wins: take remote counter + 1
|
|
229
|
-
this.wallTime = remote.wallTime;
|
|
230
|
-
this.counter = remote.counter + 1;
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
// Physical time wins: reset counter
|
|
234
|
-
this.wallTime = maxWall;
|
|
235
|
-
this.counter = 0;
|
|
236
|
-
}
|
|
237
|
-
if (this.counter > MAX_COUNTER) {
|
|
238
|
-
this.wallTime++;
|
|
239
|
-
this.counter = 0;
|
|
240
|
-
}
|
|
241
|
-
return createHLC(this.wallTime, this.counter, this.siteId);
|
|
242
|
-
}
|
|
243
|
-
/**
|
|
244
|
-
* Create an HLC at the current clock state without advancing.
|
|
245
|
-
* Useful for read operations.
|
|
246
|
-
*/
|
|
247
|
-
now() {
|
|
248
|
-
return createHLC(this.wallTime, this.counter, this.siteId);
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
//# sourceMappingURL=hlc.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"hlc.js","sourceRoot":"","sources":["../../../src/clock/hlc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAgBH;;GAEG;AACH,MAAM,WAAW,GAAG,MAAM,CAAC;AAE3B;;;GAGG;AACH,MAAM,YAAY,GAAG,MAAO,CAAC;AAE7B;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,CAAM,EAAE,CAAM;IACvC,0BAA0B;IAC1B,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ;QAAE,OAAO,CAAC,CAAC;IAEtC,kCAAkC;IAClC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC,CAAC;IACrC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO;QAAE,OAAO,CAAC,CAAC;IAEpC,kDAAkD;IAClD,OAAO,cAAc,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;AAC5C,CAAC;AAED;;GAEG;AACH,SAAS,cAAc,CAAC,CAAS,EAAE,CAAS;IAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IACzC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC;QAC7B,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC,CAAC;QAC3B,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,CAAC,CAAC;IAC5B,CAAC;IACD,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,MAAM,CAAC;AAC7B,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,CAAM,EAAE,CAAM;IACtC,OAAO,UAAU,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,OAAe,EAAE,MAAc;IACzE,OAAO,MAAM,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;AACtD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,GAAQ;IACnC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAEzC,iCAAiC;IACjC,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAE1C,+BAA+B;IAC/B,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAEtC,qBAAqB;IACrB,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAE3B,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,MAAkB;IAC/C,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,8BAA8B,MAAM,CAAC,MAAM,eAAe,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,IAAI,GAAG,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;IAE/E,MAAM,QAAQ,GAAG,IAAI,CAAC,YAAY,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;IAEpD,OAAO,SAAS,CAAC,QAAQ,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;AAC9C,CAAC;AAmBD;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAQ;IAChC,OAAO;QACL,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,QAAQ,EAAE;QACjC,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,MAAM,EAAE,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC;KACxC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CAAC,IAAmB;IAC7C,OAAO,SAAS,CACd,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,EACrB,IAAI,CAAC,OAAO,EACZ,qBAAqB,CAAC,IAAI,CAAC,MAAM,CAAC,CACnC,CAAC;AACJ,CAAC;AAED,0CAA0C;AAC1C,MAAM,eAAe,GAAG,kEAAkE,CAAC;AAE3F;;GAEG;AACH,SAAS,mBAAmB,CAAC,MAAc;IACzC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;QACxB,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,CAAC,GAAG,KAAK,CAAC;QACrD,MAAM,IAAI,eAAe,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACnD,MAAM,IAAI,eAAe,CAAC,CAAC,OAAO,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QACnD,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM;YAAE,MAAM,IAAI,eAAe,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7E,IAAI,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM;YAAE,MAAM,IAAI,eAAe,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,qBAAqB,CAAC,MAAc;IAC3C,IAAI,MAAM,CAAC,MAAM,KAAK,EAAE,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,kCAAkC,MAAM,CAAC,MAAM,eAAe,CAAC,CAAC;IAClF,CAAC;IACD,6BAA6B;IAC7B,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAChD,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAClC,IAAI,QAAQ,GAAG,CAAC,CAAC;IACjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;QAC1C,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClC,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACtC,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,EAAE,GAAG,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClE,MAAM,OAAO,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;QACzD,IAAI,QAAQ,GAAG,EAAE;YAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,OAAO,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;QAChE,IAAI,QAAQ,GAAG,EAAE;YAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,OAAO,KAAK,CAAC,CAAC,GAAG,IAAI,CAAC;QAC/D,IAAI,QAAQ,GAAG,EAAE;YAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,GAAG,OAAO,GAAG,IAAI,CAAC;IACzD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,MAAM,OAAO,UAAU;IACb,QAAQ,CAAS;IACjB,OAAO,CAAS;IACP,MAAM,CAAS;IAEhC,YAAY,MAAc,EAAE,YAAoD;QAC9E,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,QAAQ,GAAG,YAAY,EAAE,QAAQ,IAAI,EAAE,CAAC;QAC7C,IAAI,CAAC,OAAO,GAAG,YAAY,EAAE,OAAO,IAAI,CAAC,CAAC;IAC5C,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAED;;OAEG;IACH,QAAQ;QACN,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC;IAC5D,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAE/B,IAAI,GAAG,GAAG,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxB,6BAA6B;YAC7B,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC;YACpB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACnB,CAAC;aAAM,CAAC;YACN,mDAAmD;YACnD,IAAI,CAAC,OAAO,EAAE,CAAC;YACf,IAAI,IAAI,CAAC,OAAO,GAAG,WAAW,EAAE,CAAC;gBAC/B,2CAA2C;gBAC3C,IAAI,CAAC,QAAQ,EAAE,CAAC;gBAChB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;YACnB,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED;;;;OAIG;IACH,OAAO,CAAC,MAAW;QACjB,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC;QAE/B,4BAA4B;QAC5B,IAAI,MAAM,CAAC,QAAQ,GAAG,GAAG,GAAG,YAAY,EAAE,CAAC;YACzC,MAAM,IAAI,KAAK,CACb,mCAAmC,MAAM,CAAC,QAAQ,GAAG,GAAG,iBAAiB,YAAY,KAAK,CAC3F,CAAC;QACJ,CAAC;QAED,4CAA4C;QAC5C,MAAM,OAAO,GAAG,GAAG,GAAG,IAAI,CAAC,QAAQ;YACjC,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC;YACjD,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAExE,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,IAAI,OAAO,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;YAC7D,4CAA4C;YAC5C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC5D,CAAC;aAAM,IAAI,OAAO,KAAK,IAAI,CAAC,QAAQ,EAAE,CAAC;YACrC,sCAAsC;YACtC,IAAI,CAAC,OAAO,EAAE,CAAC;QACjB,CAAC;aAAM,IAAI,OAAO,KAAK,MAAM,CAAC,QAAQ,EAAE,CAAC;YACvC,uCAAuC;YACvC,IAAI,CAAC,QAAQ,GAAG,MAAM,CAAC,QAAQ,CAAC;YAChC,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,GAAG,CAAC,CAAC;QACpC,CAAC;aAAM,CAAC;YACN,oCAAoC;YACpC,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC;YACxB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACnB,CAAC;QAED,IAAI,IAAI,CAAC,OAAO,GAAG,WAAW,EAAE,CAAC;YAC/B,IAAI,CAAC,QAAQ,EAAE,CAAC;YAChB,IAAI,CAAC,OAAO,GAAG,CAAC,CAAC;QACnB,CAAC;QAED,OAAO,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;IAED;;;OAGG;IACH,GAAG;QACD,OAAO,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC7D,CAAC;CACF"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/clock/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
|
package/dist/src/clock/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/clock/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,WAAW,CAAC"}
|
package/dist/src/clock/site.d.ts
DELETED
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Site ID management - unique identifier for each replica.
|
|
3
|
-
*
|
|
4
|
-
* Site IDs are 16-byte UUIDs that uniquely identify a replica in the
|
|
5
|
-
* distributed system. They are used for:
|
|
6
|
-
* - Breaking ties in HLC comparison
|
|
7
|
-
* - Tracking which changes came from which replica
|
|
8
|
-
* - Peer-to-peer sync state tracking
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* 16-byte unique identifier for a replica.
|
|
12
|
-
*/
|
|
13
|
-
export type SiteId = Uint8Array;
|
|
14
|
-
/**
|
|
15
|
-
* Generate a new random site ID (UUID v4).
|
|
16
|
-
*/
|
|
17
|
-
export declare function generateSiteId(): SiteId;
|
|
18
|
-
/**
|
|
19
|
-
* Convert a Uint8Array to base64url encoding (no padding).
|
|
20
|
-
*/
|
|
21
|
-
export declare function toBase64Url(bytes: Uint8Array): string;
|
|
22
|
-
/**
|
|
23
|
-
* Convert a base64url string to Uint8Array.
|
|
24
|
-
*/
|
|
25
|
-
export declare function fromBase64Url(str: string): Uint8Array;
|
|
26
|
-
/**
|
|
27
|
-
* Convert site ID to base64url string for serialization.
|
|
28
|
-
* 16 bytes → 22 characters (no padding).
|
|
29
|
-
*/
|
|
30
|
-
export declare function siteIdToBase64(siteId: SiteId): string;
|
|
31
|
-
/**
|
|
32
|
-
* Parse site ID from base64url string.
|
|
33
|
-
*/
|
|
34
|
-
export declare function siteIdFromBase64(base64: string): SiteId;
|
|
35
|
-
/**
|
|
36
|
-
* Compare two site IDs for equality.
|
|
37
|
-
*/
|
|
38
|
-
export declare function siteIdEquals(a: SiteId, b: SiteId): boolean;
|
|
39
|
-
/**
|
|
40
|
-
* Storage key for site identity.
|
|
41
|
-
*/
|
|
42
|
-
export declare const SITE_ID_KEY = "si:";
|
|
43
|
-
/**
|
|
44
|
-
* Site identity record stored in the KV store.
|
|
45
|
-
*/
|
|
46
|
-
export interface SiteIdentity {
|
|
47
|
-
siteId: SiteId;
|
|
48
|
-
createdAt: number;
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Serialize site identity for storage.
|
|
52
|
-
*/
|
|
53
|
-
export declare function serializeSiteIdentity(identity: SiteIdentity): Uint8Array;
|
|
54
|
-
/**
|
|
55
|
-
* Deserialize site identity from storage.
|
|
56
|
-
*/
|
|
57
|
-
export declare function deserializeSiteIdentity(buffer: Uint8Array): SiteIdentity;
|
|
58
|
-
//# sourceMappingURL=site.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"site.d.ts","sourceRoot":"","sources":["../../../src/clock/site.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;GAEG;AACH,MAAM,MAAM,MAAM,GAAG,UAAU,CAAC;AAEhC;;GAEG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAmBvC;AAKD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAmBrD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,UAAU,CA2BrD;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAErD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAM1D;AAED;;GAEG;AACH,eAAO,MAAM,WAAW,QAAQ,CAAC;AAEjC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,UAAU,CAQxE;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,GAAG,YAAY,CAUxE"}
|
package/dist/src/clock/site.js
DELETED
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Site ID management - unique identifier for each replica.
|
|
3
|
-
*
|
|
4
|
-
* Site IDs are 16-byte UUIDs that uniquely identify a replica in the
|
|
5
|
-
* distributed system. They are used for:
|
|
6
|
-
* - Breaking ties in HLC comparison
|
|
7
|
-
* - Tracking which changes came from which replica
|
|
8
|
-
* - Peer-to-peer sync state tracking
|
|
9
|
-
*/
|
|
10
|
-
/**
|
|
11
|
-
* Generate a new random site ID (UUID v4).
|
|
12
|
-
*/
|
|
13
|
-
export function generateSiteId() {
|
|
14
|
-
const id = new Uint8Array(16);
|
|
15
|
-
// Use crypto.getRandomValues if available (browser and Node 19+)
|
|
16
|
-
if (typeof crypto !== 'undefined' && crypto.getRandomValues) {
|
|
17
|
-
crypto.getRandomValues(id);
|
|
18
|
-
}
|
|
19
|
-
else {
|
|
20
|
-
// Fallback for older Node.js
|
|
21
|
-
for (let i = 0; i < 16; i++) {
|
|
22
|
-
id[i] = Math.floor(Math.random() * 256);
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
// Set version to 4 (random UUID)
|
|
26
|
-
id[6] = (id[6] & 0x0f) | 0x40;
|
|
27
|
-
// Set variant to RFC 4122
|
|
28
|
-
id[8] = (id[8] & 0x3f) | 0x80;
|
|
29
|
-
return id;
|
|
30
|
-
}
|
|
31
|
-
// Base64url alphabet (RFC 4648 Section 5)
|
|
32
|
-
const BASE64URL_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
|
|
33
|
-
/**
|
|
34
|
-
* Convert a Uint8Array to base64url encoding (no padding).
|
|
35
|
-
*/
|
|
36
|
-
export function toBase64Url(bytes) {
|
|
37
|
-
let result = '';
|
|
38
|
-
for (let i = 0; i < bytes.length; i += 3) {
|
|
39
|
-
const byte1 = bytes[i];
|
|
40
|
-
const byte2 = i + 1 < bytes.length ? bytes[i + 1] : 0;
|
|
41
|
-
const byte3 = i + 2 < bytes.length ? bytes[i + 2] : 0;
|
|
42
|
-
const triplet = (byte1 << 16) | (byte2 << 8) | byte3;
|
|
43
|
-
result += BASE64URL_CHARS[(triplet >>> 18) & 0x3f];
|
|
44
|
-
result += BASE64URL_CHARS[(triplet >>> 12) & 0x3f];
|
|
45
|
-
if (i + 1 < bytes.length) {
|
|
46
|
-
result += BASE64URL_CHARS[(triplet >>> 6) & 0x3f];
|
|
47
|
-
}
|
|
48
|
-
if (i + 2 < bytes.length) {
|
|
49
|
-
result += BASE64URL_CHARS[triplet & 0x3f];
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
return result;
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
* Convert a base64url string to Uint8Array.
|
|
56
|
-
*/
|
|
57
|
-
export function fromBase64Url(str) {
|
|
58
|
-
// Build reverse lookup table
|
|
59
|
-
const lookup = {};
|
|
60
|
-
for (let i = 0; i < BASE64URL_CHARS.length; i++) {
|
|
61
|
-
lookup[BASE64URL_CHARS[i]] = i;
|
|
62
|
-
}
|
|
63
|
-
// Calculate output length (no padding in base64url)
|
|
64
|
-
const len = str.length;
|
|
65
|
-
const outputLen = Math.floor((len * 3) / 4);
|
|
66
|
-
const result = new Uint8Array(outputLen);
|
|
67
|
-
let writePos = 0;
|
|
68
|
-
for (let i = 0; i < len; i += 4) {
|
|
69
|
-
const c1 = lookup[str[i]] ?? 0;
|
|
70
|
-
const c2 = lookup[str[i + 1]] ?? 0;
|
|
71
|
-
const c3 = i + 2 < len ? lookup[str[i + 2]] ?? 0 : 0;
|
|
72
|
-
const c4 = i + 3 < len ? lookup[str[i + 3]] ?? 0 : 0;
|
|
73
|
-
const triplet = (c1 << 18) | (c2 << 12) | (c3 << 6) | c4;
|
|
74
|
-
if (writePos < outputLen)
|
|
75
|
-
result[writePos++] = (triplet >>> 16) & 0xff;
|
|
76
|
-
if (writePos < outputLen)
|
|
77
|
-
result[writePos++] = (triplet >>> 8) & 0xff;
|
|
78
|
-
if (writePos < outputLen)
|
|
79
|
-
result[writePos++] = triplet & 0xff;
|
|
80
|
-
}
|
|
81
|
-
return result;
|
|
82
|
-
}
|
|
83
|
-
/**
|
|
84
|
-
* Convert site ID to base64url string for serialization.
|
|
85
|
-
* 16 bytes → 22 characters (no padding).
|
|
86
|
-
*/
|
|
87
|
-
export function siteIdToBase64(siteId) {
|
|
88
|
-
return toBase64Url(siteId);
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* Parse site ID from base64url string.
|
|
92
|
-
*/
|
|
93
|
-
export function siteIdFromBase64(base64) {
|
|
94
|
-
if (base64.length !== 22) {
|
|
95
|
-
throw new Error(`Invalid site ID base64 length: ${base64.length}, expected 22`);
|
|
96
|
-
}
|
|
97
|
-
return fromBase64Url(base64);
|
|
98
|
-
}
|
|
99
|
-
/**
|
|
100
|
-
* Compare two site IDs for equality.
|
|
101
|
-
*/
|
|
102
|
-
export function siteIdEquals(a, b) {
|
|
103
|
-
if (a.length !== b.length)
|
|
104
|
-
return false;
|
|
105
|
-
for (let i = 0; i < a.length; i++) {
|
|
106
|
-
if (a[i] !== b[i])
|
|
107
|
-
return false;
|
|
108
|
-
}
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
/**
|
|
112
|
-
* Storage key for site identity.
|
|
113
|
-
*/
|
|
114
|
-
export const SITE_ID_KEY = 'si:';
|
|
115
|
-
/**
|
|
116
|
-
* Serialize site identity for storage.
|
|
117
|
-
*/
|
|
118
|
-
export function serializeSiteIdentity(identity) {
|
|
119
|
-
const buffer = new Uint8Array(24); // 16 bytes siteId + 8 bytes timestamp
|
|
120
|
-
buffer.set(identity.siteId, 0);
|
|
121
|
-
const view = new DataView(buffer.buffer);
|
|
122
|
-
view.setBigUint64(16, BigInt(identity.createdAt), false);
|
|
123
|
-
return buffer;
|
|
124
|
-
}
|
|
125
|
-
/**
|
|
126
|
-
* Deserialize site identity from storage.
|
|
127
|
-
*/
|
|
128
|
-
export function deserializeSiteIdentity(buffer) {
|
|
129
|
-
if (buffer.length !== 24) {
|
|
130
|
-
throw new Error(`Invalid site identity buffer length: ${buffer.length}, expected 24`);
|
|
131
|
-
}
|
|
132
|
-
const siteId = new Uint8Array(buffer.slice(0, 16));
|
|
133
|
-
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
134
|
-
const createdAt = Number(view.getBigUint64(16, false));
|
|
135
|
-
return { siteId, createdAt };
|
|
136
|
-
}
|
|
137
|
-
//# sourceMappingURL=site.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"site.js","sourceRoot":"","sources":["../../../src/clock/site.ts"],"names":[],"mappings":"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"}
|