@g9tm/syncdata 1.5.19 → 1.5.21
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 +9 -0
- package/dist/client/engine.d.ts +23 -1
- package/dist/client/engine.js +82 -1
- package/dist/client/engine.js.map +1 -1
- package/dist/client/storeTypes.d.ts +9 -0
- package/dist/client/storeTypes.js +5 -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/protocol/dtos.d.ts +16 -0
- package/dist/protocol/dtos.js.map +1 -1
- package/dist/protocol/wire.js +6 -0
- package/dist/protocol/wire.js.map +1 -1
- package/dist/signalr/transport.d.ts +9 -0
- package/dist/signalr/transport.js +34 -3
- package/dist/signalr/transport.js.map +1 -1
- package/dist/sqlite/revocation.d.ts +14 -0
- package/dist/sqlite/revocation.js +76 -0
- package/dist/sqlite/revocation.js.map +1 -1
- package/dist/sqlite/snapshotFiles.js.map +1 -1
- package/dist/sqlite/store.d.ts +2 -0
- package/dist/sqlite/store.js +12 -3
- package/dist/sqlite/store.js.map +1 -1
- package/package.json +1 -1
|
@@ -23,6 +23,8 @@ export class G9SignalRSyncTransport {
|
|
|
23
23
|
this._handlers = [];
|
|
24
24
|
this._connecting = null;
|
|
25
25
|
this._lastHello = null;
|
|
26
|
+
/** The model this connection already sent in full, and the server's id for it (1.5.21, twin of .NET `_modelOnConnection`). */
|
|
27
|
+
this._modelOnConnection = null;
|
|
26
28
|
if (!options || typeof options.url !== 'string' || options.url.trim() === '')
|
|
27
29
|
throw new TypeError('A hub URL is required.');
|
|
28
30
|
this._options = options;
|
|
@@ -102,12 +104,35 @@ export class G9SignalRSyncTransport {
|
|
|
102
104
|
throw new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync connection is ${String(this.client.connection.state)}.`, { retryable: true });
|
|
103
105
|
}
|
|
104
106
|
}
|
|
107
|
+
/**
|
|
108
|
+
* The model once per connection (1.5.21, TR-0069; twin of .NET `HelloAsync`): the first Hello of a connection sends the whole model, a
|
|
109
|
+
* later one on the same connection with the same tables (the engine keeps one array) only the server's id for it. A server that lost it
|
|
110
|
+
* answers `modelRequired` and the full Hello goes at once. A new connection — a reconnect included — always starts with the full model.
|
|
111
|
+
*/
|
|
105
112
|
async hello(request, signal) {
|
|
106
|
-
const
|
|
107
|
-
|
|
113
|
+
const known = this._modelOnConnection;
|
|
114
|
+
const sent = known && known.connectionId === this._connectionId() && known.tables === request.tables && request.tables.length > 0
|
|
115
|
+
? { ...request, tables: [], modelHash: known.modelHash }
|
|
116
|
+
: request;
|
|
117
|
+
let result = await this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(sent)], readHelloResult, this._callTimeoutMs(), signal);
|
|
118
|
+
if (result.modelRequired && sent !== request) {
|
|
119
|
+
this._modelOnConnection = null;
|
|
120
|
+
result = await this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(request)], readHelloResult, this._callTimeoutMs(), signal);
|
|
121
|
+
}
|
|
122
|
+
if (!result.error) {
|
|
108
123
|
this._lastHello = request;
|
|
124
|
+
this._rememberModel(request, result);
|
|
125
|
+
}
|
|
109
126
|
return result;
|
|
110
127
|
}
|
|
128
|
+
_rememberModel(full, result) {
|
|
129
|
+
if (result.modelHash && full.tables.length > 0)
|
|
130
|
+
this._modelOnConnection = { connectionId: this._connectionId(), tables: full.tables, modelHash: result.modelHash };
|
|
131
|
+
}
|
|
132
|
+
_connectionId() {
|
|
133
|
+
const id = this.client.connection.connectionId;
|
|
134
|
+
return typeof id === 'string' ? id : null;
|
|
135
|
+
}
|
|
111
136
|
/**
|
|
112
137
|
* After an automatic reconnect the last accepted Hello is sent again, so the new connection joins the table groups pokes go to
|
|
113
138
|
* (S-2, LES-0087). Fire and forget, bounded by the call timeout; the answer is not used and a failure only delays a hint.
|
|
@@ -116,7 +141,13 @@ export class G9SignalRSyncTransport {
|
|
|
116
141
|
const hello = this._lastHello;
|
|
117
142
|
if (!hello)
|
|
118
143
|
return;
|
|
119
|
-
|
|
144
|
+
// The full Hello (a new connection never holds the model): its answer names the model for the next Hello on it.
|
|
145
|
+
this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(hello)], readHelloResult, this._callTimeoutMs())
|
|
146
|
+
.then((result) => {
|
|
147
|
+
if (!result.error)
|
|
148
|
+
this._rememberModel(hello, result);
|
|
149
|
+
})
|
|
150
|
+
.catch(() => undefined);
|
|
120
151
|
}
|
|
121
152
|
push(request, chunks, signal) {
|
|
122
153
|
var _a;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/signalr/transport.ts"],"names":[],"mappings":"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","sourcesContent":["// Twin of G9SyncData.Client.SignalR/G9CSignalRSyncTransport.cs: the sync transport over the G9SignalRSuperNetCore client\r\n// (its jittered reconnect policy and connection states), every failure surfacing as a G9SyncException with the server's\r\n// stable code. Lynx hosts build the client with the native WebSocket of @g9tm/signalr-supernetcore-lynx\r\n// (`createLynxSyncTransport` in @g9tm/syncdata-lynx does).\r\nimport { G9Client, type G9ClientOptions } from '@g9tm/signalr-supernetcore-client';\r\nimport { HubConnectionState, Subject, type IHubProtocol, type IStreamResult, type ISubscription } from '@microsoft/signalr';\r\nimport { G9SyncErrorCodes, G9SyncException, isSyncException } from '../abstractions/errors.js';\r\nimport { createAbortController, onAbort } from '../internal/abort.js';\r\nimport type { G9SyncTransport } from '../client/transport.js';\r\nimport type {\r\n G9DtChangesAvailable,\r\n G9DtFetchRowsRequest,\r\n G9DtHelloRequest,\r\n G9DtHelloResult,\r\n G9DtPullContinuation,\r\n G9DtPullPlan,\r\n G9DtPullRequest,\r\n G9DtPushRequest,\r\n G9DtPushResult,\r\n G9DtReconcileRequest,\r\n G9DtSyncChunk,\r\n} from '../protocol/dtos.js';\r\nimport { G9SyncHubErrors, G9SyncProtocol } from '../protocol/protocol.js';\r\nimport {\r\n fromMessagePackNames,\r\n readChangesAvailable,\r\n readHelloResult,\r\n readPullPlan,\r\n readPushResult,\r\n readSyncChunk,\r\n toMessagePackNames,\r\n type G9WireFormat,\r\n} from '../protocol/wire.js';\r\nimport { createSyncMessagePackProtocol, G9SyncJsonHubProtocol } from './protocols.js';\r\n\r\n/** The SignalR hub protocol a client speaks (`G9ESyncHubProtocol`). The server accepts both. */\r\nexport const G9ESyncHubProtocol = {\r\n /** Text frames; payloads base64-encoded (+33%). Readable in traces. */\r\n Json: 0,\r\n /** Binary frames: payloads as raw bytes. The default. */\r\n MessagePack: 1,\r\n} as const;\r\nexport type G9ESyncHubProtocol = (typeof G9ESyncHubProtocol)[keyof typeof G9ESyncHubProtocol];\r\n\r\n/** Options of {@link G9SignalRSyncTransport} (`G9CSignalRSyncTransportOptions`). Durations are milliseconds. */\r\nexport interface G9SignalRSyncTransportOptions {\r\n /** Absolute hub URL, e.g. `https://sync.example.com/g9sync`. */\r\n url: string;\r\n /** Hub protocol; MessagePack by default. */\r\n protocol?: G9ESyncHubProtocol;\r\n /** Supplies the bearer token for every (re)connect. */\r\n accessTokenFactory?: () => string | Promise<string>;\r\n /** SignalR stateful reconnect (ADR-0069); off by default, the server must allow it too. */\r\n statefulReconnect?: boolean;\r\n /** How long one connect may take before it counts as a network failure. */\r\n connectTimeoutMs?: number;\r\n serverTimeoutMs?: number;\r\n keepAliveIntervalMs?: number;\r\n /**\r\n * How long a Hello waits for its answer before it is a retryable G9S-NET-FAILURE (ADR-0074). Default 60000; 0 = no limit.\r\n * A live connection does not guarantee an answer: pings keep it up while the call's message was lost on the way.\r\n */\r\n callTimeoutMs?: number;\r\n /**\r\n * How long a PlanPull waits for its plan. Default 300000 (5 minutes); 0 = no limit (ADR-0074, amended in 1.5.1): a site's first\r\n * plan builds key sets and plans a snapshot file - 16 s for a 450,000-row farm on a desktop, several times that on a busy server.\r\n */\r\n planTimeoutMs?: number;\r\n /** How long a push may take from its first chunk to its result; a safety net, not a pace. Default 600000; 0 = no limit. */\r\n pushTimeoutMs?: number;\r\n /**\r\n * How long a server stream (Pull, Reconcile, FetchRows) may go without a chunk before it is a retryable G9S-NET-FAILURE; the\r\n * engine resumes from its last continuation. Default 120000 (a snapshot file may still be building); 0 = no limit (ADR-0074).\r\n */\r\n streamIdleTimeoutMs?: number;\r\n /**\r\n * Everything else the G9 client takes (transport, headers, WebSocket constructor, skipNegotiation, reconnect policy, log\r\n * level…) — the twin of ConfigureHttpConnection/ConfigureBuilder. `url`, `protocol` and the timeouts above win.\r\n */\r\n client?: Partial<G9ClientOptions>;\r\n /** Builds the client (tests, hosts with their own wiring); `new G9Client(options)` by default. */\r\n createClient?: (options: G9ClientOptions) => G9Client;\r\n}\r\n\r\n/** The SignalR implementation of {@link G9SyncTransport}. */\r\nexport class G9SignalRSyncTransport implements G9SyncTransport {\r\n readonly client: G9Client;\r\n readonly format: G9WireFormat;\r\n private readonly _options: G9SignalRSyncTransportOptions;\r\n private readonly _handlers: ((changes: G9DtChangesAvailable) => void)[] = [];\r\n private _connecting: Promise<void> | null = null;\r\n private _lastHello: G9DtHelloRequest | null = null;\r\n\r\n constructor(options: G9SignalRSyncTransportOptions) {\r\n if (!options || typeof options.url !== 'string' || options.url.trim() === '') throw new TypeError('A hub URL is required.');\r\n this._options = options;\r\n const json = options.protocol === G9ESyncHubProtocol.Json;\r\n this.format = json ? 'json' : 'messagepack';\r\n const protocol: IHubProtocol = json ? new G9SyncJsonHubProtocol() : createSyncMessagePackProtocol();\r\n const clientOptions: G9ClientOptions = {\r\n ...(options.client ?? {}),\r\n url: options.url,\r\n protocol,\r\n statefulReconnect: options.statefulReconnect ?? false,\r\n serverTimeoutMs: options.serverTimeoutMs ?? 30000,\r\n keepAliveIntervalMs: options.keepAliveIntervalMs ?? 10000,\r\n };\r\n if (options.accessTokenFactory) clientOptions.accessTokenFactory = options.accessTokenFactory;\r\n this.client = options.createClient ? options.createClient(clientOptions) : new G9Client(clientOptions);\r\n this.client.on(G9SyncProtocol.Listeners.OnChangesAvailable, (payload: unknown) => this._onChanges(payload));\r\n // Twin of .NET OnReconnectedAsync (S-2, LES-0087): a connection that reconnected by itself is a new connection id in no table group.\r\n const connection = this.client.connection as { onreconnected?: (callback: (connectionId?: string) => void) => void };\r\n if (typeof connection.onreconnected === 'function') connection.onreconnected(() => this._rejoin());\r\n }\r\n\r\n get isConnected(): boolean {\r\n return this.client.connection.state === HubConnectionState.Connected;\r\n }\r\n\r\n onChangesAvailable(handler: (changes: G9DtChangesAvailable) => void): () => void {\r\n this._handlers.push(handler);\r\n return () => {\r\n const index = this._handlers.indexOf(handler);\r\n if (index >= 0) this._handlers.splice(index, 1);\r\n };\r\n }\r\n\r\n /** Connects (joins a connect in progress); a connect that takes longer than connectTimeoutMs is a network failure. */\r\n connect(signal?: AbortSignal): Promise<void> {\r\n if (this.isConnected) return Promise.resolve();\r\n if (!this._connecting) {\r\n const connecting = this._connectCore().finally(() => {\r\n if (this._connecting === connecting) this._connecting = null;\r\n });\r\n this._connecting = connecting;\r\n }\r\n const connecting = this._connecting;\r\n if (!signal) return connecting;\r\n return new Promise<void>((resolve, reject) => {\r\n const unsubscribe = onAbort(signal, () => reject(new G9SyncException(G9SyncErrorCodes.Canceled, 'The connect was canceled.')));\r\n connecting.then(\r\n () => {\r\n unsubscribe();\r\n resolve();\r\n },\r\n (error) => {\r\n unsubscribe();\r\n reject(error);\r\n },\r\n );\r\n });\r\n }\r\n\r\n private async _connectCore(): Promise<void> {\r\n const timeout = createAbortController();\r\n const timer = setTimeout(() => timeout.abort(), this._options.connectTimeoutMs ?? 20000);\r\n try {\r\n await this.client.start(timeout.signal);\r\n } catch (error) {\r\n const mapped = mapError(error, false) ?? new G9SyncException(G9SyncErrorCodes.NetworkFailure, messageOf(error), { retryable: true, cause: error });\r\n throw mapped.code === G9SyncErrorCodes.Canceled\r\n ? new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync connection to ${this._options.url} did not open in time.`, { retryable: true, cause: error })\r\n : mapped;\r\n } finally {\r\n clearTimeout(timer);\r\n }\r\n if (!this.isConnected) {\r\n throw new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync connection is ${String(this.client.connection.state)}.`, { retryable: true });\r\n }\r\n }\r\n\r\n async hello(request: G9DtHelloRequest, signal?: AbortSignal): Promise<G9DtHelloResult> {\r\n const result = await this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(request)], readHelloResult, this._callTimeoutMs(), signal);\r\n if (!result.error) this._lastHello = request;\r\n return result;\r\n }\r\n\r\n /**\r\n * After an automatic reconnect the last accepted Hello is sent again, so the new connection joins the table groups pokes go to\r\n * (S-2, LES-0087). Fire and forget, bounded by the call timeout; the answer is not used and a failure only delays a hint.\r\n */\r\n private _rejoin(): void {\r\n const hello = this._lastHello;\r\n if (!hello) return;\r\n this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(hello)], readHelloResult, this._callTimeoutMs()).catch(() => undefined);\r\n }\r\n\r\n push(request: G9DtPushRequest, chunks: AsyncIterable<G9DtSyncChunk>, signal?: AbortSignal): Promise<G9DtPushResult> {\r\n const subject = new Subject<unknown>();\r\n const result = this._invoke(G9SyncProtocol.Methods.Push, [this._wire(request), subject], readPushResult, this._options.pushTimeoutMs ?? 600000, signal);\r\n void (async () => {\r\n try {\r\n for await (const chunk of chunks) subject.next(this._wire(chunk));\r\n subject.complete();\r\n } catch (error) {\r\n subject.error(error);\r\n }\r\n })();\r\n return result;\r\n }\r\n\r\n planPull(request: G9DtPullRequest, signal?: AbortSignal): Promise<G9DtPullPlan> {\r\n return this._invoke(G9SyncProtocol.Methods.PlanPull, [this._wire(request)], readPullPlan, this._options.planTimeoutMs ?? 300000, signal);\r\n }\r\n\r\n pull(token: string, continuation: G9DtPullContinuation | null, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\r\n return this._stream(G9SyncProtocol.Methods.Pull, [token, continuation === null ? null : this._wire(continuation)], signal);\r\n }\r\n\r\n reconcile(request: G9DtReconcileRequest, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\r\n return this._stream(G9SyncProtocol.Methods.Reconcile, [this._wire(request)], signal);\r\n }\r\n\r\n fetchRows(request: G9DtFetchRowsRequest, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\r\n return this._stream(G9SyncProtocol.Methods.FetchRows, [this._wire(request)], signal);\r\n }\r\n\r\n async dispose(): Promise<void> {\r\n this._handlers.length = 0;\r\n await this.client.stop();\r\n }\r\n\r\n // ================================================================ plumbing\r\n\r\n private _wire(value: unknown): unknown {\r\n return this.format === 'messagepack' ? toMessagePackNames(value) : value;\r\n }\r\n\r\n private _read(value: unknown): unknown {\r\n return this.format === 'messagepack' ? fromMessagePackNames(value) : value;\r\n }\r\n\r\n private _callTimeoutMs(): number {\r\n return this._options.callTimeoutMs ?? 60000;\r\n }\r\n\r\n private async _invoke<T>(method: string, args: unknown[], read: (value: unknown) => T, timeoutMs: number, signal?: AbortSignal): Promise<T> {\r\n if (signal && signal.aborted) throw new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.');\r\n let unsubscribe: () => void = () => undefined;\r\n let timer: ReturnType<typeof setTimeout> | null = null;\r\n let timedOut = false;\r\n try {\r\n const call = this.client.connection.invoke(method, ...args);\r\n const raw =\r\n signal || timeoutMs > 0\r\n ? await new Promise<unknown>((resolve, reject) => {\r\n if (signal) unsubscribe = onAbort(signal, () => reject(new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.')));\r\n if (timeoutMs > 0) {\r\n timer = setTimeout(() => {\r\n timedOut = true;\r\n reject(\r\n new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync server did not answer ${method} within ${Math.round(timeoutMs / 1000)} s.`, {\r\n retryable: true,\r\n }),\r\n );\r\n }, timeoutMs);\r\n }\r\n call.then(resolve, reject);\r\n })\r\n : await call;\r\n return read(this._read(raw));\r\n } catch (error) {\r\n // ADR-0074: the answer did not come in time. The connection is not trusted any more (the server runs one invocation per\r\n // connection at a time, and whatever lost this answer may lose the next): drop it, so the retry runs on a fresh one.\r\n if (timedOut) await this._dropConnection();\r\n throw mapError(error, signal ? signal.aborted : false) ?? error;\r\n } finally {\r\n if (timer !== null) clearTimeout(timer);\r\n unsubscribe();\r\n }\r\n }\r\n\r\n /** Ends the connection after a call or stream ran out of time (ADR-0074); the next call connects afresh. Never throws. */\r\n private async _dropConnection(): Promise<void> {\r\n try {\r\n await this.client.connection.stop();\r\n } catch {\r\n // Stopping a connection that is already gone may throw; the next call connects afresh either way.\r\n }\r\n }\r\n\r\n private _stream(method: string, args: unknown[], signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\r\n // eslint-disable-next-line @typescript-eslint/no-this-alias\r\n const self = this;\r\n return {\r\n [Symbol.asyncIterator](): AsyncIterator<G9DtSyncChunk> {\r\n const queue: G9DtSyncChunk[] = [];\r\n let done = false;\r\n let failure: unknown = null;\r\n let wake: (() => void) | null = null;\r\n let subscription: ISubscription<unknown> | null = null;\r\n const notify = (): void => {\r\n const w = wake;\r\n wake = null;\r\n if (w) w();\r\n };\r\n let unsubscribeAbort: () => void = () => undefined;\r\n // ADR-0074: the idle limit runs only while the iterator waits for the next chunk, never while the caller processes one.\r\n const idleMs = self._options.streamIdleTimeoutMs ?? 120000;\r\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\r\n let idleExpired = false;\r\n const stopIdle = (): void => {\r\n if (idleTimer !== null) clearTimeout(idleTimer);\r\n idleTimer = null;\r\n };\r\n const armIdle = (): void => {\r\n stopIdle();\r\n if (idleMs <= 0 || done) return;\r\n idleTimer = setTimeout(() => {\r\n idleTimer = null;\r\n if (done) return;\r\n idleExpired = true;\r\n failure = new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync server sent nothing on ${method} for ${Math.round(idleMs / 1000)} s.`, {\r\n retryable: true,\r\n });\r\n done = true;\r\n subscription?.dispose();\r\n notify();\r\n }, idleMs);\r\n };\r\n const start = (): void => {\r\n if (subscription || done) return;\r\n let stream: IStreamResult<unknown>;\r\n try {\r\n stream = self.client.connection.stream(method, ...args);\r\n } catch (error) {\r\n failure = error;\r\n done = true;\r\n return;\r\n }\r\n subscription = stream.subscribe({\r\n next: (item) => {\r\n queue.push(readSyncChunk(self._read(item)));\r\n notify();\r\n },\r\n error: (error) => {\r\n failure = error;\r\n done = true;\r\n notify();\r\n },\r\n complete: () => {\r\n done = true;\r\n notify();\r\n },\r\n });\r\n unsubscribeAbort = onAbort(signal, () => {\r\n failure = new G9SyncException(G9SyncErrorCodes.Canceled, 'The stream was canceled.');\r\n done = true;\r\n subscription?.dispose();\r\n notify();\r\n });\r\n };\r\n const finish = (): void => {\r\n stopIdle();\r\n unsubscribeAbort();\r\n if (subscription && !done) subscription.dispose();\r\n done = true;\r\n };\r\n return {\r\n async next(): Promise<IteratorResult<G9DtSyncChunk>> {\r\n start();\r\n for (;;) {\r\n const item = queue.shift();\r\n if (item) {\r\n stopIdle();\r\n return { value: item, done: false };\r\n }\r\n if (done) {\r\n stopIdle();\r\n unsubscribeAbort();\r\n if (idleExpired) await self._dropConnection();\r\n if (failure !== null) throw mapError(failure, signal ? signal.aborted : false) ?? failure;\r\n return { value: undefined as unknown as G9DtSyncChunk, done: true };\r\n }\r\n if (idleTimer === null) armIdle();\r\n await new Promise<void>((resolve) => {\r\n wake = resolve;\r\n });\r\n }\r\n },\r\n async return(): Promise<IteratorResult<G9DtSyncChunk>> {\r\n finish();\r\n return { value: undefined as unknown as G9DtSyncChunk, done: true };\r\n },\r\n };\r\n },\r\n };\r\n }\r\n\r\n private _onChanges(payload: unknown): void {\r\n const changes = readChangesAvailable(this._read(payload));\r\n for (const handler of this._handlers.slice()) {\r\n try {\r\n handler(changes);\r\n } catch {\r\n // A ChangesAvailable handler threw (logged by the .NET transport); it must not break the connection.\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction messageOf(error: unknown): string {\r\n return error instanceof Error ? error.message : String(error);\r\n}\r\n\r\n/**\r\n * The sync exception for a transport failure (`Map`): the server's `[G9S|code|retryable]` marker wins; any other hub\r\n * error is a retryable server error; 401/403 is Unauthorized; the rest is a retryable network failure. Null leaves the\r\n * error as it is (an already mapped one).\r\n */\r\nexport function mapError(error: unknown, canceled: boolean): G9SyncException | null {\r\n if (isSyncException(error)) return null;\r\n if (canceled) return new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.', { cause: error });\r\n const message = messageOf(error);\r\n const marked = G9SyncHubErrors.tryParse(message);\r\n if (marked) return marked;\r\n const status = (error as { statusCode?: unknown }).statusCode;\r\n if (status === 401 || status === 403) return new G9SyncException(G9SyncErrorCodes.Unauthorized, 'The sync server refused the credentials.', { cause: error });\r\n if (error instanceof Error && error.name === 'AbortError') return new G9SyncException(G9SyncErrorCodes.Canceled, message, { cause: error });\r\n // A completion error from the hub: SignalR words it \"An unexpected error occurred invoking '…' on the server.\"\r\n if (/on the server|HubException/i.test(message)) return new G9SyncException(G9SyncErrorCodes.ServerError, message, { retryable: true, cause: error });\r\n return new G9SyncException(G9SyncErrorCodes.NetworkFailure, message, { retryable: true, cause: error });\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"transport.js","sourceRoot":"","sources":["../../src/signalr/transport.ts"],"names":[],"mappings":"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","sourcesContent":["// Twin of G9SyncData.Client.SignalR/G9CSignalRSyncTransport.cs: the sync transport over the G9SignalRSuperNetCore client\n// (its jittered reconnect policy and connection states), every failure surfacing as a G9SyncException with the server's\n// stable code. Lynx hosts build the client with the native WebSocket of @g9tm/signalr-supernetcore-lynx\n// (`createLynxSyncTransport` in @g9tm/syncdata-lynx does).\nimport { G9Client, type G9ClientOptions } from '@g9tm/signalr-supernetcore-client';\nimport { HubConnectionState, Subject, type IHubProtocol, type IStreamResult, type ISubscription } from '@microsoft/signalr';\nimport { G9SyncErrorCodes, G9SyncException, isSyncException } from '../abstractions/errors.js';\nimport { createAbortController, onAbort } 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';\nimport { G9SyncHubErrors, G9SyncProtocol } from '../protocol/protocol.js';\nimport {\n fromMessagePackNames,\n readChangesAvailable,\n readHelloResult,\n readPullPlan,\n readPushResult,\n readSyncChunk,\n toMessagePackNames,\n type G9WireFormat,\n} from '../protocol/wire.js';\nimport { createSyncMessagePackProtocol, G9SyncJsonHubProtocol } from './protocols.js';\n\n/** The SignalR hub protocol a client speaks (`G9ESyncHubProtocol`). The server accepts both. */\nexport const G9ESyncHubProtocol = {\n /** Text frames; payloads base64-encoded (+33%). Readable in traces. */\n Json: 0,\n /** Binary frames: payloads as raw bytes. The default. */\n MessagePack: 1,\n} as const;\nexport type G9ESyncHubProtocol = (typeof G9ESyncHubProtocol)[keyof typeof G9ESyncHubProtocol];\n\n/** Options of {@link G9SignalRSyncTransport} (`G9CSignalRSyncTransportOptions`). Durations are milliseconds. */\nexport interface G9SignalRSyncTransportOptions {\n /** Absolute hub URL, e.g. `https://sync.example.com/g9sync`. */\n url: string;\n /** Hub protocol; MessagePack by default. */\n protocol?: G9ESyncHubProtocol;\n /** Supplies the bearer token for every (re)connect. */\n accessTokenFactory?: () => string | Promise<string>;\n /** SignalR stateful reconnect (ADR-0069); off by default, the server must allow it too. */\n statefulReconnect?: boolean;\n /** How long one connect may take before it counts as a network failure. */\n connectTimeoutMs?: number;\n serverTimeoutMs?: number;\n keepAliveIntervalMs?: number;\n /**\n * How long a Hello waits for its answer before it is a retryable G9S-NET-FAILURE (ADR-0074). Default 60000; 0 = no limit.\n * A live connection does not guarantee an answer: pings keep it up while the call's message was lost on the way.\n */\n callTimeoutMs?: number;\n /**\n * How long a PlanPull waits for its plan. Default 300000 (5 minutes); 0 = no limit (ADR-0074, amended in 1.5.1): a site's first\n * plan builds key sets and plans a snapshot file - 16 s for a 450,000-row farm on a desktop, several times that on a busy server.\n */\n planTimeoutMs?: number;\n /** How long a push may take from its first chunk to its result; a safety net, not a pace. Default 600000; 0 = no limit. */\n pushTimeoutMs?: number;\n /**\n * How long a server stream (Pull, Reconcile, FetchRows) may go without a chunk before it is a retryable G9S-NET-FAILURE; the\n * engine resumes from its last continuation. Default 120000 (a snapshot file may still be building); 0 = no limit (ADR-0074).\n */\n streamIdleTimeoutMs?: number;\n /**\n * Everything else the G9 client takes (transport, headers, WebSocket constructor, skipNegotiation, reconnect policy, log\n * level…) — the twin of ConfigureHttpConnection/ConfigureBuilder. `url`, `protocol` and the timeouts above win.\n */\n client?: Partial<G9ClientOptions>;\n /** Builds the client (tests, hosts with their own wiring); `new G9Client(options)` by default. */\n createClient?: (options: G9ClientOptions) => G9Client;\n}\n\n/** The SignalR implementation of {@link G9SyncTransport}. */\nexport class G9SignalRSyncTransport implements G9SyncTransport {\n readonly client: G9Client;\n readonly format: G9WireFormat;\n private readonly _options: G9SignalRSyncTransportOptions;\n private readonly _handlers: ((changes: G9DtChangesAvailable) => void)[] = [];\n private _connecting: Promise<void> | null = null;\n private _lastHello: G9DtHelloRequest | null = null;\n /** The model this connection already sent in full, and the server's id for it (1.5.21, twin of .NET `_modelOnConnection`). */\n private _modelOnConnection: { connectionId: string | null; tables: G9DtHelloRequest['tables']; modelHash: string } | null = null;\n\n constructor(options: G9SignalRSyncTransportOptions) {\n if (!options || typeof options.url !== 'string' || options.url.trim() === '') throw new TypeError('A hub URL is required.');\n this._options = options;\n const json = options.protocol === G9ESyncHubProtocol.Json;\n this.format = json ? 'json' : 'messagepack';\n const protocol: IHubProtocol = json ? new G9SyncJsonHubProtocol() : createSyncMessagePackProtocol();\n const clientOptions: G9ClientOptions = {\n ...(options.client ?? {}),\n url: options.url,\n protocol,\n statefulReconnect: options.statefulReconnect ?? false,\n serverTimeoutMs: options.serverTimeoutMs ?? 30000,\n keepAliveIntervalMs: options.keepAliveIntervalMs ?? 10000,\n };\n if (options.accessTokenFactory) clientOptions.accessTokenFactory = options.accessTokenFactory;\n this.client = options.createClient ? options.createClient(clientOptions) : new G9Client(clientOptions);\n this.client.on(G9SyncProtocol.Listeners.OnChangesAvailable, (payload: unknown) => this._onChanges(payload));\n // Twin of .NET OnReconnectedAsync (S-2, LES-0087): a connection that reconnected by itself is a new connection id in no table group.\n const connection = this.client.connection as { onreconnected?: (callback: (connectionId?: string) => void) => void };\n if (typeof connection.onreconnected === 'function') connection.onreconnected(() => this._rejoin());\n }\n\n get isConnected(): boolean {\n return this.client.connection.state === HubConnectionState.Connected;\n }\n\n onChangesAvailable(handler: (changes: G9DtChangesAvailable) => void): () => void {\n this._handlers.push(handler);\n return () => {\n const index = this._handlers.indexOf(handler);\n if (index >= 0) this._handlers.splice(index, 1);\n };\n }\n\n /** Connects (joins a connect in progress); a connect that takes longer than connectTimeoutMs is a network failure. */\n connect(signal?: AbortSignal): Promise<void> {\n if (this.isConnected) return Promise.resolve();\n if (!this._connecting) {\n const connecting = this._connectCore().finally(() => {\n if (this._connecting === connecting) this._connecting = null;\n });\n this._connecting = connecting;\n }\n const connecting = this._connecting;\n if (!signal) return connecting;\n return new Promise<void>((resolve, reject) => {\n const unsubscribe = onAbort(signal, () => reject(new G9SyncException(G9SyncErrorCodes.Canceled, 'The connect was canceled.')));\n connecting.then(\n () => {\n unsubscribe();\n resolve();\n },\n (error) => {\n unsubscribe();\n reject(error);\n },\n );\n });\n }\n\n private async _connectCore(): Promise<void> {\n const timeout = createAbortController();\n const timer = setTimeout(() => timeout.abort(), this._options.connectTimeoutMs ?? 20000);\n try {\n await this.client.start(timeout.signal);\n } catch (error) {\n const mapped = mapError(error, false) ?? new G9SyncException(G9SyncErrorCodes.NetworkFailure, messageOf(error), { retryable: true, cause: error });\n throw mapped.code === G9SyncErrorCodes.Canceled\n ? new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync connection to ${this._options.url} did not open in time.`, { retryable: true, cause: error })\n : mapped;\n } finally {\n clearTimeout(timer);\n }\n if (!this.isConnected) {\n throw new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync connection is ${String(this.client.connection.state)}.`, { retryable: true });\n }\n }\n\n /**\n * The model once per connection (1.5.21, TR-0069; twin of .NET `HelloAsync`): the first Hello of a connection sends the whole model, a\n * later one on the same connection with the same tables (the engine keeps one array) only the server's id for it. A server that lost it\n * answers `modelRequired` and the full Hello goes at once. A new connection — a reconnect included — always starts with the full model.\n */\n async hello(request: G9DtHelloRequest, signal?: AbortSignal): Promise<G9DtHelloResult> {\n const known = this._modelOnConnection;\n const sent: G9DtHelloRequest =\n known && known.connectionId === this._connectionId() && known.tables === request.tables && request.tables.length > 0\n ? { ...request, tables: [], modelHash: known.modelHash }\n : request;\n let result = await this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(sent)], readHelloResult, this._callTimeoutMs(), signal);\n if (result.modelRequired && sent !== request) {\n this._modelOnConnection = null;\n result = await this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(request)], readHelloResult, this._callTimeoutMs(), signal);\n }\n if (!result.error) {\n this._lastHello = request;\n this._rememberModel(request, result);\n }\n return result;\n }\n\n private _rememberModel(full: G9DtHelloRequest, result: G9DtHelloResult): void {\n if (result.modelHash && full.tables.length > 0) this._modelOnConnection = { connectionId: this._connectionId(), tables: full.tables, modelHash: result.modelHash };\n }\n\n private _connectionId(): string | null {\n const id = (this.client.connection as { connectionId?: string | null }).connectionId;\n return typeof id === 'string' ? id : null;\n }\n\n /**\n * After an automatic reconnect the last accepted Hello is sent again, so the new connection joins the table groups pokes go to\n * (S-2, LES-0087). Fire and forget, bounded by the call timeout; the answer is not used and a failure only delays a hint.\n */\n private _rejoin(): void {\n const hello = this._lastHello;\n if (!hello) return;\n // The full Hello (a new connection never holds the model): its answer names the model for the next Hello on it.\n this._invoke(G9SyncProtocol.Methods.Hello, [this._wire(hello)], readHelloResult, this._callTimeoutMs())\n .then((result) => {\n if (!result.error) this._rememberModel(hello, result);\n })\n .catch(() => undefined);\n }\n\n push(request: G9DtPushRequest, chunks: AsyncIterable<G9DtSyncChunk>, signal?: AbortSignal): Promise<G9DtPushResult> {\n const subject = new Subject<unknown>();\n const result = this._invoke(G9SyncProtocol.Methods.Push, [this._wire(request), subject], readPushResult, this._options.pushTimeoutMs ?? 600000, signal);\n void (async () => {\n try {\n for await (const chunk of chunks) subject.next(this._wire(chunk));\n subject.complete();\n } catch (error) {\n subject.error(error);\n }\n })();\n return result;\n }\n\n planPull(request: G9DtPullRequest, signal?: AbortSignal): Promise<G9DtPullPlan> {\n return this._invoke(G9SyncProtocol.Methods.PlanPull, [this._wire(request)], readPullPlan, this._options.planTimeoutMs ?? 300000, signal);\n }\n\n pull(token: string, continuation: G9DtPullContinuation | null, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n return this._stream(G9SyncProtocol.Methods.Pull, [token, continuation === null ? null : this._wire(continuation)], signal);\n }\n\n reconcile(request: G9DtReconcileRequest, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n return this._stream(G9SyncProtocol.Methods.Reconcile, [this._wire(request)], signal);\n }\n\n fetchRows(request: G9DtFetchRowsRequest, signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n return this._stream(G9SyncProtocol.Methods.FetchRows, [this._wire(request)], signal);\n }\n\n async dispose(): Promise<void> {\n this._handlers.length = 0;\n await this.client.stop();\n }\n\n // ================================================================ plumbing\n\n private _wire(value: unknown): unknown {\n return this.format === 'messagepack' ? toMessagePackNames(value) : value;\n }\n\n private _read(value: unknown): unknown {\n return this.format === 'messagepack' ? fromMessagePackNames(value) : value;\n }\n\n private _callTimeoutMs(): number {\n return this._options.callTimeoutMs ?? 60000;\n }\n\n private async _invoke<T>(method: string, args: unknown[], read: (value: unknown) => T, timeoutMs: number, signal?: AbortSignal): Promise<T> {\n if (signal && signal.aborted) throw new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.');\n let unsubscribe: () => void = () => undefined;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let timedOut = false;\n try {\n const call = this.client.connection.invoke(method, ...args);\n const raw =\n signal || timeoutMs > 0\n ? await new Promise<unknown>((resolve, reject) => {\n if (signal) unsubscribe = onAbort(signal, () => reject(new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.')));\n if (timeoutMs > 0) {\n timer = setTimeout(() => {\n timedOut = true;\n reject(\n new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync server did not answer ${method} within ${Math.round(timeoutMs / 1000)} s.`, {\n retryable: true,\n }),\n );\n }, timeoutMs);\n }\n call.then(resolve, reject);\n })\n : await call;\n return read(this._read(raw));\n } catch (error) {\n // ADR-0074: the answer did not come in time. The connection is not trusted any more (the server runs one invocation per\n // connection at a time, and whatever lost this answer may lose the next): drop it, so the retry runs on a fresh one.\n if (timedOut) await this._dropConnection();\n throw mapError(error, signal ? signal.aborted : false) ?? error;\n } finally {\n if (timer !== null) clearTimeout(timer);\n unsubscribe();\n }\n }\n\n /** Ends the connection after a call or stream ran out of time (ADR-0074); the next call connects afresh. Never throws. */\n private async _dropConnection(): Promise<void> {\n try {\n await this.client.connection.stop();\n } catch {\n // Stopping a connection that is already gone may throw; the next call connects afresh either way.\n }\n }\n\n private _stream(method: string, args: unknown[], signal?: AbortSignal): AsyncIterable<G9DtSyncChunk> {\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n return {\n [Symbol.asyncIterator](): AsyncIterator<G9DtSyncChunk> {\n const queue: G9DtSyncChunk[] = [];\n let done = false;\n let failure: unknown = null;\n let wake: (() => void) | null = null;\n let subscription: ISubscription<unknown> | null = null;\n const notify = (): void => {\n const w = wake;\n wake = null;\n if (w) w();\n };\n let unsubscribeAbort: () => void = () => undefined;\n // ADR-0074: the idle limit runs only while the iterator waits for the next chunk, never while the caller processes one.\n const idleMs = self._options.streamIdleTimeoutMs ?? 120000;\n let idleTimer: ReturnType<typeof setTimeout> | null = null;\n let idleExpired = false;\n const stopIdle = (): void => {\n if (idleTimer !== null) clearTimeout(idleTimer);\n idleTimer = null;\n };\n const armIdle = (): void => {\n stopIdle();\n if (idleMs <= 0 || done) return;\n idleTimer = setTimeout(() => {\n idleTimer = null;\n if (done) return;\n idleExpired = true;\n failure = new G9SyncException(G9SyncErrorCodes.NetworkFailure, `The sync server sent nothing on ${method} for ${Math.round(idleMs / 1000)} s.`, {\n retryable: true,\n });\n done = true;\n subscription?.dispose();\n notify();\n }, idleMs);\n };\n const start = (): void => {\n if (subscription || done) return;\n let stream: IStreamResult<unknown>;\n try {\n stream = self.client.connection.stream(method, ...args);\n } catch (error) {\n failure = error;\n done = true;\n return;\n }\n subscription = stream.subscribe({\n next: (item) => {\n queue.push(readSyncChunk(self._read(item)));\n notify();\n },\n error: (error) => {\n failure = error;\n done = true;\n notify();\n },\n complete: () => {\n done = true;\n notify();\n },\n });\n unsubscribeAbort = onAbort(signal, () => {\n failure = new G9SyncException(G9SyncErrorCodes.Canceled, 'The stream was canceled.');\n done = true;\n subscription?.dispose();\n notify();\n });\n };\n const finish = (): void => {\n stopIdle();\n unsubscribeAbort();\n if (subscription && !done) subscription.dispose();\n done = true;\n };\n return {\n async next(): Promise<IteratorResult<G9DtSyncChunk>> {\n start();\n for (;;) {\n const item = queue.shift();\n if (item) {\n stopIdle();\n return { value: item, done: false };\n }\n if (done) {\n stopIdle();\n unsubscribeAbort();\n if (idleExpired) await self._dropConnection();\n if (failure !== null) throw mapError(failure, signal ? signal.aborted : false) ?? failure;\n return { value: undefined as unknown as G9DtSyncChunk, done: true };\n }\n if (idleTimer === null) armIdle();\n await new Promise<void>((resolve) => {\n wake = resolve;\n });\n }\n },\n async return(): Promise<IteratorResult<G9DtSyncChunk>> {\n finish();\n return { value: undefined as unknown as G9DtSyncChunk, done: true };\n },\n };\n },\n };\n }\n\n private _onChanges(payload: unknown): void {\n const changes = readChangesAvailable(this._read(payload));\n for (const handler of this._handlers.slice()) {\n try {\n handler(changes);\n } catch {\n // A ChangesAvailable handler threw (logged by the .NET transport); it must not break the connection.\n }\n }\n }\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\n/**\n * The sync exception for a transport failure (`Map`): the server's `[G9S|code|retryable]` marker wins; any other hub\n * error is a retryable server error; 401/403 is Unauthorized; the rest is a retryable network failure. Null leaves the\n * error as it is (an already mapped one).\n */\nexport function mapError(error: unknown, canceled: boolean): G9SyncException | null {\n if (isSyncException(error)) return null;\n if (canceled) return new G9SyncException(G9SyncErrorCodes.Canceled, 'The call was canceled.', { cause: error });\n const message = messageOf(error);\n const marked = G9SyncHubErrors.tryParse(message);\n if (marked) return marked;\n const status = (error as { statusCode?: unknown }).statusCode;\n if (status === 401 || status === 403) return new G9SyncException(G9SyncErrorCodes.Unauthorized, 'The sync server refused the credentials.', { cause: error });\n if (error instanceof Error && error.name === 'AbortError') return new G9SyncException(G9SyncErrorCodes.Canceled, message, { cause: error });\n // A completion error from the hub: SignalR words it \"An unexpected error occurred invoking '…' on the server.\"\n if (/on the server|HubException/i.test(message)) return new G9SyncException(G9SyncErrorCodes.ServerError, message, { retryable: true, cause: error });\n return new G9SyncException(G9SyncErrorCodes.NetworkFailure, message, { retryable: true, cause: error });\n}\n"]}
|
|
@@ -26,6 +26,20 @@ export declare function disposeReleasedRows(store: StoreInternals, connection: G
|
|
|
26
26
|
* NeedsReconcile, so their next sync of any kind does it (offline now is fine). A library write: capture is silent, nothing uploads.
|
|
27
27
|
*/
|
|
28
28
|
export declare function revertRejected(store: StoreInternals, localTable: string | null, key: string | null): Promise<number>;
|
|
29
|
+
/**
|
|
30
|
+
* `RefetchRowsAsync` (1.5.19): the next sync fetches these rows again and overwrites their values. Every CLEAN row a subscription
|
|
31
|
+
* holds (no pending change, no rejection, not deleted) gets `server_ver = -1` - a version no server issues, so the reconcile's
|
|
32
|
+
* digest differs and the apply writes the server's values and real version - and the subscriptions holding them become
|
|
33
|
+
* NeedsReconcile. Metadata only: the app's table and the change feed are untouched, nothing uploads.
|
|
34
|
+
*/
|
|
35
|
+
export declare function refetchRows(store: StoreInternals, localTable: string, keys: readonly string[] | null): Promise<number>;
|
|
36
|
+
/**
|
|
37
|
+
* `ReleaseUnclaimedRowsAsync` (1.5.19): disposes rows of one table that no subscription holds and the server never claimed
|
|
38
|
+
* (`server_ver = 0`), not decided before (revoked, quarantined), not an ephemeral member and not in a pending command - reason
|
|
39
|
+
* Unclaimed, capture off, nothing uploads. A pending change (and a refused one) only with `includePending`: then the revocation
|
|
40
|
+
* policy decides it like any released row (the default quarantines it, the refusal with it).
|
|
41
|
+
*/
|
|
42
|
+
export declare function releaseUnclaimedRows(store: StoreInternals, localTable: string, keys: readonly string[] | null, includePending: boolean): Promise<G9ApplyReport>;
|
|
29
43
|
/** `RemoveLocalRow`: the row leaves the app's table; its metadata becomes a tombstone at the clock's next value. */
|
|
30
44
|
export declare function removeLocalRow(connection: G9SqliteConnection, table: LocalTable, key: string): Promise<void>;
|
|
31
45
|
export declare function getQuarantined(store: StoreInternals): Promise<G9QuarantinedRow[]>;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// clock afterwards (unconditionally, like the .NET store's `++sequence`).
|
|
7
7
|
import { G9ESyncColumnType } from '../abstractions/enums.js';
|
|
8
8
|
import { G9Long } from '../abstractions/long.js';
|
|
9
|
+
import { G9SyncKey } from '../abstractions/key.js';
|
|
9
10
|
import { G9ApplyReport, G9ERevocationDisposition, G9ERevocationReason, G9ESubscriptionState, } from '../client/storeTypes.js';
|
|
10
11
|
import { asLong, asNumber, asOptionalString, asString, G9StatementBatch, statementsOf } from './connection.js';
|
|
11
12
|
import { byTid, deserializeValues, getLocal, keyValue, nowMs, readLocalValues, serializeValues } from './internals.js';
|
|
@@ -363,6 +364,81 @@ export async function revertRejected(store, localTable, key) {
|
|
|
363
364
|
return rows.length;
|
|
364
365
|
}));
|
|
365
366
|
}
|
|
367
|
+
/** Canonical keys of `keys` (a GUID key in any spelling finds its row), distinct, as JSON pages of 5000; `[null]` = the whole table. */
|
|
368
|
+
function keyPages(table, keys) {
|
|
369
|
+
if (keys === null)
|
|
370
|
+
return [null];
|
|
371
|
+
const canonical = [...new Set(keys.map((k) => { var _a; return (_a = G9SyncKey.tryNormalize(table.model.keyType, k)) !== null && _a !== void 0 ? _a : k; }))];
|
|
372
|
+
const pages = [];
|
|
373
|
+
for (let i = 0; i < canonical.length; i += 5000)
|
|
374
|
+
pages.push(JSON.stringify(canonical.slice(i, i + 5000)));
|
|
375
|
+
return pages;
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* `RefetchRowsAsync` (1.5.19): the next sync fetches these rows again and overwrites their values. Every CLEAN row a subscription
|
|
379
|
+
* holds (no pending change, no rejection, not deleted) gets `server_ver = -1` - a version no server issues, so the reconcile's
|
|
380
|
+
* digest differs and the apply writes the server's values and real version - and the subscriptions holding them become
|
|
381
|
+
* NeedsReconcile. Metadata only: the app's table and the change feed are untouched, nothing uploads.
|
|
382
|
+
*/
|
|
383
|
+
export async function refetchRows(store, localTable, keys) {
|
|
384
|
+
store.ensureInitialized();
|
|
385
|
+
const table = getLocal(store, localTable);
|
|
386
|
+
const pages = keyPages(table, keys);
|
|
387
|
+
return store.writeLock.run(() => store.writer().transaction('immediate', async () => {
|
|
388
|
+
const connection = store.writer();
|
|
389
|
+
const clean = 'tid = $t AND dirty = 0 AND rejected = 0 AND deleted = 0 AND subs <> 0';
|
|
390
|
+
let marked = 0;
|
|
391
|
+
for (const page of pages) {
|
|
392
|
+
const where = clean + (page === null ? '' : ' AND pk IN (SELECT value FROM json_each($keys))');
|
|
393
|
+
const params = page === null ? { $t: table.tid } : { $t: table.tid, $keys: page };
|
|
394
|
+
// The holders first: every subscription with its bit in one of these rows.
|
|
395
|
+
await connection.exec(`UPDATE g9_subscriptions SET state = $needs WHERE EXISTS (SELECT 1 FROM g9_rows WHERE ${where} AND ((subs >> g9_subscriptions.slot) & 1) = 1)`, { ...params, $needs: G9ESubscriptionState.NeedsReconcile });
|
|
396
|
+
marked += await connection.exec('UPDATE g9_rows SET server_ver = -1 WHERE ' + where, params);
|
|
397
|
+
}
|
|
398
|
+
return marked;
|
|
399
|
+
}));
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* `ReleaseUnclaimedRowsAsync` (1.5.19): disposes rows of one table that no subscription holds and the server never claimed
|
|
403
|
+
* (`server_ver = 0`), not decided before (revoked, quarantined), not an ephemeral member and not in a pending command - reason
|
|
404
|
+
* Unclaimed, capture off, nothing uploads. A pending change (and a refused one) only with `includePending`: then the revocation
|
|
405
|
+
* policy decides it like any released row (the default quarantines it, the refusal with it).
|
|
406
|
+
*/
|
|
407
|
+
export async function releaseUnclaimedRows(store, localTable, keys, includePending) {
|
|
408
|
+
store.ensureInitialized();
|
|
409
|
+
const table = getLocal(store, localTable);
|
|
410
|
+
const pages = keyPages(table, keys);
|
|
411
|
+
const report = new G9ApplyReport();
|
|
412
|
+
const where = 'r.tid = $t AND r.subs = 0 AND r.deleted = 0 AND r.server_ver = 0' +
|
|
413
|
+
(includePending ? '' : ' AND r.dirty = 0 AND r.rejected = 0') +
|
|
414
|
+
' AND NOT EXISTS (SELECT 1 FROM g9_revoked v WHERE v.tid = r.tid AND v.pk = r.pk)' +
|
|
415
|
+
' AND NOT EXISTS (SELECT 1 FROM g9_quarantine q WHERE q.tid = r.tid AND q.pk = r.pk)' +
|
|
416
|
+
' AND NOT EXISTS (SELECT 1 FROM g9_ephemeral_rows e WHERE e.tid = r.tid AND e.pk = r.pk)' +
|
|
417
|
+
' AND NOT EXISTS (SELECT 1 FROM g9_command_rows cr JOIN g9_commands c ON c.command_id = cr.command_id WHERE c.state = 0 AND cr.tid = r.tid AND cr.pk = r.pk)';
|
|
418
|
+
await store.writeLock.run(() => store.writer().transaction('immediate', async () => {
|
|
419
|
+
const connection = store.writer();
|
|
420
|
+
// Every page is read BEFORE anything is disposed (.NET collects the whole list first), each in key order.
|
|
421
|
+
await connection.exec('DROP TABLE IF EXISTS temp.g9_unclaimed; CREATE TEMP TABLE g9_unclaimed (n INTEGER PRIMARY KEY, tid INTEGER NOT NULL, pk TEXT NOT NULL)');
|
|
422
|
+
for (const page of pages) {
|
|
423
|
+
const byKeys = page === null ? '' : ' AND r.pk IN (SELECT value FROM json_each($keys))';
|
|
424
|
+
await connection.exec(`INSERT INTO temp.g9_unclaimed (tid, pk) SELECT r.tid, r.pk FROM g9_rows r WHERE ${where}${byKeys} ORDER BY r.pk`, page === null ? { $t: table.tid } : { $t: table.tid, $keys: page });
|
|
425
|
+
}
|
|
426
|
+
if (asNumber(await connection.scalar('SELECT count(*) FROM temp.g9_unclaimed')) > 0) {
|
|
427
|
+
// Capture OFF: a release is local housekeeping and must never reach the server as a delete.
|
|
428
|
+
await connection.exec('UPDATE g9_ctx SET applying = 1 WHERE id = 1');
|
|
429
|
+
const max = store.options.maxChangedKeysPerTable;
|
|
430
|
+
await disposeReleasedRows(store, connection, 'SELECT tid, pk FROM temp.g9_unclaimed ORDER BY n', {}, G9ERevocationReason.Unclaimed, null, report, (_tid, key) => {
|
|
431
|
+
var _a;
|
|
432
|
+
const changed = (_a = report.changedKeys[table.model.localName]) !== null && _a !== void 0 ? _a : (report.changedKeys[table.model.localName] = []);
|
|
433
|
+
if (changed.length < max)
|
|
434
|
+
changed.push(key);
|
|
435
|
+
});
|
|
436
|
+
await connection.exec('UPDATE g9_ctx SET applying = 0 WHERE id = 1');
|
|
437
|
+
}
|
|
438
|
+
await connection.exec('DROP TABLE temp.g9_unclaimed');
|
|
439
|
+
}));
|
|
440
|
+
return report;
|
|
441
|
+
}
|
|
366
442
|
/** `RemoveLocalRow`: the row leaves the app's table; its metadata becomes a tombstone at the clock's next value. */
|
|
367
443
|
export async function removeLocalRow(connection, table, key) {
|
|
368
444
|
for (const statement of removeLocalRowStatements(table, key, NEXT_SEQ, {}))
|