@dabble/patches 0.5.3 → 0.5.5

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.
Files changed (33) hide show
  1. package/dist/algorithms/client/makeChange.d.ts +2 -1
  2. package/dist/algorithms/client/makeChange.js +3 -3
  3. package/dist/algorithms/server/commitChanges.d.ts +1 -1
  4. package/dist/algorithms/server/commitChanges.js +2 -2
  5. package/dist/algorithms/server/handleOfflineSessionsAndBatches.d.ts +2 -2
  6. package/dist/algorithms/server/handleOfflineSessionsAndBatches.js +3 -3
  7. package/dist/algorithms/shared/changeBatching.d.ts +43 -5
  8. package/dist/algorithms/shared/changeBatching.js +37 -20
  9. package/dist/algorithms/shared/lz.d.ts +12 -0
  10. package/dist/algorithms/shared/lz.js +456 -0
  11. package/dist/client/Patches.d.ts +1 -0
  12. package/dist/client/PatchesDoc.d.ts +16 -4
  13. package/dist/client/PatchesDoc.js +5 -3
  14. package/dist/client/index.d.ts +1 -0
  15. package/dist/compression/index.d.ts +67 -0
  16. package/dist/compression/index.js +47 -0
  17. package/dist/index.d.ts +1 -0
  18. package/dist/json-patch/utils/log.d.ts +1 -1
  19. package/dist/json-patch/utils/log.js +1 -1
  20. package/dist/net/PatchesSync.d.ts +9 -0
  21. package/dist/net/PatchesSync.js +10 -2
  22. package/dist/net/index.d.ts +4 -1
  23. package/dist/net/websocket/RPCServer.d.ts +2 -0
  24. package/dist/net/websocket/WebSocketServer.d.ts +2 -0
  25. package/dist/server/CompressedStoreBackend.d.ts +44 -0
  26. package/dist/server/CompressedStoreBackend.js +79 -0
  27. package/dist/server/PatchesBranchManager.d.ts +2 -0
  28. package/dist/server/PatchesHistoryManager.d.ts +2 -0
  29. package/dist/server/PatchesServer.d.ts +16 -5
  30. package/dist/server/PatchesServer.js +13 -7
  31. package/dist/server/index.d.ts +4 -1
  32. package/dist/server/index.js +2 -0
  33. package/package.json +5 -1
