@korajs/sync 1.0.0-beta.0 → 1.0.0-beta.2

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.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, g as SyncEncryptionConfig, V as VersionedKey, Y as YjsDocUpdateMessage, Q as QueueStorage, h as SyncState, i as SyncStatusInfo, j as SyncConfig, k as SyncStatePersistence, l as SyncQuerySubset } from './transport-BMesMB6s.cjs';
2
- export { A as AcknowledgmentMessage, m as AwarenessStateWire, n as AwarenessUpdateMessage, E as EncryptedPayload, o as ErrorMessage, H as HandshakeMessage, p as HandshakeResponseMessage, I as InvalidScopeError, O as OperationBatchMessage, q as SYNC_STATES, r as SYNC_STATUSES, s as ScopeViolationError, t as SyncEncryptionAlgorithm, u as SyncScopeContext, v as SyncStatus, w as dedupeQuerySubsets, x as isAcknowledgmentMessage, y as isAwarenessUpdateMessage, z as isErrorMessage, B as isHandshakeMessage, C as isHandshakeResponseMessage, F as isOperationBatchMessage, G as isSyncMessage, J as isYjsDocUpdateMessage, K as operationMatchesQuerySubsets } from './transport-BMesMB6s.cjs';
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';
@@ -470,6 +470,71 @@ declare class AwarenessManager {
470
470
  private emitAwarenessEvent;
471
471
  }
472
472
 
473
+ /**
474
+ * A blob-chunk message in decoded form (chunk bytes as a `Uint8Array` rather
475
+ * than the base64 wire string). This is the shape callers of the channel work
476
+ * with; the channel handles base64 encode/decode at the wire boundary.
477
+ *
478
+ * The shape mirrors `@korajs/store`'s `ChunkMessage` so an app-layer adapter can
479
+ * bridge the two with no field translation.
480
+ */
481
+ type BlobChunkChannelMessage = {
482
+ type: 'blob-chunk-request';
483
+ requestId: string;
484
+ hash: string;
485
+ } | {
486
+ type: 'blob-chunk-response';
487
+ requestId: string;
488
+ bytes: Uint8Array | null;
489
+ } | {
490
+ type: 'blob-chunk-push';
491
+ hash: string;
492
+ bytes: Uint8Array;
493
+ };
494
+ /** Encode chunk bytes to a base64 string for the JSON wire. */
495
+ declare function encodeBlobChunkBytes(bytes: Uint8Array): string;
496
+ /** Decode base64 chunk bytes from the wire back to a `Uint8Array`. */
497
+ declare function decodeBlobChunkBytes(encoded: string): Uint8Array;
498
+ interface BlobChunkChannelOptions {
499
+ /**
500
+ * Called when a local blob-chunk message should go out on the wire. The
501
+ * caller (the sync engine) decides whether the connection is ready to send.
502
+ */
503
+ onSend?: (message: BlobChunkRequestMessage | BlobChunkResponseMessage | BlobChunkPushMessage) => void;
504
+ }
505
+ /**
506
+ * Ephemeral side channel for out-of-band blob chunk transfer over the sync
507
+ * connection. Symmetric: a peer can both request chunks it needs and answer
508
+ * requests for chunks it holds. Never persisted in the operation log — durable
509
+ * state is the `BlobRef` inside a record's fields; this channel only moves the
510
+ * referenced bytes.
511
+ *
512
+ * The channel owns the base64 wire encoding so callers work purely in
513
+ * `Uint8Array`, and its {@link BlobChunkChannelMessage} shape mirrors
514
+ * `@korajs/store`'s `ChunkMessage` so the app layer can expose it as a
515
+ * `ChunkMessagePort` without translating fields.
516
+ */
517
+ declare class BlobChunkChannel {
518
+ private readonly onSend;
519
+ private readonly handlers;
520
+ constructor(options?: BlobChunkChannelOptions);
521
+ /**
522
+ * Send a blob-chunk message to the peer. Response bytes are base64-encoded
523
+ * onto the wire here; callers pass a `Uint8Array`.
524
+ */
525
+ send(message: BlobChunkChannelMessage): void;
526
+ /**
527
+ * Register a handler for inbound blob-chunk messages. Multiple handlers are
528
+ * allowed; each receives every delivered message.
529
+ */
530
+ onMessage(handler: (message: BlobChunkChannelMessage) => void): () => void;
531
+ /**
532
+ * Deliver an inbound wire message to registered handlers, decoding response
533
+ * bytes from base64 back to a `Uint8Array` first.
534
+ */
535
+ deliver(message: BlobChunkRequestMessage | BlobChunkResponseMessage | BlobChunkPushMessage): void;
536
+ }
537
+
473
538
  /**
474
539
  * Configuration for the SyncMetricsCollector.
475
540
  */
