@signaldb/sync 1.1.2 → 1.2.0

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.
@@ -20,6 +20,7 @@ interface Options<CollectionOptions extends Record<string, any>, ItemType extend
20
20
  reactivity?: ReactivityAdapter;
21
21
  onError?: (collectionOptions: SyncOptions<CollectionOptions>, error: Error) => void;
22
22
  autostart?: boolean;
23
+ debounceTime?: number;
23
24
  }
24
25
  /**
25
26
  * Class to manage syncing of collections.
@@ -59,12 +60,14 @@ export default class SyncManager<CollectionOptions extends Record<string, any>,
59
60
  protected changes: Collection<Change<ItemType>, string>;
60
61
  protected snapshots: Collection<Snapshot<ItemType>, string>;
61
62
  protected syncOperations: Collection<SyncOperation, string>;
63
+ protected scheduledPushes: Set<string>;
62
64
  protected remoteChanges: Omit<Change, 'id' | 'time'>[];
63
65
  protected syncQueues: Map<string, PromiseQueue>;
64
66
  protected persistenceReady: Promise<void>;
65
67
  protected isDisposed: boolean;
66
68
  protected instanceId: string;
67
69
  protected id: string;
70
+ protected debouncedFlush: () => void;
68
71
  /**
69
72
  * @param options Collection options
70
73
  * @param options.pull Function to pull data from remote source.
@@ -74,6 +77,8 @@ export default class SyncManager<CollectionOptions extends Record<string, any>,
74
77
  * @param [options.persistenceAdapter] Persistence adapter to use for storing changes, snapshots and sync operations.
75
78
  * @param [options.reactivity] Reactivity adapter to use for reactivity.
76
79
  * @param [options.onError] Function to handle errors that occur async during syncing.
80
+ * @param [options.autostart] Whether to automatically start syncing new collections.
81
+ * @param [options.debounceTime] The time in milliseconds to debounce push operations.
77
82
  */
78
83
  constructor(options: Options<CollectionOptions, ItemType, IdType>);
