@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.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,10 +232,18 @@ 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":
224
240
  return isYjsDocUpdateMessage(value);
241
+ case "blob-chunk-request":
242
+ return isBlobChunkRequestMessage(value);
243
+ case "blob-chunk-response":
244
+ return isBlobChunkResponseMessage(value);
245
+ case "blob-chunk-push":
246
+ return isBlobChunkPushMessage(value);
225
247
  default:
226
248
  return false;
227
249
  }
@@ -251,6 +273,11 @@ function isErrorMessage(value) {
251
273
  const msg = value;
252
274
  return msg.type === "error" && typeof msg.messageId === "string" && typeof msg.code === "string" && typeof msg.message === "string" && typeof msg.retriable === "boolean";
253
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
+ }
254
281
  function isAwarenessUpdateMessage(value) {
255
282
  if (typeof value !== "object" || value === null) return false;
256
283
  const msg = value;
@@ -261,6 +288,21 @@ function isYjsDocUpdateMessage(value) {
261
288
  const msg = value;
262
289
  return msg.type === "yjs-doc-update" && typeof msg.messageId === "string" && typeof msg.collection === "string" && typeof msg.recordId === "string" && typeof msg.field === "string" && typeof msg.update === "string";
263
290
  }
291
+ function isBlobChunkRequestMessage(value) {
292
+ if (typeof value !== "object" || value === null) return false;
293
+ const msg = value;
294
+ return msg.type === "blob-chunk-request" && typeof msg.messageId === "string" && typeof msg.requestId === "string" && typeof msg.hash === "string";
295
+ }
296
+ function isBlobChunkResponseMessage(value) {
297
+ if (typeof value !== "object" || value === null) return false;
298
+ const msg = value;
299
+ return msg.type === "blob-chunk-response" && typeof msg.messageId === "string" && typeof msg.requestId === "string" && (typeof msg.bytes === "string" || msg.bytes === null);
300
+ }
301
+ function isBlobChunkPushMessage(value) {
302
+ if (typeof value !== "object" || value === null) return false;
303
+ const msg = value;
304
+ return msg.type === "blob-chunk-push" && typeof msg.messageId === "string" && typeof msg.hash === "string" && typeof msg.bytes === "string";
305
+ }
264
306
 
265
307
  // src/protocol/serializer.ts
266
308
  import { SyncError } from "@korajs/core";
@@ -501,7 +543,8 @@ function toProtoEnvelope(message) {
501
543
  accepted: message.accepted,
502
544
  rejectReason: message.rejectReason,
503
545
  selectedWireFormat: message.selectedWireFormat,
504
- serverTime: message.serverTime
546
+ serverTime: message.serverTime,
547
+ blobStorageEnabled: message.blobStorageEnabled
505
548
  };
506
549
  case "operation-batch":
507
550
  return {
@@ -526,12 +569,45 @@ function toProtoEnvelope(message) {
526
569
  errorMessage: message.message,
527
570
  retriable: message.retriable
528
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
+ };
529
583
  case "awareness-update":
530
584
  case "yjs-doc-update":
531
585
  return {
532
586
  type: message.type,
533
587
  messageId: message.messageId
534
588
  };
589
+ case "blob-chunk-request":
590
+ return {
591
+ type: message.type,
592
+ messageId: message.messageId,
593
+ requestId: message.requestId,
594
+ hash: message.hash
595
+ };
596
+ case "blob-chunk-response":
597
+ return {
598
+ type: message.type,
599
+ messageId: message.messageId,
600
+ requestId: message.requestId,
601
+ hasBytes: message.bytes !== null,
602
+ ...message.bytes !== null ? { chunkBytes: message.bytes } : {}
603
+ };
604
+ case "blob-chunk-push":
605
+ return {
606
+ type: message.type,
607
+ messageId: message.messageId,
608
+ hash: message.hash,
609
+ chunkBytes: message.bytes
610
+ };
535
611
  }
536
612
  }
