@signaldb/sync 2.0.0-beta.1 → 2.0.0-beta.3

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.
@@ -93,14 +93,14 @@ export default class SyncManager<CollectionOptions extends Record<string, any>,
93
93
  * Gets a collection with it's options by name
94
94
  * @deprecated Use getCollectionProperties instead.
95
95
  * @param name Name of the collection
96
- * @throws Will throw an error if the name wasn't found
96
+ * @throws {Error} Will throw an error if the name wasn't found
97
97
  * @returns Tuple of collection and options
98
98
  */
99
- getCollection(name: string): (Collection<ItemType, IdType, any> | SyncOptions<CollectionOptions>)[];
99
+ getCollection(name: string): (Collection<ItemType, IdType, any, any> | SyncOptions<CollectionOptions>)[];
100
100
  /**
101
101
  * Gets collection options by name
102
102
  * @param name Name of the collection
103
- * @throws Will throw an error if the name wasn't found
103
+ * @throws {Error} Will throw an error if the name wasn't found
104
104
  * @returns An object of all properties of the collection
105
105
  */
106
106
  getCollectionProperties(name: string): {
@@ -116,7 +116,7 @@ export default class SyncManager<CollectionOptions extends Record<string, any>,
116
116
  * @param options Options for the collection. The object needs at least a `name` property.
117
117
  * @param options.name Unique name of the collection
118
118
  */
119
- addCollection(collection: Collection<ItemType, IdType, any>, options: SyncOptions<CollectionOptions>): void;
119
+ addCollection<CollectionItem extends ItemType = ItemType>(collection: Collection<CollectionItem, IdType, any>, options: SyncOptions<CollectionOptions>): void;
120
120
  protected flushScheduledPushes(): void;
121
121
  protected schedulePush(name: string): void;
122
122
  /**
package/dist/index.mjs CHANGED
@@ -1,12 +1,12 @@
1
1
  import { isEqual as N, modify as w, randomId as S, DefaultDataAdapter as E, Collection as y } from "@signaldb/core";
2
2
  function $(l, e, t = {}) {
3
- let s, o;
4
- const { leading: n = !1, trailing: a = !0 } = t;
3
+ let s, n;
4
+ const { leading: a = !1, trailing: o = !0 } = t;
5
5
  function r(...c) {
6
- const i = n && !s, h = a && !s;
6
+ const i = a && !s, h = o && !s;
7
7
  return s && clearTimeout(s), s = setTimeout(() => {
8
- s = null, a && !i && (o = l.apply(this, c));
9
- }, e), i ? o = l.apply(this, c) : h || (o = null), o;
8
+ s = null, o && !i && (n = l.apply(this, c));
9
+ }, e), i ? n = l.apply(this, c) : h || (n = null), n;
10
10
  }
11
11
  return r;
12
12
  }
@@ -20,8 +20,8 @@ class D {
20
20
  */
21
21
  add(e) {
22
22
  return new Promise((t, s) => {
23
- this.queue.push(() => e().then(t).catch((o) => {
24
- throw s(o), o;
23
+ this.queue.push(() => e().then(t).catch((n) => {
24
+ throw s(n), n;
25
25
  })), this.dequeue();
26
26
  });
27
27
  }
@@ -47,30 +47,30 @@ class D {
47
47
  }
48
48
  }
49
49
  function C(l, e) {
50
- const t = [], s = Object.keys(l), o = Object.keys(e), n = /* @__PURE__ */ new Set([...s, ...o]);
51
- for (const a of n)
52
- if (e[a] !== l[a])
53
- if (typeof e[a] == "object" && typeof l[a] == "object" && e[a] != null && l[a] != null) {
54
- const r = C(l[a], e[a]);
50
+ const t = [], s = Object.keys(l), n = Object.keys(e), a = /* @__PURE__ */ new Set([...s, ...n]);
51
+ for (const o of a)
52
+ if (e[o] !== l[o])
53
+ if (typeof e[o] == "object" && typeof l[o] == "object" && e[o] != null && l[o] != null) {
54
+ const r = C(l[o], e[o]);
55
55
  for (const c of r)
56
- t.push(`${a}.${c}`);
56
+ t.push(`${o}.${c}`);
57
57
  } else
58
- t.push(a);
58
+ t.push(o);
59
59
  return t;
60
60
  }
61
61
  function f(l, e) {
62
- const t = [], s = [], o = /* @__PURE__ */ new Map(), n = [], a = new Map(l.map((c) => [c.id, c])), r = new Map(e.map((c) => [c.id, c]));
63
- for (const [c, i] of a) {
62
+ const t = [], s = [], n = /* @__PURE__ */ new Map(), a = [], o = new Map(l.map((c) => [c.id, c])), r = new Map(e.map((c) => [c.id, c]));
63
+ for (const [c, i] of o) {
64
64
  const h = r.get(c);
65
- h ? N(h, i) || (o.set(h.id, C(i, h)), s.push(h)) : n.push(i);
65
+ h ? N(h, i) || (n.set(h.id, C(i, h)), s.push(h)) : a.push(i);
66
66
  }
67
67
  for (const [c, i] of r)
68
- a.has(c) || t.push(i);
68
+ o.has(c) || t.push(i);
69
69
  return {
70
70
  added: t,
71
71
  modified: s,
72
- modifiedFields: o,
73
- removed: n
72
+ modifiedFields: n,
73
+ removed: a
74
74
  };
75
75
  }
76
76
  function g(l, e) {
@@ -78,14 +78,14 @@ function g(l, e) {
78
78
  return e.items;
79
79
  const t = l || [];
80
80
  return e.changes.added.forEach((s) => {
81
- const o = t.findIndex((n) => n.id === s.id);
82
- o === -1 ? t.push(s) : t[o] = s;
81
+ const n = t.findIndex((a) => a.id === s.id);
82
+ n === -1 ? t.push(s) : t[n] = s;
83
83
  }), e.changes.modified.forEach((s) => {
84
- const o = t.findIndex((n) => n.id === s.id);
85
- o === -1 ? t.push(s) : t[o] = s;
84
+ const n = t.findIndex((a) => a.id === s.id);
85
+ n === -1 ? t.push(s) : t[n] = s;
86
86
  }), e.changes.removed.forEach((s) => {
87
- const o = t.findIndex((n) => n.id === s.id);
88
- o !== -1 && t.splice(o, 1);
87
+ const n = t.findIndex((a) => a.id === s.id);
88
+ n !== -1 && t.splice(n, 1);
89
89
  }), t;
90
90
  }
91
91
  function P(l, e) {
@@ -94,11 +94,11 @@ function P(l, e) {
94
94
  if (s.type === "remove")
95
95
  t.delete(s.data);
96
96
  else if (s.type === "insert") {
97
- const o = t.get(s.data.id);
98
- t.set(s.data.id, o ? { ...o, ...s.data } : s.data);
97
+ const n = t.get(s.data.id);
98
+ t.set(s.data.id, n ? { ...n, ...s.data } : s.data);
99
99
  } else {
100
- const o = t.get(s.data.id);
101
- t.set(s.data.id, o ? w(o, s.data.modifier) : w({ id: s.data.id }, s.data.modifier));
100
+ const n = t.get(s.data.id);
101
+ t.set(s.data.id, n ? w(n, s.data.modifier) : w({ id: s.data.id }, s.data.modifier));
102
102
  }
103
103
  }), [...t.values()];
104
104
  }
@@ -108,18 +108,18 @@ function v(l) {
108
108
  function M(l, e) {
109
109
  return v(f(l, e));
110
110
  }
111
- async function F({ changes: l, lastSnapshot: e, data: t, pull: s, push: o, insert: n, update: a, remove: r, batch: c }) {
111
+ async function F({ changes: l, lastSnapshot: e, data: t, pull: s, push: n, insert: a, update: o, remove: r, batch: c }) {
112
112
  let i = t, h = e || [], p = g(e, i);
113
113
  if (l.length > 0) {
114
114
  const u = P(h, l);
115
115
  if (M(h, u)) {
116
116
  const O = P(p, l), m = f(p, O);
117
- v(m) && (await o(m), i = await s(), p = g(p, i)), h = u;
117
+ v(m) && (await n(m), i = await s(), p = g(p, i)), h = u;
118
118
  }
119
119
  }
120
120
  const d = i.changes == null ? f(h, i.items) : i.changes;
121
121
  return await c(async () => {
122
- await Promise.all(d.added.map((u) => n(u))), await Promise.all(d.modified.map((u) => a(u.id, { $set: u }))), await Promise.all(d.removed.map((u) => r(u.id)));
122
+ await Promise.all(d.added.map((u) => a(u))), await Promise.all(d.modified.map((u) => o(u.id, { $set: u }))), await Promise.all(d.removed.map((u) => r(u.id)));
123
123
  }), p;
124
124
  }
125
125
  class b {
@@ -163,11 +163,13 @@ class b {
163
163
  }), this.syncOperations = new y(`${this.options.id}-sync-operations`, s, {
164
164
  indices: ["collectionName", "status"],
165
165
  reactivity: t
166
- }), this.collectionsReady = Promise.all([
167
- this.syncOperations.isReady(),
168
- this.changes.isReady(),
169
- this.snapshots.isReady()
170
- ]).then(() => {
166
+ });
167
+ const n = [
168
+ Promise.resolve(this.syncOperations.isReady()),
169
+ Promise.resolve(this.changes.isReady()),
170
+ Promise.resolve(this.snapshots.isReady())
171
+ ];
172
+ this.collectionsReady = Promise.all(n).then(() => {
171
173
  }), this.changes.setMaxListeners(1e3), this.snapshots.setMaxListeners(1e3), this.syncOperations.setMaxListeners(1e3), this.debouncedFlush = $(this.flushScheduledPushes, this.options.debounceTime ?? 100);
172
174
  }
173
175
  getSyncQueue(e) {
@@ -187,7 +189,7 @@ class b {
187
189
  * Gets a collection with it's options by name
188
190
  * @deprecated Use getCollectionProperties instead.
189
191
  * @param name Name of the collection
190
- * @throws Will throw an error if the name wasn't found
192
+ * @throws {Error} Will throw an error if the name wasn't found
191
193
  * @returns Tuple of collection and options
192
194
  */
193
195
  getCollection(e) {
@@ -197,7 +199,7 @@ class b {
197
199
  /**
198
200
  * Gets collection options by name
199
201
  * @param name Name of the collection
200
- * @throws Will throw an error if the name wasn't found
202
+ * @throws {Error} Will throw an error if the name wasn't found
201
203
  * @returns An object of all properties of the collection
202
204
  */
203
205
  getCollectionProperties(e) {
@@ -222,38 +224,38 @@ class b {
222
224
  syncPaused: !0
223
225
  // always start paused as the autostart will start it
224
226
  });
225
- const s = (n) => {
226
- for (const a of this.remoteChanges)
227
- if (a != null && a.collectionName === n.collectionName && a.type === n.type && !(n.type === "remove" && a.data !== n.data) && a.data.id === n.data.id)
227
+ const s = (a) => {
228
+ for (const o of this.remoteChanges)
229
+ if (o != null && o.collectionName === a.collectionName && o.type === a.type && !(a.type === "remove" && o.data !== a.data) && o.data.id === a.data.id)
228
230
  return !0;
229
231
  return !1;
230
- }, o = (n, a) => {
232
+ }, n = (a, o) => {
231
233
  const r = [...this.remoteChanges];
232
234
  for (let c = 0; c < r.length; c += 1) {
233
235
  const i = r[c];
234
- i != null && i.collectionName === n && (i.type === "remove" && i.data !== a || i.data.id === a && (r[c] = null));
236
+ i != null && i.collectionName === a && (i.type === "remove" && i.data !== o || i.data.id === o && (r[c] = null));
235
237
  }
236
238
  this.remoteChanges = r.filter((c) => c != null);
237
239
  };
238
- e.on("added", (n) => {
239
- if (s({ collectionName: t.name, type: "insert", data: n })) {
240
- o(t.name, n.id);
240
+ e.on("added", (a) => {
241
+ if (s({ collectionName: t.name, type: "insert", data: a })) {
242
+ n(t.name, a.id);
241
243
  return;
242
244
  }
243
245
  this.changes.insert({
244
246
  collectionName: t.name,
245
247
  time: Date.now(),
246
248
  type: "insert",
247
- data: n
249
+ data: a
248
250
  }).then(() => {
249
251
  this.getCollectionProperties(t.name).syncPaused || this.schedulePush(t.name);
250
- }).catch((a) => {
251
- this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, a);
252
+ }).catch((o) => {
253
+ this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, o);
252
254
  });
253
- }), e.on("changed", ({ id: n }, a) => {
254
- const r = { id: n, modifier: a };
255
+ }), e.on("changed", ({ id: a }, o) => {
256
+ const r = { id: a, modifier: o };
255
257
  if (s({ collectionName: t.name, type: "update", data: r })) {
256
- o(t.name, n);
258
+ n(t.name, a);
257
259
  return;
258
260
  }
259
261
  this.changes.insert({
@@ -266,23 +268,23 @@ class b {
266
268
  }).catch((c) => {
267
269
  this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, c);
268
270
  });
269
- }), e.on("removed", ({ id: n }) => {
270
- if (s({ collectionName: t.name, type: "remove", data: n })) {
271
- o(t.name, n);
271
+ }), e.on("removed", ({ id: a }) => {
272
+ if (s({ collectionName: t.name, type: "remove", data: a })) {
273
+ n(t.name, a);
272
274
  return;
273
275
  }
274
276
  this.changes.insert({
275
277
  collectionName: t.name,
276
278
  time: Date.now(),
277
279
  type: "remove",
278
- data: n
280
+ data: a
279
281
  }).then(() => {
280
282
  this.getCollectionProperties(t.name).syncPaused || this.schedulePush(t.name);
281
- }).catch((a) => {
282
- this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, a);
283
+ }).catch((o) => {
284
+ this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, o);
283
285
  });
284
- }), this.options.autostart && this.startSync(t.name).catch((n) => {
285
- this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, n);
286
+ }), this.options.autostart && this.startSync(t.name).catch((a) => {
287
+ this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, a);
286
288
  });
287
289
  }
288
290
  flushScheduledPushes() {
@@ -311,33 +313,31 @@ class b {
311
313
  if (!t.syncPaused)
312
314
  return;
313
315
  this.schedulePush(e);
314
- const s = this.options.registerRemoteChange ? await this.options.registerRemoteChange(t.options, async (o) => {
315
- if (o == null)
316
- await this.sync(e);
317
- else {
318
- const n = Date.now(), a = await this.syncOperations.insert({
319
- start: n,
316
+ const s = this.options.registerRemoteChange ? await this.options.registerRemoteChange(t.options, async (n) => {
317
+ await (n == null ? this.sync(e) : this.getSyncQueue(e).add(async () => {
318
+ const a = Date.now(), o = await this.syncOperations.insert({
319
+ start: a,
320
320
  collectionName: e,
321
321
  instanceId: this.instanceId,
322
322
  status: "active"
323
323
  });
324
- await this.syncWithData(e, o).then(async () => {
324
+ await this.syncWithData(e, n).then(async () => {
325
325
  await this.syncOperations.removeMany({
326
- id: { $ne: a },
326
+ id: { $ne: o },
327
327
  collectionName: e,
328
328
  $or: [
329
- { end: { $lte: n } },
329
+ { end: { $lte: a } },
330
330
  { status: "active" }
331
331
  ]
332
- }), await this.syncOperations.updateOne({ id: a }, {
332
+ }), await this.syncOperations.updateOne({ id: o }, {
333
333
  $set: { status: "done", end: Date.now() }
334
334
  });
335
335
  }).catch(async (r) => {
336
- throw this.options.onError && this.options.onError(this.getCollectionProperties(e).options, r), await this.syncOperations.updateOne({ id: a }, {
336
+ throw this.options.onError && this.options.onError(this.getCollectionProperties(e).options, r), await this.syncOperations.updateOne({ id: o }, {
337
337
  $set: { status: "error", end: Date.now(), error: r.stack || r.message }
338
338
  }), r;
339
339
  });
340
- }
340
+ }));
341
341
  }) : void 0;
342
342
  this.collections.set(e, {
343
343
  ...t,
@@ -393,7 +393,7 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
393
393
  ...e ? { collectionName: e } : {},
394
394
  status: "active"
395
395
  }, { fields: { status: 1 }, async: t });
396
- return s instanceof Promise ? s.then((o) => o != null) : s != null;
396
+ return s instanceof Promise ? s.then((n) => n != null) : s != null;
397
397
  }
398
398
  /**
399
399
  * Checks if the sync manager is ready to sync.
@@ -413,16 +413,16 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
413
413
  if (this.isDisposed)
414
414
  throw new Error("SyncManager is disposed");
415
415
  await this.isReady();
416
- const { options: s, readyPromise: o } = this.getCollectionProperties(e);
417
- await o;
418
- const n = await this.syncOperations.find({
416
+ const { options: s, readyPromise: n } = this.getCollectionProperties(e);
417
+ await n;
418
+ const a = await this.syncOperations.find({
419
419
  collectionName: e,
420
420
  instanceId: this.instanceId,
421
421
  status: "active"
422
422
  }, {
423
423
  reactive: !1,
424
424
  async: !0
425
- }).count() > 0, a = Date.now();
425
+ }).count() > 0, o = Date.now();
426
426
  let r = null;
427
427
  await new Promise((i) => {
428
428
  setTimeout(i, 0);
@@ -438,15 +438,15 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
438
438
  });
439
439
  if (t?.onlyWithChanges && await this.changes.find({
440
440
  collectionName: e,
441
- time: { $lte: a }
441
+ time: { $lte: o }
442
442
  }, {
443
443
  sort: { time: 1 },
444
444
  reactive: !1,
445
445
  async: !0
446
446
  }).count() === 0)
447
447
  return;
448
- n || (r = await this.syncOperations.insert({
449
- start: a,
448
+ a || (r = await this.syncOperations.insert({
449
+ start: o,
450
450
  collectionName: e,
451
451
  instanceId: this.instanceId,
452
452
  status: "active"
@@ -465,7 +465,7 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
465
465
  id: { $ne: r },
466
466
  collectionName: e,
467
467
  $or: [
468
- { end: { $lte: a } },
468
+ { end: { $lte: o } },
469
469
  { status: "active" }
470
470
  ]
471
471
  }), await this.syncOperations.updateOne({ id: r }, {
@@ -482,7 +482,7 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
482
482
  });
483
483
  }
484
484
  async syncWithData(e, t) {
485
- const { collection: s, options: o } = this.getCollectionProperties(e), n = Date.now(), a = await this.syncOperations.findOne({
485
+ const { collection: s, options: n } = this.getCollectionProperties(e), a = Date.now(), o = await this.syncOperations.findOne({
486
486
  collectionName: e,
487
487
  status: "done"
488
488
  }, {
@@ -497,7 +497,7 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
497
497
  async: !0
498
498
  }), c = await this.changes.find({
499
499
  collectionName: e,
500
- time: { $lte: n }
500
+ time: { $lte: a }
501
501
  }, {
502
502
  sort: { time: 1 },
503
503
  reactive: !1,
@@ -507,11 +507,11 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
507
507
  changes: c,
508
508
  lastSnapshot: r?.items,
509
509
  data: t,
510
- pull: () => this.options.pull(o, {
511
- lastFinishedSyncStart: a?.start,
512
- lastFinishedSyncEnd: a?.end
510
+ pull: () => this.options.pull(n, {
511
+ lastFinishedSyncStart: o?.start,
512
+ lastFinishedSyncEnd: o?.end
513
513
  }),
514
- push: (i) => this.options.push(o, {
514
+ push: (i) => this.options.push(n, {
515
515
  changes: i,
516
516
  rawChanges: c
517
517
  }),
@@ -555,12 +555,12 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
555
555
  }).then(async (i) => {
556
556
  if (await this.snapshots.removeMany({
557
557
  collectionName: e,
558
- time: { $lte: n }
558
+ time: { $lte: a }
559
559
  }), await this.changes.removeMany({
560
560
  collectionName: e,
561
561
  id: { $in: c.map((d) => d.id) }
562
562
  }), await this.snapshots.insert({
563
- time: n,
563
+ time: a,
564
564
  collectionName: e,
565
565
  items: i
566
566
  }), await new Promise((d) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","sources":["../src/utils/debounce.ts","../src/utils/PromiseQueue.ts","../src/computeChanges.ts","../src/getSnapshot.ts","../src/applyChanges.ts","../src/sync.ts","../src/SyncManager.ts"],"sourcesContent":["/**\n * Debounces a function.\n * @param fn Function to debounce\n * @param wait Time to wait before calling the function.\n * @param [options] Debounce options\n * @param [options.leading] Whether to call the function on the leading edge of the wait interval.\n * @param [options.trailing] Whether to call the function on the trailing edge of the wait interval.\n * @returns The debounced function.\n */\nexport default function debounce(fn, wait, options = {}) {\n let timeout;\n let result;\n const { leading = false, trailing = true } = options;\n /**\n * The debounced function that will be returned.\n * @param this The context to bind the function to.\n * @param args The arguments to pass to the function.\n * @returns The result of the debounced function.\n */\n function debounced(...args) {\n const shouldCallImmediately = leading && !timeout;\n const shouldCallTrailing = trailing && !timeout;\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(() => {\n timeout = null;\n if (trailing && !shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n }, wait);\n if (shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n else if (!shouldCallTrailing) {\n result = null;\n }\n return result;\n }\n return debounced;\n}\n","/**\n * Class for queuing promises to be executed one after the other.\n * This is useful for tasks that should not be executed in parallel.\n * @example\n * const queue = new PromiseQueue();\n * queue.add(() => fetch('https://example.com/api/endpoint1'));\n * queue.add(() => fetch('https://example.com/api/endpoint2'));\n * // The second fetch will only be executed after the first one is done.\n */\nexport default class PromiseQueue {\n queue = [];\n pendingPromise = false;\n /**\n * Method to add a new promise to the queue and returns a promise that resolves when this task is done\n * @param task Function that returns a promise that will be added to the queue\n * @returns Promise that resolves when the task is done\n */\n add(task) {\n return new Promise((resolve, reject) => {\n // Wrap the task with the resolve and reject to control its completion from the outside\n this.queue.push(() => task()\n .then(resolve)\n .catch((error) => {\n reject(error);\n throw error;\n }));\n this.dequeue();\n });\n }\n /**\n * Method to check if there is a pending promise in the queue\n * @returns True if there is a pending promise, false otherwise\n */\n hasPendingPromise() {\n return this.pendingPromise;\n }\n /**\n * Method to process the queue\n */\n dequeue() {\n if (this.pendingPromise || this.queue.length === 0) {\n return;\n }\n const task = this.queue.shift();\n if (!task)\n return;\n this.pendingPromise = true;\n task()\n .then(() => {\n this.pendingPromise = false;\n this.dequeue();\n })\n .catch(() => {\n this.pendingPromise = false;\n this.dequeue();\n });\n }\n}\n","import { isEqual } from '@signaldb/core';\n/**\n * Computes the modified fields between two items recursively.\n * @param oldItem The old item\n * @param newItem The new item\n * @returns The modified fields\n */\nexport function computeModifiedFields(oldItem, newItem) {\n const modifiedFields = [];\n const oldKeys = Object.keys(oldItem);\n const newKeys = Object.keys(newItem);\n const allKeys = new Set([...oldKeys, ...newKeys]);\n for (const key of allKeys) {\n if (newItem[key] !== oldItem[key]) {\n if (typeof newItem[key] === 'object' && typeof oldItem[key] === 'object' && newItem[key] != null && oldItem[key] != null) {\n const nestedModifiedFields = computeModifiedFields(oldItem[key], newItem[key]);\n for (const nestedField of nestedModifiedFields) {\n modifiedFields.push(`${key}.${nestedField}`);\n }\n }\n else {\n modifiedFields.push(key);\n }\n }\n }\n return modifiedFields;\n}\n/**\n * Compute changes between two arrays of items.\n * @param oldItems Array of the old items\n * @param newItems Array of the new items\n * @returns The changeset\n */\nexport default function computeChanges(oldItems, newItems) {\n const added = [];\n const modified = [];\n const modifiedFields = new Map();\n const removed = [];\n const oldItemsMap = new Map(oldItems.map(item => [item.id, item]));\n const newItemsMap = new Map(newItems.map(item => [item.id, item]));\n for (const [id, oldItem] of oldItemsMap) {\n const newItem = newItemsMap.get(id);\n if (!newItem) {\n removed.push(oldItem);\n }\n else if (!isEqual(newItem, oldItem)) {\n modifiedFields.set(newItem.id, computeModifiedFields(oldItem, newItem));\n modified.push(newItem);\n }\n }\n for (const [id, newItem] of newItemsMap) {\n if (!oldItemsMap.has(id)) {\n added.push(newItem);\n }\n }\n return {\n added,\n modified,\n modifiedFields,\n removed,\n };\n}\n","/**\n * Gets the snapshot of items from the last snapshot and the changes.\n * @param lastSnapshot The last snapshot of items\n * @param data The changes to apply to the last snapshot\n * @returns The new snapshot of items\n */\nexport default function getSnapshot(lastSnapshot, data) {\n if (data.items != null)\n return data.items;\n const items = lastSnapshot || [];\n data.changes.added.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.modified.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.removed.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index !== -1)\n items.splice(index, 1);\n });\n return items;\n}\n","import { modify } from '@signaldb/core';\n/**\n * applies changes to a collection of items\n * @param items The items to apply the changes to\n * @param changes The changes to apply to the items\n * @returns The new items after applying the changes\n */\nexport default function applyChanges(items, changes) {\n // Create initial map of items by ID\n const itemMap = new Map(items.map(item => [item.id, item]));\n changes.forEach((change) => {\n if (change.type === 'remove') {\n itemMap.delete(change.data);\n }\n else if (change.type === 'insert') {\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem ? { ...existingItem, ...change.data } : change.data);\n }\n else { // change.type === 'update'\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem\n ? modify(existingItem, change.data.modifier)\n : modify({ id: change.data.id }, change.data.modifier));\n }\n });\n // Convert map back to array\n return [...itemMap.values()];\n}\n","import computeChanges from './computeChanges';\nimport getSnapshot from './getSnapshot';\nimport applyChanges from './applyChanges';\n/**\n * Checks if there are any changes in the given changeset.\n * @param changes The changeset to check.\n * @returns True if there are changes, false otherwise.\n */\nfunction hasChanges(changes) {\n return changes.added.length > 0\n || changes.modified.length > 0\n || changes.removed.length > 0;\n}\n/**\n * Checks if there is a difference between the old items and the new items.\n * @param oldItems The old items.\n * @param newItems The new items.\n * @returns True if there is a difference, false otherwise.\n */\nfunction hasDifference(oldItems, newItems) {\n return hasChanges(computeChanges(oldItems, newItems));\n}\n/**\n * Does a sync operation based on the provided options. If changes are supplied, these will be rebased on the new data.\n * Afterwards the push method will be called with the remaining changes. A new snapshot will be created and returned.\n * @param options Sync options\n * @param options.changes Changes to call the push method with\n * @param [options.lastSnapshot] The last snapshot\n * @param options.data The new data\n * @param options.pull Method to pull new data\n * @param options.push Method to push changes\n * @param options.insert Method to insert an item\n * @param options.update Method to update an item\n * @param options.remove Method to remove an item\n * @param options.batch Method to batch multiple operations\n * @returns The new snapshot\n */\nexport default async function sync({ changes, lastSnapshot, data, pull, push, insert, update, remove, batch, }) {\n let newData = data;\n let previousSnapshot = lastSnapshot || [];\n let newSnapshot = getSnapshot(lastSnapshot, newData);\n if (changes.length > 0) {\n // apply changes on last snapshot and check if there is a difference\n const lastSnapshotWithChanges = applyChanges(previousSnapshot, changes);\n if (hasDifference(previousSnapshot, lastSnapshotWithChanges)) {\n // if yes, apply the changes on the newSnapshot and check if there is a difference\n const newSnapshotWithChanges = applyChanges(newSnapshot, changes);\n const changesToPush = computeChanges(newSnapshot, newSnapshotWithChanges);\n if (hasChanges(changesToPush)) {\n // if yes, push the changes to the server\n await push(changesToPush);\n // pull new data afterwards to ensure that all server changes are applied\n newData = await pull();\n newSnapshot = getSnapshot(newSnapshot, newData);\n }\n previousSnapshot = lastSnapshotWithChanges;\n }\n }\n // apply the new changes on the collection\n const newChanges = newData.changes == null\n ? computeChanges(previousSnapshot, newData.items)\n : newData.changes;\n await batch(async () => {\n await Promise.all(newChanges.added.map(item => insert(item)));\n await Promise.all(newChanges.modified.map(item => update(item.id, { $set: item })));\n await Promise.all(newChanges.removed.map(item => remove(item.id)));\n });\n return newSnapshot;\n}\n","import { DefaultDataAdapter, Collection, randomId } from '@signaldb/core';\nimport debounce from './utils/debounce';\nimport PromiseQueue from './utils/PromiseQueue';\nimport sync from './sync';\n/**\n * Class to manage syncing of collections.\n * @template CollectionOptions\n * @template ItemType\n * @template IdType\n * @example\n * const syncManager = new SyncManager({\n * pull: async (collectionOptions) => {\n * const response = await fetch(`/api/collections/${collectionOptions.name}`)\n * return await response.json()\n * },\n * push: async (collectionOptions, { changes }) => {\n * await fetch(`/api/collections/${collectionOptions.name}`, {\n * method: 'POST',\n * body: JSON.stringify(changes),\n * })\n * },\n * })\n *\n * const collection = new Collection()\n * syncManager.addCollection(collection, {\n * name: 'todos',\n * })\n *\n * syncManager.sync('todos')\n */\nexport default class SyncManager {\n options;\n collections = new Map();\n changes;\n snapshots;\n syncOperations;\n scheduledPushes = new Set();\n remoteChanges = [];\n syncQueues = new Map();\n collectionsReady;\n isDisposed = false;\n instanceId = randomId();\n id;\n debouncedFlush;\n /**\n * @param options Collection options\n * @param options.pull Function to pull data from remote source.\n * @param options.push Function to push data to remote source.\n * @param [options.registerRemoteChange] Function to register a callback for remote changes.\n * @param [options.id] Unique identifier for this sync manager. Only nessesary if you have multiple sync managers.\n * @param [options.storageAdapter] Storage adapter to use for storing changes, snapshots and sync operations.\n * @param [options.reactivity] Reactivity adapter to use for reactivity.\n * @param [options.onError] Function to handle errors that occur async during syncing.\n * @param [options.autostart] Whether to automatically start syncing new collections.\n * @param [options.debounceTime] The time in milliseconds to debounce push operations.\n */\n constructor(options) {\n this.options = {\n autostart: true,\n ...options,\n };\n this.id = this.options.id || 'default-sync-manager';\n const { reactivity } = this.options;\n const dataAdapter = this.options.dataAdapter ?? new DefaultDataAdapter();\n this.changes = new Collection(`${this.options.id}-changes`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.snapshots = new Collection(`${this.options.id}-snapshots`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.syncOperations = new Collection(`${this.options.id}-sync-operations`, dataAdapter, {\n indices: ['collectionName', 'status'],\n reactivity,\n });\n this.collectionsReady = Promise.all([\n this.syncOperations.isReady(),\n this.changes.isReady(),\n this.snapshots.isReady(),\n ]).then(() => { });\n this.changes.setMaxListeners(1000);\n this.snapshots.setMaxListeners(1000);\n this.syncOperations.setMaxListeners(1000);\n this.debouncedFlush = debounce(this.flushScheduledPushes, this.options.debounceTime ?? 100);\n }\n getSyncQueue(name) {\n if (this.syncQueues.get(name) == null) {\n this.syncQueues.set(name, new PromiseQueue());\n }\n return this.syncQueues.get(name);\n }\n /**\n * Clears all internal data structures\n */\n async dispose() {\n this.collections.clear();\n this.syncQueues.clear();\n this.remoteChanges.splice(0);\n await Promise.all([\n this.changes.dispose(),\n this.snapshots.dispose(),\n this.syncOperations.dispose(),\n ]);\n this.isDisposed = true;\n }\n /**\n * Gets a collection with it's options by name\n * @deprecated Use getCollectionProperties instead.\n * @param name Name of the collection\n * @throws Will throw an error if the name wasn't found\n * @returns Tuple of collection and options\n */\n getCollection(name) {\n const { collection, options } = this.getCollectionProperties(name);\n return [collection, options];\n }\n /**\n * Gets collection options by name\n * @param name Name of the collection\n * @throws Will throw an error if the name wasn't found\n * @returns An object of all properties of the collection\n */\n getCollectionProperties(name) {\n const collectionParameters = this.collections.get(name);\n if (collectionParameters == null)\n throw new Error(`Collection with id '${name}' not found`);\n return collectionParameters;\n }\n /**\n * Adds a collection to the sync manager.\n * @param collection Collection to add\n * @param options Options for the collection. The object needs at least a `name` property.\n * @param options.name Unique name of the collection\n */\n addCollection(collection, options) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n this.collections.set(options.name, {\n collection,\n options,\n readyPromise: collection.ready(),\n syncPaused: true, // always start paused as the autostart will start it\n });\n const hasRemoteChange = (change) => {\n for (const remoteChange of this.remoteChanges) {\n if (remoteChange == null)\n continue;\n if (remoteChange.collectionName !== change.collectionName)\n continue;\n if (remoteChange.type !== change.type)\n continue;\n if (change.type === 'remove' && remoteChange.data !== change.data)\n continue;\n if (remoteChange.data.id !== change.data.id)\n continue;\n return true;\n }\n return false;\n };\n const removeRemoteChanges = (collectionName, id) => {\n const newRemoteChanges = [...this.remoteChanges];\n for (let i = 0; i < newRemoteChanges.length; i += 1) {\n const item = newRemoteChanges[i];\n if (item == null)\n continue;\n if (item.collectionName !== collectionName)\n continue;\n if (item.type === 'remove' && item.data !== id)\n continue;\n if (item.data.id !== id)\n continue;\n newRemoteChanges[i] = null;\n }\n this.remoteChanges = newRemoteChanges.filter(item => item != null);\n };\n collection.on('added', (item) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'insert', data: item })) {\n removeRemoteChanges(options.name, item.id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('changed', ({ id }, modifier) => {\n const data = { id, modifier };\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'update', data })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('removed', ({ id }) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'remove', data: id })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n if (this.options.autostart) {\n this.startSync(options.name)\n .catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n }\n }\n flushScheduledPushes() {\n this.scheduledPushes.forEach((name) => {\n this.pushChanges(name).catch(() => { });\n });\n this.scheduledPushes.clear();\n }\n schedulePush(name) {\n this.scheduledPushes.add(name);\n this.debouncedFlush();\n }\n /**\n * Setup all collections to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n */\n async startAll() {\n await Promise.all([...this.collections.keys()].map(id => this.startSync(id)));\n }\n /**\n * Setup a collection to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n * @param name Name of the collection\n */\n async startSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (!collectionParameters.syncPaused)\n return; // already started\n this.schedulePush(name); // push changes that were made while paused\n const cleanupFunction = this.options.registerRemoteChange\n ? await this.options.registerRemoteChange(collectionParameters.options, async (data) => {\n if (data == null) {\n await this.sync(name);\n }\n else {\n const syncTime = Date.now();\n const syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n await this.syncWithData(name, data)\n .then(async () => {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch(async (error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n throw error;\n });\n }\n })\n : undefined;\n this.collections.set(name, {\n ...collectionParameters,\n syncPaused: false,\n cleanupFunction,\n });\n }\n /**\n * Pauses the sync process for all collections.\n * This means that the collections will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n */\n async pauseAll() {\n await Promise.all([...this.collections.keys()].map(id => this.pauseSync(id)));\n }\n /**\n * Pauses the sync process for a collection.\n * This means that the collection will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n * @param name Name of the collection\n */\n async pauseSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (collectionParameters.syncPaused)\n return; // already paused\n if (collectionParameters.cleanupFunction)\n await collectionParameters.cleanupFunction();\n this.collections.set(name, {\n ...collectionParameters,\n cleanupFunction: undefined,\n syncPaused: true,\n });\n }\n /**\n * Starts the sync process for all collections\n */\n async syncAll() {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n const errors = [];\n await Promise.all([...this.collections.keys()].map(id => this.sync(id).catch((error) => {\n errors.push({ id, error });\n })));\n if (errors.length > 0)\n throw new Error(`Error while syncing collections:\\n${errors.map(error => `${error.id}: ${error.error.message}`).join('\\n\\n')}`);\n }\n /**\n * Checks if a collection is currently beeing synced\n * @param [name] Name of the collection. If not provided, it will check if any collection is currently beeing synced.\n * @param [async] If true, it will check for active syncs in the database. This is useful if you have multiple instances of the application running.\n * @returns True if the collection is currently beeing synced, false otherwise. If async is true, it will return a promise that resolves to true or false.\n */\n isSyncing(name, async) {\n const itemOrPromise = this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 }, async });\n if (itemOrPromise instanceof Promise) {\n return itemOrPromise\n .then(item => item != null);\n }\n return (itemOrPromise != null);\n }\n /**\n * Checks if the sync manager is ready to sync.\n * @returns A promise that resolves when the sync manager is ready to sync.\n */\n async isReady() {\n await this.collectionsReady;\n }\n /**\n * Starts the sync process for a collection\n * @param name Name of the collection\n * @param options Options for the sync process.\n * @param options.force If true, the sync process will be started even if there are no changes and onlyWithChanges is true.\n * @param options.onlyWithChanges If true, the sync process will only be started if there are changes.\n */\n async sync(name, options = {}) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n await this.isReady();\n const { options: collectionOptions, readyPromise } = this.getCollectionProperties(name);\n await readyPromise;\n const hasActiveSyncs = await this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\n async: true,\n }).count() > 0;\n const syncTime = Date.now();\n let syncId = null;\n // schedule for next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const doSync = async () => {\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n }\n const data = await this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n });\n await this.syncWithData(name, data);\n };\n await (options?.force ? doSync() : this.getSyncQueue(name).add(doSync))\n .catch(async (error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n }\n throw error;\n });\n if (syncId != null) {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n }\n }\n /**\n * Starts the push process for a collection (sync process but only if there are changes)\n * @param name Name of the collection\n */\n async pushChanges(name) {\n await this.sync(name, {\n onlyWithChanges: true,\n });\n }\n async syncWithData(name, data) {\n const { collection, options: collectionOptions } = this.getCollectionProperties(name);\n const syncTime = Date.now();\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n const lastSnapshot = await this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n async: true,\n });\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).fetch();\n await sync({\n changes: currentChanges,\n lastSnapshot: lastSnapshot?.items,\n data,\n pull: () => this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n }),\n push: changes => this.options.push(collectionOptions, {\n changes,\n rawChanges: currentChanges,\n }),\n insert: async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n },\n update: async (itemId, modifier) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: { id: itemId, ...modifier.$set },\n }, {\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n await collection.updateOne({ id: itemId }, {\n ...modifier,\n $setOnInsert: { id: itemId },\n }, { upsert: true });\n },\n remove: async (itemId) => {\n const itemExists = await collection.find({\n id: itemId,\n }, { reactive: false, async: true }).count() > 0;\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n await collection.removeOne({ id: itemId });\n },\n batch: async (fn) => {\n return collection.batch(async () => {\n await fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n await this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n await this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n await this.snapshots.insert({\n time: syncTime,\n collectionName: name,\n items: snapshot,\n });\n // delay sync operation update to next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const hasChanges = await this.changes.find({\n collectionName: name,\n }, { reactive: false, async: true }).count() > 0;\n if (hasChanges) {\n // check if there are unsynced changes to push\n // and sync again if there are any\n await this.sync(name, {\n force: true,\n onlyWithChanges: true,\n });\n return;\n }\n // if there are no unsynced changes apply the last snapshot\n // to make sure that collection and snapshot are in sync\n // find all items that are not in the snapshot\n const nonExistingItemIds = await collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n async: true,\n }).map(item => item.id);\n await collection.batch(async () => {\n // update all items that are in the snapshot\n await Promise.all(snapshot.map(async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n }));\n // remove all items that are not in the snapshot\n await Promise.all(nonExistingItemIds.map(async (id) => {\n await collection.removeOne({ id });\n }));\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","task","resolve","reject","error","computeModifiedFields","oldItem","newItem","modifiedFields","oldKeys","newKeys","allKeys","key","nestedModifiedFields","nestedField","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","itemMap","change","existingItem","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","reactivity","dataAdapter","DefaultDataAdapter","Collection","name","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChanges","collectionName","newRemoteChanges","modifier","cleanupFunction","syncTime","syncId","errors","async","itemOrPromise","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds"],"mappings":";AASA,SAAwBA,EAASC,GAAIC,GAAMC,IAAU,CAAA,GAAI;AACrD,MAAIC,GACAC;AACJ,QAAM,EAAE,SAAAC,IAAU,IAAO,UAAAC,IAAW,OAASJ;AAO7C,WAASK,KAAaC,GAAM;AACxB,UAAMC,IAAwBJ,KAAW,CAACF,GACpCO,IAAqBJ,KAAY,CAACH;AACxC,WAAIA,KACA,aAAaA,CAAO,GAExBA,IAAU,WAAW,MAAM;AACvB,MAAAA,IAAU,MACNG,KAAY,CAACG,MACbL,IAASJ,EAAG,MAAM,MAAMQ,CAAI;AAAA,IAEpC,GAAGP,CAAI,GACHQ,IACAL,IAASJ,EAAG,MAAM,MAAMQ,CAAI,IAEtBE,MACNN,IAAS,OAENA;AAAA,EACX;AACA,SAAOG;AACX;AC/BA,MAAqBI,EAAa;AAAA,EAC9B,QAAQ,CAAA;AAAA,EACR,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,IAAIC,GAAM;AACN,WAAO,IAAI,QAAQ,CAACC,GAASC,MAAW;AAEpC,WAAK,MAAM,KAAK,MAAMF,EAAA,EACjB,KAAKC,CAAO,EACZ,MAAM,CAACE,MAAU;AAClB,cAAAD,EAAOC,CAAK,GACNA;AAAA,MACV,CAAC,CAAC,GACF,KAAK,QAAA;AAAA,IACT,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB;AAChB,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAIA,UAAU;AACN,QAAI,KAAK,kBAAkB,KAAK,MAAM,WAAW;AAC7C;AAEJ,UAAMH,IAAO,KAAK,MAAM,MAAA;AACxB,IAAKA,MAEL,KAAK,iBAAiB,IACtBA,EAAA,EACK,KAAK,MAAM;AACZ,WAAK,iBAAiB,IACtB,KAAK,QAAA;AAAA,IACT,CAAC,EACI,MAAM,MAAM;AACb,WAAK,iBAAiB,IACtB,KAAK,QAAA;AAAA,IACT,CAAC;AAAA,EACL;AACJ;AClDO,SAASI,EAAsBC,GAASC,GAAS;AACpD,QAAMC,IAAiB,CAAA,GACjBC,IAAU,OAAO,KAAKH,CAAO,GAC7BI,IAAU,OAAO,KAAKH,CAAO,GAC7BI,wBAAc,IAAI,CAAC,GAAGF,GAAS,GAAGC,CAAO,CAAC;AAChD,aAAWE,KAAOD;AACd,QAAIJ,EAAQK,CAAG,MAAMN,EAAQM,CAAG;AAC5B,UAAI,OAAOL,EAAQK,CAAG,KAAM,YAAY,OAAON,EAAQM,CAAG,KAAM,YAAYL,EAAQK,CAAG,KAAK,QAAQN,EAAQM,CAAG,KAAK,MAAM;AACtH,cAAMC,IAAuBR,EAAsBC,EAAQM,CAAG,GAAGL,EAAQK,CAAG,CAAC;AAC7E,mBAAWE,KAAeD;AACtB,UAAAL,EAAe,KAAK,GAAGI,CAAG,IAAIE,CAAW,EAAE;AAAA,MAEnD;AAEI,QAAAN,EAAe,KAAKI,CAAG;AAInC,SAAOJ;AACX;AAOA,SAAwBO,EAAeC,GAAUC,GAAU;AACvD,QAAMC,IAAQ,CAAA,GACRC,IAAW,CAAA,GACXX,wBAAqB,IAAA,GACrBY,IAAU,CAAA,GACVC,IAAc,IAAI,IAAIL,EAAS,IAAI,CAAAM,MAAQ,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC,GAC3DC,IAAc,IAAI,IAAIN,EAAS,IAAI,CAAAK,MAAQ,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC;AACjE,aAAW,CAACE,GAAIlB,CAAO,KAAKe,GAAa;AACrC,UAAMd,IAAUgB,EAAY,IAAIC,CAAE;AAClC,IAAKjB,IAGKkB,EAAQlB,GAASD,CAAO,MAC9BE,EAAe,IAAID,EAAQ,IAAIF,EAAsBC,GAASC,CAAO,CAAC,GACtEY,EAAS,KAAKZ,CAAO,KAJrBa,EAAQ,KAAKd,CAAO;AAAA,EAM5B;AACA,aAAW,CAACkB,GAAIjB,CAAO,KAAKgB;AACxB,IAAKF,EAAY,IAAIG,CAAE,KACnBN,EAAM,KAAKX,CAAO;AAG1B,SAAO;AAAA,IACH,OAAAW;AAAA,IACA,UAAAC;AAAA,IACA,gBAAAX;AAAA,IACA,SAAAY;AAAA,EAAA;AAER;ACvDA,SAAwBM,EAAYC,GAAcC,GAAM;AACpD,MAAIA,EAAK,SAAS;AACd,WAAOA,EAAK;AAChB,QAAMC,IAAQF,KAAgB,CAAA;AAC9B,SAAAC,EAAK,QAAQ,MAAM,QAAQ,CAACN,MAAS;AACjC,UAAMQ,IAAQD,EAAM,UAAU,OAAKE,EAAE,OAAOT,EAAK,EAAE;AACnD,IAAIQ,MAAU,KACVD,EAAM,KAAKP,CAAI,IAGfO,EAAMC,CAAK,IAAIR;AAAA,EAEvB,CAAC,GACDM,EAAK,QAAQ,SAAS,QAAQ,CAACN,MAAS;AACpC,UAAMQ,IAAQD,EAAM,UAAU,OAAKE,EAAE,OAAOT,EAAK,EAAE;AACnD,IAAIQ,MAAU,KACVD,EAAM,KAAKP,CAAI,IAGfO,EAAMC,CAAK,IAAIR;AAAA,EAEvB,CAAC,GACDM,EAAK,QAAQ,QAAQ,QAAQ,CAACN,MAAS;AACnC,UAAMQ,IAAQD,EAAM,UAAU,OAAKE,EAAE,OAAOT,EAAK,EAAE;AACnD,IAAIQ,MAAU,MACVD,EAAM,OAAOC,GAAO,CAAC;AAAA,EAC7B,CAAC,GACMD;AACX;AC3BA,SAAwBG,EAAaH,GAAOI,GAAS;AAEjD,QAAMC,IAAU,IAAI,IAAIL,EAAM,IAAI,CAAAP,MAAQ,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC;AAC1D,SAAAW,EAAQ,QAAQ,CAACE,MAAW;AACxB,QAAIA,EAAO,SAAS;AAChB,MAAAD,EAAQ,OAAOC,EAAO,IAAI;AAAA,aAErBA,EAAO,SAAS,UAAU;AAC/B,YAAMC,IAAeF,EAAQ,IAAIC,EAAO,KAAK,EAAE;AAC/C,MAAAD,EAAQ,IAAIC,EAAO,KAAK,IAAIC,IAAe,EAAE,GAAGA,GAAc,GAAGD,EAAO,KAAA,IAASA,EAAO,IAAI;AAAA,IAChG,OACK;AACD,YAAMC,IAAeF,EAAQ,IAAIC,EAAO,KAAK,EAAE;AAC/C,MAAAD,EAAQ,IAAIC,EAAO,KAAK,IAAIC,IACtBC,EAAOD,GAAcD,EAAO,KAAK,QAAQ,IACzCE,EAAO,EAAE,IAAIF,EAAO,KAAK,MAAMA,EAAO,KAAK,QAAQ,CAAC;AAAA,IAC9D;AAAA,EACJ,CAAC,GAEM,CAAC,GAAGD,EAAQ,QAAQ;AAC/B;ACnBA,SAASI,EAAWL,GAAS;AACzB,SAAOA,EAAQ,MAAM,SAAS,KACvBA,EAAQ,SAAS,SAAS,KAC1BA,EAAQ,QAAQ,SAAS;AACpC;AAOA,SAASM,EAAcvB,GAAUC,GAAU;AACvC,SAAOqB,EAAWvB,EAAeC,GAAUC,CAAQ,CAAC;AACxD;AAgBA,eAA8BuB,EAAK,EAAE,SAAAP,GAAS,cAAAN,GAAc,MAAAC,GAAM,MAAAa,GAAM,MAAAC,GAAM,QAAAC,GAAQ,QAAAC,GAAQ,QAAAC,GAAQ,OAAAC,EAAA,GAAU;AAC5G,MAAIC,IAAUnB,GACVoB,IAAmBrB,KAAgB,CAAA,GACnCsB,IAAcvB,EAAYC,GAAcoB,CAAO;AACnD,MAAId,EAAQ,SAAS,GAAG;AAEpB,UAAMiB,IAA0BlB,EAAagB,GAAkBf,CAAO;AACtE,QAAIM,EAAcS,GAAkBE,CAAuB,GAAG;AAE1D,YAAMC,IAAyBnB,EAAaiB,GAAahB,CAAO,GAC1DmB,IAAgBrC,EAAekC,GAAaE,CAAsB;AACxE,MAAIb,EAAWc,CAAa,MAExB,MAAMV,EAAKU,CAAa,GAExBL,IAAU,MAAMN,EAAA,GAChBQ,IAAcvB,EAAYuB,GAAaF,CAAO,IAElDC,IAAmBE;AAAA,IACvB;AAAA,EACJ;AAEA,QAAMG,IAAaN,EAAQ,WAAW,OAChChC,EAAeiC,GAAkBD,EAAQ,KAAK,IAC9CA,EAAQ;AACd,eAAMD,EAAM,YAAY;AACpB,UAAM,QAAQ,IAAIO,EAAW,MAAM,IAAI,CAAA/B,MAAQqB,EAAOrB,CAAI,CAAC,CAAC,GAC5D,MAAM,QAAQ,IAAI+B,EAAW,SAAS,IAAI,CAAA/B,MAAQsB,EAAOtB,EAAK,IAAI,EAAE,MAAMA,EAAA,CAAM,CAAC,CAAC,GAClF,MAAM,QAAQ,IAAI+B,EAAW,QAAQ,IAAI,OAAQR,EAAOvB,EAAK,EAAE,CAAC,CAAC;AAAA,EACrE,CAAC,GACM2B;AACX;ACtCA,MAAqBK,EAAY;AAAA,EAC7B;AAAA,EACA,kCAAkB,IAAA;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,sCAAsB,IAAA;AAAA,EACtB,gBAAgB,CAAA;AAAA,EAChB,iCAAiB,IAAA;AAAA,EACjB;AAAA,EACA,aAAa;AAAA,EACb,aAAaC,EAAA;AAAA,EACb;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,YAAYhE,GAAS;AACjB,SAAK,UAAU;AAAA,MACX,WAAW;AAAA,MACX,GAAGA;AAAA,IAAA,GAEP,KAAK,KAAK,KAAK,QAAQ,MAAM;AAC7B,UAAM,EAAE,YAAAiE,MAAe,KAAK,SACtBC,IAAc,KAAK,QAAQ,eAAe,IAAIC,EAAA;AACpD,SAAK,UAAU,IAAIC,EAAW,GAAG,KAAK,QAAQ,EAAE,YAAYF,GAAa;AAAA,MACrE,SAAS,CAAC,gBAAgB;AAAA,MAC1B,YAAAD;AAAA,IAAA,CACH,GACD,KAAK,YAAY,IAAIG,EAAW,GAAG,KAAK,QAAQ,EAAE,cAAcF,GAAa;AAAA,MACzE,SAAS,CAAC,gBAAgB;AAAA,MAC1B,YAAAD;AAAA,IAAA,CACH,GACD,KAAK,iBAAiB,IAAIG,EAAW,GAAG,KAAK,QAAQ,EAAE,oBAAoBF,GAAa;AAAA,MACpF,SAAS,CAAC,kBAAkB,QAAQ;AAAA,MACpC,YAAAD;AAAA,IAAA,CACH,GACD,KAAK,mBAAmB,QAAQ,IAAI;AAAA,MAChC,KAAK,eAAe,QAAA;AAAA,MACpB,KAAK,QAAQ,QAAA;AAAA,MACb,KAAK,UAAU,QAAA;AAAA,IAAQ,CAC1B,EAAE,KAAK,MAAM;AAAA,IAAE,CAAC,GACjB,KAAK,QAAQ,gBAAgB,GAAI,GACjC,KAAK,UAAU,gBAAgB,GAAI,GACnC,KAAK,eAAe,gBAAgB,GAAI,GACxC,KAAK,iBAAiBpE,EAAS,KAAK,sBAAsB,KAAK,QAAQ,gBAAgB,GAAG;AAAA,EAC9F;AAAA,EACA,aAAawE,GAAM;AACf,WAAI,KAAK,WAAW,IAAIA,CAAI,KAAK,QAC7B,KAAK,WAAW,IAAIA,GAAM,IAAI5D,GAAc,GAEzC,KAAK,WAAW,IAAI4D,CAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAIA,MAAM,UAAU;AACZ,SAAK,YAAY,MAAA,GACjB,KAAK,WAAW,MAAA,GAChB,KAAK,cAAc,OAAO,CAAC,GAC3B,MAAM,QAAQ,IAAI;AAAA,MACd,KAAK,QAAQ,QAAA;AAAA,MACb,KAAK,UAAU,QAAA;AAAA,MACf,KAAK,eAAe,QAAA;AAAA,IAAQ,CAC/B,GACD,KAAK,aAAa;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAcA,GAAM;AAChB,UAAM,EAAE,YAAAC,GAAY,SAAAtE,EAAA,IAAY,KAAK,wBAAwBqE,CAAI;AACjE,WAAO,CAACC,GAAYtE,CAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAwBqE,GAAM;AAC1B,UAAME,IAAuB,KAAK,YAAY,IAAIF,CAAI;AACtD,QAAIE,KAAwB;AACxB,YAAM,IAAI,MAAM,uBAAuBF,CAAI,aAAa;AAC5D,WAAOE;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAcD,GAAYtE,GAAS;AAC/B,QAAI,KAAK;AACL,YAAM,IAAI,MAAM,yBAAyB;AAC7C,SAAK,YAAY,IAAIA,EAAQ,MAAM;AAAA,MAC/B,YAAAsE;AAAA,MACA,SAAAtE;AAAA,MACA,cAAcsE,EAAW,MAAA;AAAA,MACzB,YAAY;AAAA;AAAA,IAAA,CACf;AACD,UAAME,IAAkB,CAAC5B,MAAW;AAChC,iBAAW6B,KAAgB,KAAK;AAC5B,YAAIA,KAAgB,QAEhBA,EAAa,mBAAmB7B,EAAO,kBAEvC6B,EAAa,SAAS7B,EAAO,QAE7B,EAAAA,EAAO,SAAS,YAAY6B,EAAa,SAAS7B,EAAO,SAEzD6B,EAAa,KAAK,OAAO7B,EAAO,KAAK;AAEzC,iBAAO;AAEX,aAAO;AAAA,IACX,GACM8B,IAAsB,CAACC,GAAgB1C,MAAO;AAChD,YAAM2C,IAAmB,CAAC,GAAG,KAAK,aAAa;AAC/C,eAASpC,IAAI,GAAGA,IAAIoC,EAAiB,QAAQpC,KAAK,GAAG;AACjD,cAAMT,IAAO6C,EAAiBpC,CAAC;AAC/B,QAAIT,KAAQ,QAERA,EAAK,mBAAmB4C,MAExB5C,EAAK,SAAS,YAAYA,EAAK,SAASE,KAExCF,EAAK,KAAK,OAAOE,MAErB2C,EAAiBpC,CAAC,IAAI;AAAA,MAC1B;AACA,WAAK,gBAAgBoC,EAAiB,OAAO,CAAA7C,MAAQA,KAAQ,IAAI;AAAA,IACrE;AACA,IAAAuC,EAAW,GAAG,SAAS,CAACvC,MAAS;AAE7B,UAAIyC,EAAgB,EAAE,gBAAgBxE,EAAQ,MAAM,MAAM,UAAU,MAAM+B,EAAA,CAAM,GAAG;AAC/E,QAAA2C,EAAoB1E,EAAQ,MAAM+B,EAAK,EAAE;AACzC;AAAA,MACJ;AACA,WAAK,QAAQ,OAAO;AAAA,QAChB,gBAAgB/B,EAAQ;AAAA,QACxB,MAAM,KAAK,IAAA;AAAA,QACX,MAAM;AAAA,QACN,MAAM+B;AAAA,MAAA,CACT,EAAE,KAAK,MAAM;AACV,QAAI,KAAK,wBAAwB/B,EAAQ,IAAI,EAAE,cAE/C,KAAK,aAAaA,EAAQ,IAAI;AAAA,MAClC,CAAC,EAAE,MAAM,CAACa,MAAU;AAChB,QAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,MAClF,CAAC;AAAA,IACL,CAAC,GACDyD,EAAW,GAAG,WAAW,CAAC,EAAE,IAAArC,EAAA,GAAM4C,MAAa;AAC3C,YAAMxC,IAAO,EAAE,IAAAJ,GAAI,UAAA4C,EAAA;AAEnB,UAAIL,EAAgB,EAAE,gBAAgBxE,EAAQ,MAAM,MAAM,UAAU,MAAAqC,EAAA,CAAM,GAAG;AACzE,QAAAqC,EAAoB1E,EAAQ,MAAMiC,CAAE;AACpC;AAAA,MACJ;AACA,WAAK,QAAQ,OAAO;AAAA,QAChB,gBAAgBjC,EAAQ;AAAA,QACxB,MAAM,KAAK,IAAA;AAAA,QACX,MAAM;AAAA,QACN,MAAAqC;AAAA,MAAA,CACH,EAAE,KAAK,MAAM;AACV,QAAI,KAAK,wBAAwBrC,EAAQ,IAAI,EAAE,cAE/C,KAAK,aAAaA,EAAQ,IAAI;AAAA,MAClC,CAAC,EAAE,MAAM,CAACa,MAAU;AAChB,QAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,MAClF,CAAC;AAAA,IACL,CAAC,GACDyD,EAAW,GAAG,WAAW,CAAC,EAAE,IAAArC,QAAS;AAEjC,UAAIuC,EAAgB,EAAE,gBAAgBxE,EAAQ,MAAM,MAAM,UAAU,MAAMiC,EAAA,CAAI,GAAG;AAC7E,QAAAyC,EAAoB1E,EAAQ,MAAMiC,CAAE;AACpC;AAAA,MACJ;AACA,WAAK,QAAQ,OAAO;AAAA,QAChB,gBAAgBjC,EAAQ;AAAA,QACxB,MAAM,KAAK,IAAA;AAAA,QACX,MAAM;AAAA,QACN,MAAMiC;AAAA,MAAA,CACT,EAAE,KAAK,MAAM;AACV,QAAI,KAAK,wBAAwBjC,EAAQ,IAAI,EAAE,cAE/C,KAAK,aAAaA,EAAQ,IAAI;AAAA,MAClC,CAAC,EAAE,MAAM,CAACa,MAAU;AAChB,QAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,MAClF,CAAC;AAAA,IACL,CAAC,GACG,KAAK,QAAQ,aACb,KAAK,UAAUb,EAAQ,IAAI,EACtB,MAAM,CAACa,MAAU;AAClB,MAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,IAClF,CAAC;AAAA,EAET;AAAA,EACA,uBAAuB;AACnB,SAAK,gBAAgB,QAAQ,CAACwD,MAAS;AACnC,WAAK,YAAYA,CAAI,EAAE,MAAM,MAAM;AAAA,MAAE,CAAC;AAAA,IAC1C,CAAC,GACD,KAAK,gBAAgB,MAAA;AAAA,EACzB;AAAA,EACA,aAAaA,GAAM;AACf,SAAK,gBAAgB,IAAIA,CAAI,GAC7B,KAAK,eAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW;AACb,UAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,KAAA,CAAM,EAAE,IAAI,CAAApC,MAAM,KAAK,UAAUA,CAAE,CAAC,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAUoC,GAAM;AAClB,UAAME,IAAuB,KAAK,wBAAwBF,CAAI;AAC9D,QAAI,CAACE,EAAqB;AACtB;AACJ,SAAK,aAAaF,CAAI;AACtB,UAAMS,IAAkB,KAAK,QAAQ,uBAC/B,MAAM,KAAK,QAAQ,qBAAqBP,EAAqB,SAAS,OAAOlC,MAAS;AACpF,UAAIA,KAAQ;AACR,cAAM,KAAK,KAAKgC,CAAI;AAAA,WAEnB;AACD,cAAMU,IAAW,KAAK,IAAA,GAChBC,IAAS,MAAM,KAAK,eAAe,OAAO;AAAA,UAC5C,OAAOD;AAAA,UACP,gBAAgBV;AAAA,UAChB,YAAY,KAAK;AAAA,UACjB,QAAQ;AAAA,QAAA,CACX;AACD,cAAM,KAAK,aAAaA,GAAMhC,CAAI,EAC7B,KAAK,YAAY;AAElB,gBAAM,KAAK,eAAe,WAAW;AAAA,YACjC,IAAI,EAAE,KAAK2C,EAAA;AAAA,YACX,gBAAgBX;AAAA,YAChB,KAAK;AAAA,cACD,EAAE,KAAK,EAAE,MAAMU,IAAS;AAAA,cACxB,EAAE,QAAQ,SAAA;AAAA,YAAS;AAAA,UACvB,CACH,GAED,MAAM,KAAK,eAAe,UAAU,EAAE,IAAIC,KAAU;AAAA,YAChD,MAAM,EAAE,QAAQ,QAAQ,KAAK,KAAK,MAAI;AAAA,UAAE,CAC3C;AAAA,QACL,CAAC,EACI,MAAM,OAAOnE,MAAU;AACxB,gBAAI,KAAK,QAAQ,WACb,KAAK,QAAQ,QAAQ,KAAK,wBAAwBwD,CAAI,EAAE,SAASxD,CAAK,GAE1E,MAAM,KAAK,eAAe,UAAU,EAAE,IAAImE,KAAU;AAAA,YAChD,MAAM,EAAE,QAAQ,SAAS,KAAK,KAAK,IAAA,GAAO,OAAOnE,EAAM,SAASA,EAAM,QAAA;AAAA,UAAQ,CACjF,GACKA;AAAA,QACV,CAAC;AAAA,MACL;AAAA,IACJ,CAAC,IACC;AACN,SAAK,YAAY,IAAIwD,GAAM;AAAA,MACvB,GAAGE;AAAA,MACH,YAAY;AAAA,MACZ,iBAAAO;AAAA,IAAA,CACH;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW;AACb,UAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,KAAA,CAAM,EAAE,IAAI,CAAA7C,MAAM,KAAK,UAAUA,CAAE,CAAC,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAUoC,GAAM;AAClB,UAAME,IAAuB,KAAK,wBAAwBF,CAAI;AAC9D,IAAIE,EAAqB,eAErBA,EAAqB,mBACrB,MAAMA,EAAqB,gBAAA,GAC/B,KAAK,YAAY,IAAIF,GAAM;AAAA,MACvB,GAAGE;AAAA,MACH,iBAAiB;AAAA,MACjB,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAIA,MAAM,UAAU;AACZ,QAAI,KAAK;AACL,YAAM,IAAI,MAAM,yBAAyB;AAC7C,UAAMU,IAAS,CAAA;AAIf,QAHA,MAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,MAAM,EAAE,IAAI,OAAM,KAAK,KAAKhD,CAAE,EAAE,MAAM,CAACpB,MAAU;AACpF,MAAAoE,EAAO,KAAK,EAAE,IAAAhD,GAAI,OAAApB,EAAA,CAAO;AAAA,IAC7B,CAAC,CAAC,CAAC,GACCoE,EAAO,SAAS;AAChB,YAAM,IAAI,MAAM;AAAA,EAAqCA,EAAO,IAAI,CAAApE,MAAS,GAAGA,EAAM,EAAE,KAAKA,EAAM,MAAM,OAAO,EAAE,EAAE,KAAK;AAAA;AAAA,CAAM,CAAC,EAAE;AAAA,EACtI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUwD,GAAMa,GAAO;AACnB,UAAMC,IAAgB,KAAK,eAAe,QAAQ;AAAA,MAC9C,GAAGd,IAAO,EAAE,gBAAgBA,EAAA,IAAS,CAAA;AAAA,MACrC,QAAQ;AAAA,IAAA,GACT,EAAE,QAAQ,EAAE,QAAQ,EAAA,GAAK,OAAAa,GAAO;AACnC,WAAIC,aAAyB,UAClBA,EACF,KAAK,CAAApD,MAAQA,KAAQ,IAAI,IAE1BoD,KAAiB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU;AACZ,UAAM,KAAK;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAKd,GAAMrE,IAAU,IAAI;AAC3B,QAAI,KAAK;AACL,YAAM,IAAI,MAAM,yBAAyB;AAC7C,UAAM,KAAK,QAAA;AACX,UAAM,EAAE,SAASoF,GAAmB,cAAAC,MAAiB,KAAK,wBAAwBhB,CAAI;AACtF,UAAMgB;AACN,UAAMC,IAAiB,MAAM,KAAK,eAAe,KAAK;AAAA,MAClD,gBAAgBjB;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,QAAQ;AAAA,IAAA,GACT;AAAA,MACC,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,EAAE,MAAA,IAAU,GACPU,IAAW,KAAK,IAAA;AACtB,QAAIC,IAAS;AAEb,UAAM,IAAI,QAAQ,CAACrE,MAAY;AAC3B,iBAAWA,GAAS,CAAC;AAAA,IACzB,CAAC;AACD,UAAM4E,IAAS,YAAY;AACvB,YAAMC,IAAmB,MAAM,KAAK,eAAe,QAAQ;AAAA,QACvD,gBAAgBnB;AAAA,QAChB,QAAQ;AAAA,MAAA,GACT;AAAA,QACC,MAAM,EAAE,KAAK,GAAA;AAAA,QACb,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACV;AACD,UAAIrE,GAAS,mBACc,MAAM,KAAK,QAAQ,KAAK;AAAA,QAC3C,gBAAgBqE;AAAA,QAChB,MAAM,EAAE,MAAMU,EAAA;AAAA,MAAS,GACxB;AAAA,QACC,MAAM,EAAE,MAAM,EAAA;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACV,EAAE,MAAA,MACoB;AACnB;AAER,MAAKO,MACDN,IAAS,MAAM,KAAK,eAAe,OAAO;AAAA,QACtC,OAAOD;AAAA,QACP,gBAAgBV;AAAA,QAChB,YAAY,KAAK;AAAA,QACjB,QAAQ;AAAA,MAAA,CACX;AAEL,YAAMhC,IAAO,MAAM,KAAK,QAAQ,KAAK+C,GAAmB;AAAA,QACpD,uBAAuBI,GAAkB;AAAA,QACzC,qBAAqBA,GAAkB;AAAA,MAAA,CAC1C;AACD,YAAM,KAAK,aAAanB,GAAMhC,CAAI;AAAA,IACtC;AACA,WAAOrC,GAAS,QAAQuF,EAAA,IAAW,KAAK,aAAalB,CAAI,EAAE,IAAIkB,CAAM,GAChE,MAAM,OAAO1E,MAAU;AACxB,YAAImE,KAAU,SACN,KAAK,QAAQ,WACb,KAAK,QAAQ,QAAQI,GAAmBvE,CAAK,GACjD,MAAM,KAAK,eAAe,UAAU,EAAE,IAAImE,KAAU;AAAA,QAChD,MAAM,EAAE,QAAQ,SAAS,KAAK,KAAK,IAAA,GAAO,OAAOnE,EAAM,SAASA,EAAM,QAAA;AAAA,MAAQ,CACjF,IAECA;AAAA,IACV,CAAC,GACGmE,KAAU,SAEV,MAAM,KAAK,eAAe,WAAW;AAAA,MACjC,IAAI,EAAE,KAAKA,EAAA;AAAA,MACX,gBAAgBX;AAAA,MAChB,KAAK;AAAA,QACD,EAAE,KAAK,EAAE,MAAMU,IAAS;AAAA,QACxB,EAAE,QAAQ,SAAA;AAAA,MAAS;AAAA,IACvB,CACH,GAED,MAAM,KAAK,eAAe,UAAU,EAAE,IAAIC,KAAU;AAAA,MAChD,MAAM,EAAE,QAAQ,QAAQ,KAAK,KAAK,MAAI;AAAA,IAAE,CAC3C;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAYX,GAAM;AACpB,UAAM,KAAK,KAAKA,GAAM;AAAA,MAClB,iBAAiB;AAAA,IAAA,CACpB;AAAA,EACL;AAAA,EACA,MAAM,aAAaA,GAAMhC,GAAM;AAC3B,UAAM,EAAE,YAAAiC,GAAY,SAASc,MAAsB,KAAK,wBAAwBf,CAAI,GAC9EU,IAAW,KAAK,IAAA,GAChBS,IAAmB,MAAM,KAAK,eAAe,QAAQ;AAAA,MACvD,gBAAgBnB;AAAA,MAChB,QAAQ;AAAA,IAAA,GACT;AAAA,MACC,MAAM,EAAE,KAAK,GAAA;AAAA,MACb,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,GACKjC,IAAe,MAAM,KAAK,UAAU,QAAQ;AAAA,MAC9C,gBAAgBiC;AAAA,IAAA,GACjB;AAAA,MACC,MAAM,EAAE,MAAM,GAAA;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,GACKoB,IAAiB,MAAM,KAAK,QAAQ,KAAK;AAAA,MAC3C,gBAAgBpB;AAAA,MAChB,MAAM,EAAE,MAAMU,EAAA;AAAA,IAAS,GACxB;AAAA,MACC,MAAM,EAAE,MAAM,EAAA;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,EAAE,MAAA;AACH,UAAM9B,EAAK;AAAA,MACP,SAASwC;AAAA,MACT,cAAcrD,GAAc;AAAA,MAC5B,MAAAC;AAAA,MACA,MAAM,MAAM,KAAK,QAAQ,KAAK+C,GAAmB;AAAA,QAC7C,uBAAuBI,GAAkB;AAAA,QACzC,qBAAqBA,GAAkB;AAAA,MAAA,CAC1C;AAAA,MACD,MAAM,CAAA9C,MAAW,KAAK,QAAQ,KAAK0C,GAAmB;AAAA,QAClD,SAAA1C;AAAA,QACA,YAAY+C;AAAA,MAAA,CACf;AAAA,MACD,QAAQ,OAAO1D,MAAS;AAEpB,aAAK,cAAc,KAAK;AAAA,UACpB,gBAAgBsC;AAAA,UAChB,MAAM;AAAA,UACN,MAAMtC;AAAA,QAAA,GACP;AAAA,UACC,gBAAgBsC;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,EAAE,IAAItC,EAAK,IAAI,UAAU,EAAE,MAAMA,EAAA,EAAK;AAAA,QAAE,CACjD,GAED,MAAMuC,EAAW,WAAW,EAAE,IAAIvC,EAAK,GAAA,GAAMA,GAAM,EAAE,QAAQ,IAAM;AAAA,MACvE;AAAA,MACA,QAAQ,OAAO2D,GAAQb,MAAa;AAEhC,aAAK,cAAc,KAAK;AAAA,UACpB,gBAAgBR;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,EAAE,IAAIqB,GAAQ,GAAGb,EAAS,KAAA;AAAA,QAAK,GACtC;AAAA,UACC,gBAAgBR;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,EAAE,IAAIqB,GAAQ,UAAAb,EAAA;AAAA,QAAS,CAChC,GACD,MAAMP,EAAW,UAAU,EAAE,IAAIoB,KAAU;AAAA,UACvC,GAAGb;AAAA,UACH,cAAc,EAAE,IAAIa,EAAA;AAAA,QAAO,GAC5B,EAAE,QAAQ,IAAM;AAAA,MACvB;AAAA,MACA,QAAQ,OAAOA,MAAW;AAItB,QAHmB,MAAMpB,EAAW,KAAK;AAAA,UACrC,IAAIoB;AAAA,QAAA,GACL,EAAE,UAAU,IAAO,OAAO,IAAM,EAAE,MAAA,IAAU,MAG/C,KAAK,cAAc,KAAK;AAAA,UACpB,gBAAgBrB;AAAA,UAChB,MAAM;AAAA,UACN,MAAMqB;AAAA,QAAA,CACT,GACD,MAAMpB,EAAW,UAAU,EAAE,IAAIoB,GAAQ;AAAA,MAC7C;AAAA,MACA,OAAO,OAAO5F,MACHwE,EAAW,MAAM,YAAY;AAChC,cAAMxE,EAAA;AAAA,MACV,CAAC;AAAA,IACL,CACH,EACI,KAAK,OAAO6F,MAAa;AAwB1B,UAtBA,MAAM,KAAK,UAAU,WAAW;AAAA,QAC5B,gBAAgBtB;AAAA,QAChB,MAAM,EAAE,MAAMU,EAAA;AAAA,MAAS,CAC1B,GAED,MAAM,KAAK,QAAQ,WAAW;AAAA,QAC1B,gBAAgBV;AAAA,QAChB,IAAI,EAAE,KAAKoB,EAAe,IAAI,CAAAG,MAAKA,EAAE,EAAE,EAAA;AAAA,MAAE,CAC5C,GAED,MAAM,KAAK,UAAU,OAAO;AAAA,QACxB,MAAMb;AAAA,QACN,gBAAgBV;AAAA,QAChB,OAAOsB;AAAA,MAAA,CACV,GAED,MAAM,IAAI,QAAQ,CAAChF,MAAY;AAC3B,mBAAWA,GAAS,CAAC;AAAA,MACzB,CAAC,GACkB,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,gBAAgB0D;AAAA,MAAA,GACjB,EAAE,UAAU,IAAO,OAAO,IAAM,EAAE,MAAA,IAAU,GAC/B;AAGZ,cAAM,KAAK,KAAKA,GAAM;AAAA,UAClB,OAAO;AAAA,UACP,iBAAiB;AAAA,QAAA,CACpB;AACD;AAAA,MACJ;AAIA,YAAMwB,IAAqB,MAAMvB,EAAW,KAAK;AAAA,QAC7C,IAAI,EAAE,MAAMqB,EAAS,IAAI,CAAA5D,MAAQA,EAAK,EAAE,EAAA;AAAA,MAAE,GAC3C;AAAA,QACC,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACV,EAAE,IAAI,CAAAA,MAAQA,EAAK,EAAE;AACtB,YAAMuC,EAAW,MAAM,YAAY;AAE/B,cAAM,QAAQ,IAAIqB,EAAS,IAAI,OAAO5D,MAAS;AAE3C,eAAK,cAAc,KAAK;AAAA,YACpB,gBAAgBsC;AAAA,YAChB,MAAM;AAAA,YACN,MAAMtC;AAAA,UAAA,GACP;AAAA,YACC,gBAAgBsC;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,EAAE,IAAItC,EAAK,IAAI,UAAU,EAAE,MAAMA,EAAA,EAAK;AAAA,UAAE,CACjD,GAED,MAAMuC,EAAW,WAAW,EAAE,IAAIvC,EAAK,GAAA,GAAMA,GAAM,EAAE,QAAQ,IAAM;AAAA,QACvE,CAAC,CAAC,GAEF,MAAM,QAAQ,IAAI8D,EAAmB,IAAI,OAAO5D,MAAO;AACnD,gBAAMqC,EAAW,UAAU,EAAE,IAAArC,GAAI;AAAA,QACrC,CAAC,CAAC;AAAA,MACN,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AACJ;"}
1
+ {"version":3,"file":"index.mjs","sources":["../src/utils/debounce.ts","../src/utils/PromiseQueue.ts","../src/computeChanges.ts","../src/getSnapshot.ts","../src/applyChanges.ts","../src/sync.ts","../src/SyncManager.ts"],"sourcesContent":["/**\n * Debounces a function.\n * @param fn Function to debounce\n * @param wait Time to wait before calling the function.\n * @param [options] Debounce options\n * @param [options.leading] Whether to call the function on the leading edge of the wait interval.\n * @param [options.trailing] Whether to call the function on the trailing edge of the wait interval.\n * @returns The debounced function.\n */\nexport default function debounce(fn, wait, options = {}) {\n let timeout;\n let result;\n const { leading = false, trailing = true } = options;\n /**\n * The debounced function that will be returned.\n * @param this The context to bind the function to.\n * @param args The arguments to pass to the function.\n * @returns The result of the debounced function.\n */\n function debounced(...args) {\n const shouldCallImmediately = leading && !timeout;\n const shouldCallTrailing = trailing && !timeout;\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(() => {\n timeout = null;\n if (trailing && !shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n }, wait);\n if (shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n else if (!shouldCallTrailing) {\n result = null;\n }\n return result;\n }\n return debounced;\n}\n","/**\n * Class for queuing promises to be executed one after the other.\n * This is useful for tasks that should not be executed in parallel.\n * @example\n * const queue = new PromiseQueue();\n * queue.add(() => fetch('https://example.com/api/endpoint1'));\n * queue.add(() => fetch('https://example.com/api/endpoint2'));\n * // The second fetch will only be executed after the first one is done.\n */\nexport default class PromiseQueue {\n queue = [];\n pendingPromise = false;\n /**\n * Method to add a new promise to the queue and returns a promise that resolves when this task is done\n * @param task Function that returns a promise that will be added to the queue\n * @returns Promise that resolves when the task is done\n */\n add(task) {\n return new Promise((resolve, reject) => {\n // Wrap the task with the resolve and reject to control its completion from the outside\n this.queue.push(() => task()\n .then(resolve)\n .catch((error) => {\n reject(error);\n throw error;\n }));\n this.dequeue();\n });\n }\n /**\n * Method to check if there is a pending promise in the queue\n * @returns True if there is a pending promise, false otherwise\n */\n hasPendingPromise() {\n return this.pendingPromise;\n }\n /**\n * Method to process the queue\n */\n dequeue() {\n if (this.pendingPromise || this.queue.length === 0) {\n return;\n }\n const task = this.queue.shift();\n if (!task)\n return;\n this.pendingPromise = true;\n task()\n .then(() => {\n this.pendingPromise = false;\n this.dequeue();\n })\n .catch(() => {\n this.pendingPromise = false;\n this.dequeue();\n });\n }\n}\n","import { isEqual } from '@signaldb/core';\n/**\n * Computes the modified fields between two items recursively.\n * @param oldItem The old item\n * @param newItem The new item\n * @returns The modified fields\n */\nexport function computeModifiedFields(oldItem, newItem) {\n const modifiedFields = [];\n const oldKeys = Object.keys(oldItem);\n const newKeys = Object.keys(newItem);\n const allKeys = new Set([...oldKeys, ...newKeys]);\n for (const key of allKeys) {\n if (newItem[key] !== oldItem[key]) {\n if (typeof newItem[key] === 'object' && typeof oldItem[key] === 'object' && newItem[key] != null && oldItem[key] != null) {\n const nestedModifiedFields = computeModifiedFields(oldItem[key], newItem[key]);\n for (const nestedField of nestedModifiedFields) {\n modifiedFields.push(`${key}.${nestedField}`);\n }\n }\n else {\n modifiedFields.push(key);\n }\n }\n }\n return modifiedFields;\n}\n/**\n * Compute changes between two arrays of items.\n * @param oldItems Array of the old items\n * @param newItems Array of the new items\n * @returns The changeset\n */\nexport default function computeChanges(oldItems, newItems) {\n const added = [];\n const modified = [];\n const modifiedFields = new Map();\n const removed = [];\n const oldItemsMap = new Map(oldItems.map(item => [item.id, item]));\n const newItemsMap = new Map(newItems.map(item => [item.id, item]));\n for (const [id, oldItem] of oldItemsMap) {\n const newItem = newItemsMap.get(id);\n if (!newItem) {\n removed.push(oldItem);\n }\n else if (!isEqual(newItem, oldItem)) {\n modifiedFields.set(newItem.id, computeModifiedFields(oldItem, newItem));\n modified.push(newItem);\n }\n }\n for (const [id, newItem] of newItemsMap) {\n if (!oldItemsMap.has(id)) {\n added.push(newItem);\n }\n }\n return {\n added,\n modified,\n modifiedFields,\n removed,\n };\n}\n","/**\n * Gets the snapshot of items from the last snapshot and the changes.\n * @param lastSnapshot The last snapshot of items\n * @param data The changes to apply to the last snapshot\n * @returns The new snapshot of items\n */\nexport default function getSnapshot(lastSnapshot, data) {\n if (data.items != null)\n return data.items;\n const items = lastSnapshot || [];\n data.changes.added.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.modified.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.removed.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index !== -1)\n items.splice(index, 1);\n });\n return items;\n}\n","import { modify } from '@signaldb/core';\n/**\n * applies changes to a collection of items\n * @param items The items to apply the changes to\n * @param changes The changes to apply to the items\n * @returns The new items after applying the changes\n */\nexport default function applyChanges(items, changes) {\n // Create initial map of items by ID\n const itemMap = new Map(items.map(item => [item.id, item]));\n changes.forEach((change) => {\n if (change.type === 'remove') {\n itemMap.delete(change.data);\n }\n else if (change.type === 'insert') {\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem ? { ...existingItem, ...change.data } : change.data);\n }\n else { // change.type === 'update'\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem\n ? modify(existingItem, change.data.modifier)\n : modify({ id: change.data.id }, change.data.modifier));\n }\n });\n // Convert map back to array\n return [...itemMap.values()];\n}\n","import computeChanges from './computeChanges';\nimport getSnapshot from './getSnapshot';\nimport applyChanges from './applyChanges';\n/**\n * Checks if there are any changes in the given changeset.\n * @param changes The changeset to check.\n * @returns True if there are changes, false otherwise.\n */\nfunction hasChanges(changes) {\n return changes.added.length > 0\n || changes.modified.length > 0\n || changes.removed.length > 0;\n}\n/**\n * Checks if there is a difference between the old items and the new items.\n * @param oldItems The old items.\n * @param newItems The new items.\n * @returns True if there is a difference, false otherwise.\n */\nfunction hasDifference(oldItems, newItems) {\n return hasChanges(computeChanges(oldItems, newItems));\n}\n/**\n * Does a sync operation based on the provided options. If changes are supplied, these will be rebased on the new data.\n * Afterwards the push method will be called with the remaining changes. A new snapshot will be created and returned.\n * @param options Sync options\n * @param options.changes Changes to call the push method with\n * @param [options.lastSnapshot] The last snapshot\n * @param options.data The new data\n * @param options.pull Method to pull new data\n * @param options.push Method to push changes\n * @param options.insert Method to insert an item\n * @param options.update Method to update an item\n * @param options.remove Method to remove an item\n * @param options.batch Method to batch multiple operations\n * @returns The new snapshot\n */\nexport default async function sync({ changes, lastSnapshot, data, pull, push, insert, update, remove, batch, }) {\n let newData = data;\n let previousSnapshot = lastSnapshot || [];\n let newSnapshot = getSnapshot(lastSnapshot, newData);\n if (changes.length > 0) {\n // apply changes on last snapshot and check if there is a difference\n const lastSnapshotWithChanges = applyChanges(previousSnapshot, changes);\n if (hasDifference(previousSnapshot, lastSnapshotWithChanges)) {\n // if yes, apply the changes on the newSnapshot and check if there is a difference\n const newSnapshotWithChanges = applyChanges(newSnapshot, changes);\n const changesToPush = computeChanges(newSnapshot, newSnapshotWithChanges);\n if (hasChanges(changesToPush)) {\n // if yes, push the changes to the server\n await push(changesToPush);\n // pull new data afterwards to ensure that all server changes are applied\n newData = await pull();\n newSnapshot = getSnapshot(newSnapshot, newData);\n }\n previousSnapshot = lastSnapshotWithChanges;\n }\n }\n // apply the new changes on the collection\n const newChanges = newData.changes == null\n ? computeChanges(previousSnapshot, newData.items)\n : newData.changes;\n await batch(async () => {\n await Promise.all(newChanges.added.map(item => insert(item)));\n await Promise.all(newChanges.modified.map(item => update(item.id, { $set: item })));\n await Promise.all(newChanges.removed.map(item => remove(item.id)));\n });\n return newSnapshot;\n}\n","import { DefaultDataAdapter, Collection, randomId } from '@signaldb/core';\nimport debounce from './utils/debounce';\nimport PromiseQueue from './utils/PromiseQueue';\nimport sync from './sync';\n/**\n * Class to manage syncing of collections.\n * @template CollectionOptions\n * @template ItemType\n * @template IdType\n * @example\n * const syncManager = new SyncManager({\n * pull: async (collectionOptions) => {\n * const response = await fetch(`/api/collections/${collectionOptions.name}`)\n * return await response.json()\n * },\n * push: async (collectionOptions, { changes }) => {\n * await fetch(`/api/collections/${collectionOptions.name}`, {\n * method: 'POST',\n * body: JSON.stringify(changes),\n * })\n * },\n * })\n *\n * const collection = new Collection()\n * syncManager.addCollection(collection, {\n * name: 'todos',\n * })\n *\n * syncManager.sync('todos')\n */\nexport default class SyncManager {\n options;\n collections = new Map();\n changes;\n snapshots;\n syncOperations;\n scheduledPushes = new Set();\n remoteChanges = [];\n syncQueues = new Map();\n collectionsReady;\n isDisposed = false;\n instanceId = randomId();\n id;\n debouncedFlush;\n /**\n * @param options Collection options\n * @param options.pull Function to pull data from remote source.\n * @param options.push Function to push data to remote source.\n * @param [options.registerRemoteChange] Function to register a callback for remote changes.\n * @param [options.id] Unique identifier for this sync manager. Only nessesary if you have multiple sync managers.\n * @param [options.storageAdapter] Storage adapter to use for storing changes, snapshots and sync operations.\n * @param [options.reactivity] Reactivity adapter to use for reactivity.\n * @param [options.onError] Function to handle errors that occur async during syncing.\n * @param [options.autostart] Whether to automatically start syncing new collections.\n * @param [options.debounceTime] The time in milliseconds to debounce push operations.\n */\n constructor(options) {\n this.options = {\n autostart: true,\n ...options,\n };\n this.id = this.options.id || 'default-sync-manager';\n const { reactivity } = this.options;\n const dataAdapter = this.options.dataAdapter ?? new DefaultDataAdapter();\n this.changes = new Collection(`${this.options.id}-changes`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.snapshots = new Collection(`${this.options.id}-snapshots`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.syncOperations = new Collection(`${this.options.id}-sync-operations`, dataAdapter, {\n indices: ['collectionName', 'status'],\n reactivity,\n });\n const readiness = [\n Promise.resolve(this.syncOperations.isReady()),\n Promise.resolve(this.changes.isReady()),\n Promise.resolve(this.snapshots.isReady()),\n ];\n this.collectionsReady = Promise.all(readiness).then(() => { });\n this.changes.setMaxListeners(1000);\n this.snapshots.setMaxListeners(1000);\n this.syncOperations.setMaxListeners(1000);\n this.debouncedFlush = debounce(this.flushScheduledPushes, this.options.debounceTime ?? 100);\n }\n getSyncQueue(name) {\n if (this.syncQueues.get(name) == null) {\n this.syncQueues.set(name, new PromiseQueue());\n }\n return this.syncQueues.get(name);\n }\n /**\n * Clears all internal data structures\n */\n async dispose() {\n this.collections.clear();\n this.syncQueues.clear();\n this.remoteChanges.splice(0);\n await Promise.all([\n this.changes.dispose(),\n this.snapshots.dispose(),\n this.syncOperations.dispose(),\n ]);\n this.isDisposed = true;\n }\n /**\n * Gets a collection with it's options by name\n * @deprecated Use getCollectionProperties instead.\n * @param name Name of the collection\n * @throws {Error} Will throw an error if the name wasn't found\n * @returns Tuple of collection and options\n */\n getCollection(name) {\n const { collection, options } = this.getCollectionProperties(name);\n return [collection, options];\n }\n /**\n * Gets collection options by name\n * @param name Name of the collection\n * @throws {Error} Will throw an error if the name wasn't found\n * @returns An object of all properties of the collection\n */\n getCollectionProperties(name) {\n const collectionParameters = this.collections.get(name);\n if (collectionParameters == null)\n throw new Error(`Collection with id '${name}' not found`);\n return collectionParameters;\n }\n /**\n * Adds a collection to the sync manager.\n * @param collection Collection to add\n * @param options Options for the collection. The object needs at least a `name` property.\n * @param options.name Unique name of the collection\n */\n addCollection(collection, options) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n this.collections.set(options.name, {\n collection: collection,\n options,\n readyPromise: collection.ready(),\n syncPaused: true, // always start paused as the autostart will start it\n });\n const hasRemoteChange = (change) => {\n for (const remoteChange of this.remoteChanges) {\n if (remoteChange == null)\n continue;\n if (remoteChange.collectionName !== change.collectionName)\n continue;\n if (remoteChange.type !== change.type)\n continue;\n if (change.type === 'remove' && remoteChange.data !== change.data)\n continue;\n if (remoteChange.data.id !== change.data.id)\n continue;\n return true;\n }\n return false;\n };\n const removeRemoteChanges = (collectionName, id) => {\n const newRemoteChanges = [...this.remoteChanges];\n for (let i = 0; i < newRemoteChanges.length; i += 1) {\n const item = newRemoteChanges[i];\n if (item == null)\n continue;\n if (item.collectionName !== collectionName)\n continue;\n if (item.type === 'remove' && item.data !== id)\n continue;\n if (item.data.id !== id)\n continue;\n newRemoteChanges[i] = null;\n }\n this.remoteChanges = newRemoteChanges.filter(item => item != null);\n };\n collection.on('added', (item) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'insert', data: item })) {\n removeRemoteChanges(options.name, item.id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('changed', ({ id }, modifier) => {\n const data = { id, modifier };\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'update', data })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('removed', ({ id }) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'remove', data: id })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n if (this.options.autostart) {\n this.startSync(options.name)\n .catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n }\n }\n flushScheduledPushes() {\n this.scheduledPushes.forEach((name) => {\n this.pushChanges(name).catch(() => { });\n });\n this.scheduledPushes.clear();\n }\n schedulePush(name) {\n this.scheduledPushes.add(name);\n this.debouncedFlush();\n }\n /**\n * Setup all collections to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n */\n async startAll() {\n await Promise.all([...this.collections.keys()].map(id => this.startSync(id)));\n }\n /**\n * Setup a collection to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n * @param name Name of the collection\n */\n async startSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (!collectionParameters.syncPaused)\n return; // already started\n this.schedulePush(name); // push changes that were made while paused\n const cleanupFunction = this.options.registerRemoteChange\n ? await this.options.registerRemoteChange(collectionParameters.options, async (data) => {\n await (data == null\n ? this.sync(name)\n : this.getSyncQueue(name).add(async () => {\n const syncTime = Date.now();\n const syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n await this.syncWithData(name, data)\n .then(async () => {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch(async (error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n throw error;\n });\n }));\n })\n : undefined;\n this.collections.set(name, {\n ...collectionParameters,\n syncPaused: false,\n cleanupFunction,\n });\n }\n /**\n * Pauses the sync process for all collections.\n * This means that the collections will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n */\n async pauseAll() {\n await Promise.all([...this.collections.keys()].map(id => this.pauseSync(id)));\n }\n /**\n * Pauses the sync process for a collection.\n * This means that the collection will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n * @param name Name of the collection\n */\n async pauseSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (collectionParameters.syncPaused)\n return; // already paused\n if (collectionParameters.cleanupFunction)\n await collectionParameters.cleanupFunction();\n this.collections.set(name, {\n ...collectionParameters,\n cleanupFunction: undefined,\n syncPaused: true,\n });\n }\n /**\n * Starts the sync process for all collections\n */\n async syncAll() {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n const errors = [];\n await Promise.all([...this.collections.keys()].map(id => this.sync(id).catch((error) => {\n errors.push({ id, error });\n })));\n if (errors.length > 0)\n throw new Error(`Error while syncing collections:\\n${errors.map(error => `${error.id}: ${error.error.message}`).join('\\n\\n')}`);\n }\n /**\n * Checks if a collection is currently beeing synced\n * @param [name] Name of the collection. If not provided, it will check if any collection is currently beeing synced.\n * @param [async] If true, it will check for active syncs in the database. This is useful if you have multiple instances of the application running.\n * @returns True if the collection is currently beeing synced, false otherwise. If async is true, it will return a promise that resolves to true or false.\n */\n isSyncing(name, async) {\n const itemOrPromise = this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 }, async });\n if (itemOrPromise instanceof Promise) {\n return itemOrPromise\n .then(item => item != null);\n }\n return (itemOrPromise != null);\n }\n /**\n * Checks if the sync manager is ready to sync.\n * @returns A promise that resolves when the sync manager is ready to sync.\n */\n async isReady() {\n await this.collectionsReady;\n }\n /**\n * Starts the sync process for a collection\n * @param name Name of the collection\n * @param options Options for the sync process.\n * @param options.force If true, the sync process will be started even if there are no changes and onlyWithChanges is true.\n * @param options.onlyWithChanges If true, the sync process will only be started if there are changes.\n */\n async sync(name, options = {}) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n await this.isReady();\n const { options: collectionOptions, readyPromise } = this.getCollectionProperties(name);\n await readyPromise;\n const hasActiveSyncs = await this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\n async: true,\n }).count() > 0;\n const syncTime = Date.now();\n let syncId = null;\n // schedule for next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const doSync = async () => {\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n }\n const data = await this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n });\n await this.syncWithData(name, data);\n };\n await (options?.force ? doSync() : this.getSyncQueue(name).add(doSync))\n .catch(async (error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n }\n throw error;\n });\n if (syncId != null) {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n }\n }\n /**\n * Starts the push process for a collection (sync process but only if there are changes)\n * @param name Name of the collection\n */\n async pushChanges(name) {\n await this.sync(name, {\n onlyWithChanges: true,\n });\n }\n async syncWithData(name, data) {\n const { collection, options: collectionOptions } = this.getCollectionProperties(name);\n const syncTime = Date.now();\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n const lastSnapshot = await this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n async: true,\n });\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).fetch();\n await sync({\n changes: currentChanges,\n lastSnapshot: lastSnapshot?.items,\n data,\n pull: () => this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n }),\n push: changes => this.options.push(collectionOptions, {\n changes,\n rawChanges: currentChanges,\n }),\n insert: async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n },\n update: async (itemId, modifier) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: { id: itemId, ...modifier.$set },\n }, {\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n await collection.updateOne({ id: itemId }, {\n ...modifier,\n $setOnInsert: { id: itemId },\n }, { upsert: true });\n },\n remove: async (itemId) => {\n const itemExists = await collection.find({\n id: itemId,\n }, { reactive: false, async: true }).count() > 0;\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n await collection.removeOne({ id: itemId });\n },\n batch: async (fn) => {\n return collection.batch(async () => {\n await fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n await this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n await this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n await this.snapshots.insert({\n time: syncTime,\n collectionName: name,\n items: snapshot,\n });\n // delay sync operation update to next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const hasChanges = await this.changes.find({\n collectionName: name,\n }, { reactive: false, async: true }).count() > 0;\n if (hasChanges) {\n // check if there are unsynced changes to push\n // and sync again if there are any\n await this.sync(name, {\n force: true,\n onlyWithChanges: true,\n });\n return;\n }\n // if there are no unsynced changes apply the last snapshot\n // to make sure that collection and snapshot are in sync\n // find all items that are not in the snapshot\n const nonExistingItemIds = await collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n async: true,\n }).map(item => item.id);\n await collection.batch(async () => {\n // update all items that are in the snapshot\n await Promise.all(snapshot.map(async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n }));\n // remove all items that are not in the snapshot\n await Promise.all(nonExistingItemIds.map(async (id) => {\n await collection.removeOne({ id });\n }));\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","task","resolve","reject","error","computeModifiedFields","oldItem","newItem","modifiedFields","oldKeys","newKeys","allKeys","key","nestedModifiedFields","nestedField","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","itemMap","change","existingItem","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","reactivity","dataAdapter","DefaultDataAdapter","Collection","readiness","name","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChanges","collectionName","newRemoteChanges","modifier","cleanupFunction","syncTime","syncId","errors","async","itemOrPromise","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds"],"mappings":";AASA,SAAwBA,EAASC,GAAIC,GAAMC,IAAU,CAAA,GAAI;AACrD,MAAIC,GACAC;AACJ,QAAM,EAAE,SAAAC,IAAU,IAAO,UAAAC,IAAW,OAASJ;AAO7C,WAASK,KAAaC,GAAM;AACxB,UAAMC,IAAwBJ,KAAW,CAACF,GACpCO,IAAqBJ,KAAY,CAACH;AACxC,WAAIA,KACA,aAAaA,CAAO,GAExBA,IAAU,WAAW,MAAM;AACvB,MAAAA,IAAU,MACNG,KAAY,CAACG,MACbL,IAASJ,EAAG,MAAM,MAAMQ,CAAI;AAAA,IAEpC,GAAGP,CAAI,GACHQ,IACAL,IAASJ,EAAG,MAAM,MAAMQ,CAAI,IAEtBE,MACNN,IAAS,OAENA;AAAA,EACX;AACA,SAAOG;AACX;AC/BA,MAAqBI,EAAa;AAAA,EAC9B,QAAQ,CAAA;AAAA,EACR,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMjB,IAAIC,GAAM;AACN,WAAO,IAAI,QAAQ,CAACC,GAASC,MAAW;AAEpC,WAAK,MAAM,KAAK,MAAMF,EAAA,EACjB,KAAKC,CAAO,EACZ,MAAM,CAACE,MAAU;AAClB,cAAAD,EAAOC,CAAK,GACNA;AAAA,MACV,CAAC,CAAC,GACF,KAAK,QAAA;AAAA,IACT,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,oBAAoB;AAChB,WAAO,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAIA,UAAU;AACN,QAAI,KAAK,kBAAkB,KAAK,MAAM,WAAW;AAC7C;AAEJ,UAAMH,IAAO,KAAK,MAAM,MAAA;AACxB,IAAKA,MAEL,KAAK,iBAAiB,IACtBA,EAAA,EACK,KAAK,MAAM;AACZ,WAAK,iBAAiB,IACtB,KAAK,QAAA;AAAA,IACT,CAAC,EACI,MAAM,MAAM;AACb,WAAK,iBAAiB,IACtB,KAAK,QAAA;AAAA,IACT,CAAC;AAAA,EACL;AACJ;AClDO,SAASI,EAAsBC,GAASC,GAAS;AACpD,QAAMC,IAAiB,CAAA,GACjBC,IAAU,OAAO,KAAKH,CAAO,GAC7BI,IAAU,OAAO,KAAKH,CAAO,GAC7BI,wBAAc,IAAI,CAAC,GAAGF,GAAS,GAAGC,CAAO,CAAC;AAChD,aAAWE,KAAOD;AACd,QAAIJ,EAAQK,CAAG,MAAMN,EAAQM,CAAG;AAC5B,UAAI,OAAOL,EAAQK,CAAG,KAAM,YAAY,OAAON,EAAQM,CAAG,KAAM,YAAYL,EAAQK,CAAG,KAAK,QAAQN,EAAQM,CAAG,KAAK,MAAM;AACtH,cAAMC,IAAuBR,EAAsBC,EAAQM,CAAG,GAAGL,EAAQK,CAAG,CAAC;AAC7E,mBAAWE,KAAeD;AACtB,UAAAL,EAAe,KAAK,GAAGI,CAAG,IAAIE,CAAW,EAAE;AAAA,MAEnD;AAEI,QAAAN,EAAe,KAAKI,CAAG;AAInC,SAAOJ;AACX;AAOA,SAAwBO,EAAeC,GAAUC,GAAU;AACvD,QAAMC,IAAQ,CAAA,GACRC,IAAW,CAAA,GACXX,wBAAqB,IAAA,GACrBY,IAAU,CAAA,GACVC,IAAc,IAAI,IAAIL,EAAS,IAAI,CAAAM,MAAQ,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC,GAC3DC,IAAc,IAAI,IAAIN,EAAS,IAAI,CAAAK,MAAQ,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC;AACjE,aAAW,CAACE,GAAIlB,CAAO,KAAKe,GAAa;AACrC,UAAMd,IAAUgB,EAAY,IAAIC,CAAE;AAClC,IAAKjB,IAGKkB,EAAQlB,GAASD,CAAO,MAC9BE,EAAe,IAAID,EAAQ,IAAIF,EAAsBC,GAASC,CAAO,CAAC,GACtEY,EAAS,KAAKZ,CAAO,KAJrBa,EAAQ,KAAKd,CAAO;AAAA,EAM5B;AACA,aAAW,CAACkB,GAAIjB,CAAO,KAAKgB;AACxB,IAAKF,EAAY,IAAIG,CAAE,KACnBN,EAAM,KAAKX,CAAO;AAG1B,SAAO;AAAA,IACH,OAAAW;AAAA,IACA,UAAAC;AAAA,IACA,gBAAAX;AAAA,IACA,SAAAY;AAAA,EAAA;AAER;ACvDA,SAAwBM,EAAYC,GAAcC,GAAM;AACpD,MAAIA,EAAK,SAAS;AACd,WAAOA,EAAK;AAChB,QAAMC,IAAQF,KAAgB,CAAA;AAC9B,SAAAC,EAAK,QAAQ,MAAM,QAAQ,CAACN,MAAS;AACjC,UAAMQ,IAAQD,EAAM,UAAU,OAAKE,EAAE,OAAOT,EAAK,EAAE;AACnD,IAAIQ,MAAU,KACVD,EAAM,KAAKP,CAAI,IAGfO,EAAMC,CAAK,IAAIR;AAAA,EAEvB,CAAC,GACDM,EAAK,QAAQ,SAAS,QAAQ,CAACN,MAAS;AACpC,UAAMQ,IAAQD,EAAM,UAAU,OAAKE,EAAE,OAAOT,EAAK,EAAE;AACnD,IAAIQ,MAAU,KACVD,EAAM,KAAKP,CAAI,IAGfO,EAAMC,CAAK,IAAIR;AAAA,EAEvB,CAAC,GACDM,EAAK,QAAQ,QAAQ,QAAQ,CAACN,MAAS;AACnC,UAAMQ,IAAQD,EAAM,UAAU,OAAKE,EAAE,OAAOT,EAAK,EAAE;AACnD,IAAIQ,MAAU,MACVD,EAAM,OAAOC,GAAO,CAAC;AAAA,EAC7B,CAAC,GACMD;AACX;AC3BA,SAAwBG,EAAaH,GAAOI,GAAS;AAEjD,QAAMC,IAAU,IAAI,IAAIL,EAAM,IAAI,CAAAP,MAAQ,CAACA,EAAK,IAAIA,CAAI,CAAC,CAAC;AAC1D,SAAAW,EAAQ,QAAQ,CAACE,MAAW;AACxB,QAAIA,EAAO,SAAS;AAChB,MAAAD,EAAQ,OAAOC,EAAO,IAAI;AAAA,aAErBA,EAAO,SAAS,UAAU;AAC/B,YAAMC,IAAeF,EAAQ,IAAIC,EAAO,KAAK,EAAE;AAC/C,MAAAD,EAAQ,IAAIC,EAAO,KAAK,IAAIC,IAAe,EAAE,GAAGA,GAAc,GAAGD,EAAO,KAAA,IAASA,EAAO,IAAI;AAAA,IAChG,OACK;AACD,YAAMC,IAAeF,EAAQ,IAAIC,EAAO,KAAK,EAAE;AAC/C,MAAAD,EAAQ,IAAIC,EAAO,KAAK,IAAIC,IACtBC,EAAOD,GAAcD,EAAO,KAAK,QAAQ,IACzCE,EAAO,EAAE,IAAIF,EAAO,KAAK,MAAMA,EAAO,KAAK,QAAQ,CAAC;AAAA,IAC9D;AAAA,EACJ,CAAC,GAEM,CAAC,GAAGD,EAAQ,QAAQ;AAC/B;ACnBA,SAASI,EAAWL,GAAS;AACzB,SAAOA,EAAQ,MAAM,SAAS,KACvBA,EAAQ,SAAS,SAAS,KAC1BA,EAAQ,QAAQ,SAAS;AACpC;AAOA,SAASM,EAAcvB,GAAUC,GAAU;AACvC,SAAOqB,EAAWvB,EAAeC,GAAUC,CAAQ,CAAC;AACxD;AAgBA,eAA8BuB,EAAK,EAAE,SAAAP,GAAS,cAAAN,GAAc,MAAAC,GAAM,MAAAa,GAAM,MAAAC,GAAM,QAAAC,GAAQ,QAAAC,GAAQ,QAAAC,GAAQ,OAAAC,EAAA,GAAU;AAC5G,MAAIC,IAAUnB,GACVoB,IAAmBrB,KAAgB,CAAA,GACnCsB,IAAcvB,EAAYC,GAAcoB,CAAO;AACnD,MAAId,EAAQ,SAAS,GAAG;AAEpB,UAAMiB,IAA0BlB,EAAagB,GAAkBf,CAAO;AACtE,QAAIM,EAAcS,GAAkBE,CAAuB,GAAG;AAE1D,YAAMC,IAAyBnB,EAAaiB,GAAahB,CAAO,GAC1DmB,IAAgBrC,EAAekC,GAAaE,CAAsB;AACxE,MAAIb,EAAWc,CAAa,MAExB,MAAMV,EAAKU,CAAa,GAExBL,IAAU,MAAMN,EAAA,GAChBQ,IAAcvB,EAAYuB,GAAaF,CAAO,IAElDC,IAAmBE;AAAA,IACvB;AAAA,EACJ;AAEA,QAAMG,IAAaN,EAAQ,WAAW,OAChChC,EAAeiC,GAAkBD,EAAQ,KAAK,IAC9CA,EAAQ;AACd,eAAMD,EAAM,YAAY;AACpB,UAAM,QAAQ,IAAIO,EAAW,MAAM,IAAI,CAAA/B,MAAQqB,EAAOrB,CAAI,CAAC,CAAC,GAC5D,MAAM,QAAQ,IAAI+B,EAAW,SAAS,IAAI,CAAA/B,MAAQsB,EAAOtB,EAAK,IAAI,EAAE,MAAMA,EAAA,CAAM,CAAC,CAAC,GAClF,MAAM,QAAQ,IAAI+B,EAAW,QAAQ,IAAI,OAAQR,EAAOvB,EAAK,EAAE,CAAC,CAAC;AAAA,EACrE,CAAC,GACM2B;AACX;ACtCA,MAAqBK,EAAY;AAAA,EAC7B;AAAA,EACA,kCAAkB,IAAA;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EACA,sCAAsB,IAAA;AAAA,EACtB,gBAAgB,CAAA;AAAA,EAChB,iCAAiB,IAAA;AAAA,EACjB;AAAA,EACA,aAAa;AAAA,EACb,aAAaC,EAAA;AAAA,EACb;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,YAAYhE,GAAS;AACjB,SAAK,UAAU;AAAA,MACX,WAAW;AAAA,MACX,GAAGA;AAAA,IAAA,GAEP,KAAK,KAAK,KAAK,QAAQ,MAAM;AAC7B,UAAM,EAAE,YAAAiE,MAAe,KAAK,SACtBC,IAAc,KAAK,QAAQ,eAAe,IAAIC,EAAA;AACpD,SAAK,UAAU,IAAIC,EAAW,GAAG,KAAK,QAAQ,EAAE,YAAYF,GAAa;AAAA,MACrE,SAAS,CAAC,gBAAgB;AAAA,MAC1B,YAAAD;AAAA,IAAA,CACH,GACD,KAAK,YAAY,IAAIG,EAAW,GAAG,KAAK,QAAQ,EAAE,cAAcF,GAAa;AAAA,MACzE,SAAS,CAAC,gBAAgB;AAAA,MAC1B,YAAAD;AAAA,IAAA,CACH,GACD,KAAK,iBAAiB,IAAIG,EAAW,GAAG,KAAK,QAAQ,EAAE,oBAAoBF,GAAa;AAAA,MACpF,SAAS,CAAC,kBAAkB,QAAQ;AAAA,MACpC,YAAAD;AAAA,IAAA,CACH;AACD,UAAMI,IAAY;AAAA,MACd,QAAQ,QAAQ,KAAK,eAAe,SAAS;AAAA,MAC7C,QAAQ,QAAQ,KAAK,QAAQ,SAAS;AAAA,MACtC,QAAQ,QAAQ,KAAK,UAAU,SAAS;AAAA,IAAA;AAE5C,SAAK,mBAAmB,QAAQ,IAAIA,CAAS,EAAE,KAAK,MAAM;AAAA,IAAE,CAAC,GAC7D,KAAK,QAAQ,gBAAgB,GAAI,GACjC,KAAK,UAAU,gBAAgB,GAAI,GACnC,KAAK,eAAe,gBAAgB,GAAI,GACxC,KAAK,iBAAiBxE,EAAS,KAAK,sBAAsB,KAAK,QAAQ,gBAAgB,GAAG;AAAA,EAC9F;AAAA,EACA,aAAayE,GAAM;AACf,WAAI,KAAK,WAAW,IAAIA,CAAI,KAAK,QAC7B,KAAK,WAAW,IAAIA,GAAM,IAAI7D,GAAc,GAEzC,KAAK,WAAW,IAAI6D,CAAI;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA,EAIA,MAAM,UAAU;AACZ,SAAK,YAAY,MAAA,GACjB,KAAK,WAAW,MAAA,GAChB,KAAK,cAAc,OAAO,CAAC,GAC3B,MAAM,QAAQ,IAAI;AAAA,MACd,KAAK,QAAQ,QAAA;AAAA,MACb,KAAK,UAAU,QAAA;AAAA,MACf,KAAK,eAAe,QAAA;AAAA,IAAQ,CAC/B,GACD,KAAK,aAAa;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,cAAcA,GAAM;AAChB,UAAM,EAAE,YAAAC,GAAY,SAAAvE,EAAA,IAAY,KAAK,wBAAwBsE,CAAI;AACjE,WAAO,CAACC,GAAYvE,CAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,wBAAwBsE,GAAM;AAC1B,UAAME,IAAuB,KAAK,YAAY,IAAIF,CAAI;AACtD,QAAIE,KAAwB;AACxB,YAAM,IAAI,MAAM,uBAAuBF,CAAI,aAAa;AAC5D,WAAOE;AAAA,EACX;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,cAAcD,GAAYvE,GAAS;AAC/B,QAAI,KAAK;AACL,YAAM,IAAI,MAAM,yBAAyB;AAC7C,SAAK,YAAY,IAAIA,EAAQ,MAAM;AAAA,MAC/B,YAAAuE;AAAA,MACA,SAAAvE;AAAA,MACA,cAAcuE,EAAW,MAAA;AAAA,MACzB,YAAY;AAAA;AAAA,IAAA,CACf;AACD,UAAME,IAAkB,CAAC7B,MAAW;AAChC,iBAAW8B,KAAgB,KAAK;AAC5B,YAAIA,KAAgB,QAEhBA,EAAa,mBAAmB9B,EAAO,kBAEvC8B,EAAa,SAAS9B,EAAO,QAE7B,EAAAA,EAAO,SAAS,YAAY8B,EAAa,SAAS9B,EAAO,SAEzD8B,EAAa,KAAK,OAAO9B,EAAO,KAAK;AAEzC,iBAAO;AAEX,aAAO;AAAA,IACX,GACM+B,IAAsB,CAACC,GAAgB3C,MAAO;AAChD,YAAM4C,IAAmB,CAAC,GAAG,KAAK,aAAa;AAC/C,eAASrC,IAAI,GAAGA,IAAIqC,EAAiB,QAAQrC,KAAK,GAAG;AACjD,cAAMT,IAAO8C,EAAiBrC,CAAC;AAC/B,QAAIT,KAAQ,QAERA,EAAK,mBAAmB6C,MAExB7C,EAAK,SAAS,YAAYA,EAAK,SAASE,KAExCF,EAAK,KAAK,OAAOE,MAErB4C,EAAiBrC,CAAC,IAAI;AAAA,MAC1B;AACA,WAAK,gBAAgBqC,EAAiB,OAAO,CAAA9C,MAAQA,KAAQ,IAAI;AAAA,IACrE;AACA,IAAAwC,EAAW,GAAG,SAAS,CAACxC,MAAS;AAE7B,UAAI0C,EAAgB,EAAE,gBAAgBzE,EAAQ,MAAM,MAAM,UAAU,MAAM+B,EAAA,CAAM,GAAG;AAC/E,QAAA4C,EAAoB3E,EAAQ,MAAM+B,EAAK,EAAE;AACzC;AAAA,MACJ;AACA,WAAK,QAAQ,OAAO;AAAA,QAChB,gBAAgB/B,EAAQ;AAAA,QACxB,MAAM,KAAK,IAAA;AAAA,QACX,MAAM;AAAA,QACN,MAAM+B;AAAA,MAAA,CACT,EAAE,KAAK,MAAM;AACV,QAAI,KAAK,wBAAwB/B,EAAQ,IAAI,EAAE,cAE/C,KAAK,aAAaA,EAAQ,IAAI;AAAA,MAClC,CAAC,EAAE,MAAM,CAACa,MAAU;AAChB,QAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,MAClF,CAAC;AAAA,IACL,CAAC,GACD0D,EAAW,GAAG,WAAW,CAAC,EAAE,IAAAtC,EAAA,GAAM6C,MAAa;AAC3C,YAAMzC,IAAO,EAAE,IAAAJ,GAAI,UAAA6C,EAAA;AAEnB,UAAIL,EAAgB,EAAE,gBAAgBzE,EAAQ,MAAM,MAAM,UAAU,MAAAqC,EAAA,CAAM,GAAG;AACzE,QAAAsC,EAAoB3E,EAAQ,MAAMiC,CAAE;AACpC;AAAA,MACJ;AACA,WAAK,QAAQ,OAAO;AAAA,QAChB,gBAAgBjC,EAAQ;AAAA,QACxB,MAAM,KAAK,IAAA;AAAA,QACX,MAAM;AAAA,QACN,MAAAqC;AAAA,MAAA,CACH,EAAE,KAAK,MAAM;AACV,QAAI,KAAK,wBAAwBrC,EAAQ,IAAI,EAAE,cAE/C,KAAK,aAAaA,EAAQ,IAAI;AAAA,MAClC,CAAC,EAAE,MAAM,CAACa,MAAU;AAChB,QAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,MAClF,CAAC;AAAA,IACL,CAAC,GACD0D,EAAW,GAAG,WAAW,CAAC,EAAE,IAAAtC,QAAS;AAEjC,UAAIwC,EAAgB,EAAE,gBAAgBzE,EAAQ,MAAM,MAAM,UAAU,MAAMiC,EAAA,CAAI,GAAG;AAC7E,QAAA0C,EAAoB3E,EAAQ,MAAMiC,CAAE;AACpC;AAAA,MACJ;AACA,WAAK,QAAQ,OAAO;AAAA,QAChB,gBAAgBjC,EAAQ;AAAA,QACxB,MAAM,KAAK,IAAA;AAAA,QACX,MAAM;AAAA,QACN,MAAMiC;AAAA,MAAA,CACT,EAAE,KAAK,MAAM;AACV,QAAI,KAAK,wBAAwBjC,EAAQ,IAAI,EAAE,cAE/C,KAAK,aAAaA,EAAQ,IAAI;AAAA,MAClC,CAAC,EAAE,MAAM,CAACa,MAAU;AAChB,QAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,MAClF,CAAC;AAAA,IACL,CAAC,GACG,KAAK,QAAQ,aACb,KAAK,UAAUb,EAAQ,IAAI,EACtB,MAAM,CAACa,MAAU;AAClB,MAAK,KAAK,QAAQ,WAElB,KAAK,QAAQ,QAAQ,KAAK,wBAAwBb,EAAQ,IAAI,EAAE,SAASa,CAAK;AAAA,IAClF,CAAC;AAAA,EAET;AAAA,EACA,uBAAuB;AACnB,SAAK,gBAAgB,QAAQ,CAACyD,MAAS;AACnC,WAAK,YAAYA,CAAI,EAAE,MAAM,MAAM;AAAA,MAAE,CAAC;AAAA,IAC1C,CAAC,GACD,KAAK,gBAAgB,MAAA;AAAA,EACzB;AAAA,EACA,aAAaA,GAAM;AACf,SAAK,gBAAgB,IAAIA,CAAI,GAC7B,KAAK,eAAA;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAAW;AACb,UAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,KAAA,CAAM,EAAE,IAAI,CAAArC,MAAM,KAAK,UAAUA,CAAE,CAAC,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,UAAUqC,GAAM;AAClB,UAAME,IAAuB,KAAK,wBAAwBF,CAAI;AAC9D,QAAI,CAACE,EAAqB;AACtB;AACJ,SAAK,aAAaF,CAAI;AACtB,UAAMS,IAAkB,KAAK,QAAQ,uBAC/B,MAAM,KAAK,QAAQ,qBAAqBP,EAAqB,SAAS,OAAOnC,MAAS;AACpF,aAAOA,KAAQ,OACT,KAAK,KAAKiC,CAAI,IACd,KAAK,aAAaA,CAAI,EAAE,IAAI,YAAY;AACtC,cAAMU,IAAW,KAAK,IAAA,GAChBC,IAAS,MAAM,KAAK,eAAe,OAAO;AAAA,UAC5C,OAAOD;AAAA,UACP,gBAAgBV;AAAA,UAChB,YAAY,KAAK;AAAA,UACjB,QAAQ;AAAA,QAAA,CACX;AACD,cAAM,KAAK,aAAaA,GAAMjC,CAAI,EAC7B,KAAK,YAAY;AAElB,gBAAM,KAAK,eAAe,WAAW;AAAA,YACjC,IAAI,EAAE,KAAK4C,EAAA;AAAA,YACX,gBAAgBX;AAAA,YAChB,KAAK;AAAA,cACD,EAAE,KAAK,EAAE,MAAMU,IAAS;AAAA,cACxB,EAAE,QAAQ,SAAA;AAAA,YAAS;AAAA,UACvB,CACH,GAED,MAAM,KAAK,eAAe,UAAU,EAAE,IAAIC,KAAU;AAAA,YAChD,MAAM,EAAE,QAAQ,QAAQ,KAAK,KAAK,MAAI;AAAA,UAAE,CAC3C;AAAA,QACL,CAAC,EACI,MAAM,OAAOpE,MAAU;AACxB,gBAAI,KAAK,QAAQ,WACb,KAAK,QAAQ,QAAQ,KAAK,wBAAwByD,CAAI,EAAE,SAASzD,CAAK,GAE1E,MAAM,KAAK,eAAe,UAAU,EAAE,IAAIoE,KAAU;AAAA,YAChD,MAAM,EAAE,QAAQ,SAAS,KAAK,KAAK,IAAA,GAAO,OAAOpE,EAAM,SAASA,EAAM,QAAA;AAAA,UAAQ,CACjF,GACKA;AAAA,QACV,CAAC;AAAA,MACL,CAAC;AAAA,IACT,CAAC,IACC;AACN,SAAK,YAAY,IAAIyD,GAAM;AAAA,MACvB,GAAGE;AAAA,MACH,YAAY;AAAA,MACZ,iBAAAO;AAAA,IAAA,CACH;AAAA,EACL;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW;AACb,UAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,KAAA,CAAM,EAAE,IAAI,CAAA9C,MAAM,KAAK,UAAUA,CAAE,CAAC,CAAC;AAAA,EAChF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,UAAUqC,GAAM;AAClB,UAAME,IAAuB,KAAK,wBAAwBF,CAAI;AAC9D,IAAIE,EAAqB,eAErBA,EAAqB,mBACrB,MAAMA,EAAqB,gBAAA,GAC/B,KAAK,YAAY,IAAIF,GAAM;AAAA,MACvB,GAAGE;AAAA,MACH,iBAAiB;AAAA,MACjB,YAAY;AAAA,IAAA,CACf;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAIA,MAAM,UAAU;AACZ,QAAI,KAAK;AACL,YAAM,IAAI,MAAM,yBAAyB;AAC7C,UAAMU,IAAS,CAAA;AAIf,QAHA,MAAM,QAAQ,IAAI,CAAC,GAAG,KAAK,YAAY,MAAM,EAAE,IAAI,OAAM,KAAK,KAAKjD,CAAE,EAAE,MAAM,CAACpB,MAAU;AACpF,MAAAqE,EAAO,KAAK,EAAE,IAAAjD,GAAI,OAAApB,EAAA,CAAO;AAAA,IAC7B,CAAC,CAAC,CAAC,GACCqE,EAAO,SAAS;AAChB,YAAM,IAAI,MAAM;AAAA,EAAqCA,EAAO,IAAI,CAAArE,MAAS,GAAGA,EAAM,EAAE,KAAKA,EAAM,MAAM,OAAO,EAAE,EAAE,KAAK;AAAA;AAAA,CAAM,CAAC,EAAE;AAAA,EACtI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,UAAUyD,GAAMa,GAAO;AACnB,UAAMC,IAAgB,KAAK,eAAe,QAAQ;AAAA,MAC9C,GAAGd,IAAO,EAAE,gBAAgBA,EAAA,IAAS,CAAA;AAAA,MACrC,QAAQ;AAAA,IAAA,GACT,EAAE,QAAQ,EAAE,QAAQ,EAAA,GAAK,OAAAa,GAAO;AACnC,WAAIC,aAAyB,UAClBA,EACF,KAAK,CAAArD,MAAQA,KAAQ,IAAI,IAE1BqD,KAAiB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU;AACZ,UAAM,KAAK;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,KAAKd,GAAMtE,IAAU,IAAI;AAC3B,QAAI,KAAK;AACL,YAAM,IAAI,MAAM,yBAAyB;AAC7C,UAAM,KAAK,QAAA;AACX,UAAM,EAAE,SAASqF,GAAmB,cAAAC,MAAiB,KAAK,wBAAwBhB,CAAI;AACtF,UAAMgB;AACN,UAAMC,IAAiB,MAAM,KAAK,eAAe,KAAK;AAAA,MAClD,gBAAgBjB;AAAA,MAChB,YAAY,KAAK;AAAA,MACjB,QAAQ;AAAA,IAAA,GACT;AAAA,MACC,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,EAAE,MAAA,IAAU,GACPU,IAAW,KAAK,IAAA;AACtB,QAAIC,IAAS;AAEb,UAAM,IAAI,QAAQ,CAACtE,MAAY;AAC3B,iBAAWA,GAAS,CAAC;AAAA,IACzB,CAAC;AACD,UAAM6E,IAAS,YAAY;AACvB,YAAMC,IAAmB,MAAM,KAAK,eAAe,QAAQ;AAAA,QACvD,gBAAgBnB;AAAA,QAChB,QAAQ;AAAA,MAAA,GACT;AAAA,QACC,MAAM,EAAE,KAAK,GAAA;AAAA,QACb,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACV;AACD,UAAItE,GAAS,mBACc,MAAM,KAAK,QAAQ,KAAK;AAAA,QAC3C,gBAAgBsE;AAAA,QAChB,MAAM,EAAE,MAAMU,EAAA;AAAA,MAAS,GACxB;AAAA,QACC,MAAM,EAAE,MAAM,EAAA;AAAA,QACd,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACV,EAAE,MAAA,MACoB;AACnB;AAER,MAAKO,MACDN,IAAS,MAAM,KAAK,eAAe,OAAO;AAAA,QACtC,OAAOD;AAAA,QACP,gBAAgBV;AAAA,QAChB,YAAY,KAAK;AAAA,QACjB,QAAQ;AAAA,MAAA,CACX;AAEL,YAAMjC,IAAO,MAAM,KAAK,QAAQ,KAAKgD,GAAmB;AAAA,QACpD,uBAAuBI,GAAkB;AAAA,QACzC,qBAAqBA,GAAkB;AAAA,MAAA,CAC1C;AACD,YAAM,KAAK,aAAanB,GAAMjC,CAAI;AAAA,IACtC;AACA,WAAOrC,GAAS,QAAQwF,EAAA,IAAW,KAAK,aAAalB,CAAI,EAAE,IAAIkB,CAAM,GAChE,MAAM,OAAO3E,MAAU;AACxB,YAAIoE,KAAU,SACN,KAAK,QAAQ,WACb,KAAK,QAAQ,QAAQI,GAAmBxE,CAAK,GACjD,MAAM,KAAK,eAAe,UAAU,EAAE,IAAIoE,KAAU;AAAA,QAChD,MAAM,EAAE,QAAQ,SAAS,KAAK,KAAK,IAAA,GAAO,OAAOpE,EAAM,SAASA,EAAM,QAAA;AAAA,MAAQ,CACjF,IAECA;AAAA,IACV,CAAC,GACGoE,KAAU,SAEV,MAAM,KAAK,eAAe,WAAW;AAAA,MACjC,IAAI,EAAE,KAAKA,EAAA;AAAA,MACX,gBAAgBX;AAAA,MAChB,KAAK;AAAA,QACD,EAAE,KAAK,EAAE,MAAMU,IAAS;AAAA,QACxB,EAAE,QAAQ,SAAA;AAAA,MAAS;AAAA,IACvB,CACH,GAED,MAAM,KAAK,eAAe,UAAU,EAAE,IAAIC,KAAU;AAAA,MAChD,MAAM,EAAE,QAAQ,QAAQ,KAAK,KAAK,MAAI;AAAA,IAAE,CAC3C;AAAA,EAET;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAYX,GAAM;AACpB,UAAM,KAAK,KAAKA,GAAM;AAAA,MAClB,iBAAiB;AAAA,IAAA,CACpB;AAAA,EACL;AAAA,EACA,MAAM,aAAaA,GAAMjC,GAAM;AAC3B,UAAM,EAAE,YAAAkC,GAAY,SAASc,MAAsB,KAAK,wBAAwBf,CAAI,GAC9EU,IAAW,KAAK,IAAA,GAChBS,IAAmB,MAAM,KAAK,eAAe,QAAQ;AAAA,MACvD,gBAAgBnB;AAAA,MAChB,QAAQ;AAAA,IAAA,GACT;AAAA,MACC,MAAM,EAAE,KAAK,GAAA;AAAA,MACb,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,GACKlC,IAAe,MAAM,KAAK,UAAU,QAAQ;AAAA,MAC9C,gBAAgBkC;AAAA,IAAA,GACjB;AAAA,MACC,MAAM,EAAE,MAAM,GAAA;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,GACKoB,IAAiB,MAAM,KAAK,QAAQ,KAAK;AAAA,MAC3C,gBAAgBpB;AAAA,MAChB,MAAM,EAAE,MAAMU,EAAA;AAAA,IAAS,GACxB;AAAA,MACC,MAAM,EAAE,MAAM,EAAA;AAAA,MACd,UAAU;AAAA,MACV,OAAO;AAAA,IAAA,CACV,EAAE,MAAA;AACH,UAAM/B,EAAK;AAAA,MACP,SAASyC;AAAA,MACT,cAActD,GAAc;AAAA,MAC5B,MAAAC;AAAA,MACA,MAAM,MAAM,KAAK,QAAQ,KAAKgD,GAAmB;AAAA,QAC7C,uBAAuBI,GAAkB;AAAA,QACzC,qBAAqBA,GAAkB;AAAA,MAAA,CAC1C;AAAA,MACD,MAAM,CAAA/C,MAAW,KAAK,QAAQ,KAAK2C,GAAmB;AAAA,QAClD,SAAA3C;AAAA,QACA,YAAYgD;AAAA,MAAA,CACf;AAAA,MACD,QAAQ,OAAO3D,MAAS;AAEpB,aAAK,cAAc,KAAK;AAAA,UACpB,gBAAgBuC;AAAA,UAChB,MAAM;AAAA,UACN,MAAMvC;AAAA,QAAA,GACP;AAAA,UACC,gBAAgBuC;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,EAAE,IAAIvC,EAAK,IAAI,UAAU,EAAE,MAAMA,EAAA,EAAK;AAAA,QAAE,CACjD,GAED,MAAMwC,EAAW,WAAW,EAAE,IAAIxC,EAAK,GAAA,GAAMA,GAAM,EAAE,QAAQ,IAAM;AAAA,MACvE;AAAA,MACA,QAAQ,OAAO4D,GAAQb,MAAa;AAEhC,aAAK,cAAc,KAAK;AAAA,UACpB,gBAAgBR;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,EAAE,IAAIqB,GAAQ,GAAGb,EAAS,KAAA;AAAA,QAAK,GACtC;AAAA,UACC,gBAAgBR;AAAA,UAChB,MAAM;AAAA,UACN,MAAM,EAAE,IAAIqB,GAAQ,UAAAb,EAAA;AAAA,QAAS,CAChC,GACD,MAAMP,EAAW,UAAU,EAAE,IAAIoB,KAAU;AAAA,UACvC,GAAGb;AAAA,UACH,cAAc,EAAE,IAAIa,EAAA;AAAA,QAAO,GAC5B,EAAE,QAAQ,IAAM;AAAA,MACvB;AAAA,MACA,QAAQ,OAAOA,MAAW;AAItB,QAHmB,MAAMpB,EAAW,KAAK;AAAA,UACrC,IAAIoB;AAAA,QAAA,GACL,EAAE,UAAU,IAAO,OAAO,IAAM,EAAE,MAAA,IAAU,MAG/C,KAAK,cAAc,KAAK;AAAA,UACpB,gBAAgBrB;AAAA,UAChB,MAAM;AAAA,UACN,MAAMqB;AAAA,QAAA,CACT,GACD,MAAMpB,EAAW,UAAU,EAAE,IAAIoB,GAAQ;AAAA,MAC7C;AAAA,MACA,OAAO,OAAO7F,MACHyE,EAAW,MAAM,YAAY;AAChC,cAAMzE,EAAA;AAAA,MACV,CAAC;AAAA,IACL,CACH,EACI,KAAK,OAAO8F,MAAa;AAwB1B,UAtBA,MAAM,KAAK,UAAU,WAAW;AAAA,QAC5B,gBAAgBtB;AAAA,QAChB,MAAM,EAAE,MAAMU,EAAA;AAAA,MAAS,CAC1B,GAED,MAAM,KAAK,QAAQ,WAAW;AAAA,QAC1B,gBAAgBV;AAAA,QAChB,IAAI,EAAE,KAAKoB,EAAe,IAAI,CAAAG,MAAKA,EAAE,EAAE,EAAA;AAAA,MAAE,CAC5C,GAED,MAAM,KAAK,UAAU,OAAO;AAAA,QACxB,MAAMb;AAAA,QACN,gBAAgBV;AAAA,QAChB,OAAOsB;AAAA,MAAA,CACV,GAED,MAAM,IAAI,QAAQ,CAACjF,MAAY;AAC3B,mBAAWA,GAAS,CAAC;AAAA,MACzB,CAAC,GACkB,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,gBAAgB2D;AAAA,MAAA,GACjB,EAAE,UAAU,IAAO,OAAO,IAAM,EAAE,MAAA,IAAU,GAC/B;AAGZ,cAAM,KAAK,KAAKA,GAAM;AAAA,UAClB,OAAO;AAAA,UACP,iBAAiB;AAAA,QAAA,CACpB;AACD;AAAA,MACJ;AAIA,YAAMwB,IAAqB,MAAMvB,EAAW,KAAK;AAAA,QAC7C,IAAI,EAAE,MAAMqB,EAAS,IAAI,CAAA7D,MAAQA,EAAK,EAAE,EAAA;AAAA,MAAE,GAC3C;AAAA,QACC,UAAU;AAAA,QACV,OAAO;AAAA,MAAA,CACV,EAAE,IAAI,CAAAA,MAAQA,EAAK,EAAE;AACtB,YAAMwC,EAAW,MAAM,YAAY;AAE/B,cAAM,QAAQ,IAAIqB,EAAS,IAAI,OAAO7D,MAAS;AAE3C,eAAK,cAAc,KAAK;AAAA,YACpB,gBAAgBuC;AAAA,YAChB,MAAM;AAAA,YACN,MAAMvC;AAAA,UAAA,GACP;AAAA,YACC,gBAAgBuC;AAAA,YAChB,MAAM;AAAA,YACN,MAAM,EAAE,IAAIvC,EAAK,IAAI,UAAU,EAAE,MAAMA,EAAA,EAAK;AAAA,UAAE,CACjD,GAED,MAAMwC,EAAW,WAAW,EAAE,IAAIxC,EAAK,GAAA,GAAMA,GAAM,EAAE,QAAQ,IAAM;AAAA,QACvE,CAAC,CAAC,GAEF,MAAM,QAAQ,IAAI+D,EAAmB,IAAI,OAAO7D,MAAO;AACnD,gBAAMsC,EAAW,UAAU,EAAE,IAAAtC,GAAI;AAAA,QACrC,CAAC,CAAC;AAAA,MACN,CAAC;AAAA,IACL,CAAC;AAAA,EACL;AACJ;"}
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
- (function(f,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("@signaldb/core")):typeof define=="function"&&define.amd?define(["exports","@signaldb/core"],u):(f=typeof globalThis<"u"?globalThis:f||self,u(f.SignalDB={},f.core))})(this,(function(f,u){"use strict";function O(l,e,t={}){let s,o;const{leading:n=!1,trailing:a=!0}=t;function r(...c){const i=n&&!s,h=a&&!s;return s&&clearTimeout(s),s=setTimeout(()=>{s=null,a&&!i&&(o=l.apply(this,c))},e),i?o=l.apply(this,c):h||(o=null),o}return r}class S{queue=[];pendingPromise=!1;add(e){return new Promise((t,s)=>{this.queue.push(()=>e().then(t).catch(o=>{throw s(o),o})),this.dequeue()})}hasPendingPromise(){return this.pendingPromise}dequeue(){if(this.pendingPromise||this.queue.length===0)return;const e=this.queue.shift();e&&(this.pendingPromise=!0,e().then(()=>{this.pendingPromise=!1,this.dequeue()}).catch(()=>{this.pendingPromise=!1,this.dequeue()}))}}function w(l,e){const t=[],s=Object.keys(l),o=Object.keys(e),n=new Set([...s,...o]);for(const a of n)if(e[a]!==l[a])if(typeof e[a]=="object"&&typeof l[a]=="object"&&e[a]!=null&&l[a]!=null){const r=w(l[a],e[a]);for(const c of r)t.push(`${a}.${c}`)}else t.push(a);return t}function m(l,e){const t=[],s=[],o=new Map,n=[],a=new Map(l.map(c=>[c.id,c])),r=new Map(e.map(c=>[c.id,c]));for(const[c,i]of a){const h=r.get(c);h?u.isEqual(h,i)||(o.set(h.id,w(i,h)),s.push(h)):n.push(i)}for(const[c,i]of r)a.has(c)||t.push(i);return{added:t,modified:s,modifiedFields:o,removed:n}}function g(l,e){if(e.items!=null)return e.items;const t=l||[];return e.changes.added.forEach(s=>{const o=t.findIndex(n=>n.id===s.id);o===-1?t.push(s):t[o]=s}),e.changes.modified.forEach(s=>{const o=t.findIndex(n=>n.id===s.id);o===-1?t.push(s):t[o]=s}),e.changes.removed.forEach(s=>{const o=t.findIndex(n=>n.id===s.id);o!==-1&&t.splice(o,1)}),t}function P(l,e){const t=new Map(l.map(s=>[s.id,s]));return e.forEach(s=>{if(s.type==="remove")t.delete(s.data);else if(s.type==="insert"){const o=t.get(s.data.id);t.set(s.data.id,o?{...o,...s.data}:s.data)}else{const o=t.get(s.data.id);t.set(s.data.id,o?u.modify(o,s.data.modifier):u.modify({id:s.data.id},s.data.modifier))}}),[...t.values()]}function C(l){return l.added.length>0||l.modified.length>0||l.removed.length>0}function N(l,e){return C(m(l,e))}async function E({changes:l,lastSnapshot:e,data:t,pull:s,push:o,insert:n,update:a,remove:r,batch:c}){let i=t,h=e||[],y=g(e,i);if(l.length>0){const p=P(h,l);if(N(h,p)){const M=P(y,l),v=m(y,M);C(v)&&(await o(v),i=await s(),y=g(y,i)),h=p}}const d=i.changes==null?m(h,i.items):i.changes;return await c(async()=>{await Promise.all(d.added.map(p=>n(p))),await Promise.all(d.modified.map(p=>a(p.id,{$set:p}))),await Promise.all(d.removed.map(p=>r(p.id)))}),y}class ${options;collections=new Map;changes;snapshots;syncOperations;scheduledPushes=new Set;remoteChanges=[];syncQueues=new Map;collectionsReady;isDisposed=!1;instanceId=u.randomId();id;debouncedFlush;constructor(e){this.options={autostart:!0,...e},this.id=this.options.id||"default-sync-manager";const{reactivity:t}=this.options,s=this.options.dataAdapter??new u.DefaultDataAdapter;this.changes=new u.Collection(`${this.options.id}-changes`,s,{indices:["collectionName"],reactivity:t}),this.snapshots=new u.Collection(`${this.options.id}-snapshots`,s,{indices:["collectionName"],reactivity:t}),this.syncOperations=new u.Collection(`${this.options.id}-sync-operations`,s,{indices:["collectionName","status"],reactivity:t}),this.collectionsReady=Promise.all([this.syncOperations.isReady(),this.changes.isReady(),this.snapshots.isReady()]).then(()=>{}),this.changes.setMaxListeners(1e3),this.snapshots.setMaxListeners(1e3),this.syncOperations.setMaxListeners(1e3),this.debouncedFlush=O(this.flushScheduledPushes,this.options.debounceTime??100)}getSyncQueue(e){return this.syncQueues.get(e)==null&&this.syncQueues.set(e,new S),this.syncQueues.get(e)}async dispose(){this.collections.clear(),this.syncQueues.clear(),this.remoteChanges.splice(0),await Promise.all([this.changes.dispose(),this.snapshots.dispose(),this.syncOperations.dispose()]),this.isDisposed=!0}getCollection(e){const{collection:t,options:s}=this.getCollectionProperties(e);return[t,s]}getCollectionProperties(e){const t=this.collections.get(e);if(t==null)throw new Error(`Collection with id '${e}' not found`);return t}addCollection(e,t){if(this.isDisposed)throw new Error("SyncManager is disposed");this.collections.set(t.name,{collection:e,options:t,readyPromise:e.ready(),syncPaused:!0});const s=n=>{for(const a of this.remoteChanges)if(a!=null&&a.collectionName===n.collectionName&&a.type===n.type&&!(n.type==="remove"&&a.data!==n.data)&&a.data.id===n.data.id)return!0;return!1},o=(n,a)=>{const r=[...this.remoteChanges];for(let c=0;c<r.length;c+=1){const i=r[c];i!=null&&i.collectionName===n&&(i.type==="remove"&&i.data!==a||i.data.id===a&&(r[c]=null))}this.remoteChanges=r.filter(c=>c!=null)};e.on("added",n=>{if(s({collectionName:t.name,type:"insert",data:n})){o(t.name,n.id);return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"insert",data:n}).then(()=>{this.getCollectionProperties(t.name).syncPaused||this.schedulePush(t.name)}).catch(a=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,a)})}),e.on("changed",({id:n},a)=>{const r={id:n,modifier:a};if(s({collectionName:t.name,type:"update",data:r})){o(t.name,n);return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"update",data:r}).then(()=>{this.getCollectionProperties(t.name).syncPaused||this.schedulePush(t.name)}).catch(c=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,c)})}),e.on("removed",({id:n})=>{if(s({collectionName:t.name,type:"remove",data:n})){o(t.name,n);return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"remove",data:n}).then(()=>{this.getCollectionProperties(t.name).syncPaused||this.schedulePush(t.name)}).catch(a=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,a)})}),this.options.autostart&&this.startSync(t.name).catch(n=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,n)})}flushScheduledPushes(){this.scheduledPushes.forEach(e=>{this.pushChanges(e).catch(()=>{})}),this.scheduledPushes.clear()}schedulePush(e){this.scheduledPushes.add(e),this.debouncedFlush()}async startAll(){await Promise.all([...this.collections.keys()].map(e=>this.startSync(e)))}async startSync(e){const t=this.getCollectionProperties(e);if(!t.syncPaused)return;this.schedulePush(e);const s=this.options.registerRemoteChange?await this.options.registerRemoteChange(t.options,async o=>{if(o==null)await this.sync(e);else{const n=Date.now(),a=await this.syncOperations.insert({start:n,collectionName:e,instanceId:this.instanceId,status:"active"});await this.syncWithData(e,o).then(async()=>{await this.syncOperations.removeMany({id:{$ne:a},collectionName:e,$or:[{end:{$lte:n}},{status:"active"}]}),await this.syncOperations.updateOne({id:a},{$set:{status:"done",end:Date.now()}})}).catch(async r=>{throw this.options.onError&&this.options.onError(this.getCollectionProperties(e).options,r),await this.syncOperations.updateOne({id:a},{$set:{status:"error",end:Date.now(),error:r.stack||r.message}}),r})}}):void 0;this.collections.set(e,{...t,syncPaused:!1,cleanupFunction:s})}async pauseAll(){await Promise.all([...this.collections.keys()].map(e=>this.pauseSync(e)))}async pauseSync(e){const t=this.getCollectionProperties(e);t.syncPaused||(t.cleanupFunction&&await t.cleanupFunction(),this.collections.set(e,{...t,cleanupFunction:void 0,syncPaused:!0}))}async syncAll(){if(this.isDisposed)throw new Error("SyncManager is disposed");const e=[];if(await Promise.all([...this.collections.keys()].map(t=>this.sync(t).catch(s=>{e.push({id:t,error:s})}))),e.length>0)throw new Error(`Error while syncing collections:
1
+ (function(f,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("@signaldb/core")):typeof define=="function"&&define.amd?define(["exports","@signaldb/core"],u):(f=typeof globalThis<"u"?globalThis:f||self,u(f.SignalDB={},f.core))})(this,(function(f,u){"use strict";function O(l,e,t={}){let s,n;const{leading:a=!1,trailing:o=!0}=t;function r(...c){const i=a&&!s,h=o&&!s;return s&&clearTimeout(s),s=setTimeout(()=>{s=null,o&&!i&&(n=l.apply(this,c))},e),i?n=l.apply(this,c):h||(n=null),n}return r}class S{queue=[];pendingPromise=!1;add(e){return new Promise((t,s)=>{this.queue.push(()=>e().then(t).catch(n=>{throw s(n),n})),this.dequeue()})}hasPendingPromise(){return this.pendingPromise}dequeue(){if(this.pendingPromise||this.queue.length===0)return;const e=this.queue.shift();e&&(this.pendingPromise=!0,e().then(()=>{this.pendingPromise=!1,this.dequeue()}).catch(()=>{this.pendingPromise=!1,this.dequeue()}))}}function w(l,e){const t=[],s=Object.keys(l),n=Object.keys(e),a=new Set([...s,...n]);for(const o of a)if(e[o]!==l[o])if(typeof e[o]=="object"&&typeof l[o]=="object"&&e[o]!=null&&l[o]!=null){const r=w(l[o],e[o]);for(const c of r)t.push(`${o}.${c}`)}else t.push(o);return t}function m(l,e){const t=[],s=[],n=new Map,a=[],o=new Map(l.map(c=>[c.id,c])),r=new Map(e.map(c=>[c.id,c]));for(const[c,i]of o){const h=r.get(c);h?u.isEqual(h,i)||(n.set(h.id,w(i,h)),s.push(h)):a.push(i)}for(const[c,i]of r)o.has(c)||t.push(i);return{added:t,modified:s,modifiedFields:n,removed:a}}function g(l,e){if(e.items!=null)return e.items;const t=l||[];return e.changes.added.forEach(s=>{const n=t.findIndex(a=>a.id===s.id);n===-1?t.push(s):t[n]=s}),e.changes.modified.forEach(s=>{const n=t.findIndex(a=>a.id===s.id);n===-1?t.push(s):t[n]=s}),e.changes.removed.forEach(s=>{const n=t.findIndex(a=>a.id===s.id);n!==-1&&t.splice(n,1)}),t}function P(l,e){const t=new Map(l.map(s=>[s.id,s]));return e.forEach(s=>{if(s.type==="remove")t.delete(s.data);else if(s.type==="insert"){const n=t.get(s.data.id);t.set(s.data.id,n?{...n,...s.data}:s.data)}else{const n=t.get(s.data.id);t.set(s.data.id,n?u.modify(n,s.data.modifier):u.modify({id:s.data.id},s.data.modifier))}}),[...t.values()]}function C(l){return l.added.length>0||l.modified.length>0||l.removed.length>0}function N(l,e){return C(m(l,e))}async function E({changes:l,lastSnapshot:e,data:t,pull:s,push:n,insert:a,update:o,remove:r,batch:c}){let i=t,h=e||[],y=g(e,i);if(l.length>0){const p=P(h,l);if(N(h,p)){const M=P(y,l),v=m(y,M);C(v)&&(await n(v),i=await s(),y=g(y,i)),h=p}}const d=i.changes==null?m(h,i.items):i.changes;return await c(async()=>{await Promise.all(d.added.map(p=>a(p))),await Promise.all(d.modified.map(p=>o(p.id,{$set:p}))),await Promise.all(d.removed.map(p=>r(p.id)))}),y}class ${options;collections=new Map;changes;snapshots;syncOperations;scheduledPushes=new Set;remoteChanges=[];syncQueues=new Map;collectionsReady;isDisposed=!1;instanceId=u.randomId();id;debouncedFlush;constructor(e){this.options={autostart:!0,...e},this.id=this.options.id||"default-sync-manager";const{reactivity:t}=this.options,s=this.options.dataAdapter??new u.DefaultDataAdapter;this.changes=new u.Collection(`${this.options.id}-changes`,s,{indices:["collectionName"],reactivity:t}),this.snapshots=new u.Collection(`${this.options.id}-snapshots`,s,{indices:["collectionName"],reactivity:t}),this.syncOperations=new u.Collection(`${this.options.id}-sync-operations`,s,{indices:["collectionName","status"],reactivity:t});const n=[Promise.resolve(this.syncOperations.isReady()),Promise.resolve(this.changes.isReady()),Promise.resolve(this.snapshots.isReady())];this.collectionsReady=Promise.all(n).then(()=>{}),this.changes.setMaxListeners(1e3),this.snapshots.setMaxListeners(1e3),this.syncOperations.setMaxListeners(1e3),this.debouncedFlush=O(this.flushScheduledPushes,this.options.debounceTime??100)}getSyncQueue(e){return this.syncQueues.get(e)==null&&this.syncQueues.set(e,new S),this.syncQueues.get(e)}async dispose(){this.collections.clear(),this.syncQueues.clear(),this.remoteChanges.splice(0),await Promise.all([this.changes.dispose(),this.snapshots.dispose(),this.syncOperations.dispose()]),this.isDisposed=!0}getCollection(e){const{collection:t,options:s}=this.getCollectionProperties(e);return[t,s]}getCollectionProperties(e){const t=this.collections.get(e);if(t==null)throw new Error(`Collection with id '${e}' not found`);return t}addCollection(e,t){if(this.isDisposed)throw new Error("SyncManager is disposed");this.collections.set(t.name,{collection:e,options:t,readyPromise:e.ready(),syncPaused:!0});const s=a=>{for(const o of this.remoteChanges)if(o!=null&&o.collectionName===a.collectionName&&o.type===a.type&&!(a.type==="remove"&&o.data!==a.data)&&o.data.id===a.data.id)return!0;return!1},n=(a,o)=>{const r=[...this.remoteChanges];for(let c=0;c<r.length;c+=1){const i=r[c];i!=null&&i.collectionName===a&&(i.type==="remove"&&i.data!==o||i.data.id===o&&(r[c]=null))}this.remoteChanges=r.filter(c=>c!=null)};e.on("added",a=>{if(s({collectionName:t.name,type:"insert",data:a})){n(t.name,a.id);return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"insert",data:a}).then(()=>{this.getCollectionProperties(t.name).syncPaused||this.schedulePush(t.name)}).catch(o=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,o)})}),e.on("changed",({id:a},o)=>{const r={id:a,modifier:o};if(s({collectionName:t.name,type:"update",data:r})){n(t.name,a);return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"update",data:r}).then(()=>{this.getCollectionProperties(t.name).syncPaused||this.schedulePush(t.name)}).catch(c=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,c)})}),e.on("removed",({id:a})=>{if(s({collectionName:t.name,type:"remove",data:a})){n(t.name,a);return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"remove",data:a}).then(()=>{this.getCollectionProperties(t.name).syncPaused||this.schedulePush(t.name)}).catch(o=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,o)})}),this.options.autostart&&this.startSync(t.name).catch(a=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,a)})}flushScheduledPushes(){this.scheduledPushes.forEach(e=>{this.pushChanges(e).catch(()=>{})}),this.scheduledPushes.clear()}schedulePush(e){this.scheduledPushes.add(e),this.debouncedFlush()}async startAll(){await Promise.all([...this.collections.keys()].map(e=>this.startSync(e)))}async startSync(e){const t=this.getCollectionProperties(e);if(!t.syncPaused)return;this.schedulePush(e);const s=this.options.registerRemoteChange?await this.options.registerRemoteChange(t.options,async n=>{await(n==null?this.sync(e):this.getSyncQueue(e).add(async()=>{const a=Date.now(),o=await this.syncOperations.insert({start:a,collectionName:e,instanceId:this.instanceId,status:"active"});await this.syncWithData(e,n).then(async()=>{await this.syncOperations.removeMany({id:{$ne:o},collectionName:e,$or:[{end:{$lte:a}},{status:"active"}]}),await this.syncOperations.updateOne({id:o},{$set:{status:"done",end:Date.now()}})}).catch(async r=>{throw this.options.onError&&this.options.onError(this.getCollectionProperties(e).options,r),await this.syncOperations.updateOne({id:o},{$set:{status:"error",end:Date.now(),error:r.stack||r.message}}),r})}))}):void 0;this.collections.set(e,{...t,syncPaused:!1,cleanupFunction:s})}async pauseAll(){await Promise.all([...this.collections.keys()].map(e=>this.pauseSync(e)))}async pauseSync(e){const t=this.getCollectionProperties(e);t.syncPaused||(t.cleanupFunction&&await t.cleanupFunction(),this.collections.set(e,{...t,cleanupFunction:void 0,syncPaused:!0}))}async syncAll(){if(this.isDisposed)throw new Error("SyncManager is disposed");const e=[];if(await Promise.all([...this.collections.keys()].map(t=>this.sync(t).catch(s=>{e.push({id:t,error:s})}))),e.length>0)throw new Error(`Error while syncing collections:
2
2
  ${e.map(t=>`${t.id}: ${t.error.message}`).join(`
3
3
 
4
- `)}`)}isSyncing(e,t){const s=this.syncOperations.findOne({...e?{collectionName:e}:{},status:"active"},{fields:{status:1},async:t});return s instanceof Promise?s.then(o=>o!=null):s!=null}async isReady(){await this.collectionsReady}async sync(e,t={}){if(this.isDisposed)throw new Error("SyncManager is disposed");await this.isReady();const{options:s,readyPromise:o}=this.getCollectionProperties(e);await o;const n=await this.syncOperations.find({collectionName:e,instanceId:this.instanceId,status:"active"},{reactive:!1,async:!0}).count()>0,a=Date.now();let r=null;await new Promise(i=>{setTimeout(i,0)});const c=async()=>{const i=await this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1,async:!0});if(t?.onlyWithChanges&&await this.changes.find({collectionName:e,time:{$lte:a}},{sort:{time:1},reactive:!1,async:!0}).count()===0)return;n||(r=await this.syncOperations.insert({start:a,collectionName:e,instanceId:this.instanceId,status:"active"}));const h=await this.options.pull(s,{lastFinishedSyncStart:i?.start,lastFinishedSyncEnd:i?.end});await this.syncWithData(e,h)};await(t?.force?c():this.getSyncQueue(e).add(c)).catch(async i=>{throw r!=null&&(this.options.onError&&this.options.onError(s,i),await this.syncOperations.updateOne({id:r},{$set:{status:"error",end:Date.now(),error:i.stack||i.message}})),i}),r!=null&&(await this.syncOperations.removeMany({id:{$ne:r},collectionName:e,$or:[{end:{$lte:a}},{status:"active"}]}),await this.syncOperations.updateOne({id:r},{$set:{status:"done",end:Date.now()}}))}async pushChanges(e){await this.sync(e,{onlyWithChanges:!0})}async syncWithData(e,t){const{collection:s,options:o}=this.getCollectionProperties(e),n=Date.now(),a=await this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1,async:!0}),r=await this.snapshots.findOne({collectionName:e},{sort:{time:-1},reactive:!1,async:!0}),c=await this.changes.find({collectionName:e,time:{$lte:n}},{sort:{time:1},reactive:!1,async:!0}).fetch();await E({changes:c,lastSnapshot:r?.items,data:t,pull:()=>this.options.pull(o,{lastFinishedSyncStart:a?.start,lastFinishedSyncEnd:a?.end}),push:i=>this.options.push(o,{changes:i,rawChanges:c}),insert:async i=>{this.remoteChanges.push({collectionName:e,type:"insert",data:i},{collectionName:e,type:"update",data:{id:i.id,modifier:{$set:i}}}),await s.replaceOne({id:i.id},i,{upsert:!0})},update:async(i,h)=>{this.remoteChanges.push({collectionName:e,type:"insert",data:{id:i,...h.$set}},{collectionName:e,type:"update",data:{id:i,modifier:h}}),await s.updateOne({id:i},{...h,$setOnInsert:{id:i}},{upsert:!0})},remove:async i=>{await s.find({id:i},{reactive:!1,async:!0}).count()>0&&(this.remoteChanges.push({collectionName:e,type:"remove",data:i}),await s.removeOne({id:i}))},batch:async i=>s.batch(async()=>{await i()})}).then(async i=>{if(await this.snapshots.removeMany({collectionName:e,time:{$lte:n}}),await this.changes.removeMany({collectionName:e,id:{$in:c.map(d=>d.id)}}),await this.snapshots.insert({time:n,collectionName:e,items:i}),await new Promise(d=>{setTimeout(d,0)}),await this.changes.find({collectionName:e},{reactive:!1,async:!0}).count()>0){await this.sync(e,{force:!0,onlyWithChanges:!0});return}const y=await s.find({id:{$nin:i.map(d=>d.id)}},{reactive:!1,async:!0}).map(d=>d.id);await s.batch(async()=>{await Promise.all(i.map(async d=>{this.remoteChanges.push({collectionName:e,type:"insert",data:d},{collectionName:e,type:"update",data:{id:d.id,modifier:{$set:d}}}),await s.replaceOne({id:d.id},d,{upsert:!0})})),await Promise.all(y.map(async d=>{await s.removeOne({id:d})}))})})}}f.SyncManager=$,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})}));
4
+ `)}`)}isSyncing(e,t){const s=this.syncOperations.findOne({...e?{collectionName:e}:{},status:"active"},{fields:{status:1},async:t});return s instanceof Promise?s.then(n=>n!=null):s!=null}async isReady(){await this.collectionsReady}async sync(e,t={}){if(this.isDisposed)throw new Error("SyncManager is disposed");await this.isReady();const{options:s,readyPromise:n}=this.getCollectionProperties(e);await n;const a=await this.syncOperations.find({collectionName:e,instanceId:this.instanceId,status:"active"},{reactive:!1,async:!0}).count()>0,o=Date.now();let r=null;await new Promise(i=>{setTimeout(i,0)});const c=async()=>{const i=await this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1,async:!0});if(t?.onlyWithChanges&&await this.changes.find({collectionName:e,time:{$lte:o}},{sort:{time:1},reactive:!1,async:!0}).count()===0)return;a||(r=await this.syncOperations.insert({start:o,collectionName:e,instanceId:this.instanceId,status:"active"}));const h=await this.options.pull(s,{lastFinishedSyncStart:i?.start,lastFinishedSyncEnd:i?.end});await this.syncWithData(e,h)};await(t?.force?c():this.getSyncQueue(e).add(c)).catch(async i=>{throw r!=null&&(this.options.onError&&this.options.onError(s,i),await this.syncOperations.updateOne({id:r},{$set:{status:"error",end:Date.now(),error:i.stack||i.message}})),i}),r!=null&&(await this.syncOperations.removeMany({id:{$ne:r},collectionName:e,$or:[{end:{$lte:o}},{status:"active"}]}),await this.syncOperations.updateOne({id:r},{$set:{status:"done",end:Date.now()}}))}async pushChanges(e){await this.sync(e,{onlyWithChanges:!0})}async syncWithData(e,t){const{collection:s,options:n}=this.getCollectionProperties(e),a=Date.now(),o=await this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1,async:!0}),r=await this.snapshots.findOne({collectionName:e},{sort:{time:-1},reactive:!1,async:!0}),c=await this.changes.find({collectionName:e,time:{$lte:a}},{sort:{time:1},reactive:!1,async:!0}).fetch();await E({changes:c,lastSnapshot:r?.items,data:t,pull:()=>this.options.pull(n,{lastFinishedSyncStart:o?.start,lastFinishedSyncEnd:o?.end}),push:i=>this.options.push(n,{changes:i,rawChanges:c}),insert:async i=>{this.remoteChanges.push({collectionName:e,type:"insert",data:i},{collectionName:e,type:"update",data:{id:i.id,modifier:{$set:i}}}),await s.replaceOne({id:i.id},i,{upsert:!0})},update:async(i,h)=>{this.remoteChanges.push({collectionName:e,type:"insert",data:{id:i,...h.$set}},{collectionName:e,type:"update",data:{id:i,modifier:h}}),await s.updateOne({id:i},{...h,$setOnInsert:{id:i}},{upsert:!0})},remove:async i=>{await s.find({id:i},{reactive:!1,async:!0}).count()>0&&(this.remoteChanges.push({collectionName:e,type:"remove",data:i}),await s.removeOne({id:i}))},batch:async i=>s.batch(async()=>{await i()})}).then(async i=>{if(await this.snapshots.removeMany({collectionName:e,time:{$lte:a}}),await this.changes.removeMany({collectionName:e,id:{$in:c.map(d=>d.id)}}),await this.snapshots.insert({time:a,collectionName:e,items:i}),await new Promise(d=>{setTimeout(d,0)}),await this.changes.find({collectionName:e},{reactive:!1,async:!0}).count()>0){await this.sync(e,{force:!0,onlyWithChanges:!0});return}const y=await s.find({id:{$nin:i.map(d=>d.id)}},{reactive:!1,async:!0}).map(d=>d.id);await s.batch(async()=>{await Promise.all(i.map(async d=>{this.remoteChanges.push({collectionName:e,type:"insert",data:d},{collectionName:e,type:"update",data:{id:d.id,modifier:{$set:d}}}),await s.replaceOne({id:d.id},d,{upsert:!0})})),await Promise.all(y.map(async d=>{await s.removeOne({id:d})}))})})}}f.SyncManager=$,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})}));
5
5
  //# sourceMappingURL=index.umd.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/utils/debounce.ts","../src/utils/PromiseQueue.ts","../src/computeChanges.ts","../src/getSnapshot.ts","../src/applyChanges.ts","../src/sync.ts","../src/SyncManager.ts"],"sourcesContent":["/**\n * Debounces a function.\n * @param fn Function to debounce\n * @param wait Time to wait before calling the function.\n * @param [options] Debounce options\n * @param [options.leading] Whether to call the function on the leading edge of the wait interval.\n * @param [options.trailing] Whether to call the function on the trailing edge of the wait interval.\n * @returns The debounced function.\n */\nexport default function debounce(fn, wait, options = {}) {\n let timeout;\n let result;\n const { leading = false, trailing = true } = options;\n /**\n * The debounced function that will be returned.\n * @param this The context to bind the function to.\n * @param args The arguments to pass to the function.\n * @returns The result of the debounced function.\n */\n function debounced(...args) {\n const shouldCallImmediately = leading && !timeout;\n const shouldCallTrailing = trailing && !timeout;\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(() => {\n timeout = null;\n if (trailing && !shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n }, wait);\n if (shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n else if (!shouldCallTrailing) {\n result = null;\n }\n return result;\n }\n return debounced;\n}\n","/**\n * Class for queuing promises to be executed one after the other.\n * This is useful for tasks that should not be executed in parallel.\n * @example\n * const queue = new PromiseQueue();\n * queue.add(() => fetch('https://example.com/api/endpoint1'));\n * queue.add(() => fetch('https://example.com/api/endpoint2'));\n * // The second fetch will only be executed after the first one is done.\n */\nexport default class PromiseQueue {\n queue = [];\n pendingPromise = false;\n /**\n * Method to add a new promise to the queue and returns a promise that resolves when this task is done\n * @param task Function that returns a promise that will be added to the queue\n * @returns Promise that resolves when the task is done\n */\n add(task) {\n return new Promise((resolve, reject) => {\n // Wrap the task with the resolve and reject to control its completion from the outside\n this.queue.push(() => task()\n .then(resolve)\n .catch((error) => {\n reject(error);\n throw error;\n }));\n this.dequeue();\n });\n }\n /**\n * Method to check if there is a pending promise in the queue\n * @returns True if there is a pending promise, false otherwise\n */\n hasPendingPromise() {\n return this.pendingPromise;\n }\n /**\n * Method to process the queue\n */\n dequeue() {\n if (this.pendingPromise || this.queue.length === 0) {\n return;\n }\n const task = this.queue.shift();\n if (!task)\n return;\n this.pendingPromise = true;\n task()\n .then(() => {\n this.pendingPromise = false;\n this.dequeue();\n })\n .catch(() => {\n this.pendingPromise = false;\n this.dequeue();\n });\n }\n}\n","import { isEqual } from '@signaldb/core';\n/**\n * Computes the modified fields between two items recursively.\n * @param oldItem The old item\n * @param newItem The new item\n * @returns The modified fields\n */\nexport function computeModifiedFields(oldItem, newItem) {\n const modifiedFields = [];\n const oldKeys = Object.keys(oldItem);\n const newKeys = Object.keys(newItem);\n const allKeys = new Set([...oldKeys, ...newKeys]);\n for (const key of allKeys) {\n if (newItem[key] !== oldItem[key]) {\n if (typeof newItem[key] === 'object' && typeof oldItem[key] === 'object' && newItem[key] != null && oldItem[key] != null) {\n const nestedModifiedFields = computeModifiedFields(oldItem[key], newItem[key]);\n for (const nestedField of nestedModifiedFields) {\n modifiedFields.push(`${key}.${nestedField}`);\n }\n }\n else {\n modifiedFields.push(key);\n }\n }\n }\n return modifiedFields;\n}\n/**\n * Compute changes between two arrays of items.\n * @param oldItems Array of the old items\n * @param newItems Array of the new items\n * @returns The changeset\n */\nexport default function computeChanges(oldItems, newItems) {\n const added = [];\n const modified = [];\n const modifiedFields = new Map();\n const removed = [];\n const oldItemsMap = new Map(oldItems.map(item => [item.id, item]));\n const newItemsMap = new Map(newItems.map(item => [item.id, item]));\n for (const [id, oldItem] of oldItemsMap) {\n const newItem = newItemsMap.get(id);\n if (!newItem) {\n removed.push(oldItem);\n }\n else if (!isEqual(newItem, oldItem)) {\n modifiedFields.set(newItem.id, computeModifiedFields(oldItem, newItem));\n modified.push(newItem);\n }\n }\n for (const [id, newItem] of newItemsMap) {\n if (!oldItemsMap.has(id)) {\n added.push(newItem);\n }\n }\n return {\n added,\n modified,\n modifiedFields,\n removed,\n };\n}\n","/**\n * Gets the snapshot of items from the last snapshot and the changes.\n * @param lastSnapshot The last snapshot of items\n * @param data The changes to apply to the last snapshot\n * @returns The new snapshot of items\n */\nexport default function getSnapshot(lastSnapshot, data) {\n if (data.items != null)\n return data.items;\n const items = lastSnapshot || [];\n data.changes.added.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.modified.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.removed.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index !== -1)\n items.splice(index, 1);\n });\n return items;\n}\n","import { modify } from '@signaldb/core';\n/**\n * applies changes to a collection of items\n * @param items The items to apply the changes to\n * @param changes The changes to apply to the items\n * @returns The new items after applying the changes\n */\nexport default function applyChanges(items, changes) {\n // Create initial map of items by ID\n const itemMap = new Map(items.map(item => [item.id, item]));\n changes.forEach((change) => {\n if (change.type === 'remove') {\n itemMap.delete(change.data);\n }\n else if (change.type === 'insert') {\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem ? { ...existingItem, ...change.data } : change.data);\n }\n else { // change.type === 'update'\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem\n ? modify(existingItem, change.data.modifier)\n : modify({ id: change.data.id }, change.data.modifier));\n }\n });\n // Convert map back to array\n return [...itemMap.values()];\n}\n","import computeChanges from './computeChanges';\nimport getSnapshot from './getSnapshot';\nimport applyChanges from './applyChanges';\n/**\n * Checks if there are any changes in the given changeset.\n * @param changes The changeset to check.\n * @returns True if there are changes, false otherwise.\n */\nfunction hasChanges(changes) {\n return changes.added.length > 0\n || changes.modified.length > 0\n || changes.removed.length > 0;\n}\n/**\n * Checks if there is a difference between the old items and the new items.\n * @param oldItems The old items.\n * @param newItems The new items.\n * @returns True if there is a difference, false otherwise.\n */\nfunction hasDifference(oldItems, newItems) {\n return hasChanges(computeChanges(oldItems, newItems));\n}\n/**\n * Does a sync operation based on the provided options. If changes are supplied, these will be rebased on the new data.\n * Afterwards the push method will be called with the remaining changes. A new snapshot will be created and returned.\n * @param options Sync options\n * @param options.changes Changes to call the push method with\n * @param [options.lastSnapshot] The last snapshot\n * @param options.data The new data\n * @param options.pull Method to pull new data\n * @param options.push Method to push changes\n * @param options.insert Method to insert an item\n * @param options.update Method to update an item\n * @param options.remove Method to remove an item\n * @param options.batch Method to batch multiple operations\n * @returns The new snapshot\n */\nexport default async function sync({ changes, lastSnapshot, data, pull, push, insert, update, remove, batch, }) {\n let newData = data;\n let previousSnapshot = lastSnapshot || [];\n let newSnapshot = getSnapshot(lastSnapshot, newData);\n if (changes.length > 0) {\n // apply changes on last snapshot and check if there is a difference\n const lastSnapshotWithChanges = applyChanges(previousSnapshot, changes);\n if (hasDifference(previousSnapshot, lastSnapshotWithChanges)) {\n // if yes, apply the changes on the newSnapshot and check if there is a difference\n const newSnapshotWithChanges = applyChanges(newSnapshot, changes);\n const changesToPush = computeChanges(newSnapshot, newSnapshotWithChanges);\n if (hasChanges(changesToPush)) {\n // if yes, push the changes to the server\n await push(changesToPush);\n // pull new data afterwards to ensure that all server changes are applied\n newData = await pull();\n newSnapshot = getSnapshot(newSnapshot, newData);\n }\n previousSnapshot = lastSnapshotWithChanges;\n }\n }\n // apply the new changes on the collection\n const newChanges = newData.changes == null\n ? computeChanges(previousSnapshot, newData.items)\n : newData.changes;\n await batch(async () => {\n await Promise.all(newChanges.added.map(item => insert(item)));\n await Promise.all(newChanges.modified.map(item => update(item.id, { $set: item })));\n await Promise.all(newChanges.removed.map(item => remove(item.id)));\n });\n return newSnapshot;\n}\n","import { DefaultDataAdapter, Collection, randomId } from '@signaldb/core';\nimport debounce from './utils/debounce';\nimport PromiseQueue from './utils/PromiseQueue';\nimport sync from './sync';\n/**\n * Class to manage syncing of collections.\n * @template CollectionOptions\n * @template ItemType\n * @template IdType\n * @example\n * const syncManager = new SyncManager({\n * pull: async (collectionOptions) => {\n * const response = await fetch(`/api/collections/${collectionOptions.name}`)\n * return await response.json()\n * },\n * push: async (collectionOptions, { changes }) => {\n * await fetch(`/api/collections/${collectionOptions.name}`, {\n * method: 'POST',\n * body: JSON.stringify(changes),\n * })\n * },\n * })\n *\n * const collection = new Collection()\n * syncManager.addCollection(collection, {\n * name: 'todos',\n * })\n *\n * syncManager.sync('todos')\n */\nexport default class SyncManager {\n options;\n collections = new Map();\n changes;\n snapshots;\n syncOperations;\n scheduledPushes = new Set();\n remoteChanges = [];\n syncQueues = new Map();\n collectionsReady;\n isDisposed = false;\n instanceId = randomId();\n id;\n debouncedFlush;\n /**\n * @param options Collection options\n * @param options.pull Function to pull data from remote source.\n * @param options.push Function to push data to remote source.\n * @param [options.registerRemoteChange] Function to register a callback for remote changes.\n * @param [options.id] Unique identifier for this sync manager. Only nessesary if you have multiple sync managers.\n * @param [options.storageAdapter] Storage adapter to use for storing changes, snapshots and sync operations.\n * @param [options.reactivity] Reactivity adapter to use for reactivity.\n * @param [options.onError] Function to handle errors that occur async during syncing.\n * @param [options.autostart] Whether to automatically start syncing new collections.\n * @param [options.debounceTime] The time in milliseconds to debounce push operations.\n */\n constructor(options) {\n this.options = {\n autostart: true,\n ...options,\n };\n this.id = this.options.id || 'default-sync-manager';\n const { reactivity } = this.options;\n const dataAdapter = this.options.dataAdapter ?? new DefaultDataAdapter();\n this.changes = new Collection(`${this.options.id}-changes`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.snapshots = new Collection(`${this.options.id}-snapshots`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.syncOperations = new Collection(`${this.options.id}-sync-operations`, dataAdapter, {\n indices: ['collectionName', 'status'],\n reactivity,\n });\n this.collectionsReady = Promise.all([\n this.syncOperations.isReady(),\n this.changes.isReady(),\n this.snapshots.isReady(),\n ]).then(() => { });\n this.changes.setMaxListeners(1000);\n this.snapshots.setMaxListeners(1000);\n this.syncOperations.setMaxListeners(1000);\n this.debouncedFlush = debounce(this.flushScheduledPushes, this.options.debounceTime ?? 100);\n }\n getSyncQueue(name) {\n if (this.syncQueues.get(name) == null) {\n this.syncQueues.set(name, new PromiseQueue());\n }\n return this.syncQueues.get(name);\n }\n /**\n * Clears all internal data structures\n */\n async dispose() {\n this.collections.clear();\n this.syncQueues.clear();\n this.remoteChanges.splice(0);\n await Promise.all([\n this.changes.dispose(),\n this.snapshots.dispose(),\n this.syncOperations.dispose(),\n ]);\n this.isDisposed = true;\n }\n /**\n * Gets a collection with it's options by name\n * @deprecated Use getCollectionProperties instead.\n * @param name Name of the collection\n * @throws Will throw an error if the name wasn't found\n * @returns Tuple of collection and options\n */\n getCollection(name) {\n const { collection, options } = this.getCollectionProperties(name);\n return [collection, options];\n }\n /**\n * Gets collection options by name\n * @param name Name of the collection\n * @throws Will throw an error if the name wasn't found\n * @returns An object of all properties of the collection\n */\n getCollectionProperties(name) {\n const collectionParameters = this.collections.get(name);\n if (collectionParameters == null)\n throw new Error(`Collection with id '${name}' not found`);\n return collectionParameters;\n }\n /**\n * Adds a collection to the sync manager.\n * @param collection Collection to add\n * @param options Options for the collection. The object needs at least a `name` property.\n * @param options.name Unique name of the collection\n */\n addCollection(collection, options) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n this.collections.set(options.name, {\n collection,\n options,\n readyPromise: collection.ready(),\n syncPaused: true, // always start paused as the autostart will start it\n });\n const hasRemoteChange = (change) => {\n for (const remoteChange of this.remoteChanges) {\n if (remoteChange == null)\n continue;\n if (remoteChange.collectionName !== change.collectionName)\n continue;\n if (remoteChange.type !== change.type)\n continue;\n if (change.type === 'remove' && remoteChange.data !== change.data)\n continue;\n if (remoteChange.data.id !== change.data.id)\n continue;\n return true;\n }\n return false;\n };\n const removeRemoteChanges = (collectionName, id) => {\n const newRemoteChanges = [...this.remoteChanges];\n for (let i = 0; i < newRemoteChanges.length; i += 1) {\n const item = newRemoteChanges[i];\n if (item == null)\n continue;\n if (item.collectionName !== collectionName)\n continue;\n if (item.type === 'remove' && item.data !== id)\n continue;\n if (item.data.id !== id)\n continue;\n newRemoteChanges[i] = null;\n }\n this.remoteChanges = newRemoteChanges.filter(item => item != null);\n };\n collection.on('added', (item) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'insert', data: item })) {\n removeRemoteChanges(options.name, item.id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('changed', ({ id }, modifier) => {\n const data = { id, modifier };\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'update', data })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('removed', ({ id }) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'remove', data: id })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n if (this.options.autostart) {\n this.startSync(options.name)\n .catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n }\n }\n flushScheduledPushes() {\n this.scheduledPushes.forEach((name) => {\n this.pushChanges(name).catch(() => { });\n });\n this.scheduledPushes.clear();\n }\n schedulePush(name) {\n this.scheduledPushes.add(name);\n this.debouncedFlush();\n }\n /**\n * Setup all collections to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n */\n async startAll() {\n await Promise.all([...this.collections.keys()].map(id => this.startSync(id)));\n }\n /**\n * Setup a collection to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n * @param name Name of the collection\n */\n async startSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (!collectionParameters.syncPaused)\n return; // already started\n this.schedulePush(name); // push changes that were made while paused\n const cleanupFunction = this.options.registerRemoteChange\n ? await this.options.registerRemoteChange(collectionParameters.options, async (data) => {\n if (data == null) {\n await this.sync(name);\n }\n else {\n const syncTime = Date.now();\n const syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n await this.syncWithData(name, data)\n .then(async () => {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch(async (error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n throw error;\n });\n }\n })\n : undefined;\n this.collections.set(name, {\n ...collectionParameters,\n syncPaused: false,\n cleanupFunction,\n });\n }\n /**\n * Pauses the sync process for all collections.\n * This means that the collections will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n */\n async pauseAll() {\n await Promise.all([...this.collections.keys()].map(id => this.pauseSync(id)));\n }\n /**\n * Pauses the sync process for a collection.\n * This means that the collection will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n * @param name Name of the collection\n */\n async pauseSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (collectionParameters.syncPaused)\n return; // already paused\n if (collectionParameters.cleanupFunction)\n await collectionParameters.cleanupFunction();\n this.collections.set(name, {\n ...collectionParameters,\n cleanupFunction: undefined,\n syncPaused: true,\n });\n }\n /**\n * Starts the sync process for all collections\n */\n async syncAll() {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n const errors = [];\n await Promise.all([...this.collections.keys()].map(id => this.sync(id).catch((error) => {\n errors.push({ id, error });\n })));\n if (errors.length > 0)\n throw new Error(`Error while syncing collections:\\n${errors.map(error => `${error.id}: ${error.error.message}`).join('\\n\\n')}`);\n }\n /**\n * Checks if a collection is currently beeing synced\n * @param [name] Name of the collection. If not provided, it will check if any collection is currently beeing synced.\n * @param [async] If true, it will check for active syncs in the database. This is useful if you have multiple instances of the application running.\n * @returns True if the collection is currently beeing synced, false otherwise. If async is true, it will return a promise that resolves to true or false.\n */\n isSyncing(name, async) {\n const itemOrPromise = this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 }, async });\n if (itemOrPromise instanceof Promise) {\n return itemOrPromise\n .then(item => item != null);\n }\n return (itemOrPromise != null);\n }\n /**\n * Checks if the sync manager is ready to sync.\n * @returns A promise that resolves when the sync manager is ready to sync.\n */\n async isReady() {\n await this.collectionsReady;\n }\n /**\n * Starts the sync process for a collection\n * @param name Name of the collection\n * @param options Options for the sync process.\n * @param options.force If true, the sync process will be started even if there are no changes and onlyWithChanges is true.\n * @param options.onlyWithChanges If true, the sync process will only be started if there are changes.\n */\n async sync(name, options = {}) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n await this.isReady();\n const { options: collectionOptions, readyPromise } = this.getCollectionProperties(name);\n await readyPromise;\n const hasActiveSyncs = await this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\n async: true,\n }).count() > 0;\n const syncTime = Date.now();\n let syncId = null;\n // schedule for next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const doSync = async () => {\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n }\n const data = await this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n });\n await this.syncWithData(name, data);\n };\n await (options?.force ? doSync() : this.getSyncQueue(name).add(doSync))\n .catch(async (error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n }\n throw error;\n });\n if (syncId != null) {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n }\n }\n /**\n * Starts the push process for a collection (sync process but only if there are changes)\n * @param name Name of the collection\n */\n async pushChanges(name) {\n await this.sync(name, {\n onlyWithChanges: true,\n });\n }\n async syncWithData(name, data) {\n const { collection, options: collectionOptions } = this.getCollectionProperties(name);\n const syncTime = Date.now();\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n const lastSnapshot = await this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n async: true,\n });\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).fetch();\n await sync({\n changes: currentChanges,\n lastSnapshot: lastSnapshot?.items,\n data,\n pull: () => this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n }),\n push: changes => this.options.push(collectionOptions, {\n changes,\n rawChanges: currentChanges,\n }),\n insert: async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n },\n update: async (itemId, modifier) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: { id: itemId, ...modifier.$set },\n }, {\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n await collection.updateOne({ id: itemId }, {\n ...modifier,\n $setOnInsert: { id: itemId },\n }, { upsert: true });\n },\n remove: async (itemId) => {\n const itemExists = await collection.find({\n id: itemId,\n }, { reactive: false, async: true }).count() > 0;\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n await collection.removeOne({ id: itemId });\n },\n batch: async (fn) => {\n return collection.batch(async () => {\n await fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n await this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n await this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n await this.snapshots.insert({\n time: syncTime,\n collectionName: name,\n items: snapshot,\n });\n // delay sync operation update to next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const hasChanges = await this.changes.find({\n collectionName: name,\n }, { reactive: false, async: true }).count() > 0;\n if (hasChanges) {\n // check if there are unsynced changes to push\n // and sync again if there are any\n await this.sync(name, {\n force: true,\n onlyWithChanges: true,\n });\n return;\n }\n // if there are no unsynced changes apply the last snapshot\n // to make sure that collection and snapshot are in sync\n // find all items that are not in the snapshot\n const nonExistingItemIds = await collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n async: true,\n }).map(item => item.id);\n await collection.batch(async () => {\n // update all items that are in the snapshot\n await Promise.all(snapshot.map(async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n }));\n // remove all items that are not in the snapshot\n await Promise.all(nonExistingItemIds.map(async (id) => {\n await collection.removeOne({ id });\n }));\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","task","resolve","reject","error","computeModifiedFields","oldItem","newItem","modifiedFields","oldKeys","newKeys","allKeys","key","nestedModifiedFields","nestedField","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","itemMap","change","existingItem","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","reactivity","dataAdapter","DefaultDataAdapter","Collection","name","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChanges","collectionName","newRemoteChanges","modifier","cleanupFunction","syncTime","syncId","errors","async","itemOrPromise","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/utils/debounce.ts","../src/utils/PromiseQueue.ts","../src/computeChanges.ts","../src/getSnapshot.ts","../src/applyChanges.ts","../src/sync.ts","../src/SyncManager.ts"],"sourcesContent":["/**\n * Debounces a function.\n * @param fn Function to debounce\n * @param wait Time to wait before calling the function.\n * @param [options] Debounce options\n * @param [options.leading] Whether to call the function on the leading edge of the wait interval.\n * @param [options.trailing] Whether to call the function on the trailing edge of the wait interval.\n * @returns The debounced function.\n */\nexport default function debounce(fn, wait, options = {}) {\n let timeout;\n let result;\n const { leading = false, trailing = true } = options;\n /**\n * The debounced function that will be returned.\n * @param this The context to bind the function to.\n * @param args The arguments to pass to the function.\n * @returns The result of the debounced function.\n */\n function debounced(...args) {\n const shouldCallImmediately = leading && !timeout;\n const shouldCallTrailing = trailing && !timeout;\n if (timeout) {\n clearTimeout(timeout);\n }\n timeout = setTimeout(() => {\n timeout = null;\n if (trailing && !shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n }, wait);\n if (shouldCallImmediately) {\n result = fn.apply(this, args);\n }\n else if (!shouldCallTrailing) {\n result = null;\n }\n return result;\n }\n return debounced;\n}\n","/**\n * Class for queuing promises to be executed one after the other.\n * This is useful for tasks that should not be executed in parallel.\n * @example\n * const queue = new PromiseQueue();\n * queue.add(() => fetch('https://example.com/api/endpoint1'));\n * queue.add(() => fetch('https://example.com/api/endpoint2'));\n * // The second fetch will only be executed after the first one is done.\n */\nexport default class PromiseQueue {\n queue = [];\n pendingPromise = false;\n /**\n * Method to add a new promise to the queue and returns a promise that resolves when this task is done\n * @param task Function that returns a promise that will be added to the queue\n * @returns Promise that resolves when the task is done\n */\n add(task) {\n return new Promise((resolve, reject) => {\n // Wrap the task with the resolve and reject to control its completion from the outside\n this.queue.push(() => task()\n .then(resolve)\n .catch((error) => {\n reject(error);\n throw error;\n }));\n this.dequeue();\n });\n }\n /**\n * Method to check if there is a pending promise in the queue\n * @returns True if there is a pending promise, false otherwise\n */\n hasPendingPromise() {\n return this.pendingPromise;\n }\n /**\n * Method to process the queue\n */\n dequeue() {\n if (this.pendingPromise || this.queue.length === 0) {\n return;\n }\n const task = this.queue.shift();\n if (!task)\n return;\n this.pendingPromise = true;\n task()\n .then(() => {\n this.pendingPromise = false;\n this.dequeue();\n })\n .catch(() => {\n this.pendingPromise = false;\n this.dequeue();\n });\n }\n}\n","import { isEqual } from '@signaldb/core';\n/**\n * Computes the modified fields between two items recursively.\n * @param oldItem The old item\n * @param newItem The new item\n * @returns The modified fields\n */\nexport function computeModifiedFields(oldItem, newItem) {\n const modifiedFields = [];\n const oldKeys = Object.keys(oldItem);\n const newKeys = Object.keys(newItem);\n const allKeys = new Set([...oldKeys, ...newKeys]);\n for (const key of allKeys) {\n if (newItem[key] !== oldItem[key]) {\n if (typeof newItem[key] === 'object' && typeof oldItem[key] === 'object' && newItem[key] != null && oldItem[key] != null) {\n const nestedModifiedFields = computeModifiedFields(oldItem[key], newItem[key]);\n for (const nestedField of nestedModifiedFields) {\n modifiedFields.push(`${key}.${nestedField}`);\n }\n }\n else {\n modifiedFields.push(key);\n }\n }\n }\n return modifiedFields;\n}\n/**\n * Compute changes between two arrays of items.\n * @param oldItems Array of the old items\n * @param newItems Array of the new items\n * @returns The changeset\n */\nexport default function computeChanges(oldItems, newItems) {\n const added = [];\n const modified = [];\n const modifiedFields = new Map();\n const removed = [];\n const oldItemsMap = new Map(oldItems.map(item => [item.id, item]));\n const newItemsMap = new Map(newItems.map(item => [item.id, item]));\n for (const [id, oldItem] of oldItemsMap) {\n const newItem = newItemsMap.get(id);\n if (!newItem) {\n removed.push(oldItem);\n }\n else if (!isEqual(newItem, oldItem)) {\n modifiedFields.set(newItem.id, computeModifiedFields(oldItem, newItem));\n modified.push(newItem);\n }\n }\n for (const [id, newItem] of newItemsMap) {\n if (!oldItemsMap.has(id)) {\n added.push(newItem);\n }\n }\n return {\n added,\n modified,\n modifiedFields,\n removed,\n };\n}\n","/**\n * Gets the snapshot of items from the last snapshot and the changes.\n * @param lastSnapshot The last snapshot of items\n * @param data The changes to apply to the last snapshot\n * @returns The new snapshot of items\n */\nexport default function getSnapshot(lastSnapshot, data) {\n if (data.items != null)\n return data.items;\n const items = lastSnapshot || [];\n data.changes.added.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.modified.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index === -1) {\n items.push(item);\n }\n else {\n items[index] = item;\n }\n });\n data.changes.removed.forEach((item) => {\n const index = items.findIndex(i => i.id === item.id);\n if (index !== -1)\n items.splice(index, 1);\n });\n return items;\n}\n","import { modify } from '@signaldb/core';\n/**\n * applies changes to a collection of items\n * @param items The items to apply the changes to\n * @param changes The changes to apply to the items\n * @returns The new items after applying the changes\n */\nexport default function applyChanges(items, changes) {\n // Create initial map of items by ID\n const itemMap = new Map(items.map(item => [item.id, item]));\n changes.forEach((change) => {\n if (change.type === 'remove') {\n itemMap.delete(change.data);\n }\n else if (change.type === 'insert') {\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem ? { ...existingItem, ...change.data } : change.data);\n }\n else { // change.type === 'update'\n const existingItem = itemMap.get(change.data.id);\n itemMap.set(change.data.id, existingItem\n ? modify(existingItem, change.data.modifier)\n : modify({ id: change.data.id }, change.data.modifier));\n }\n });\n // Convert map back to array\n return [...itemMap.values()];\n}\n","import computeChanges from './computeChanges';\nimport getSnapshot from './getSnapshot';\nimport applyChanges from './applyChanges';\n/**\n * Checks if there are any changes in the given changeset.\n * @param changes The changeset to check.\n * @returns True if there are changes, false otherwise.\n */\nfunction hasChanges(changes) {\n return changes.added.length > 0\n || changes.modified.length > 0\n || changes.removed.length > 0;\n}\n/**\n * Checks if there is a difference between the old items and the new items.\n * @param oldItems The old items.\n * @param newItems The new items.\n * @returns True if there is a difference, false otherwise.\n */\nfunction hasDifference(oldItems, newItems) {\n return hasChanges(computeChanges(oldItems, newItems));\n}\n/**\n * Does a sync operation based on the provided options. If changes are supplied, these will be rebased on the new data.\n * Afterwards the push method will be called with the remaining changes. A new snapshot will be created and returned.\n * @param options Sync options\n * @param options.changes Changes to call the push method with\n * @param [options.lastSnapshot] The last snapshot\n * @param options.data The new data\n * @param options.pull Method to pull new data\n * @param options.push Method to push changes\n * @param options.insert Method to insert an item\n * @param options.update Method to update an item\n * @param options.remove Method to remove an item\n * @param options.batch Method to batch multiple operations\n * @returns The new snapshot\n */\nexport default async function sync({ changes, lastSnapshot, data, pull, push, insert, update, remove, batch, }) {\n let newData = data;\n let previousSnapshot = lastSnapshot || [];\n let newSnapshot = getSnapshot(lastSnapshot, newData);\n if (changes.length > 0) {\n // apply changes on last snapshot and check if there is a difference\n const lastSnapshotWithChanges = applyChanges(previousSnapshot, changes);\n if (hasDifference(previousSnapshot, lastSnapshotWithChanges)) {\n // if yes, apply the changes on the newSnapshot and check if there is a difference\n const newSnapshotWithChanges = applyChanges(newSnapshot, changes);\n const changesToPush = computeChanges(newSnapshot, newSnapshotWithChanges);\n if (hasChanges(changesToPush)) {\n // if yes, push the changes to the server\n await push(changesToPush);\n // pull new data afterwards to ensure that all server changes are applied\n newData = await pull();\n newSnapshot = getSnapshot(newSnapshot, newData);\n }\n previousSnapshot = lastSnapshotWithChanges;\n }\n }\n // apply the new changes on the collection\n const newChanges = newData.changes == null\n ? computeChanges(previousSnapshot, newData.items)\n : newData.changes;\n await batch(async () => {\n await Promise.all(newChanges.added.map(item => insert(item)));\n await Promise.all(newChanges.modified.map(item => update(item.id, { $set: item })));\n await Promise.all(newChanges.removed.map(item => remove(item.id)));\n });\n return newSnapshot;\n}\n","import { DefaultDataAdapter, Collection, randomId } from '@signaldb/core';\nimport debounce from './utils/debounce';\nimport PromiseQueue from './utils/PromiseQueue';\nimport sync from './sync';\n/**\n * Class to manage syncing of collections.\n * @template CollectionOptions\n * @template ItemType\n * @template IdType\n * @example\n * const syncManager = new SyncManager({\n * pull: async (collectionOptions) => {\n * const response = await fetch(`/api/collections/${collectionOptions.name}`)\n * return await response.json()\n * },\n * push: async (collectionOptions, { changes }) => {\n * await fetch(`/api/collections/${collectionOptions.name}`, {\n * method: 'POST',\n * body: JSON.stringify(changes),\n * })\n * },\n * })\n *\n * const collection = new Collection()\n * syncManager.addCollection(collection, {\n * name: 'todos',\n * })\n *\n * syncManager.sync('todos')\n */\nexport default class SyncManager {\n options;\n collections = new Map();\n changes;\n snapshots;\n syncOperations;\n scheduledPushes = new Set();\n remoteChanges = [];\n syncQueues = new Map();\n collectionsReady;\n isDisposed = false;\n instanceId = randomId();\n id;\n debouncedFlush;\n /**\n * @param options Collection options\n * @param options.pull Function to pull data from remote source.\n * @param options.push Function to push data to remote source.\n * @param [options.registerRemoteChange] Function to register a callback for remote changes.\n * @param [options.id] Unique identifier for this sync manager. Only nessesary if you have multiple sync managers.\n * @param [options.storageAdapter] Storage adapter to use for storing changes, snapshots and sync operations.\n * @param [options.reactivity] Reactivity adapter to use for reactivity.\n * @param [options.onError] Function to handle errors that occur async during syncing.\n * @param [options.autostart] Whether to automatically start syncing new collections.\n * @param [options.debounceTime] The time in milliseconds to debounce push operations.\n */\n constructor(options) {\n this.options = {\n autostart: true,\n ...options,\n };\n this.id = this.options.id || 'default-sync-manager';\n const { reactivity } = this.options;\n const dataAdapter = this.options.dataAdapter ?? new DefaultDataAdapter();\n this.changes = new Collection(`${this.options.id}-changes`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.snapshots = new Collection(`${this.options.id}-snapshots`, dataAdapter, {\n indices: ['collectionName'],\n reactivity,\n });\n this.syncOperations = new Collection(`${this.options.id}-sync-operations`, dataAdapter, {\n indices: ['collectionName', 'status'],\n reactivity,\n });\n const readiness = [\n Promise.resolve(this.syncOperations.isReady()),\n Promise.resolve(this.changes.isReady()),\n Promise.resolve(this.snapshots.isReady()),\n ];\n this.collectionsReady = Promise.all(readiness).then(() => { });\n this.changes.setMaxListeners(1000);\n this.snapshots.setMaxListeners(1000);\n this.syncOperations.setMaxListeners(1000);\n this.debouncedFlush = debounce(this.flushScheduledPushes, this.options.debounceTime ?? 100);\n }\n getSyncQueue(name) {\n if (this.syncQueues.get(name) == null) {\n this.syncQueues.set(name, new PromiseQueue());\n }\n return this.syncQueues.get(name);\n }\n /**\n * Clears all internal data structures\n */\n async dispose() {\n this.collections.clear();\n this.syncQueues.clear();\n this.remoteChanges.splice(0);\n await Promise.all([\n this.changes.dispose(),\n this.snapshots.dispose(),\n this.syncOperations.dispose(),\n ]);\n this.isDisposed = true;\n }\n /**\n * Gets a collection with it's options by name\n * @deprecated Use getCollectionProperties instead.\n * @param name Name of the collection\n * @throws {Error} Will throw an error if the name wasn't found\n * @returns Tuple of collection and options\n */\n getCollection(name) {\n const { collection, options } = this.getCollectionProperties(name);\n return [collection, options];\n }\n /**\n * Gets collection options by name\n * @param name Name of the collection\n * @throws {Error} Will throw an error if the name wasn't found\n * @returns An object of all properties of the collection\n */\n getCollectionProperties(name) {\n const collectionParameters = this.collections.get(name);\n if (collectionParameters == null)\n throw new Error(`Collection with id '${name}' not found`);\n return collectionParameters;\n }\n /**\n * Adds a collection to the sync manager.\n * @param collection Collection to add\n * @param options Options for the collection. The object needs at least a `name` property.\n * @param options.name Unique name of the collection\n */\n addCollection(collection, options) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n this.collections.set(options.name, {\n collection: collection,\n options,\n readyPromise: collection.ready(),\n syncPaused: true, // always start paused as the autostart will start it\n });\n const hasRemoteChange = (change) => {\n for (const remoteChange of this.remoteChanges) {\n if (remoteChange == null)\n continue;\n if (remoteChange.collectionName !== change.collectionName)\n continue;\n if (remoteChange.type !== change.type)\n continue;\n if (change.type === 'remove' && remoteChange.data !== change.data)\n continue;\n if (remoteChange.data.id !== change.data.id)\n continue;\n return true;\n }\n return false;\n };\n const removeRemoteChanges = (collectionName, id) => {\n const newRemoteChanges = [...this.remoteChanges];\n for (let i = 0; i < newRemoteChanges.length; i += 1) {\n const item = newRemoteChanges[i];\n if (item == null)\n continue;\n if (item.collectionName !== collectionName)\n continue;\n if (item.type === 'remove' && item.data !== id)\n continue;\n if (item.data.id !== id)\n continue;\n newRemoteChanges[i] = null;\n }\n this.remoteChanges = newRemoteChanges.filter(item => item != null);\n };\n collection.on('added', (item) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'insert', data: item })) {\n removeRemoteChanges(options.name, item.id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('changed', ({ id }, modifier) => {\n const data = { id, modifier };\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'update', data })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n collection.on('removed', ({ id }) => {\n // skip the change if it was a remote change\n if (hasRemoteChange({ collectionName: options.name, type: 'remove', data: id })) {\n removeRemoteChanges(options.name, id);\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n }).then(() => {\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\n }).catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n });\n if (this.options.autostart) {\n this.startSync(options.name)\n .catch((error) => {\n if (!this.options.onError)\n return;\n this.options.onError(this.getCollectionProperties(options.name).options, error);\n });\n }\n }\n flushScheduledPushes() {\n this.scheduledPushes.forEach((name) => {\n this.pushChanges(name).catch(() => { });\n });\n this.scheduledPushes.clear();\n }\n schedulePush(name) {\n this.scheduledPushes.add(name);\n this.debouncedFlush();\n }\n /**\n * Setup all collections to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n */\n async startAll() {\n await Promise.all([...this.collections.keys()].map(id => this.startSync(id)));\n }\n /**\n * Setup a collection to be synced with remote changes\n * and enable automatic pushing changes to the remote source.\n * @param name Name of the collection\n */\n async startSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (!collectionParameters.syncPaused)\n return; // already started\n this.schedulePush(name); // push changes that were made while paused\n const cleanupFunction = this.options.registerRemoteChange\n ? await this.options.registerRemoteChange(collectionParameters.options, async (data) => {\n await (data == null\n ? this.sync(name)\n : this.getSyncQueue(name).add(async () => {\n const syncTime = Date.now();\n const syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n await this.syncWithData(name, data)\n .then(async () => {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch(async (error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n throw error;\n });\n }));\n })\n : undefined;\n this.collections.set(name, {\n ...collectionParameters,\n syncPaused: false,\n cleanupFunction,\n });\n }\n /**\n * Pauses the sync process for all collections.\n * This means that the collections will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n */\n async pauseAll() {\n await Promise.all([...this.collections.keys()].map(id => this.pauseSync(id)));\n }\n /**\n * Pauses the sync process for a collection.\n * This means that the collection will not be synced with remote changes\n * and changes will not automatically be pushed to the remote source.\n * @param name Name of the collection\n */\n async pauseSync(name) {\n const collectionParameters = this.getCollectionProperties(name);\n if (collectionParameters.syncPaused)\n return; // already paused\n if (collectionParameters.cleanupFunction)\n await collectionParameters.cleanupFunction();\n this.collections.set(name, {\n ...collectionParameters,\n cleanupFunction: undefined,\n syncPaused: true,\n });\n }\n /**\n * Starts the sync process for all collections\n */\n async syncAll() {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n const errors = [];\n await Promise.all([...this.collections.keys()].map(id => this.sync(id).catch((error) => {\n errors.push({ id, error });\n })));\n if (errors.length > 0)\n throw new Error(`Error while syncing collections:\\n${errors.map(error => `${error.id}: ${error.error.message}`).join('\\n\\n')}`);\n }\n /**\n * Checks if a collection is currently beeing synced\n * @param [name] Name of the collection. If not provided, it will check if any collection is currently beeing synced.\n * @param [async] If true, it will check for active syncs in the database. This is useful if you have multiple instances of the application running.\n * @returns True if the collection is currently beeing synced, false otherwise. If async is true, it will return a promise that resolves to true or false.\n */\n isSyncing(name, async) {\n const itemOrPromise = this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 }, async });\n if (itemOrPromise instanceof Promise) {\n return itemOrPromise\n .then(item => item != null);\n }\n return (itemOrPromise != null);\n }\n /**\n * Checks if the sync manager is ready to sync.\n * @returns A promise that resolves when the sync manager is ready to sync.\n */\n async isReady() {\n await this.collectionsReady;\n }\n /**\n * Starts the sync process for a collection\n * @param name Name of the collection\n * @param options Options for the sync process.\n * @param options.force If true, the sync process will be started even if there are no changes and onlyWithChanges is true.\n * @param options.onlyWithChanges If true, the sync process will only be started if there are changes.\n */\n async sync(name, options = {}) {\n if (this.isDisposed)\n throw new Error('SyncManager is disposed');\n await this.isReady();\n const { options: collectionOptions, readyPromise } = this.getCollectionProperties(name);\n await readyPromise;\n const hasActiveSyncs = await this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\n async: true,\n }).count() > 0;\n const syncTime = Date.now();\n let syncId = null;\n // schedule for next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const doSync = async () => {\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = await this.syncOperations.insert({\n start: syncTime,\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n });\n }\n const data = await this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n });\n await this.syncWithData(name, data);\n };\n await (options?.force ? doSync() : this.getSyncQueue(name).add(doSync))\n .catch(async (error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'error', end: Date.now(), error: error.stack || error.message },\n });\n }\n throw error;\n });\n if (syncId != null) {\n // clean up old sync operations\n await this.syncOperations.removeMany({\n id: { $ne: syncId },\n collectionName: name,\n $or: [\n { end: { $lte: syncTime } },\n { status: 'active' },\n ],\n });\n // update sync operation status to done after everthing was finished\n await this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n }\n }\n /**\n * Starts the push process for a collection (sync process but only if there are changes)\n * @param name Name of the collection\n */\n async pushChanges(name) {\n await this.sync(name, {\n onlyWithChanges: true,\n });\n }\n async syncWithData(name, data) {\n const { collection, options: collectionOptions } = this.getCollectionProperties(name);\n const syncTime = Date.now();\n const lastFinishedSync = await this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n async: true,\n });\n const lastSnapshot = await this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n async: true,\n });\n const currentChanges = await this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n async: true,\n }).fetch();\n await sync({\n changes: currentChanges,\n lastSnapshot: lastSnapshot?.items,\n data,\n pull: () => this.options.pull(collectionOptions, {\n lastFinishedSyncStart: lastFinishedSync?.start,\n lastFinishedSyncEnd: lastFinishedSync?.end,\n }),\n push: changes => this.options.push(collectionOptions, {\n changes,\n rawChanges: currentChanges,\n }),\n insert: async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n },\n update: async (itemId, modifier) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: { id: itemId, ...modifier.$set },\n }, {\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n await collection.updateOne({ id: itemId }, {\n ...modifier,\n $setOnInsert: { id: itemId },\n }, { upsert: true });\n },\n remove: async (itemId) => {\n const itemExists = await collection.find({\n id: itemId,\n }, { reactive: false, async: true }).count() > 0;\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n await collection.removeOne({ id: itemId });\n },\n batch: async (fn) => {\n return collection.batch(async () => {\n await fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n await this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n await this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n await this.snapshots.insert({\n time: syncTime,\n collectionName: name,\n items: snapshot,\n });\n // delay sync operation update to next tick to allow other tasks to run first\n await new Promise((resolve) => {\n setTimeout(resolve, 0);\n });\n const hasChanges = await this.changes.find({\n collectionName: name,\n }, { reactive: false, async: true }).count() > 0;\n if (hasChanges) {\n // check if there are unsynced changes to push\n // and sync again if there are any\n await this.sync(name, {\n force: true,\n onlyWithChanges: true,\n });\n return;\n }\n // if there are no unsynced changes apply the last snapshot\n // to make sure that collection and snapshot are in sync\n // find all items that are not in the snapshot\n const nonExistingItemIds = await collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n async: true,\n }).map(item => item.id);\n await collection.batch(async () => {\n // update all items that are in the snapshot\n await Promise.all(snapshot.map(async (item) => {\n // add multiple remote changes as we don't know if the item will be updated or inserted during replace\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n }, {\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // replace the item\n await collection.replaceOne({ id: item.id }, item, { upsert: true });\n }));\n // remove all items that are not in the snapshot\n await Promise.all(nonExistingItemIds.map(async (id) => {\n await collection.removeOne({ id });\n }));\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","task","resolve","reject","error","computeModifiedFields","oldItem","newItem","modifiedFields","oldKeys","newKeys","allKeys","key","nestedModifiedFields","nestedField","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","itemMap","change","existingItem","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","reactivity","dataAdapter","DefaultDataAdapter","Collection","readiness","name","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChanges","collectionName","newRemoteChanges","modifier","cleanupFunction","syncTime","syncId","errors","async","itemOrPromise","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaldb/sync",
3
- "version": "2.0.0-beta.1",
3
+ "version": "2.0.0-beta.3",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "build": "rimraf dist && vite build",
@@ -54,6 +54,6 @@
54
54
  "dist"
55
55
  ],
56
56
  "peerDependencies": {
57
- "@signaldb/core": "^2.0.0-beta.1"
57
+ "@signaldb/core": "^2.0.0-beta.3"
58
58
  }
59
59
  }