entropic-bond 1.59.5 → 1.60.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.
package/README.md CHANGED
@@ -19,7 +19,7 @@ Typically, you will derive all your business logic entities from the `EntropicCo
19
19
 
20
20
  ### API
21
21
 
22
- You can find the API documentation in the docs/ directory.
22
+ You can find the API documentation in the [docs/](./docs) directory.
23
23
 
24
24
  ### Persistence
25
25
 
@@ -31,7 +31,7 @@ The properties or attributes that you want to be streamed should be preceded by
31
31
 
32
32
  ```ts
33
33
  @registerPersistentClass( 'MyEntity' )
34
- class MyEntity extends EntropicBond {
34
+ class MyEntity extends Persistent {
35
35
  @persistent private _persistentProp1: string
36
36
  @persistent private _persistentProp2: boolean
37
37
  @persistent private _persistentProp3: AnotherPersistentObject
@@ -88,10 +88,214 @@ You should instantiate the concrete implementation of the `DataSource` and pass
88
88
  Store.useDataSource( new JsonDataSource() )
89
89
  ```
90
90
 
91
+ > See the complete example at [samples/01-persistence.ts](./samples/01-persistence.ts)
92
+
91
93
  ### Observability
92
94
 
95
+ The observability mechanism allows entities to notify when their properties change. Derive your class from `EntropicComponent` (which extends `Persistent`) and use `changeProp` in setters or `pushAndNotify`/`removeAndNotify` for arrays.
96
+
97
+ ```ts
98
+ import { EntropicComponent } from 'entropic-bond'
99
+
100
+ class MyEntity extends EntropicComponent {
101
+ private _name: string = ''
102
+
103
+ get name(): string { return this._name }
104
+ set name(value: string) { this.changeProp('name', value) }
105
+ }
106
+
107
+ const entity = new MyEntity()
108
+ const unsub = entity.onChange(event => console.log('Changed:', event))
109
+
110
+ entity.name = 'new value' // triggers the onChange listener
111
+ unsub() // removes the listener
112
+ ```
113
+
114
+ You can also directly use the generic `Observable<T>` class for standalone observer patterns.
115
+
116
+ ```ts
117
+ import { Observable } from 'entropic-bond'
118
+
119
+ const observable = new Observable<string>()
120
+ const unsubscribe = observable.subscribe(event => console.log(event))
121
+ observable.notify('hello')
122
+ ```
123
+
124
+ > See the complete example at [samples/02-observability.ts](./samples/02-observability.ts)
125
+
93
126
  ### Auth
94
127
 
128
+ Authentication is abstracted via `AuthService`. Register a concrete implementation and use the `Auth` singleton.
129
+
130
+ ```ts
131
+ import { Auth, AuthMock } from 'entropic-bond'
132
+
133
+ Auth.useAuthService(new AuthMock())
134
+
135
+ async function example() {
136
+ const user = await Auth.instance.login({ authProvider: 'email', email: 'user@test.com', password: '123456' })
137
+ console.log(user.id, user.email)
138
+
139
+ Auth.instance.onAuthStateChange(credentials => {
140
+ console.log('Auth state changed:', credentials)
141
+ })
142
+ }
143
+ ```
144
+
145
+ Plugins exist for production providers (e.g., Firebase Authentication). To create a custom provider, implement the `AuthService` abstract class.
146
+
147
+ > See the complete example at [samples/03-auth.ts](./samples/03-auth.ts)
148
+
149
+ ### Server Auth
150
+
151
+ For admin-level user management (list, update, delete users), use `ServerAuth`.
152
+
153
+ ```ts
154
+ import { ServerAuth, ServerAuthMock } from 'entropic-bond'
155
+
156
+ ServerAuth.useServerAuthService(new ServerAuthMock())
157
+
158
+ const user = await ServerAuth.instance.getUser('user-id')
159
+ await ServerAuth.instance.updateUser('user-id', { name: 'Updated Name' })
160
+ await ServerAuth.instance.deleteUser('user-id')
161
+ ```
162
+
163
+ > See the complete example at [samples/04-server-auth.ts](./samples/04-server-auth.ts)
164
+
165
+ ### Cloud Storage
166
+
167
+ File storage is abstracted via `CloudStorage`. Register a provider and use the singleton, or use the `StoredFile` persistent entity.
168
+
169
+ ```ts
170
+ import { CloudStorage, MockCloudStorage, StoredFile } from 'entropic-bond'
171
+
172
+ CloudStorage.useCloudStorage(new MockCloudStorage())
173
+
174
+ // Direct usage
175
+ const url = await CloudStorage.defaultCloudStorage.save('my-file', fileData)
176
+ const downloadUrl = await CloudStorage.defaultCloudStorage.getUrl('my-file')
177
+
178
+ // Or with StoredFile (persistent entity)
179
+ const file = new StoredFile()
180
+ file.setDataToStore(someBlob)
181
+ await file.save()
182
+ console.log(file.url)
183
+ ```
184
+
185
+ > See the complete example at [samples/05-cloud-storage.ts](./samples/05-cloud-storage.ts)
186
+
187
+ ### Cloud Functions
188
+
189
+ Call serverless functions through an abstract interface.
190
+
191
+ ```ts
192
+ import { CloudFunctions, CloudFunctionsMock } from 'entropic-bond'
193
+
194
+ const mockService = new CloudFunctionsMock({
195
+ myFunction: async (params) => `Hello ${params.name}`
196
+ })
197
+ CloudFunctions.useCloudFunctionsService(mockService)
198
+
199
+ const fn = CloudFunctions.instance.getFunction('myFunction')
200
+ const result = await fn({ name: 'World' })
201
+ ```
202
+
203
+ > See the complete example at [samples/06-cloud-functions.ts](./samples/06-cloud-functions.ts)
204
+
205
+ ### Realtime document listeners
206
+
207
+ The `Model` supports realtime updates on documents and collections.
208
+
209
+ ```ts
210
+ const model = Store.getModel<MyEntity>('MyEntity')
211
+
212
+ // Listen to a single document
213
+ const unsubscribe1 = model.onDocumentChange('doc-id', change => {
214
+ console.log('Before:', change.before, 'After:', change.after)
215
+ })
216
+
217
+ // Listen to a collection query
218
+ const unsubscribe2 = model.onCollectionChange(
219
+ model.find().where('name', '==', 'foo'),
220
+ change => console.log('Collection changed:', change)
221
+ )
222
+
223
+ // Listen to a wildcard collection template
224
+ const unsubscribe3 = model.onCollectionTemplateChange('{userId}/Posts', change => {
225
+ console.log('Post changed in', change.collectionPath)
226
+ })
227
+ ```
228
+
229
+ > See the complete example at [samples/07-realtime-listeners.ts](./samples/07-realtime-listeners.ts)
230
+
231
+ ### DataSource plugins
232
+
233
+ The persistence layer uses a `DataSource` to communicate with the database. Implement the abstract `DataSource` class to support new backends.
234
+
235
+ ```ts
236
+ import { DataSource, Store } from 'entropic-bond'
237
+
238
+ class MyDatabase extends DataSource {
239
+ // implement all abstract methods: findById, find, save, delete, etc.
240
+ }
241
+
242
+ Store.useDataSource(new MyDatabase())
243
+ ```
244
+
245
+ The official Firebase plugin is available as `entropic-bond-firebase`.
246
+
247
+ ```sh
248
+ npm i entropic-bond-firebase
249
+ ```
250
+
251
+ > See the complete example at [samples/10-datasource-plugin.ts](./samples/10-datasource-plugin.ts)
252
+
253
+ ### Cached property references
254
+
255
+ When a property holds a reference to another persistent entity, you can embed selected primitive fields directly in the reference to avoid extra queries.
256
+
257
+ ```ts
258
+ @registerPersistentClass('Team')
259
+ class Team extends EntropicComponent {
260
+ @persistent private _name: string
261
+ }
262
+
263
+ @registerPersistentClass('User')
264
+ class User extends EntropicComponent {
265
+ @persistentReferenceWithCachedProps(['_name'], 'Team')
266
+ private _team: Team
267
+ }
268
+ ```
269
+
270
+ The `CachedPropsUpdater` (installed via `DataSource.installCachedPropsUpdater()`) will propagate changes to cached props across all referencing documents.
271
+
272
+ > See the complete example at [samples/08-cached-props.ts](./samples/08-cached-props.ts)
273
+
274
+ ### Utility functions
275
+
276
+ ```ts
277
+ import { camelCase, snakeCase, replaceValue, getDeepValue } from 'entropic-bond'
278
+
279
+ camelCase('hello-world') // 'helloWorld'
280
+ snakeCase('helloWorld') // 'hello-world'
281
+ replaceValue('Hi ${name}', { name: 'John' }) // 'Hi John'
282
+ ```
283
+
284
+ > See the complete example at [samples/09-utils.ts](./samples/09-utils.ts)
95
285
 
286
+ ### Samples
96
287
 
288
+ Complete, runnable examples are available in the [`samples/`](./samples) directory:
97
289
 
290
+ | Section | Sample |
291
+ |---------|--------|
292
+ | Persistence | [01-persistence.ts](./samples/01-persistence.ts) |
293
+ | Observability | [02-observability.ts](./samples/02-observability.ts) |
294
+ | Auth | [03-auth.ts](./samples/03-auth.ts) |
295
+ | Server Auth | [04-server-auth.ts](./samples/04-server-auth.ts) |
296
+ | Cloud Storage | [05-cloud-storage.ts](./samples/05-cloud-storage.ts) |
297
+ | Cloud Functions | [06-cloud-functions.ts](./samples/06-cloud-functions.ts) |
298
+ | Realtime listeners | [07-realtime-listeners.ts](./samples/07-realtime-listeners.ts) |
299
+ | Cached property references | [08-cached-props.ts](./samples/08-cached-props.ts) |
300
+ | Utility functions | [09-utils.ts](./samples/09-utils.ts) |
301
+ | DataSource plugins | [10-datasource-plugin.ts](./samples/10-datasource-plugin.ts) |
@@ -15,16 +15,16 @@ var e = class {
15
15
  get subscribersCount() {
16
16
  return this.subscribers.size;
17
17
  }
18
- }, t = /* @__PURE__ */ new Uint8Array(16);
19
- function n() {
20
- return crypto.getRandomValues(t);
18
+ }, t = [];
19
+ for (let e = 0; e < 256; ++e) t.push((e + 256).toString(16).slice(1));
20
+ function n(e, n = 0) {
21
+ return (t[e[n + 0]] + t[e[n + 1]] + t[e[n + 2]] + t[e[n + 3]] + "-" + t[e[n + 4]] + t[e[n + 5]] + "-" + t[e[n + 6]] + t[e[n + 7]] + "-" + t[e[n + 8]] + t[e[n + 9]] + "-" + t[e[n + 10]] + t[e[n + 11]] + t[e[n + 12]] + t[e[n + 13]] + t[e[n + 14]] + t[e[n + 15]]).toLowerCase();
21
22
  }
22
23
  //#endregion
23
- //#region node_modules/uuid/dist/stringify.js
24
- var r = [];
25
- for (let e = 0; e < 256; ++e) r.push((e + 256).toString(16).slice(1));
26
- function i(e, t = 0) {
27
- return (r[e[t + 0]] + r[e[t + 1]] + r[e[t + 2]] + r[e[t + 3]] + "-" + r[e[t + 4]] + r[e[t + 5]] + "-" + r[e[t + 6]] + r[e[t + 7]] + "-" + r[e[t + 8]] + r[e[t + 9]] + "-" + r[e[t + 10]] + r[e[t + 11]] + r[e[t + 12]] + r[e[t + 13]] + r[e[t + 14]] + r[e[t + 15]]).toLowerCase();
24
+ //#region node_modules/uuid/dist/rng.js
25
+ var r = /* @__PURE__ */ new Uint8Array(16);
26
+ function i() {
27
+ return crypto.getRandomValues(r);
28
28
  }
29
29
  //#endregion
30
30
  //#region node_modules/uuid/dist/v4.js
@@ -33,17 +33,17 @@ function a(e, t, n) {
33
33
  }
34
34
  function o(e, t, r) {
35
35
  e ||= {};
36
- let a = e.random ?? e.rng?.() ?? n();
36
+ let a = e.random ?? e.rng?.() ?? i();
37
37
  if (a.length < 16) throw Error("Random bytes length must be >= 16");
38
38
  if (a[6] = a[6] & 15 | 64, a[8] = a[8] & 63 | 128, t) {
39
39
  if (r ||= 0, r < 0 || r + 16 > t.length) throw RangeError(`UUID byte range ${r}:${r + 15} is out of buffer bounds`);
40
40
  for (let e = 0; e < 16; ++e) t[r + e] = a[e];
41
41
  return t;
42
42
  }
43
- return i(a);
43
+ return n(a);
44
44
  }
45
45
  //#endregion
46
- //#region \0@oxc-project+runtime@0.137.0/helpers/esm/decorate.js
46
+ //#region \0@oxc-project+runtime@0.148.0/helpers/esm/decorate.js
47
47
  function s(e, t, n, r) {
48
48
  var i = arguments.length, a = i < 3 ? t : r === null ? r = Object.getOwnPropertyDescriptor(t, n) : r, o;
49
49
  if (typeof Reflect == "object" && typeof Reflect.decorate == "function") a = Reflect.decorate(e, t, n, r);
@@ -112,7 +112,7 @@ var c = class e {
112
112
  }
113
113
  isPropValueValid(e) {
114
114
  let t = this.getPropInfo(e);
115
- return t.validator ? t.validator(this[t.name], t, this) : !0;
115
+ return !t.validator || t.validator(this[t.name], t, this);
116
116
  }
117
117
  clone(e) {
118
118
  let t = e.toObject();
@@ -222,8 +222,8 @@ var c = class e {
222
222
  if (n.length === 0) return "undefined[]";
223
223
  let t = n[0];
224
224
  return t instanceof e ? t.className + "[]" : typeof t + "[]";
225
- } else if (n instanceof e) return n.className;
226
- else return typeof n;
225
+ }
226
+ return n instanceof e ? n.className : typeof n;
227
227
  }
228
228
  static getSystemRegisteredReferencesWithCachedProps() {
229
229
  return e.registeredClasses().reduce((t, n) => {
@@ -282,7 +282,7 @@ function m(e, t, n, r) {
282
282
  }
283
283
  function h(e) {
284
284
  return function(t, n) {
285
- Object.getOwnPropertyDescriptor(t, "_persistentProperties") || (t._persistentProperties ? t._persistentProperties = [...t._persistentProperties] : t._persistentProperties = []);
285
+ Object.getOwnPropertyDescriptor(t, "_persistentProperties") || (t._persistentProperties = t._persistentProperties ? [...t._persistentProperties] : []);
286
286
  let r = t._persistentProperties.find((e) => e.name === n);
287
287
  r ? Object.assign(r, e) : t._persistentProperties.push({
288
288
  name: n,
@@ -332,7 +332,7 @@ var S = class extends c {
332
332
  }
333
333
  changeProp(e, t) {
334
334
  let n = "_" + String(e);
335
- return this[n] === t ? !1 : (this[n] = t, this._onChange.notify({ [e]: t }), !0);
335
+ return this[n] !== t && (this[n] = t, this._onChange.notify({ [e]: t }), !0);
336
336
  }
337
337
  notify(e) {
338
338
  this._onChange.notify(e);
@@ -377,6 +377,23 @@ var S = class extends c {
377
377
  this._stream.delete(e, this.collectionName).then(() => t()).catch((e) => n(e));
378
378
  });
379
379
  }
380
+ runTransaction(e) {
381
+ return this._stream.runTransaction((t) => e({
382
+ findById: async (e) => {
383
+ let n = await t.findById(e, this.collectionName);
384
+ return n ? c.createInstance(n) : void 0;
385
+ },
386
+ save: async (e) => {
387
+ let n = e.toObject();
388
+ this.collectionName !== n.__className && (n.__rootCollections[this.collectionName] = n.__rootCollections[n.__className], delete n.__rootCollections[n.__className]), await Promise.all(Object.entries(n.__rootCollections).map(([e, n]) => Promise.all((n ?? []).map((n) => t.save(n.id, e, n)))));
389
+ },
390
+ delete: async (e) => {
391
+ await t.delete(e.id, this.collectionName);
392
+ }
393
+ })).catch((e) => {
394
+ throw e instanceof D && e.storedDoc && !(e.storedDoc instanceof c) && (e.storedDoc = c.createInstance(e.storedDoc)), e;
395
+ });
396
+ }
380
397
  find() {
381
398
  return new w(this);
382
399
  }
@@ -398,13 +415,13 @@ var S = class extends c {
398
415
  return this.mapToInstance(() => this._stream.next(e));
399
416
  }
400
417
  onDocumentChange(e, t) {
401
- return this._stream.onDocumentChange(this.collectionName, e, (e) => t(D.toPersistentDocumentChange(e)));
418
+ return this._stream.onDocumentChange(this.collectionName, e, (e) => t(O.toPersistentDocumentChange(e)));
402
419
  }
403
420
  onCollectionChange(e, t) {
404
- return this._stream.onCollectionChange(this.preprocessQueryObject(e.getQueryObject()), this.collectionName, (e) => t(e.map((e) => D.toPersistentDocumentChange(e))));
421
+ return this._stream.onCollectionChange(this.preprocessQueryObject(e.getQueryObject()), this.collectionName, (e) => t(e.map((e) => O.toPersistentDocumentChange(e))));
405
422
  }
406
423
  onCollectionTemplateChange(e, t) {
407
- return this._stream.onDocumentTemplateChange(e, (e) => t(D.toPersistentDocumentChange(e)));
424
+ return this._stream.onDocumentTemplateChange(e, (e) => t(O.toPersistentDocumentChange(e)));
408
425
  }
409
426
  mapToInstance(e) {
410
427
  return new Promise((t, n) => {
@@ -415,7 +432,7 @@ var S = class extends c {
415
432
  if (Object.values(e).length === 0) return e;
416
433
  let t = e.operations?.map((e) => {
417
434
  let t = e.value[0] ?? e.value;
418
- return D.isArrayOperator(e.operator) && t instanceof c ? {
435
+ return O.isArrayOperator(e.operator) && t instanceof c ? {
419
436
  property: c.searchableArrayNameFor(e.property),
420
437
  operator: e.operator,
421
438
  value: Array.isArray(e.value) ? e.value.map((e) => e.id) : t.id,
@@ -578,10 +595,10 @@ var S = class extends c {
578
595
  return n ? this.onDocumentChange(t, n) : Promise.resolve();
579
596
  }
580
597
  async onDocumentChange(t, n) {
581
- let r = D.toPersistentDocumentChange(t);
598
+ let r = O.toPersistentDocumentChange(t);
582
599
  this._beforeDocumentChange?.(r, n);
583
600
  let i = {};
584
- t.type !== "update" || !r.before || r.after?.id && this._disabledChangeListeners.has(r.after?.id) || (await Promise.all(n.map(async (t) => {
601
+ t.type === "update" && r.before && (r.after?.id && this._disabledChangeListeners.has(r.after?.id) || (await Promise.all(n.map(async (t) => {
585
602
  let n = e.ownerCollectionPath(c.createInstance(t.ownerClassName()), t, r.params), a = await this._resolveCollectionPaths(n);
586
603
  await Promise.all(a.map(async (e) => {
587
604
  let n = T.getModel(e), a = n.find(), o = !1;
@@ -606,7 +623,7 @@ var S = class extends c {
606
623
  } else return Promise.resolve();
607
624
  })]);
608
625
  }));
609
- })), this._afterDocumentChange?.(i, n));
626
+ })), this._afterDocumentChange?.(i, n)));
610
627
  }
611
628
  disableChangeListener(e) {
612
629
  this._disabledChangeListeners.add(e.id);
@@ -618,7 +635,11 @@ var S = class extends c {
618
635
  let r;
619
636
  return r = typeof t.ownerCollection == "function" ? t.ownerCollection(e, t, n) : t.ownerCollection ?? e.className, r;
620
637
  }
621
- }, D = class e {
638
+ }, D = class extends Error {
639
+ constructor(e) {
640
+ super("Transaction conflict: the document was modified by another writer."), this.storedDoc = e, this.name = "TransactionConflictError";
641
+ }
642
+ }, O = class e {
622
643
  constructor() {
623
644
  this._cachedPropsUpdater = void 0;
624
645
  }
@@ -659,7 +680,8 @@ var S = class extends c {
659
680
  if (typeof e == "object" && !Array.isArray(e)) {
660
681
  let t = Object.keys(e)[0], [n, r] = this.toPropertyPathValue(e[t]);
661
682
  return [`${t}${n ? "." + n : ""}`, r];
662
- } else return [void 0, e];
683
+ }
684
+ return [void 0, e];
663
685
  }
664
686
  static isStringMatchingTemplate(e, t) {
665
687
  let n = e.split("/"), r = t.split("/");
@@ -689,9 +711,9 @@ var S = class extends c {
689
711
  }
690
712
  return i;
691
713
  }
692
- }, O = class extends D {
714
+ }, k = class extends O {
693
715
  constructor(e) {
694
- super(), this._jsonRawData = {}, this._lastMatchingDocs = [], this._lastLimit = 0, this._cursor = 0, this._simulateDelay = 0, this._pendingPromises = [], this._documentListeners = {}, this._collectionListeners = {}, e && (this._jsonRawData = e);
716
+ super(), this._jsonRawData = {}, this._versions = {}, this._lastMatchingDocs = [], this._lastLimit = 0, this._cursor = 0, this._simulateDelay = 0, this._pendingPromises = [], this._documentListeners = {}, this._collectionListeners = {}, e && (this._jsonRawData = e);
695
717
  }
696
718
  setDataStore(e) {
697
719
  return this._jsonRawData = e, this;
@@ -708,7 +730,7 @@ var S = class extends c {
708
730
  return Object.entries(e).forEach(([e, t]) => {
709
731
  this._jsonRawData[e] || (this._jsonRawData[e] = {}), t?.forEach((t) => {
710
732
  let n = this._jsonRawData[e][t.id];
711
- this._jsonRawData[e][t.id] = t, this.notifyChange(e, t, n);
733
+ this._jsonRawData[e][t.id] = t, this.bumpVersion(e, t.id), this.notifyChange(e, t, n);
712
734
  });
713
735
  }), this.resolveWithDelay();
714
736
  }
@@ -719,7 +741,42 @@ var S = class extends c {
719
741
  }
720
742
  delete(e, t) {
721
743
  if (this._simulateError?.delete) throw Error(this._simulateError.delete);
722
- return delete this._jsonRawData[t][e], this.resolveWithDelay();
744
+ return delete this._jsonRawData[t][e], this.bumpVersion(t, e), this.resolveWithDelay();
745
+ }
746
+ runTransaction(e) {
747
+ let t = [], n = [];
748
+ return e({
749
+ findById: (e, n) => (t.push({
750
+ collectionName: n,
751
+ id: e,
752
+ version: this.versionOf(n, e)
753
+ }), this.resolveWithDelay(this._jsonRawData[n]?.[e])),
754
+ save: (e, t, r) => (n.push({
755
+ type: "save",
756
+ collectionName: t,
757
+ id: e,
758
+ doc: r
759
+ }), this.resolveWithDelay()),
760
+ delete: (e, t) => (n.push({
761
+ type: "delete",
762
+ collectionName: t,
763
+ id: e
764
+ }), this.resolveWithDelay())
765
+ }).then((e) => {
766
+ let r = t.find((e) => e.version !== this.versionOf(e.collectionName, e.id));
767
+ if (r) throw new D(this._jsonRawData[r.collectionName]?.[r.id]);
768
+ return n.forEach((e) => {
769
+ if (e.type === "delete") delete this._jsonRawData[e.collectionName][e.id], this.bumpVersion(e.collectionName, e.id);
770
+ else {
771
+ this._jsonRawData[e.collectionName] || (this._jsonRawData[e.collectionName] = {});
772
+ let t = this._jsonRawData[e.collectionName][e.id], n = {
773
+ ...t ?? {},
774
+ ...e.doc
775
+ };
776
+ this._jsonRawData[e.collectionName][e.id] = n, this.bumpVersion(e.collectionName, e.id), this.notifyChange(e.collectionName, n, t);
777
+ }
778
+ }), e;
779
+ });
723
780
  }
724
781
  next(e) {
725
782
  return e && (this._lastLimit = e), this.incCursor(this._lastLimit), this.resolveWithDelay(this._lastMatchingDocs.slice(this._cursor, this._cursor + this._lastLimit));
@@ -758,7 +815,7 @@ var S = class extends c {
758
815
  let i = this._documentListeners[n];
759
816
  i ||= (this._documentListeners[n] = {}, this._documentListeners[n]);
760
817
  let a = (r) => {
761
- r.params = D.extractTemplateParams(n, e), t(r);
818
+ r.params = O.extractTemplateParams(n, e), t(r);
762
819
  }, o = Math.random().toString(36).substring(2, 9);
763
820
  i[o] = a, r.push(() => delete i[o]);
764
821
  }), () => r.forEach((e) => e());
@@ -773,12 +830,12 @@ var S = class extends c {
773
830
  this._cursor += e, this._cursor > this._lastMatchingDocs.length && (this._cursor = this._lastMatchingDocs.length);
774
831
  }
775
832
  simulateError(e) {
776
- return e === void 0 ? (this._simulateError = void 0, this) : (typeof e == "string" ? this._simulateError = {
833
+ return e === void 0 ? (this._simulateError = void 0, this) : (this._simulateError = typeof e == "string" ? {
777
834
  store: e,
778
835
  find: e,
779
836
  findById: e,
780
837
  delete: e
781
- } : this._simulateError = e, this);
838
+ } : e, this);
782
839
  }
783
840
  notifyChange(e, t, n) {
784
841
  let r = {
@@ -791,7 +848,7 @@ var S = class extends c {
791
848
  Object.values(this._documentListeners[e] ?? {}).forEach((e) => e(r)), Object.values(this._collectionListeners[e] ?? {}).forEach((e) => e(r));
792
849
  }
793
850
  decCursor(e) {
794
- return this._cursor -= e, this._cursor < 0 ? (this._cursor = 0, !0) : !1;
851
+ return this._cursor -= e, this._cursor < 0 && (this._cursor = 0, !0);
795
852
  }
796
853
  queryProcessor(e, t, n) {
797
854
  return {
@@ -808,7 +865,8 @@ var S = class extends c {
808
865
  if (n.aggregate) {
809
866
  let i = e.filter((e) => this.isQueryMatched(e, n));
810
867
  return r === 0 ? i : t.concat(i);
811
- } else return t.filter((e) => this.isQueryMatched(e, n));
868
+ }
869
+ return t.filter((e) => this.isQueryMatched(e, n));
812
870
  }, e);
813
871
  }
814
872
  deepValue(e, t) {
@@ -846,9 +904,15 @@ var S = class extends c {
846
904
  return Promise.resolve(this.collectionsMatchingTemplate(e));
847
905
  }
848
906
  collectionsMatchingTemplate(e) {
849
- return Object.keys(this._jsonRawData).filter((t) => D.isStringMatchingTemplate(e, t));
907
+ return Object.keys(this._jsonRawData).filter((t) => O.isStringMatchingTemplate(e, t));
908
+ }
909
+ versionOf(e, t) {
910
+ return this._versions[e]?.[t] ?? 0;
911
+ }
912
+ bumpVersion(e, t) {
913
+ this._versions[e] || (this._versions[e] = {}), this._versions[e][t] = (this._versions[e][t] ?? 0) + 1;
850
914
  }
851
- }, k = class e {
915
+ }, A = class e {
852
916
  static registerCloudStorage(t, n) {
853
917
  e._cloudStorageFactoryMap[t] = n;
854
918
  }
@@ -871,14 +935,14 @@ var S = class extends c {
871
935
  this._cloudStorageFactoryMap = {};
872
936
  }
873
937
  };
874
- function A(e, t) {
875
- return k.registerCloudStorage(e, t), (t) => {
938
+ function j(e, t) {
939
+ return A.registerCloudStorage(e, t), (t) => {
876
940
  t.prototype.__className = e;
877
941
  };
878
942
  }
879
943
  //#endregion
880
944
  //#region src/cloud-storage/mock-cloud-storage.ts
881
- var j = class extends k {
945
+ var M = class extends A {
882
946
  constructor(e = "") {
883
947
  super(), this._simulateDelay = 0, this._pendingPromises = [], this.mockFileSystem = {}, this._pathToMockFiles = e;
884
948
  }
@@ -913,18 +977,18 @@ var j = class extends k {
913
977
  return delete this.mockFileSystem[e], this.resolveWithDelay();
914
978
  }
915
979
  };
916
- j = s([A("MockCloudStorage", () => new j())], j);
980
+ M = s([j("MockCloudStorage", () => new M())], M);
917
981
  //#endregion
918
982
  //#region src/cloud-storage/stored-file.ts
919
- var M = /* @__PURE__ */ function(e) {
983
+ var N = /* @__PURE__ */ function(e) {
920
984
  return e[e.stored = 0] = "stored", e[e.pendingDataSet = 1] = "pendingDataSet", e[e.deleted = 2] = "deleted", e;
921
- }({}), N = class extends c {
985
+ }({}), P = class extends c {
922
986
  constructor(...t) {
923
987
  super(...t), this._onChange = new e();
924
988
  }
925
989
  async save({ data: e, fileName: t, progress: n, cloudStorageProvider: r } = {}) {
926
990
  let i = e || this._pendingData;
927
- i && (this._reference && await this.delete(), this.provider = r || k.defaultCloudStorage, this._originalFileName = t || (i instanceof File ? i.name : void 0), this._reference = await this.provider.save(this.id, i, n), this._url = await this.provider.getUrl(this._reference), this._pendingData = void 0, this._onChange.notify({
991
+ i && (this._reference && await this.delete(), this.provider = r || A.defaultCloudStorage, this._originalFileName = t || (i instanceof File ? i.name : void 0), this._reference = await this.provider.save(this.id, i, n), this._url = await this.provider.getUrl(this._reference), this._pendingData = void 0, this._onChange.notify({
928
992
  event: 0,
929
993
  storedFile: this
930
994
  }));
@@ -944,9 +1008,9 @@ var M = /* @__PURE__ */ function(e) {
944
1008
  }
945
1009
  get provider() {
946
1010
  if (!this._provider) try {
947
- this._provider = k.createInstance(this._cloudStorageProviderName);
1011
+ this._provider = A.createInstance(this._cloudStorageProviderName);
948
1012
  } catch {
949
- this._provider = k.defaultCloudStorage;
1013
+ this._provider = A.defaultCloudStorage;
950
1014
  }
951
1015
  return this._provider;
952
1016
  }
@@ -970,10 +1034,10 @@ var M = /* @__PURE__ */ function(e) {
970
1034
  return this._onChange.subscribe(e);
971
1035
  }
972
1036
  };
973
- s([l], N.prototype, "_reference", void 0), s([l], N.prototype, "_url", void 0), s([l], N.prototype, "_cloudStorageProviderName", void 0), s([l], N.prototype, "_originalFileName", void 0), s([l], N.prototype, "_mimeType", void 0), N = s([g("StoredFile")], N);
1037
+ s([l], P.prototype, "_reference", void 0), s([l], P.prototype, "_url", void 0), s([l], P.prototype, "_cloudStorageProviderName", void 0), s([l], P.prototype, "_originalFileName", void 0), s([l], P.prototype, "_mimeType", void 0), P = s([g("StoredFile")], P);
974
1038
  //#endregion
975
1039
  //#region src/auth/auth.ts
976
- var P = class {}, F = class t extends P {
1040
+ var F = class {}, I = class t extends F {
977
1041
  static {
978
1042
  this.error = { shouldBeRegistered: "You should register an auth service before using Auth." };
979
1043
  }
@@ -1023,7 +1087,7 @@ var P = class {}, F = class t extends P {
1023
1087
  static {
1024
1088
  this._instance = void 0;
1025
1089
  }
1026
- }, I = class extends P {
1090
+ }, L = class extends F {
1027
1091
  constructor(...e) {
1028
1092
  super(...e), this.pendingPromises = [], this._fakeRegisteredUsers = {};
1029
1093
  }
@@ -1098,7 +1162,7 @@ var P = class {}, F = class t extends P {
1098
1162
  creationDate: 0
1099
1163
  };
1100
1164
  }
1101
- }, L = class e {
1165
+ }, R = class e {
1102
1166
  constructor() {}
1103
1167
  static {
1104
1168
  this.error = { shouldBeRegistered: "You should register a cloud functions service with useCloudFunctionsService static method before using CloudFunctions." };
@@ -1126,7 +1190,7 @@ var P = class {}, F = class t extends P {
1126
1190
  processResult(e) {
1127
1191
  if (e != null) return e.__className ? c.createInstance(e) : Array.isArray(e) ? e.map((e) => this.processResult(e)) : typeof e == "object" ? Object.entries(e).reduce((e, [t, n]) => (e[t] = this.processResult(n), e), {}) : e;
1128
1192
  }
1129
- }, R = class {
1193
+ }, z = class {
1130
1194
  constructor(e) {
1131
1195
  this._registeredFunctions = e;
1132
1196
  }
@@ -1138,7 +1202,7 @@ var P = class {}, F = class t extends P {
1138
1202
  callFunction(e, t) {
1139
1203
  return e(t);
1140
1204
  }
1141
- }, z = class {}, B = class e extends z {
1205
+ }, B = class {}, V = class e extends B {
1142
1206
  static {
1143
1207
  this.error = { shouldBeRegistered: "You should register a Server Auth service before using the Server Auth." };
1144
1208
  }
@@ -1167,7 +1231,7 @@ var P = class {}, F = class t extends P {
1167
1231
  static {
1168
1232
  this._instance = void 0;
1169
1233
  }
1170
- }, V = class extends z {
1234
+ }, H = class extends B {
1171
1235
  constructor(e) {
1172
1236
  super(), this._userCredentials = e;
1173
1237
  }
@@ -1195,23 +1259,23 @@ var P = class {}, F = class t extends P {
1195
1259
  };
1196
1260
  //#endregion
1197
1261
  //#region src/utils/utils.ts
1198
- function H(e, t) {
1262
+ function U(e, t) {
1199
1263
  return e ? e.replace(/\${\s*(\w*)\s*}/g, function(e, n) {
1200
1264
  return t[n] || "";
1201
1265
  }) : "";
1202
1266
  }
1203
- function U(e) {
1267
+ function W(e) {
1204
1268
  return e ? e.replace(/([-_ ][\w])/g, (e) => e.toUpperCase().replace("-", "").replace("_", "").replace(" ", "")) : "";
1205
1269
  }
1206
- function W(e, t = "-") {
1270
+ function G(e, t = "-") {
1207
1271
  if (!e) return "";
1208
1272
  let n = e.slice(1).replace(/( |[A-Z])/g, (e) => e === " " ? "-" : t + e[0].toLowerCase());
1209
1273
  return e[0].toLocaleLowerCase() + n.replace(/--/g, "-");
1210
1274
  }
1211
- function G(e, t) {
1275
+ function K(e, t) {
1212
1276
  return t.split(".").reduce((e, t) => e[t], e);
1213
1277
  }
1214
1278
  //#endregion
1215
- export { F as Auth, I as AuthMock, P as AuthService, E as CachedPropsUpdater, L as CloudFunctions, R as CloudFunctionsMock, k as CloudStorage, D as DataSource, S as EntropicComponent, O as JsonDataSource, j as MockCloudStorage, C as Model, e as Observable, c as Persistent, w as Query, B as ServerAuth, V as ServerAuthMock, z as ServerAuthService, T as Store, N as StoredFile, M as StoredFileEvent, U as camelCase, G as getDeepValue, l as persistent, h as persistentParser, p as persistentPureReference, m as persistentPureReferenceWithCachedProps, d as persistentReference, u as persistentReferenceAt, f as persistentReferenceWithCachedProps, A as registerCloudStorage, _ as registerLegacyClassName, g as registerPersistentClass, H as replaceValue, y as required, b as requiredWithValidator, v as searchableArray, W as snakeCase, x as typeName };
1279
+ export { I as Auth, L as AuthMock, F as AuthService, E as CachedPropsUpdater, R as CloudFunctions, z as CloudFunctionsMock, A as CloudStorage, O as DataSource, S as EntropicComponent, k as JsonDataSource, M as MockCloudStorage, C as Model, e as Observable, c as Persistent, w as Query, V as ServerAuth, H as ServerAuthMock, B as ServerAuthService, T as Store, P as StoredFile, N as StoredFileEvent, D as TransactionConflictError, W as camelCase, K as getDeepValue, l as persistent, h as persistentParser, p as persistentPureReference, m as persistentPureReferenceWithCachedProps, d as persistentReference, u as persistentReferenceAt, f as persistentReferenceWithCachedProps, j as registerCloudStorage, _ as registerLegacyClassName, g as registerPersistentClass, U as replaceValue, y as required, b as requiredWithValidator, v as searchableArray, G as snakeCase, x as typeName };
1216
1280
 
1217
1281
  //# sourceMappingURL=entropic-bond.js.map