@quereus/plugin-sync 0.3.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 +154 -0
- package/dist/src/clock/hlc.d.ts +105 -0
- package/dist/src/clock/hlc.d.ts.map +1 -0
- package/dist/src/clock/hlc.js +251 -0
- package/dist/src/clock/hlc.js.map +1 -0
- package/dist/src/clock/index.d.ts +6 -0
- package/dist/src/clock/index.d.ts.map +1 -0
- package/dist/src/clock/index.js +6 -0
- package/dist/src/clock/index.js.map +1 -0
- package/dist/src/clock/site.d.ts +58 -0
- package/dist/src/clock/site.d.ts.map +1 -0
- package/dist/src/clock/site.js +137 -0
- package/dist/src/clock/site.js.map +1 -0
- package/dist/src/create-sync-module.d.ts +85 -0
- package/dist/src/create-sync-module.d.ts.map +1 -0
- package/dist/src/create-sync-module.js +54 -0
- package/dist/src/create-sync-module.js.map +1 -0
- package/dist/src/index.d.ts +31 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +42 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/metadata/change-log.d.ts +67 -0
- package/dist/src/metadata/change-log.d.ts.map +1 -0
- package/dist/src/metadata/change-log.js +107 -0
- package/dist/src/metadata/change-log.js.map +1 -0
- package/dist/src/metadata/column-version.d.ts +58 -0
- package/dist/src/metadata/column-version.d.ts.map +1 -0
- package/dist/src/metadata/column-version.js +100 -0
- package/dist/src/metadata/column-version.js.map +1 -0
- package/dist/src/metadata/index.d.ts +11 -0
- package/dist/src/metadata/index.d.ts.map +1 -0
- package/dist/src/metadata/index.js +11 -0
- package/dist/src/metadata/index.js.map +1 -0
- package/dist/src/metadata/keys.d.ts +180 -0
- package/dist/src/metadata/keys.d.ts.map +1 -0
- package/dist/src/metadata/keys.js +390 -0
- package/dist/src/metadata/keys.js.map +1 -0
- package/dist/src/metadata/peer-state.d.ts +52 -0
- package/dist/src/metadata/peer-state.d.ts.map +1 -0
- package/dist/src/metadata/peer-state.js +87 -0
- package/dist/src/metadata/peer-state.js.map +1 -0
- package/dist/src/metadata/schema-migration.d.ts +60 -0
- package/dist/src/metadata/schema-migration.d.ts.map +1 -0
- package/dist/src/metadata/schema-migration.js +126 -0
- package/dist/src/metadata/schema-migration.js.map +1 -0
- package/dist/src/metadata/schema-version.d.ts +163 -0
- package/dist/src/metadata/schema-version.d.ts.map +1 -0
- package/dist/src/metadata/schema-version.js +307 -0
- package/dist/src/metadata/schema-version.js.map +1 -0
- package/dist/src/metadata/tombstones.d.ts +67 -0
- package/dist/src/metadata/tombstones.d.ts.map +1 -0
- package/dist/src/metadata/tombstones.js +125 -0
- package/dist/src/metadata/tombstones.js.map +1 -0
- package/dist/src/sync/events.d.ts +117 -0
- package/dist/src/sync/events.d.ts.map +1 -0
- package/dist/src/sync/events.js +56 -0
- package/dist/src/sync/events.js.map +1 -0
- package/dist/src/sync/index.d.ts +8 -0
- package/dist/src/sync/index.d.ts.map +1 -0
- package/dist/src/sync/index.js +8 -0
- package/dist/src/sync/index.js.map +1 -0
- package/dist/src/sync/manager.d.ts +146 -0
- package/dist/src/sync/manager.d.ts.map +1 -0
- package/dist/src/sync/manager.js +8 -0
- package/dist/src/sync/manager.js.map +1 -0
- package/dist/src/sync/protocol.d.ts +282 -0
- package/dist/src/sync/protocol.d.ts.map +1 -0
- package/dist/src/sync/protocol.js +16 -0
- package/dist/src/sync/protocol.js.map +1 -0
- package/dist/src/sync/store-adapter.d.ts +42 -0
- package/dist/src/sync/store-adapter.d.ts.map +1 -0
- package/dist/src/sync/store-adapter.js +232 -0
- package/dist/src/sync/store-adapter.js.map +1 -0
- package/dist/src/sync/sync-manager-impl.d.ts +91 -0
- package/dist/src/sync/sync-manager-impl.d.ts.map +1 -0
- package/dist/src/sync/sync-manager-impl.js +1123 -0
- package/dist/src/sync/sync-manager-impl.js.map +1 -0
- package/package.json +64 -0
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tombstone tracking for deletion synchronization.
|
|
3
|
+
*
|
|
4
|
+
* When a row is deleted, a tombstone is created with the deletion HLC.
|
|
5
|
+
* Tombstones prevent deleted rows from being resurrected by older writes.
|
|
6
|
+
*/
|
|
7
|
+
import type { SqlValue } from '@quereus/quereus';
|
|
8
|
+
import type { KVStore, WriteBatch } from '@quereus/plugin-store';
|
|
9
|
+
import { type HLC } from '../clock/hlc.js';
|
|
10
|
+
/**
|
|
11
|
+
* Tombstone record.
|
|
12
|
+
*/
|
|
13
|
+
export interface Tombstone {
|
|
14
|
+
hlc: HLC;
|
|
15
|
+
createdAt: number;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Serialize a tombstone for storage.
|
|
19
|
+
* Format: 26 bytes HLC + 8 bytes createdAt
|
|
20
|
+
*/
|
|
21
|
+
export declare function serializeTombstone(tombstone: Tombstone): Uint8Array;
|
|
22
|
+
/**
|
|
23
|
+
* Deserialize a tombstone from storage.
|
|
24
|
+
*/
|
|
25
|
+
export declare function deserializeTombstone(buffer: Uint8Array): Tombstone;
|
|
26
|
+
/**
|
|
27
|
+
* Tombstone store operations.
|
|
28
|
+
*/
|
|
29
|
+
export declare class TombstoneStore {
|
|
30
|
+
private readonly kv;
|
|
31
|
+
private readonly tombstoneTTL;
|
|
32
|
+
constructor(kv: KVStore, tombstoneTTL: number);
|
|
33
|
+
/**
|
|
34
|
+
* Get the tombstone for a row, if it exists.
|
|
35
|
+
*/
|
|
36
|
+
getTombstone(schemaName: string, tableName: string, pk: SqlValue[]): Promise<Tombstone | undefined>;
|
|
37
|
+
/**
|
|
38
|
+
* Create a tombstone for a deleted row.
|
|
39
|
+
*/
|
|
40
|
+
setTombstone(schemaName: string, tableName: string, pk: SqlValue[], hlc: HLC): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Set tombstone in a batch.
|
|
43
|
+
*/
|
|
44
|
+
setTombstoneBatch(batch: WriteBatch, schemaName: string, tableName: string, pk: SqlValue[], hlc: HLC): void;
|
|
45
|
+
/**
|
|
46
|
+
* Delete a tombstone (used when resurrecting a row).
|
|
47
|
+
*/
|
|
48
|
+
deleteTombstone(schemaName: string, tableName: string, pk: SqlValue[]): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Check if a row is deleted and the deletion should block a write.
|
|
51
|
+
* Returns true if the row is deleted and the incoming HLC is older than the deletion.
|
|
52
|
+
*/
|
|
53
|
+
isDeletedAndBlocking(schemaName: string, tableName: string, pk: SqlValue[], incomingHLC: HLC, allowResurrection: boolean): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* Prune expired tombstones.
|
|
56
|
+
* Returns the number of tombstones deleted.
|
|
57
|
+
*/
|
|
58
|
+
pruneExpired(schemaName: string, tableName: string): Promise<number>;
|
|
59
|
+
/**
|
|
60
|
+
* Get all tombstones for a table (for sync).
|
|
61
|
+
*/
|
|
62
|
+
getAllTombstones(schemaName: string, tableName: string): AsyncIterable<{
|
|
63
|
+
pk: SqlValue[];
|
|
64
|
+
tombstone: Tombstone;
|
|
65
|
+
}>;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=tombstones.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tombstones.d.ts","sourceRoot":"","sources":["../../../src/metadata/tombstones.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACjE,OAAO,EAAE,KAAK,GAAG,EAA4C,MAAM,iBAAiB,CAAC;AAGrF;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,GAAG,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,SAAS,GAAG,UAAU,CASnE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,UAAU,GAAG,SAAS,CAKlE;AAED;;GAEG;AACH,qBAAa,cAAc;IAEvB,OAAO,CAAC,QAAQ,CAAC,EAAE;IACnB,OAAO,CAAC,QAAQ,CAAC,YAAY;gBADZ,EAAE,EAAE,OAAO,EACX,YAAY,EAAE,MAAM;IAGvC;;OAEG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,GACb,OAAO,CAAC,SAAS,GAAG,SAAS,CAAC;IAOjC;;OAEG;IACG,YAAY,CAChB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,GAAG,EAAE,GAAG,GACP,OAAO,CAAC,IAAI,CAAC;IAMhB;;OAEG;IACH,iBAAiB,CACf,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,GAAG,EAAE,GAAG,GACP,IAAI;IAMP;;OAEG;IACG,eAAe,CACnB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,GACb,OAAO,CAAC,IAAI,CAAC;IAKhB;;;OAGG;IACG,oBAAoB,CACxB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,EAAE,EAAE,QAAQ,EAAE,EACd,WAAW,EAAE,GAAG,EAChB,iBAAiB,EAAE,OAAO,GACzB,OAAO,CAAC,OAAO,CAAC;IAanB;;;OAGG;IACG,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkB1E;;OAEG;IACI,gBAAgB,CACrB,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,GAChB,aAAa,CAAC;QAAE,EAAE,EAAE,QAAQ,EAAE,CAAC;QAAC,SAAS,EAAE,SAAS,CAAA;KAAE,CAAC;CAc3D"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tombstone tracking for deletion synchronization.
|
|
3
|
+
*
|
|
4
|
+
* When a row is deleted, a tombstone is created with the deletion HLC.
|
|
5
|
+
* Tombstones prevent deleted rows from being resurrected by older writes.
|
|
6
|
+
*/
|
|
7
|
+
import { serializeHLC, deserializeHLC, compareHLC } from '../clock/hlc.js';
|
|
8
|
+
import { buildTombstoneKey, buildTombstoneScanBounds, decodePK } from './keys.js';
|
|
9
|
+
/**
|
|
10
|
+
* Serialize a tombstone for storage.
|
|
11
|
+
* Format: 26 bytes HLC + 8 bytes createdAt
|
|
12
|
+
*/
|
|
13
|
+
export function serializeTombstone(tombstone) {
|
|
14
|
+
const result = new Uint8Array(34);
|
|
15
|
+
const hlcBytes = serializeHLC(tombstone.hlc);
|
|
16
|
+
result.set(hlcBytes, 0);
|
|
17
|
+
const view = new DataView(result.buffer);
|
|
18
|
+
view.setBigUint64(26, BigInt(tombstone.createdAt), false);
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Deserialize a tombstone from storage.
|
|
23
|
+
*/
|
|
24
|
+
export function deserializeTombstone(buffer) {
|
|
25
|
+
const hlc = deserializeHLC(buffer.slice(0, 26));
|
|
26
|
+
const view = new DataView(buffer.buffer, buffer.byteOffset, buffer.byteLength);
|
|
27
|
+
const createdAt = Number(view.getBigUint64(26, false));
|
|
28
|
+
return { hlc, createdAt };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Tombstone store operations.
|
|
32
|
+
*/
|
|
33
|
+
export class TombstoneStore {
|
|
34
|
+
kv;
|
|
35
|
+
tombstoneTTL;
|
|
36
|
+
constructor(kv, tombstoneTTL) {
|
|
37
|
+
this.kv = kv;
|
|
38
|
+
this.tombstoneTTL = tombstoneTTL;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Get the tombstone for a row, if it exists.
|
|
42
|
+
*/
|
|
43
|
+
async getTombstone(schemaName, tableName, pk) {
|
|
44
|
+
const key = buildTombstoneKey(schemaName, tableName, pk);
|
|
45
|
+
const data = await this.kv.get(key);
|
|
46
|
+
if (!data)
|
|
47
|
+
return undefined;
|
|
48
|
+
return deserializeTombstone(data);
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Create a tombstone for a deleted row.
|
|
52
|
+
*/
|
|
53
|
+
async setTombstone(schemaName, tableName, pk, hlc) {
|
|
54
|
+
const key = buildTombstoneKey(schemaName, tableName, pk);
|
|
55
|
+
const tombstone = { hlc, createdAt: Date.now() };
|
|
56
|
+
await this.kv.put(key, serializeTombstone(tombstone));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Set tombstone in a batch.
|
|
60
|
+
*/
|
|
61
|
+
setTombstoneBatch(batch, schemaName, tableName, pk, hlc) {
|
|
62
|
+
const key = buildTombstoneKey(schemaName, tableName, pk);
|
|
63
|
+
const tombstone = { hlc, createdAt: Date.now() };
|
|
64
|
+
batch.put(key, serializeTombstone(tombstone));
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Delete a tombstone (used when resurrecting a row).
|
|
68
|
+
*/
|
|
69
|
+
async deleteTombstone(schemaName, tableName, pk) {
|
|
70
|
+
const key = buildTombstoneKey(schemaName, tableName, pk);
|
|
71
|
+
await this.kv.delete(key);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Check if a row is deleted and the deletion should block a write.
|
|
75
|
+
* Returns true if the row is deleted and the incoming HLC is older than the deletion.
|
|
76
|
+
*/
|
|
77
|
+
async isDeletedAndBlocking(schemaName, tableName, pk, incomingHLC, allowResurrection) {
|
|
78
|
+
const tombstone = await this.getTombstone(schemaName, tableName, pk);
|
|
79
|
+
if (!tombstone)
|
|
80
|
+
return false;
|
|
81
|
+
if (allowResurrection) {
|
|
82
|
+
// Resurrection allowed: only block if incoming is older
|
|
83
|
+
return compareHLC(incomingHLC, tombstone.hlc) <= 0;
|
|
84
|
+
}
|
|
85
|
+
else {
|
|
86
|
+
// No resurrection: any tombstone blocks writes
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Prune expired tombstones.
|
|
92
|
+
* Returns the number of tombstones deleted.
|
|
93
|
+
*/
|
|
94
|
+
async pruneExpired(schemaName, tableName) {
|
|
95
|
+
const bounds = buildTombstoneScanBounds(schemaName, tableName);
|
|
96
|
+
const now = Date.now();
|
|
97
|
+
const batch = this.kv.batch();
|
|
98
|
+
let count = 0;
|
|
99
|
+
for await (const entry of this.kv.iterate(bounds)) {
|
|
100
|
+
const tombstone = deserializeTombstone(entry.value);
|
|
101
|
+
if (now - tombstone.createdAt > this.tombstoneTTL) {
|
|
102
|
+
batch.delete(entry.key);
|
|
103
|
+
count++;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
await batch.write();
|
|
107
|
+
return count;
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Get all tombstones for a table (for sync).
|
|
111
|
+
*/
|
|
112
|
+
async *getAllTombstones(schemaName, tableName) {
|
|
113
|
+
const bounds = buildTombstoneScanBounds(schemaName, tableName);
|
|
114
|
+
for await (const entry of this.kv.iterate(bounds)) {
|
|
115
|
+
// Extract PK from key: tb:{schema}.{table}:{pk_json}
|
|
116
|
+
const keyStr = new TextDecoder().decode(entry.key);
|
|
117
|
+
const firstColon = keyStr.indexOf(':');
|
|
118
|
+
const secondColon = keyStr.indexOf(':', firstColon + 1);
|
|
119
|
+
const pkJson = keyStr.slice(secondColon + 1);
|
|
120
|
+
const pk = decodePK(pkJson);
|
|
121
|
+
yield { pk, tombstone: deserializeTombstone(entry.value) };
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=tombstones.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tombstones.js","sourceRoot":"","sources":["../../../src/metadata/tombstones.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync event types for reactive UI integration.
|
|
3
|
+
*
|
|
4
|
+
* These events allow applications to react to sync state changes,
|
|
5
|
+
* remote data updates, and conflict resolution.
|
|
6
|
+
*/
|
|
7
|
+
import type { SqlValue } from '@quereus/quereus';
|
|
8
|
+
import type { HLC } from '../clock/hlc.js';
|
|
9
|
+
import type { SiteId } from '../clock/site.js';
|
|
10
|
+
import type { Change } from './protocol.js';
|
|
11
|
+
/**
|
|
12
|
+
* Fired when remote changes are applied locally.
|
|
13
|
+
*/
|
|
14
|
+
export interface RemoteChangeEvent {
|
|
15
|
+
/** Origin replica */
|
|
16
|
+
readonly siteId: SiteId;
|
|
17
|
+
/** Transaction ID */
|
|
18
|
+
readonly transactionId: string;
|
|
19
|
+
/** Changes that were applied */
|
|
20
|
+
readonly changes: Change[];
|
|
21
|
+
/** When changes were applied locally */
|
|
22
|
+
readonly appliedAt: HLC;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Fired when local changes are made.
|
|
26
|
+
*/
|
|
27
|
+
export interface LocalChangeEvent {
|
|
28
|
+
/** Transaction ID */
|
|
29
|
+
readonly transactionId: string;
|
|
30
|
+
/** Changes made locally */
|
|
31
|
+
readonly changes: Change[];
|
|
32
|
+
/** True if not yet synced to any peer */
|
|
33
|
+
readonly pendingSync: boolean;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Fired when a conflict is resolved.
|
|
37
|
+
*/
|
|
38
|
+
export interface ConflictEvent {
|
|
39
|
+
/** Table where conflict occurred */
|
|
40
|
+
readonly table: string;
|
|
41
|
+
/** Primary key of the row */
|
|
42
|
+
readonly pk: SqlValue[];
|
|
43
|
+
/** Column where conflict occurred */
|
|
44
|
+
readonly column: string;
|
|
45
|
+
/** Local value that was in conflict */
|
|
46
|
+
readonly localValue: SqlValue;
|
|
47
|
+
/** Remote value that was in conflict */
|
|
48
|
+
readonly remoteValue: SqlValue;
|
|
49
|
+
/** Which value won */
|
|
50
|
+
readonly winner: 'local' | 'remote';
|
|
51
|
+
/** HLC of the winning value */
|
|
52
|
+
readonly winningHLC: HLC;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Sync connection state.
|
|
56
|
+
*/
|
|
57
|
+
export type SyncState = {
|
|
58
|
+
readonly status: 'disconnected';
|
|
59
|
+
} | {
|
|
60
|
+
readonly status: 'connecting';
|
|
61
|
+
} | {
|
|
62
|
+
readonly status: 'syncing';
|
|
63
|
+
readonly progress: number;
|
|
64
|
+
} | {
|
|
65
|
+
readonly status: 'synced';
|
|
66
|
+
readonly lastSyncHLC: HLC;
|
|
67
|
+
} | {
|
|
68
|
+
readonly status: 'error';
|
|
69
|
+
readonly error: Error;
|
|
70
|
+
};
|
|
71
|
+
/**
|
|
72
|
+
* Unsubscribe function returned by event listeners.
|
|
73
|
+
*/
|
|
74
|
+
export type Unsubscribe = () => void;
|
|
75
|
+
/**
|
|
76
|
+
* Sync event emitter for reactive UI integration.
|
|
77
|
+
*/
|
|
78
|
+
export interface SyncEventEmitter {
|
|
79
|
+
/**
|
|
80
|
+
* Subscribe to remote change events.
|
|
81
|
+
* Fired when changes from another replica are applied locally.
|
|
82
|
+
*/
|
|
83
|
+
onRemoteChange(listener: (event: RemoteChangeEvent) => void): Unsubscribe;
|
|
84
|
+
/**
|
|
85
|
+
* Subscribe to local change events.
|
|
86
|
+
* Fired when local mutations occur.
|
|
87
|
+
*/
|
|
88
|
+
onLocalChange(listener: (event: LocalChangeEvent) => void): Unsubscribe;
|
|
89
|
+
/**
|
|
90
|
+
* Subscribe to sync state changes.
|
|
91
|
+
* Fired when connection state changes.
|
|
92
|
+
*/
|
|
93
|
+
onSyncStateChange(listener: (state: SyncState) => void): Unsubscribe;
|
|
94
|
+
/**
|
|
95
|
+
* Subscribe to conflict resolution events.
|
|
96
|
+
* Fired when a conflict is resolved via LWW.
|
|
97
|
+
*/
|
|
98
|
+
onConflictResolved(listener: (event: ConflictEvent) => void): Unsubscribe;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Default implementation of SyncEventEmitter.
|
|
102
|
+
*/
|
|
103
|
+
export declare class SyncEventEmitterImpl implements SyncEventEmitter {
|
|
104
|
+
private remoteChangeListeners;
|
|
105
|
+
private localChangeListeners;
|
|
106
|
+
private syncStateListeners;
|
|
107
|
+
private conflictListeners;
|
|
108
|
+
onRemoteChange(listener: (event: RemoteChangeEvent) => void): Unsubscribe;
|
|
109
|
+
onLocalChange(listener: (event: LocalChangeEvent) => void): Unsubscribe;
|
|
110
|
+
onSyncStateChange(listener: (state: SyncState) => void): Unsubscribe;
|
|
111
|
+
onConflictResolved(listener: (event: ConflictEvent) => void): Unsubscribe;
|
|
112
|
+
emitRemoteChange(event: RemoteChangeEvent): void;
|
|
113
|
+
emitLocalChange(event: LocalChangeEvent): void;
|
|
114
|
+
emitSyncStateChange(state: SyncState): void;
|
|
115
|
+
emitConflictResolved(event: ConflictEvent): void;
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../../src/sync/events.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sync event types for reactive UI integration.
|
|
3
|
+
*
|
|
4
|
+
* These events allow applications to react to sync state changes,
|
|
5
|
+
* remote data updates, and conflict resolution.
|
|
6
|
+
*/
|
|
7
|
+
// ============================================================================
|
|
8
|
+
// Event Emitter Implementation
|
|
9
|
+
// ============================================================================
|
|
10
|
+
/**
|
|
11
|
+
* Default implementation of SyncEventEmitter.
|
|
12
|
+
*/
|
|
13
|
+
export class SyncEventEmitterImpl {
|
|
14
|
+
remoteChangeListeners = new Set();
|
|
15
|
+
localChangeListeners = new Set();
|
|
16
|
+
syncStateListeners = new Set();
|
|
17
|
+
conflictListeners = new Set();
|
|
18
|
+
onRemoteChange(listener) {
|
|
19
|
+
this.remoteChangeListeners.add(listener);
|
|
20
|
+
return () => this.remoteChangeListeners.delete(listener);
|
|
21
|
+
}
|
|
22
|
+
onLocalChange(listener) {
|
|
23
|
+
this.localChangeListeners.add(listener);
|
|
24
|
+
return () => this.localChangeListeners.delete(listener);
|
|
25
|
+
}
|
|
26
|
+
onSyncStateChange(listener) {
|
|
27
|
+
this.syncStateListeners.add(listener);
|
|
28
|
+
return () => this.syncStateListeners.delete(listener);
|
|
29
|
+
}
|
|
30
|
+
onConflictResolved(listener) {
|
|
31
|
+
this.conflictListeners.add(listener);
|
|
32
|
+
return () => this.conflictListeners.delete(listener);
|
|
33
|
+
}
|
|
34
|
+
// Internal emit methods
|
|
35
|
+
emitRemoteChange(event) {
|
|
36
|
+
for (const listener of this.remoteChangeListeners) {
|
|
37
|
+
listener(event);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
emitLocalChange(event) {
|
|
41
|
+
for (const listener of this.localChangeListeners) {
|
|
42
|
+
listener(event);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
emitSyncStateChange(state) {
|
|
46
|
+
for (const listener of this.syncStateListeners) {
|
|
47
|
+
listener(state);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
emitConflictResolved(event) {
|
|
51
|
+
for (const listener of this.conflictListeners) {
|
|
52
|
+
listener(event);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=events.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/sync/events.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAyGH,+EAA+E;AAC/E,+BAA+B;AAC/B,+EAA+E;AAE/E;;GAEG;AACH,MAAM,OAAO,oBAAoB;IACvB,qBAAqB,GAAG,IAAI,GAAG,EAAsC,CAAC;IACtE,oBAAoB,GAAG,IAAI,GAAG,EAAqC,CAAC;IACpE,kBAAkB,GAAG,IAAI,GAAG,EAA8B,CAAC;IAC3D,iBAAiB,GAAG,IAAI,GAAG,EAAkC,CAAC;IAEtE,cAAc,CAAC,QAA4C;QACzD,IAAI,CAAC,qBAAqB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,qBAAqB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC3D,CAAC;IAED,aAAa,CAAC,QAA2C;QACvD,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACxC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,oBAAoB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IAC1D,CAAC;IAED,iBAAiB,CAAC,QAAoC;QACpD,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxD,CAAC;IAED,kBAAkB,CAAC,QAAwC;QACzD,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACvD,CAAC;IAED,wBAAwB;IAExB,gBAAgB,CAAC,KAAwB;QACvC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,qBAAqB,EAAE,CAAC;YAClD,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,eAAe,CAAC,KAAuB;QACrC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,oBAAoB,EAAE,CAAC;YACjD,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,mBAAmB,CAAC,KAAgB;QAClC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,kBAAkB,EAAE,CAAC;YAC/C,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,oBAAoB,CAAC,KAAoB;QACvC,KAAK,MAAM,QAAQ,IAAI,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC9C,QAAQ,CAAC,KAAK,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/sync/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SyncManager - main API for sync operations.
|
|
3
|
+
*
|
|
4
|
+
* This interface defines the transport-agnostic sync API.
|
|
5
|
+
* Applications implement their own transport layer and call these methods.
|
|
6
|
+
*/
|
|
7
|
+
import type { HLC } from '../clock/hlc.js';
|
|
8
|
+
import type { SiteId } from '../clock/site.js';
|
|
9
|
+
import type { ApplyResult, ChangeSet, Snapshot, SnapshotChunk, SnapshotProgress } from './protocol.js';
|
|
10
|
+
/**
|
|
11
|
+
* Main sync manager interface.
|
|
12
|
+
*
|
|
13
|
+
* This is the primary API for sync operations. Applications use this to:
|
|
14
|
+
* - Get changes to send to peers
|
|
15
|
+
* - Apply changes received from peers
|
|
16
|
+
* - Manage sync state
|
|
17
|
+
*/
|
|
18
|
+
export interface SyncManager {
|
|
19
|
+
/**
|
|
20
|
+
* Get this replica's site ID.
|
|
21
|
+
*/
|
|
22
|
+
getSiteId(): SiteId;
|
|
23
|
+
/**
|
|
24
|
+
* Get current HLC for state comparison.
|
|
25
|
+
*/
|
|
26
|
+
getCurrentHLC(): HLC;
|
|
27
|
+
/**
|
|
28
|
+
* Get all changes since a peer's last known state.
|
|
29
|
+
*
|
|
30
|
+
* @param peerSiteId - The peer requesting changes
|
|
31
|
+
* @param sinceHLC - The peer's last known HLC (omit for full sync)
|
|
32
|
+
* @returns Array of change sets to send to the peer
|
|
33
|
+
*/
|
|
34
|
+
getChangesSince(peerSiteId: SiteId, sinceHLC?: HLC): Promise<ChangeSet[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Apply changes received from a peer.
|
|
37
|
+
*
|
|
38
|
+
* Changes are applied atomically per transaction.
|
|
39
|
+
* Conflicts are resolved using column-level LWW.
|
|
40
|
+
*
|
|
41
|
+
* @param changes - Change sets received from a peer
|
|
42
|
+
* @returns Statistics about what was applied
|
|
43
|
+
*/
|
|
44
|
+
applyChanges(changes: ChangeSet[]): Promise<ApplyResult>;
|
|
45
|
+
/**
|
|
46
|
+
* Check if delta sync is possible with a peer.
|
|
47
|
+
*
|
|
48
|
+
* Returns false if:
|
|
49
|
+
* - Tombstone TTL has expired for relevant data
|
|
50
|
+
* - Peer's last sync is too old
|
|
51
|
+
* - Full snapshot is required
|
|
52
|
+
*
|
|
53
|
+
* @param peerSiteId - The peer to check
|
|
54
|
+
* @param sinceHLC - The peer's last known HLC
|
|
55
|
+
*/
|
|
56
|
+
canDeltaSync(peerSiteId: SiteId, sinceHLC: HLC): Promise<boolean>;
|
|
57
|
+
/**
|
|
58
|
+
* Get a full snapshot for initial sync or TTL expiration recovery.
|
|
59
|
+
*
|
|
60
|
+
* This includes all current data and schema state.
|
|
61
|
+
*/
|
|
62
|
+
getSnapshot(): Promise<Snapshot>;
|
|
63
|
+
/**
|
|
64
|
+
* Apply a full snapshot (replaces all local data).
|
|
65
|
+
*
|
|
66
|
+
* Used for initial sync or when delta sync is not possible.
|
|
67
|
+
*
|
|
68
|
+
* @param snapshot - Full snapshot from a peer
|
|
69
|
+
*/
|
|
70
|
+
applySnapshot(snapshot: Snapshot): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Update the last sync state for a peer.
|
|
73
|
+
*
|
|
74
|
+
* Called after successfully syncing with a peer.
|
|
75
|
+
*
|
|
76
|
+
* @param peerSiteId - The peer we synced with
|
|
77
|
+
* @param hlc - The HLC we synced up to
|
|
78
|
+
*/
|
|
79
|
+
updatePeerSyncState(peerSiteId: SiteId, hlc: HLC): Promise<void>;
|
|
80
|
+
/**
|
|
81
|
+
* Get the last sync state for a peer.
|
|
82
|
+
*
|
|
83
|
+
* @param peerSiteId - The peer to check
|
|
84
|
+
* @returns The last HLC we synced to, or undefined if never synced
|
|
85
|
+
*/
|
|
86
|
+
getPeerSyncState(peerSiteId: SiteId): Promise<HLC | undefined>;
|
|
87
|
+
/**
|
|
88
|
+
* Prune expired tombstones.
|
|
89
|
+
*
|
|
90
|
+
* Should be called periodically to clean up old tombstones.
|
|
91
|
+
* Returns the number of tombstones pruned.
|
|
92
|
+
*/
|
|
93
|
+
pruneTombstones(): Promise<number>;
|
|
94
|
+
/**
|
|
95
|
+
* Stream a snapshot as chunks for memory-efficient transfer.
|
|
96
|
+
*
|
|
97
|
+
* Use this instead of getSnapshot() for large databases.
|
|
98
|
+
* Chunks are yielded in order and can be sent over any streaming transport.
|
|
99
|
+
*
|
|
100
|
+
* @param chunkSize - Max column version entries per chunk (default: 1000)
|
|
101
|
+
*/
|
|
102
|
+
getSnapshotStream(chunkSize?: number): AsyncIterable<SnapshotChunk>;
|
|
103
|
+
/**
|
|
104
|
+
* Apply a streamed snapshot.
|
|
105
|
+
*
|
|
106
|
+
* Processes chunks as they arrive, minimizing memory usage.
|
|
107
|
+
* Supports resumption via checkpoint tracking.
|
|
108
|
+
*
|
|
109
|
+
* @param chunks - Async iterable of snapshot chunks
|
|
110
|
+
* @param onProgress - Optional progress callback
|
|
111
|
+
*/
|
|
112
|
+
applySnapshotStream(chunks: AsyncIterable<SnapshotChunk>, onProgress?: (progress: SnapshotProgress) => void): Promise<void>;
|
|
113
|
+
/**
|
|
114
|
+
* Get a resumable checkpoint for an in-progress snapshot.
|
|
115
|
+
*
|
|
116
|
+
* Used to resume an interrupted snapshot transfer.
|
|
117
|
+
*
|
|
118
|
+
* @param snapshotId - The snapshot ID to get checkpoint for
|
|
119
|
+
*/
|
|
120
|
+
getSnapshotCheckpoint(snapshotId: string): Promise<SnapshotCheckpoint | undefined>;
|
|
121
|
+
/**
|
|
122
|
+
* Resume a snapshot transfer from a checkpoint.
|
|
123
|
+
*
|
|
124
|
+
* @param checkpoint - Previously saved checkpoint
|
|
125
|
+
*/
|
|
126
|
+
resumeSnapshotStream(checkpoint: SnapshotCheckpoint): AsyncIterable<SnapshotChunk>;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Checkpoint for resumable snapshot transfers.
|
|
130
|
+
*/
|
|
131
|
+
export interface SnapshotCheckpoint {
|
|
132
|
+
readonly snapshotId: string;
|
|
133
|
+
readonly siteId: SiteId;
|
|
134
|
+
readonly hlc: HLC;
|
|
135
|
+
/** Last completed table index. */
|
|
136
|
+
readonly lastTableIndex: number;
|
|
137
|
+
/** Last completed entry within current table. */
|
|
138
|
+
readonly lastEntryIndex: number;
|
|
139
|
+
/** Tables completed so far. */
|
|
140
|
+
readonly completedTables: string[];
|
|
141
|
+
/** Total entries processed. */
|
|
142
|
+
readonly entriesProcessed: number;
|
|
143
|
+
/** Timestamp when checkpoint was created. */
|
|
144
|
+
readonly createdAt: number;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=manager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../src/sync/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEvG;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,SAAS,IAAI,MAAM,CAAC;IAEpB;;OAEG;IACH,aAAa,IAAI,GAAG,CAAC;IAErB;;;;;;OAMG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,GAAG,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC;IAE1E;;;;;;;;OAQG;IACH,YAAY,CAAC,OAAO,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IAEzD;;;;;;;;;;OAUG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAElE;;;;OAIG;IACH,WAAW,IAAI,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEjC;;;;;;OAMG;IACH,aAAa,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjD;;;;;;;OAOG;IACH,mBAAmB,CAAC,UAAU,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjE;;;;;OAKG;IACH,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,GAAG,SAAS,CAAC,CAAC;IAE/D;;;;;OAKG;IACH,eAAe,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAMnC;;;;;;;OAOG;IACH,iBAAiB,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;IAEpE;;;;;;;;OAQG;IACH,mBAAmB,CACjB,MAAM,EAAE,aAAa,CAAC,aAAa,CAAC,EACpC,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,gBAAgB,KAAK,IAAI,GAChD,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;;;;OAMG;IACH,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,GAAG,SAAS,CAAC,CAAC;IAEnF;;;;OAIG;IACH,oBAAoB,CAAC,UAAU,EAAE,kBAAkB,GAAG,aAAa,CAAC,aAAa,CAAC,CAAC;CACpF;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,GAAG,EAAE,GAAG,CAAC;IAClB,kCAAkC;IAClC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,iDAAiD;IACjD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,+BAA+B;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,EAAE,CAAC;IACnC,+BAA+B;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../../src/sync/manager.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|