@loro-dev/streams-crdt 0.1.0 → 0.1.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/README.md CHANGED
@@ -295,6 +295,91 @@ The required ordering is:
295
295
  If you cannot provide steps 1 and 3, do not use a persisted remote cursor
296
296
  store.
297
297
 
298
+ ## Snapshot Codec Hooks
299
+
300
+ Use `snapshotCodec` when you want transport to transform full snapshots during
301
+ upload and bootstrap:
302
+
303
+ ```ts
304
+ const transport = new StreamsCrdt({
305
+ streamUrl,
306
+ adapter: createLoroDocAdapter(doc),
307
+ snapshotCodec: {
308
+ // Sync or async are both allowed.
309
+ compress: async (snapshot) => snapshot,
310
+ decompress: (snapshot) => snapshot,
311
+ },
312
+ });
313
+ ```
314
+
315
+ ### Behavior
316
+
317
+ - `snapshotCodec.compress(snapshot)` runs right before a snapshot is uploaded to
318
+ Loro Streams
319
+ - `snapshotCodec.decompress(snapshot)` runs right after a non-empty snapshot is
320
+ downloaded from Loro Streams and right before `adapter.applySnapshot(...)`
321
+ - Both hooks must be provided together
322
+ - Both hooks may return either `Uint8Array` or `Promise<Uint8Array>`
323
+ - These hooks affect **full snapshots only**. Incremental update batches are
324
+ unchanged
325
+
326
+ ### Compatibility
327
+
328
+ Transport does not version or negotiate snapshot codecs for you.
329
+
330
+ If you enable `snapshotCodec`, you must make sure `decompress` can still read
331
+ any older snapshots that are already stored for that stream. This is especially
332
+ important when:
333
+
334
+ - existing snapshots were uploaded without compression
335
+ - you change the compression format later
336
+ - you roll out the codec gradually across clients
337
+
338
+ ### `@loro-dev/streams-crdt/zstd`
339
+
340
+ `@loro-dev/streams-crdt/zstd` is an optional helper entry point built on top of
341
+ [`@bokuweb/zstd-wasm`](https://www.npmjs.com/package/@bokuweb/zstd-wasm).
342
+
343
+ Install the optional peer dependency first:
344
+
345
+ ```bash
346
+ pnpm add @loro-dev/streams-crdt @bokuweb/zstd-wasm
347
+ ```
348
+
349
+ Then wire the exported hooks directly into `snapshotCodec`:
350
+
351
+ ```ts
352
+ import { LoroDoc } from "loro-crdt";
353
+ import {
354
+ createLoroDocAdapter,
355
+ createStreamUrl,
356
+ StreamsCrdt,
357
+ } from "@loro-dev/streams-crdt/loro";
358
+ import {
359
+ compress,
360
+ decompress,
361
+ } from "@loro-dev/streams-crdt/zstd";
362
+
363
+ const doc = new LoroDoc();
364
+ const transport = new StreamsCrdt({
365
+ streamUrl: createStreamUrl({
366
+ bucketId: "my-bucket",
367
+ streamId: "doc-1",
368
+ }),
369
+ adapter: createLoroDocAdapter(doc),
370
+ snapshotCodec: { compress, decompress },
371
+ });
372
+ ```
373
+
374
+ `@loro-dev/streams-crdt/zstd` exports:
375
+
376
+ - `compress(snapshot)` — async; uses an extra Worker when available and falls
377
+ back to the current thread otherwise
378
+ - `compressInWorker(snapshot)` — async; worker-only compression helper
379
+ - `compressOnCurrentThread(snapshot)` — async; current-thread compression
380
+ helper
381
+ - `decompress(snapshot)` — async; current-thread decompression helper
382
+
298
383
  ## Automatic Snapshot Upload
299
384
 
300
385
  The transport can upload snapshots automatically during `join()` when callers
@@ -348,6 +433,7 @@ const transport = new StreamsCrdt({
348
433
  | `@loro-dev/streams-crdt` | Transport core, cursor stores, ID helpers, all shared types |
349
434
  | `@loro-dev/streams-crdt/loro` | Everything above + `createLoroDocAdapter(doc)` |
350
435
  | `@loro-dev/streams-crdt/flock` | Everything above + `createFlockAdapter(flock)` |
436
+ | `@loro-dev/streams-crdt/zstd` | Snapshot `compress` / `decompress` hooks backed by `@bokuweb/zstd-wasm` |
351
437
 
352
438
  ## Public API Reference
353
439
 
@@ -364,6 +450,7 @@ const transport = new StreamsCrdt({
364
450
  - `TransportJoinParams` — `join()` options
365
451
  - `TransportSubscription` — active live subscription handle
366
452
  - `TransportRoomStatus` — `"joined" | "reconnecting" | "disconnected" | "error"`
453
+ - `SnapshotCodec`, `SnapshotTransformHook` — full snapshot encode/decode hooks
367
454
  - `SnapshotUploadOptions` — snapshot upload configuration
368
455
  - `RemoteCursor` — replay progress metadata
369
456
  - `RemoteCursorStore` — abstract cursor storage interface
@@ -389,6 +476,16 @@ const transport = new StreamsCrdt({
389
476
  - `createFlockAdapter(flock)` — creates a `CrdtAdapter` for one `Flock` replica
390
477
  - `FlockVersionVector` — Flock-specific version vector type
391
478
 
479
+ ### Zstd Entry Point
480
+
481
+ `@loro-dev/streams-crdt/zstd` exports:
482
+
483
+ - `compress(snapshot)` — async snapshot compression helper
484
+ - `compressInWorker(snapshot)` — async worker-only snapshot compression helper
485
+ - `compressOnCurrentThread(snapshot)` — async current-thread snapshot
486
+ compression helper
487
+ - `decompress(snapshot)` — async snapshot decompression helper
488
+
392
489
  ## Notes
393
490
 
394
491
  - `createStreamIfMissing` defaults to `false` and only affects the initial sync/join bootstrap
package/dist/flock.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as IndexedDbRemoteCursorStore, D as RemoteCursorStore, E as RemoteCursorSaveSource, O as createInitialRemoteCursor, S as InMemoryRemoteCursorStore, T as RemoteCursor, _ as TransportRoomStatus, a as CrdtAdapter, b as BeforeRemoteCursorSaveContext, c as JsonValue, d as StreamsAuthProvider, f as StreamsCrdtOptions, g as TransportJoinParams, h as TransportError, i as StreamsCrdt, l as Result, m as TransportDeleteStreamSuccess, n as isValidBucketId, o as CrdtUpdateBatch, p as TransportCreateStreamSuccess, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotUploadOptions, v as TransportSubscription, w as IndexedDbRemoteCursorStoreOptions, x as BeforeRemoteCursorSaveHook, y as TransportSyncSuccess } from "./stream-id-1f2mhtmk.js";
1
+ import { A as createInitialRemoteCursor, C as BeforeRemoteCursorSaveHook, D as RemoteCursor, E as IndexedDbRemoteCursorStoreOptions, O as RemoteCursorSaveSource, S as BeforeRemoteCursorSaveContext, T as IndexedDbRemoteCursorStore, _ as TransportError, a as CrdtAdapter, b as TransportSubscription, c as JsonValue, d as SnapshotTransformHook, f as SnapshotUploadOptions, g as TransportDeleteStreamSuccess, h as TransportCreateStreamSuccess, i as StreamsCrdt, k as RemoteCursorStore, l as Result, m as StreamsCrdtOptions, n as isValidBucketId, o as CrdtUpdateBatch, p as StreamsAuthProvider, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotCodec, v as TransportJoinParams, w as InMemoryRemoteCursorStore, x as TransportSyncSuccess, y as TransportRoomStatus } from "./stream-id-B9n-uFFB.js";
2
2
 
3
3
  //#region src/flock.d.ts
4
4
  type FlockVersionEntry = {
@@ -32,5 +32,5 @@ type FlockLike = {
32
32
  */
33
33
  declare function createFlockAdapter(flock: FlockLike): CrdtAdapter<JsonObject>;
34
34
  //#endregion
35
- export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, FlockVersionVector, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createFlockAdapter, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
35
+ export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, FlockVersionVector, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createFlockAdapter, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
36
36
  //# sourceMappingURL=flock.d.ts.map
package/dist/flock.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-CIhmveJD.js";
1
+ import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-YOFZ4I6Y.js";
2
2
  //#region src/flock.ts
3
3
  function toVersionVector(version) {
4
4
  const out = {};
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { C as IndexedDbRemoteCursorStore, D as RemoteCursorStore, E as RemoteCursorSaveSource, O as createInitialRemoteCursor, S as InMemoryRemoteCursorStore, T as RemoteCursor, _ as TransportRoomStatus, a as CrdtAdapter, b as BeforeRemoteCursorSaveContext, c as JsonValue, d as StreamsAuthProvider, f as StreamsCrdtOptions, g as TransportJoinParams, h as TransportError, i as StreamsCrdt, l as Result, m as TransportDeleteStreamSuccess, n as isValidBucketId, o as CrdtUpdateBatch, p as TransportCreateStreamSuccess, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotUploadOptions, v as TransportSubscription, w as IndexedDbRemoteCursorStoreOptions, x as BeforeRemoteCursorSaveHook, y as TransportSyncSuccess } from "./stream-id-1f2mhtmk.js";
2
- export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
1
+ import { A as createInitialRemoteCursor, C as BeforeRemoteCursorSaveHook, D as RemoteCursor, E as IndexedDbRemoteCursorStoreOptions, O as RemoteCursorSaveSource, S as BeforeRemoteCursorSaveContext, T as IndexedDbRemoteCursorStore, _ as TransportError, a as CrdtAdapter, b as TransportSubscription, c as JsonValue, d as SnapshotTransformHook, f as SnapshotUploadOptions, g as TransportDeleteStreamSuccess, h as TransportCreateStreamSuccess, i as StreamsCrdt, k as RemoteCursorStore, l as Result, m as StreamsCrdtOptions, n as isValidBucketId, o as CrdtUpdateBatch, p as StreamsAuthProvider, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotCodec, v as TransportJoinParams, w as InMemoryRemoteCursorStore, x as TransportSyncSuccess, y as TransportRoomStatus } from "./stream-id-B9n-uFFB.js";
2
+ export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-CIhmveJD.js";
1
+ import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-YOFZ4I6Y.js";
2
2
  export { InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, StreamsCrdt, createInitialRemoteCursor, createStreamUrl, isValidBucketId, isValidRillId };
package/dist/loro.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { C as IndexedDbRemoteCursorStore, D as RemoteCursorStore, E as RemoteCursorSaveSource, O as createInitialRemoteCursor, S as InMemoryRemoteCursorStore, T as RemoteCursor, _ as TransportRoomStatus, a as CrdtAdapter, b as BeforeRemoteCursorSaveContext, c as JsonValue, d as StreamsAuthProvider, f as StreamsCrdtOptions, g as TransportJoinParams, h as TransportError, i as StreamsCrdt, l as Result, m as TransportDeleteStreamSuccess, n as isValidBucketId, o as CrdtUpdateBatch, p as TransportCreateStreamSuccess, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotUploadOptions, v as TransportSubscription, w as IndexedDbRemoteCursorStoreOptions, x as BeforeRemoteCursorSaveHook, y as TransportSyncSuccess } from "./stream-id-1f2mhtmk.js";
1
+ import { A as createInitialRemoteCursor, C as BeforeRemoteCursorSaveHook, D as RemoteCursor, E as IndexedDbRemoteCursorStoreOptions, O as RemoteCursorSaveSource, S as BeforeRemoteCursorSaveContext, T as IndexedDbRemoteCursorStore, _ as TransportError, a as CrdtAdapter, b as TransportSubscription, c as JsonValue, d as SnapshotTransformHook, f as SnapshotUploadOptions, g as TransportDeleteStreamSuccess, h as TransportCreateStreamSuccess, i as StreamsCrdt, k as RemoteCursorStore, l as Result, m as StreamsCrdtOptions, n as isValidBucketId, o as CrdtUpdateBatch, p as StreamsAuthProvider, r as isValidRillId, s as JsonObject, t as createStreamUrl, u as SnapshotCodec, v as TransportJoinParams, w as InMemoryRemoteCursorStore, x as TransportSyncSuccess, y as TransportRoomStatus } from "./stream-id-B9n-uFFB.js";
2
2
  import { LoroDoc } from "loro-crdt";
3
3
 
4
4
  //#region src/loro.d.ts
@@ -18,5 +18,5 @@ import { LoroDoc } from "loro-crdt";
18
18
  */
19
19
  declare function createLoroDocAdapter(doc: LoroDoc): CrdtAdapter<JsonObject>;
20
20
  //#endregion
21
- export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createLoroDocAdapter, createStreamUrl, isValidBucketId, isValidRillId };
21
+ export { BeforeRemoteCursorSaveContext, BeforeRemoteCursorSaveHook, CrdtAdapter, CrdtUpdateBatch, InMemoryRemoteCursorStore, IndexedDbRemoteCursorStore, IndexedDbRemoteCursorStoreOptions, JsonObject, JsonValue, RemoteCursor, RemoteCursorSaveSource, RemoteCursorStore, Result, SnapshotCodec, SnapshotTransformHook, SnapshotUploadOptions, StreamsAuthProvider, StreamsCrdt, StreamsCrdtOptions, TransportCreateStreamSuccess, TransportDeleteStreamSuccess, TransportError, TransportJoinParams, TransportRoomStatus, TransportSubscription, TransportSyncSuccess, createInitialRemoteCursor, createLoroDocAdapter, createStreamUrl, isValidBucketId, isValidRillId };
22
22
  //# sourceMappingURL=loro.d.ts.map
package/dist/loro.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-CIhmveJD.js";
1
+ import { a as InMemoryRemoteCursorStore, i as StreamsCrdt, n as isValidBucketId, o as IndexedDbRemoteCursorStore, r as isValidRillId, s as createInitialRemoteCursor, t as createStreamUrl } from "./stream-id-YOFZ4I6Y.js";
2
2
  import { VersionVector, decodeImportBlobMeta } from "loro-crdt";
3
3
  //#region src/loro.ts
4
4
  function toDocVersionRecord(version) {
@@ -239,6 +239,24 @@ interface SnapshotUploadOptions {
239
239
  /** Minimum byte delta since the last remote snapshot before uploading. */
240
240
  readonly minBytesSinceRemoteSnapshot?: number;
241
241
  }
242
+ /**
243
+ * Transforms a remote snapshot payload during upload or bootstrap.
244
+ */
245
+ type SnapshotTransformHook = (snapshot: Uint8Array) => MaybePromise<Uint8Array>;
246
+ /**
247
+ * Optional snapshot codec hooks used only for full snapshot upload/bootstrap.
248
+ *
249
+ * `compress` runs before transport uploads a snapshot to Loro Streams.
250
+ * `decompress` runs after transport downloads a non-empty snapshot and before
251
+ * the adapter imports it.
252
+ *
253
+ * Callers own compatibility with any snapshots that were already uploaded
254
+ * without this codec or with an older codec revision.
255
+ */
256
+ interface SnapshotCodec {
257
+ readonly compress: SnapshotTransformHook;
258
+ readonly decompress: SnapshotTransformHook;
259
+ }
242
260
  /**
243
261
  * Active live subscription returned by `join()`.
244
262
  *
@@ -334,6 +352,17 @@ interface StreamsCrdtOptions<TVersion extends JsonObject> {
334
352
  * hooks.
335
353
  */
336
354
  readonly beforeRemoteCursorSaveHooks?: ReadonlyArray<BeforeRemoteCursorSaveHook<TVersion>>;
355
+ /**
356
+ * Optional codec hooks for full snapshots only.
357
+ *
358
+ * Both hooks must be provided together. If set, transport compresses the
359
+ * adapter snapshot before upload and decompresses downloaded snapshots before
360
+ * `applySnapshot()`.
361
+ *
362
+ * Callers must keep compatibility with any older snapshots already stored on
363
+ * the server.
364
+ */
365
+ readonly snapshotCodec?: SnapshotCodec;
337
366
  readonly snapshotUpload?: SnapshotUploadOptions;
338
367
  readonly reconnectConfig?: Partial<ReconnectConfig>;
339
368
  readonly debug?: boolean;
@@ -459,5 +488,5 @@ declare function createStreamUrl(input: {
459
488
  baseUrl?: string;
460
489
  }): string;
461
490
  //#endregion
462
- export { IndexedDbRemoteCursorStore as C, RemoteCursorStore as D, RemoteCursorSaveSource as E, createInitialRemoteCursor as O, InMemoryRemoteCursorStore as S, RemoteCursor as T, TransportRoomStatus as _, CrdtAdapter as a, BeforeRemoteCursorSaveContext as b, JsonValue as c, StreamsAuthProvider as d, StreamsCrdtOptions as f, TransportJoinParams as g, TransportError as h, StreamsCrdt as i, Result as l, TransportDeleteStreamSuccess as m, isValidBucketId as n, CrdtUpdateBatch as o, TransportCreateStreamSuccess as p, isValidRillId as r, JsonObject as s, createStreamUrl as t, SnapshotUploadOptions as u, TransportSubscription as v, IndexedDbRemoteCursorStoreOptions as w, BeforeRemoteCursorSaveHook as x, TransportSyncSuccess as y };
463
- //# sourceMappingURL=stream-id-1f2mhtmk.d.ts.map
491
+ export { createInitialRemoteCursor as A, BeforeRemoteCursorSaveHook as C, RemoteCursor as D, IndexedDbRemoteCursorStoreOptions as E, RemoteCursorSaveSource as O, BeforeRemoteCursorSaveContext as S, IndexedDbRemoteCursorStore as T, TransportError as _, CrdtAdapter as a, TransportSubscription as b, JsonValue as c, SnapshotTransformHook as d, SnapshotUploadOptions as f, TransportDeleteStreamSuccess as g, TransportCreateStreamSuccess as h, StreamsCrdt as i, RemoteCursorStore as k, Result as l, StreamsCrdtOptions as m, isValidBucketId as n, CrdtUpdateBatch as o, StreamsAuthProvider as p, isValidRillId as r, JsonObject as s, createStreamUrl as t, SnapshotCodec as u, TransportJoinParams as v, InMemoryRemoteCursorStore as w, TransportSyncSuccess as x, TransportRoomStatus as y };
492
+ //# sourceMappingURL=stream-id-B9n-uFFB.d.ts.map
@@ -589,6 +589,18 @@ function normalizeSnapshotUploadConfig(config) {
589
589
  minBytesSinceRemoteSnapshot: BigInt(Math.floor(minBytes))
590
590
  };
591
591
  }
592
+ function assertSnapshotBytes(value, label) {
593
+ if (value instanceof Uint8Array) return value;
594
+ throw new Error(`${label} must return Uint8Array`);
595
+ }
596
+ function normalizeSnapshotCodec(codec) {
597
+ if (codec == null) return;
598
+ if (typeof codec.compress !== "function" || typeof codec.decompress !== "function") throw new Error("snapshotCodec.compress and snapshotCodec.decompress must be provided together");
599
+ return {
600
+ compress: async (snapshot) => assertSnapshotBytes(await codec.compress(snapshot), "snapshotCodec.compress"),
601
+ decompress: async (snapshot) => assertSnapshotBytes(await codec.decompress(snapshot), "snapshotCodec.decompress")
602
+ };
603
+ }
592
604
  function jsonValueEquals(a, b) {
593
605
  if (a === b) return true;
594
606
  if (typeof a !== typeof b || a == null || b == null) return false;
@@ -1003,14 +1015,16 @@ var StreamsTransportClient = class {
1003
1015
  //#region src/transport-cursor.ts
1004
1016
  var TransportCursorManager = class {
1005
1017
  adapter;
1018
+ decodeSnapshot;
1006
1019
  saveRemoteCursor;
1007
1020
  constructor(options) {
1008
1021
  this.adapter = options.adapter;
1022
+ this.decodeSnapshot = options.decodeSnapshot;
1009
1023
  this.saveRemoteCursor = options.saveRemoteCursor;
1010
1024
  }
1011
1025
  async applyBootstrapPayload(cursor, snapshot, updates, nextOffset) {
1012
1026
  let nextVersion = cursor.serverLowerBoundVersion;
1013
- if (snapshot.byteLength > 0) nextVersion = await this.adapter.applySnapshot(snapshot);
1027
+ if (snapshot.byteLength > 0) nextVersion = await this.adapter.applySnapshot(this.decodeSnapshot == null ? snapshot : await this.decodeSnapshot(snapshot));
1014
1028
  if (updates.length > 0) nextVersion = await this.adapter.applyRemoteUpdates([...updates], nextVersion);
1015
1029
  return await this.saveRemoteCursor({
1016
1030
  ...cursor,
@@ -1194,6 +1208,7 @@ function createTransportSnapshotState() {
1194
1208
  var TransportSnapshotManager = class {
1195
1209
  adapter;
1196
1210
  config;
1211
+ encodeSnapshot;
1197
1212
  readSnapshotOffsetValue;
1198
1213
  putSnapshotAt;
1199
1214
  enqueueExclusive;
@@ -1203,6 +1218,7 @@ var TransportSnapshotManager = class {
1203
1218
  constructor(options) {
1204
1219
  this.adapter = options.adapter;
1205
1220
  this.config = options.config;
1221
+ this.encodeSnapshot = options.encodeSnapshot;
1206
1222
  this.readSnapshotOffsetValue = options.readSnapshotOffsetValue;
1207
1223
  this.putSnapshotAt = options.putSnapshotAt;
1208
1224
  this.enqueueExclusive = options.enqueueExclusive;
@@ -1273,7 +1289,7 @@ var TransportSnapshotManager = class {
1273
1289
  if (tailBytes <= snapshotBytes) return;
1274
1290
  if (tailBytes - snapshotBytes < config.minBytesSinceRemoteSnapshot) return;
1275
1291
  const snapshot = this.adapter.exportSnapshot();
1276
- await this.putSnapshotAt(state.cursor.nextOffset, snapshot);
1292
+ await this.putSnapshotAt(state.cursor.nextOffset, this.encodeSnapshot == null ? snapshot : await this.encodeSnapshot(snapshot));
1277
1293
  } catch (error) {
1278
1294
  this.logError("snapshot upload failed", error);
1279
1295
  }
@@ -1367,6 +1383,7 @@ var StreamsCrdt = class StreamsCrdt {
1367
1383
  };
1368
1384
  this.debug = options.debug ?? false;
1369
1385
  this.beforeRemoteCursorSave = composeBeforeRemoteCursorSaveHooks(options.beforeRemoteCursorSave, ...options.beforeRemoteCursorSaveHooks ?? []);
1386
+ const snapshotCodec = normalizeSnapshotCodec(options.snapshotCodec);
1370
1387
  const snapshotUploadConfig = normalizeSnapshotUploadConfig(options.snapshotUpload);
1371
1388
  this.client = new StreamsTransportClient({
1372
1389
  streamUrl: this.streamUrl,
@@ -1377,11 +1394,13 @@ var StreamsCrdt = class StreamsCrdt {
1377
1394
  });
1378
1395
  this.cursorManager = new TransportCursorManager({
1379
1396
  adapter: this.adapter,
1397
+ decodeSnapshot: snapshotCodec?.decompress,
1380
1398
  saveRemoteCursor: (cursor, source) => this.saveRemoteCursor(cursor, source)
1381
1399
  });
1382
1400
  this.snapshotManager = new TransportSnapshotManager({
1383
1401
  adapter: this.adapter,
1384
1402
  config: snapshotUploadConfig,
1403
+ encodeSnapshot: snapshotCodec?.compress,
1385
1404
  readSnapshotOffsetValue: () => this.readSnapshotOffsetValue(),
1386
1405
  putSnapshotAt: (snapshotOffset, snapshot) => this.putSnapshotAt(snapshotOffset, snapshot),
1387
1406
  enqueueExclusive: (task) => this.enqueueExclusive(task),
@@ -2148,4 +2167,4 @@ function createStreamUrl(input) {
2148
2167
  //#endregion
2149
2168
  export { InMemoryRemoteCursorStore as a, StreamsCrdt as i, isValidBucketId as n, IndexedDbRemoteCursorStore as o, isValidRillId as r, createInitialRemoteCursor as s, createStreamUrl as t };
2150
2169
 
2151
- //# sourceMappingURL=stream-id-CIhmveJD.js.map
2170
+ //# sourceMappingURL=stream-id-YOFZ4I6Y.js.map