@g9tm/syncdata 1.5.6 → 1.5.8

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/PARITY.md CHANGED
@@ -44,6 +44,8 @@ it). This file maps every .NET piece to its twin and lists every deliberate diff
44
44
  | `IncarnationMarkerPath` | `incarnationMarker` (`fileIncarnationMarker(fileSystem, path)`) | any `G9FileSystem` (Lynx: the SignalR native module's) |
45
45
  | `ExportPendingChangesAsync(path)` | `exportPendingChanges(writeLine)` | the caller writes the lines where it wants |
46
46
  | `CheckIntegrityAsync` | `checkIntegrity()` | |
47
+ | `KeepLostConflicts` (LES-0072) | `keepLostConflicts` | same SQL, same rejection row (code, lost columns, server values as JSON); `G9ApplyReport.conflictsKept`; `test/keepLostConflicts.test.ts` |
48
+ | `SaveHelloAsync(hello, localMidpointUtc, ct)` (LES-0075) | `saveHello(hello, signal, localMidpointMs)` | the engine measures the Hello round trip in both clients and stores `serverTime - midpoint` |
47
49
  | `G9CSqliteException` (`IG9SyncLocalStoreFailure`) | `G9SqliteStoreError` (`localStoreFailure`) | classified from the driver's code |
48
50
  | `G9CSignalRSyncTransport`, options | `G9SignalRSyncTransport` (`@g9tm/syncdata/signalr`) | over `G9Client` of `@g9tm/signalr-supernetcore-client`; Lynx: `createLynxSyncTransport`. Limits (ADR-0074): `CallTimeout` / `PlanTimeout` / `PushTimeout` / `StreamIdleTimeout` = `callTimeoutMs` / `planTimeoutMs` / `pushTimeoutMs` / `streamIdleTimeoutMs`, same defaults, same retryable `G9S-NET-FAILURE`, same connection drop (`SignalRTimeoutTests` / `test/transportTimeouts.test.ts`) |
49
51
  | `G9CInMemorySyncTransport`, `G9CTransportFaults` | `G9FaultInjectingTransport`, `G9TransportFaults` (`@g9tm/syncdata/testing`) | wraps a real transport (no in-process server engine in JavaScript) |
@@ -468,16 +468,23 @@ export class G9SyncEngine {
468
468
  await this._ensureConnected(ct);
469
469
  await this._store.collectExpiredEphemeral(Date.now(), ct);
470
470
  const subscriptions = await this._store.getSubscriptions(ct);
471
- const hello = await this._withRetry((token) => this._transport.hello({
472
- clientId: this._clientId,
473
- appVersion: this._options.appVersion,
474
- protocolVersion: 1,
475
- tables: this.model.tables.map((t) => t.toWire()),
476
- subscriptions: subscriptions.map(toSubscriptionRef),
477
- }, token), ct);
471
+ let helloMidpointMs = Date.now();
472
+ const hello = await this._withRetry(async (token) => {
473
+ // The round trip of the attempt that answered: its midpoint is the local time of the server's clock reading (LES-0075).
474
+ const sent = Date.now();
475
+ const answer = await this._transport.hello({
476
+ clientId: this._clientId,
477
+ appVersion: this._options.appVersion,
478
+ protocolVersion: 1,
479
+ tables: this.model.tables.map((t) => t.toWire()),
480
+ subscriptions: subscriptions.map(toSubscriptionRef),
481
+ }, token);
482
+ helloMidpointMs = sent + (Date.now() - sent) / 2;
483
+ return answer;
484
+ }, ct);
478
485
  if (hello.error)
479
486
  throw syncErrorToException(hello.error);
480
- await this._store.saveHello(hello, ct);
487
+ await this._store.saveHello(hello, ct, helloMidpointMs);
481
488
  if (hello.unknownTables.length > 0) {
482
489
  this._log('warning', 20016, 'The server does not know these client tables (they will not sync): ' + hello.unknownTables.join(', '));
483
490
  }
@@ -871,7 +878,8 @@ export class G9SyncEngine {
871
878
  // What the server TOOK (its acknowledgement), not "sent minus refused": a row refused on the device (too large) is in
872
879
  // `rejected` but was never sent (LES-0071).
873
880
  accepted += report.accepted + report.commandsCompleted;
874
- rejected += result.rejections.length;
881
+ // A conflict the device lost is kept on it as a rejection (LES-0072): refused work the operator must decide on.
882
+ rejected += result.rejections.length + report.conflictsKept;
875
883
  conflicts += result.conflicts.length;
876
884
  tracker.report(pushed);
877
885
  this._log('debug', 20014, `Pushed batch ${batch.batchId}: ${batch.rowCount} rows, ${result.rejections.length} rejected, ${result.conflicts.length} conflicts, replayed ${result.alreadyApplied}`);