@@ -779,6 +844,14 @@ declare class OutboundQueue {
779
844
  * Whether initialize() has been called.
780
845
  */
781
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>;
782
855
  /**
783
856
  * Remove operations by id from queue and persistent storage.
784
857
  * Used when ops were already sent during handshake delta exchange.
@@ -802,6 +875,11 @@ interface SyncEngineOptions {
802
875
  emitter?: KoraEventEmitter;
803
876
  /** Queue storage for persistent outbound queue. Defaults to in-memory. */
804
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;
805
883
  /**
806
884
  * Optional encryptor for end-to-end encryption.
807
885
  * When provided, `data` and `previousData` fields of operations are encrypted
@@ -846,10 +924,12 @@ declare class SyncEngine {
846
924
  private readonly serializer;
847
925
  private readonly emitter;
848
926
  private readonly outboundQueue;
927
+ private readonly rejectedStorage;
849
928
  private readonly batchSize;
850
929
  private readonly encryptor;
851
930
  private readonly awarenessManager;
852
931
  private readonly richtextDocChannel;
932
+ private readonly blobChunkChannel;
853
933
  private readonly metricsCollector;
854
934
  private readonly syncState;
855
935
  private remoteVector;
@@ -864,6 +944,7 @@ declare class SyncEngine {
864
944
  private schemaBlocked;
865
945
  private clockBlocked;
866
946
  private clockSkewMs;
947
+ private blobStorageEnabled;
867
948
  private deltaBatchesReceived;
868
949
  private deltaReceiveComplete;
869
950
  private deltaSendComplete;
@@ -998,6 +1079,22 @@ declare class SyncEngine {
998
1079
  * Optional side channel for incremental Yjs updates on large richtext fields.
999
1080
  */
1000
1081
  getRichtextDocChannel(): RichtextDocChannel;
1082
+ /**
1083
+ * Side channel for out-of-band blob chunk transfer over the sync connection.
1084
+ * The app layer bridges this to a `ChunkMessagePort` to pull/serve blob bytes.
1085
+ */
1086
+ getBlobChunkChannel(): BlobChunkChannel;
1087
+ /**
1088
+ * Whether the connected server persists blob bytes centrally (learned from the
1089
+ * handshake response). When true, the app uploads the bytes behind `blob`
1090
+ * fields so they stay available after the authoring device goes offline.
1091
+ */
1092
+ isBlobStorageEnabled(): boolean;
1093
+ /**
1094
+ * Upload a blob chunk (or manifest) to the server for central persistence.
1095
+ * A no-op unless connected and the server advertised blob storage.
1096
+ */
1097
+ uploadBlobChunk(hash: string, bytes: Uint8Array): void;
1001
1098
  private messageChain;
1002
1099
  private enqueueMessage;
1003
1100
  private handleMessageAsync;
@@ -1024,6 +1121,25 @@ declare class SyncEngine {
1024
1121
  private handleOperationBatch;
1025
1122
  private handleAcknowledgment;
1026
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>;
1027
1143
  private checkDeltaComplete;
1028
1144
  /**
1029
1145
  * Effective server vector: persisted last-ack merged with live handshake remote vector.
@@ -1292,4 +1408,4 @@ declare function getRemoteAwarenessStates(awareness: AwarenessManager): Awarenes
1292
1408
  */
1293
1409
  declare function subscribeRemoteAwarenessStates(awareness: AwarenessManager, listener: (states: AwarenessState[]) => void): () => void;
1294
1410
 
1295
- export { type AwarenessChange, type AwarenessCursor, AwarenessManager, type AwarenessMessage, type AwarenessState, type AwarenessUser, 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, decodeDeltaCursor, decodeYjsUpdate, deriveKey, deriveVersionedKey, 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, g as SyncEncryptionConfig, V as VersionedKey, Y as YjsDocUpdateMessage, Q as QueueStorage, h as SyncState, i as SyncStatusInfo, j as SyncConfig, k as SyncStatePersistence, l as SyncQuerySubset } from './transport-BMesMB6s.js';
2
- export { A as AcknowledgmentMessage, m as AwarenessStateWire, n as AwarenessUpdateMessage, E as EncryptedPayload, o as ErrorMessage, H as HandshakeMessage, p as HandshakeResponseMessage, I as InvalidScopeError, O as OperationBatchMessage, q as SYNC_STATES, r as SYNC_STATUSES, s as ScopeViolationError, t as SyncEncryptionAlgorithm, u as SyncScopeContext, v as SyncStatus, w as dedupeQuerySubsets, x as isAcknowledgmentMessage, y as isAwarenessUpdateMessage, z as isErrorMessage, B as isHandshakeMessage, C as isHandshakeResponseMessage, F as isOperationBatchMessage, G as isSyncMessage, J as isYjsDocUpdateMessage, K as operationMatchesQuerySubsets } from './transport-BMesMB6s.js';
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';
@@ -470,6 +470,71 @@ declare class AwarenessManager {
470
470
  private emitAwarenessEvent;
471
471
  }
472
472
 
473
+ /**
474
+ * A blob-chunk message in decoded form (chunk bytes as a `Uint8Array` rather
475
+ * than the base64 wire string). This is the shape callers of the channel work
476
+ * with; the channel handles base64 encode/decode at the wire boundary.
477
+ *
478
+ * The shape mirrors `@korajs/store`'s `ChunkMessage` so an app-layer adapter can
479
+ * bridge the two with no field translation.
480
+ */
481
+ type BlobChunkChannelMessage = {
482
+ type: 'blob-chunk-request';
483
+ requestId: string;
484
+ hash: string;
485
+ } | {
486
+ type: 'blob-chunk-response';
487
+ requestId: string;
488
+ bytes: Uint8Array | null;
489
+ } | {
490
+ type: 'blob-chunk-push';
491
+ hash: string;
492
+ bytes: Uint8Array;
493
+ };
494
+ /** Encode chunk bytes to a base64 string for the JSON wire. */
495
+ declare function encodeBlobChunkBytes(bytes: Uint8Array): string;
496
+ /** Decode base64 chunk bytes from the wire back to a `Uint8Array`. */
497
+ declare function decodeBlobChunkBytes(encoded: string): Uint8Array;
498
+ interface BlobChunkChannelOptions {
499
+ /**
500
+ * Called when a local blob-chunk message should go out on the wire. The
501
+ * caller (the sync engine) decides whether the connection is ready to send.
502
+ */
503
+ onSend?: (message: BlobChunkRequestMessage | BlobChunkResponseMessage | BlobChunkPushMessage) => void;
504
+ }
505
+ /**
506
+ * Ephemeral side channel for out-of-band blob chunk transfer over the sync
507
+ * connection. Symmetric: a peer can both request chunks it needs and answer
508
+ * requests for chunks it holds. Never persisted in the operation log — durable
509
+ * state is the `BlobRef` inside a record's fields; this channel only moves the
510
+ * referenced bytes.
511
+ *
512
+ * The channel owns the base64 wire encoding so callers work purely in
513
+ * `Uint8Array`, and its {@link BlobChunkChannelMessage} shape mirrors
514
+ * `@korajs/store`'s `ChunkMessage` so the app layer can expose it as a
515
+ * `ChunkMessagePort` without translating fields.
516
+ */
517
+ declare class BlobChunkChannel {
518
+ private readonly onSend;
519
+ private readonly handlers;
520
+ constructor(options?: BlobChunkChannelOptions);
521
+ /**
522
+ * Send a blob-chunk message to the peer. Response bytes are base64-encoded
523
+ * onto the wire here; callers pass a `Uint8Array`.
524
+ */
525
+ send(message: BlobChunkChannelMessage): void;
526
+ /**
527
+ * Register a handler for inbound blob-chunk messages. Multiple handlers are
528
+ * allowed; each receives every delivered message.
529
+ */
530
+ onMessage(handler: (message: BlobChunkChannelMessage) => void): () => void;
531
+ /**
532
+ * Deliver an inbound wire message to registered handlers, decoding response
533
+ * bytes from base64 back to a `Uint8Array` first.
534
+ */
535
+ deliver(message: BlobChunkRequestMessage | BlobChunkResponseMessage | BlobChunkPushMessage): void;
536
+ }
537
+
473
538
  /**
474
539
  * Configuration for the SyncMetricsCollector.
475
540
  */
@@ -779,6 +844,14 @@ declare class OutboundQueue {
779
844
  * Whether initialize() has been called.
780
845
  */
781
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>;
782
855
  /**
783
856
  * Remove operations by id from queue and persistent storage.
784
857
  * Used when ops were already sent during handshake delta exchange.
@@ -802,6 +875,11 @@ interface SyncEngineOptions {
802
875
  emitter?: KoraEventEmitter;
803
876
  /** Queue storage for persistent outbound queue. Defaults to in-memory. */
804
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;
805
883
  /**
806
884
  * Optional encryptor for end-to-end encryption.
807
885
  * When provided, `data` and `previousData` fields of operations are encrypted
@@ -846,10 +924,12 @@ declare class SyncEngine {
846
924
  private readonly serializer;
847
925
  private readonly emitter;
848
926
  private readonly outboundQueue;
927
+ private readonly rejectedStorage;
849
928
  private readonly batchSize;
850
929
  private readonly encryptor;
851
930
  private readonly awarenessManager;
852
931
  private readonly richtextDocChannel;
932
+ private readonly blobChunkChannel;
853
933
  private readonly metricsCollector;
854
934
  private readonly syncState;
855
935
  private remoteVector;
@@ -864,6 +944,7 @@ declare class SyncEngine {
864
944
  private schemaBlocked;
865
945
  private clockBlocked;
866
946
  private clockSkewMs;
947
+ private blobStorageEnabled;
867
948
  private deltaBatchesReceived;
868
949
  private deltaReceiveComplete;
869
950
  private deltaSendComplete;
@@ -998,6 +1079,22 @@ declare class SyncEngine {
998
1079
  * Optional side channel for incremental Yjs updates on large richtext fields.
999
1080
  */
1000
1081
  getRichtextDocChannel(): RichtextDocChannel;
1082
+ /**
1083
+ * Side channel for out-of-band blob chunk transfer over the sync connection.
1084
+ * The app layer bridges this to a `ChunkMessagePort` to pull/serve blob bytes.
1085
+ */
1086
+ getBlobChunkChannel(): BlobChunkChannel;
1087
+ /**
1088
+ * Whether the connected server persists blob bytes centrally (learned from the
1089
+ * handshake response). When true, the app uploads the bytes behind `blob`
1090
+ * fields so they stay available after the authoring device goes offline.
1091
+ */
1092
+ isBlobStorageEnabled(): boolean;
1093
+ /**
1094
+ * Upload a blob chunk (or manifest) to the server for central persistence.
1095
+ * A no-op unless connected and the server advertised blob storage.
1096
+ */
1097
+ uploadBlobChunk(hash: string, bytes: Uint8Array): void;
1001
1098
  private messageChain;
1002
1099
  private enqueueMessage;
1003
1100
  private handleMessageAsync;
@@ -1024,6 +1121,25 @@ declare class SyncEngine {
1024
1121
  private handleOperationBatch;
1025
1122
  private handleAcknowledgment;
1026
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>;
1027
1143
  private checkDeltaComplete;
1028
1144
  /**
1029
1145
  * Effective server vector: persisted last-ack merged with live handshake remote vector.
@@ -1292,4 +1408,4 @@ declare function getRemoteAwarenessStates(awareness: AwarenessManager): Awarenes
1292
1408
  */
1293
1409
  declare function subscribeRemoteAwarenessStates(awareness: AwarenessManager, listener: (states: AwarenessState[]) => void): () => void;
1294
1410
 
1295
- export { type AwarenessChange, type AwarenessCursor, AwarenessManager, type AwarenessMessage, type AwarenessState, type AwarenessUser, 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, decodeDeltaCursor, decodeYjsUpdate, deriveKey, deriveVersionedKey, 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 };