@korajs/sync 1.0.0-beta.0 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +250 -19
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +86 -3
- package/dist/index.d.ts +86 -3
- package/dist/index.js +229 -4
- package/dist/index.js.map +1 -1
- package/dist/internal.d.cts +1 -1
- package/dist/internal.d.ts +1 -1
- package/dist/{transport-BMesMB6s.d.cts → transport-CZLMdZ0k.d.cts} +65 -2
- package/dist/{transport-BMesMB6s.d.ts → transport-CZLMdZ0k.d.ts} +65 -2
- package/package.json +4 -3
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
AwarenessManager: () => AwarenessManager,
|
|
34
|
+
BlobChunkChannel: () => BlobChunkChannel,
|
|
34
35
|
ChaosTransport: () => ChaosTransport,
|
|
35
36
|
ConnectionMonitor: () => ConnectionMonitor,
|
|
36
37
|
DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD: () => DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD,
|
|
@@ -55,11 +56,13 @@ __export(index_exports, {
|
|
|
55
56
|
WebSocketTransport: () => WebSocketTransport,
|
|
56
57
|
createDeltaCursorFromBatch: () => createDeltaCursorFromBatch,
|
|
57
58
|
createSyncStatusController: () => createSyncStatusController,
|
|
59
|
+
decodeBlobChunkBytes: () => decodeBlobChunkBytes,
|
|
58
60
|
decodeDeltaCursor: () => decodeDeltaCursor,
|
|
59
61
|
decodeYjsUpdate: () => decodeYjsUpdate,
|
|
60
62
|
dedupeQuerySubsets: () => dedupeQuerySubsets,
|
|
61
63
|
deriveKey: () => deriveKey,
|
|
62
64
|
deriveVersionedKey: () => deriveVersionedKey,
|
|
65
|
+
encodeBlobChunkBytes: () => encodeBlobChunkBytes,
|
|
63
66
|
encodeDeltaCursor: () => encodeDeltaCursor,
|
|
64
67
|
encodeYjsUpdate: () => encodeYjsUpdate,
|
|
65
68
|
filterOperationsByScope: () => filterOperationsByScope,
|
|
@@ -67,6 +70,9 @@ __export(index_exports, {
|
|
|
67
70
|
getRemoteAwarenessStates: () => getRemoteAwarenessStates,
|
|
68
71
|
isAcknowledgmentMessage: () => isAcknowledgmentMessage,
|
|
69
72
|
isAwarenessUpdateMessage: () => isAwarenessUpdateMessage,
|
|
73
|
+
isBlobChunkPushMessage: () => isBlobChunkPushMessage,
|
|
74
|
+
isBlobChunkRequestMessage: () => isBlobChunkRequestMessage,
|
|
75
|
+
isBlobChunkResponseMessage: () => isBlobChunkResponseMessage,
|
|
70
76
|
isClientSchemaVersionSupported: () => isClientSchemaVersionSupported,
|
|
71
77
|
isEncryptedPayload: () => isEncryptedPayload,
|
|
72
78
|
isErrorMessage: () => isErrorMessage,
|
|
@@ -306,6 +312,12 @@ function isSyncMessage(value) {
|
|
|
306
312
|
return isAwarenessUpdateMessage(value);
|
|
307
313
|
case "yjs-doc-update":
|
|
308
314
|
return isYjsDocUpdateMessage(value);
|
|
315
|
+
case "blob-chunk-request":
|
|
316
|
+
return isBlobChunkRequestMessage(value);
|
|
317
|
+
case "blob-chunk-response":
|
|
318
|
+
return isBlobChunkResponseMessage(value);
|
|
319
|
+
case "blob-chunk-push":
|
|
320
|
+
return isBlobChunkPushMessage(value);
|
|
309
321
|
default:
|
|
310
322
|
return false;
|
|
311
323
|
}
|
|
@@ -345,6 +357,21 @@ function isYjsDocUpdateMessage(value) {
|
|
|
345
357
|
const msg = value;
|
|
346
358
|
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";
|
|
347
359
|
}
|
|
360
|
+
function isBlobChunkRequestMessage(value) {
|
|
361
|
+
if (typeof value !== "object" || value === null) return false;
|
|
362
|
+
const msg = value;
|
|
363
|
+
return msg.type === "blob-chunk-request" && typeof msg.messageId === "string" && typeof msg.requestId === "string" && typeof msg.hash === "string";
|
|
364
|
+
}
|
|
365
|
+
function isBlobChunkResponseMessage(value) {
|
|
366
|
+
if (typeof value !== "object" || value === null) return false;
|
|
367
|
+
const msg = value;
|
|
368
|
+
return msg.type === "blob-chunk-response" && typeof msg.messageId === "string" && typeof msg.requestId === "string" && (typeof msg.bytes === "string" || msg.bytes === null);
|
|
369
|
+
}
|
|
370
|
+
function isBlobChunkPushMessage(value) {
|
|
371
|
+
if (typeof value !== "object" || value === null) return false;
|
|
372
|
+
const msg = value;
|
|
373
|
+
return msg.type === "blob-chunk-push" && typeof msg.messageId === "string" && typeof msg.hash === "string" && typeof msg.bytes === "string";
|
|
374
|
+
}
|
|
348
375
|
|
|
349
376
|
// src/protocol/serializer.ts
|
|
350
377
|
var import_core2 = require("@korajs/core");
|
|
@@ -585,7 +612,8 @@ function toProtoEnvelope(message) {
|
|
|
585
612
|
accepted: message.accepted,
|
|
586
613
|
rejectReason: message.rejectReason,
|
|
587
614
|
selectedWireFormat: message.selectedWireFormat,
|
|
588
|
-
serverTime: message.serverTime
|
|
615
|
+
serverTime: message.serverTime,
|
|
616
|
+
blobStorageEnabled: message.blobStorageEnabled
|
|
589
617
|
};
|
|
590
618
|
case "operation-batch":
|
|
591
619
|
return {
|
|
@@ -616,6 +644,28 @@ function toProtoEnvelope(message) {
|
|
|
616
644
|
type: message.type,
|
|
617
645
|
messageId: message.messageId
|
|
618
646
|
};
|
|
647
|
+
case "blob-chunk-request":
|
|
648
|
+
return {
|
|
649
|
+
type: message.type,
|
|
650
|
+
messageId: message.messageId,
|
|
651
|
+
requestId: message.requestId,
|
|
652
|
+
hash: message.hash
|
|
653
|
+
};
|
|
654
|
+
case "blob-chunk-response":
|
|
655
|
+
return {
|
|
656
|
+
type: message.type,
|
|
657
|
+
messageId: message.messageId,
|
|
658
|
+
requestId: message.requestId,
|
|
659
|
+
hasBytes: message.bytes !== null,
|
|
660
|
+
...message.bytes !== null ? { chunkBytes: message.bytes } : {}
|
|
661
|
+
};
|
|
662
|
+
case "blob-chunk-push":
|
|
663
|
+
return {
|
|
664
|
+
type: message.type,
|
|
665
|
+
messageId: message.messageId,
|
|
666
|
+
hash: message.hash,
|
|
667
|
+
chunkBytes: message.bytes
|
|
668
|
+
};
|
|
619
669
|
}
|
|
620
670
|
}
|
|
621
671
|
function fromProtoEnvelope(envelope) {
|
|
@@ -648,7 +698,8 @@ function fromProtoEnvelope(envelope) {
|
|
|
648
698
|
selectedWireFormat: envelope.selectedWireFormat === "json" || envelope.selectedWireFormat === "protobuf" ? envelope.selectedWireFormat : void 0,
|
|
649
699
|
// Preserve the server's wall-clock time so clock-skew detection and
|
|
650
700
|
// automatic timestamp rebase work over the protobuf wire, not just JSON.
|
|
651
|
-
...envelope.serverTime !== void 0 ? { serverTime: envelope.serverTime } : {}
|
|
701
|
+
...envelope.serverTime !== void 0 ? { serverTime: envelope.serverTime } : {},
|
|
702
|
+
...envelope.blobStorageEnabled !== void 0 ? { blobStorageEnabled: envelope.blobStorageEnabled } : {}
|
|
652
703
|
};
|
|
653
704
|
case "operation-batch":
|
|
654
705
|
return {
|
|
@@ -673,6 +724,27 @@ function fromProtoEnvelope(envelope) {
|
|
|
673
724
|
message: envelope.errorMessage ?? "Unknown error",
|
|
674
725
|
retriable: envelope.retriable ?? false
|
|
675
726
|
};
|
|
727
|
+
case "blob-chunk-request":
|
|
728
|
+
return {
|
|
729
|
+
type: "blob-chunk-request",
|
|
730
|
+
messageId: envelope.messageId,
|
|
731
|
+
requestId: envelope.requestId ?? "",
|
|
732
|
+
hash: envelope.hash ?? ""
|
|
733
|
+
};
|
|
734
|
+
case "blob-chunk-response":
|
|
735
|
+
return {
|
|
736
|
+
type: "blob-chunk-response",
|
|
737
|
+
messageId: envelope.messageId,
|
|
738
|
+
requestId: envelope.requestId ?? "",
|
|
739
|
+
bytes: envelope.hasBytes ? envelope.chunkBytes ?? "" : null
|
|
740
|
+
};
|
|
741
|
+
case "blob-chunk-push":
|
|
742
|
+
return {
|
|
743
|
+
type: "blob-chunk-push",
|
|
744
|
+
messageId: envelope.messageId,
|
|
745
|
+
hash: envelope.hash ?? "",
|
|
746
|
+
bytes: envelope.chunkBytes ?? ""
|
|
747
|
+
};
|
|
676
748
|
default:
|
|
677
749
|
throw new import_core2.SyncError("Failed to decode sync message: unknown protobuf type", {
|
|
678
750
|
type: envelope.type
|
|
@@ -818,6 +890,14 @@ function encodeEnvelope(envelope) {
|
|
|
818
890
|
}
|
|
819
891
|
if (envelope.retriable !== void 0) writer.uint32(144).bool(envelope.retriable);
|
|
820
892
|
if (envelope.serverTime !== void 0) writer.uint32(152).int64(envelope.serverTime);
|
|
893
|
+
if (envelope.requestId && envelope.requestId.length > 0)
|
|
894
|
+
writer.uint32(162).string(envelope.requestId);
|
|
895
|
+
if (envelope.hash && envelope.hash.length > 0) writer.uint32(170).string(envelope.hash);
|
|
896
|
+
if (envelope.chunkBytes && envelope.chunkBytes.length > 0)
|
|
897
|
+
writer.uint32(178).string(envelope.chunkBytes);
|
|
898
|
+
if (envelope.hasBytes !== void 0) writer.uint32(184).bool(envelope.hasBytes);
|
|
899
|
+
if (envelope.blobStorageEnabled !== void 0)
|
|
900
|
+
writer.uint32(200).bool(envelope.blobStorageEnabled);
|
|
821
901
|
return writer.finish();
|
|
822
902
|
}
|
|
823
903
|
function decodeEnvelope(bytes) {
|
|
@@ -889,6 +969,21 @@ function decodeEnvelope(bytes) {
|
|
|
889
969
|
case 19:
|
|
890
970
|
envelope.serverTime = longToNumber(reader.int64());
|
|
891
971
|
break;
|
|
972
|
+
case 20:
|
|
973
|
+
envelope.requestId = reader.string();
|
|
974
|
+
break;
|
|
975
|
+
case 21:
|
|
976
|
+
envelope.hash = reader.string();
|
|
977
|
+
break;
|
|
978
|
+
case 22:
|
|
979
|
+
envelope.chunkBytes = reader.string();
|
|
980
|
+
break;
|
|
981
|
+
case 23:
|
|
982
|
+
envelope.hasBytes = reader.bool();
|
|
983
|
+
break;
|
|
984
|
+
case 25:
|
|
985
|
+
envelope.blobStorageEnabled = reader.bool();
|
|
986
|
+
break;
|
|
892
987
|
default:
|
|
893
988
|
reader.skipType(tag & 7);
|
|
894
989
|
}
|
|
@@ -1480,7 +1575,7 @@ var ChaosTransport = class {
|
|
|
1480
1575
|
};
|
|
1481
1576
|
|
|
1482
1577
|
// src/engine/sync-engine.ts
|
|
1483
|
-
var
|
|
1578
|
+
var import_core7 = require("@korajs/core");
|
|
1484
1579
|
var import_internal2 = require("@korajs/core/internal");
|
|
1485
1580
|
|
|
1486
1581
|
// src/awareness/awareness-manager.ts
|
|
@@ -1689,6 +1784,95 @@ var AwarenessManager = class {
|
|
|
1689
1784
|
}
|
|
1690
1785
|
};
|
|
1691
1786
|
|
|
1787
|
+
// src/blob/blob-chunk-channel.ts
|
|
1788
|
+
var import_core5 = require("@korajs/core");
|
|
1789
|
+
function encodeBlobChunkBytes(bytes) {
|
|
1790
|
+
let binary = "";
|
|
1791
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
1792
|
+
binary += String.fromCharCode(bytes[i]);
|
|
1793
|
+
}
|
|
1794
|
+
return btoa(binary);
|
|
1795
|
+
}
|
|
1796
|
+
function decodeBlobChunkBytes(encoded) {
|
|
1797
|
+
const binary = atob(encoded);
|
|
1798
|
+
const out = new Uint8Array(binary.length);
|
|
1799
|
+
for (let i = 0; i < binary.length; i++) {
|
|
1800
|
+
out[i] = binary.charCodeAt(i);
|
|
1801
|
+
}
|
|
1802
|
+
return out;
|
|
1803
|
+
}
|
|
1804
|
+
var BlobChunkChannel = class {
|
|
1805
|
+
onSend;
|
|
1806
|
+
handlers = /* @__PURE__ */ new Set();
|
|
1807
|
+
constructor(options) {
|
|
1808
|
+
this.onSend = options?.onSend ?? null;
|
|
1809
|
+
}
|
|
1810
|
+
/**
|
|
1811
|
+
* Send a blob-chunk message to the peer. Response bytes are base64-encoded
|
|
1812
|
+
* onto the wire here; callers pass a `Uint8Array`.
|
|
1813
|
+
*/
|
|
1814
|
+
send(message) {
|
|
1815
|
+
if (!this.onSend) {
|
|
1816
|
+
return;
|
|
1817
|
+
}
|
|
1818
|
+
if (message.type === "blob-chunk-request") {
|
|
1819
|
+
this.onSend({
|
|
1820
|
+
type: "blob-chunk-request",
|
|
1821
|
+
messageId: (0, import_core5.generateUUIDv7)(),
|
|
1822
|
+
requestId: message.requestId,
|
|
1823
|
+
hash: message.hash
|
|
1824
|
+
});
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
if (message.type === "blob-chunk-push") {
|
|
1828
|
+
this.onSend({
|
|
1829
|
+
type: "blob-chunk-push",
|
|
1830
|
+
messageId: (0, import_core5.generateUUIDv7)(),
|
|
1831
|
+
hash: message.hash,
|
|
1832
|
+
bytes: encodeBlobChunkBytes(message.bytes)
|
|
1833
|
+
});
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
this.onSend({
|
|
1837
|
+
type: "blob-chunk-response",
|
|
1838
|
+
messageId: (0, import_core5.generateUUIDv7)(),
|
|
1839
|
+
requestId: message.requestId,
|
|
1840
|
+
bytes: message.bytes === null ? null : encodeBlobChunkBytes(message.bytes)
|
|
1841
|
+
});
|
|
1842
|
+
}
|
|
1843
|
+
/**
|
|
1844
|
+
* Register a handler for inbound blob-chunk messages. Multiple handlers are
|
|
1845
|
+
* allowed; each receives every delivered message.
|
|
1846
|
+
*/
|
|
1847
|
+
onMessage(handler) {
|
|
1848
|
+
this.handlers.add(handler);
|
|
1849
|
+
return () => {
|
|
1850
|
+
this.handlers.delete(handler);
|
|
1851
|
+
};
|
|
1852
|
+
}
|
|
1853
|
+
/**
|
|
1854
|
+
* Deliver an inbound wire message to registered handlers, decoding response
|
|
1855
|
+
* bytes from base64 back to a `Uint8Array` first.
|
|
1856
|
+
*/
|
|
1857
|
+
deliver(message) {
|
|
1858
|
+
if (this.handlers.size === 0) {
|
|
1859
|
+
return;
|
|
1860
|
+
}
|
|
1861
|
+
const decoded = message.type === "blob-chunk-request" ? { type: "blob-chunk-request", requestId: message.requestId, hash: message.hash } : message.type === "blob-chunk-push" ? {
|
|
1862
|
+
type: "blob-chunk-push",
|
|
1863
|
+
hash: message.hash,
|
|
1864
|
+
bytes: decodeBlobChunkBytes(message.bytes)
|
|
1865
|
+
} : {
|
|
1866
|
+
type: "blob-chunk-response",
|
|
1867
|
+
requestId: message.requestId,
|
|
1868
|
+
bytes: message.bytes === null ? null : decodeBlobChunkBytes(message.bytes)
|
|
1869
|
+
};
|
|
1870
|
+
for (const handler of this.handlers) {
|
|
1871
|
+
handler(decoded);
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1874
|
+
};
|
|
1875
|
+
|
|
1692
1876
|
// src/diagnostics/bandwidth-estimator.ts
|
|
1693
1877
|
var BandwidthEstimator = class {
|
|
1694
1878
|
maxSamples;
|
|
@@ -2132,7 +2316,7 @@ var SyncMetricsCollector = class {
|
|
|
2132
2316
|
};
|
|
2133
2317
|
|
|
2134
2318
|
// src/richtext/richtext-doc-channel.ts
|
|
2135
|
-
var
|
|
2319
|
+
var import_core6 = require("@korajs/core");
|
|
2136
2320
|
|
|
2137
2321
|
// src/richtext/doc-channel-wire.ts
|
|
2138
2322
|
function encodeYjsUpdate(update) {
|
|
@@ -2211,7 +2395,7 @@ var RichtextDocChannel = class {
|
|
|
2211
2395
|
}
|
|
2212
2396
|
this.onSend({
|
|
2213
2397
|
type: "yjs-doc-update",
|
|
2214
|
-
messageId: (0,
|
|
2398
|
+
messageId: (0, import_core6.generateUUIDv7)(),
|
|
2215
2399
|
collection,
|
|
2216
2400
|
recordId,
|
|
2217
2401
|
field,
|
|
@@ -2443,6 +2627,7 @@ var SyncEngine = class {
|
|
|
2443
2627
|
encryptor;
|
|
2444
2628
|
awarenessManager;
|
|
2445
2629
|
richtextDocChannel;
|
|
2630
|
+
blobChunkChannel;
|
|
2446
2631
|
metricsCollector;
|
|
2447
2632
|
syncState;
|
|
2448
2633
|
remoteVector = /* @__PURE__ */ new Map();
|
|
@@ -2457,6 +2642,7 @@ var SyncEngine = class {
|
|
|
2457
2642
|
schemaBlocked = false;
|
|
2458
2643
|
clockBlocked = false;
|
|
2459
2644
|
clockSkewMs = null;
|
|
2645
|
+
blobStorageEnabled = false;
|
|
2460
2646
|
// Track delta exchange state
|
|
2461
2647
|
deltaBatchesReceived = 0;
|
|
2462
2648
|
deltaReceiveComplete = false;
|
|
@@ -2505,6 +2691,14 @@ var SyncEngine = class {
|
|
|
2505
2691
|
this.transport.send(message);
|
|
2506
2692
|
}
|
|
2507
2693
|
});
|
|
2694
|
+
this.blobChunkChannel = new BlobChunkChannel({
|
|
2695
|
+
onSend: (message) => {
|
|
2696
|
+
if (this.state !== "streaming") {
|
|
2697
|
+
return;
|
|
2698
|
+
}
|
|
2699
|
+
this.transport.send(message);
|
|
2700
|
+
}
|
|
2701
|
+
});
|
|
2508
2702
|
this.awarenessManager.onSend((message) => {
|
|
2509
2703
|
if (this.state !== "streaming") return;
|
|
2510
2704
|
const wireMessage = {
|
|
@@ -2521,7 +2715,7 @@ var SyncEngine = class {
|
|
|
2521
2715
|
*/
|
|
2522
2716
|
async start() {
|
|
2523
2717
|
if (this.state !== "disconnected") {
|
|
2524
|
-
throw new
|
|
2718
|
+
throw new import_core7.SyncError("Cannot start sync engine: not in disconnected state", {
|
|
2525
2719
|
currentState: this.state
|
|
2526
2720
|
});
|
|
2527
2721
|
}
|
|
@@ -2538,7 +2732,7 @@ var SyncEngine = class {
|
|
|
2538
2732
|
this.transport.onClose((reason) => this.handleTransportClose(reason));
|
|
2539
2733
|
this.transport.onError((err) => this.handleTransportError(err));
|
|
2540
2734
|
if (this.schemaBlocked) {
|
|
2541
|
-
throw new
|
|
2735
|
+
throw new import_core7.SyncError(
|
|
2542
2736
|
"Sync is blocked due to schema version mismatch. Upgrade the app schema or align sync.schemaVersion with the server.",
|
|
2543
2737
|
{ code: "SCHEMA_MISMATCH_BLOCKED" }
|
|
2544
2738
|
);
|
|
@@ -2708,7 +2902,7 @@ var SyncEngine = class {
|
|
|
2708
2902
|
return this.getStatus().pendingOperations;
|
|
2709
2903
|
}
|
|
2710
2904
|
emitApplyFailure(op, result, overrides) {
|
|
2711
|
-
const reason = (0,
|
|
2905
|
+
const reason = (0, import_core7.defaultApplyFailureReason)(result, overrides);
|
|
2712
2906
|
this.emitter?.emit({
|
|
2713
2907
|
type: "sync:apply-failed",
|
|
2714
2908
|
operationId: op.id,
|
|
@@ -2818,6 +3012,31 @@ var SyncEngine = class {
|
|
|
2818
3012
|
getRichtextDocChannel() {
|
|
2819
3013
|
return this.richtextDocChannel;
|
|
2820
3014
|
}
|
|
3015
|
+
/**
|
|
3016
|
+
* Side channel for out-of-band blob chunk transfer over the sync connection.
|
|
3017
|
+
* The app layer bridges this to a `ChunkMessagePort` to pull/serve blob bytes.
|
|
3018
|
+
*/
|
|
3019
|
+
getBlobChunkChannel() {
|
|
3020
|
+
return this.blobChunkChannel;
|
|
3021
|
+
}
|
|
3022
|
+
/**
|
|
3023
|
+
* Whether the connected server persists blob bytes centrally (learned from the
|
|
3024
|
+
* handshake response). When true, the app uploads the bytes behind `blob`
|
|
3025
|
+
* fields so they stay available after the authoring device goes offline.
|
|
3026
|
+
*/
|
|
3027
|
+
isBlobStorageEnabled() {
|
|
3028
|
+
return this.blobStorageEnabled;
|
|
3029
|
+
}
|
|
3030
|
+
/**
|
|
3031
|
+
* Upload a blob chunk (or manifest) to the server for central persistence.
|
|
3032
|
+
* A no-op unless connected and the server advertised blob storage.
|
|
3033
|
+
*/
|
|
3034
|
+
uploadBlobChunk(hash, bytes) {
|
|
3035
|
+
if (this.state !== "streaming" || !this.blobStorageEnabled) {
|
|
3036
|
+
return;
|
|
3037
|
+
}
|
|
3038
|
+
this.blobChunkChannel.send({ type: "blob-chunk-push", hash, bytes });
|
|
3039
|
+
}
|
|
2821
3040
|
// --- Private methods ---
|
|
2822
3041
|
messageChain = Promise.resolve();
|
|
2823
3042
|
enqueueMessage(message) {
|
|
@@ -2843,6 +3062,11 @@ var SyncEngine = class {
|
|
|
2843
3062
|
case "yjs-doc-update":
|
|
2844
3063
|
this.richtextDocChannel.deliver(message);
|
|
2845
3064
|
break;
|
|
3065
|
+
case "blob-chunk-request":
|
|
3066
|
+
case "blob-chunk-response":
|
|
3067
|
+
case "blob-chunk-push":
|
|
3068
|
+
this.blobChunkChannel.deliver(message);
|
|
3069
|
+
break;
|
|
2846
3070
|
}
|
|
2847
3071
|
}
|
|
2848
3072
|
handleMessageFailure(error) {
|
|
@@ -2875,6 +3099,7 @@ var SyncEngine = class {
|
|
|
2875
3099
|
}
|
|
2876
3100
|
async handleHandshakeResponse(msg) {
|
|
2877
3101
|
if (this.state !== "handshaking") return;
|
|
3102
|
+
this.blobStorageEnabled = msg.blobStorageEnabled === true;
|
|
2878
3103
|
if (typeof msg.serverTime === "number") {
|
|
2879
3104
|
this.evaluateClockSkew(msg.serverTime);
|
|
2880
3105
|
if (this.clockBlocked) {
|
|
@@ -3059,7 +3284,7 @@ var SyncEngine = class {
|
|
|
3059
3284
|
const targetSchemaVersion = this.config.schemaVersion ?? DEFAULT_SCHEMA_VERSION;
|
|
3060
3285
|
const transforms = this.config.operationTransforms ?? [];
|
|
3061
3286
|
for (const op of inScopeOps) {
|
|
3062
|
-
const transformed = transforms.length > 0 ? (0,
|
|
3287
|
+
const transformed = transforms.length > 0 ? (0, import_core7.applyOperationTransforms)(op, targetSchemaVersion, transforms) : op;
|
|
3063
3288
|
if (transformed === null) {
|
|
3064
3289
|
continue;
|
|
3065
3290
|
}
|
|
@@ -3069,20 +3294,20 @@ var SyncEngine = class {
|
|
|
3069
3294
|
this.emitApplyFailure(transformed, result);
|
|
3070
3295
|
}
|
|
3071
3296
|
} catch (error) {
|
|
3072
|
-
if (error instanceof
|
|
3297
|
+
if (error instanceof import_core7.ClockDriftError) {
|
|
3073
3298
|
this.emitApplyFailure(transformed, "rejected", {
|
|
3074
|
-
code:
|
|
3299
|
+
code: import_core7.APPLY_FAILURE_CODES.CLOCK_DRIFT,
|
|
3075
3300
|
message: error.message,
|
|
3076
3301
|
retriable: false
|
|
3077
3302
|
});
|
|
3078
3303
|
continue;
|
|
3079
3304
|
}
|
|
3080
3305
|
const message = error instanceof Error ? error.message : "Apply failed";
|
|
3081
|
-
const code = error instanceof
|
|
3306
|
+
const code = error instanceof import_core7.SyncError ? error.code : error instanceof import_core7.KoraError ? error.code : error instanceof Error && "code" in error && typeof error.code === "string" ? error.code : import_core7.APPLY_FAILURE_CODES.APPLY_FAILED;
|
|
3082
3307
|
this.emitApplyFailure(transformed, "rejected", {
|
|
3083
3308
|
code,
|
|
3084
3309
|
message,
|
|
3085
|
-
retriable: code !==
|
|
3310
|
+
retriable: code !== import_core7.APPLY_FAILURE_CODES.REFERENTIAL_INTEGRITY
|
|
3086
3311
|
});
|
|
3087
3312
|
}
|
|
3088
3313
|
}
|
|
@@ -3352,7 +3577,7 @@ var SyncEngine = class {
|
|
|
3352
3577
|
transitionTo(newState) {
|
|
3353
3578
|
const validTargets = VALID_TRANSITIONS[this.state];
|
|
3354
3579
|
if (!validTargets.includes(newState)) {
|
|
3355
|
-
throw new
|
|
3580
|
+
throw new import_core7.SyncError(`Invalid sync state transition: ${this.state} \u2192 ${newState}`, {
|
|
3356
3581
|
from: this.state,
|
|
3357
3582
|
to: newState
|
|
3358
3583
|
});
|
|
@@ -3634,11 +3859,11 @@ var ReconnectionManager = class {
|
|
|
3634
3859
|
};
|
|
3635
3860
|
|
|
3636
3861
|
// src/encryption/sync-encryptor.ts
|
|
3637
|
-
var
|
|
3862
|
+
var import_core9 = require("@korajs/core");
|
|
3638
3863
|
|
|
3639
3864
|
// src/encryption/key-derivation.ts
|
|
3640
|
-
var
|
|
3641
|
-
var KeyDerivationError = class extends
|
|
3865
|
+
var import_core8 = require("@korajs/core");
|
|
3866
|
+
var KeyDerivationError = class extends import_core8.SyncError {
|
|
3642
3867
|
constructor(message, context) {
|
|
3643
3868
|
super(message, { ...context, errorType: "KEY_DERIVATION_ERROR" });
|
|
3644
3869
|
this.name = "KeyDerivationError";
|
|
@@ -3720,13 +3945,13 @@ async function deriveVersionedKey(passphrase, version, salt, iterations = DEFAUL
|
|
|
3720
3945
|
}
|
|
3721
3946
|
|
|
3722
3947
|
// src/encryption/sync-encryptor.ts
|
|
3723
|
-
var EncryptionError = class extends
|
|
3948
|
+
var EncryptionError = class extends import_core9.SyncError {
|
|
3724
3949
|
constructor(message, context) {
|
|
3725
3950
|
super(message, { ...context, errorType: "ENCRYPTION_ERROR" });
|
|
3726
3951
|
this.name = "EncryptionError";
|
|
3727
3952
|
}
|
|
3728
3953
|
};
|
|
3729
|
-
var DecryptionError = class extends
|
|
3954
|
+
var DecryptionError = class extends import_core9.SyncError {
|
|
3730
3955
|
constructor(message, context) {
|
|
3731
3956
|
super(message, { ...context, errorType: "DECRYPTION_ERROR" });
|
|
3732
3957
|
this.name = "DecryptionError";
|
|
@@ -4223,6 +4448,7 @@ function subscribeRemoteAwarenessStates(awareness, listener) {
|
|
|
4223
4448
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4224
4449
|
0 && (module.exports = {
|
|
4225
4450
|
AwarenessManager,
|
|
4451
|
+
BlobChunkChannel,
|
|
4226
4452
|
ChaosTransport,
|
|
4227
4453
|
ConnectionMonitor,
|
|
4228
4454
|
DEFAULT_RICHTEXT_DOC_CHANNEL_THRESHOLD,
|
|
@@ -4247,11 +4473,13 @@ function subscribeRemoteAwarenessStates(awareness, listener) {
|
|
|
4247
4473
|
WebSocketTransport,
|
|
4248
4474
|
createDeltaCursorFromBatch,
|
|
4249
4475
|
createSyncStatusController,
|
|
4476
|
+
decodeBlobChunkBytes,
|
|
4250
4477
|
decodeDeltaCursor,
|
|
4251
4478
|
decodeYjsUpdate,
|
|
4252
4479
|
dedupeQuerySubsets,
|
|
4253
4480
|
deriveKey,
|
|
4254
4481
|
deriveVersionedKey,
|
|
4482
|
+
encodeBlobChunkBytes,
|
|
4255
4483
|
encodeDeltaCursor,
|
|
4256
4484
|
encodeYjsUpdate,
|
|
4257
4485
|
filterOperationsByScope,
|
|
@@ -4259,6 +4487,9 @@ function subscribeRemoteAwarenessStates(awareness, listener) {
|
|
|
4259
4487
|
getRemoteAwarenessStates,
|
|
4260
4488
|
isAcknowledgmentMessage,
|
|
4261
4489
|
isAwarenessUpdateMessage,
|
|
4490
|
+
isBlobChunkPushMessage,
|
|
4491
|
+
isBlobChunkRequestMessage,
|
|
4492
|
+
isBlobChunkResponseMessage,
|
|
4262
4493
|
isClientSchemaVersionSupported,
|
|
4263
4494
|
isEncryptedPayload,
|
|
4264
4495
|
isErrorMessage,
|