@syncular/client 0.0.6-135 → 0.0.6-138
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/dist/client.d.ts +24 -4
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +18 -20
- package/dist/client.js.map +1 -1
- package/dist/create-client.d.ts +17 -0
- package/dist/create-client.d.ts.map +1 -1
- package/dist/create-client.js +3 -0
- package/dist/create-client.js.map +1 -1
- package/dist/engine/SyncEngine.d.ts +15 -0
- package/dist/engine/SyncEngine.d.ts.map +1 -1
- package/dist/engine/SyncEngine.js +255 -32
- package/dist/engine/SyncEngine.js.map +1 -1
- package/dist/engine/types.d.ts +35 -1
- package/dist/engine/types.d.ts.map +1 -1
- package/dist/handlers/types.d.ts +9 -0
- package/dist/handlers/types.d.ts.map +1 -1
- package/dist/pull-engine.d.ts.map +1 -1
- package/dist/pull-engine.js +9 -1
- package/dist/pull-engine.js.map +1 -1
- package/dist/push-engine.d.ts +2 -0
- package/dist/push-engine.d.ts.map +1 -1
- package/dist/push-engine.js +52 -3
- package/dist/push-engine.js.map +1 -1
- package/dist/query/fingerprint.d.ts +1 -1
- package/dist/query/fingerprint.d.ts.map +1 -1
- package/dist/query/fingerprint.js +29 -6
- package/dist/query/fingerprint.js.map +1 -1
- package/dist/sync-loop.d.ts +2 -0
- package/dist/sync-loop.d.ts.map +1 -1
- package/dist/sync-loop.js +48 -2
- package/dist/sync-loop.js.map +1 -1
- package/package.json +3 -3
- package/src/client.test.ts +43 -6
- package/src/client.ts +47 -23
- package/src/create-client.ts +21 -0
- package/src/engine/SyncEngine.test.ts +257 -0
- package/src/engine/SyncEngine.ts +318 -32
- package/src/engine/types.ts +38 -0
- package/src/handlers/types.ts +9 -0
- package/src/pull-engine.test.ts +94 -0
- package/src/pull-engine.ts +12 -1
- package/src/push-engine.ts +67 -3
- package/src/query/fingerprint.test.ts +73 -0
- package/src/query/fingerprint.ts +33 -6
- package/src/sync-loop.ts +70 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-engine.d.ts","sourceRoot":"","sources":["../src/push-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EAChB,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"push-engine.d.ts","sourceRoot":"","sources":["../src/push-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EAChB,aAAa,EACd,MAAM,gBAAgB,CAAC;AAExB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAOrD,OAAO,KAAK,EACV,gBAAgB,EAEjB,MAAM,iBAAiB,CAAC;AACzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,gBAAgB,EAAE,CAAC;CAC9B;AAED,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;IAC5B,UAAU,CAAC,EAAE,cAAc,CAAC;CAC7B;AAoDD,wBAAsB,YAAY,CAAC,EAAE,SAAS,YAAY,EACxD,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EACd,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,kBAAkB,CAAC,CA4L7B"}
|
package/dist/push-engine.js
CHANGED
|
@@ -12,6 +12,28 @@ function clonePushRequest(request) {
|
|
|
12
12
|
return structuredClone(request);
|
|
13
13
|
return JSON.parse(JSON.stringify(request));
|
|
14
14
|
}
|
|
15
|
+
function firstPushErrorCode(response) {
|
|
16
|
+
const firstError = response.results.find((result) => result.status === 'error');
|
|
17
|
+
if (firstError &&
|
|
18
|
+
'code' in firstError &&
|
|
19
|
+
typeof firstError.code === 'string' &&
|
|
20
|
+
firstError.code) {
|
|
21
|
+
return firstError.code;
|
|
22
|
+
}
|
|
23
|
+
const hasConflict = response.results.some((result) => result.status === 'conflict');
|
|
24
|
+
return hasConflict ? 'CONFLICT' : null;
|
|
25
|
+
}
|
|
26
|
+
function buildPushResult(args) {
|
|
27
|
+
return {
|
|
28
|
+
outboxCommitId: args.outboxCommitId,
|
|
29
|
+
clientCommitId: args.clientCommitId,
|
|
30
|
+
status: args.status,
|
|
31
|
+
commitSeq: args.response.commitSeq ?? null,
|
|
32
|
+
results: args.response.results,
|
|
33
|
+
errorCode: firstPushErrorCode(args.response),
|
|
34
|
+
timestamp: Date.now(),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
15
37
|
export async function syncPushOnce(db, transport, options) {
|
|
16
38
|
// getNextSendableOutboxCommit now atomically claims the commit
|
|
17
39
|
// (marks it as 'sending' and returns it in one operation)
|
|
@@ -134,7 +156,16 @@ export async function syncPushOnce(db, transport, options) {
|
|
|
134
156
|
commitSeq: responseToUse.commitSeq ?? null,
|
|
135
157
|
responseJson,
|
|
136
158
|
});
|
|
137
|
-
return {
|
|
159
|
+
return {
|
|
160
|
+
pushed: true,
|
|
161
|
+
response: responseToUse,
|
|
162
|
+
pushResult: buildPushResult({
|
|
163
|
+
outboxCommitId: next.id,
|
|
164
|
+
clientCommitId: next.client_commit_id,
|
|
165
|
+
status: responseToUse.status,
|
|
166
|
+
response: responseToUse,
|
|
167
|
+
}),
|
|
168
|
+
};
|
|
138
169
|
}
|
|
139
170
|
// Check if all errors are retriable - if so, keep pending for retry
|
|
140
171
|
const errorResults = responseToUse.results.filter((r) => r.status === 'error');
|
|
@@ -149,7 +180,16 @@ export async function syncPushOnce(db, transport, options) {
|
|
|
149
180
|
error: `Retriable: ${errorMessages}`,
|
|
150
181
|
responseJson,
|
|
151
182
|
});
|
|
152
|
-
return {
|
|
183
|
+
return {
|
|
184
|
+
pushed: true,
|
|
185
|
+
response: responseToUse,
|
|
186
|
+
pushResult: buildPushResult({
|
|
187
|
+
outboxCommitId: next.id,
|
|
188
|
+
clientCommitId: next.client_commit_id,
|
|
189
|
+
status: 'retriable',
|
|
190
|
+
response: responseToUse,
|
|
191
|
+
}),
|
|
192
|
+
};
|
|
153
193
|
}
|
|
154
194
|
// Terminal rejection - mark as failed and record conflicts
|
|
155
195
|
await upsertConflictsForRejectedCommit(db, {
|
|
@@ -162,6 +202,15 @@ export async function syncPushOnce(db, transport, options) {
|
|
|
162
202
|
error: 'REJECTED',
|
|
163
203
|
responseJson,
|
|
164
204
|
});
|
|
165
|
-
return {
|
|
205
|
+
return {
|
|
206
|
+
pushed: true,
|
|
207
|
+
response: responseToUse,
|
|
208
|
+
pushResult: buildPushResult({
|
|
209
|
+
outboxCommitId: next.id,
|
|
210
|
+
clientCommitId: next.client_commit_id,
|
|
211
|
+
status: 'rejected',
|
|
212
|
+
response: responseToUse,
|
|
213
|
+
}),
|
|
214
|
+
};
|
|
166
215
|
}
|
|
167
216
|
//# sourceMappingURL=push-engine.js.map
|
package/dist/push-engine.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"push-engine.js","sourceRoot":"","sources":["../src/push-engine.ts"],"names":[],"mappings":"AAAA;;GAEG;AAOH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"push-engine.js","sourceRoot":"","sources":["../src/push-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -46,7 +46,7 @@ export declare function computeFingerprint<T extends Record<string, unknown>>(ro
|
|
|
46
46
|
export declare function canFingerprint<T>(rows: T[], keyField?: string): boolean;
|
|
47
47
|
/**
|
|
48
48
|
* Compute row-level fingerprint from query results.
|
|
49
|
-
* Format: `table:count:
|
|
49
|
+
* Format: `table:count:hash`
|
|
50
50
|
*/
|
|
51
51
|
export declare function computeRowFingerprint(rows: unknown[], table: string, engine: MutationTimestampSource, keyField: string): string;
|
|
52
52
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/query/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5D;
|
|
1
|
+
{"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/query/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,WAAW,uBAAuB;IACtC,oBAAoB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;CAC5D;AA4BD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClE,IAAI,EAAE,CAAC,EAAE,EACT,MAAM,EAAE,uBAAuB,EAC/B,KAAK,EAAE,MAAM,EACb,QAAQ,SAAO,GACd,MAAM,CAWR;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,QAAQ,SAAO,GAAG,OAAO,CAGrE;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,OAAO,EAAE,EACf,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,uBAAuB,EAC/B,QAAQ,EAAE,MAAM,GACf,MAAM,CAaR;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,MAAM,CAI7E;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGtE"}
|
|
@@ -4,6 +4,28 @@
|
|
|
4
4
|
* Provides efficient fingerprint computation for query results to avoid
|
|
5
5
|
* expensive deep equality checks. Uses mutation timestamps from the SyncEngine.
|
|
6
6
|
*/
|
|
7
|
+
const FNV_OFFSET_BASIS = 0x811c9dc5;
|
|
8
|
+
const FNV_PRIME = 0x01000193;
|
|
9
|
+
function hashMix(hash, value) {
|
|
10
|
+
return Math.imul(hash ^ value, FNV_PRIME) >>> 0;
|
|
11
|
+
}
|
|
12
|
+
function hashString(hash, value) {
|
|
13
|
+
let next = hash;
|
|
14
|
+
for (let i = 0; i < value.length; i++) {
|
|
15
|
+
next = hashMix(next, value.charCodeAt(i));
|
|
16
|
+
}
|
|
17
|
+
return next;
|
|
18
|
+
}
|
|
19
|
+
function hashTimestamp(hash, value) {
|
|
20
|
+
if (!Number.isFinite(value)) {
|
|
21
|
+
return hashMix(hash, 0);
|
|
22
|
+
}
|
|
23
|
+
// Keep three decimal places to preserve sub-millisecond precision.
|
|
24
|
+
const scaled = Math.round(value * 1000);
|
|
25
|
+
const lowBits = scaled >>> 0;
|
|
26
|
+
const highBits = Math.floor(scaled / 0x1_0000_0000) >>> 0;
|
|
27
|
+
return hashMix(hashMix(hash, lowBits), highBits);
|
|
28
|
+
}
|
|
7
29
|
/**
|
|
8
30
|
* Compute a fingerprint for query results based on length + ids + mutation timestamps.
|
|
9
31
|
* Much faster than deep equality for large datasets.
|
|
@@ -57,19 +79,20 @@ export function canFingerprint(rows, keyField = 'id') {
|
|
|
57
79
|
}
|
|
58
80
|
/**
|
|
59
81
|
* Compute row-level fingerprint from query results.
|
|
60
|
-
* Format: `table:count:
|
|
82
|
+
* Format: `table:count:hash`
|
|
61
83
|
*/
|
|
62
84
|
export function computeRowFingerprint(rows, table, engine, keyField) {
|
|
63
|
-
|
|
64
|
-
return `${table}:0:`;
|
|
65
|
-
const parts = [];
|
|
85
|
+
let hash = hashMix(FNV_OFFSET_BASIS, rows.length);
|
|
66
86
|
for (const row of rows) {
|
|
67
87
|
const r = row;
|
|
68
88
|
const id = String(r[keyField] ?? '');
|
|
69
89
|
const ts = engine.getMutationTimestamp(table, id);
|
|
70
|
-
|
|
90
|
+
hash = hashString(hash, id);
|
|
91
|
+
hash = hashMix(hash, 0); // separator
|
|
92
|
+
hash = hashTimestamp(hash, ts);
|
|
93
|
+
hash = hashMix(hash, 1); // separator
|
|
71
94
|
}
|
|
72
|
-
return `${table}:${rows.length}:${
|
|
95
|
+
return `${table}:${rows.length}:${hash.toString(16).padStart(8, '0')}`;
|
|
73
96
|
}
|
|
74
97
|
/**
|
|
75
98
|
* Compute value-based fingerprint for aggregate/scalar queries.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/query/fingerprint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,kBAAkB,CAChC,IAAS,EACT,MAA+B,EAC/B,KAAa,EACb,QAAQ,GAAG,IAAI,EACP;IACR,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;QACvC,MAAM,EAAE,GAAG,MAAM,CAAC,oBAAoB,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAClD,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,GAAG,IAAI,CAAC,MAAM,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;AAAA,CAC5C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,cAAc,CAAI,IAAS,EAAE,QAAQ,GAAG,IAAI,EAAW;IACrE,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACnC,OAAO,QAAQ,IAAK,IAAI,CAAC,CAAC,CAA6B,CAAC;AAAA,CACzD;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,IAAe,EACf,KAAa,EACb,MAA+B,EAC/B,QAAgB,EACR;IACR,IAAI,IAAI,
|
|
1
|
+
{"version":3,"file":"fingerprint.js","sourceRoot":"","sources":["../../src/query/fingerprint.ts"],"names":[],"mappings":"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"}
|
package/dist/sync-loop.d.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { SyncPullResponse, SyncSubscriptionRequest, SyncTransport } from '@syncular/core';
|
|
7
7
|
import type { Kysely } from 'kysely';
|
|
8
|
+
import type { PushResultInfo } from './engine/types';
|
|
8
9
|
import type { ClientHandlerCollection } from './handlers/collection';
|
|
9
10
|
import { type SyncPushOnceOptions } from './push-engine';
|
|
10
11
|
import type { SyncClientDb } from './schema';
|
|
@@ -29,6 +30,7 @@ export interface SyncOnceResult {
|
|
|
29
30
|
pushedCommits: number;
|
|
30
31
|
pullRounds: number;
|
|
31
32
|
pullResponse: SyncPullResponse;
|
|
33
|
+
pushResults: PushResultInfo[];
|
|
32
34
|
}
|
|
33
35
|
export declare function syncOnce<DB extends SyncClientDb>(db: Kysely<DB>, transport: SyncTransport, handlers: ClientHandlerCollection<DB>, options: SyncOnceOptions): Promise<SyncOnceResult>;
|
|
34
36
|
//# sourceMappingURL=sync-loop.d.ts.map
|
package/dist/sync-loop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-loop.d.ts","sourceRoot":"","sources":["../src/sync-loop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EAIhB,uBAAuB,EACvB,aAAa,EACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAgBrE,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,eAAe,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"sync-loop.d.ts","sourceRoot":"","sources":["../src/sync-loop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAEV,gBAAgB,EAIhB,uBAAuB,EACvB,aAAa,EACd,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAErC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AACrD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAgBrE,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,eAAe,CAAC;AACvE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAkK7C,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC;IACzC,aAAa,EAAE,KAAK,CAAC,IAAI,CAAC,uBAAuB,EAAE,QAAQ,CAAC,CAAC,CAAC;IAC9D,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2DAA2D;IAC3D,OAAO,CAAC,EAAE,IAAI,GAAG,OAAO,GAAG,MAAM,CAAC;IAClC,yEAAyE;IACzE,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACjD;AAED,MAAM,WAAW,cAAc;IAC7B,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,gBAAgB,CAAC;IAC/B,WAAW,EAAE,cAAc,EAAE,CAAC;CAC/B;AAqOD,wBAAsB,QAAQ,CAAC,EAAE,SAAS,YAAY,EACpD,EAAE,EAAE,MAAM,CAAC,EAAE,CAAC,EACd,SAAS,EAAE,aAAa,EACxB,QAAQ,EAAE,uBAAuB,CAAC,EAAE,CAAC,EACrC,OAAO,EAAE,eAAe,GACvB,OAAO,CAAC,cAAc,CAAC,CAEzB"}
|
package/dist/sync-loop.js
CHANGED
|
@@ -7,9 +7,32 @@ import { upsertConflictsForRejectedCommit } from './conflicts.js';
|
|
|
7
7
|
import { getNextSendableOutboxCommit, markOutboxCommitAcked, markOutboxCommitFailed, markOutboxCommitPending, } from './outbox.js';
|
|
8
8
|
import { applyPullResponse, buildPullRequest, createFollowupPullState, syncPullOnce, } from './pull-engine.js';
|
|
9
9
|
import { syncPushOnce } from './push-engine.js';
|
|
10
|
+
function firstPushErrorCode(response) {
|
|
11
|
+
const firstError = response.results.find((result) => result.status === 'error');
|
|
12
|
+
if (firstError &&
|
|
13
|
+
'code' in firstError &&
|
|
14
|
+
typeof firstError.code === 'string' &&
|
|
15
|
+
firstError.code) {
|
|
16
|
+
return firstError.code;
|
|
17
|
+
}
|
|
18
|
+
const hasConflict = response.results.some((result) => result.status === 'conflict');
|
|
19
|
+
return hasConflict ? 'CONFLICT' : null;
|
|
20
|
+
}
|
|
21
|
+
function buildPushResult(args) {
|
|
22
|
+
return {
|
|
23
|
+
outboxCommitId: args.outboxCommitId,
|
|
24
|
+
clientCommitId: args.clientCommitId,
|
|
25
|
+
status: args.status,
|
|
26
|
+
commitSeq: args.response.commitSeq ?? null,
|
|
27
|
+
results: args.response.results,
|
|
28
|
+
errorCode: firstPushErrorCode(args.response),
|
|
29
|
+
timestamp: Date.now(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
10
32
|
async function syncPushUntilSettled(db, transport, options) {
|
|
11
33
|
const maxCommits = Math.max(1, Math.min(1000, options.maxCommits ?? 20));
|
|
12
34
|
let pushedCount = 0;
|
|
35
|
+
const pushResults = [];
|
|
13
36
|
for (let i = 0; i < maxCommits; i++) {
|
|
14
37
|
const res = await syncPushOnce(db, transport, {
|
|
15
38
|
clientId: options.clientId,
|
|
@@ -19,8 +42,11 @@ async function syncPushUntilSettled(db, transport, options) {
|
|
|
19
42
|
if (!res.pushed)
|
|
20
43
|
break;
|
|
21
44
|
pushedCount += 1;
|
|
45
|
+
if (res.pushResult) {
|
|
46
|
+
pushResults.push(res.pushResult);
|
|
47
|
+
}
|
|
22
48
|
}
|
|
23
|
-
return { pushedCount };
|
|
49
|
+
return { pushedCount, pushResults };
|
|
24
50
|
}
|
|
25
51
|
function hasPushViaWs(transport) {
|
|
26
52
|
return 'pushViaWs' in transport && typeof transport.pushViaWs === 'function';
|
|
@@ -169,6 +195,7 @@ async function syncOnceCombined(db, transport, handlers, options) {
|
|
|
169
195
|
}
|
|
170
196
|
// Process push response
|
|
171
197
|
let pushedCommits = 0;
|
|
198
|
+
const pushResults = [];
|
|
172
199
|
if (outbox && pushRequest) {
|
|
173
200
|
let pushRes = wsPushResponse ?? combined.push;
|
|
174
201
|
if (!pushRes) {
|
|
@@ -194,6 +221,12 @@ async function syncOnceCombined(db, transport, handlers, options) {
|
|
|
194
221
|
commitSeq: pushRes.commitSeq ?? null,
|
|
195
222
|
responseJson,
|
|
196
223
|
});
|
|
224
|
+
pushResults.push(buildPushResult({
|
|
225
|
+
outboxCommitId: outbox.id,
|
|
226
|
+
clientCommitId: outbox.client_commit_id,
|
|
227
|
+
status: pushRes.status,
|
|
228
|
+
response: pushRes,
|
|
229
|
+
}));
|
|
197
230
|
pushedCommits = 1;
|
|
198
231
|
}
|
|
199
232
|
else {
|
|
@@ -207,6 +240,12 @@ async function syncOnceCombined(db, transport, handlers, options) {
|
|
|
207
240
|
error: 'Retriable',
|
|
208
241
|
responseJson,
|
|
209
242
|
});
|
|
243
|
+
pushResults.push(buildPushResult({
|
|
244
|
+
outboxCommitId: outbox.id,
|
|
245
|
+
clientCommitId: outbox.client_commit_id,
|
|
246
|
+
status: 'retriable',
|
|
247
|
+
response: pushRes,
|
|
248
|
+
}));
|
|
210
249
|
pushedCommits = 1;
|
|
211
250
|
}
|
|
212
251
|
else {
|
|
@@ -220,6 +259,12 @@ async function syncOnceCombined(db, transport, handlers, options) {
|
|
|
220
259
|
error: 'REJECTED',
|
|
221
260
|
responseJson,
|
|
222
261
|
});
|
|
262
|
+
pushResults.push(buildPushResult({
|
|
263
|
+
outboxCommitId: outbox.id,
|
|
264
|
+
clientCommitId: outbox.client_commit_id,
|
|
265
|
+
status: 'rejected',
|
|
266
|
+
response: pushRes,
|
|
267
|
+
}));
|
|
223
268
|
pushedCommits = 1;
|
|
224
269
|
}
|
|
225
270
|
}
|
|
@@ -231,6 +276,7 @@ async function syncOnceCombined(db, transport, handlers, options) {
|
|
|
231
276
|
maxCommits: (options.maxPushCommits ?? 20) - 1,
|
|
232
277
|
});
|
|
233
278
|
pushedCommits += remaining.pushedCount;
|
|
279
|
+
pushResults.push(...remaining.pushResults);
|
|
234
280
|
}
|
|
235
281
|
// Process pull response
|
|
236
282
|
let pullResponse = { ok: true, subscriptions: [] };
|
|
@@ -255,7 +301,7 @@ async function syncOnceCombined(db, transport, handlers, options) {
|
|
|
255
301
|
};
|
|
256
302
|
}
|
|
257
303
|
}
|
|
258
|
-
return { pushedCommits, pullRounds, pullResponse };
|
|
304
|
+
return { pushedCommits, pullRounds, pullResponse, pushResults };
|
|
259
305
|
}
|
|
260
306
|
export async function syncOnce(db, transport, handlers, options) {
|
|
261
307
|
return syncOnceCombined(db, transport, handlers, options);
|
package/dist/sync-loop.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync-loop.js","sourceRoot":"","sources":["../src/sync-loop.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,EAAE,gCAAgC,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sync-loop.js","sourceRoot":"","sources":["../src/sync-loop.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@syncular/client",
|
|
3
|
-
"version": "0.0.6-
|
|
3
|
+
"version": "0.0.6-138",
|
|
4
4
|
"description": "Client-side sync engine with offline-first support, outbox, and conflict resolution",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "Benjamin Kniffler",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"release": "bunx syncular-publish"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@syncular/core": "0.0.6-
|
|
50
|
-
"@syncular/transport-http": "0.0.6-
|
|
49
|
+
"@syncular/core": "0.0.6-138",
|
|
50
|
+
"@syncular/transport-http": "0.0.6-138"
|
|
51
51
|
},
|
|
52
52
|
"peerDependencies": {
|
|
53
53
|
"kysely": "*"
|
package/src/client.test.ts
CHANGED
|
@@ -141,13 +141,13 @@ describe('Client conflict events', () => {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
async function runConflictCheck(
|
|
144
|
-
|
|
144
|
+
engineInstance: SyncEngine<TestDb>
|
|
145
145
|
): Promise<void> {
|
|
146
|
-
const checker = Reflect.get(
|
|
146
|
+
const checker = Reflect.get(engineInstance, 'emitNewConflicts');
|
|
147
147
|
if (typeof checker !== 'function') {
|
|
148
|
-
throw new Error('Expected
|
|
148
|
+
throw new Error('Expected emitNewConflicts to be callable');
|
|
149
149
|
}
|
|
150
|
-
await checker.call(
|
|
150
|
+
await checker.call(engineInstance);
|
|
151
151
|
}
|
|
152
152
|
|
|
153
153
|
beforeEach(async () => {
|
|
@@ -184,6 +184,11 @@ describe('Client conflict events', () => {
|
|
|
184
184
|
subscriptions: [],
|
|
185
185
|
});
|
|
186
186
|
Reflect.set(client, 'engine', engine);
|
|
187
|
+
const wireEngineEvents = Reflect.get(client, 'wireEngineEvents');
|
|
188
|
+
if (typeof wireEngineEvents !== 'function') {
|
|
189
|
+
throw new Error('Expected wireEngineEvents to be callable');
|
|
190
|
+
}
|
|
191
|
+
wireEngineEvents.call(client);
|
|
187
192
|
});
|
|
188
193
|
|
|
189
194
|
afterEach(async () => {
|
|
@@ -220,11 +225,43 @@ describe('Client conflict events', () => {
|
|
|
220
225
|
newEvents.push(conflict.id);
|
|
221
226
|
});
|
|
222
227
|
|
|
223
|
-
await runConflictCheck(
|
|
224
|
-
await runConflictCheck(
|
|
228
|
+
await runConflictCheck(engine);
|
|
229
|
+
await runConflictCheck(engine);
|
|
225
230
|
|
|
226
231
|
expect(newEvents).toEqual(['conflict-1']);
|
|
227
232
|
});
|
|
233
|
+
|
|
234
|
+
it('forwards push:result events from the engine', () => {
|
|
235
|
+
const pushResults: Array<{ clientCommitId: string; status: string }> = [];
|
|
236
|
+
client.on('push:result', (result) => {
|
|
237
|
+
pushResults.push({
|
|
238
|
+
clientCommitId: result.clientCommitId,
|
|
239
|
+
status: result.status,
|
|
240
|
+
});
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
const emit = Reflect.get(engine, 'emit');
|
|
244
|
+
if (typeof emit !== 'function') {
|
|
245
|
+
throw new Error('Expected SyncEngine.emit to be callable');
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
emit.call(engine, 'push:result', {
|
|
249
|
+
outboxCommitId: 'outbox-1',
|
|
250
|
+
clientCommitId: 'commit-1',
|
|
251
|
+
status: 'rejected',
|
|
252
|
+
commitSeq: null,
|
|
253
|
+
results: [],
|
|
254
|
+
errorCode: 'CONFLICT',
|
|
255
|
+
timestamp: Date.now(),
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
expect(pushResults).toEqual([
|
|
259
|
+
{
|
|
260
|
+
clientCommitId: 'commit-1',
|
|
261
|
+
status: 'rejected',
|
|
262
|
+
},
|
|
263
|
+
]);
|
|
264
|
+
});
|
|
228
265
|
});
|
|
229
266
|
|
|
230
267
|
describe('Client blob upload queue recovery', () => {
|
package/src/client.ts
CHANGED
|
@@ -24,6 +24,7 @@ import type {
|
|
|
24
24
|
ConflictInfo,
|
|
25
25
|
OutboxStats,
|
|
26
26
|
PresenceEntry,
|
|
27
|
+
PushResultInfo,
|
|
27
28
|
SubscriptionProgress,
|
|
28
29
|
SyncAwaitBootstrapOptions,
|
|
29
30
|
SyncAwaitPhaseOptions,
|
|
@@ -120,6 +121,24 @@ export interface ClientOptions<DB extends SyncClientDb> {
|
|
|
120
121
|
/** Optional: Polling interval in milliseconds (default: 10000) */
|
|
121
122
|
pollIntervalMs?: number;
|
|
122
123
|
|
|
124
|
+
/**
|
|
125
|
+
* Optional: Debounce window (ms) for coalescing `data:change` events.
|
|
126
|
+
* - `0` (default): emit immediately
|
|
127
|
+
* - `>0`: merge scopes and emit once per window
|
|
128
|
+
*/
|
|
129
|
+
dataChangeDebounceMs?: number;
|
|
130
|
+
/**
|
|
131
|
+
* Optional: Debounce override while sync is actively running.
|
|
132
|
+
* Falls back to `dataChangeDebounceMs` when omitted.
|
|
133
|
+
*/
|
|
134
|
+
dataChangeDebounceMsWhenSyncing?: number;
|
|
135
|
+
/**
|
|
136
|
+
* Optional: Debounce override while connection is reconnecting.
|
|
137
|
+
* Falls back to `dataChangeDebounceMsWhenSyncing` (if syncing) and then
|
|
138
|
+
* `dataChangeDebounceMs` when omitted.
|
|
139
|
+
*/
|
|
140
|
+
dataChangeDebounceMsWhenReconnecting?: number;
|
|
141
|
+
|
|
123
142
|
/** Optional: State ID for multi-tenant scenarios */
|
|
124
143
|
stateId?: string;
|
|
125
144
|
|
|
@@ -231,6 +250,7 @@ type ClientEventType =
|
|
|
231
250
|
| 'sync:complete'
|
|
232
251
|
| 'sync:live'
|
|
233
252
|
| 'sync:error'
|
|
253
|
+
| 'push:result'
|
|
234
254
|
| 'bootstrap:start'
|
|
235
255
|
| 'bootstrap:progress'
|
|
236
256
|
| 'bootstrap:complete'
|
|
@@ -248,6 +268,7 @@ type ClientEventPayloads = {
|
|
|
248
268
|
'sync:complete': SyncResult;
|
|
249
269
|
'sync:live': { timestamp: number };
|
|
250
270
|
'sync:error': { code: string; message: string };
|
|
271
|
+
'push:result': PushResultInfo;
|
|
251
272
|
'bootstrap:start': {
|
|
252
273
|
timestamp: number;
|
|
253
274
|
stateId: string;
|
|
@@ -314,7 +335,6 @@ export class Client<DB extends SyncClientDb = SyncClientDb> {
|
|
|
314
335
|
private engine: SyncEngine<DB> | null = null;
|
|
315
336
|
private started = false;
|
|
316
337
|
private destroyed = false;
|
|
317
|
-
private emittedConflictIds = new Set<string>();
|
|
318
338
|
private eventListeners = new Map<
|
|
319
339
|
ClientEventType,
|
|
320
340
|
Set<ClientEventHandler<any>>
|
|
@@ -413,6 +433,11 @@ export class Client<DB extends SyncClientDb = SyncClientDb> {
|
|
|
413
433
|
plugins: this.options.plugins,
|
|
414
434
|
realtimeEnabled: this.options.realtimeEnabled,
|
|
415
435
|
pollIntervalMs: this.options.pollIntervalMs,
|
|
436
|
+
dataChangeDebounceMs: this.options.dataChangeDebounceMs,
|
|
437
|
+
dataChangeDebounceMsWhenSyncing:
|
|
438
|
+
this.options.dataChangeDebounceMsWhenSyncing,
|
|
439
|
+
dataChangeDebounceMsWhenReconnecting:
|
|
440
|
+
this.options.dataChangeDebounceMsWhenReconnecting,
|
|
416
441
|
stateId: this.options.stateId,
|
|
417
442
|
migrate: undefined, // We already ran migrations
|
|
418
443
|
});
|
|
@@ -642,6 +667,20 @@ export class Client<DB extends SyncClientDb = SyncClientDb> {
|
|
|
642
667
|
return this.engine.subscribe(callback);
|
|
643
668
|
}
|
|
644
669
|
|
|
670
|
+
/**
|
|
671
|
+
* Subscribe to state changes with selector-based equality filtering.
|
|
672
|
+
*/
|
|
673
|
+
subscribeSelector<T>(
|
|
674
|
+
selector: () => T,
|
|
675
|
+
callback: () => void,
|
|
676
|
+
isEqual?: (previous: T, next: T) => boolean
|
|
677
|
+
): () => void {
|
|
678
|
+
if (!this.engine) {
|
|
679
|
+
return () => {};
|
|
680
|
+
}
|
|
681
|
+
return this.engine.subscribeSelector(selector, callback, isEqual);
|
|
682
|
+
}
|
|
683
|
+
|
|
645
684
|
// ===========================================================================
|
|
646
685
|
// Events
|
|
647
686
|
// ===========================================================================
|
|
@@ -721,7 +760,6 @@ export class Client<DB extends SyncClientDb = SyncClientDb> {
|
|
|
721
760
|
},
|
|
722
761
|
});
|
|
723
762
|
|
|
724
|
-
this.emittedConflictIds.delete(id);
|
|
725
763
|
if (resolvedConflict) {
|
|
726
764
|
this.emit('conflict:resolved', resolvedConflict);
|
|
727
765
|
}
|
|
@@ -938,9 +976,14 @@ export class Client<DB extends SyncClientDb = SyncClientDb> {
|
|
|
938
976
|
|
|
939
977
|
this.engine.on('sync:error', (error) => {
|
|
940
978
|
this.emit('sync:error', { code: error.code, message: error.message });
|
|
979
|
+
});
|
|
941
980
|
|
|
942
|
-
|
|
943
|
-
this.
|
|
981
|
+
this.engine.on('push:result', (payload) => {
|
|
982
|
+
this.emit('push:result', payload);
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
this.engine.on('conflict:new', (payload) => {
|
|
986
|
+
this.emit('conflict:new', this.mapConflictInfo(payload));
|
|
944
987
|
});
|
|
945
988
|
|
|
946
989
|
this.engine.on('bootstrap:start', (payload) => {
|
|
@@ -983,25 +1026,6 @@ export class Client<DB extends SyncClientDb = SyncClientDb> {
|
|
|
983
1026
|
});
|
|
984
1027
|
}
|
|
985
1028
|
|
|
986
|
-
private async checkForNewConflicts(): Promise<void> {
|
|
987
|
-
const conflicts = await this.getConflicts();
|
|
988
|
-
const activeIds = new Set(conflicts.map((conflict) => conflict.id));
|
|
989
|
-
|
|
990
|
-
for (const id of this.emittedConflictIds) {
|
|
991
|
-
if (!activeIds.has(id)) {
|
|
992
|
-
this.emittedConflictIds.delete(id);
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
|
|
996
|
-
for (const conflict of conflicts) {
|
|
997
|
-
if (this.emittedConflictIds.has(conflict.id)) {
|
|
998
|
-
continue;
|
|
999
|
-
}
|
|
1000
|
-
this.emittedConflictIds.add(conflict.id);
|
|
1001
|
-
this.emit('conflict:new', conflict);
|
|
1002
|
-
}
|
|
1003
|
-
}
|
|
1004
|
-
|
|
1005
1029
|
private mapConflictInfo(info: ConflictInfo): Conflict {
|
|
1006
1030
|
let serverPayload: Record<string, unknown> | null = null;
|
|
1007
1031
|
if (info.serverRowJson) {
|
package/src/create-client.ts
CHANGED
|
@@ -141,6 +141,23 @@ interface CreateClientOptions<DB extends SyncClientDb> {
|
|
|
141
141
|
realtime?: boolean;
|
|
142
142
|
/** Polling interval in ms (default: 10000) */
|
|
143
143
|
pollIntervalMs?: number;
|
|
144
|
+
/**
|
|
145
|
+
* Debounce window (ms) for coalescing `data:change` events.
|
|
146
|
+
* - `0` (default): emit immediately
|
|
147
|
+
* - `>0`: merge scopes and emit once per window
|
|
148
|
+
*/
|
|
149
|
+
dataChangeDebounceMs?: number;
|
|
150
|
+
/**
|
|
151
|
+
* Debounce override while sync is actively running.
|
|
152
|
+
* Falls back to `dataChangeDebounceMs` when omitted.
|
|
153
|
+
*/
|
|
154
|
+
dataChangeDebounceMsWhenSyncing?: number;
|
|
155
|
+
/**
|
|
156
|
+
* Debounce override while connection is reconnecting.
|
|
157
|
+
* Falls back to `dataChangeDebounceMsWhenSyncing` (if syncing) and then
|
|
158
|
+
* `dataChangeDebounceMs` when omitted.
|
|
159
|
+
*/
|
|
160
|
+
dataChangeDebounceMsWhenReconnecting?: number;
|
|
144
161
|
};
|
|
145
162
|
|
|
146
163
|
/** Optional: Local blob storage adapter */
|
|
@@ -315,6 +332,10 @@ export async function createClient<DB extends SyncClientDb>(
|
|
|
315
332
|
codecDialect,
|
|
316
333
|
realtimeEnabled: sync.realtime ?? true,
|
|
317
334
|
pollIntervalMs: sync.pollIntervalMs,
|
|
335
|
+
dataChangeDebounceMs: sync.dataChangeDebounceMs,
|
|
336
|
+
dataChangeDebounceMsWhenSyncing: sync.dataChangeDebounceMsWhenSyncing,
|
|
337
|
+
dataChangeDebounceMsWhenReconnecting:
|
|
338
|
+
sync.dataChangeDebounceMsWhenReconnecting,
|
|
318
339
|
});
|
|
319
340
|
|
|
320
341
|
// Auto-start
|