@g9tm/syncdata 1.2.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/LICENSE.md +21 -0
- package/PARITY.md +71 -0
- package/README.md +71 -0
- package/THIRD-PARTY-NOTICES.md +31 -0
- package/dist/abstractions/digest.d.ts +27 -0
- package/dist/abstractions/digest.js +78 -0
- package/dist/abstractions/digest.js.map +1 -0
- package/dist/abstractions/enums.d.ts +42 -0
- package/dist/abstractions/enums.js +60 -0
- package/dist/abstractions/enums.js.map +1 -0
- package/dist/abstractions/errors.d.ts +72 -0
- package/dist/abstractions/errors.js +90 -0
- package/dist/abstractions/errors.js.map +1 -0
- package/dist/abstractions/guid.d.ts +24 -0
- package/dist/abstractions/guid.js +93 -0
- package/dist/abstractions/guid.js.map +1 -0
- package/dist/abstractions/key.d.ts +16 -0
- package/dist/abstractions/key.js +47 -0
- package/dist/abstractions/key.js.map +1 -0
- package/dist/abstractions/long.d.ts +103 -0
- package/dist/abstractions/long.js +351 -0
- package/dist/abstractions/long.js.map +1 -0
- package/dist/abstractions/parameters.d.ts +49 -0
- package/dist/abstractions/parameters.js +153 -0
- package/dist/abstractions/parameters.js.map +1 -0
- package/dist/brotli-js/decode.d.ts +8 -0
- package/dist/brotli-js/decode.js +2004 -0
- package/dist/brotli-js/decode.js.map +1 -0
- package/dist/brotli-js/index.d.ts +5 -0
- package/dist/brotli-js/index.js +19 -0
- package/dist/brotli-js/index.js.map +1 -0
- package/dist/client/engine.d.ts +110 -0
- package/dist/client/engine.js +1158 -0
- package/dist/client/engine.js.map +1 -0
- package/dist/client/model.d.ts +61 -0
- package/dist/client/model.js +154 -0
- package/dist/client/model.js.map +1 -0
- package/dist/client/progress.d.ts +101 -0
- package/dist/client/progress.js +251 -0
- package/dist/client/progress.js.map +1 -0
- package/dist/client/runs.d.ts +219 -0
- package/dist/client/runs.js +239 -0
- package/dist/client/runs.js.map +1 -0
- package/dist/client/storeTypes.d.ts +428 -0
- package/dist/client/storeTypes.js +256 -0
- package/dist/client/storeTypes.js.map +1 -0
- package/dist/client/transport.d.ts +19 -0
- package/dist/client/transport.js +2 -0
- package/dist/client/transport.js.map +1 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.js +35 -0
- package/dist/index.js.map +1 -0
- package/dist/internal/abort.d.ts +21 -0
- package/dist/internal/abort.js +125 -0
- package/dist/internal/abort.js.map +1 -0
- package/dist/internal/base64.d.ts +8 -0
- package/dist/internal/base64.js +85 -0
- package/dist/internal/base64.js.map +1 -0
- package/dist/internal/dotnetFormat.d.ts +32 -0
- package/dist/internal/dotnetFormat.js +207 -0
- package/dist/internal/dotnetFormat.js.map +1 -0
- package/dist/internal/md5.d.ts +2 -0
- package/dist/internal/md5.js +97 -0
- package/dist/internal/md5.js.map +1 -0
- package/dist/internal/sha256.d.ts +20 -0
- package/dist/internal/sha256.js +153 -0
- package/dist/internal/sha256.js.map +1 -0
- package/dist/internal/utf8.d.ts +8 -0
- package/dist/internal/utf8.js +143 -0
- package/dist/internal/utf8.js.map +1 -0
- package/dist/node/index.d.ts +9 -0
- package/dist/node/index.js +35 -0
- package/dist/node/index.js.map +1 -0
- package/dist/node/sqliteDriver.d.ts +11 -0
- package/dist/node/sqliteDriver.js +252 -0
- package/dist/node/sqliteDriver.js.map +1 -0
- package/dist/protocol/dtos.d.ts +280 -0
- package/dist/protocol/dtos.js +33 -0
- package/dist/protocol/dtos.js.map +1 -0
- package/dist/protocol/protocol.d.ts +36 -0
- package/dist/protocol/protocol.js +63 -0
- package/dist/protocol/protocol.js.map +1 -0
- package/dist/protocol/rowBatch/columnLayout.d.ts +4 -0
- package/dist/protocol/rowBatch/columnLayout.js +309 -0
- package/dist/protocol/rowBatch/columnLayout.js.map +1 -0
- package/dist/protocol/rowBatch/format.d.ts +74 -0
- package/dist/protocol/rowBatch/format.js +163 -0
- package/dist/protocol/rowBatch/format.js.map +1 -0
- package/dist/protocol/rowBatch/reader.d.ts +119 -0
- package/dist/protocol/rowBatch/reader.js +459 -0
- package/dist/protocol/rowBatch/reader.js.map +1 -0
- package/dist/protocol/rowBatch/writer.d.ts +101 -0
- package/dist/protocol/rowBatch/writer.js +412 -0
- package/dist/protocol/rowBatch/writer.js.map +1 -0
- package/dist/protocol/wire.d.ts +32 -0
- package/dist/protocol/wire.js +329 -0
- package/dist/protocol/wire.js.map +1 -0
- package/dist/signalr/index.d.ts +2 -0
- package/dist/signalr/index.js +5 -0
- package/dist/signalr/index.js.map +1 -0
- package/dist/signalr/protocols.d.ts +17 -0
- package/dist/signalr/protocols.js +109 -0
- package/dist/signalr/protocols.js.map +1 -0
- package/dist/signalr/transport.d.ts +67 -0
- package/dist/signalr/transport.js +286 -0
- package/dist/signalr/transport.js.map +1 -0
- package/dist/sqlite/apply.d.ts +91 -0
- package/dist/sqlite/apply.js +657 -0
- package/dist/sqlite/apply.js.map +1 -0
- package/dist/sqlite/commands.d.ts +24 -0
- package/dist/sqlite/commands.js +167 -0
- package/dist/sqlite/commands.js.map +1 -0
- package/dist/sqlite/connection.d.ts +81 -0
- package/dist/sqlite/connection.js +322 -0
- package/dist/sqlite/connection.js.map +1 -0
- package/dist/sqlite/driver.d.ts +63 -0
- package/dist/sqlite/driver.js +9 -0
- package/dist/sqlite/driver.js.map +1 -0
- package/dist/sqlite/index.d.ts +6 -0
- package/dist/sqlite/index.js +7 -0
- package/dist/sqlite/index.js.map +1 -0
- package/dist/sqlite/internals.d.ts +63 -0
- package/dist/sqlite/internals.js +194 -0
- package/dist/sqlite/internals.js.map +1 -0
- package/dist/sqlite/options.d.ts +78 -0
- package/dist/sqlite/options.js +78 -0
- package/dist/sqlite/options.js.map +1 -0
- package/dist/sqlite/push.d.ts +9 -0
- package/dist/sqlite/push.js +272 -0
- package/dist/sqlite/push.js.map +1 -0
- package/dist/sqlite/query.d.ts +38 -0
- package/dist/sqlite/query.js +476 -0
- package/dist/sqlite/query.js.map +1 -0
- package/dist/sqlite/revocation.d.ts +28 -0
- package/dist/sqlite/revocation.js +337 -0
- package/dist/sqlite/revocation.js.map +1 -0
- package/dist/sqlite/sql.d.ts +60 -0
- package/dist/sqlite/sql.js +324 -0
- package/dist/sqlite/sql.js.map +1 -0
- package/dist/sqlite/store.d.ts +116 -0
- package/dist/sqlite/store.js +664 -0
- package/dist/sqlite/store.js.map +1 -0
- package/dist/sqlite/values.d.ts +29 -0
- package/dist/sqlite/values.js +288 -0
- package/dist/sqlite/values.js.map +1 -0
- package/dist/testing/index.d.ts +61 -0
- package/dist/testing/index.js +175 -0
- package/dist/testing/index.js.map +1 -0
- package/package.json +104 -0
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
// @g9tm/syncdata/testing — the twin of G9SyncData.Testing's fault scripting (G9CTransportFaults). The .NET in-memory
|
|
2
|
+
// transport calls a server engine in-process; JavaScript has no server engine, so the TypeScript twin wraps ANY transport
|
|
3
|
+
// (typically the SignalR transport against a test server) and injects the same scripted faults (PARITY.md).
|
|
4
|
+
import { G9SyncErrorCodes, G9SyncException } from '../abstractions/errors.js';
|
|
5
|
+
import { delay } from '../internal/abort.js';
|
|
6
|
+
/** The protocol operations (`G9ETransportOperation`). */
|
|
7
|
+
export const G9ETransportOperation = {
|
|
8
|
+
Connect: 0,
|
|
9
|
+
Hello: 1,
|
|
10
|
+
Push: 2,
|
|
11
|
+
PlanPull: 3,
|
|
12
|
+
Pull: 4,
|
|
13
|
+
Reconcile: 5,
|
|
14
|
+
FetchRows: 6,
|
|
15
|
+
};
|
|
16
|
+
const NAMES = ['Connect', 'Hello', 'Push', 'PlanPull', 'Pull', 'Reconcile', 'FetchRows'];
|
|
17
|
+
/** Scripted transport failures, each consumed once per affected call (`G9CTransportFaults`). */
|
|
18
|
+
export class G9TransportFaults {
|
|
19
|
+
constructor() {
|
|
20
|
+
/** Delay (ms) added before every call and every streamed chunk. */
|
|
21
|
+
this.latencyMs = 0;
|
|
22
|
+
this._failBefore = new Map();
|
|
23
|
+
this._failAfter = new Map();
|
|
24
|
+
this._breakAfter = new Map();
|
|
25
|
+
}
|
|
26
|
+
/** The next `times` calls fail before reaching the server. */
|
|
27
|
+
failBefore(operation, times = 1) {
|
|
28
|
+
var _a;
|
|
29
|
+
this._failBefore.set(operation, ((_a = this._failBefore.get(operation)) !== null && _a !== void 0 ? _a : 0) + times);
|
|
30
|
+
return this;
|
|
31
|
+
}
|
|
32
|
+
/** The next `times` unary calls complete on the server, then the response is lost ("applied but not acknowledged"). */
|
|
33
|
+
failAfter(operation, times = 1) {
|
|
34
|
+
var _a;
|
|
35
|
+
this._failAfter.set(operation, ((_a = this._failAfter.get(operation)) !== null && _a !== void 0 ? _a : 0) + times);
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
/** The next `times` streams of the operation break after delivering `chunks` chunks. */
|
|
39
|
+
breakStreamAfter(operation, chunks, times = 1) {
|
|
40
|
+
var _a;
|
|
41
|
+
if (chunks < 0)
|
|
42
|
+
throw new RangeError('chunks must be non-negative.');
|
|
43
|
+
const queue = (_a = this._breakAfter.get(operation)) !== null && _a !== void 0 ? _a : [];
|
|
44
|
+
for (let i = 0; i < times; i++)
|
|
45
|
+
queue.push(chunks);
|
|
46
|
+
this._breakAfter.set(operation, queue);
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
clear() {
|
|
50
|
+
this._failBefore.clear();
|
|
51
|
+
this._failAfter.clear();
|
|
52
|
+
this._breakAfter.clear();
|
|
53
|
+
}
|
|
54
|
+
/** @internal */
|
|
55
|
+
takeFailBefore(operation) {
|
|
56
|
+
return take(this._failBefore, operation);
|
|
57
|
+
}
|
|
58
|
+
/** @internal */
|
|
59
|
+
takeFailAfter(operation) {
|
|
60
|
+
return take(this._failAfter, operation);
|
|
61
|
+
}
|
|
62
|
+
/** @internal Chunks to deliver before breaking, or -1. */
|
|
63
|
+
takeStreamBreak(operation) {
|
|
64
|
+
const queue = this._breakAfter.get(operation);
|
|
65
|
+
return queue && queue.length > 0 ? queue.shift() : -1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function take(map, operation) {
|
|
69
|
+
var _a;
|
|
70
|
+
const remaining = (_a = map.get(operation)) !== null && _a !== void 0 ? _a : 0;
|
|
71
|
+
if (remaining <= 0)
|
|
72
|
+
return false;
|
|
73
|
+
map.set(operation, remaining - 1);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
function networkFailure(operation, reason) {
|
|
77
|
+
return new G9SyncException(G9SyncErrorCodes.NetworkFailure, `Injected fault on ${NAMES[operation]}: ${reason}.`, { retryable: true });
|
|
78
|
+
}
|
|
79
|
+
/** A transport that injects {@link G9TransportFaults} into another one, and counts calls. */
|
|
80
|
+
export class G9FaultInjectingTransport {
|
|
81
|
+
constructor(inner) {
|
|
82
|
+
this.faults = new G9TransportFaults();
|
|
83
|
+
/** The continuation of every pull call, in call order (null for a fresh pull). */
|
|
84
|
+
this.pullContinuations = [];
|
|
85
|
+
this._calls = new Map();
|
|
86
|
+
this._disconnected = false;
|
|
87
|
+
this.inner = inner;
|
|
88
|
+
}
|
|
89
|
+
get isConnected() {
|
|
90
|
+
return !this._disconnected && this.inner.isConnected;
|
|
91
|
+
}
|
|
92
|
+
callCount(operation) {
|
|
93
|
+
var _a;
|
|
94
|
+
return (_a = this._calls.get(operation)) !== null && _a !== void 0 ? _a : 0;
|
|
95
|
+
}
|
|
96
|
+
/** Simulates a dropped connection: the next call fails until the engine reconnects. */
|
|
97
|
+
disconnect() {
|
|
98
|
+
this._disconnected = true;
|
|
99
|
+
}
|
|
100
|
+
onChangesAvailable(handler) {
|
|
101
|
+
return this.inner.onChangesAvailable(handler);
|
|
102
|
+
}
|
|
103
|
+
async connect(signal) {
|
|
104
|
+
await this._begin(G9ETransportOperation.Connect, signal);
|
|
105
|
+
this._disconnected = false;
|
|
106
|
+
await this.inner.connect(signal);
|
|
107
|
+
}
|
|
108
|
+
hello(request, signal) {
|
|
109
|
+
return this._unary(G9ETransportOperation.Hello, signal, () => this.inner.hello(request, signal));
|
|
110
|
+
}
|
|
111
|
+
push(request, chunks, signal) {
|
|
112
|
+
return this._unary(G9ETransportOperation.Push, signal, () => this.inner.push(request, chunks, signal));
|
|
113
|
+
}
|
|
114
|
+
planPull(request, signal) {
|
|
115
|
+
return this._unary(G9ETransportOperation.PlanPull, signal, () => this.inner.planPull(request, signal));
|
|
116
|
+
}
|
|
117
|
+
pull(token, continuation, signal) {
|
|
118
|
+
this.pullContinuations.push(continuation ? { ...continuation } : null);
|
|
119
|
+
return this._stream(G9ETransportOperation.Pull, signal, () => this.inner.pull(token, continuation, signal));
|
|
120
|
+
}
|
|
121
|
+
reconcile(request, signal) {
|
|
122
|
+
return this._stream(G9ETransportOperation.Reconcile, signal, () => this.inner.reconcile(request, signal));
|
|
123
|
+
}
|
|
124
|
+
fetchRows(request, signal) {
|
|
125
|
+
return this._stream(G9ETransportOperation.FetchRows, signal, () => this.inner.fetchRows(request, signal));
|
|
126
|
+
}
|
|
127
|
+
dispose() {
|
|
128
|
+
return this.inner.dispose();
|
|
129
|
+
}
|
|
130
|
+
async _begin(operation, signal) {
|
|
131
|
+
var _a;
|
|
132
|
+
if (signal && signal.aborted)
|
|
133
|
+
throw new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.');
|
|
134
|
+
this._calls.set(operation, ((_a = this._calls.get(operation)) !== null && _a !== void 0 ? _a : 0) + 1);
|
|
135
|
+
if (this.faults.latencyMs > 0)
|
|
136
|
+
await delay(this.faults.latencyMs, signal);
|
|
137
|
+
if (this.faults.takeFailBefore(operation))
|
|
138
|
+
throw networkFailure(operation, 'the call failed before reaching the server');
|
|
139
|
+
}
|
|
140
|
+
_ensureConnected() {
|
|
141
|
+
if (this._disconnected)
|
|
142
|
+
throw new G9SyncException(G9SyncErrorCodes.NetworkFailure, 'The transport is not connected.', { retryable: true });
|
|
143
|
+
}
|
|
144
|
+
async _unary(operation, signal, call) {
|
|
145
|
+
await this._begin(operation, signal);
|
|
146
|
+
this._ensureConnected();
|
|
147
|
+
const result = await call();
|
|
148
|
+
if (this.faults.takeFailAfter(operation))
|
|
149
|
+
throw networkFailure(operation, 'the response was lost after the server completed the call');
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
_stream(operation, signal, open) {
|
|
153
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
154
|
+
const self = this;
|
|
155
|
+
return {
|
|
156
|
+
async *[Symbol.asyncIterator]() {
|
|
157
|
+
await self._begin(operation, signal);
|
|
158
|
+
self._ensureConnected();
|
|
159
|
+
const breakAfter = self.faults.takeStreamBreak(operation);
|
|
160
|
+
let delivered = 0;
|
|
161
|
+
for await (const chunk of open()) {
|
|
162
|
+
if (breakAfter >= 0 && delivered >= breakAfter)
|
|
163
|
+
throw networkFailure(operation, `the stream broke after ${delivered} chunks`);
|
|
164
|
+
if (self._disconnected)
|
|
165
|
+
throw networkFailure(operation, 'the connection dropped');
|
|
166
|
+
if (self.faults.latencyMs > 0)
|
|
167
|
+
await delay(self.faults.latencyMs, signal);
|
|
168
|
+
delivered++;
|
|
169
|
+
yield chunk;
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"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","sourcesContent":["// @g9tm/syncdata/testing — the twin of G9SyncData.Testing's fault scripting (G9CTransportFaults). The .NET in-memory\n// transport calls a server engine in-process; JavaScript has no server engine, so the TypeScript twin wraps ANY transport\n// (typically the SignalR transport against a test server) and injects the same scripted faults (PARITY.md).\nimport { G9SyncErrorCodes, G9SyncException } from '../abstractions/errors.js';\nimport { delay } from '../internal/abort.js';\nimport type { G9SyncTransport } from '../client/transport.js';\nimport type {\n G9DtChangesAvailable,\n G9DtFetchRowsRequest,\n G9DtHelloRequest,\n G9DtHelloResult,\n G9DtPullContinuation,\n G9DtPullPlan,\n G9DtPullRequest,\n G9DtPushRequest,\n G9DtPushResult,\n G9DtReconcileRequest,\n G9DtSyncChunk,\n} from '../protocol/dtos.js';\n\n/** The protocol operations (`G9ETransportOperation`). */\nexport const G9ETransportOperation = {\n Connect: 0,\n Hello: 1,\n Push: 2,\n PlanPull: 3,\n Pull: 4,\n Reconcile: 5,\n FetchRows: 6,\n} as const;\nexport type G9ETransportOperation = (typeof G9ETransportOperation)[keyof typeof G9ETransportOperation];\n\nconst NAMES = ['Connect', 'Hello', 'Push', 'PlanPull', 'Pull', 'Reconcile', 'FetchRows'];\n\n/** Scripted transport failures, each consumed once per affected call (`G9CTransportFaults`). */\nexport class G9TransportFaults {\n /** Delay (ms) added before every call and every streamed chunk. */\n latencyMs = 0;\n private readonly _failBefore = new Map<number, number>();\n private readonly _failAfter = new Map<number, number>();\n private readonly _breakAfter = new Map<number, number[]>();\n\n /** The next `times` calls fail before reaching the server. */\n failBefore(operation: G9ETransportOperation, times = 1): this {\n this._failBefore.set(operation, (this._failBefore.get(operation) ?? 0) + times);\n return this;\n }\n\n /** The next `times` unary calls complete on the server, then the response is lost (\"applied but not acknowledged\"). */\n failAfter(operation: G9ETransportOperation, times = 1): this {\n this._failAfter.set(operation, (this._failAfter.get(operation) ?? 0) + times);\n return this;\n }\n\n /** The next `times` streams of the operation break after delivering `chunks` chunks. */\n breakStreamAfter(operation: G9ETransportOperation, chunks: number, times = 1): this {\n if (chunks < 0) throw new RangeError('chunks must be non-negative.');\n const queue = this._breakAfter.get(operation) ?? [];\n for (let i = 0; i < times; i++) queue.push(chunks);\n this._breakAfter.set(operation, queue);\n return this;\n }\n\n clear(): void {\n this._failBefore.clear();\n this._failAfter.clear();\n this._breakAfter.clear();\n }\n\n /** @internal */\n takeFailBefore(operation: number): boolean {\n return take(this._failBefore, operation);\n }\n\n /** @internal */\n takeFailAfter(operation: number): boolean {\n return take(this._failAfter, operation);\n }\n\n /** @internal Chunks to deliver before breaking, or -1. */\n takeStreamBreak(operation: number): number {\n const queue = this._breakAfter.get(operation);\n return queue && queue.length > 0 ? (queue.shift() as number) : -1;\n }\n}\n\nfunction take(map: Map<number, number>, operation: number): boolean {\n const remaining = map.get(operation) ?? 0;\n if (remaining <= 0) return false;\n map.set(operation, remaining - 1);\n return true;\n}\n\nfunction networkFailure(operation: number, reason: string): G9SyncException {\n return new G9SyncException(G9SyncErrorCodes.NetworkFailure, `Injected fault on ${NAMES[operation]}: ${reason}.`, { retryable: true });\n}\n\n/** A transport that injects {@link G9TransportFaults} into another one, and counts calls. */\nexport class G9FaultInjectingTransport implements G9SyncTransport {\n readonly inner: G9SyncTransport;\n readonly faults = new G9TransportFaults();\n /** The continuation of every pull call, in call order (null for a fresh pull). */\n readonly pullContinuations: (G9DtPullContinuation | null)[] = [];\n private readonly _calls = new Map<number, number>();\n private _disconnected = false;\n\n constructor(inner: G9SyncTransport) {\n this.inner = inner;\n }\n\n get isConnected(): boolean {\n return !this._disconnected && this.inner.isConnected;\n }\n\n callCount(operation: G9ETransportOperation): number {\n return this._calls.get(operation) ?? 0;\n }\n\n /** Simulates a dropped connection: the next call fails until the engine reconnects. */\n disconnect(): void {\n this._disconnected = true;\n }\n\n onChangesAvailable(handler: (changes: G9DtChangesAvailable) => void): () => void {\n return this.inner.onChangesAvailable(handler);\n }\n\n async connect(signal?: AbortSignal): Promise<void> {\n await this._begin(G9ETransportOperation.Connect, signal);\n this._disconnected = false;\n await this.inner.connect(signal);\n }\n\n hello(request: G9DtHelloRequest, signal?: AbortSignal): Promise<G9DtHelloResult> {\n return this._unary(G9ETransportOperation.Hello, signal, () => this.inner.hello(request, signal));\n }\n\n push(request: G9DtPushRequest, chunks: AsyncIterable<G9DtSyncChunk>, signal?: AbortSignal): Promise<G9DtPushResult> {\n return this._unary(G9ETransportOperation.Push, signal, () => this.inner.push(request, chunks, signal));\n }\n\n planPull(request: G9DtPullRequest, signal?: AbortSignal): Promise<G9DtPullPlan> {\n return this._unary(G9ETransportOperation.PlanPull, signal, () => this.inner.planPull(request, signal));\n }\n\n pull(token: string, continuation: G9DtPullContinuation | null, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n this.pullContinuations.push(continuation ? { ...continuation } : null);\n return this._stream(G9ETransportOperation.Pull, signal, () => this.inner.pull(token, continuation, signal));\n }\n\n reconcile(request: G9DtReconcileRequest, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n return this._stream(G9ETransportOperation.Reconcile, signal, () => this.inner.reconcile(request, signal));\n }\n\n fetchRows(request: G9DtFetchRowsRequest, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n return this._stream(G9ETransportOperation.FetchRows, signal, () => this.inner.fetchRows(request, signal));\n }\n\n dispose(): Promise<void> {\n return this.inner.dispose();\n }\n\n private async _begin(operation: number, signal?: AbortSignal): Promise<void> {\n if (signal && signal.aborted) throw new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.');\n this._calls.set(operation, (this._calls.get(operation) ?? 0) + 1);\n if (this.faults.latencyMs > 0) await delay(this.faults.latencyMs, signal);\n if (this.faults.takeFailBefore(operation)) throw networkFailure(operation, 'the call failed before reaching the server');\n }\n\n private _ensureConnected(): void {\n if (this._disconnected) throw new G9SyncException(G9SyncErrorCodes.NetworkFailure, 'The transport is not connected.', { retryable: true });\n }\n\n private async _unary<T>(operation: number, signal: AbortSignal | undefined, call: () => Promise<T>): Promise<T> {\n await this._begin(operation, signal);\n this._ensureConnected();\n const result = await call();\n if (this.faults.takeFailAfter(operation)) throw networkFailure(operation, 'the response was lost after the server completed the call');\n return result;\n }\n\n private _stream(operation: number, signal: AbortSignal | undefined, open: () => AsyncIterable<G9DtSyncChunk>): AsyncIterable<G9DtSyncChunk> {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n return {\n async *[Symbol.asyncIterator](): AsyncGenerator<G9DtSyncChunk> {\n await self._begin(operation, signal);\n self._ensureConnected();\n const breakAfter = self.faults.takeStreamBreak(operation);\n let delivered = 0;\n for await (const chunk of open()) {\n if (breakAfter >= 0 && delivered >= breakAfter) throw networkFailure(operation, `the stream broke after ${delivered} chunks`);\n if (self._disconnected) throw networkFailure(operation, 'the connection dropped');\n if (self.faults.latencyMs > 0) await delay(self.faults.latencyMs, signal);\n delivered++;\n yield chunk;\n }\n },\n };\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@g9tm/syncdata",
|
|
3
|
+
"version": "1.2.1",
|
|
4
|
+
"description": "TypeScript twin of the G9SyncData .NET client for Lynx, Node and browsers: the sync engine, the G9RowBatch protocol, the SQLite client store (same schema as the .NET store) and the SignalR transport.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Iman Kari (G9TM)",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"default": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./sqlite": {
|
|
19
|
+
"types": "./dist/sqlite/index.d.ts",
|
|
20
|
+
"import": "./dist/sqlite/index.js",
|
|
21
|
+
"default": "./dist/sqlite/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./signalr": {
|
|
24
|
+
"types": "./dist/signalr/index.d.ts",
|
|
25
|
+
"import": "./dist/signalr/index.js",
|
|
26
|
+
"default": "./dist/signalr/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./testing": {
|
|
29
|
+
"types": "./dist/testing/index.d.ts",
|
|
30
|
+
"import": "./dist/testing/index.js",
|
|
31
|
+
"default": "./dist/testing/index.js"
|
|
32
|
+
},
|
|
33
|
+
"./node": {
|
|
34
|
+
"types": "./dist/node/index.d.ts",
|
|
35
|
+
"import": "./dist/node/index.js",
|
|
36
|
+
"default": "./dist/node/index.js"
|
|
37
|
+
},
|
|
38
|
+
"./brotli-js": {
|
|
39
|
+
"types": "./dist/brotli-js/index.d.ts",
|
|
40
|
+
"import": "./dist/brotli-js/index.js",
|
|
41
|
+
"default": "./dist/brotli-js/index.js"
|
|
42
|
+
},
|
|
43
|
+
"./package.json": "./package.json"
|
|
44
|
+
},
|
|
45
|
+
"files": [
|
|
46
|
+
"dist",
|
|
47
|
+
"README.md",
|
|
48
|
+
"PARITY.md",
|
|
49
|
+
"LICENSE.md",
|
|
50
|
+
"THIRD-PARTY-NOTICES.md"
|
|
51
|
+
],
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=22.12.0"
|
|
54
|
+
},
|
|
55
|
+
"keywords": [
|
|
56
|
+
"sync",
|
|
57
|
+
"offline-first",
|
|
58
|
+
"sqlite",
|
|
59
|
+
"signalr",
|
|
60
|
+
"lynx",
|
|
61
|
+
"g9"
|
|
62
|
+
],
|
|
63
|
+
"publishConfig": {
|
|
64
|
+
"access": "public"
|
|
65
|
+
},
|
|
66
|
+
"scripts": {
|
|
67
|
+
"clean": "node scripts/clean.mjs",
|
|
68
|
+
"build": "node scripts/clean.mjs && tsc -p tsconfig.build.json",
|
|
69
|
+
"typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.test.json --noEmit",
|
|
70
|
+
"test": "vitest run",
|
|
71
|
+
"test:interop": "vitest run --config vitest.interop.config.ts",
|
|
72
|
+
"test:watch": "vitest",
|
|
73
|
+
"prepack": "npm run build"
|
|
74
|
+
},
|
|
75
|
+
"peerDependencies": {
|
|
76
|
+
"@g9tm/signalr-supernetcore-client": "^2.10.0",
|
|
77
|
+
"@microsoft/signalr": "^10.0.0",
|
|
78
|
+
"@microsoft/signalr-protocol-msgpack": "^10.0.0",
|
|
79
|
+
"@msgpack/msgpack": "^2.8.0"
|
|
80
|
+
},
|
|
81
|
+
"peerDependenciesMeta": {
|
|
82
|
+
"@g9tm/signalr-supernetcore-client": {
|
|
83
|
+
"optional": true
|
|
84
|
+
},
|
|
85
|
+
"@microsoft/signalr": {
|
|
86
|
+
"optional": true
|
|
87
|
+
},
|
|
88
|
+
"@microsoft/signalr-protocol-msgpack": {
|
|
89
|
+
"optional": true
|
|
90
|
+
},
|
|
91
|
+
"@msgpack/msgpack": {
|
|
92
|
+
"optional": true
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"devDependencies": {
|
|
96
|
+
"@g9tm/signalr-supernetcore-client": "file:../../vendor/g9tm-signalr-supernetcore-client-2.10.0.tgz",
|
|
97
|
+
"@microsoft/signalr": "^10.0.11",
|
|
98
|
+
"@microsoft/signalr-protocol-msgpack": "^10.0.11",
|
|
99
|
+
"@msgpack/msgpack": "2.8.0",
|
|
100
|
+
"@types/node": "^22.15.0",
|
|
101
|
+
"typescript": "~5.9.3",
|
|
102
|
+
"vitest": "^5.0.1"
|
|
103
|
+
}
|
|
104
|
+
}
|