@korajs/sync 1.0.0-beta.1 → 1.0.0-beta.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +142 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +36 -3
- package/dist/index.d.ts +36 -3
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/{transport-CZLMdZ0k.d.cts → transport-BGr-_eH8.d.cts} +75 -2
- package/dist/{transport-CZLMdZ0k.d.ts → transport-BGr-_eH8.d.ts} +75 -2
- package/package.json +3 -3
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SyncScopeMap, D as DeltaCursor, a as SyncMessage, b as SerializedOperation, W as WireFormat, c as SyncTransport, T as TransportOptions, d as TransportMessageHandler, e as TransportCloseHandler, f as TransportErrorHandler, B as BlobChunkRequestMessage, g as BlobChunkResponseMessage, h as BlobChunkPushMessage, i as SyncEncryptionConfig, V as VersionedKey, Y as YjsDocUpdateMessage, Q as QueueStorage, j as SyncState, k as SyncStatusInfo, l as SyncConfig, m as SyncStatePersistence, n as SyncQuerySubset } from './transport-
|
|
2
|
-
export { A as AcknowledgmentMessage,
|
|
1
|
+
import { S as SyncScopeMap, D as DeltaCursor, a as SyncMessage, b as SerializedOperation, W as WireFormat, c as SyncTransport, T as TransportOptions, d as TransportMessageHandler, e as TransportCloseHandler, f as TransportErrorHandler, B as BlobChunkRequestMessage, g as BlobChunkResponseMessage, h as BlobChunkPushMessage, i as SyncEncryptionConfig, V as VersionedKey, Y as YjsDocUpdateMessage, Q as QueueStorage, j as SyncState, k as SyncStatusInfo, l as SyncConfig, R as RejectedOperationStorage, m as SyncStatePersistence, n as SyncQuerySubset, o as RejectedOperation } from './transport-BGr-_eH8.cjs';
|
|
2
|
+
export { A as AcknowledgmentMessage, p as AwarenessStateWire, q as AwarenessUpdateMessage, E as EncryptedPayload, r as ErrorMessage, H as HandshakeMessage, s as HandshakeResponseMessage, I as InvalidScopeError, M as MemoryRejectedOperationStorage, O as OperationBatchMessage, t as OperationRejectedMessage, u as SYNC_STATES, v as SYNC_STATUSES, w as ScopeViolationError, x as SyncEncryptionAlgorithm, y as SyncScopeContext, z as SyncStatus, C as dedupeQuerySubsets, F as isAcknowledgmentMessage, G as isAwarenessUpdateMessage, J as isBlobChunkPushMessage, K as isBlobChunkRequestMessage, L as isBlobChunkResponseMessage, N as isErrorMessage, P as isHandshakeMessage, U as isHandshakeResponseMessage, X as isOperationBatchMessage, Z as isOperationRejectedMessage, _ as isSyncMessage, $ as isYjsDocUpdateMessage, a0 as operationMatchesQuerySubsets } from './transport-BGr-_eH8.cjs';
|
|
3
3
|
import * as _korajs_core from '@korajs/core';
|
|
4
4
|
import { Operation, VersionVector, ApplyResult, KoraEventEmitter, TimeSource, SyncError, ConnectionQuality } from '@korajs/core';
|
|
5
5
|
export { ApplyFailureReason, ApplyResult } from '@korajs/core';
|
|
@@ -844,6 +844,14 @@ declare class OutboundQueue {
|
|
|
844
844
|
* Whether initialize() has been called.
|
|
845
845
|
*/
|
|
846
846
|
get isInitialized(): boolean;
|
|
847
|
+
/**
|
|
848
|
+
* Remove a single operation the server permanently rejected — from the queue,
|
|
849
|
+
* from any in-flight batch, and from durable storage — so a later batch ack or
|
|
850
|
+
* a reconnect `returnBatch` can never resend or resurrect it. Returns the
|
|
851
|
+
* removed operation so the caller can record it in a durable rejected store,
|
|
852
|
+
* or null if it was not present (already acknowledged and removed).
|
|
853
|
+
*/
|
|
854
|
+
reject(opId: string): Promise<Operation | null>;
|
|
847
855
|
/**
|
|
848
856
|
* Remove operations by id from queue and persistent storage.
|
|
849
857
|
* Used when ops were already sent during handshake delta exchange.
|
|
@@ -867,6 +875,11 @@ interface SyncEngineOptions {
|
|
|
867
875
|
emitter?: KoraEventEmitter;
|
|
868
876
|
/** Queue storage for persistent outbound queue. Defaults to in-memory. */
|
|
869
877
|
queueStorage?: QueueStorage;
|
|
878
|
+
/**
|
|
879
|
+
* Durable storage for operations the server rejected. Defaults to in-memory.
|
|
880
|
+
* Provide a store-backed implementation so rejections survive a page refresh.
|
|
881
|
+
*/
|
|
882
|
+
rejectedStorage?: RejectedOperationStorage;
|
|
870
883
|
/**
|
|
871
884
|
* Optional encryptor for end-to-end encryption.
|
|
872
885
|
* When provided, `data` and `previousData` fields of operations are encrypted
|
|
@@ -911,6 +924,7 @@ declare class SyncEngine {
|
|
|
911
924
|
private readonly serializer;
|
|
912
925
|
private readonly emitter;
|
|
913
926
|
private readonly outboundQueue;
|
|
927
|
+
private readonly rejectedStorage;
|
|
914
928
|
private readonly batchSize;
|
|
915
929
|
private readonly encryptor;
|
|
916
930
|
private readonly awarenessManager;
|
|
@@ -1107,6 +1121,25 @@ declare class SyncEngine {
|
|
|
1107
1121
|
private handleOperationBatch;
|
|
1108
1122
|
private handleAcknowledgment;
|
|
1109
1123
|
private handleError;
|
|
1124
|
+
/**
|
|
1125
|
+
* Handle a per-operation rejection: divert the op out of the pending outbound
|
|
1126
|
+
* queue (so it is never retried or resurrected on reconnect), record it in the
|
|
1127
|
+
* durable rejected store (so it is kept and explainable), and emit an event so
|
|
1128
|
+
* the app can reconcile. Unlike {@link handleError}, this is a normal per-op
|
|
1129
|
+
* signal, so the connection stays up.
|
|
1130
|
+
*/
|
|
1131
|
+
private handleOperationRejected;
|
|
1132
|
+
/**
|
|
1133
|
+
* Every operation the server rejected that has not yet been reconciled. The app
|
|
1134
|
+
* uses this (alongside the `sync:operation-rejected` event) to surface failed
|
|
1135
|
+
* submissions and decide whether to roll back or resubmit.
|
|
1136
|
+
*/
|
|
1137
|
+
getRejectedOperations(): Promise<RejectedOperation[]>;
|
|
1138
|
+
/**
|
|
1139
|
+
* Forget rejected operations by id once the app has reconciled them (rolled the
|
|
1140
|
+
* optimistic write back or resubmitted a corrected op).
|
|
1141
|
+
*/
|
|
1142
|
+
clearRejectedOperations(operationIds: string[]): Promise<void>;
|
|
1110
1143
|
private checkDeltaComplete;
|
|
1111
1144
|
/**
|
|
1112
1145
|
* Effective server vector: persisted last-ack merged with live handshake remote vector.
|
|
@@ -1375,4 +1408,4 @@ declare function getRemoteAwarenessStates(awareness: AwarenessManager): Awarenes
|
|
|
1375
1408
|
*/
|
|
1376
1409
|
declare function subscribeRemoteAwarenessStates(awareness: AwarenessManager, listener: (states: AwarenessState[]) => void): () => void;
|
|
1377
1410
|
|
|
1378
|
-
export { type AwarenessChange, type AwarenessCursor, AwarenessManager, type AwarenessMessage, type AwarenessState, type AwarenessUser, BlobChunkChannel, type BlobChunkChannelMessage, type BlobChunkChannelOptions, BlobChunkPushMessage, BlobChunkRequestMessage, BlobChunkResponseMessage, type ChaosConfig, ChaosTransport, ConnectionMonitor, type ConnectionMonitorConfig, type CursorInfo, DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD, DecryptionError, DeltaCursor, EncryptionError, HttpLongPollingTransport, type HttpLongPollingTransportOptions, JsonMessageSerializer, KeyDerivationError, type MessageSerializer, NegotiatedMessageSerializer, OFFLINE_SYNC_STATUS, type OutboundBatch, OutboundQueue, ProtobufMessageSerializer, QueueStorage, type ReconnectionConfig, ReconnectionManager, RichtextDocChannel, type RichtextDocChannelOptions, type RichtextDocListener, SCHEMA_MISMATCH_PREFIX, SerializedOperation, SyncConfig, type SyncDiagnostics, SyncEncryptionConfig, SyncEncryptor, SyncEngine, type SyncEngineOptions, SyncMessage, SyncQuerySubset, SyncScopeMap, SyncState, SyncStatePersistence, type SyncStatusController, type SyncStatusControllerOptions, SyncStatusInfo, type SyncStore, SyncTransport, TransportCloseHandler, TransportErrorHandler, TransportMessageHandler, TransportOptions, VersionedKey, type WebSocketConstructor, type WebSocketLike, WebSocketTransport, type WebSocketTransportOptions, WireFormat, YjsDocUpdateMessage, createDeltaCursorFromBatch, createSyncStatusController, decodeBlobChunkBytes, decodeDeltaCursor, decodeYjsUpdate, deriveKey, deriveVersionedKey, encodeBlobChunkBytes, encodeDeltaCursor, encodeYjsUpdate, filterOperationsByScope, generateSalt, getRemoteAwarenessStates, isClientSchemaVersionSupported, isEncryptedPayload, isSchemaMismatchReject, operationMatchesScope, richtextDocKey, sliceOperationsAfterCursor, subscribeRemoteAwarenessStates, versionVectorToWire, wireToVersionVector };
|
|
1411
|
+
export { type AwarenessChange, type AwarenessCursor, AwarenessManager, type AwarenessMessage, type AwarenessState, type AwarenessUser, BlobChunkChannel, type BlobChunkChannelMessage, type BlobChunkChannelOptions, BlobChunkPushMessage, BlobChunkRequestMessage, BlobChunkResponseMessage, type ChaosConfig, ChaosTransport, ConnectionMonitor, type ConnectionMonitorConfig, type CursorInfo, DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD, DecryptionError, DeltaCursor, EncryptionError, HttpLongPollingTransport, type HttpLongPollingTransportOptions, JsonMessageSerializer, KeyDerivationError, type MessageSerializer, NegotiatedMessageSerializer, OFFLINE_SYNC_STATUS, type OutboundBatch, OutboundQueue, ProtobufMessageSerializer, QueueStorage, type ReconnectionConfig, ReconnectionManager, RejectedOperation, RejectedOperationStorage, RichtextDocChannel, type RichtextDocChannelOptions, type RichtextDocListener, SCHEMA_MISMATCH_PREFIX, SerializedOperation, SyncConfig, type SyncDiagnostics, SyncEncryptionConfig, SyncEncryptor, SyncEngine, type SyncEngineOptions, SyncMessage, SyncQuerySubset, SyncScopeMap, SyncState, SyncStatePersistence, type SyncStatusController, type SyncStatusControllerOptions, SyncStatusInfo, type SyncStore, SyncTransport, TransportCloseHandler, TransportErrorHandler, TransportMessageHandler, TransportOptions, VersionedKey, type WebSocketConstructor, type WebSocketLike, WebSocketTransport, type WebSocketTransportOptions, WireFormat, YjsDocUpdateMessage, createDeltaCursorFromBatch, createSyncStatusController, decodeBlobChunkBytes, decodeDeltaCursor, decodeYjsUpdate, deriveKey, deriveVersionedKey, encodeBlobChunkBytes, encodeDeltaCursor, encodeYjsUpdate, filterOperationsByScope, generateSalt, getRemoteAwarenessStates, isClientSchemaVersionSupported, isEncryptedPayload, isSchemaMismatchReject, operationMatchesScope, richtextDocKey, sliceOperationsAfterCursor, subscribeRemoteAwarenessStates, versionVectorToWire, wireToVersionVector };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as SyncScopeMap, D as DeltaCursor, a as SyncMessage, b as SerializedOperation, W as WireFormat, c as SyncTransport, T as TransportOptions, d as TransportMessageHandler, e as TransportCloseHandler, f as TransportErrorHandler, B as BlobChunkRequestMessage, g as BlobChunkResponseMessage, h as BlobChunkPushMessage, i as SyncEncryptionConfig, V as VersionedKey, Y as YjsDocUpdateMessage, Q as QueueStorage, j as SyncState, k as SyncStatusInfo, l as SyncConfig, m as SyncStatePersistence, n as SyncQuerySubset } from './transport-
|
|
2
|
-
export { A as AcknowledgmentMessage,
|
|
1
|
+
import { S as SyncScopeMap, D as DeltaCursor, a as SyncMessage, b as SerializedOperation, W as WireFormat, c as SyncTransport, T as TransportOptions, d as TransportMessageHandler, e as TransportCloseHandler, f as TransportErrorHandler, B as BlobChunkRequestMessage, g as BlobChunkResponseMessage, h as BlobChunkPushMessage, i as SyncEncryptionConfig, V as VersionedKey, Y as YjsDocUpdateMessage, Q as QueueStorage, j as SyncState, k as SyncStatusInfo, l as SyncConfig, R as RejectedOperationStorage, m as SyncStatePersistence, n as SyncQuerySubset, o as RejectedOperation } from './transport-BGr-_eH8.js';
|
|
2
|
+
export { A as AcknowledgmentMessage, p as AwarenessStateWire, q as AwarenessUpdateMessage, E as EncryptedPayload, r as ErrorMessage, H as HandshakeMessage, s as HandshakeResponseMessage, I as InvalidScopeError, M as MemoryRejectedOperationStorage, O as OperationBatchMessage, t as OperationRejectedMessage, u as SYNC_STATES, v as SYNC_STATUSES, w as ScopeViolationError, x as SyncEncryptionAlgorithm, y as SyncScopeContext, z as SyncStatus, C as dedupeQuerySubsets, F as isAcknowledgmentMessage, G as isAwarenessUpdateMessage, J as isBlobChunkPushMessage, K as isBlobChunkRequestMessage, L as isBlobChunkResponseMessage, N as isErrorMessage, P as isHandshakeMessage, U as isHandshakeResponseMessage, X as isOperationBatchMessage, Z as isOperationRejectedMessage, _ as isSyncMessage, $ as isYjsDocUpdateMessage, a0 as operationMatchesQuerySubsets } from './transport-BGr-_eH8.js';
|
|
3
3
|
import * as _korajs_core from '@korajs/core';
|
|
4
4
|
import { Operation, VersionVector, ApplyResult, KoraEventEmitter, TimeSource, SyncError, ConnectionQuality } from '@korajs/core';
|
|
5
5
|
export { ApplyFailureReason, ApplyResult } from '@korajs/core';
|
|
@@ -844,6 +844,14 @@ declare class OutboundQueue {
|
|
|
844
844
|
* Whether initialize() has been called.
|
|
845
845
|
*/
|
|
846
846
|
get isInitialized(): boolean;
|
|
847
|
+
/**
|
|
848
|
+
* Remove a single operation the server permanently rejected — from the queue,
|
|
849
|
+
* from any in-flight batch, and from durable storage — so a later batch ack or
|
|
850
|
+
* a reconnect `returnBatch` can never resend or resurrect it. Returns the
|
|
851
|
+
* removed operation so the caller can record it in a durable rejected store,
|
|
852
|
+
* or null if it was not present (already acknowledged and removed).
|
|
853
|
+
*/
|
|
854
|
+
reject(opId: string): Promise<Operation | null>;
|
|
847
855
|
/**
|
|
848
856
|
* Remove operations by id from queue and persistent storage.
|
|
849
857
|
* Used when ops were already sent during handshake delta exchange.
|
|
@@ -867,6 +875,11 @@ interface SyncEngineOptions {
|
|
|
867
875
|
emitter?: KoraEventEmitter;
|
|
868
876
|
/** Queue storage for persistent outbound queue. Defaults to in-memory. */
|
|
869
877
|
queueStorage?: QueueStorage;
|
|
878
|
+
/**
|
|
879
|
+
* Durable storage for operations the server rejected. Defaults to in-memory.
|
|
880
|
+
* Provide a store-backed implementation so rejections survive a page refresh.
|
|
881
|
+
*/
|
|
882
|
+
rejectedStorage?: RejectedOperationStorage;
|
|
870
883
|
/**
|
|
871
884
|
* Optional encryptor for end-to-end encryption.
|
|
872
885
|
* When provided, `data` and `previousData` fields of operations are encrypted
|
|
@@ -911,6 +924,7 @@ declare class SyncEngine {
|
|
|
911
924
|
private readonly serializer;
|
|
912
925
|
private readonly emitter;
|
|
913
926
|
private readonly outboundQueue;
|
|
927
|
+
private readonly rejectedStorage;
|
|
914
928
|
private readonly batchSize;
|
|
915
929
|
private readonly encryptor;
|
|
916
930
|
private readonly awarenessManager;
|
|
@@ -1107,6 +1121,25 @@ declare class SyncEngine {
|
|
|
1107
1121
|
private handleOperationBatch;
|
|
1108
1122
|
private handleAcknowledgment;
|
|
1109
1123
|
private handleError;
|
|
1124
|
+
/**
|
|
1125
|
+
* Handle a per-operation rejection: divert the op out of the pending outbound
|
|
1126
|
+
* queue (so it is never retried or resurrected on reconnect), record it in the
|
|
1127
|
+
* durable rejected store (so it is kept and explainable), and emit an event so
|
|
1128
|
+
* the app can reconcile. Unlike {@link handleError}, this is a normal per-op
|
|
1129
|
+
* signal, so the connection stays up.
|
|
1130
|
+
*/
|
|
1131
|
+
private handleOperationRejected;
|
|
1132
|
+
/**
|
|
1133
|
+
* Every operation the server rejected that has not yet been reconciled. The app
|
|
1134
|
+
* uses this (alongside the `sync:operation-rejected` event) to surface failed
|
|
1135
|
+
* submissions and decide whether to roll back or resubmit.
|
|
1136
|
+
*/
|
|
1137
|
+
getRejectedOperations(): Promise<RejectedOperation[]>;
|
|
1138
|
+
/**
|
|
1139
|
+
* Forget rejected operations by id once the app has reconciled them (rolled the
|
|
1140
|
+
* optimistic write back or resubmitted a corrected op).
|
|
1141
|
+
*/
|
|
1142
|
+
clearRejectedOperations(operationIds: string[]): Promise<void>;
|
|
1110
1143
|
private checkDeltaComplete;
|
|
1111
1144
|
/**
|
|
1112
1145
|
* Effective server vector: persisted last-ack merged with live handshake remote vector.
|
|
@@ -1375,4 +1408,4 @@ declare function getRemoteAwarenessStates(awareness: AwarenessManager): Awarenes
|
|
|
1375
1408
|
*/
|
|
1376
1409
|
declare function subscribeRemoteAwarenessStates(awareness: AwarenessManager, listener: (states: AwarenessState[]) => void): () => void;
|
|
1377
1410
|
|
|
1378
|
-
export { type AwarenessChange, type AwarenessCursor, AwarenessManager, type AwarenessMessage, type AwarenessState, type AwarenessUser, BlobChunkChannel, type BlobChunkChannelMessage, type BlobChunkChannelOptions, BlobChunkPushMessage, BlobChunkRequestMessage, BlobChunkResponseMessage, type ChaosConfig, ChaosTransport, ConnectionMonitor, type ConnectionMonitorConfig, type CursorInfo, DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD, DecryptionError, DeltaCursor, EncryptionError, HttpLongPollingTransport, type HttpLongPollingTransportOptions, JsonMessageSerializer, KeyDerivationError, type MessageSerializer, NegotiatedMessageSerializer, OFFLINE_SYNC_STATUS, type OutboundBatch, OutboundQueue, ProtobufMessageSerializer, QueueStorage, type ReconnectionConfig, ReconnectionManager, RichtextDocChannel, type RichtextDocChannelOptions, type RichtextDocListener, SCHEMA_MISMATCH_PREFIX, SerializedOperation, SyncConfig, type SyncDiagnostics, SyncEncryptionConfig, SyncEncryptor, SyncEngine, type SyncEngineOptions, SyncMessage, SyncQuerySubset, SyncScopeMap, SyncState, SyncStatePersistence, type SyncStatusController, type SyncStatusControllerOptions, SyncStatusInfo, type SyncStore, SyncTransport, TransportCloseHandler, TransportErrorHandler, TransportMessageHandler, TransportOptions, VersionedKey, type WebSocketConstructor, type WebSocketLike, WebSocketTransport, type WebSocketTransportOptions, WireFormat, YjsDocUpdateMessage, createDeltaCursorFromBatch, createSyncStatusController, decodeBlobChunkBytes, decodeDeltaCursor, decodeYjsUpdate, deriveKey, deriveVersionedKey, encodeBlobChunkBytes, encodeDeltaCursor, encodeYjsUpdate, filterOperationsByScope, generateSalt, getRemoteAwarenessStates, isClientSchemaVersionSupported, isEncryptedPayload, isSchemaMismatchReject, operationMatchesScope, richtextDocKey, sliceOperationsAfterCursor, subscribeRemoteAwarenessStates, versionVectorToWire, wireToVersionVector };
|
|
1411
|
+
export { type AwarenessChange, type AwarenessCursor, AwarenessManager, type AwarenessMessage, type AwarenessState, type AwarenessUser, BlobChunkChannel, type BlobChunkChannelMessage, type BlobChunkChannelOptions, BlobChunkPushMessage, BlobChunkRequestMessage, BlobChunkResponseMessage, type ChaosConfig, ChaosTransport, ConnectionMonitor, type ConnectionMonitorConfig, type CursorInfo, DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD, DecryptionError, DeltaCursor, EncryptionError, HttpLongPollingTransport, type HttpLongPollingTransportOptions, JsonMessageSerializer, KeyDerivationError, type MessageSerializer, NegotiatedMessageSerializer, OFFLINE_SYNC_STATUS, type OutboundBatch, OutboundQueue, ProtobufMessageSerializer, QueueStorage, type ReconnectionConfig, ReconnectionManager, RejectedOperation, RejectedOperationStorage, RichtextDocChannel, type RichtextDocChannelOptions, type RichtextDocListener, SCHEMA_MISMATCH_PREFIX, SerializedOperation, SyncConfig, type SyncDiagnostics, SyncEncryptionConfig, SyncEncryptor, SyncEngine, type SyncEngineOptions, SyncMessage, SyncQuerySubset, SyncScopeMap, SyncState, SyncStatePersistence, type SyncStatusController, type SyncStatusControllerOptions, SyncStatusInfo, type SyncStore, SyncTransport, TransportCloseHandler, TransportErrorHandler, TransportMessageHandler, TransportOptions, VersionedKey, type WebSocketConstructor, type WebSocketLike, WebSocketTransport, type WebSocketTransportOptions, WireFormat, YjsDocUpdateMessage, createDeltaCursorFromBatch, createSyncStatusController, decodeBlobChunkBytes, decodeDeltaCursor, decodeYjsUpdate, deriveKey, deriveVersionedKey, encodeBlobChunkBytes, encodeDeltaCursor, encodeYjsUpdate, filterOperationsByScope, generateSalt, getRemoteAwarenessStates, isClientSchemaVersionSupported, isEncryptedPayload, isSchemaMismatchReject, operationMatchesScope, richtextDocKey, sliceOperationsAfterCursor, subscribeRemoteAwarenessStates, versionVectorToWire, wireToVersionVector };
|
package/dist/index.js
CHANGED
|
@@ -21,6 +21,20 @@ var SYNC_STATUSES = [
|
|
|
21
21
|
"error",
|
|
22
22
|
"schema-mismatch"
|
|
23
23
|
];
|
|
24
|
+
var MemoryRejectedOperationStorage = class {
|
|
25
|
+
rejected = /* @__PURE__ */ new Map();
|
|
26
|
+
async record(rejected) {
|
|
27
|
+
this.rejected.set(rejected.operationId, rejected);
|
|
28
|
+
}
|
|
29
|
+
async list() {
|
|
30
|
+
return [...this.rejected.values()];
|
|
31
|
+
}
|
|
32
|
+
async remove(operationIds) {
|
|
33
|
+
for (const id of operationIds) {
|
|
34
|
+
this.rejected.delete(id);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
24
38
|
var ScopeViolationError = class extends KoraError {
|
|
25
39
|
constructor(operationId, collection, scope, message) {
|
|
26
40
|
super(
|
|
@@ -218,6 +232,8 @@ function isSyncMessage(value) {
|
|
|
218
232
|
return isAcknowledgmentMessage(value);
|
|
219
233
|
case "error":
|
|
220
234
|
return isErrorMessage(value);
|
|
235
|
+
case "operation-rejected":
|
|
236
|
+
return isOperationRejectedMessage(value);
|
|
221
237
|
case "awareness-update":
|
|
222
238
|
return isAwarenessUpdateMessage(value);
|
|
223
239
|
case "yjs-doc-update":
|
|
@@ -257,6 +273,11 @@ function isErrorMessage(value) {
|
|
|
257
273
|
const msg = value;
|
|
258
274
|
return msg.type === "error" && typeof msg.messageId === "string" && typeof msg.code === "string" && typeof msg.message === "string" && typeof msg.retriable === "boolean";
|
|
259
275
|
}
|
|
276
|
+
function isOperationRejectedMessage(value) {
|
|
277
|
+
if (typeof value !== "object" || value === null) return false;
|
|
278
|
+
const msg = value;
|
|
279
|
+
return msg.type === "operation-rejected" && typeof msg.messageId === "string" && typeof msg.operationId === "string" && typeof msg.collection === "string" && typeof msg.recordId === "string" && typeof msg.code === "string" && typeof msg.message === "string" && typeof msg.retriable === "boolean";
|
|
280
|
+
}
|
|
260
281
|
function isAwarenessUpdateMessage(value) {
|
|
261
282
|
if (typeof value !== "object" || value === null) return false;
|
|
262
283
|
const msg = value;
|
|
@@ -548,6 +569,17 @@ function toProtoEnvelope(message) {
|
|
|
548
569
|
errorMessage: message.message,
|
|
549
570
|
retriable: message.retriable
|
|
550
571
|
};
|
|
572
|
+
case "operation-rejected":
|
|
573
|
+
return {
|
|
574
|
+
type: message.type,
|
|
575
|
+
messageId: message.messageId,
|
|
576
|
+
operationId: message.operationId,
|
|
577
|
+
collection: message.collection,
|
|
578
|
+
recordId: message.recordId,
|
|
579
|
+
errorCode: message.code,
|
|
580
|
+
errorMessage: message.message,
|
|
581
|
+
retriable: message.retriable
|
|
582
|
+
};
|
|
551
583
|
case "awareness-update":
|
|
552
584
|
case "yjs-doc-update":
|
|
553
585
|
return {
|
|
@@ -634,6 +666,17 @@ function fromProtoEnvelope(envelope) {
|
|
|
634
666
|
message: envelope.errorMessage ?? "Unknown error",
|
|
635
667
|
retriable: envelope.retriable ?? false
|
|
636
668
|
};
|
|
669
|
+
case "operation-rejected":
|
|
670
|
+
return {
|
|
671
|
+
type: "operation-rejected",
|
|
672
|
+
messageId: envelope.messageId,
|
|
673
|
+
operationId: envelope.operationId ?? "",
|
|
674
|
+
collection: envelope.collection ?? "",
|
|
675
|
+
recordId: envelope.recordId ?? "",
|
|
676
|
+
code: envelope.errorCode ?? "REJECTED",
|
|
677
|
+
message: envelope.errorMessage ?? "",
|
|
678
|
+
retriable: envelope.retriable ?? false
|
|
679
|
+
};
|
|
637
680
|
case "blob-chunk-request":
|
|
638
681
|
return {
|
|
639
682
|
type: "blob-chunk-request",
|
|
@@ -808,6 +851,12 @@ function encodeEnvelope(envelope) {
|
|
|
808
851
|
if (envelope.hasBytes !== void 0) writer.uint32(184).bool(envelope.hasBytes);
|
|
809
852
|
if (envelope.blobStorageEnabled !== void 0)
|
|
810
853
|
writer.uint32(200).bool(envelope.blobStorageEnabled);
|
|
854
|
+
if (envelope.operationId && envelope.operationId.length > 0)
|
|
855
|
+
writer.uint32(210).string(envelope.operationId);
|
|
856
|
+
if (envelope.collection && envelope.collection.length > 0)
|
|
857
|
+
writer.uint32(218).string(envelope.collection);
|
|
858
|
+
if (envelope.recordId && envelope.recordId.length > 0)
|
|
859
|
+
writer.uint32(226).string(envelope.recordId);
|
|
811
860
|
return writer.finish();
|
|
812
861
|
}
|
|
813
862
|
function decodeEnvelope(bytes) {
|
|
@@ -894,6 +943,15 @@ function decodeEnvelope(bytes) {
|
|
|
894
943
|
case 25:
|
|
895
944
|
envelope.blobStorageEnabled = reader.bool();
|
|
896
945
|
break;
|
|
946
|
+
case 26:
|
|
947
|
+
envelope.operationId = reader.string();
|
|
948
|
+
break;
|
|
949
|
+
case 27:
|
|
950
|
+
envelope.collection = reader.string();
|
|
951
|
+
break;
|
|
952
|
+
case 28:
|
|
953
|
+
envelope.recordId = reader.string();
|
|
954
|
+
break;
|
|
897
955
|
default:
|
|
898
956
|
reader.skipType(tag & 7);
|
|
899
957
|
}
|
|
@@ -2482,6 +2540,37 @@ var OutboundQueue = class {
|
|
|
2482
2540
|
get isInitialized() {
|
|
2483
2541
|
return this.initialized;
|
|
2484
2542
|
}
|
|
2543
|
+
/**
|
|
2544
|
+
* Remove a single operation the server permanently rejected — from the queue,
|
|
2545
|
+
* from any in-flight batch, and from durable storage — so a later batch ack or
|
|
2546
|
+
* a reconnect `returnBatch` can never resend or resurrect it. Returns the
|
|
2547
|
+
* removed operation so the caller can record it in a durable rejected store,
|
|
2548
|
+
* or null if it was not present (already acknowledged and removed).
|
|
2549
|
+
*/
|
|
2550
|
+
async reject(opId) {
|
|
2551
|
+
let removed = null;
|
|
2552
|
+
for (const [batchId, ops] of this.inFlight) {
|
|
2553
|
+
const idx = ops.findIndex((op) => op.id === opId);
|
|
2554
|
+
if (idx !== -1) {
|
|
2555
|
+
removed = ops[idx] ?? null;
|
|
2556
|
+
ops.splice(idx, 1);
|
|
2557
|
+
if (ops.length === 0) {
|
|
2558
|
+
this.inFlight.delete(batchId);
|
|
2559
|
+
}
|
|
2560
|
+
break;
|
|
2561
|
+
}
|
|
2562
|
+
}
|
|
2563
|
+
if (!removed) {
|
|
2564
|
+
const idx = this.queue.findIndex((op) => op.id === opId);
|
|
2565
|
+
if (idx !== -1) {
|
|
2566
|
+
removed = this.queue[idx] ?? null;
|
|
2567
|
+
this.queue.splice(idx, 1);
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
this.seen.delete(opId);
|
|
2571
|
+
await this.storage.dequeue([opId]);
|
|
2572
|
+
return removed;
|
|
2573
|
+
}
|
|
2485
2574
|
/**
|
|
2486
2575
|
* Remove operations by id from queue and persistent storage.
|
|
2487
2576
|
* Used when ops were already sent during handshake delta exchange.
|
|
@@ -2521,6 +2610,7 @@ var SyncEngine = class {
|
|
|
2521
2610
|
serializer;
|
|
2522
2611
|
emitter;
|
|
2523
2612
|
outboundQueue;
|
|
2613
|
+
rejectedStorage;
|
|
2524
2614
|
batchSize;
|
|
2525
2615
|
encryptor;
|
|
2526
2616
|
awarenessManager;
|
|
@@ -2573,6 +2663,7 @@ var SyncEngine = class {
|
|
|
2573
2663
|
this.activeScope = options.config.scopeMap;
|
|
2574
2664
|
const queueStorage = options.queueStorage ?? new MemoryQueueStorage();
|
|
2575
2665
|
this.outboundQueue = new OutboundQueue(queueStorage);
|
|
2666
|
+
this.rejectedStorage = options.rejectedStorage ?? new MemoryRejectedOperationStorage();
|
|
2576
2667
|
this.metricsCollector = new SyncMetricsCollector(options.metricsConfig);
|
|
2577
2668
|
if (this.emitter) {
|
|
2578
2669
|
this.metricsCollector.attachEmitter(this.emitter);
|
|
@@ -2954,6 +3045,9 @@ var SyncEngine = class {
|
|
|
2954
3045
|
case "error":
|
|
2955
3046
|
this.handleError(message);
|
|
2956
3047
|
break;
|
|
3048
|
+
case "operation-rejected":
|
|
3049
|
+
await this.handleOperationRejected(message);
|
|
3050
|
+
break;
|
|
2957
3051
|
case "awareness-update":
|
|
2958
3052
|
this.handleAwarenessUpdate(message);
|
|
2959
3053
|
break;
|
|
@@ -3291,6 +3385,50 @@ var SyncEngine = class {
|
|
|
3291
3385
|
this.emitter?.emit({ type: "sync:disconnected", reason: msg.message });
|
|
3292
3386
|
this.transitionTo("disconnected");
|
|
3293
3387
|
}
|
|
3388
|
+
/**
|
|
3389
|
+
* Handle a per-operation rejection: divert the op out of the pending outbound
|
|
3390
|
+
* queue (so it is never retried or resurrected on reconnect), record it in the
|
|
3391
|
+
* durable rejected store (so it is kept and explainable), and emit an event so
|
|
3392
|
+
* the app can reconcile. Unlike {@link handleError}, this is a normal per-op
|
|
3393
|
+
* signal, so the connection stays up.
|
|
3394
|
+
*/
|
|
3395
|
+
async handleOperationRejected(msg) {
|
|
3396
|
+
await this.outboundQueue.reject(msg.operationId);
|
|
3397
|
+
await this.rejectedStorage.record({
|
|
3398
|
+
operationId: msg.operationId,
|
|
3399
|
+
collection: msg.collection,
|
|
3400
|
+
recordId: msg.recordId,
|
|
3401
|
+
code: msg.code,
|
|
3402
|
+
message: msg.message,
|
|
3403
|
+
retriable: msg.retriable,
|
|
3404
|
+
rejectedAt: Date.now()
|
|
3405
|
+
});
|
|
3406
|
+
await this.refreshPendingCount();
|
|
3407
|
+
this.emitter?.emit({
|
|
3408
|
+
type: "sync:operation-rejected",
|
|
3409
|
+
operationId: msg.operationId,
|
|
3410
|
+
collection: msg.collection,
|
|
3411
|
+
recordId: msg.recordId,
|
|
3412
|
+
code: msg.code,
|
|
3413
|
+
message: msg.message,
|
|
3414
|
+
retriable: msg.retriable
|
|
3415
|
+
});
|
|
3416
|
+
}
|
|
3417
|
+
/**
|
|
3418
|
+
* Every operation the server rejected that has not yet been reconciled. The app
|
|
3419
|
+
* uses this (alongside the `sync:operation-rejected` event) to surface failed
|
|
3420
|
+
* submissions and decide whether to roll back or resubmit.
|
|
3421
|
+
*/
|
|
3422
|
+
getRejectedOperations() {
|
|
3423
|
+
return this.rejectedStorage.list();
|
|
3424
|
+
}
|
|
3425
|
+
/**
|
|
3426
|
+
* Forget rejected operations by id once the app has reconciled them (rolled the
|
|
3427
|
+
* optimistic write back or resubmitted a corrected op).
|
|
3428
|
+
*/
|
|
3429
|
+
clearRejectedOperations(operationIds) {
|
|
3430
|
+
return this.rejectedStorage.remove(operationIds);
|
|
3431
|
+
}
|
|
3294
3432
|
async checkDeltaComplete() {
|
|
3295
3433
|
if (!this.deltaSendComplete || !this.deltaReceiveComplete) {
|
|
3296
3434
|
return;
|
|
@@ -4355,6 +4493,7 @@ export {
|
|
|
4355
4493
|
InvalidScopeError,
|
|
4356
4494
|
JsonMessageSerializer,
|
|
4357
4495
|
KeyDerivationError,
|
|
4496
|
+
MemoryRejectedOperationStorage,
|
|
4358
4497
|
NegotiatedMessageSerializer,
|
|
4359
4498
|
OFFLINE_SYNC_STATUS,
|
|
4360
4499
|
OutboundQueue,
|
|
@@ -4393,6 +4532,7 @@ export {
|
|
|
4393
4532
|
isHandshakeMessage,
|
|
4394
4533
|
isHandshakeResponseMessage,
|
|
4395
4534
|
isOperationBatchMessage,
|
|
4535
|
+
isOperationRejectedMessage,
|
|
4396
4536
|
isSchemaMismatchReject,
|
|
4397
4537
|
isSyncMessage,
|
|
4398
4538
|
isYjsDocUpdateMessage,
|