@@ -0,0 +1,456 @@
1
+ import "../../chunk-IZ2YBCUP.js";
2
+ const f = String.fromCharCode;
3
+ const keyStrBase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
4
+ const keyStrUriSafe = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-$";
5
+ const baseReverseDic = {};
6
+ function compress(uncompressed) {
7
+ return _compress(uncompressed, 16, (a) => f(a));
8
+ }
9
+ function decompress(compressed) {
10
+ if (compressed == null) return "";
11
+ if (compressed === "") return null;
12
+ return _decompress(compressed.length, 32768, (index) => compressed.charCodeAt(index));
13
+ }
14
+ function compressToBase64(input) {
15
+ if (input == null) return "";
16
+ const res = _compress(input, 6, (a) => keyStrBase64.charAt(a));
17
+ switch (res.length % 4) {
18
+ case 0:
19
+ return res;
20
+ case 1:
21
+ return res + "===";
22
+ case 2:
23
+ return res + "==";
24
+ case 3:
25
+ return res + "=";
26
+ default:
27
+ return res;
28
+ }
29
+ }
30
+ function decompressFromBase64(input) {
31
+ if (input == null) return "";
32
+ if (input === "") return null;
33
+ return _decompress(input.length, 32, (index) => getBaseValue(keyStrBase64, input.charAt(index)));
34
+ }
35
+ function compressToUTF16(input) {
36
+ if (input == null) return "";
37
+ return _compress(input, 15, (a) => f(a + 32)) + " ";
38
+ }
39
+ function decompressFromUTF16(compressed) {
40
+ if (compressed == null) return "";
41
+ if (compressed === "") return null;
42
+ return _decompress(compressed.length, 16384, (index) => compressed.charCodeAt(index) - 32);
43
+ }
44
+ function compressToUint8Array(uncompressed) {
45
+ const compressed = compress(uncompressed);
46
+ const buf = new Uint8Array(compressed.length * 2);
47
+ for (let i = 0, length = compressed.length; i < length; i++) {
48
+ const currentValue = compressed.charCodeAt(i);
49
+ buf[i * 2] = currentValue >>> 8;
50
+ buf[i * 2 + 1] = currentValue % 256;
51
+ }
52
+ return buf;
53
+ }
54
+ function decompressFromUint8Array(compressed) {
55
+ if (compressed == null) {
56
+ return decompress(null);
57
+ } else {
58
+ const buf = new Array(compressed.length / 2);
59
+ for (let i = 0, length = buf.length; i < length; i++) {
60
+ buf[i] = compressed[i * 2] * 256 + compressed[i * 2 + 1];
61
+ }
62
+ const result = [];
63
+ buf.forEach((c) => result.push(f(c)));
64
+ return decompress(result.join(""));
65
+ }
66
+ }
67
+ function compressToEncodedURIComponent(input) {
68
+ if (input == null) return "";
69
+ return _compress(input, 6, (a) => keyStrUriSafe.charAt(a));
70
+ }
71
+ function decompressFromEncodedURIComponent(input) {
72
+ if (input == null) return "";
73
+ if (input === "") return null;
74
+ const normalizedInput = input.replace(/ /g, "+");
75
+ return _decompress(
76
+ normalizedInput.length,
77
+ 32,
78
+ (index) => getBaseValue(keyStrUriSafe, normalizedInput.charAt(index))
79
+ );
80
+ }
81
+ function getBaseValue(alphabet, character) {
82
+ if (!baseReverseDic[alphabet]) {
83
+ baseReverseDic[alphabet] = {};
84
+ for (let i = 0; i < alphabet.length; i++) {
85
+ baseReverseDic[alphabet][alphabet.charAt(i)] = i;
86
+ }
87
+ }
88
+ return baseReverseDic[alphabet][character];
89
+ }
90
+ function _compress(uncompressed, bitsPerChar, getCharFromInt) {
91
+ if (uncompressed == null) return "";
92
+ let i;
93
+ let value;
94
+ const context_dictionary = {};
95
+ const context_dictionaryToCreate = {};
96
+ let context_c = "";
97
+ let context_wc = "";
98
+ let context_w = "";
99
+ let context_enlargeIn = 2;
100
+ let context_dictSize = 3;
101
+ let context_numBits = 2;
102
+ const context_data = [];
103
+ let context_data_val = 0;
104
+ let context_data_position = 0;
105
+ for (let ii = 0; ii < uncompressed.length; ii += 1) {
106
+ context_c = uncompressed.charAt(ii);
107
+ if (!Object.prototype.hasOwnProperty.call(context_dictionary, context_c)) {
108
+ context_dictionary[context_c] = context_dictSize++;
109
+ context_dictionaryToCreate[context_c] = true;
110
+ }
111
+ context_wc = context_w + context_c;
112
+ if (Object.prototype.hasOwnProperty.call(context_dictionary, context_wc)) {
113
+ context_w = context_wc;
114
+ } else {
115
+ if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
116
+ if (context_w.charCodeAt(0) < 256) {
117
+ for (i = 0; i < context_numBits; i++) {
118
+ context_data_val = context_data_val << 1;
119
+ if (context_data_position === bitsPerChar - 1) {
120
+ context_data_position = 0;
121
+ context_data.push(getCharFromInt(context_data_val));
122
+ context_data_val = 0;
123
+ } else {
124
+ context_data_position++;
125
+ }
126
+ }
127
+ value = context_w.charCodeAt(0);
128
+ for (i = 0; i < 8; i++) {
129
+ context_data_val = context_data_val << 1 | value & 1;
130
+ if (context_data_position === bitsPerChar - 1) {
131
+ context_data_position = 0;
132
+ context_data.push(getCharFromInt(context_data_val));
133
+ context_data_val = 0;
134
+ } else {
135
+ context_data_position++;
136
+ }
137
+ value = value >> 1;
138
+ }
139
+ } else {
140
+ value = 1;
141
+ for (i = 0; i < context_numBits; i++) {
142
+ context_data_val = context_data_val << 1 | value;
143
+ if (context_data_position === bitsPerChar - 1) {
144
+ context_data_position = 0;
145
+ context_data.push(getCharFromInt(context_data_val));
146
+ context_data_val = 0;
147
+ } else {
148
+ context_data_position++;
149
+ }
150
+ value = 0;
151
+ }
152
+ value = context_w.charCodeAt(0);
153
+ for (i = 0; i < 16; i++) {
154
+ context_data_val = context_data_val << 1 | value & 1;
155
+ if (context_data_position === bitsPerChar - 1) {
156
+ context_data_position = 0;
157
+ context_data.push(getCharFromInt(context_data_val));
158
+ context_data_val = 0;
159
+ } else {
160
+ context_data_position++;
161
+ }
162
+ value = value >> 1;
163
+ }
164
+ }
165
+ context_enlargeIn--;
166
+ if (context_enlargeIn === 0) {
167
+ context_enlargeIn = Math.pow(2, context_numBits);
168
+ context_numBits++;
169
+ }
170
+ delete context_dictionaryToCreate[context_w];
171
+ } else {
172
+ value = context_dictionary[context_w];
173
+ for (i = 0; i < context_numBits; i++) {
174
+ context_data_val = context_data_val << 1 | value & 1;
175
+ if (context_data_position === bitsPerChar - 1) {
176
+ context_data_position = 0;
177
+ context_data.push(getCharFromInt(context_data_val));
178
+ context_data_val = 0;
179
+ } else {
180
+ context_data_position++;
181
+ }
182
+ value = value >> 1;
183
+ }
184
+ }
185
+ context_enlargeIn--;
186
+ if (context_enlargeIn === 0) {
187
+ context_enlargeIn = Math.pow(2, context_numBits);
188
+ context_numBits++;
189
+ }
190
+ context_dictionary[context_wc] = context_dictSize++;
191
+ context_w = String(context_c);
192
+ }
193
+ }
194
+ if (context_w !== "") {
195
+ if (Object.prototype.hasOwnProperty.call(context_dictionaryToCreate, context_w)) {
196
+ if (context_w.charCodeAt(0) < 256) {
197
+ for (i = 0; i < context_numBits; i++) {
198
+ context_data_val = context_data_val << 1;
199
+ if (context_data_position === bitsPerChar - 1) {
200
+ context_data_position = 0;
201
+ context_data.push(getCharFromInt(context_data_val));
202
+ context_data_val = 0;
203
+ } else {
204
+ context_data_position++;
205
+ }
206
+ }
207
+ value = context_w.charCodeAt(0);
208
+ for (i = 0; i < 8; i++) {
209
+ context_data_val = context_data_val << 1 | value & 1;
210
+ if (context_data_position === bitsPerChar - 1) {
211
+ context_data_position = 0;
212
+ context_data.push(getCharFromInt(context_data_val));
213
+ context_data_val = 0;
214
+ } else {
215
+ context_data_position++;
216
+ }
217
+ value = value >> 1;
218
+ }
219
+ } else {
220
+ value = 1;
221
+ for (i = 0; i < context_numBits; i++) {
222
+ context_data_val = context_data_val << 1 | value;
223
+ if (context_data_position === bitsPerChar - 1) {
224
+ context_data_position = 0;
225
+ context_data.push(getCharFromInt(context_data_val));
226
+ context_data_val = 0;
227
+ } else {
228
+ context_data_position++;
229
+ }
230
+ value = 0;
231
+ }
232
+ value = context_w.charCodeAt(0);
233
+ for (i = 0; i < 16; i++) {
234
+ context_data_val = context_data_val << 1 | value & 1;
235
+ if (context_data_position === bitsPerChar - 1) {
236
+ context_data_position = 0;
237
+ context_data.push(getCharFromInt(context_data_val));
238
+ context_data_val = 0;
239
+ } else {
240
+ context_data_position++;
241
+ }
242
+ value = value >> 1;
243
+ }
244
+ }
245
+ context_enlargeIn--;
246
+ if (context_enlargeIn === 0) {
247
+ context_enlargeIn = Math.pow(2, context_numBits);
248
+ context_numBits++;
249
+ }
250
+ delete context_dictionaryToCreate[context_w];
251
+ } else {
252
+ value = context_dictionary[context_w];
253
+ for (i = 0; i < context_numBits; i++) {
254
+ context_data_val = context_data_val << 1 | value & 1;
255
+ if (context_data_position === bitsPerChar - 1) {
256
+ context_data_position = 0;
257
+ context_data.push(getCharFromInt(context_data_val));
258
+ context_data_val = 0;
259
+ } else {
260
+ context_data_position++;
261
+ }
262
+ value = value >> 1;
263
+ }
264
+ }
265
+ context_enlargeIn--;
266
+ if (context_enlargeIn === 0) {
267
+ context_enlargeIn = Math.pow(2, context_numBits);
268
+ context_numBits++;
269
+ }
270
+ }
271
+ value = 2;
272
+ for (i = 0; i < context_numBits; i++) {
273
+ context_data_val = context_data_val << 1 | value & 1;
274
+ if (context_data_position === bitsPerChar - 1) {
275
+ context_data_position = 0;
276
+ context_data.push(getCharFromInt(context_data_val));
277
+ context_data_val = 0;
278
+ } else {
279
+ context_data_position++;
280
+ }
281
+ value = value >> 1;
282
+ }
283
+ while (true) {
284
+ context_data_val = context_data_val << 1;
285
+ if (context_data_position === bitsPerChar - 1) {
286
+ context_data.push(getCharFromInt(context_data_val));
287
+ break;
288
+ } else context_data_position++;
289
+ }
290
+ return context_data.join("");
291
+ }
292
+ function _decompress(length, resetValue, getNextValue) {
293
+ const dictionary = [];
294
+ let enlargeIn = 4;
295
+ let dictSize = 4;
296
+ let numBits = 3;
297
+ let entry = "";
298
+ const result = [];
299
+ let w;
300
+ let bits;
301
+ let resb;
302
+ let maxpower;
303
+ let power;
304
+ let c;
305
+ const data = { val: getNextValue(0), position: resetValue, index: 1 };
306
+ for (let i = 0; i < 3; i += 1) {
307
+ dictionary[i] = i;
308
+ }
309
+ bits = 0;
310
+ maxpower = Math.pow(2, 2);
311
+ power = 1;
312
+ while (power !== maxpower) {
313
+ resb = data.val & data.position;
314
+ data.position >>= 1;
315
+ if (data.position === 0) {
316
+ data.position = resetValue;
317
+ data.val = getNextValue(data.index++);
318
+ }
319
+ bits |= (resb > 0 ? 1 : 0) * power;
320
+ power <<= 1;
321
+ }
322
+ const next = bits;
323
+ switch (next) {
324
+ case 0:
325
+ bits = 0;
326
+ maxpower = Math.pow(2, 8);
327
+ power = 1;
328
+ while (power !== maxpower) {
329
+ resb = data.val & data.position;
330
+ data.position >>= 1;
331
+ if (data.position === 0) {
332
+ data.position = resetValue;
333
+ data.val = getNextValue(data.index++);
334
+ }
335
+ bits |= (resb > 0 ? 1 : 0) * power;
336
+ power <<= 1;
337
+ }
338
+ c = f(bits);
339
+ break;
340
+ case 1:
341
+ bits = 0;
342
+ maxpower = Math.pow(2, 16);
343
+ power = 1;
344
+ while (power !== maxpower) {
345
+ resb = data.val & data.position;
346
+ data.position >>= 1;
347
+ if (data.position === 0) {
348
+ data.position = resetValue;
349
+ data.val = getNextValue(data.index++);
350
+ }
351
+ bits |= (resb > 0 ? 1 : 0) * power;
352
+ power <<= 1;
353
+ }
354
+ c = f(bits);
355
+ break;
356
+ case 2:
357
+ return "";
358
+ default:
359
+ return "";
360
+ }
361
+ dictionary[3] = c;
362
+ w = c;
363
+ result.push(c);
364
+ while (true) {
365
+ if (data.index > length) {
366
+ return "";
367
+ }
368
+ bits = 0;
369
+ maxpower = Math.pow(2, numBits);
370
+ power = 1;
371
+ while (power !== maxpower) {
372
+ resb = data.val & data.position;
373
+ data.position >>= 1;
374
+ if (data.position === 0) {
375
+ data.position = resetValue;
376
+ data.val = getNextValue(data.index++);
377
+ }
378
+ bits |= (resb > 0 ? 1 : 0) * power;
379
+ power <<= 1;
380
+ }
381
+ c = bits;
382
+ switch (c) {
383
+ case 0:
384
+ bits = 0;
385
+ maxpower = Math.pow(2, 8);
386
+ power = 1;
387
+ while (power !== maxpower) {
388
+ resb = data.val & data.position;
389
+ data.position >>= 1;
390
+ if (data.position === 0) {
391
+ data.position = resetValue;
392
+ data.val = getNextValue(data.index++);
393
+ }
394
+ bits |= (resb > 0 ? 1 : 0) * power;
395
+ power <<= 1;
396
+ }
397
+ dictionary[dictSize++] = f(bits);
398
+ c = dictSize - 1;
399
+ enlargeIn--;
400
+ break;
401
+ case 1:
402
+ bits = 0;
403
+ maxpower = Math.pow(2, 16);
404
+ power = 1;
405
+ while (power !== maxpower) {
406
+ resb = data.val & data.position;
407
+ data.position >>= 1;
408
+ if (data.position === 0) {
409
+ data.position = resetValue;
410
+ data.val = getNextValue(data.index++);
411
+ }
412
+ bits |= (resb > 0 ? 1 : 0) * power;
413
+ power <<= 1;
414
+ }
415
+ dictionary[dictSize++] = f(bits);
416
+ c = dictSize - 1;
417
+ enlargeIn--;
418
+ break;
419
+ case 2:
420
+ return result.join("");
421
+ }
422
+ if (enlargeIn === 0) {
423
+ enlargeIn = Math.pow(2, numBits);
424
+ numBits++;
425
+ }
426
+ if (dictionary[c]) {
427
+ entry = dictionary[c];
428
+ } else {
429
+ if (c === dictSize) {
430
+ entry = w + w.charAt(0);
431
+ } else {
432
+ return null;
433
+ }
434
+ }
435
+ result.push(entry);
436
+ dictionary[dictSize++] = w + entry.charAt(0);
437
+ enlargeIn--;
438
+ w = entry;
439
+ if (enlargeIn === 0) {
440
+ enlargeIn = Math.pow(2, numBits);
441
+ numBits++;
442
+ }
443
+ }
444
+ }
445
+ export {
446
+ compress,
447
+ compressToBase64,
448
+ compressToEncodedURIComponent,
449
+ compressToUTF16,
450
+ compressToUint8Array,
451
+ decompress,
452
+ decompressFromBase64,
453
+ decompressFromEncodedURIComponent,
454
+ decompressFromUTF16,
455
+ decompressFromUint8Array
456
+ };
@@ -5,6 +5,7 @@ import { PatchesStore } from './PatchesStore.js';
5
5
  import '../json-patch/JSONPatch.js';