79
84
  protected createPersistenceAdapter(name: string): {
@@ -113,7 +118,7 @@ export default class SyncManager<CollectionOptions extends Record<string, any>,
113
118
  * @param options.name Unique name of the collection
114
119
  */
115
120
  addCollection(collection: Collection<ItemType, IdType, any>, options: SyncOptions<CollectionOptions>): void;
116
- protected deboucedPush: (name: string) => void;
121
+ protected flushScheduledPushes(): void;
117
122
  protected schedulePush(name: string): void;
118
123
  /**
119
124
  * Setup all collections to be synced with remote changes
@@ -6,4 +6,4 @@ import type { Change } from './types';
6
6
  * @param changes The changes to apply to the items
7
7
  * @returns The new items after applying the changes
8
8
  */
9
- export default function applyChanges<ItemType extends BaseItem<IdType>, IdType>(items: ItemType[], changes: Change<ItemType, IdType>[]): Promise<ItemType[]>;
9
+ export default function applyChanges<ItemType extends BaseItem<IdType>, IdType>(items: ItemType[], changes: Change<ItemType, IdType>[]): ItemType[];
package/dist/index.mjs CHANGED
@@ -1,22 +1,22 @@
1
- var N = Object.defineProperty;
2
- var $ = (r, e, t) => e in r ? N(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
- var u = (r, e, t) => $(r, typeof e != "symbol" ? e + "" : e, t);
4
- import { isEqual as g, Collection as m, modify as x, randomId as D, createIndex as y } from "@signaldb/core";
5
- function S(r, e, t = {}) {
6
- let s, i;
1
+ var $ = Object.defineProperty;
2
+ var S = (r, e, t) => e in r ? $(r, e, { enumerable: !0, configurable: !0, writable: !0, value: t }) : r[e] = t;
3
+ var d = (r, e, t) => S(r, typeof e != "symbol" ? e + "" : e, t);
4
+ import { isEqual as y, modify as P, randomId as x, Collection as g, createIndex as m } from "@signaldb/core";
5
+ function D(r, e, t = {}) {
6
+ let s, n;
7
7
  const { leading: a = !1, trailing: o = !0 } = t;
8
8
  function c(...l) {
9
- const n = a && !s, d = o && !s;
9
+ const i = a && !s, u = o && !s;
10
10
  return s && clearTimeout(s), s = setTimeout(() => {
11
- s = null, o && !n && (i = r.apply(this, l));
12
- }, e), n ? i = r.apply(this, l) : d || (i = null), i;
11
+ s = null, o && !i && (n = r.apply(this, l));
12
+ }, e), i ? n = r.apply(this, l) : u || (n = null), n;
13
13
  }
14
14
  return c;
15
15
  }
16
- class M {
16
+ class I {
17
17
  constructor() {
18
- u(this, "queue", []);
19
- u(this, "pendingPromise", !1);
18
+ d(this, "queue", []);
19
+ d(this, "pendingPromise", !1);
20
20
  }
21
21
  /**
22
22
  * Method to add a new promise to the queue and returns a promise that resolves when this task is done
@@ -25,8 +25,8 @@ class M {
25
25
  */
26
26
  add(e) {
27
27
  return new Promise((t, s) => {
28
- this.queue.push(() => e().then(t).catch((i) => {
29
- throw s(i), i;
28
+ this.queue.push(() => e().then(t).catch((n) => {
29
+ throw s(n), n;
30
30
  })), this.dequeue();
31
31
  });
32
32
  }
@@ -52,70 +52,65 @@ class M {
52
52
  }
53
53
  }
54
54
  function w(r, e) {
55
- const t = [], s = [], i = [], a = new Map(r.map((c) => [c.id, c])), o = new Map(e.map((c) => [c.id, c]));
55
+ const t = [], s = [], n = [], a = new Map(r.map((c) => [c.id, c])), o = new Map(e.map((c) => [c.id, c]));
56
56
  for (const [c, l] of a) {
57
- const n = o.get(c);
58
- n ? g(n, l) || s.push(n) : i.push(l);
57
+ const i = o.get(c);
58
+ i ? y(i, l) || s.push(i) : n.push(l);
59
59
  }
60
60
  for (const [c, l] of o)
61
61
  a.has(c) || t.push(l);
62
- return { added: t, modified: s, removed: i };
62
+ return { added: t, modified: s, removed: n };
63
63
  }
64
- function P(r, e) {
64
+ function v(r, e) {
65
65
  if (e.items != null)
66
66
  return e.items;
67
67
  const t = r || [];
68
68
  return e.changes.added.forEach((s) => {
69
- const i = t.findIndex((a) => a.id === s.id);
70
- i === -1 ? t.push(s) : t[i] = s;
69
+ const n = t.findIndex((a) => a.id === s.id);
70
+ n === -1 ? t.push(s) : t[n] = s;
71
71
  }), e.changes.modified.forEach((s) => {
72
- const i = t.findIndex((a) => a.id === s.id);
73
- i === -1 ? t.push(s) : t[i] = s;
72
+ const n = t.findIndex((a) => a.id === s.id);
73
+ n === -1 ? t.push(s) : t[n] = s;
74
74
  }), e.changes.removed.forEach((s) => {
75
- const i = t.findIndex((a) => a.id === s.id);
76
- i !== -1 && t.splice(i, 1);
75
+ const n = t.findIndex((a) => a.id === s.id);
76
+ n !== -1 && t.splice(n, 1);
77
77
  }), t;
78
78
  }
79
- async function v(r, e) {
80
- const t = new m();
81
- t.batch(() => {
82
- r.forEach((i) => t.insert(i)), e.forEach((i) => {
83
- if (i.type === "remove") {
84
- t.removeOne({ id: i.data });
85
- return;
86
- }
87
- const a = { id: i.data.id }, o = t.findOne(a);
88
- if (i.type === "insert") {
89
- o ? t.updateOne(a, { $set: i.data }) : t.insert(i.data);
90
- return;
91
- }
92
- o ? t.updateOne(a, i.data.modifier) : t.insert(x(a, i.data.modifier));
93
- });
94
- });
95
- const s = t.find().fetch();
96
- return await t.dispose(), s;
79
+ function N(r, e) {
80
+ const t = new Map(r.map((s) => [s.id, s]));
81
+ return e.forEach((s) => {
82
+ if (s.type === "remove")
83
+ t.delete(s.data);
84
+ else if (s.type === "insert") {
85
+ const n = t.get(s.data.id);
86
+ t.set(s.data.id, n ? { ...n, ...s.data } : s.data);
87
+ } else {
88
+ const n = t.get(s.data.id);
89
+ t.set(s.data.id, n ? P(n, s.data.modifier) : P({ id: s.data.id }, s.data.modifier));
90
+ }
91
+ }), [...t.values()];
97
92
  }
98
93
  function O(r) {
99
94
  return r.added.length > 0 || r.modified.length > 0 || r.removed.length > 0;
100
95
  }
101
- function I(r, e) {
96
+ function M(r, e) {
102
97
  return O(w(r, e));
103
98
  }
104
- async function R({ changes: r, lastSnapshot: e, data: t, pull: s, push: i, insert: a, update: o, remove: c, batch: l }) {
105
- let n = t, d = e || [], f = P(e, n);
99
+ async function R({ changes: r, lastSnapshot: e, data: t, pull: s, push: n, insert: a, update: o, remove: c, batch: l }) {
100
+ let i = t, u = e || [], f = v(e, i);
106
101
  if (r.length > 0) {
107
- const p = await v(d, r);
108
- if (I(d, p)) {
109
- const E = await v(f, r), C = w(f, E);
110
- O(C) && (await i(C), n = await s(), f = P(f, n)), d = p;
102
+ const p = N(u, r);
103
+ if (M(u, p)) {
104
+ const E = N(f, r), C = w(f, E);
105
+ O(C) && (await n(C), i = await s(), f = v(f, i)), u = p;
111
106
  }
112
107
  }
113
- const h = n.changes == null ? w(d, n.items) : n.changes;
108
+ const h = i.changes == null ? w(u, i.items) : i.changes;
114
109
  return l(() => {
115
110
  h.added.forEach((p) => a(p)), h.modified.forEach((p) => o(p.id, { $set: p })), h.removed.forEach((p) => c(p.id));
116
111
  }), f;
117
112
  }
118
- class T {
113
+ class b {
119
114
  /**
120
115
  * @param options Collection options
121
116
  * @param options.pull Function to pull data from remote source.
@@ -125,49 +120,49 @@ class T {
125
120
  * @param [options.persistenceAdapter] Persistence adapter to use for storing changes, snapshots and sync operations.
126
121
  * @param [options.reactivity] Reactivity adapter to use for reactivity.
127
122
  * @param [options.onError] Function to handle errors that occur async during syncing.
123
+ * @param [options.autostart] Whether to automatically start syncing new collections.
124
+ * @param [options.debounceTime] The time in milliseconds to debounce push operations.
128
125
  */
129
126
  constructor(e) {
130
- u(this, "options");
131
- u(this, "collections", /* @__PURE__ */ new Map());
132
- u(this, "changes");
133
- u(this, "snapshots");
134
- u(this, "syncOperations");
135
- u(this, "remoteChanges", []);
136
- u(this, "syncQueues", /* @__PURE__ */ new Map());
137
- u(this, "persistenceReady");
138
- u(this, "isDisposed", !1);
139
- u(this, "instanceId", D());
140
- u(this, "id");
141
- u(this, "deboucedPush", S((e) => {
142
- this.pushChanges(e).catch(() => {
143
- });
144
- }, 100));
127
+ d(this, "options");
128
+ d(this, "collections", /* @__PURE__ */ new Map());
129
+ d(this, "changes");
130
+ d(this, "snapshots");
131
+ d(this, "syncOperations");
132
+ d(this, "scheduledPushes", /* @__PURE__ */ new Set());
133
+ d(this, "remoteChanges", []);
134
+ d(this, "syncQueues", /* @__PURE__ */ new Map());
135
+ d(this, "persistenceReady");
136
+ d(this, "isDisposed", !1);
137
+ d(this, "instanceId", x());
138
+ d(this, "id");
139
+ d(this, "debouncedFlush");
145
140
  this.options = {
146
141
  autostart: !0,
147
142
  ...e
148
143
  }, this.id = this.options.id || "default-sync-manager";
149
- const { reactivity: t } = this.options, s = this.createPersistenceAdapter("changes"), i = this.createPersistenceAdapter("snapshots"), a = this.createPersistenceAdapter("sync-operations");
150
- this.changes = new m({
144
+ const { reactivity: t } = this.options, s = this.createPersistenceAdapter("changes"), n = this.createPersistenceAdapter("snapshots"), a = this.createPersistenceAdapter("sync-operations");
145
+ this.changes = new g({
151
146
  name: `${this.options.id}-changes`,
152
147
  persistence: s == null ? void 0 : s.adapter,
153
- indices: [y("collectionName")],
148
+ indices: [m("collectionName")],
154
149
  reactivity: t
155
- }), this.snapshots = new m({
150
+ }), this.snapshots = new g({
156
151
  name: `${this.options.id}-snapshots`,
157
- persistence: i == null ? void 0 : i.adapter,
158
- indices: [y("collectionName")],
152
+ persistence: n == null ? void 0 : n.adapter,
153
+ indices: [m("collectionName")],
159
154
  reactivity: t
160
- }), this.syncOperations = new m({
155
+ }), this.syncOperations = new g({
161
156
  name: `${this.options.id}-sync-operations`,
162
157
  persistence: a == null ? void 0 : a.adapter,
163
- indices: [y("collectionName"), y("status")],
158
+ indices: [m("collectionName"), m("status")],
164
159
  reactivity: t
165
- }), this.changes.on("persistence.error", (o) => s == null ? void 0 : s.handler(o)), this.snapshots.on("persistence.error", (o) => i == null ? void 0 : i.handler(o)), this.syncOperations.on("persistence.error", (o) => a == null ? void 0 : a.handler(o)), this.persistenceReady = Promise.all([
160
+ }), this.changes.on("persistence.error", (o) => s == null ? void 0 : s.handler(o)), this.snapshots.on("persistence.error", (o) => n == null ? void 0 : n.handler(o)), this.syncOperations.on("persistence.error", (o) => a == null ? void 0 : a.handler(o)), this.persistenceReady = Promise.all([
166
161
  this.syncOperations.isReady(),
167
162
  this.changes.isReady(),
168
163
  this.snapshots.isReady()
169
164
  ]).then(() => {
170
- }), this.changes.setMaxListeners(1e3), this.snapshots.setMaxListeners(1e3), this.syncOperations.setMaxListeners(1e3);
165
+ }), this.changes.setMaxListeners(1e3), this.snapshots.setMaxListeners(1e3), this.syncOperations.setMaxListeners(1e3), this.debouncedFlush = D(this.flushScheduledPushes, this.options.debounceTime ?? 100);
171
166
  }
172
167
  createPersistenceAdapter(e) {
173
168
  if (this.options.persistenceAdapter == null)
@@ -175,14 +170,14 @@ class T {
175
170
  let t = () => {
176
171
  };
177
172
  return {
178
- adapter: this.options.persistenceAdapter(`${this.id}-${e}`, (i) => {
179
- t = i;
173
+ adapter: this.options.persistenceAdapter(`${this.id}-${e}`, (n) => {
174
+ t = n;
180
175
  }),
181
- handler: (i) => t(i)
176
+ handler: (n) => t(n)
182
177
  };
183
178
  }
184
179
  getSyncQueue(e) {
185
- return this.syncQueues.get(e) == null && this.syncQueues.set(e, new M()), this.syncQueues.get(e);
180
+ return this.syncQueues.get(e) == null && this.syncQueues.set(e, new I()), this.syncQueues.get(e);
186
181
  }
187
182
  /**
188
183
  * Clears all internal data structures
@@ -235,19 +230,19 @@ class T {
235
230
  });
236
231
  const s = (a) => {
237
232
  for (const o of this.remoteChanges)
238
- if (g(o, a))
233
+ if (y(o, a))
239
234
  return !0;
240
235
  return !1;
241
- }, i = (a) => {
236
+ }, n = (a) => {
242
237
  for (let o = 0; o < this.remoteChanges.length; o += 1)
243
- if (g(this.remoteChanges[o], a)) {
238
+ if (y(this.remoteChanges[o], a)) {
244
239
  this.remoteChanges.splice(o, 1);
245
240
  return;
246
241
  }
247
242
  };
248
243
  e.on("added", (a) => {
249
244
  if (s({ collectionName: t.name, type: "insert", data: a })) {
250
- i({ collectionName: t.name, type: "insert", data: a });
245
+ n({ collectionName: t.name, type: "insert", data: a });
251
246
  return;
252
247
  }
253
248
  this.changes.insert({
@@ -259,7 +254,7 @@ class T {
259
254
  }), e.on("changed", ({ id: a }, o) => {
260
255
  const c = { id: a, modifier: o };
261
256
  if (s({ collectionName: t.name, type: "update", data: c })) {
262
- i({ collectionName: t.name, type: "update", data: c });
257
+ n({ collectionName: t.name, type: "update", data: c });
263
258
  return;
264
259
  }
265
260
  this.changes.insert({
@@ -270,7 +265,7 @@ class T {
270
265
  }), !this.getCollectionProperties(t.name).syncPaused && this.schedulePush(t.name);
271
266
  }), e.on("removed", ({ id: a }) => {
272
267
  if (s({ collectionName: t.name, type: "remove", data: a })) {
273
- i({ collectionName: t.name, type: "remove", data: a });
268
+ n({ collectionName: t.name, type: "remove", data: a });
274
269
  return;
275
270
  }
276
271
  this.changes.insert({
@@ -283,8 +278,14 @@ class T {
283
278
  this.options.onError && this.options.onError(this.getCollectionProperties(t.name).options, a);
284
279
  });
285
280
  }
281
+ flushScheduledPushes() {
282
+ this.scheduledPushes.forEach((e) => {
283
+ this.pushChanges(e).catch(() => {
284
+ });
285
+ }), this.scheduledPushes.clear();
286
+ }
286
287
  schedulePush(e) {
287
- this.deboucedPush(e);
288
+ this.scheduledPushes.add(e), this.debouncedFlush();
288
289
  }
289
290
  /**
290
291
  * Setup all collections to be synced with remote changes
@@ -303,8 +304,8 @@ class T {
303
304
  if (!t.syncPaused)
304
305
  return;
305
306
  this.schedulePush(e);
306
- const s = this.options.registerRemoteChange ? await this.options.registerRemoteChange(t.options, async (i) => {
307
- if (i == null)
307
+ const s = this.options.registerRemoteChange ? await this.options.registerRemoteChange(t.options, async (n) => {
308
+ if (n == null)
308
309
  await this.sync(e);
309
310
  else {
310
311
  const a = Date.now(), o = this.syncOperations.insert({
@@ -313,7 +314,7 @@ class T {
313
314
  instanceId: this.instanceId,
314
315
  status: "active"
315
316
  });
316
- await this.syncWithData(e, i).then(() => {
317
+ await this.syncWithData(e, n).then(() => {
317
318
  this.syncOperations.removeMany({
318
319
  id: { $ne: o },
319
320
  collectionName: e,
@@ -403,8 +404,8 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
403
404
  if (this.isDisposed)
404
405
  throw new Error("SyncManager is disposed");
405
406
  await this.isReady();
406
- const { options: s, readyPromise: i } = this.getCollectionProperties(e);
407
- await i;
407
+ const { options: s, readyPromise: n } = this.getCollectionProperties(e);
408
+ await n;
408
409
  const a = this.syncOperations.find({
409
410
  collectionName: e,
410
411
  instanceId: this.instanceId,
@@ -413,11 +414,11 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
413
414
  reactive: !1
414
415
  }).count() > 0, o = Date.now();
415
416
  let c = null;
416
- await new Promise((n) => {
417
- setTimeout(n, 0);
417
+ await new Promise((i) => {
418
+ setTimeout(i, 0);
418
419
  });
419
420
  const l = async () => {
420
- const n = this.syncOperations.findOne({
421
+ const i = this.syncOperations.findOne({
421
422
  collectionName: e,
422
423
  status: "done"
423
424
  }, {
@@ -438,16 +439,16 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
438
439
  instanceId: this.instanceId,
439
440
  status: "active"
440
441
  }));
441
- const d = await this.options.pull(s, {
442
- lastFinishedSyncStart: n == null ? void 0 : n.start,
443
- lastFinishedSyncEnd: n == null ? void 0 : n.end
442
+ const u = await this.options.pull(s, {
443
+ lastFinishedSyncStart: i == null ? void 0 : i.start,
444
+ lastFinishedSyncEnd: i == null ? void 0 : i.end
444
445
  });
445
- await this.syncWithData(e, d);
446
+ await this.syncWithData(e, u);
446
447
  };
447
- await (t != null && t.force ? l() : this.getSyncQueue(e).add(l)).catch((n) => {
448
- throw c != null && (this.options.onError && this.options.onError(s, n), this.syncOperations.updateOne({ id: c }, {
449
- $set: { status: "error", end: Date.now(), error: n.stack || n.message }
450
- })), n;
448
+ await (t != null && t.force ? l() : this.getSyncQueue(e).add(l)).catch((i) => {
449
+ throw c != null && (this.options.onError && this.options.onError(s, i), this.syncOperations.updateOne({ id: c }, {
450
+ $set: { status: "error", end: Date.now(), error: i.stack || i.message }
451
+ })), i;
451
452
  }), c != null && (this.syncOperations.removeMany({
452
453
  id: { $ne: c },
453
454
  collectionName: e,
@@ -469,7 +470,7 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
469
470
  });
470
471
  }
471
472
  async syncWithData(e, t) {
472
- const { collection: s, options: i } = this.getCollectionProperties(e), a = Date.now(), o = this.syncOperations.findOne({
473
+ const { collection: s, options: n } = this.getCollectionProperties(e), a = Date.now(), o = this.syncOperations.findOne({
473
474
  collectionName: e,
474
475
  status: "done"
475
476
  }, {
@@ -491,33 +492,33 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
491
492
  changes: l,
492
493
  lastSnapshot: c == null ? void 0 : c.items,
493
494
  data: t,
494
- pull: () => this.options.pull(i, {
495
+ pull: () => this.options.pull(n, {
495
496
  lastFinishedSyncStart: o == null ? void 0 : o.start,
496
497
  lastFinishedSyncEnd: o == null ? void 0 : o.end
497
498
  }),
498
- push: (n) => this.options.push(i, { changes: n }),
499
- insert: (n) => {
500
- if (n.id && !!s.findOne({
501
- id: n.id
499
+ push: (i) => this.options.push(n, { changes: i }),
500
+ insert: (i) => {
501
+ if (i.id && !!s.findOne({
502
+ id: i.id
502
503
  }, { reactive: !1 })) {
503
504
  this.remoteChanges.push({
504
505
  collectionName: e,
505
506
  type: "update",
506
- data: { id: n.id, modifier: { $set: n } }
507
- }), s.updateOne({ id: n.id }, { $set: n });
507
+ data: { id: i.id, modifier: { $set: i } }
508
+ }), s.updateOne({ id: i.id }, { $set: i });
508
509
  return;
509
510
  }
510
511
  this.remoteChanges.push({
511
512
  collectionName: e,
512
513
  type: "insert",
513
- data: n
514
- }), s.insert(n);
514
+ data: i
515
+ }), s.insert(i);
515
516
  },
516
- update: (n, d) => {
517
- if (n && !s.findOne({
518
- id: n
517
+ update: (i, u) => {
518
+ if (i && !s.findOne({
519
+ id: i
519
520
  }, { reactive: !1 })) {
520
- const h = { ...d.$set, id: n };
521
+ const h = { ...u.$set, id: i };
521
522
  this.remoteChanges.push({
522
523
  collectionName: e,
523
524
  type: "insert",
@@ -528,24 +529,24 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
528
529
  this.remoteChanges.push({
529
530
  collectionName: e,
530
531
  type: "update",
531
- data: { id: n, modifier: d }
532
- }), s.updateOne({ id: n }, d);
532
+ data: { id: i, modifier: u }
533
+ }), s.updateOne({ id: i }, u);
533
534
  },
534
- remove: (n) => {
535
+ remove: (i) => {
535
536
  s.findOne({
536
- id: n
537
+ id: i
537
538
  }, { reactive: !1 }) && (this.remoteChanges.push({
538
539
  collectionName: e,
539
540
  type: "remove",
540
- data: n
541
- }), s.removeOne({ id: n }));
541
+ data: i
542
+ }), s.removeOne({ id: i }));
542
543
  },
543
- batch: (n) => {
544
+ batch: (i) => {
544
545
  s.batch(() => {
545
- n();
546
+ i();
546
547
  });
547
548
  }
548
- }).then(async (n) => {
549
+ }).then(async (i) => {
549
550
  if (this.snapshots.removeMany({
550
551
  collectionName: e,
551
552
  time: { $lte: a }
@@ -555,7 +556,7 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
555
556
  }), this.snapshots.insert({
556
557
  time: a,
557
558
  collectionName: e,
558
- items: n
559
+ items: i
559
560
  }), await new Promise((h) => {
560
561
  setTimeout(h, 0);
561
562
  }), this.changes.find({
@@ -568,27 +569,31 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
568
569
  return;
569
570
  }
570
571
  const f = s.find({
571
- id: { $nin: n.map((h) => h.id) }
572
+ id: { $nin: i.map((h) => h.id) }
572
573
  }, {
573
574
  reactive: !1
574
575
  }).map((h) => h.id);
575
576
  s.batch(() => {
576
- n.forEach((h) => {
577
- const p = !!s.findOne({
577
+ i.forEach((h) => {
578
+ const p = s.findOne({
578
579
  id: h.id
579
580
  }, {
580
581
  reactive: !1
581
582
  });
582
583
  /* istanbul ignore else -- @preserve */
583
- p ? (this.remoteChanges.push({
584
- collectionName: e,
585
- type: "update",
586
- data: { id: h.id, modifier: { $set: h } }
587
- }), s.updateOne({ id: h.id }, { $set: h })) : (this.remoteChanges.push({
588
- collectionName: e,
589
- type: "insert",
590
- data: h
591
- }), s.insert(h));
584
+ if (p) {
585
+ /* istanbul ignore if -- @preserve */
586
+ y(p, h) || (this.remoteChanges.push({
587
+ collectionName: e,
588
+ type: "update",
589
+ data: { id: h.id, modifier: { $set: h } }
590
+ }), s.updateOne({ id: h.id }, { $set: h }));
591
+ } else
592
+ this.remoteChanges.push({
593
+ collectionName: e,
594
+ type: "insert",
595
+ data: h
596
+ }), s.insert(h);
592
597
  }), f.forEach((h) => {
593
598
  s.removeOne({ id: h });
594
599
  });
@@ -597,6 +602,6 @@ ${e.map((t) => `${t.id}: ${t.error.message}`).join(`
597
602
  }
598
603
  }
599
604
  export {
600
- T as SyncManager
605
+ b as SyncManager
601
606
  };
602
607
  //# sourceMappingURL=index.mjs.map
@@ -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 * 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 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 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 { added, modified, removed };\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 { Collection, 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 async function applyChanges(items, changes) {\n const collection = new Collection();\n collection.batch(() => {\n items.forEach(item => collection.insert(item));\n changes.forEach((change) => {\n if (change.type === 'remove') {\n collection.removeOne({ id: change.data });\n return;\n }\n const selector = { id: change.data.id };\n const itemExists = collection.findOne(selector);\n if (change.type === 'insert') {\n if (itemExists) { // update item if it alread exists\n collection.updateOne(selector, { $set: change.data });\n }\n else { // insert item if it does not exist\n collection.insert(change.data);\n }\n return;\n }\n // change.type === 'update'\n if (itemExists) { // update item if it exists\n collection.updateOne(selector, change.data.modifier);\n }\n else { // insert item if it does not exist\n collection.insert(modify(selector, change.data.modifier));\n }\n });\n });\n const result = collection.find().fetch();\n await collection.dispose();\n return result;\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 = await 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 = await 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 batch(() => {\n newChanges.added.forEach(item => insert(item));\n newChanges.modified.forEach(item => update(item.id, { $set: item }));\n newChanges.removed.forEach(item => remove(item.id));\n });\n return newSnapshot;\n}\n","import { Collection, randomId, isEqual, createIndex } 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 remoteChanges = [];\n syncQueues = new Map();\n persistenceReady;\n isDisposed = false;\n instanceId = randomId();\n id;\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.persistenceAdapter] Persistence 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 */\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 changesPersistence = this.createPersistenceAdapter('changes');\n const snapshotsPersistence = this.createPersistenceAdapter('snapshots');\n const syncOperationsPersistence = this.createPersistenceAdapter('sync-operations');\n this.changes = new Collection({\n name: `${this.options.id}-changes`,\n persistence: changesPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.snapshots = new Collection({\n name: `${this.options.id}-snapshots`,\n persistence: snapshotsPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.syncOperations = new Collection({\n name: `${this.options.id}-sync-operations`,\n persistence: syncOperationsPersistence?.adapter,\n indices: [createIndex('collectionName'), createIndex('status')],\n reactivity,\n });\n this.changes.on('persistence.error', error => changesPersistence?.handler(error));\n this.snapshots.on('persistence.error', error => snapshotsPersistence?.handler(error));\n this.syncOperations.on('persistence.error', error => syncOperationsPersistence?.handler(error));\n this.persistenceReady = 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 }\n createPersistenceAdapter(name) {\n if (this.options.persistenceAdapter == null)\n return;\n let errorHandler = () => { };\n const adapter = this.options.persistenceAdapter(`${this.id}-${name}`, (handler) => {\n errorHandler = handler;\n });\n return {\n adapter,\n handler: (error) => errorHandler(error),\n };\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, this.remoteChanges.length);\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.isReady(),\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 (isEqual(remoteChange, change)) {\n return true;\n }\n }\n return false;\n };\n const removeRemoteChange = (change) => {\n for (let i = 0; i < this.remoteChanges.length; i += 1) {\n if (isEqual(this.remoteChanges[i], change)) {\n this.remoteChanges.splice(i, 1);\n return;\n }\n }\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 removeRemoteChange({ collectionName: options.name, type: 'insert', data: item });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'update', data });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'remove', data: id });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 deboucedPush = debounce((name) => {\n this.pushChanges(name).catch(() => { });\n }, 100);\n schedulePush(name) {\n this.deboucedPush(name);\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 = 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(() => {\n // clean up old sync operations\n 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 this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch((error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n 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 * @returns True if the collection is currently beeing synced, false otherwise.\n */\n isSyncing(name) {\n return this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 } }) != 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.persistenceReady;\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 = this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = 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((error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n 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 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 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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n const lastSnapshot = this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n });\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\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, { changes }),\n insert: (item) => {\n const itemExists = item.id && !!collection.findOne({\n id: item.id,\n }, { reactive: false });\n if (itemExists) {\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // update the item if it already exists\n collection.updateOne({ id: item.id }, { $set: item });\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n },\n update: (itemId, modifier) => {\n const itemExists = itemId && !collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (itemExists) {\n const item = { ...modifier.$set, id: itemId };\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n // insert the item if it does not exist\n collection.insert(item);\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n collection.updateOne({ id: itemId }, modifier);\n },\n remove: (itemId) => {\n const itemExists = !!collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n collection.removeOne({ id: itemId });\n },\n batch: (fn) => {\n collection.batch(() => {\n fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n 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 = this.changes.find({\n collectionName: name,\n }, { reactive: false }).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 = collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n }).map(item => item.id);\n collection.batch(() => {\n // update all items that are in the snapshot\n snapshot.forEach((item) => {\n const itemExists = !!collection.findOne({\n id: item.id,\n }, {\n reactive: false,\n });\n /* istanbul ignore else -- @preserve */\n if (itemExists) {\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n collection.updateOne({ id: item.id }, { $set: item });\n }\n else { // this case should never happen\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n }\n });\n // remove all items that are not in the snapshot\n nonExistingItemIds.forEach((id) => {\n collection.removeOne({ id });\n });\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","__publicField","task","resolve","reject","error","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","oldItem","newItem","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","collection","Collection","change","selector","itemExists","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","name","reactivity","changesPersistence","snapshotsPersistence","syncOperationsPersistence","createIndex","errorHandler","handler","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChange","modifier","cleanupFunction","syncTime","syncId","errors","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds"],"mappings":"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"}
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 * 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 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 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 { added, modified, removed };\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 batch(() => {\n newChanges.added.forEach(item => insert(item));\n newChanges.modified.forEach(item => update(item.id, { $set: item }));\n newChanges.removed.forEach(item => remove(item.id));\n });\n return newSnapshot;\n}\n","import { Collection, randomId, isEqual, createIndex } 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 persistenceReady;\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.persistenceAdapter] Persistence 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 changesPersistence = this.createPersistenceAdapter('changes');\n const snapshotsPersistence = this.createPersistenceAdapter('snapshots');\n const syncOperationsPersistence = this.createPersistenceAdapter('sync-operations');\n this.changes = new Collection({\n name: `${this.options.id}-changes`,\n persistence: changesPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.snapshots = new Collection({\n name: `${this.options.id}-snapshots`,\n persistence: snapshotsPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.syncOperations = new Collection({\n name: `${this.options.id}-sync-operations`,\n persistence: syncOperationsPersistence?.adapter,\n indices: [createIndex('collectionName'), createIndex('status')],\n reactivity,\n });\n this.changes.on('persistence.error', error => changesPersistence?.handler(error));\n this.snapshots.on('persistence.error', error => snapshotsPersistence?.handler(error));\n this.syncOperations.on('persistence.error', error => syncOperationsPersistence?.handler(error));\n this.persistenceReady = 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 createPersistenceAdapter(name) {\n if (this.options.persistenceAdapter == null)\n return;\n let errorHandler = () => { };\n const adapter = this.options.persistenceAdapter(`${this.id}-${name}`, (handler) => {\n errorHandler = handler;\n });\n return {\n adapter,\n handler: (error) => errorHandler(error),\n };\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, this.remoteChanges.length);\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.isReady(),\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 (isEqual(remoteChange, change)) {\n return true;\n }\n }\n return false;\n };\n const removeRemoteChange = (change) => {\n for (let i = 0; i < this.remoteChanges.length; i += 1) {\n if (isEqual(this.remoteChanges[i], change)) {\n this.remoteChanges.splice(i, 1);\n return;\n }\n }\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 removeRemoteChange({ collectionName: options.name, type: 'insert', data: item });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'update', data });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'remove', data: id });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 = 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(() => {\n // clean up old sync operations\n 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 this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch((error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n 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 * @returns True if the collection is currently beeing synced, false otherwise.\n */\n isSyncing(name) {\n return this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 } }) != 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.persistenceReady;\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 = this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = 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((error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n 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 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 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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n const lastSnapshot = this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n });\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\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, { changes }),\n insert: (item) => {\n const itemExists = item.id && !!collection.findOne({\n id: item.id,\n }, { reactive: false });\n if (itemExists) {\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // update the item if it already exists\n collection.updateOne({ id: item.id }, { $set: item });\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n },\n update: (itemId, modifier) => {\n const itemExists = itemId && !collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (itemExists) {\n const item = { ...modifier.$set, id: itemId };\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n // insert the item if it does not exist\n collection.insert(item);\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n collection.updateOne({ id: itemId }, modifier);\n },\n remove: (itemId) => {\n const itemExists = !!collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n collection.removeOne({ id: itemId });\n },\n batch: (fn) => {\n collection.batch(() => {\n fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n 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 = this.changes.find({\n collectionName: name,\n }, { reactive: false }).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 = collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n }).map(item => item.id);\n collection.batch(() => {\n // update all items that are in the snapshot\n snapshot.forEach((item) => {\n const currentItem = collection.findOne({\n id: item.id,\n }, {\n reactive: false,\n });\n /* istanbul ignore else -- @preserve */\n if (currentItem) {\n /* istanbul ignore if -- @preserve */\n if (!isEqual(currentItem, item)) { // this case should never happen\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n collection.updateOne({ id: item.id }, { $set: item });\n }\n }\n else { // this case should never happen\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n }\n });\n // remove all items that are not in the snapshot\n nonExistingItemIds.forEach((id) => {\n collection.removeOne({ id });\n });\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","__publicField","task","resolve","reject","error","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","oldItem","newItem","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","changesPersistence","snapshotsPersistence","syncOperationsPersistence","Collection","createIndex","name","errorHandler","handler","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChange","modifier","cleanupFunction","syncTime","syncId","errors","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds","currentItem"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -1,5 +1,5 @@
1
- (function(f,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("@signaldb/core")):typeof define=="function"&&define.amd?define(["exports","@signaldb/core"],r):(f=typeof globalThis<"u"?globalThis:f||self,r(f.SignalDB={},f.core))})(this,function(f,r){"use strict";var D=Object.defineProperty;var I=(f,r,g)=>r in f?D(f,r,{enumerable:!0,configurable:!0,writable:!0,value:g}):f[r]=g;var p=(f,r,g)=>I(f,typeof r!="symbol"?r+"":r,g);function g(l,e,t={}){let s,i;const{leading:a=!1,trailing:o=!0}=t;function c(...d){const n=a&&!s,u=o&&!s;return s&&clearTimeout(s),s=setTimeout(()=>{s=null,o&&!n&&(i=l.apply(this,d))},e),n?i=l.apply(this,d):u||(i=null),i}return c}class E{constructor(){p(this,"queue",[]);p(this,"pendingPromise",!1)}add(e){return new Promise((t,s)=>{this.queue.push(()=>e().then(t).catch(i=>{throw s(i),i})),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=[],i=[],a=new Map(l.map(c=>[c.id,c])),o=new Map(e.map(c=>[c.id,c]));for(const[c,d]of a){const n=o.get(c);n?r.isEqual(n,d)||s.push(n):i.push(d)}for(const[c,d]of o)a.has(c)||t.push(d);return{added:t,modified:s,removed:i}}function C(l,e){if(e.items!=null)return e.items;const t=l||[];return e.changes.added.forEach(s=>{const i=t.findIndex(a=>a.id===s.id);i===-1?t.push(s):t[i]=s}),e.changes.modified.forEach(s=>{const i=t.findIndex(a=>a.id===s.id);i===-1?t.push(s):t[i]=s}),e.changes.removed.forEach(s=>{const i=t.findIndex(a=>a.id===s.id);i!==-1&&t.splice(i,1)}),t}async function P(l,e){const t=new r.Collection;t.batch(()=>{l.forEach(i=>t.insert(i)),e.forEach(i=>{if(i.type==="remove"){t.removeOne({id:i.data});return}const a={id:i.data.id},o=t.findOne(a);if(i.type==="insert"){o?t.updateOne(a,{$set:i.data}):t.insert(i.data);return}o?t.updateOne(a,i.data.modifier):t.insert(r.modify(a,i.data.modifier))})});const s=t.find().fetch();return await t.dispose(),s}function v(l){return l.added.length>0||l.modified.length>0||l.removed.length>0}function N(l,e){return v(w(l,e))}async function $({changes:l,lastSnapshot:e,data:t,pull:s,push:i,insert:a,update:o,remove:c,batch:d}){let n=t,u=e||[],m=C(e,n);if(l.length>0){const y=await P(u,l);if(N(u,y)){const S=await P(m,l),O=w(m,S);v(O)&&(await i(O),n=await s(),m=C(m,n)),u=y}}const h=n.changes==null?w(u,n.items):n.changes;return d(()=>{h.added.forEach(y=>a(y)),h.modified.forEach(y=>o(y.id,{$set:y})),h.removed.forEach(y=>c(y.id))}),m}class x{constructor(e){p(this,"options");p(this,"collections",new Map);p(this,"changes");p(this,"snapshots");p(this,"syncOperations");p(this,"remoteChanges",[]);p(this,"syncQueues",new Map);p(this,"persistenceReady");p(this,"isDisposed",!1);p(this,"instanceId",r.randomId());p(this,"id");p(this,"deboucedPush",g(e=>{this.pushChanges(e).catch(()=>{})},100));this.options={autostart:!0,...e},this.id=this.options.id||"default-sync-manager";const{reactivity:t}=this.options,s=this.createPersistenceAdapter("changes"),i=this.createPersistenceAdapter("snapshots"),a=this.createPersistenceAdapter("sync-operations");this.changes=new r.Collection({name:`${this.options.id}-changes`,persistence:s==null?void 0:s.adapter,indices:[r.createIndex("collectionName")],reactivity:t}),this.snapshots=new r.Collection({name:`${this.options.id}-snapshots`,persistence:i==null?void 0:i.adapter,indices:[r.createIndex("collectionName")],reactivity:t}),this.syncOperations=new r.Collection({name:`${this.options.id}-sync-operations`,persistence:a==null?void 0:a.adapter,indices:[r.createIndex("collectionName"),r.createIndex("status")],reactivity:t}),this.changes.on("persistence.error",o=>s==null?void 0:s.handler(o)),this.snapshots.on("persistence.error",o=>i==null?void 0:i.handler(o)),this.syncOperations.on("persistence.error",o=>a==null?void 0:a.handler(o)),this.persistenceReady=Promise.all([this.syncOperations.isReady(),this.changes.isReady(),this.snapshots.isReady()]).then(()=>{}),this.changes.setMaxListeners(1e3),this.snapshots.setMaxListeners(1e3),this.syncOperations.setMaxListeners(1e3)}createPersistenceAdapter(e){if(this.options.persistenceAdapter==null)return;let t=()=>{};return{adapter:this.options.persistenceAdapter(`${this.id}-${e}`,i=>{t=i}),handler:i=>t(i)}}getSyncQueue(e){return this.syncQueues.get(e)==null&&this.syncQueues.set(e,new E),this.syncQueues.get(e)}async dispose(){this.collections.clear(),this.syncQueues.clear(),this.remoteChanges.splice(0,this.remoteChanges.length),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.isReady(),syncPaused:!0});const s=a=>{for(const o of this.remoteChanges)if(r.isEqual(o,a))return!0;return!1},i=a=>{for(let o=0;o<this.remoteChanges.length;o+=1)if(r.isEqual(this.remoteChanges[o],a)){this.remoteChanges.splice(o,1);return}};e.on("added",a=>{if(s({collectionName:t.name,type:"insert",data:a})){i({collectionName:t.name,type:"insert",data:a});return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"insert",data:a}),!this.getCollectionProperties(t.name).syncPaused&&this.schedulePush(t.name)}),e.on("changed",({id:a},o)=>{const c={id:a,modifier:o};if(s({collectionName:t.name,type:"update",data:c})){i({collectionName:t.name,type:"update",data:c});return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"update",data:c}),!this.getCollectionProperties(t.name).syncPaused&&this.schedulePush(t.name)}),e.on("removed",({id:a})=>{if(s({collectionName:t.name,type:"remove",data:a})){i({collectionName:t.name,type:"remove",data:a});return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"remove",data:a}),!this.getCollectionProperties(t.name).syncPaused&&this.schedulePush(t.name)}),this.options.autostart&&this.startSync(t.name).catch(a=>{this.options.onError&&this.options.onError(this.getCollectionProperties(t.name).options,a)})}schedulePush(e){this.deboucedPush(e)}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 i=>{if(i==null)await this.sync(e);else{const a=Date.now(),o=this.syncOperations.insert({start:a,collectionName:e,instanceId:this.instanceId,status:"active"});await this.syncWithData(e,i).then(()=>{this.syncOperations.removeMany({id:{$ne:o},collectionName:e,$or:[{end:{$lte:a}},{status:"active"}]}),this.syncOperations.updateOne({id:o},{$set:{status:"done",end:Date.now()}})}).catch(c=>{throw this.options.onError&&this.options.onError(this.getCollectionProperties(e).options,c),this.syncOperations.updateOne({id:o},{$set:{status:"error",end:Date.now(),error:c.stack||c.message}}),c})}}):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,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("@signaldb/core")):typeof define=="function"&&define.amd?define(["exports","@signaldb/core"],r):(f=typeof globalThis<"u"?globalThis:f||self,r(f.SignalDB={},f.core))})(this,function(f,r){"use strict";var I=Object.defineProperty;var D=(f,r,g)=>r in f?I(f,r,{enumerable:!0,configurable:!0,writable:!0,value:g}):f[r]=g;var l=(f,r,g)=>D(f,typeof r!="symbol"?r+"":r,g);function g(d,e,t={}){let s,n;const{leading:a=!1,trailing:o=!0}=t;function c(...u){const i=a&&!s,p=o&&!s;return s&&clearTimeout(s),s=setTimeout(()=>{s=null,o&&!i&&(n=d.apply(this,u))},e),i?n=d.apply(this,u):p||(n=null),n}return c}class O{constructor(){l(this,"queue",[]);l(this,"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(d,e){const t=[],s=[],n=[],a=new Map(d.map(c=>[c.id,c])),o=new Map(e.map(c=>[c.id,c]));for(const[c,u]of a){const i=o.get(c);i?r.isEqual(i,u)||s.push(i):n.push(u)}for(const[c,u]of o)a.has(c)||t.push(u);return{added:t,modified:s,removed:n}}function C(d,e){if(e.items!=null)return e.items;const t=d||[];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(d,e){const t=new Map(d.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?r.modify(n,s.data.modifier):r.modify({id:s.data.id},s.data.modifier))}}),[...t.values()]}function v(d){return d.added.length>0||d.modified.length>0||d.removed.length>0}function N(d,e){return v(w(d,e))}async function $({changes:d,lastSnapshot:e,data:t,pull:s,push:n,insert:a,update:o,remove:c,batch:u}){let i=t,p=e||[],m=C(e,i);if(d.length>0){const y=P(p,d);if(N(p,y)){const x=P(m,d),E=w(m,x);v(E)&&(await n(E),i=await s(),m=C(m,i)),p=y}}const h=i.changes==null?w(p,i.items):i.changes;return u(()=>{h.added.forEach(y=>a(y)),h.modified.forEach(y=>o(y.id,{$set:y})),h.removed.forEach(y=>c(y.id))}),m}class S{constructor(e){l(this,"options");l(this,"collections",new Map);l(this,"changes");l(this,"snapshots");l(this,"syncOperations");l(this,"scheduledPushes",new Set);l(this,"remoteChanges",[]);l(this,"syncQueues",new Map);l(this,"persistenceReady");l(this,"isDisposed",!1);l(this,"instanceId",r.randomId());l(this,"id");l(this,"debouncedFlush");this.options={autostart:!0,...e},this.id=this.options.id||"default-sync-manager";const{reactivity:t}=this.options,s=this.createPersistenceAdapter("changes"),n=this.createPersistenceAdapter("snapshots"),a=this.createPersistenceAdapter("sync-operations");this.changes=new r.Collection({name:`${this.options.id}-changes`,persistence:s==null?void 0:s.adapter,indices:[r.createIndex("collectionName")],reactivity:t}),this.snapshots=new r.Collection({name:`${this.options.id}-snapshots`,persistence:n==null?void 0:n.adapter,indices:[r.createIndex("collectionName")],reactivity:t}),this.syncOperations=new r.Collection({name:`${this.options.id}-sync-operations`,persistence:a==null?void 0:a.adapter,indices:[r.createIndex("collectionName"),r.createIndex("status")],reactivity:t}),this.changes.on("persistence.error",o=>s==null?void 0:s.handler(o)),this.snapshots.on("persistence.error",o=>n==null?void 0:n.handler(o)),this.syncOperations.on("persistence.error",o=>a==null?void 0:a.handler(o)),this.persistenceReady=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=g(this.flushScheduledPushes,this.options.debounceTime??100)}createPersistenceAdapter(e){if(this.options.persistenceAdapter==null)return;let t=()=>{};return{adapter:this.options.persistenceAdapter(`${this.id}-${e}`,n=>{t=n}),handler:n=>t(n)}}getSyncQueue(e){return this.syncQueues.get(e)==null&&this.syncQueues.set(e,new O),this.syncQueues.get(e)}async dispose(){this.collections.clear(),this.syncQueues.clear(),this.remoteChanges.splice(0,this.remoteChanges.length),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.isReady(),syncPaused:!0});const s=a=>{for(const o of this.remoteChanges)if(r.isEqual(o,a))return!0;return!1},n=a=>{for(let o=0;o<this.remoteChanges.length;o+=1)if(r.isEqual(this.remoteChanges[o],a)){this.remoteChanges.splice(o,1);return}};e.on("added",a=>{if(s({collectionName:t.name,type:"insert",data:a})){n({collectionName:t.name,type:"insert",data:a});return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"insert",data:a}),!this.getCollectionProperties(t.name).syncPaused&&this.schedulePush(t.name)}),e.on("changed",({id:a},o)=>{const c={id:a,modifier:o};if(s({collectionName:t.name,type:"update",data:c})){n({collectionName:t.name,type:"update",data:c});return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"update",data:c}),!this.getCollectionProperties(t.name).syncPaused&&this.schedulePush(t.name)}),e.on("removed",({id:a})=>{if(s({collectionName:t.name,type:"remove",data:a})){n({collectionName:t.name,type:"remove",data:a});return}this.changes.insert({collectionName:t.name,time:Date.now(),type:"remove",data:a}),!this.getCollectionProperties(t.name).syncPaused&&this.schedulePush(t.name)}),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=>{if(n==null)await this.sync(e);else{const a=Date.now(),o=this.syncOperations.insert({start:a,collectionName:e,instanceId:this.instanceId,status:"active"});await this.syncWithData(e,n).then(()=>{this.syncOperations.removeMany({id:{$ne:o},collectionName:e,$or:[{end:{$lte:a}},{status:"active"}]}),this.syncOperations.updateOne({id:o},{$set:{status:"done",end:Date.now()}})}).catch(c=>{throw this.options.onError&&this.options.onError(this.getCollectionProperties(e).options,c),this.syncOperations.updateOne({id:o},{$set:{status:"error",end:Date.now(),error:c.stack||c.message}}),c})}}):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){return this.syncOperations.findOne({...e?{collectionName:e}:{},status:"active"},{fields:{status:1}})!=null}async isReady(){await this.persistenceReady}async sync(e,t={}){if(this.isDisposed)throw new Error("SyncManager is disposed");await this.isReady();const{options:s,readyPromise:i}=this.getCollectionProperties(e);await i;const a=this.syncOperations.find({collectionName:e,instanceId:this.instanceId,status:"active"},{reactive:!1}).count()>0,o=Date.now();let c=null;await new Promise(n=>{setTimeout(n,0)});const d=async()=>{const n=this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1});if(t!=null&&t.onlyWithChanges&&this.changes.find({collectionName:e,time:{$lte:o}},{sort:{time:1},reactive:!1}).count()===0)return;a||(c=this.syncOperations.insert({start:o,collectionName:e,instanceId:this.instanceId,status:"active"}));const u=await this.options.pull(s,{lastFinishedSyncStart:n==null?void 0:n.start,lastFinishedSyncEnd:n==null?void 0:n.end});await this.syncWithData(e,u)};await(t!=null&&t.force?d():this.getSyncQueue(e).add(d)).catch(n=>{throw c!=null&&(this.options.onError&&this.options.onError(s,n),this.syncOperations.updateOne({id:c},{$set:{status:"error",end:Date.now(),error:n.stack||n.message}})),n}),c!=null&&(this.syncOperations.removeMany({id:{$ne:c},collectionName:e,$or:[{end:{$lte:o}},{status:"active"}]}),this.syncOperations.updateOne({id:c},{$set:{status:"done",end:Date.now()}}))}async pushChanges(e){await this.sync(e,{onlyWithChanges:!0})}async syncWithData(e,t){const{collection:s,options:i}=this.getCollectionProperties(e),a=Date.now(),o=this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1}),c=this.snapshots.findOne({collectionName:e},{sort:{time:-1},reactive:!1}),d=this.changes.find({collectionName:e,time:{$lte:a}},{sort:{time:1},reactive:!1}).fetch();await $({changes:d,lastSnapshot:c==null?void 0:c.items,data:t,pull:()=>this.options.pull(i,{lastFinishedSyncStart:o==null?void 0:o.start,lastFinishedSyncEnd:o==null?void 0:o.end}),push:n=>this.options.push(i,{changes:n}),insert:n=>{if(n.id&&!!s.findOne({id:n.id},{reactive:!1})){this.remoteChanges.push({collectionName:e,type:"update",data:{id:n.id,modifier:{$set:n}}}),s.updateOne({id:n.id},{$set:n});return}this.remoteChanges.push({collectionName:e,type:"insert",data:n}),s.insert(n)},update:(n,u)=>{if(n&&!s.findOne({id:n},{reactive:!1})){const h={...u.$set,id:n};this.remoteChanges.push({collectionName:e,type:"insert",data:h}),s.insert(h);return}this.remoteChanges.push({collectionName:e,type:"update",data:{id:n,modifier:u}}),s.updateOne({id:n},u)},remove:n=>{s.findOne({id:n},{reactive:!1})&&(this.remoteChanges.push({collectionName:e,type:"remove",data:n}),s.removeOne({id:n}))},batch:n=>{s.batch(()=>{n()})}}).then(async n=>{if(this.snapshots.removeMany({collectionName:e,time:{$lte:a}}),this.changes.removeMany({collectionName:e,id:{$in:d.map(h=>h.id)}}),this.snapshots.insert({time:a,collectionName:e,items:n}),await new Promise(h=>{setTimeout(h,0)}),this.changes.find({collectionName:e},{reactive:!1}).count()>0){await this.sync(e,{force:!0,onlyWithChanges:!0});return}const m=s.find({id:{$nin:n.map(h=>h.id)}},{reactive:!1}).map(h=>h.id);s.batch(()=>{n.forEach(h=>{const y=!!s.findOne({id:h.id},{reactive:!1});/* istanbul ignore else -- @preserve */y?(this.remoteChanges.push({collectionName:e,type:"update",data:{id:h.id,modifier:{$set:h}}}),s.updateOne({id:h.id},{$set:h})):(this.remoteChanges.push({collectionName:e,type:"insert",data:h}),s.insert(h))}),m.forEach(h=>{s.removeOne({id:h})})})})}}f.SyncManager=x,Object.defineProperty(f,Symbol.toStringTag,{value:"Module"})});
4
+ `)}`)}isSyncing(e){return this.syncOperations.findOne({...e?{collectionName:e}:{},status:"active"},{fields:{status:1}})!=null}async isReady(){await this.persistenceReady}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=this.syncOperations.find({collectionName:e,instanceId:this.instanceId,status:"active"},{reactive:!1}).count()>0,o=Date.now();let c=null;await new Promise(i=>{setTimeout(i,0)});const u=async()=>{const i=this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1});if(t!=null&&t.onlyWithChanges&&this.changes.find({collectionName:e,time:{$lte:o}},{sort:{time:1},reactive:!1}).count()===0)return;a||(c=this.syncOperations.insert({start:o,collectionName:e,instanceId:this.instanceId,status:"active"}));const p=await this.options.pull(s,{lastFinishedSyncStart:i==null?void 0:i.start,lastFinishedSyncEnd:i==null?void 0:i.end});await this.syncWithData(e,p)};await(t!=null&&t.force?u():this.getSyncQueue(e).add(u)).catch(i=>{throw c!=null&&(this.options.onError&&this.options.onError(s,i),this.syncOperations.updateOne({id:c},{$set:{status:"error",end:Date.now(),error:i.stack||i.message}})),i}),c!=null&&(this.syncOperations.removeMany({id:{$ne:c},collectionName:e,$or:[{end:{$lte:o}},{status:"active"}]}),this.syncOperations.updateOne({id:c},{$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=this.syncOperations.findOne({collectionName:e,status:"done"},{sort:{end:-1},reactive:!1}),c=this.snapshots.findOne({collectionName:e},{sort:{time:-1},reactive:!1}),u=this.changes.find({collectionName:e,time:{$lte:a}},{sort:{time:1},reactive:!1}).fetch();await $({changes:u,lastSnapshot:c==null?void 0:c.items,data:t,pull:()=>this.options.pull(n,{lastFinishedSyncStart:o==null?void 0:o.start,lastFinishedSyncEnd:o==null?void 0:o.end}),push:i=>this.options.push(n,{changes:i}),insert:i=>{if(i.id&&!!s.findOne({id:i.id},{reactive:!1})){this.remoteChanges.push({collectionName:e,type:"update",data:{id:i.id,modifier:{$set:i}}}),s.updateOne({id:i.id},{$set:i});return}this.remoteChanges.push({collectionName:e,type:"insert",data:i}),s.insert(i)},update:(i,p)=>{if(i&&!s.findOne({id:i},{reactive:!1})){const h={...p.$set,id:i};this.remoteChanges.push({collectionName:e,type:"insert",data:h}),s.insert(h);return}this.remoteChanges.push({collectionName:e,type:"update",data:{id:i,modifier:p}}),s.updateOne({id:i},p)},remove:i=>{s.findOne({id:i},{reactive:!1})&&(this.remoteChanges.push({collectionName:e,type:"remove",data:i}),s.removeOne({id:i}))},batch:i=>{s.batch(()=>{i()})}}).then(async i=>{if(this.snapshots.removeMany({collectionName:e,time:{$lte:a}}),this.changes.removeMany({collectionName:e,id:{$in:u.map(h=>h.id)}}),this.snapshots.insert({time:a,collectionName:e,items:i}),await new Promise(h=>{setTimeout(h,0)}),this.changes.find({collectionName:e},{reactive:!1}).count()>0){await this.sync(e,{force:!0,onlyWithChanges:!0});return}const m=s.find({id:{$nin:i.map(h=>h.id)}},{reactive:!1}).map(h=>h.id);s.batch(()=>{i.forEach(h=>{const y=s.findOne({id:h.id},{reactive:!1});/* istanbul ignore else -- @preserve */if(y){/* istanbul ignore if -- @preserve */r.isEqual(y,h)||(this.remoteChanges.push({collectionName:e,type:"update",data:{id:h.id,modifier:{$set:h}}}),s.updateOne({id:h.id},{$set:h}))}else this.remoteChanges.push({collectionName:e,type:"insert",data:h}),s.insert(h)}),m.forEach(h=>{s.removeOne({id:h})})})})}}f.SyncManager=S,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 * 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 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 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 { added, modified, removed };\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 { Collection, 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 async function applyChanges(items, changes) {\n const collection = new Collection();\n collection.batch(() => {\n items.forEach(item => collection.insert(item));\n changes.forEach((change) => {\n if (change.type === 'remove') {\n collection.removeOne({ id: change.data });\n return;\n }\n const selector = { id: change.data.id };\n const itemExists = collection.findOne(selector);\n if (change.type === 'insert') {\n if (itemExists) { // update item if it alread exists\n collection.updateOne(selector, { $set: change.data });\n }\n else { // insert item if it does not exist\n collection.insert(change.data);\n }\n return;\n }\n // change.type === 'update'\n if (itemExists) { // update item if it exists\n collection.updateOne(selector, change.data.modifier);\n }\n else { // insert item if it does not exist\n collection.insert(modify(selector, change.data.modifier));\n }\n });\n });\n const result = collection.find().fetch();\n await collection.dispose();\n return result;\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 = await 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 = await 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 batch(() => {\n newChanges.added.forEach(item => insert(item));\n newChanges.modified.forEach(item => update(item.id, { $set: item }));\n newChanges.removed.forEach(item => remove(item.id));\n });\n return newSnapshot;\n}\n","import { Collection, randomId, isEqual, createIndex } 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 remoteChanges = [];\n syncQueues = new Map();\n persistenceReady;\n isDisposed = false;\n instanceId = randomId();\n id;\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.persistenceAdapter] Persistence 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 */\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 changesPersistence = this.createPersistenceAdapter('changes');\n const snapshotsPersistence = this.createPersistenceAdapter('snapshots');\n const syncOperationsPersistence = this.createPersistenceAdapter('sync-operations');\n this.changes = new Collection({\n name: `${this.options.id}-changes`,\n persistence: changesPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.snapshots = new Collection({\n name: `${this.options.id}-snapshots`,\n persistence: snapshotsPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.syncOperations = new Collection({\n name: `${this.options.id}-sync-operations`,\n persistence: syncOperationsPersistence?.adapter,\n indices: [createIndex('collectionName'), createIndex('status')],\n reactivity,\n });\n this.changes.on('persistence.error', error => changesPersistence?.handler(error));\n this.snapshots.on('persistence.error', error => snapshotsPersistence?.handler(error));\n this.syncOperations.on('persistence.error', error => syncOperationsPersistence?.handler(error));\n this.persistenceReady = 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 }\n createPersistenceAdapter(name) {\n if (this.options.persistenceAdapter == null)\n return;\n let errorHandler = () => { };\n const adapter = this.options.persistenceAdapter(`${this.id}-${name}`, (handler) => {\n errorHandler = handler;\n });\n return {\n adapter,\n handler: (error) => errorHandler(error),\n };\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, this.remoteChanges.length);\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.isReady(),\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 (isEqual(remoteChange, change)) {\n return true;\n }\n }\n return false;\n };\n const removeRemoteChange = (change) => {\n for (let i = 0; i < this.remoteChanges.length; i += 1) {\n if (isEqual(this.remoteChanges[i], change)) {\n this.remoteChanges.splice(i, 1);\n return;\n }\n }\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 removeRemoteChange({ collectionName: options.name, type: 'insert', data: item });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'update', data });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'remove', data: id });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 deboucedPush = debounce((name) => {\n this.pushChanges(name).catch(() => { });\n }, 100);\n schedulePush(name) {\n this.deboucedPush(name);\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 = 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(() => {\n // clean up old sync operations\n 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 this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch((error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n 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 * @returns True if the collection is currently beeing synced, false otherwise.\n */\n isSyncing(name) {\n return this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 } }) != 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.persistenceReady;\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 = this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = 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((error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n 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 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 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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n const lastSnapshot = this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n });\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\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, { changes }),\n insert: (item) => {\n const itemExists = item.id && !!collection.findOne({\n id: item.id,\n }, { reactive: false });\n if (itemExists) {\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // update the item if it already exists\n collection.updateOne({ id: item.id }, { $set: item });\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n },\n update: (itemId, modifier) => {\n const itemExists = itemId && !collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (itemExists) {\n const item = { ...modifier.$set, id: itemId };\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n // insert the item if it does not exist\n collection.insert(item);\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n collection.updateOne({ id: itemId }, modifier);\n },\n remove: (itemId) => {\n const itemExists = !!collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n collection.removeOne({ id: itemId });\n },\n batch: (fn) => {\n collection.batch(() => {\n fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n 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 = this.changes.find({\n collectionName: name,\n }, { reactive: false }).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 = collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n }).map(item => item.id);\n collection.batch(() => {\n // update all items that are in the snapshot\n snapshot.forEach((item) => {\n const itemExists = !!collection.findOne({\n id: item.id,\n }, {\n reactive: false,\n });\n /* istanbul ignore else -- @preserve */\n if (itemExists) {\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n collection.updateOne({ id: item.id }, { $set: item });\n }\n else { // this case should never happen\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n }\n });\n // remove all items that are not in the snapshot\n nonExistingItemIds.forEach((id) => {\n collection.removeOne({ id });\n });\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","__publicField","task","resolve","reject","error","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","oldItem","newItem","isEqual","getSnapshot","lastSnapshot","data","items","index","i","applyChanges","changes","collection","Collection","change","selector","itemExists","modify","hasChanges","hasDifference","sync","pull","push","insert","update","remove","batch","newData","previousSnapshot","newSnapshot","lastSnapshotWithChanges","newSnapshotWithChanges","changesToPush","newChanges","SyncManager","randomId","name","reactivity","changesPersistence","snapshotsPersistence","syncOperationsPersistence","createIndex","errorHandler","handler","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChange","modifier","cleanupFunction","syncTime","syncId","errors","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 * 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 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 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 { added, modified, removed };\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 batch(() => {\n newChanges.added.forEach(item => insert(item));\n newChanges.modified.forEach(item => update(item.id, { $set: item }));\n newChanges.removed.forEach(item => remove(item.id));\n });\n return newSnapshot;\n}\n","import { Collection, randomId, isEqual, createIndex } 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 persistenceReady;\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.persistenceAdapter] Persistence 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 changesPersistence = this.createPersistenceAdapter('changes');\n const snapshotsPersistence = this.createPersistenceAdapter('snapshots');\n const syncOperationsPersistence = this.createPersistenceAdapter('sync-operations');\n this.changes = new Collection({\n name: `${this.options.id}-changes`,\n persistence: changesPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.snapshots = new Collection({\n name: `${this.options.id}-snapshots`,\n persistence: snapshotsPersistence?.adapter,\n indices: [createIndex('collectionName')],\n reactivity,\n });\n this.syncOperations = new Collection({\n name: `${this.options.id}-sync-operations`,\n persistence: syncOperationsPersistence?.adapter,\n indices: [createIndex('collectionName'), createIndex('status')],\n reactivity,\n });\n this.changes.on('persistence.error', error => changesPersistence?.handler(error));\n this.snapshots.on('persistence.error', error => snapshotsPersistence?.handler(error));\n this.syncOperations.on('persistence.error', error => syncOperationsPersistence?.handler(error));\n this.persistenceReady = 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 createPersistenceAdapter(name) {\n if (this.options.persistenceAdapter == null)\n return;\n let errorHandler = () => { };\n const adapter = this.options.persistenceAdapter(`${this.id}-${name}`, (handler) => {\n errorHandler = handler;\n });\n return {\n adapter,\n handler: (error) => errorHandler(error),\n };\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, this.remoteChanges.length);\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.isReady(),\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 (isEqual(remoteChange, change)) {\n return true;\n }\n }\n return false;\n };\n const removeRemoteChange = (change) => {\n for (let i = 0; i < this.remoteChanges.length; i += 1) {\n if (isEqual(this.remoteChanges[i], change)) {\n this.remoteChanges.splice(i, 1);\n return;\n }\n }\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 removeRemoteChange({ collectionName: options.name, type: 'insert', data: item });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'insert',\n data: item,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'update', data });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'update',\n data,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 removeRemoteChange({ collectionName: options.name, type: 'remove', data: id });\n return;\n }\n this.changes.insert({\n collectionName: options.name,\n time: Date.now(),\n type: 'remove',\n data: id,\n });\n if (this.getCollectionProperties(options.name).syncPaused)\n return;\n this.schedulePush(options.name);\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 = 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(() => {\n // clean up old sync operations\n 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 this.syncOperations.updateOne({ id: syncId }, {\n $set: { status: 'done', end: Date.now() },\n });\n })\n .catch((error) => {\n if (this.options.onError) {\n this.options.onError(this.getCollectionProperties(name).options, error);\n }\n 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 * @returns True if the collection is currently beeing synced, false otherwise.\n */\n isSyncing(name) {\n return this.syncOperations.findOne({\n ...name ? { collectionName: name } : {},\n status: 'active',\n }, { fields: { status: 1 } }) != 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.persistenceReady;\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 = this.syncOperations.find({\n collectionName: name,\n instanceId: this.instanceId,\n status: 'active',\n }, {\n reactive: false,\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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n if (options?.onlyWithChanges) {\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\n }).count();\n if (currentChanges === 0)\n return;\n }\n if (!hasActiveSyncs) {\n syncId = 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((error) => {\n if (syncId != null) {\n if (this.options.onError)\n this.options.onError(collectionOptions, error);\n 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 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 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 = this.syncOperations.findOne({\n collectionName: name,\n status: 'done',\n }, {\n sort: { end: -1 },\n reactive: false,\n });\n const lastSnapshot = this.snapshots.findOne({\n collectionName: name,\n }, {\n sort: { time: -1 },\n reactive: false,\n });\n const currentChanges = this.changes.find({\n collectionName: name,\n time: { $lte: syncTime },\n }, {\n sort: { time: 1 },\n reactive: false,\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, { changes }),\n insert: (item) => {\n const itemExists = item.id && !!collection.findOne({\n id: item.id,\n }, { reactive: false });\n if (itemExists) {\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n // update the item if it already exists\n collection.updateOne({ id: item.id }, { $set: item });\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n },\n update: (itemId, modifier) => {\n const itemExists = itemId && !collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (itemExists) {\n const item = { ...modifier.$set, id: itemId };\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n // insert the item if it does not exist\n collection.insert(item);\n return;\n }\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: itemId, modifier },\n });\n collection.updateOne({ id: itemId }, modifier);\n },\n remove: (itemId) => {\n const itemExists = !!collection.findOne({\n id: itemId,\n }, { reactive: false });\n if (!itemExists)\n return;\n this.remoteChanges.push({\n collectionName: name,\n type: 'remove',\n data: itemId,\n });\n collection.removeOne({ id: itemId });\n },\n batch: (fn) => {\n collection.batch(() => {\n fn();\n });\n },\n })\n .then(async (snapshot) => {\n // clean up old snapshots\n this.snapshots.removeMany({\n collectionName: name,\n time: { $lte: syncTime },\n });\n // clean up processed changes\n this.changes.removeMany({\n collectionName: name,\n id: { $in: currentChanges.map(c => c.id) },\n });\n // insert new snapshot\n 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 = this.changes.find({\n collectionName: name,\n }, { reactive: false }).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 = collection.find({\n id: { $nin: snapshot.map(item => item.id) },\n }, {\n reactive: false,\n }).map(item => item.id);\n collection.batch(() => {\n // update all items that are in the snapshot\n snapshot.forEach((item) => {\n const currentItem = collection.findOne({\n id: item.id,\n }, {\n reactive: false,\n });\n /* istanbul ignore else -- @preserve */\n if (currentItem) {\n /* istanbul ignore if -- @preserve */\n if (!isEqual(currentItem, item)) { // this case should never happen\n this.remoteChanges.push({\n collectionName: name,\n type: 'update',\n data: { id: item.id, modifier: { $set: item } },\n });\n collection.updateOne({ id: item.id }, { $set: item });\n }\n }\n else { // this case should never happen\n this.remoteChanges.push({\n collectionName: name,\n type: 'insert',\n data: item,\n });\n collection.insert(item);\n }\n });\n // remove all items that are not in the snapshot\n nonExistingItemIds.forEach((id) => {\n collection.removeOne({ id });\n });\n });\n });\n }\n}\n"],"names":["debounce","fn","wait","options","timeout","result","leading","trailing","debounced","args","shouldCallImmediately","shouldCallTrailing","PromiseQueue","__publicField","task","resolve","reject","error","computeChanges","oldItems","newItems","added","modified","removed","oldItemsMap","item","newItemsMap","id","oldItem","newItem","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","changesPersistence","snapshotsPersistence","syncOperationsPersistence","Collection","createIndex","name","errorHandler","handler","collection","collectionParameters","hasRemoteChange","remoteChange","removeRemoteChange","modifier","cleanupFunction","syncTime","syncId","errors","collectionOptions","readyPromise","hasActiveSyncs","doSync","lastFinishedSync","currentChanges","itemId","snapshot","c","nonExistingItemIds","currentItem"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signaldb/sync",
3
- "version": "1.1.2",
3
+ "version": "1.2.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "build": "rimraf dist && vite build"