tinybase 5.0.0-beta.6 → 5.0.0-beta.7

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 (92) hide show
  1. package/lib/cjs/synchronizers/synchronizer-local.cjs +1 -0
  2. package/lib/cjs/synchronizers/synchronizer-local.cjs.gz +0 -0
  3. package/lib/cjs/synchronizers/synchronizer-ws-client.cjs +1 -0
  4. package/lib/cjs/synchronizers/synchronizer-ws-client.cjs.gz +0 -0
  5. package/lib/cjs/synchronizers/synchronizer-ws-server.cjs +1 -0
  6. package/lib/cjs/synchronizers/synchronizer-ws-server.cjs.gz +0 -0
  7. package/lib/cjs/synchronizers.cjs +1 -0
  8. package/lib/cjs/synchronizers.cjs.gz +0 -0
  9. package/lib/cjs/tinybase.cjs +1 -1
  10. package/lib/cjs/tinybase.cjs.gz +0 -0
  11. package/lib/cjs-es6/synchronizers/synchronizer-local.cjs +1 -0
  12. package/lib/cjs-es6/synchronizers/synchronizer-local.cjs.gz +0 -0
  13. package/lib/cjs-es6/synchronizers/synchronizer-ws-client.cjs +1 -0
  14. package/lib/cjs-es6/synchronizers/synchronizer-ws-client.cjs.gz +0 -0
  15. package/lib/cjs-es6/synchronizers/synchronizer-ws-server.cjs +1 -0
  16. package/lib/cjs-es6/synchronizers/synchronizer-ws-server.cjs.gz +0 -0
  17. package/lib/cjs-es6/synchronizers.cjs +1 -0
  18. package/lib/cjs-es6/synchronizers.cjs.gz +0 -0
  19. package/lib/cjs-es6/tinybase.cjs +1 -1
  20. package/lib/cjs-es6/tinybase.cjs.gz +0 -0
  21. package/lib/debug/synchronizers/synchronizer-local.js +502 -0
  22. package/lib/debug/{persisters/persister-sync.js → synchronizers/synchronizer-ws-client.js} +83 -152
  23. package/lib/debug/synchronizers/synchronizer-ws-server.js +57 -0
  24. package/lib/debug/synchronizers.js +466 -0
  25. package/lib/debug/tinybase.js +254 -84
  26. package/lib/es6/synchronizers/synchronizer-local.js +1 -0
  27. package/lib/es6/synchronizers/synchronizer-local.js.gz +0 -0
  28. package/lib/es6/synchronizers/synchronizer-ws-client.js +1 -0
  29. package/lib/es6/synchronizers/synchronizer-ws-client.js.gz +0 -0
  30. package/lib/es6/synchronizers/synchronizer-ws-server.js +1 -0
  31. package/lib/es6/synchronizers/synchronizer-ws-server.js.gz +0 -0
  32. package/lib/es6/synchronizers.js +1 -0
  33. package/lib/es6/synchronizers.js.gz +0 -0
  34. package/lib/es6/tinybase.js +1 -1
  35. package/lib/es6/tinybase.js.gz +0 -0
  36. package/lib/synchronizers/synchronizer-local.js +1 -0
  37. package/lib/synchronizers/synchronizer-local.js.gz +0 -0
  38. package/lib/synchronizers/synchronizer-ws-client.js +1 -0
  39. package/lib/synchronizers/synchronizer-ws-client.js.gz +0 -0
  40. package/lib/synchronizers/synchronizer-ws-server.js +1 -0
  41. package/lib/synchronizers/synchronizer-ws-server.js.gz +0 -0
  42. package/lib/synchronizers.js +1 -0
  43. package/lib/synchronizers.js.gz +0 -0
  44. package/lib/tinybase.js +1 -1
  45. package/lib/tinybase.js.gz +0 -0
  46. package/lib/types/persisters.d.ts +8 -16
  47. package/lib/types/synchronizers/synchronizer-local.d.ts +27 -0
  48. package/lib/types/synchronizers/synchronizer-ws-client.d.ts +30 -0
  49. package/lib/types/synchronizers/synchronizer-ws-server.d.ts +24 -0
  50. package/lib/types/synchronizers.d.ts +131 -0
  51. package/lib/types/tinybase.d.ts +1 -0
  52. package/lib/types/with-schemas/persisters.d.ts +13 -57
  53. package/lib/types/with-schemas/synchronizers/synchronizer-local.d.ts +29 -0
  54. package/lib/types/with-schemas/synchronizers/synchronizer-ws-client.d.ts +32 -0
  55. package/lib/types/with-schemas/synchronizers/synchronizer-ws-server.d.ts +24 -0
  56. package/lib/types/with-schemas/synchronizers.d.ts +146 -0
  57. package/lib/umd/synchronizers/synchronizer-local.js +1 -0
  58. package/lib/umd/synchronizers/synchronizer-local.js.gz +0 -0
  59. package/lib/umd/synchronizers/synchronizer-ws-client.js +1 -0
  60. package/lib/umd/synchronizers/synchronizer-ws-client.js.gz +0 -0
  61. package/lib/umd/synchronizers/synchronizer-ws-server.js +1 -0
  62. package/lib/umd/synchronizers/synchronizer-ws-server.js.gz +0 -0
  63. package/lib/umd/synchronizers.js +1 -0
  64. package/lib/umd/synchronizers.js.gz +0 -0
  65. package/lib/umd/tinybase.js +1 -1
  66. package/lib/umd/tinybase.js.gz +0 -0
  67. package/lib/umd-es6/synchronizers/synchronizer-local.js +1 -0
  68. package/lib/umd-es6/synchronizers/synchronizer-local.js.gz +0 -0
  69. package/lib/umd-es6/synchronizers/synchronizer-ws-client.js +1 -0
  70. package/lib/umd-es6/synchronizers/synchronizer-ws-client.js.gz +0 -0
  71. package/lib/umd-es6/synchronizers/synchronizer-ws-server.js +1 -0
  72. package/lib/umd-es6/synchronizers/synchronizer-ws-server.js.gz +0 -0
  73. package/lib/umd-es6/synchronizers.js +1 -0
  74. package/lib/umd-es6/synchronizers.js.gz +0 -0
  75. package/lib/umd-es6/tinybase.js +1 -1
  76. package/lib/umd-es6/tinybase.js.gz +0 -0
  77. package/package.json +1 -1
  78. package/readme.md +2 -2
  79. package/lib/cjs/persisters/persister-sync.cjs +0 -1
  80. package/lib/cjs/persisters/persister-sync.cjs.gz +0 -0
  81. package/lib/cjs-es6/persisters/persister-sync.cjs +0 -1
  82. package/lib/cjs-es6/persisters/persister-sync.cjs.gz +0 -0
  83. package/lib/es6/persisters/persister-sync.js +0 -1
  84. package/lib/es6/persisters/persister-sync.js.gz +0 -0
  85. package/lib/persisters/persister-sync.js +0 -1
  86. package/lib/persisters/persister-sync.js.gz +0 -0
  87. package/lib/types/persisters/persister-sync.d.ts +0 -182
  88. package/lib/types/with-schemas/persisters/persister-sync.d.ts +0 -195
  89. package/lib/umd/persisters/persister-sync.js +0 -1
  90. package/lib/umd/persisters/persister-sync.js.gz +0 -0
  91. package/lib/umd-es6/persisters/persister-sync.js +0 -1
  92. package/lib/umd-es6/persisters/persister-sync.js.gz +0 -0