537
613
  function fromProtoEnvelope(envelope) {
@@ -564,7 +640,8 @@ function fromProtoEnvelope(envelope) {
564
640
  selectedWireFormat: envelope.selectedWireFormat === "json" || envelope.selectedWireFormat === "protobuf" ? envelope.selectedWireFormat : void 0,
565
641
  // Preserve the server's wall-clock time so clock-skew detection and
566
642
  // automatic timestamp rebase work over the protobuf wire, not just JSON.
567
- ...envelope.serverTime !== void 0 ? { serverTime: envelope.serverTime } : {}
643
+ ...envelope.serverTime !== void 0 ? { serverTime: envelope.serverTime } : {},
644
+ ...envelope.blobStorageEnabled !== void 0 ? { blobStorageEnabled: envelope.blobStorageEnabled } : {}
568
645
  };
569
646
  case "operation-batch":
570
647
  return {
@@ -589,6 +666,38 @@ function fromProtoEnvelope(envelope) {
589
666
  message: envelope.errorMessage ?? "Unknown error",
590
667
  retriable: envelope.retriable ?? false
591
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
+ };
680
+ case "blob-chunk-request":
681
+ return {
682
+ type: "blob-chunk-request",
683
+ messageId: envelope.messageId,
684
+ requestId: envelope.requestId ?? "",
685
+ hash: envelope.hash ?? ""
686
+ };
687
+ case "blob-chunk-response":
688
+ return {
689
+ type: "blob-chunk-response",
690
+ messageId: envelope.messageId,
691
+ requestId: envelope.requestId ?? "",
692
+ bytes: envelope.hasBytes ? envelope.chunkBytes ?? "" : null
693
+ };
694
+ case "blob-chunk-push":
695
+ return {
696
+ type: "blob-chunk-push",
697
+ messageId: envelope.messageId,
698
+ hash: envelope.hash ?? "",
699
+ bytes: envelope.chunkBytes ?? ""
700
+ };
592
701
  default:
593
702
  throw new SyncError("Failed to decode sync message: unknown protobuf type", {
594
703
  type: envelope.type
@@ -734,6 +843,20 @@ function encodeEnvelope(envelope) {
734
843
  }
735
844
  if (envelope.retriable !== void 0) writer.uint32(144).bool(envelope.retriable);
736
845
  if (envelope.serverTime !== void 0) writer.uint32(152).int64(envelope.serverTime);
846
+ if (envelope.requestId && envelope.requestId.length > 0)
847
+ writer.uint32(162).string(envelope.requestId);
848
+ if (envelope.hash && envelope.hash.length > 0) writer.uint32(170).string(envelope.hash);
849
+ if (envelope.chunkBytes && envelope.chunkBytes.length > 0)
850
+ writer.uint32(178).string(envelope.chunkBytes);
851
+ if (envelope.hasBytes !== void 0) writer.uint32(184).bool(envelope.hasBytes);
852
+ if (envelope.blobStorageEnabled !== void 0)
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);
737
860
  return writer.finish();
738
861
  }
739
862
  function decodeEnvelope(bytes) {
@@ -805,6 +928,30 @@ function decodeEnvelope(bytes) {
805
928
  case 19:
806
929
  envelope.serverTime = longToNumber(reader.int64());
807
930
  break;
931
+ case 20:
932
+ envelope.requestId = reader.string();
933
+ break;
934
+ case 21:
935
+ envelope.hash = reader.string();
936
+ break;
937
+ case 22:
938
+ envelope.chunkBytes = reader.string();
939
+ break;
940
+ case 23:
941
+ envelope.hasBytes = reader.bool();
942
+ break;
943
+ case 25:
944
+ envelope.blobStorageEnabled = reader.bool();
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;
808
955
  default:
809
956
  reader.skipType(tag & 7);
810
957
  }
@@ -1612,6 +1759,95 @@ var AwarenessManager = class {
1612
1759
  }
1613
1760
  };
1614
1761
 
1762
+ // src/blob/blob-chunk-channel.ts
1763
+ import { generateUUIDv7 } from "@korajs/core";
1764
+ function encodeBlobChunkBytes(bytes) {
1765
+ let binary = "";
1766
+ for (let i = 0; i < bytes.length; i++) {
1767
+ binary += String.fromCharCode(bytes[i]);
1768
+ }
1769
+ return btoa(binary);
1770
+ }
1771
+ function decodeBlobChunkBytes(encoded) {
1772
+ const binary = atob(encoded);
1773
+ const out = new Uint8Array(binary.length);
1774
+ for (let i = 0; i < binary.length; i++) {
1775
+ out[i] = binary.charCodeAt(i);
1776
+ }
1777
+ return out;
1778
+ }
1779
+ var BlobChunkChannel = class {
1780
+ onSend;
1781
+ handlers = /* @__PURE__ */ new Set();
1782
+ constructor(options) {
1783
+ this.onSend = options?.onSend ?? null;
1784
+ }
1785
+ /**
1786
+ * Send a blob-chunk message to the peer. Response bytes are base64-encoded
1787
+ * onto the wire here; callers pass a `Uint8Array`.
1788
+ */
1789
+ send(message) {
1790
+ if (!this.onSend) {
1791
+ return;
1792
+ }
1793
+ if (message.type === "blob-chunk-request") {
1794
+ this.onSend({
1795
+ type: "blob-chunk-request",
1796
+ messageId: generateUUIDv7(),
1797
+ requestId: message.requestId,
1798
+ hash: message.hash
1799
+ });
1800
+ return;
1801
+ }
1802
+ if (message.type === "blob-chunk-push") {
1803
+ this.onSend({
1804
+ type: "blob-chunk-push",
1805
+ messageId: generateUUIDv7(),
1806
+ hash: message.hash,
1807
+ bytes: encodeBlobChunkBytes(message.bytes)
1808
+ });
1809
+ return;
1810
+ }
1811
+ this.onSend({
1812
+ type: "blob-chunk-response",
1813
+ messageId: generateUUIDv7(),
1814
+ requestId: message.requestId,
1815
+ bytes: message.bytes === null ? null : encodeBlobChunkBytes(message.bytes)
1816
+ });
1817
+ }
1818
+ /**
1819
+ * Register a handler for inbound blob-chunk messages. Multiple handlers are
1820
+ * allowed; each receives every delivered message.
1821
+ */
1822
+ onMessage(handler) {
1823
+ this.handlers.add(handler);
1824
+ return () => {
1825
+ this.handlers.delete(handler);
1826
+ };
1827
+ }
1828
+ /**
1829
+ * Deliver an inbound wire message to registered handlers, decoding response
1830
+ * bytes from base64 back to a `Uint8Array` first.
1831
+ */
1832
+ deliver(message) {
1833
+ if (this.handlers.size === 0) {
1834
+ return;
1835
+ }
1836
+ const decoded = message.type === "blob-chunk-request" ? { type: "blob-chunk-request", requestId: message.requestId, hash: message.hash } : message.type === "blob-chunk-push" ? {
1837
+ type: "blob-chunk-push",
1838
+ hash: message.hash,
1839
+ bytes: decodeBlobChunkBytes(message.bytes)
1840
+ } : {
1841
+ type: "blob-chunk-response",
1842
+ requestId: message.requestId,
1843
+ bytes: message.bytes === null ? null : decodeBlobChunkBytes(message.bytes)
1844
+ };
1845
+ for (const handler of this.handlers) {
1846
+ handler(decoded);
1847
+ }
1848
+ }
1849
+ };
1850
+
1615
1851
  // src/diagnostics/bandwidth-estimator.ts
1616
1852
  var BandwidthEstimator = class {
1617
1853
  maxSamples;
@@ -2055,7 +2291,7 @@ var SyncMetricsCollector = class {
2055
2291
  };
2056
2292
 
2057
2293
  // src/richtext/richtext-doc-channel.ts
2058
- import { generateUUIDv7 } from "@korajs/core";
2294
+ import { generateUUIDv7 as generateUUIDv72 } from "@korajs/core";
2059
2295
 
2060
2296
  // src/richtext/doc-channel-wire.ts
2061
2297
  function encodeYjsUpdate(update) {
@@ -2134,7 +2370,7 @@ var RichtextDocChannel = class {
2134
2370
  }
2135
2371
  this.onSend({
2136
2372
  type: "yjs-doc-update",
2137
- messageId: generateUUIDv7(),
2373
+ messageId: generateUUIDv72(),
2138
2374
  collection,
2139
2375
  recordId,
2140
2376
  field,
@@ -2304,6 +2540,37 @@ var OutboundQueue = class {
2304
2540
  get isInitialized() {
2305
2541
  return this.initialized;
2306
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
+ }
2307
2574
  /**
2308
2575
  * Remove operations by id from queue and persistent storage.
2309
2576
  * Used when ops were already sent during handshake delta exchange.
@@ -2343,10 +2610,12 @@ var SyncEngine = class {
2343
2610
  serializer;
2344
2611
  emitter;
2345
2612
  outboundQueue;
2613
+ rejectedStorage;
2346
2614
  batchSize;
2347
2615
  encryptor;
2348
2616
  awarenessManager;
2349
2617
  richtextDocChannel;
2618
+ blobChunkChannel;
2350
2619
  metricsCollector;
2351
2620
  syncState;
2352
2621
  remoteVector = /* @__PURE__ */ new Map();
@@ -2361,6 +2630,7 @@ var SyncEngine = class {
2361
2630
  schemaBlocked = false;
2362
2631
  clockBlocked = false;
2363
2632
  clockSkewMs = null;
2633
+ blobStorageEnabled = false;
2364
2634
  // Track delta exchange state
2365
2635
  deltaBatchesReceived = 0;
2366
2636
  deltaReceiveComplete = false;
@@ -2393,6 +2663,7 @@ var SyncEngine = class {
2393
2663
  this.activeScope = options.config.scopeMap;
2394
2664
  const queueStorage = options.queueStorage ?? new MemoryQueueStorage();
2395
2665
  this.outboundQueue = new OutboundQueue(queueStorage);
2666
+ this.rejectedStorage = options.rejectedStorage ?? new MemoryRejectedOperationStorage();
2396
2667
  this.metricsCollector = new SyncMetricsCollector(options.metricsConfig);
2397
2668
  if (this.emitter) {
2398
2669
  this.metricsCollector.attachEmitter(this.emitter);
@@ -2409,6 +2680,14 @@ var SyncEngine = class {
2409
2680
  this.transport.send(message);
2410
2681
  }
2411
2682
  });
2683
+ this.blobChunkChannel = new BlobChunkChannel({
2684
+ onSend: (message) => {
2685
+ if (this.state !== "streaming") {
2686
+ return;
2687
+ }
2688
+ this.transport.send(message);
2689
+ }
2690
+ });
2412
2691
  this.awarenessManager.onSend((message) => {
2413
2692
  if (this.state !== "streaming") return;
2414
2693
  const wireMessage = {
@@ -2722,6 +3001,31 @@ var SyncEngine = class {
2722
3001
  getRichtextDocChannel() {
2723
3002
  return this.richtextDocChannel;
2724
3003
  }
3004
+ /**
3005
+ * Side channel for out-of-band blob chunk transfer over the sync connection.
3006
+ * The app layer bridges this to a `ChunkMessagePort` to pull/serve blob bytes.
3007
+ */
3008
+ getBlobChunkChannel() {
3009
+ return this.blobChunkChannel;
3010
+ }
3011
+ /**
3012
+ * Whether the connected server persists blob bytes centrally (learned from the
3013
+ * handshake response). When true, the app uploads the bytes behind `blob`
3014
+ * fields so they stay available after the authoring device goes offline.
3015
+ */
3016
+ isBlobStorageEnabled() {
3017
+ return this.blobStorageEnabled;
3018
+ }
3019
+ /**
3020
+ * Upload a blob chunk (or manifest) to the server for central persistence.
3021
+ * A no-op unless connected and the server advertised blob storage.
3022
+ */
3023
+ uploadBlobChunk(hash, bytes) {
3024
+ if (this.state !== "streaming" || !this.blobStorageEnabled) {
3025
+ return;
3026
+ }
3027
+ this.blobChunkChannel.send({ type: "blob-chunk-push", hash, bytes });
3028
+ }
2725
3029
  // --- Private methods ---
2726
3030
  messageChain = Promise.resolve();
2727
3031
  enqueueMessage(message) {
@@ -2741,12 +3045,20 @@ var SyncEngine = class {
2741
3045
  case "error":
2742
3046
  this.handleError(message);
2743
3047
  break;
3048
+ case "operation-rejected":
3049
+ await this.handleOperationRejected(message);
3050
+ break;
2744
3051
  case "awareness-update":
2745
3052
  this.handleAwarenessUpdate(message);
2746
3053
  break;
2747
3054
  case "yjs-doc-update":
2748
3055
  this.richtextDocChannel.deliver(message);
2749
3056
  break;
3057
+ case "blob-chunk-request":
3058
+ case "blob-chunk-response":
3059
+ case "blob-chunk-push":
3060
+ this.blobChunkChannel.deliver(message);
3061
+ break;
2750
3062
  }
2751
3063
  }
2752
3064
  handleMessageFailure(error) {
@@ -2779,6 +3091,7 @@ var SyncEngine = class {
2779
3091
  }
2780
3092
  async handleHandshakeResponse(msg) {
2781
3093
  if (this.state !== "handshaking") return;
3094
+ this.blobStorageEnabled = msg.blobStorageEnabled === true;
2782
3095
  if (typeof msg.serverTime === "number") {
2783
3096
  this.evaluateClockSkew(msg.serverTime);
2784
3097
  if (this.clockBlocked) {
@@ -3072,6 +3385,50 @@ var SyncEngine = class {
3072
3385
  this.emitter?.emit({ type: "sync:disconnected", reason: msg.message });
3073
3386
  this.transitionTo("disconnected");
3074
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
+ }
3075
3432
  async checkDeltaComplete() {
3076
3433
  if (!this.deltaSendComplete || !this.deltaReceiveComplete) {
3077
3434
  return;
@@ -4126,6 +4483,7 @@ function subscribeRemoteAwarenessStates(awareness, listener) {
4126
4483
  }
4127
4484
  export {
4128
4485
  AwarenessManager,
4486
+ BlobChunkChannel,
4129
4487
  ChaosTransport,
4130
4488
  ConnectionMonitor,
4131
4489
  DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD,
@@ -4135,6 +4493,7 @@ export {
4135
4493
  InvalidScopeError,
4136
4494
  JsonMessageSerializer,
4137
4495
  KeyDerivationError,
4496
+ MemoryRejectedOperationStorage,
4138
4497
  NegotiatedMessageSerializer,
4139
4498
  OFFLINE_SYNC_STATUS,
4140
4499
  OutboundQueue,
@@ -4150,11 +4509,13 @@ export {
4150
4509
  WebSocketTransport,
4151
4510
  createDeltaCursorFromBatch,
4152
4511
  createSyncStatusController,
4512
+ decodeBlobChunkBytes,
4153
4513
  decodeDeltaCursor,
4154
4514
  decodeYjsUpdate,
4155
4515
  dedupeQuerySubsets,
4156
4516
  deriveKey,
4157
4517
  deriveVersionedKey,
4518
+ encodeBlobChunkBytes,
4158
4519
  encodeDeltaCursor,
4159
4520
  encodeYjsUpdate,
4160
4521
  filterOperationsByScope,
@@ -4162,12 +4523,16 @@ export {
4162
4523
  getRemoteAwarenessStates,
4163
4524
  isAcknowledgmentMessage,
4164
4525
  isAwarenessUpdateMessage,
4526
+ isBlobChunkPushMessage,
4527
+ isBlobChunkRequestMessage,
4528
+ isBlobChunkResponseMessage,
4165
4529
  isClientSchemaVersionSupported,
4166
4530
  isEncryptedPayload,
4167
4531
  isErrorMessage,
4168
4532
  isHandshakeMessage,
4169
4533
  isHandshakeResponseMessage,
4170
4534
  isOperationBatchMessage,
4535
+ isOperationRejectedMessage,
4171
4536
  isSchemaMismatchReject,
4172
4537
  isSyncMessage,
4173
4538
  isYjsDocUpdateMessage,