@quereus/sync-client 0.1.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.
@@ -0,0 +1,31 @@
1
+ /**
2
+ * @quereus/sync-client - WebSocket sync client for Quereus
3
+ *
4
+ * This package provides a WebSocket-based sync client that connects to a
5
+ * sync server and handles bidirectional synchronization of changes.
6
+ *
7
+ * Features:
8
+ * - Automatic reconnection with exponential backoff
9
+ * - Local change batching with debouncing
10
+ * - Delta sync tracking (only send/receive changes since last sync)
11
+ * - Event callbacks for status changes, remote changes, and errors
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { SyncClient } from '@quereus/sync-client';
16
+ *
17
+ * const client = new SyncClient({
18
+ * syncManager,
19
+ * onStatusChange: (status) => console.log('Status:', status),
20
+ * onRemoteChanges: (result) => console.log('Applied:', result.applied),
21
+ * });
22
+ *
23
+ * await client.connect('ws://localhost:8080/sync');
24
+ * ```
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+ export { SyncClient } from './sync-client.js';
29
+ export { serializeChangeSet, deserializeChangeSet, serializeHLCForTransport, deserializeHLCFromTransport, } from './serialization.js';
30
+ export type { SyncStatus, SyncEvent, SyncEventType, SyncClientOptions, SerializedChangeSet, SerializedChange, SerializedSchemaMigration, ClientMessage, ServerMessage, HandshakeMessage, HandshakeAckMessage, GetChangesMessage, ChangesMessage, PushChangesMessage, ApplyChangesMessage, ApplyResultMessage, GetSnapshotMessage, PingMessage, PongMessage, ErrorMessage, } from './types.js';
31
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,UAAU,EACV,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EAEzB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @quereus/sync-client - WebSocket sync client for Quereus
3
+ *
4
+ * This package provides a WebSocket-based sync client that connects to a
5
+ * sync server and handles bidirectional synchronization of changes.
6
+ *
7
+ * Features:
8
+ * - Automatic reconnection with exponential backoff
9
+ * - Local change batching with debouncing
10
+ * - Delta sync tracking (only send/receive changes since last sync)
11
+ * - Event callbacks for status changes, remote changes, and errors
12
+ *
13
+ * @example
14
+ * ```typescript
15
+ * import { SyncClient } from '@quereus/sync-client';
16
+ *
17
+ * const client = new SyncClient({
18
+ * syncManager,
19
+ * onStatusChange: (status) => console.log('Status:', status),
20
+ * onRemoteChanges: (result) => console.log('Applied:', result.applied),
21
+ * });
22
+ *
23
+ * await client.connect('ws://localhost:8080/sync');
24
+ * ```
25
+ *
26
+ * @packageDocumentation
27
+ */
28
+ export { SyncClient } from './sync-client.js';
29
+ export { serializeChangeSet, deserializeChangeSet, serializeHLCForTransport, deserializeHLCFromTransport, } from './serialization.js';
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Serialization helpers for ChangeSet transport over JSON.
3
+ *
4
+ * - SiteIds use base64url encoding (via siteIdToBase64/siteIdFromBase64)
5
+ * - HLCs use standard base64 encoding (via btoa/atob in browser, Buffer in Node)
6
+ */
7
+ import { type ChangeSet, type HLC } from '@quereus/plugin-sync';
8
+ import type { SerializedChangeSet } from './types.js';
9
+ /**
10
+ * Serialize a ChangeSet for JSON transport.
11
+ *
12
+ * @param cs - The ChangeSet to serialize
13
+ * @returns A JSON-serializable object
14
+ */
15
+ export declare function serializeChangeSet(cs: ChangeSet): SerializedChangeSet;
16
+ /**
17
+ * Deserialize a ChangeSet from JSON transport format.
18
+ *
19
+ * @param obj - The serialized ChangeSet object
20
+ * @returns The deserialized ChangeSet
21
+ */
22
+ export declare function deserializeChangeSet(obj: SerializedChangeSet): ChangeSet;
23
+ /**
24
+ * Serialize an HLC for transport (base64 encoding).
25
+ *
26
+ * @param hlc - The HLC to serialize
27
+ * @returns Base64-encoded string
28
+ */
29
+ export declare function serializeHLCForTransport(hlc: HLC): string;
30
+ /**
31
+ * Deserialize an HLC from transport format.
32
+ *
33
+ * @param str - Base64-encoded HLC string
34
+ * @returns The deserialized HLC
35
+ */
36
+ export declare function deserializeHLCFromTransport(str: string): HLC;
37
+ //# sourceMappingURL=serialization.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../src/serialization.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAKL,KAAK,SAAS,EAGd,KAAK,GAAG,EACT,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAkCtD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,SAAS,GAAG,mBAAmB,CAcrE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,mBAAmB,GAAG,SAAS,CAcxE;AAED;;;;;GAKG;AACH,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CAEzD;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAE5D"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Serialization helpers for ChangeSet transport over JSON.
3
+ *
4
+ * - SiteIds use base64url encoding (via siteIdToBase64/siteIdFromBase64)
5
+ * - HLCs use standard base64 encoding (via btoa/atob in browser, Buffer in Node)
6
+ */
7
+ import { serializeHLC, deserializeHLC, siteIdToBase64, siteIdFromBase64, } from '@quereus/plugin-sync';
8
+ // ============================================================================
9
+ // Base64 helpers (work in both browser and Node.js)
10
+ // ============================================================================
11
+ /**
12
+ * Encode bytes to base64 string.
13
+ */
14
+ function bytesToBase64(bytes) {
15
+ // Browser: use btoa
16
+ if (typeof btoa === 'function') {
17
+ return btoa(String.fromCharCode(...bytes));
18
+ }
19
+ // Node.js: use Buffer
20
+ return Buffer.from(bytes).toString('base64');
21
+ }
22
+ /**
23
+ * Decode base64 string to bytes.
24
+ */
25
+ function base64ToBytes(str) {
26
+ // Browser: use atob
27
+ if (typeof atob === 'function') {
28
+ return Uint8Array.from(atob(str), c => c.charCodeAt(0));
29
+ }
30
+ // Node.js: use Buffer
31
+ return new Uint8Array(Buffer.from(str, 'base64'));
32
+ }
33
+ // ============================================================================
34
+ // ChangeSet Serialization
35
+ // ============================================================================
36
+ /**
37
+ * Serialize a ChangeSet for JSON transport.
38
+ *
39
+ * @param cs - The ChangeSet to serialize
40
+ * @returns A JSON-serializable object
41
+ */
42
+ export function serializeChangeSet(cs) {
43
+ return {
44
+ siteId: siteIdToBase64(cs.siteId),
45
+ transactionId: cs.transactionId,
46
+ hlc: bytesToBase64(serializeHLC(cs.hlc)),
47
+ changes: cs.changes.map(c => ({
48
+ ...c,
49
+ hlc: bytesToBase64(serializeHLC(c.hlc)),
50
+ })),
51
+ schemaMigrations: cs.schemaMigrations.map(m => ({
52
+ ...m,
53
+ hlc: bytesToBase64(serializeHLC(m.hlc)),
54
+ })),
55
+ };
56
+ }
57
+ /**
58
+ * Deserialize a ChangeSet from JSON transport format.
59
+ *
60
+ * @param obj - The serialized ChangeSet object
61
+ * @returns The deserialized ChangeSet
62
+ */
63
+ export function deserializeChangeSet(obj) {
64
+ return {
65
+ siteId: siteIdFromBase64(obj.siteId),
66
+ transactionId: obj.transactionId,
67
+ hlc: deserializeHLC(base64ToBytes(obj.hlc)),
68
+ changes: obj.changes.map(c => ({
69
+ ...c,
70
+ hlc: deserializeHLC(base64ToBytes(c.hlc)),
71
+ })),
72
+ schemaMigrations: obj.schemaMigrations.map(m => ({
73
+ ...m,
74
+ hlc: deserializeHLC(base64ToBytes(m.hlc)),
75
+ })),
76
+ };
77
+ }
78
+ /**
79
+ * Serialize an HLC for transport (base64 encoding).
80
+ *
81
+ * @param hlc - The HLC to serialize
82
+ * @returns Base64-encoded string
83
+ */
84
+ export function serializeHLCForTransport(hlc) {
85
+ return bytesToBase64(serializeHLC(hlc));
86
+ }
87
+ /**
88
+ * Deserialize an HLC from transport format.
89
+ *
90
+ * @param str - Base64-encoded HLC string
91
+ * @returns The deserialized HLC
92
+ */
93
+ export function deserializeHLCFromTransport(str) {
94
+ return deserializeHLC(base64ToBytes(str));
95
+ }
96
+ //# sourceMappingURL=serialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/serialization.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * SyncClient - WebSocket-based sync client for Quereus.
3
+ *
4
+ * Handles:
5
+ * - WebSocket connection and handshake
6
+ * - Message dispatch (changes, push_changes, apply_result, error, pong)
7
+ * - Reconnection with exponential backoff
8
+ * - Local change debouncing
9
+ * - Delta sync tracking (lastSentHLC, pendingSentHLC)
10
+ */
11
+ import type { SyncClientOptions, SyncStatus } from './types.js';
12
+ /**
13
+ * WebSocket sync client for Quereus.
14
+ *
15
+ * Connects to a sync server and handles bidirectional synchronization
16
+ * of changes with automatic reconnection and local change batching.
17
+ */
18
+ export declare class SyncClient {
19
+ private readonly syncManager;
20
+ private readonly syncEvents;
21
+ private readonly options;
22
+ private ws;
23
+ private serverSiteId;
24
+ private _status;
25
+ private connectionUrl;
26
+ private connectionToken;
27
+ private reconnectAttempts;
28
+ private reconnectTimer;
29
+ private intentionalDisconnect;
30
+ private lastSentHLC;
31
+ private pendingSentHLC;
32
+ private debounceTimer;
33
+ private pendingLocalChangeCount;
34
+ private localChangeUnsubscribe;
35
+ constructor(options: SyncClientOptions);
36
+ /** Current connection status */
37
+ get status(): SyncStatus;
38
+ /** Whether the client is connected and synced */
39
+ get isConnected(): boolean;
40
+ /** Whether the client is fully synced */
41
+ get isSynced(): boolean;
42
+ /**
43
+ * Connect to a sync server.
44
+ *
45
+ * @param url - WebSocket URL of the sync server
46
+ * @param token - Optional authentication token
47
+ * @returns Promise that resolves when connected (not yet synced)
48
+ */
49
+ connect(url: string, token?: string): Promise<void>;
50
+ /**
51
+ * Disconnect from the sync server.
52
+ * Stops reconnection attempts.
53
+ */
54
+ disconnect(): Promise<void>;
55
+ private handleMessage;
56
+ private handleHandshakeAck;
57
+ private handleChanges;
58
+ private handleApplyResult;
59
+ private sendHandshake;
60
+ private requestChangesFromServer;
61
+ private send;
62
+ private subscribeToLocalChanges;
63
+ private debouncePushLocalChanges;
64
+ private pushLocalChanges;
65
+ private scheduleReconnect;
66
+ private clearReconnectTimer;
67
+ private clearDebounceTimer;
68
+ private setStatus;
69
+ private emitSyncEvent;
70
+ }
71
+ //# sourceMappingURL=sync-client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-client.d.ts","sourceRoot":"","sources":["../../src/sync-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAaH,OAAO,KAAK,EACV,iBAAiB,EACjB,UAAU,EAGX,MAAM,YAAY,CAAC;AAapB;;;;;GAKG;AACH,qBAAa,UAAU;IACrB,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAc;IAC1C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAmB;IAC9C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAED;IAGvB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,YAAY,CAAuB;IAG3C,OAAO,CAAC,OAAO,CAA0C;IACzD,OAAO,CAAC,aAAa,CAAuB;IAC5C,OAAO,CAAC,eAAe,CAAiC;IAGxD,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,qBAAqB,CAAS;IAGtC,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,cAAc,CAAoB;IAG1C,OAAO,CAAC,aAAa,CAA8C;IACnE,OAAO,CAAC,uBAAuB,CAAK;IAGpC,OAAO,CAAC,sBAAsB,CAA6B;gBAE/C,OAAO,EAAE,iBAAiB;IAYtC,gCAAgC;IAChC,IAAI,MAAM,IAAI,UAAU,CAEvB;IAED,iDAAiD;IACjD,IAAI,WAAW,IAAI,OAAO,CAEzB;IAED,yCAAyC;IACzC,IAAI,QAAQ,IAAI,OAAO,CAEtB;IAED;;;;;;OAMG;IACG,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4DzD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YA8BnB,aAAa;YA+Bb,kBAAkB;YAiBlB,aAAa;IAgC3B,OAAO,CAAC,iBAAiB;IAazB,OAAO,CAAC,aAAa;YASP,wBAAwB;IAatC,OAAO,CAAC,IAAI;IAWZ,OAAO,CAAC,uBAAuB;IAa/B,OAAO,CAAC,wBAAwB;YASlB,gBAAgB;IAuC9B,OAAO,CAAC,iBAAiB;IA0BzB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,aAAa;CAatB"}
@@ -0,0 +1,342 @@
1
+ /**
2
+ * SyncClient - WebSocket-based sync client for Quereus.
3
+ *
4
+ * Handles:
5
+ * - WebSocket connection and handshake
6
+ * - Message dispatch (changes, push_changes, apply_result, error, pong)
7
+ * - Reconnection with exponential backoff
8
+ * - Local change debouncing
9
+ * - Delta sync tracking (lastSentHLC, pendingSentHLC)
10
+ */
11
+ import { siteIdToBase64, siteIdFromBase64, compareHLC, } from '@quereus/plugin-sync';
12
+ import { serializeChangeSet, deserializeChangeSet, serializeHLCForTransport, } from './serialization.js';
13
+ // Default configuration values
14
+ const DEFAULT_RECONNECT_DELAY_MS = 1000;
15
+ const DEFAULT_MAX_RECONNECT_DELAY_MS = 60_000;
16
+ const DEFAULT_LOCAL_CHANGE_DEBOUNCE_MS = 50;
17
+ /**
18
+ * WebSocket sync client for Quereus.
19
+ *
20
+ * Connects to a sync server and handles bidirectional synchronization
21
+ * of changes with automatic reconnection and local change batching.
22
+ */
23
+ export class SyncClient {
24
+ syncManager;
25
+ syncEvents;
26
+ options;
27
+ // WebSocket state
28
+ ws = null;
29
+ serverSiteId = null;
30
+ // Connection state
31
+ _status = { status: 'disconnected' };
32
+ connectionUrl = null;
33
+ connectionToken = undefined;
34
+ // Reconnection state
35
+ reconnectAttempts = 0;
36
+ reconnectTimer = null;
37
+ intentionalDisconnect = false;
38
+ // Delta sync tracking
39
+ lastSentHLC = null;
40
+ pendingSentHLC = null;
41
+ // Local change debouncing
42
+ debounceTimer = null;
43
+ pendingLocalChangeCount = 0;
44
+ // Local change listener cleanup
45
+ localChangeUnsubscribe = null;
46
+ constructor(options) {
47
+ this.syncManager = options.syncManager;
48
+ this.syncEvents = options.syncEvents;
49
+ this.options = {
50
+ ...options,
51
+ autoReconnect: options.autoReconnect ?? true,
52
+ reconnectDelayMs: options.reconnectDelayMs ?? DEFAULT_RECONNECT_DELAY_MS,
53
+ maxReconnectDelayMs: options.maxReconnectDelayMs ?? DEFAULT_MAX_RECONNECT_DELAY_MS,
54
+ localChangeDebounceMs: options.localChangeDebounceMs ?? DEFAULT_LOCAL_CHANGE_DEBOUNCE_MS,
55
+ };
56
+ }
57
+ /** Current connection status */
58
+ get status() {
59
+ return this._status;
60
+ }
61
+ /** Whether the client is connected and synced */
62
+ get isConnected() {
63
+ return this.ws?.readyState === WebSocket.OPEN;
64
+ }
65
+ /** Whether the client is fully synced */
66
+ get isSynced() {
67
+ return this._status.status === 'synced';
68
+ }
69
+ /**
70
+ * Connect to a sync server.
71
+ *
72
+ * @param url - WebSocket URL of the sync server
73
+ * @param token - Optional authentication token
74
+ * @returns Promise that resolves when connected (not yet synced)
75
+ */
76
+ async connect(url, token) {
77
+ // Store connection params for reconnection
78
+ this.connectionUrl = url;
79
+ this.connectionToken = token;
80
+ this.intentionalDisconnect = false;
81
+ // Clear any pending reconnect timer
82
+ this.clearReconnectTimer();
83
+ // Close existing connection
84
+ if (this.ws) {
85
+ this.ws.close();
86
+ this.ws = null;
87
+ }
88
+ this.setStatus({ status: 'connecting' });
89
+ return new Promise((resolve, reject) => {
90
+ try {
91
+ const wsUrl = token ? `${url}?token=${encodeURIComponent(token)}` : url;
92
+ this.ws = new WebSocket(wsUrl);
93
+ this.ws.onopen = () => {
94
+ this.reconnectAttempts = 0;
95
+ this.sendHandshake(token);
96
+ this.setStatus({ status: 'syncing', progress: 0 });
97
+ this.emitSyncEvent('state-change', 'Connected to sync server, handshake sent');
98
+ resolve();
99
+ };
100
+ this.ws.onclose = () => {
101
+ this.setStatus({ status: 'disconnected' });
102
+ this.emitSyncEvent('state-change', 'Disconnected from sync server');
103
+ this.scheduleReconnect();
104
+ };
105
+ this.ws.onerror = () => {
106
+ const error = new Error('WebSocket connection failed');
107
+ this.setStatus({ status: 'error', message: error.message });
108
+ this.emitSyncEvent('error', error.message);
109
+ // Only reject on first attempt
110
+ if (this.reconnectAttempts === 0) {
111
+ reject(error);
112
+ }
113
+ };
114
+ this.ws.onmessage = (event) => {
115
+ this.handleMessage(event.data).catch(err => {
116
+ console.error('Error handling sync message:', err);
117
+ this.emitSyncEvent('error', `Sync error: ${err instanceof Error ? err.message : 'Unknown'}`);
118
+ });
119
+ };
120
+ }
121
+ catch (error) {
122
+ const msg = error instanceof Error ? error.message : 'Connection failed';
123
+ this.setStatus({ status: 'error', message: msg });
124
+ reject(error);
125
+ }
126
+ });
127
+ }
128
+ /**
129
+ * Disconnect from the sync server.
130
+ * Stops reconnection attempts.
131
+ */
132
+ async disconnect() {
133
+ this.intentionalDisconnect = true;
134
+ // Clear timers
135
+ this.clearReconnectTimer();
136
+ this.clearDebounceTimer();
137
+ // Remove local change listener
138
+ if (this.localChangeUnsubscribe) {
139
+ this.localChangeUnsubscribe();
140
+ this.localChangeUnsubscribe = null;
141
+ }
142
+ // Close WebSocket
143
+ if (this.ws) {
144
+ this.ws.close();
145
+ this.ws = null;
146
+ }
147
+ this.serverSiteId = null;
148
+ this.lastSentHLC = null;
149
+ this.pendingSentHLC = null;
150
+ this.setStatus({ status: 'disconnected' });
151
+ this.emitSyncEvent('state-change', 'Disconnected from sync server (manual)');
152
+ }
153
+ // ==========================================================================
154
+ // Private: Message Handlers
155
+ // ==========================================================================
156
+ async handleMessage(data) {
157
+ const message = JSON.parse(data);
158
+ switch (message.type) {
159
+ case 'handshake_ack':
160
+ await this.handleHandshakeAck(message);
161
+ break;
162
+ case 'changes':
163
+ case 'push_changes':
164
+ await this.handleChanges(message.changeSets || []);
165
+ break;
166
+ case 'apply_result':
167
+ this.handleApplyResult(message);
168
+ break;
169
+ case 'error':
170
+ this.emitSyncEvent('error', `Server error: ${message.message} (${message.code})`);
171
+ this.options.onError?.(new Error(message.message));
172
+ break;
173
+ case 'pong':
174
+ // Heartbeat response - no action needed
175
+ break;
176
+ default:
177
+ console.warn('Unknown sync message type:', message.type);
178
+ }
179
+ }
180
+ async handleHandshakeAck(message) {
181
+ if (message.serverSiteId) {
182
+ this.serverSiteId = siteIdFromBase64(message.serverSiteId);
183
+ }
184
+ this.emitSyncEvent('state-change', `Authenticated with server (connection: ${message.connectionId?.slice(0, 8) ?? 'unknown'})`);
185
+ // Request changes from server since our last sync with this peer
186
+ await this.requestChangesFromServer();
187
+ // Subscribe to local changes for pushing to server
188
+ this.subscribeToLocalChanges();
189
+ }
190
+ async handleChanges(serializedChangeSets) {
191
+ const changeSets = serializedChangeSets.map(cs => deserializeChangeSet(cs));
192
+ const result = await this.syncManager.applyChanges(changeSets);
193
+ // Update peer sync state with the max HLC from received changes
194
+ if (changeSets.length > 0 && this.serverSiteId) {
195
+ let maxHLC;
196
+ for (const cs of changeSets) {
197
+ if (!maxHLC || compareHLC(cs.hlc, maxHLC) > 0) {
198
+ maxHLC = cs.hlc;
199
+ }
200
+ }
201
+ if (maxHLC) {
202
+ await this.syncManager.updatePeerSyncState(this.serverSiteId, maxHLC);
203
+ }
204
+ }
205
+ // Emit events
206
+ if (result.applied > 0 || result.conflicts > 0 || result.skipped > 0) {
207
+ const conflictText = result.conflicts > 0 ? ` (${result.conflicts} conflicts resolved)` : '';
208
+ const skippedText = result.skipped > 0 ? `, ${result.skipped} skipped` : '';
209
+ this.emitSyncEvent('remote-change', `Applied ${result.applied} column changes${conflictText}${skippedText}`, { changeCount: result.applied, conflicts: result.conflicts, skipped: result.skipped });
210
+ }
211
+ this.options.onRemoteChanges?.(result, changeSets);
212
+ this.setStatus({ status: 'synced', lastSyncTime: Date.now() });
213
+ }
214
+ handleApplyResult(message) {
215
+ // Update lastSentHLC to enable delta sync on next send
216
+ if (this.pendingSentHLC) {
217
+ this.lastSentHLC = this.pendingSentHLC;
218
+ this.pendingSentHLC = null;
219
+ }
220
+ this.emitSyncEvent('info', `Server applied ${message.applied ?? 0} change(s)`);
221
+ }
222
+ // ==========================================================================
223
+ // Private: Message Sending
224
+ // ==========================================================================
225
+ sendHandshake(token) {
226
+ const siteId = this.syncManager.getSiteId();
227
+ this.send({
228
+ type: 'handshake',
229
+ siteId: siteIdToBase64(siteId),
230
+ token,
231
+ });
232
+ }
233
+ async requestChangesFromServer() {
234
+ if (!this.serverSiteId)
235
+ return;
236
+ const lastSyncHLC = await this.syncManager.getPeerSyncState(this.serverSiteId);
237
+ const msg = { type: 'get_changes' };
238
+ if (lastSyncHLC) {
239
+ msg.sinceHLC = serializeHLCForTransport(lastSyncHLC);
240
+ }
241
+ this.send(msg);
242
+ }
243
+ send(message) {
244
+ if (this.ws?.readyState === WebSocket.OPEN) {
245
+ this.ws.send(JSON.stringify(message));
246
+ }
247
+ }
248
+ // ==========================================================================
249
+ // Private: Local Change Handling
250
+ // ==========================================================================
251
+ subscribeToLocalChanges() {
252
+ // Unsubscribe from previous if any
253
+ if (this.localChangeUnsubscribe) {
254
+ this.localChangeUnsubscribe();
255
+ }
256
+ // Subscribe to local changes via SyncEventEmitter
257
+ this.localChangeUnsubscribe = this.syncEvents.onLocalChange(() => {
258
+ this.pendingLocalChangeCount++;
259
+ this.debouncePushLocalChanges();
260
+ });
261
+ }
262
+ debouncePushLocalChanges() {
263
+ this.clearDebounceTimer();
264
+ this.debounceTimer = setTimeout(async () => {
265
+ this.debounceTimer = null;
266
+ await this.pushLocalChanges();
267
+ }, this.options.localChangeDebounceMs);
268
+ }
269
+ async pushLocalChanges() {
270
+ if (!this.isConnected)
271
+ return;
272
+ // Get changes since lastSentHLC (delta sync)
273
+ const changes = await this.syncManager.getChangesSince(this.syncManager.getSiteId(), this.lastSentHLC ?? undefined);
274
+ if (changes.length === 0)
275
+ return;
276
+ // Track the max HLC we're sending for delta sync
277
+ let maxHLC;
278
+ for (const cs of changes) {
279
+ if (!maxHLC || compareHLC(cs.hlc, maxHLC) > 0) {
280
+ maxHLC = cs.hlc;
281
+ }
282
+ }
283
+ this.pendingSentHLC = maxHLC ?? null;
284
+ // Serialize and send
285
+ const serialized = changes.map(cs => serializeChangeSet(cs));
286
+ this.emitSyncEvent('local-change', `Sending ${changes.length} change set(s) to server`, {
287
+ changeCount: changes.length,
288
+ });
289
+ this.send({
290
+ type: 'apply_changes',
291
+ changes: serialized,
292
+ });
293
+ this.pendingLocalChangeCount = 0;
294
+ }
295
+ // ==========================================================================
296
+ // Private: Reconnection
297
+ // ==========================================================================
298
+ scheduleReconnect() {
299
+ if (this.intentionalDisconnect || !this.connectionUrl || !this.options.autoReconnect) {
300
+ return;
301
+ }
302
+ // Exponential backoff: 1s, 2s, 4s, 8s, ... up to max
303
+ const delay = Math.min(this.options.reconnectDelayMs * Math.pow(2, this.reconnectAttempts), this.options.maxReconnectDelayMs);
304
+ this.reconnectAttempts++;
305
+ this.emitSyncEvent('state-change', `Reconnecting in ${Math.round(delay / 1000)}s (attempt ${this.reconnectAttempts})`);
306
+ this.reconnectTimer = setTimeout(() => {
307
+ this.reconnectTimer = null;
308
+ this.connect(this.connectionUrl, this.connectionToken).catch(() => {
309
+ // Error already handled in connect, reconnect will be scheduled by onclose
310
+ });
311
+ }, delay);
312
+ }
313
+ clearReconnectTimer() {
314
+ if (this.reconnectTimer) {
315
+ clearTimeout(this.reconnectTimer);
316
+ this.reconnectTimer = null;
317
+ }
318
+ }
319
+ clearDebounceTimer() {
320
+ if (this.debounceTimer) {
321
+ clearTimeout(this.debounceTimer);
322
+ this.debounceTimer = null;
323
+ }
324
+ }
325
+ // ==========================================================================
326
+ // Private: Status & Events
327
+ // ==========================================================================
328
+ setStatus(status) {
329
+ this._status = status;
330
+ this.options.onStatusChange?.(status);
331
+ }
332
+ emitSyncEvent(type, message, details) {
333
+ const event = {
334
+ type,
335
+ timestamp: Date.now(),
336
+ message,
337
+ details,
338
+ };
339
+ this.options.onSyncEvent?.(event);
340
+ }
341
+ }
342
+ //# sourceMappingURL=sync-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sync-client.js","sourceRoot":"","sources":["../../src/sync-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ /**
2
+ * Types for the WebSocket sync client.
3
+ */
4
+ import type { ApplyResult, ChangeSet, SyncManager, SyncEventEmitter } from '@quereus/plugin-sync';
5
+ /**
6
+ * Sync connection status.
7
+ */
8
+ export type SyncStatus = {
9
+ status: 'disconnected';
10
+ } | {
11
+ status: 'connecting';
12
+ } | {
13
+ status: 'syncing';
14
+ progress: number;
15
+ } | {
16
+ status: 'synced';
17
+ lastSyncTime: number;
18
+ } | {
19
+ status: 'error';
20
+ message: string;
21
+ };
22
+ /**
23
+ * Sync event types for logging/UI notifications.
24
+ */
25
+ export type SyncEventType = 'remote-change' | 'local-change' | 'conflict' | 'state-change' | 'error' | 'info';
26
+ /**
27
+ * Sync event for logging/UI display.
28
+ */
29
+ export interface SyncEvent {
30
+ type: SyncEventType;
31
+ timestamp: number;
32
+ message: string;
33
+ details?: {
34
+ table?: string;
35
+ changeCount?: number;
36
+ conflicts?: number;
37
+ skipped?: number;
38
+ };
39
+ }
40
+ /**
41
+ * Options for configuring the SyncClient.
42
+ */
43
+ export interface SyncClientOptions {
44
+ /**
45
+ * The SyncManager instance to use for sync operations.
46
+ */
47
+ syncManager: SyncManager;
48
+ /**
49
+ * The SyncEventEmitter to subscribe to local change events.
50
+ * Required for automatic pushing of local changes to the server.
51
+ */
52
+ syncEvents: SyncEventEmitter;
53
+ /**
54
+ * Callback when connection status changes.
55
+ */
56
+ onStatusChange?: (status: SyncStatus) => void;
57
+ /**
58
+ * Callback when remote changes are applied.
59
+ */
60
+ onRemoteChanges?: (result: ApplyResult, changeSets: ChangeSet[]) => void;
61
+ /**
62
+ * Callback when a sync event occurs (for logging/UI).
63
+ */
64
+ onSyncEvent?: (event: SyncEvent) => void;
65
+ /**
66
+ * Callback when an error occurs.
67
+ */
68
+ onError?: (error: Error) => void;
69
+ /**
70
+ * Whether to automatically reconnect on disconnect.
71
+ * @default true
72
+ */
73
+ autoReconnect?: boolean;
74
+ /**
75
+ * Initial delay for reconnection (milliseconds).
76
+ * @default 1000
77
+ */
78
+ reconnectDelayMs?: number;
79
+ /**
80
+ * Maximum delay for reconnection (milliseconds).
81
+ * @default 60000
82
+ */
83
+ maxReconnectDelayMs?: number;
84
+ /**
85
+ * Debounce delay for batching local changes (milliseconds).
86
+ * @default 50
87
+ */
88
+ localChangeDebounceMs?: number;
89
+ }
90
+ /** Client → Server: Handshake */
91
+ export interface HandshakeMessage {
92
+ type: 'handshake';
93
+ siteId: string;
94
+ token?: string;
95
+ }
96
+ /** Client → Server: Request changes */
97
+ export interface GetChangesMessage {
98
+ type: 'get_changes';
99
+ sinceHLC?: string;
100
+ }
101
+ /** Client → Server: Apply local changes */
102
+ export interface ApplyChangesMessage {
103
+ type: 'apply_changes';
104
+ changes: SerializedChangeSet[];
105
+ }
106
+ /** Client → Server: Request snapshot */
107
+ export interface GetSnapshotMessage {
108
+ type: 'get_snapshot';
109
+ }
110
+ /** Client → Server: Heartbeat */
111
+ export interface PingMessage {
112
+ type: 'ping';
113
+ }
114
+ export type ClientMessage = HandshakeMessage | GetChangesMessage | ApplyChangesMessage | GetSnapshotMessage | PingMessage;
115
+ /** Server → Client: Handshake acknowledgment */
116
+ export interface HandshakeAckMessage {
117
+ type: 'handshake_ack';
118
+ serverSiteId: string;
119
+ connectionId?: string;
120
+ }
121
+ /** Server → Client: Changes response */
122
+ export interface ChangesMessage {
123
+ type: 'changes';
124
+ changeSets: SerializedChangeSet[];
125
+ }
126
+ /** Server → Client: Pushed changes from another peer */
127
+ export interface PushChangesMessage {
128
+ type: 'push_changes';
129
+ changeSets: SerializedChangeSet[];
130
+ }
131
+ /** Server → Client: Apply result */
132
+ export interface ApplyResultMessage {
133
+ type: 'apply_result';
134
+ applied: number;
135
+ skipped: number;
136
+ conflicts: number;
137
+ transactions: number;
138
+ }
139
+ /** Server → Client: Error */
140
+ export interface ErrorMessage {
141
+ type: 'error';
142
+ code: string;
143
+ message: string;
144
+ }
145
+ /** Server → Client: Heartbeat response */
146
+ export interface PongMessage {
147
+ type: 'pong';
148
+ }
149
+ export type ServerMessage = HandshakeAckMessage | ChangesMessage | PushChangesMessage | ApplyResultMessage | ErrorMessage | PongMessage;
150
+ /**
151
+ * A ChangeSet serialized for JSON transport.
152
+ * SiteIds are base64url-encoded, HLCs are base64-encoded.
153
+ */
154
+ export interface SerializedChangeSet {
155
+ siteId: string;
156
+ transactionId: string;
157
+ hlc: string;
158
+ changes: SerializedChange[];
159
+ schemaMigrations: SerializedSchemaMigration[];
160
+ }
161
+ export interface SerializedChange {
162
+ type: 'column' | 'delete';
163
+ schema: string;
164
+ table: string;
165
+ pk: unknown[];
166
+ column?: string;
167
+ value?: unknown;
168
+ hlc: string;
169
+ }
170
+ export interface SerializedSchemaMigration {
171
+ type: string;
172
+ schema: string;
173
+ table: string;
174
+ ddl: string;
175
+ hlc: string;
176
+ schemaVersion: number;
177
+ }
178
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Types for the WebSocket sync client.
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG"}
package/package.json ADDED
@@ -0,0 +1,59 @@
1
+ {
2
+ "name": "@quereus/sync-client",
3
+ "version": "0.1.1",
4
+ "type": "module",
5
+ "description": "WebSocket sync client for Quereus - handles connection, reconnection, and change synchronization",
6
+ "keywords": [
7
+ "quereus",
8
+ "sync",
9
+ "websocket",
10
+ "crdt",
11
+ "replication",
12
+ "offline-first",
13
+ "client"
14
+ ],
15
+ "publisher": "Got Choices Foundation",
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "https://github.com/gotchoices/quereus.git",
19
+ "directory": "packages/quereus-sync-client"
20
+ },
21
+ "license": "MIT",
22
+ "main": "dist/src/index.js",
23
+ "types": "./dist/src/index.d.ts",
24
+ "files": [
25
+ "dist",
26
+ "!**/*.tsbuildinfo"
27
+ ],
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/src/index.d.ts",
31
+ "import": "./dist/src/index.js"
32
+ }
33
+ },
34
+ "scripts": {
35
+ "clean": "rimraf dist",
36
+ "build": "tsc",
37
+ "typecheck": "tsc --noEmit",
38
+ "test": "cd ../.. && node --import ./packages/quereus-sync-client/register.mjs node_modules/mocha/bin/mocha.js \"packages/quereus-sync-client/test/**/*.spec.ts\" --colors",
39
+ "test:single": "cd ../.. && node --import ./packages/quereus-sync-client/register.mjs node_modules/mocha/bin/mocha.js --bail"
40
+ },
41
+ "peerDependencies": {
42
+ "@quereus/plugin-sync": "*"
43
+ },
44
+ "devDependencies": {
45
+ "@quereus/plugin-sync": "*",
46
+ "@types/mocha": "^10.0.10",
47
+ "@types/node": "^22.15.29",
48
+ "chai": "^5.2.0",
49
+ "mocha": "^11.5.0",
50
+ "rimraf": "^6.1.2",
51
+ "ts-node": "^10.9.2",
52
+ "typescript": "^5.8.3"
53
+ },
54
+ "quereus": {
55
+ "provides": {
56
+ "sync-client": true
57
+ }
58
+ }
59
+ }