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 +206 -2
- package/lib/entropic-bond.js +121 -57
- package/lib/entropic-bond.js.map +1 -1
- package/lib/entropic-bond.umd.cjs +2 -2
- package/lib/entropic-bond.umd.cjs.map +1 -1
- package/package.json +13 -12
- package/lib/auth/auth-mock.d.ts +0 -22
- package/lib/auth/auth.d.ts +0 -131
- package/lib/auth/user-auth-types.d.ts +0 -22
- package/lib/cloud-functions/cloud-functions-mock.d.ts +0 -10
- package/lib/cloud-functions/cloud-functions.d.ts +0 -19
- package/lib/cloud-storage/cloud-storage.d.ts +0 -23
- package/lib/cloud-storage/mock-cloud-storage.d.ts +0 -20
- package/lib/cloud-storage/stored-file.d.ts +0 -39
- package/lib/index.d.ts +0 -20
- package/lib/observable/observable.d.ts +0 -52
- package/lib/persistent/entropic-component.d.ts +0 -75
- package/lib/persistent/persistent.d.ts +0 -373
- package/lib/server-auth/server-auth-mock.d.ts +0 -12
- package/lib/server-auth/server-auth.d.ts +0 -24
- package/lib/store/cached-props-updater.d.ts +0 -66
- package/lib/store/data-source.d.ts +0 -158
- package/lib/store/json-data-source.d.ts +0 -77
- package/lib/store/mocks/test-user.d.ts +0 -54
- package/lib/store/model.d.ts +0 -244
- package/lib/store/store.d.ts +0 -62
- package/lib/types/utility-types.d.ts +0 -44
- package/lib/utils/test-utils/test-person.d.ts +0 -33
- package/lib/utils/utils.d.ts +0 -60
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
|
|
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) |
|
package/lib/entropic-bond.js
CHANGED
|
@@ -15,16 +15,16 @@ var e = class {
|
|
|
15
15
|
get subscribersCount() {
|
|
16
16
|
return this.subscribers.size;
|
|
17
17
|
}
|
|
18
|
-
}, t =
|
|
19
|
-
|
|
20
|
-
|
|
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/
|
|
24
|
-
var r =
|
|
25
|
-
|
|
26
|
-
|
|
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?.() ??
|
|
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
|
|
43
|
+
return n(a);
|
|
44
44
|
}
|
|
45
45
|
//#endregion
|
|
46
|
-
//#region \0@oxc-project+runtime@0.
|
|
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
|
|
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
|
-
}
|
|
226
|
-
|
|
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
|
|
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]
|
|
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(
|
|
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) =>
|
|
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(
|
|
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
|
|
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 =
|
|
598
|
+
let r = O.toPersistentDocumentChange(t);
|
|
582
599
|
this._beforeDocumentChange?.(r, n);
|
|
583
600
|
let i = {};
|
|
584
|
-
t.type
|
|
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
|
|
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
|
-
}
|
|
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
|
-
},
|
|
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 =
|
|
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" ?
|
|
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
|
-
} :
|
|
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
|
|
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
|
-
}
|
|
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) =>
|
|
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
|
-
},
|
|
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
|
|
875
|
-
return
|
|
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
|
|
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
|
-
|
|
980
|
+
M = s([j("MockCloudStorage", () => new M())], M);
|
|
917
981
|
//#endregion
|
|
918
982
|
//#region src/cloud-storage/stored-file.ts
|
|
919
|
-
var
|
|
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
|
-
}({}),
|
|
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 ||
|
|
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 =
|
|
1011
|
+
this._provider = A.createInstance(this._cloudStorageProviderName);
|
|
948
1012
|
} catch {
|
|
949
|
-
this._provider =
|
|
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],
|
|
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
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
-
},
|
|
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
|
|
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
|
|
1267
|
+
function W(e) {
|
|
1204
1268
|
return e ? e.replace(/([-_ ][\w])/g, (e) => e.toUpperCase().replace("-", "").replace("_", "").replace(" ", "")) : "";
|
|
1205
1269
|
}
|
|
1206
|
-
function
|
|
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
|
|
1275
|
+
function K(e, t) {
|
|
1212
1276
|
return t.split(".").reduce((e, t) => e[t], e);
|
|
1213
1277
|
}
|
|
1214
1278
|
//#endregion
|
|
1215
|
-
export {
|
|
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
|