6
6
  import '@dabble/delta';
7
7
  import '../json-patch/types.js';
8
+ import '../algorithms/shared/changeBatching.js';
8
9
 
9
10
  interface PatchesOptions {
10
11
  /** Persistence layer instance (e.g., new IndexedDBStore('my-db') or new InMemoryStore()). */
@@ -1,4 +1,5 @@
1
1
  import { Signal, Unsubscriber } from '../event-signal.js';
2
+ import { SizeCalculator } from '../algorithms/shared/changeBatching.js';
2
3
  import { PatchesSnapshot, SyncingState, Change, ChangeMutator } from '../types.js';
3
4
  import '../json-patch/JSONPatch.js';
4
5
  import '@dabble/delta';
@@ -9,10 +10,20 @@ import '../json-patch/types.js';
9
10
  */
10
11
  interface PatchesDocOptions {
11
12
  /**
12
- * Maximum size in bytes for a single payload (network message).
13
- * Changes exceeding this will be split into multiple smaller changes.
13
+ * Maximum size in bytes for a single change's storage representation.
14
+ * Changes exceeding this will be split. Used for backends with row size limits.
14
15
  */
15
- maxPayloadBytes?: number;
16
+ maxStorageBytes?: number;
17
+ /**
18
+ * Custom size calculator for storage limit checks.
19
+ * Import from '@dabble/patches/compression' for actual compression measurement,
20
+ * or provide your own function (e.g., ratio estimate).
21
+ *
22
+ * @example
23
+ * import { compressedSizeBase64 } from '@dabble/patches/compression';
24
+ * { sizeCalculator: compressedSizeBase64, maxStorageBytes: 1_000_000 }
25
+ */
26
+ sizeCalculator?: SizeCalculator;
16
27
  }
17
28
  /**
18
29
  * Represents a document synchronized using JSON patches.
@@ -25,7 +36,8 @@ declare class PatchesDoc<T extends object = object> {
25
36
  protected _snapshot: PatchesSnapshot<T>;
26
37
  protected _changeMetadata: Record<string, any>;
27
38
  protected _syncing: SyncingState;
28
- protected readonly _maxPayloadBytes?: number;
39
+ protected readonly _maxStorageBytes?: number;
40
+ protected readonly _sizeCalculator?: SizeCalculator;
29
41
  /** Subscribe to be notified before local state changes. */
30
42
  readonly onBeforeChange: Signal<(change: Change) => void>;
31
43
  /** Subscribe to be notified after local state changes are applied. */
@@ -9,7 +9,8 @@ class PatchesDoc {
9
9
  _snapshot;
10
10
  _changeMetadata = {};
11
11
  _syncing = null;
12
- _maxPayloadBytes;
12
+ _maxStorageBytes;
13
+ _sizeCalculator;
13
14
  /** Subscribe to be notified before local state changes. */
14
15
  onBeforeChange = signal();
15
16
  /** Subscribe to be notified after local state changes are applied. */
@@ -28,7 +29,8 @@ class PatchesDoc {
28
29
  this._state = structuredClone(initialState);
29
30
  this._snapshot = { state: this._state, rev: 0, changes: [] };
30
31
  this._changeMetadata = initialMetadata;
31
- this._maxPayloadBytes = options.maxPayloadBytes;
32
+ this._maxStorageBytes = options.maxStorageBytes;
33
+ this._sizeCalculator = options.sizeCalculator;
32
34
  }
33
35
  /** The unique identifier for this document, once assigned. */
34
36
  get id() {
@@ -86,7 +88,7 @@ class PatchesDoc {
86
88
  * @returns The generated Change objects.
87
89
  */
88
90
  change(mutator) {
89
- const changes = makeChange(this._snapshot, mutator, this._changeMetadata, this._maxPayloadBytes);
91
+ const changes = makeChange(this._snapshot, mutator, this._changeMetadata, this._maxStorageBytes, this._sizeCalculator);
90
92
  if (changes.length === 0) {
91
93
  return changes;
92
94
  }
@@ -9,4 +9,5 @@ import '../json-patch/JSONPatch.js';
9
9
  import '@dabble/delta';
10
10
  import '../json-patch/types.js';
11
11
  import '../event-signal.js';
12
+ import '../algorithms/shared/changeBatching.js';
12
13
  import '../net/protocol/types.js';
@@ -0,0 +1,67 @@
1
+ export { compressToBase64, compressToUint8Array, decompressFromBase64, decompressFromUint8Array } from '../algorithms/shared/lz.js';
2
+ import { JSONPatchOp } from '../json-patch/types.js';
3
+
4
+ /**
5
+ * Tree-shakable compression utilities for Patches.
6
+ *
7
+ * This module provides compression functionality that is only bundled
8
+ * when explicitly imported. If you don't use compression, these ~18KB
9
+ * won't be included in your bundle.
10
+ *
11
+ * @example Client: Size calculator for change splitting
12
+ * ```typescript
13
+ * import { compressedSizeBase64 } from '@dabble/patches/compression';
14
+ *
15
+ * new PatchesDoc(state, {}, {
16
+ * sizeCalculator: compressedSizeBase64,
17
+ * maxStorageBytes: 1_000_000
18
+ * });
19
+ * ```
20
+ *
21
+ * @example Server: Compressor for storage backend
22
+ * ```typescript
23
+ * import { base64Compressor } from '@dabble/patches/compression';
24
+ *
25
+ * const backend = new CompressedStoreBackend(store, base64Compressor);
26
+ * ```
27
+ */
28
+
29
+ /**
30
+ * Function that calculates the storage size of data.
31
+ * Used by change batching to determine if changes need to be split.
32
+ */
33
+ type SizeCalculator = (data: unknown) => number;
34
+ /**
35
+ * Calculate size after base64 LZ compression.
36
+ * Use this when your server uses base64 compression format.
37
+ */
38
+ declare const compressedSizeBase64: SizeCalculator;
39
+ /**
40
+ * Calculate size after uint8array LZ compression.
41
+ * Use this when your server uses binary compression format.
42
+ */
43
+ declare const compressedSizeUint8: SizeCalculator;
44
+ /**
45
+ * Interface for compressing/decompressing JSON Patch operations.
46
+ * Passed to CompressedStoreBackend to enable transparent compression.
47
+ */
48
+ interface OpsCompressor {
49
+ /** Compress ops to string or binary format */
50
+ compress: (ops: JSONPatchOp[]) => string | Uint8Array;
51
+ /** Decompress string or binary back to ops array */
52
+ decompress: (compressed: string | Uint8Array) => JSONPatchOp[];
53
+ /** Type guard to check if ops are in compressed format */
54
+ isCompressed: (ops: unknown) => ops is string | Uint8Array;
55
+ }
56
+ /**
57
+ * Compressor that uses base64 encoding.
58
+ * Works with any storage backend that supports strings.
59
+ */
60
+ declare const base64Compressor: OpsCompressor;
61
+ /**
62
+ * Compressor that uses binary Uint8Array format.
63
+ * More efficient storage but requires backend that supports binary data.
64
+ */
65
+ declare const uint8Compressor: OpsCompressor;
66
+
67
+ export { type OpsCompressor, type SizeCalculator, base64Compressor, compressedSizeBase64, compressedSizeUint8, uint8Compressor };
@@ -0,0 +1,47 @@
1
+ import "../chunk-IZ2YBCUP.js";
2
+ import {
3
+ compressToBase64,
4
+ compressToUint8Array,
5
+ decompressFromBase64,
6
+ decompressFromUint8Array
7
+ } from "../algorithms/shared/lz.js";
8
+ const compressedSizeBase64 = (data) => {
9
+ if (data === void 0) return 0;
10
+ try {
11
+ const json = JSON.stringify(data);
12
+ if (!json) return 0;
13
+ return compressToBase64(json).length;
14
+ } catch {
15
+ return 0;
16
+ }
17
+ };
18
+ const compressedSizeUint8 = (data) => {
19
+ if (data === void 0) return 0;
20
+ try {
21
+ const json = JSON.stringify(data);
22
+ if (!json) return 0;
23
+ return compressToUint8Array(json).length;
24
+ } catch {
25
+ return 0;
26
+ }
27
+ };
28
+ const base64Compressor = {
29
+ compress: (ops) => compressToBase64(JSON.stringify(ops)),
30
+ decompress: (compressed) => JSON.parse(decompressFromBase64(compressed) || "[]"),
31
+ isCompressed: (ops) => typeof ops === "string"
32
+ };
33
+ const uint8Compressor = {
34
+ compress: (ops) => compressToUint8Array(JSON.stringify(ops)),
35
+ decompress: (compressed) => JSON.parse(decompressFromUint8Array(compressed) || "[]"),
36
+ isCompressed: (ops) => ops instanceof Uint8Array
37
+ };
38
+ export {
39
+ base64Compressor,
40
+ compressToBase64,
41
+ compressToUint8Array,
42
+ compressedSizeBase64,
43
+ compressedSizeUint8,
44
+ decompressFromBase64,
45
+ decompressFromUint8Array,
46
+ uint8Compressor
47
+ };
package/dist/index.d.ts CHANGED
@@ -26,4 +26,5 @@ export { move } from './json-patch/ops/move.js';
26
26
  export { remove } from './json-patch/ops/remove.js';
27
27
  export { replace } from './json-patch/ops/replace.js';
28
28
  export { test } from './json-patch/ops/test.js';
29
+ import './algorithms/shared/changeBatching.js';
29
30
  import './net/protocol/types.js';
@@ -1,4 +1,4 @@
1
- declare let log: (...data: any[]) => void;
1
+ declare let log: (...args: any[]) => void;
2
2
  declare function verbose(value: boolean): void;
3
3
 
4
4
  export { log, verbose };
@@ -1,5 +1,5 @@
1
1
  import "../../chunk-IZ2YBCUP.js";
2
- let log = console.log;
2
+ let log = () => void 0;
3
3
  function verbose(value) {
4
4
  log = value ? console.log : () => void 0;
5
5
  }