@@ -0,0 +1,502 @@
1
+ const getTypeOf = (thing) => typeof thing;
2
+ const EMPTY_STRING = '';
3
+ const STRING = getTypeOf(EMPTY_STRING);
4
+ const strCharCodeAt = (str, position) => str.charCodeAt(position);
5
+
6
+ const promise = Promise;
7
+ const mathMax = Math.max;
8
+ const isUndefined = (thing) => thing == void 0;
9
+ const ifNotUndefined = (value, then, otherwise) =>
10
+ isUndefined(value) ? otherwise?.() : then(value);
11
+ const isString = (thing) => getTypeOf(thing) == STRING;
12
+ const size = (arrayOrString) => arrayOrString.length;
13
+ const promiseNew = (resolver) => new promise(resolver);
14
+
15
+ const arrayForEach = (array, cb) => array.forEach(cb);
16
+ const arrayPush = (array, ...values) => array.push(...values);
17
+ const arrayShift = (array) => array.shift();
18
+
19
+ const object = Object;
20
+ const getPrototypeOf = (obj) => object.getPrototypeOf(obj);
21
+ const isObject = (obj) =>
22
+ !isUndefined(obj) &&
23
+ ifNotUndefined(
24
+ getPrototypeOf(obj),
25
+ (objPrototype) =>
26
+ objPrototype == object.prototype ||
27
+ isUndefined(getPrototypeOf(objPrototype)),
28
+ /* istanbul ignore next */
29
+ () => true,
30
+ );
31
+ const objIds = object.keys;
32
+ const objFreeze = object.freeze;
33
+ const objSize = (obj) => size(objIds(obj));
34
+ const objIsEmpty = (obj) => isObject(obj) && objSize(obj) == 0;
35
+
36
+ const collHas = (coll, keyOrValue) => coll?.has(keyOrValue) ?? false;
37
+ const collForEach = (coll, cb) => coll?.forEach(cb);
38
+ const collDel = (coll, keyOrValue) => coll?.delete(keyOrValue);
39
+
40
+ const mapNew = (entries) => new Map(entries);
41
+ const mapGet = (map, key) => map?.get(key);
42
+ const mapForEach = (map, cb) =>
43
+ collForEach(map, (value, key) => cb(key, value));
44
+ const mapSet = (map, key, value) =>
45
+ isUndefined(value) ? (collDel(map, key), map) : map?.set(key, value);
46
+ const mapEnsure = (map, key, getDefaultValue, hadExistingValue) => {
47
+ if (!collHas(map, key)) {
48
+ mapSet(map, key, getDefaultValue());
49
+ } else {
50
+ hadExistingValue?.(mapGet(map, key));
51
+ }
52
+ return mapGet(map, key);
53
+ };
54
+
55
+ const scheduleRunning = mapNew();
56
+ const scheduleActions = mapNew();
57
+ const getStoreFunctions = (supportsMergeableStore, store) =>
58
+ !supportsMergeableStore || isUndefined(store.getMergeableContent)
59
+ ? [
60
+ 0,
61
+ store.getContent,
62
+ store.getTransactionChanges,
63
+ ([changedTables, changedValues]) =>
64
+ !objIsEmpty(changedTables) || !objIsEmpty(changedValues),
65
+ ]
66
+ : [
67
+ 1,
68
+ store.getMergeableContent,
69
+ store.getTransactionMergeableChanges,
70
+ ([, [[, changedTables], [, changedValues]]]) =>
71
+ !objIsEmpty(changedTables) || !objIsEmpty(changedValues),
72
+ ];
73
+ const createCustomPersister = (
74
+ store,
75
+ getPersisted,
76
+ setPersisted,
77
+ addPersisterListener,
78
+ delPersisterListener,
79
+ onIgnoredError,
80
+ supportsMergeableStore,
81
+ extra = {},
82
+ scheduleId = [],
83
+ ) => {
84
+ let loadSave = 0;
85
+ let loads = 0;
86
+ let saves = 0;
87
+ let action;
88
+ let autoLoadHandle;
89
+ let autoSaveListenerId;
90
+ mapEnsure(scheduleRunning, scheduleId, () => 0);
91
+ mapEnsure(scheduleActions, scheduleId, () => []);
92
+ const [isMergeableStore, getContent, getChanges, hasChanges] =
93
+ getStoreFunctions(supportsMergeableStore, store);
94
+ const run = async () => {
95
+ /* istanbul ignore else */
96
+ if (!mapGet(scheduleRunning, scheduleId)) {
97
+ mapSet(scheduleRunning, scheduleId, 1);
98
+ while (
99
+ !isUndefined((action = arrayShift(mapGet(scheduleActions, scheduleId))))
100
+ ) {
101
+ try {
102
+ await action();
103
+ } catch (error) {
104
+ /* istanbul ignore next */
105
+ onIgnoredError?.(error);
106
+ }
107
+ }
108
+ mapSet(scheduleRunning, scheduleId, 0);
109
+ }
110
+ };
111
+ const loadLock = async (actions) => {
112
+ /* istanbul ignore else */
113
+ if (loadSave != 2) {
114
+ loadSave = 1;
115
+ {
116
+ loads++;
117
+ }
118
+ await persister.schedule(async () => {
119
+ await actions();
120
+ loadSave = 0;
121
+ });
122
+ }
123
+ return persister;
124
+ };
125
+ const setContentOrChanges = (contentOrChanges) => {
126
+ (isMergeableStore && isString(contentOrChanges?.[0])
127
+ ? contentOrChanges?.[1][2] === 1
128
+ ? store.applyMergeableChanges
129
+ : store.setMergeableContent
130
+ : contentOrChanges?.[2] === 1
131
+ ? store.applyChanges
132
+ : store.setContent)(contentOrChanges);
133
+ };
134
+ const persister = {
135
+ load: async (initialTables, initialValues) =>
136
+ await loadLock(async () => {
137
+ try {
138
+ setContentOrChanges(await getPersisted());
139
+ } catch (error) {
140
+ onIgnoredError?.(error);
141
+ store.setContent([initialTables, initialValues]);
142
+ }
143
+ }),
144
+ startAutoLoad: async (initialTables = {}, initialValues = {}) => {
145
+ await persister.stopAutoLoad().load(initialTables, initialValues);
146
+ autoLoadHandle = addPersisterListener(
147
+ async (getContent2, getChanges2) => {
148
+ const changes = getChanges2?.();
149
+ await loadLock(async () => {
150
+ try {
151
+ setContentOrChanges(
152
+ changes ?? getContent2?.() ?? (await getPersisted()),
153
+ );
154
+ } catch (error) {
155
+ onIgnoredError?.(error);
156
+ }
157
+ });
158
+ },
159
+ );
160
+ return persister;
161
+ },
162
+ stopAutoLoad: () => {
163
+ if (autoLoadHandle) {
164
+ delPersisterListener(autoLoadHandle);
165
+ autoLoadHandle = void 0;
166
+ }
167
+ return persister;
168
+ },
169
+ isAutoLoading: () => !isUndefined(autoLoadHandle),
170
+ save: async (getChanges2) => {
171
+ /* istanbul ignore else */
172
+ if (loadSave != 1) {
173
+ loadSave = 2;
174
+ {
175
+ saves++;
176
+ }
177
+ await persister.schedule(async () => {
178
+ try {
179
+ await setPersisted(getContent, getChanges2);
180
+ } catch (error) {
181
+ /* istanbul ignore next */
182
+ onIgnoredError?.(error);
183
+ }
184
+ loadSave = 0;
185
+ });
186
+ }
187
+ return persister;
188
+ },
189
+ startAutoSave: async () => {
190
+ await persister.stopAutoSave().save();
191
+ autoSaveListenerId = store.addDidFinishTransactionListener(() => {
192
+ const changes = getChanges();
193
+ if (hasChanges(changes)) {
194
+ persister.save(() => changes);
195
+ }
196
+ });
197
+ return persister;
198
+ },
199
+ stopAutoSave: () => {
200
+ ifNotUndefined(autoSaveListenerId, store.delListener);
201
+ autoSaveListenerId = void 0;
202
+ return persister;
203
+ },
204
+ isAutoSaving: () => !isUndefined(autoSaveListenerId),
205
+ schedule: async (...actions) => {
206
+ arrayPush(mapGet(scheduleActions, scheduleId), ...actions);
207
+ await run();
208
+ return persister;
209
+ },
210
+ getStore: () => store,
211
+ destroy: () => persister.stopAutoLoad().stopAutoSave(),
212
+ getStats: () => ({loads, saves}),
213
+ ...extra,
214
+ };
215
+ return objFreeze(persister);
216
+ };
217
+
218
+ const textEncoder = new globalThis.TextEncoder();
219
+ const getHash = (value) => {
220
+ let hash = 2166136261;
221
+ arrayForEach(textEncoder.encode(value), (char) => {
222
+ hash ^= char;
223
+ hash +=
224
+ (hash << 1) + (hash << 4) + (hash << 7) + (hash << 8) + (hash << 24);
225
+ });
226
+ return hash >>> 0;
227
+ };
228
+
229
+ const MASK6 = 63;
230
+ const SHIFT36 = 2 ** 36;
231
+ const SHIFT30 = 2 ** 30;
232
+ const SHIFT24 = 2 ** 24;
233
+ const SHIFT18 = 2 ** 18;
234
+ const SHIFT12 = 2 ** 12;
235
+ const SHIFT6 = 2 ** 6;
236
+ const toB64 = (num) => String.fromCharCode(48 + (num & MASK6));
237
+ const fromB64 = (str, pos) => strCharCodeAt(str, pos) - 48;
238
+ const encodeHlc = (logicalTime42, counter24, clientHash30) =>
239
+ toB64(logicalTime42 / SHIFT36) +
240
+ toB64(logicalTime42 / SHIFT30) +
241
+ toB64(logicalTime42 / SHIFT24) +
242
+ toB64(logicalTime42 / SHIFT18) +
243
+ toB64(logicalTime42 / SHIFT12) +
244
+ toB64(logicalTime42 / SHIFT6) +
245
+ toB64(logicalTime42) +
246
+ toB64(counter24 / SHIFT18) +
247
+ toB64(counter24 / SHIFT12) +
248
+ toB64(counter24 / SHIFT6) +
249
+ toB64(counter24) +
250
+ toB64(clientHash30 / SHIFT24) +
251
+ toB64(clientHash30 / SHIFT18) +
252
+ toB64(clientHash30 / SHIFT12) +
253
+ toB64(clientHash30 / SHIFT6) +
254
+ toB64(clientHash30);
255
+ const decodeHlc = (hlc16) => [
256
+ fromB64(hlc16, 0) * SHIFT36 +
257
+ fromB64(hlc16, 1) * SHIFT30 +
258
+ fromB64(hlc16, 2) * SHIFT24 +
259
+ fromB64(hlc16, 3) * SHIFT18 +
260
+ fromB64(hlc16, 4) * SHIFT12 +
261
+ fromB64(hlc16, 5) * SHIFT6 +
262
+ fromB64(hlc16, 6),
263
+ fromB64(hlc16, 7) * SHIFT18 +
264
+ fromB64(hlc16, 8) * SHIFT12 +
265
+ fromB64(hlc16, 9) * SHIFT6 +
266
+ fromB64(hlc16, 10),
267
+ fromB64(hlc16, 11) * SHIFT24 +
268
+ fromB64(hlc16, 12) * SHIFT18 +
269
+ fromB64(hlc16, 13) * SHIFT12 +
270
+ fromB64(hlc16, 14) * SHIFT6 +
271
+ fromB64(hlc16, 15),
272
+ ];
273
+ const getHlcFunctions = (uniqueId) => {
274
+ let logicalTime = 0;
275
+ let lastCounter = -1;
276
+ const uniqueIdHash = getHash(uniqueId);
277
+ const getHlc = () => {
278
+ seenHlc();
279
+ return encodeHlc(logicalTime, ++lastCounter, uniqueIdHash);
280
+ };
281
+ const seenHlc = (hlc) => {
282
+ const previousLogicalTime = logicalTime;
283
+ const [remoteLogicalTime, remoteCounter] =
284
+ isUndefined(hlc) || hlc == '' ? [0, 0] : decodeHlc(hlc);
285
+ logicalTime = mathMax(
286
+ previousLogicalTime,
287
+ remoteLogicalTime,
288
+ globalThis.HLC_TIME ?? Date.now(),
289
+ );
290
+ lastCounter =
291
+ logicalTime == previousLogicalTime
292
+ ? logicalTime == remoteLogicalTime
293
+ ? mathMax(lastCounter, remoteCounter)
294
+ : lastCounter
295
+ : logicalTime == remoteLogicalTime
296
+ ? remoteCounter
297
+ : -1;
298
+ };
299
+ return [getHlc, seenHlc];
300
+ };
301
+
302
+ const RESPONSE = 0;
303
+ const CONTENT_HASHES = 1;
304
+ const GET_CONTENT_HASHES = 2;
305
+ const GET_TABLE_IDS_DIFF = 3;
306
+ const GET_ROW_IDS_DIFF = 4;
307
+ const GET_TABLES_CHANGES = 5;
308
+ const GET_VALUES_CHANGES = 6;
309
+ const createCustomSynchronizer = (
310
+ store,
311
+ send,
312
+ onReceive,
313
+ destroy,
314
+ requestTimeoutSeconds = 1,
315
+ onIgnoredError,
316
+ ) => {
317
+ let persisterListener;
318
+ let sends = 0;
319
+ let receives = 0;
320
+ const [getHlc] = getHlcFunctions(store.getId());
321
+ const pendingRequests = mapNew();
322
+ onReceive((fromClientId, requestId, messageType, messageBody) => {
323
+ {
324
+ receives++;
325
+ }
326
+ if (messageType == RESPONSE) {
327
+ ifNotUndefined(
328
+ mapGet(pendingRequests, requestId),
329
+ ([toClientId, handleResponse]) =>
330
+ isUndefined(toClientId) || toClientId == fromClientId
331
+ ? handleResponse(messageBody, fromClientId)
332
+ : /* istanbul ignore next */
333
+ 0,
334
+ );
335
+ } else if (messageType == CONTENT_HASHES && persister.isAutoLoading()) {
336
+ getChangesFromOtherStore(fromClientId, messageBody).then((changes) =>
337
+ persisterListener?.(void 0, () => changes),
338
+ );
339
+ } else {
340
+ ifNotUndefined(
341
+ messageType == GET_CONTENT_HASHES && persister.isAutoSaving()
342
+ ? store.getMergeableContentHashes()
343
+ : messageType == GET_TABLE_IDS_DIFF
344
+ ? store.getMergeableTableIdsDiff(messageBody)
345
+ : messageType == GET_ROW_IDS_DIFF
346
+ ? store.getMergeableRowIdsDiff(messageBody)
347
+ : messageType == GET_TABLES_CHANGES
348
+ ? store.getMergeableTablesChanges(messageBody)
349
+ : messageType == GET_VALUES_CHANGES
350
+ ? store.getMergeableValuesChanges(messageBody)
351
+ : void 0,
352
+ (response) => {
353
+ {
354
+ sends++;
355
+ }
356
+ send(fromClientId, requestId, RESPONSE, response);
357
+ },
358
+ );
359
+ }
360
+ });
361
+ const request = async (toClientId, messageType, messageBody = EMPTY_STRING) =>
362
+ promiseNew((resolve, reject) => {
363
+ const requestId = getHlc();
364
+ const timeout = setTimeout(() => {
365
+ collDel(pendingRequests, requestId);
366
+ reject(
367
+ `No response from ${toClientId ?? 'anyone'} to '${messageType}'`,
368
+ );
369
+ }, requestTimeoutSeconds * 1e3);
370
+ mapSet(pendingRequests, requestId, [
371
+ toClientId,
372
+ (response, fromClientId) => {
373
+ clearTimeout(timeout);
374
+ collDel(pendingRequests, requestId);
375
+ resolve([response, fromClientId]);
376
+ },
377
+ ]);
378
+ {
379
+ sends++;
380
+ }
381
+ send(toClientId, requestId, messageType, messageBody);
382
+ });
383
+ const getChangesFromOtherStore = async (
384
+ otherClientId = null,
385
+ otherContentHashes,
386
+ ) => {
387
+ if (isUndefined(otherContentHashes)) {
388
+ [otherContentHashes, otherClientId] = await request(
389
+ otherClientId,
390
+ GET_CONTENT_HASHES,
391
+ );
392
+ }
393
+ const [otherContentTime, [otherTablesHash, otherValuesHash]] =
394
+ otherContentHashes;
395
+ const [, [tablesHash, valuesHash]] = store.getMergeableContentHashes();
396
+ const changes = [EMPTY_STRING, [[EMPTY_STRING, {}], [EMPTY_STRING, {}], 1]];
397
+ if (tablesHash != otherTablesHash) {
398
+ changes[0] = otherContentTime;
399
+ changes[1][0] = (
400
+ await request(
401
+ otherClientId,
402
+ GET_TABLES_CHANGES,
403
+ store.getMergeableCellHashes(
404
+ (
405
+ await request(
406
+ otherClientId,
407
+ GET_ROW_IDS_DIFF,
408
+ store.getMergeableRowHashes(
409
+ (
410
+ await request(
411
+ otherClientId,
412
+ GET_TABLE_IDS_DIFF,
413
+ store.getMergeableTableHashes(),
414
+ )
415
+ )[0],
416
+ ),
417
+ )
418
+ )[0],
419
+ ),
420
+ )
421
+ )[0];
422
+ }
423
+ if (valuesHash != otherValuesHash) {
424
+ changes[0] = otherContentTime;
425
+ changes[1][1] = (
426
+ await request(
427
+ otherClientId,
428
+ GET_VALUES_CHANGES,
429
+ store.getMergeableValuesHashes(),
430
+ )
431
+ )[0];
432
+ }
433
+ return changes;
434
+ };
435
+ const getPersisted = async () => {
436
+ const changes = await getChangesFromOtherStore();
437
+ return changes[0] != EMPTY_STRING ? changes : void 0;
438
+ };
439
+ const setPersisted = async () => {
440
+ {
441
+ sends++;
442
+ }
443
+ send(null, null, CONTENT_HASHES, store.getMergeableContentHashes());
444
+ };
445
+ const addPersisterListener = (listener) => (persisterListener = listener);
446
+ const delPersisterListener = () => (persisterListener = void 0);
447
+ const persister = createCustomPersister(
448
+ store,
449
+ getPersisted,
450
+ setPersisted,
451
+ addPersisterListener,
452
+ delPersisterListener,
453
+ onIgnoredError,
454
+ true,
455
+ {
456
+ startSync: async () =>
457
+ await (await persister.startAutoLoad()).startAutoSave(),
458
+ stopSync: () => persister.stopAutoLoad().stopAutoSave(),
459
+ destroy: () => {
460
+ destroy();
461
+ return persister.stopSync();
462
+ },
463
+ getSynchronizerStats: () => ({sends, receives}),
464
+ },
465
+ );
466
+ return persister;
467
+ };
468
+
469
+ const clients = mapNew();
470
+ const createLocalSynchronizer = (store, onIgnoredError) => {
471
+ const clientId = '' + Math.random();
472
+ const onReceive = (receive) => {
473
+ mapSet(clients, clientId, receive);
474
+ };
475
+ const send = (toClientId, requestId, messageType, messageBody) => {
476
+ isUndefined(toClientId)
477
+ ? mapForEach(clients, (otherClientId, receive) =>
478
+ otherClientId != clientId
479
+ ? receive(clientId, requestId, messageType, messageBody)
480
+ : 0,
481
+ )
482
+ : mapGet(clients, toClientId)?.(
483
+ clientId,
484
+ requestId,
485
+ messageType,
486
+ messageBody,
487
+ );
488
+ };
489
+ const destroy = () => {
490
+ collDel(clients, clientId);
491
+ };
492
+ return createCustomSynchronizer(
493
+ store,
494
+ send,
495
+ onReceive,
496
+ destroy,
497
+ 1e-3,
498
+ onIgnoredError,
499
+ );
500
+ };
501
+
502
+ export {createLocalSynchronizer};