@g9tm/syncdata 1.3.1 → 1.5.0
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 +4 -3
- package/dist/client/engine.d.ts +6 -1
- package/dist/client/engine.js +10 -1
- package/dist/client/engine.js.map +1 -1
- package/dist/client/storeTypes.d.ts +18 -0
- package/dist/client/storeTypes.js +17 -0
- package/dist/client/storeTypes.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/signalr/transport.d.ts +16 -0
- package/dist/signalr/transport.js +73 -7
- package/dist/signalr/transport.js.map +1 -1
- package/dist/sqlite/query.d.ts +3 -1
- package/dist/sqlite/query.js +16 -0
- package/dist/sqlite/query.js.map +1 -1
- package/dist/sqlite/snapshotFiles.js +27 -7
- package/dist/sqlite/snapshotFiles.js.map +1 -1
- package/dist/sqlite/store.d.ts +2 -1
- package/dist/sqlite/store.js +3 -0
- package/dist/sqlite/store.js.map +1 -1
- package/package.json +1 -1
package/PARITY.md
CHANGED
|
@@ -13,7 +13,7 @@ it). This file maps every .NET piece to its twin and lists every deliberate diff
|
|
|
13
13
|
| Requests written by TypeScript, parsed by the .NET server's own hub protocols (JSON and Nerdbank MessagePack) and compared with the .NET samples | `test/hub.test.ts` → `test/golden/js-vectors.json` → `JsGoldenVectorsTests.Requests_the_TypeScript_client_writes_deserialize_on_the_server` |
|
|
14
14
|
| The TypeScript engine + store + transport against the real .NET sample server (50,000 rows, push, pokes, reconcile, unsubscribe), over both hub protocols | `test/interop/server.test.ts` (`npm run test:interop`) |
|
|
15
15
|
| The database the TypeScript store writes equals the one the .NET store writes for the same sync: app rows and storage classes, every `g9_*` row, the schema, the stored JSON | `test/interop/server.test.ts` → database parity |
|
|
16
|
-
| A site's first download as a snapshot FILE (ADR-0072) copied by the TypeScript store leaves the database the .NET store leaves (both sites as files, the second
|
|
16
|
+
| A site's first download as a snapshot FILE (ADR-0072) copied by the TypeScript store leaves the database the .NET store leaves (both sites as files, the second appended to the first's table) | `test/interop/server.test.ts` → "a snapshot FILE copied by the TypeScript store" |
|
|
17
17
|
| The same scenario in a Lynx-shaped runtime (no BigInt/TextEncoder/URL/WebSocket, native modules behind a copying bridge), with and without snapshot files through `lynxSnapshotFileSink`'s module methods | `@g9tm/syncdata-lynx` `npm run test:lynxsim` |
|
|
18
18
|
|
|
19
19
|
`G9_UPDATE_GOLDEN=1` rewrites the golden files after an intended change; commit them with the change that needs them.
|
|
@@ -37,14 +37,15 @@ it). This file maps every .NET piece to its twin and lists every deliberate diff
|
|
|
37
37
|
| `G9CSyncRun`, `G9CSyncRequest`, `G9CSyncRunResult`, `G9CSyncPostStep` | `G9SyncRun`, `G9SyncRequest`, `G9SyncRunResult`, `G9SyncPostStep` | `run.progress()` is the bounded progress channel |
|
|
38
38
|
| `G9CSyncProgressTracker`, `G9DtSyncProgress` | `G9SyncProgressTracker`, `G9DtSyncProgress` (`etaMs`) | same planning, creep and monotonicity |
|
|
39
39
|
| `IG9SyncClientStore` | `G9SyncClientStore` | |
|
|
40
|
+
| `ReadChangeFeedAsync(table, after, limit, G9CChangeFeedKeyFilter, ct)` | `readChangeFeedFiltered(table, after, limit, G9ChangeFeedKeyFilter, signal?)` | a named method instead of an overload; the same SQL and the same validation (`validateChangeFeedKeyFilter`) |
|
|
40
41
|
| `G9CSqliteSyncStore`, options | `G9SqliteSyncStore` (`@g9tm/syncdata/sqlite`) over a `G9SqliteDriver` | same tables, triggers, SQL, JSON blobs and storage forms |
|
|
41
|
-
| Snapshot files (`G9CSqliteSyncStore.SnapshotFiles.cs`): `AcceptSnapshotFiles`, `SnapshotFileDirectory`, checkpoints, staging, verification, the copy/columns/merge apply, the sweep | `snapshotFiles: G9SnapshotFileSink` (`nodeSnapshotFileSink(dir)` in `@g9tm/syncdata/node`, `lynxSnapshotFileSink(db)` in `@g9tm/syncdata-lynx`), `src/sqlite/snapshotFiles.ts` | the same SQL statement for statement; the bytes go through the sink (decompress + SHA-256 + positional write) instead of `RandomAccess` in process; `G9CSnapshotFileWriter` (the server's) has no twin |
|
|
42
|
+
| Snapshot files (`G9CSqliteSyncStore.SnapshotFiles.cs`): `AcceptSnapshotFiles`, `SnapshotFileDirectory`, checkpoints, staging, verification, the copy/columns/append/merge apply, the sweep | `snapshotFiles: G9SnapshotFileSink` (`nodeSnapshotFileSink(dir)` in `@g9tm/syncdata/node`, `lynxSnapshotFileSink(db)` in `@g9tm/syncdata-lynx`), `src/sqlite/snapshotFiles.ts` | the same SQL statement for statement; the bytes go through the sink (decompress + SHA-256 + positional write) instead of `RandomAccess` in process; `G9CSnapshotFileWriter` (the server's) has no twin |
|
|
42
43
|
| `EnqueueCommand(sqlite3 appConnection, …)` | `enqueueCommandOnSession({ driver, session, tx }, …)` | SAVEPOINT inside the app's transaction |
|
|
43
44
|
| `IncarnationMarkerPath` | `incarnationMarker` (`fileIncarnationMarker(fileSystem, path)`) | any `G9FileSystem` (Lynx: the SignalR native module's) |
|
|
44
45
|
| `ExportPendingChangesAsync(path)` | `exportPendingChanges(writeLine)` | the caller writes the lines where it wants |
|
|
45
46
|
| `CheckIntegrityAsync` | `checkIntegrity()` | |
|
|
46
47
|
| `G9CSqliteException` (`IG9SyncLocalStoreFailure`) | `G9SqliteStoreError` (`localStoreFailure`) | classified from the driver's code |
|
|
47
|
-
| `G9CSignalRSyncTransport`, options | `G9SignalRSyncTransport` (`@g9tm/syncdata/signalr`) | over `G9Client` of `@g9tm/signalr-supernetcore-client`; Lynx: `createLynxSyncTransport` |
|
|
48
|
+
| `G9CSignalRSyncTransport`, options | `G9SignalRSyncTransport` (`@g9tm/syncdata/signalr`) | over `G9Client` of `@g9tm/signalr-supernetcore-client`; Lynx: `createLynxSyncTransport`. Limits (ADR-0074): `CallTimeout` / `PushTimeout` / `StreamIdleTimeout` = `callTimeoutMs` / `pushTimeoutMs` / `streamIdleTimeoutMs`, same defaults, same retryable `G9S-NET-FAILURE`, same connection drop (`SignalRTimeoutTests` / `test/transportTimeouts.test.ts`) |
|
|
48
49
|
| `G9CInMemorySyncTransport`, `G9CTransportFaults` | `G9FaultInjectingTransport`, `G9TransportFaults` (`@g9tm/syncdata/testing`) | wraps a real transport (no in-process server engine in JavaScript) |
|
|
49
50
|
|
|
50
51
|
## Deliberate differences
|
package/dist/client/engine.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { G9SyncParameters } from '../abstractions/parameters.js';
|
|
|
2
2
|
import { type G9DtHelloResult, type G9DtNegotiatedTable, type G9DtSubscriptionState } from '../protocol/dtos.js';
|
|
3
3
|
import type { G9SyncClientModel } from './model.js';
|
|
4
4
|
import { G9SyncRun, type G9RowsAppliedEvent, type G9SubscriptionOptions, type G9SyncEngineOptions, type G9SyncHealth, type G9SyncRequest, type G9SyncRunResult } from './runs.js';
|
|
5
|
-
import { type G9ChangeFeedEntry, type G9LocalCommand, type G9LocalCommandWriter, type G9ELocalCommandState, type G9PendingSummary, type G9QuarantinedRow, type G9RetainedRow, type G9SyncClientStore, type G9SyncRejection, type G9SyncSubscriptionRecord } from './storeTypes.js';
|
|
5
|
+
import { type G9ChangeFeedEntry, type G9ChangeFeedKeyFilter, type G9LocalCommand, type G9LocalCommandWriter, type G9ELocalCommandState, type G9PendingSummary, type G9QuarantinedRow, type G9RetainedRow, type G9SyncClientStore, type G9SyncRejection, type G9SyncSubscriptionRecord } from './storeTypes.js';
|
|
6
6
|
import type { G9SyncTransport } from './transport.js';
|
|
7
7
|
/**
|
|
8
8
|
* The client sync engine (`G9CSyncEngine`): one per local database. Owns a prioritised run queue, so status queries
|
|
@@ -74,6 +74,11 @@ export declare class G9SyncEngine {
|
|
|
74
74
|
getRetained(signal?: AbortSignal): Promise<G9RetainedRow[]>;
|
|
75
75
|
retryRejected(localTable?: string | null, key?: string | null, signal?: AbortSignal): Promise<number>;
|
|
76
76
|
readChangeFeed(localTable: string, afterSequence: number, limit?: number, signal?: AbortSignal): Promise<G9ChangeFeedEntry[]>;
|
|
77
|
+
/**
|
|
78
|
+
* The change feed for one table narrowed to the keys `keyFilter` selects (plus every deletion), so a projection of one site does
|
|
79
|
+
* not walk the entries of every other one (`ReadChangeFeedAsync(..., G9CChangeFeedKeyFilter, ...)`).
|
|
80
|
+
*/
|
|
81
|
+
readChangeFeedFiltered(localTable: string, afterSequence: number, limit: number, keyFilter: G9ChangeFeedKeyFilter, signal?: AbortSignal): Promise<G9ChangeFeedEntry[]>;
|
|
77
82
|
/** The highest sequence readChangeFeed can return today (a watermark above it belongs to a store that no longer exists). */
|
|
78
83
|
getChangeSequence(signal?: AbortSignal): Promise<number>;
|
|
79
84
|
/** The highest sequence ever purged from the change feed; 0 when nothing was (ADR-0059). */
|
package/dist/client/engine.js
CHANGED
|
@@ -11,7 +11,7 @@ import { G9EPullPartKind, G9ESubscriptionAction, syncErrorToException, } from '.
|
|
|
11
11
|
import { openRowBatch } from '../protocol/rowBatch/reader.js';
|
|
12
12
|
import { G9ESyncPhase, G9SyncProgressTracker, phaseName } from './progress.js';
|
|
13
13
|
import { G9ESyncOutcome, G9ESyncPriority, G9SyncRun, canCoalesce, describeModelProblem, isTransientError, makeRunResult, normalizeError, outcomeName, priorityName, requestSignature, resolveEngineOptions, resolveRequest, } from './runs.js';
|
|
14
|
-
import { G9ApplyReport, G9ESubscriptionState, toSubscriptionRef, } from './storeTypes.js';
|
|
14
|
+
import { G9ApplyReport, G9ESubscriptionState, toSubscriptionRef, validateChangeFeedKeyFilter, } from './storeTypes.js';
|
|
15
15
|
const STAT_CONNECTING = 'Connecting';
|
|
16
16
|
const STAT_PLANNING = 'Planning';
|
|
17
17
|
const STAT_PUSH_PER_K_ROW = 'PushPerKRow';
|
|
@@ -240,6 +240,15 @@ export class G9SyncEngine {
|
|
|
240
240
|
await this.initialize(signal);
|
|
241
241
|
return this._store.readChangeFeed(localTable, afterSequence, limit, signal);
|
|
242
242
|
}
|
|
243
|
+
/**
|
|
244
|
+
* The change feed for one table narrowed to the keys `keyFilter` selects (plus every deletion), so a projection of one site does
|
|
245
|
+
* not walk the entries of every other one (`ReadChangeFeedAsync(..., G9CChangeFeedKeyFilter, ...)`).
|
|
246
|
+
*/
|
|
247
|
+
async readChangeFeedFiltered(localTable, afterSequence, limit, keyFilter, signal) {
|
|
248
|
+
validateChangeFeedKeyFilter(keyFilter);
|
|
249
|
+
await this.initialize(signal);
|
|
250
|
+
return this._store.readChangeFeedFiltered(localTable, afterSequence, limit, keyFilter, signal);
|
|
251
|
+
}
|
|
243
252
|
/** The highest sequence readChangeFeed can return today (a watermark above it belongs to a store that no longer exists). */
|
|
244
253
|
async getChangeSequence(signal) {
|
|
245
254
|
await this.initialize(signal);
|