@livequery/client 2.0.31 → 2.0.104

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +477 -0
  2. package/dist/LivequeryCollection.d.ts +92 -0
  3. package/dist/LivequeryCollection.d.ts.map +1 -0
  4. package/dist/LivequeryCollection.js +231 -0
  5. package/dist/LivequeryCollection.js.map +1 -0
  6. package/dist/LivequeryCore.d.ts +67 -0
  7. package/dist/LivequeryCore.d.ts.map +1 -0
  8. package/dist/LivequeryCore.js +343 -0
  9. package/dist/LivequeryCore.js.map +1 -0
  10. package/dist/LivequeryDocument.d.ts +23 -0
  11. package/dist/LivequeryDocument.d.ts.map +1 -0
  12. package/dist/LivequeryDocument.js +22 -0
  13. package/dist/LivequeryDocument.js.map +1 -0
  14. package/dist/LivequeryMemoryStorage.d.ts +14 -0
  15. package/dist/LivequeryMemoryStorage.d.ts.map +1 -0
  16. package/dist/LivequeryMemoryStorage.js +89 -0
  17. package/dist/LivequeryMemoryStorage.js.map +1 -0
  18. package/dist/LivequeryStorge.d.ts +12 -0
  19. package/dist/LivequeryStorge.d.ts.map +1 -0
  20. package/dist/LivequeryStorge.js +2 -0
  21. package/dist/LivequeryStorge.js.map +1 -0
  22. package/dist/LivequeryTransporter.d.ts +22 -0
  23. package/dist/LivequeryTransporter.d.ts.map +1 -0
  24. package/dist/LivequeryTransporter.js +2 -0
  25. package/dist/LivequeryTransporter.js.map +1 -0
  26. package/dist/helpers/filterDocs.d.ts +5 -0
  27. package/dist/helpers/filterDocs.d.ts.map +1 -0
  28. package/dist/helpers/filterDocs.js +80 -0
  29. package/dist/helpers/filterDocs.js.map +1 -0
  30. package/dist/helpers/tryCatch.d.ts +2 -0
  31. package/dist/helpers/tryCatch.d.ts.map +1 -0
  32. package/dist/helpers/tryCatch.js +10 -0
  33. package/dist/helpers/tryCatch.js.map +1 -0
  34. package/dist/helpers/whenCompleted.d.ts +3 -0
  35. package/dist/helpers/whenCompleted.d.ts.map +1 -0
  36. package/dist/helpers/whenCompleted.js +5 -0
  37. package/dist/helpers/whenCompleted.js.map +1 -0
  38. package/dist/index.d.ts +9 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +9 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/types.d.ts +70 -0
  43. package/dist/types.d.ts.map +1 -0
  44. package/dist/types.js +2 -0
  45. package/dist/types.js.map +1 -0
  46. package/package.json +95 -18
  47. package/build/Collection.d.ts +0 -52
  48. package/build/Collection.js +0 -366
  49. package/build/index.d.ts +0 -1
  50. package/build/index.js +0 -1
  51. package/build/tsconfig.tsbuildinfo +0 -1
@@ -0,0 +1,231 @@
1
+ import { BehaviorSubject, debounceTime, EMPTY, filter, finalize, merge, Observable, pairwise, Subject, Subscription, switchMap, tap } from "rxjs";
2
+ import { LivequeryCore } from "./LivequeryCore.js";
3
+ import { LivequeryDocument } from "./LivequeryDocument.js";
4
+ export class LivequeryCollection {
5
+ core;
6
+ options;
7
+ id = (Math.random() * 1e18).toString(36);
8
+ #keys = new Map();
9
+ #indexes;
10
+ #filters = new Subject();
11
+ ref;
12
+ collection_ref;
13
+ items;
14
+ summary;
15
+ metadata;
16
+ loading;
17
+ filters;
18
+ paging;
19
+ error;
20
+ constructor(core, options = {}) {
21
+ this.core = core;
22
+ this.options = options;
23
+ this.#indexes = new Map();
24
+ this.items = new BehaviorSubject([]);
25
+ this.summary = new BehaviorSubject({});
26
+ this.loading = new BehaviorSubject(null);
27
+ this.filters = new BehaviorSubject(options?.filters || {});
28
+ this.paging = new BehaviorSubject({
29
+ total: 0,
30
+ current: 0
31
+ });
32
+ this.error = new BehaviorSubject(null);
33
+ if (options) {
34
+ this.options = options;
35
+ }
36
+ }
37
+ #commit(items) {
38
+ this.items.next(items);
39
+ this.#indexes = items.reduce((p, c, index) => {
40
+ p.set(c.value.id, index);
41
+ return p;
42
+ }, new Map());
43
+ }
44
+ #subscription = null;
45
+ initialize(ref) {
46
+ if (!ref)
47
+ return;
48
+ if (typeof window == 'undefined')
49
+ return;
50
+ this.ref = ref;
51
+ const refs = ref.split('/');
52
+ this.collection_ref = refs.length % 2 == 0 ? refs.slice(0, -1).join('/') : ref;
53
+ const timer = this.options.lazy !== true && setTimeout(() => !ref.includes('undefined') && this.query(this.filters.value || {}));
54
+ this.#subscription?.unsubscribe();
55
+ this.#subscription = merge(this.options.debounce ? merge(this.#filters.pipe(debounceTime(this.options.debounce), switchMap(filters => this.query(filters)))) : EMPTY, this.core.watch(this.ref, this.id, this.options.mode || 'server-first').pipe(finalize(() => {
56
+ timer && clearTimeout(timer);
57
+ }), tap(event => {
58
+ event.loading !== undefined && event.loading !== this.loading.value && this.loading.next(event.loading);
59
+ event.summary && this.summary.next(event.summary);
60
+ event.metadata && this.metadata.next(event.metadata);
61
+ event.paging && this.paging.next(event.paging);
62
+ event.error && this.error.next(event.error);
63
+ if (!event.changes || event.changes.length == 0)
64
+ return;
65
+ const chaos = event.changes && event.changes.some(change => {
66
+ if (change.type == 'added' || change.type == 'removed')
67
+ return true;
68
+ if (change.data && change.data.id != change.id)
69
+ return true;
70
+ return Object.keys(change.data || {}).some(k => this.#keys.has(k));
71
+ });
72
+ const sorter = (a, b) => {
73
+ for (const [key, order] of this.#keys) {
74
+ const va = a.value[key];
75
+ const vb = b.value[key];
76
+ if (typeof va === 'number' && typeof vb === 'number') {
77
+ if (va < vb)
78
+ return -order;
79
+ if (va > vb)
80
+ return order;
81
+ }
82
+ if (typeof va === 'string' && typeof vb === 'string') {
83
+ if (va < vb)
84
+ return -order;
85
+ if (va > vb)
86
+ return order;
87
+ }
88
+ }
89
+ return 0;
90
+ };
91
+ const events = event.changes.reduce((p, c) => {
92
+ return {
93
+ ...p,
94
+ [c.type]: [
95
+ ...(p[c.type] || []),
96
+ c
97
+ ]
98
+ };
99
+ }, {
100
+ added: [],
101
+ modified: [],
102
+ removed: []
103
+ });
104
+ const updated_items = events.modified.reduce((p, { data, id }) => {
105
+ const index = this.#indexes.get(id);
106
+ const target = index != undefined && index >= 0 ? p[index] : null;
107
+ target && target.next({ ...target.value, ...data });
108
+ return p;
109
+ }, this.items.value);
110
+ const new_items = (events.added
111
+ .filter(a => a.data)
112
+ .reduce((p, c) => {
113
+ if (!p.indexes.has(c.id)) {
114
+ const doc = new LivequeryDocument(this, { id: c.id, ...c.data });
115
+ p.list.push(doc);
116
+ p.indexes.add(c.id);
117
+ }
118
+ return p;
119
+ }, {
120
+ list: [],
121
+ indexes: new Set(this.#indexes.keys())
122
+ }));
123
+ const remove_indexes = (events.removed
124
+ .map(r => this.#indexes.get(r.id))
125
+ .filter(i => i != undefined)
126
+ .sort((a, b) => b - a));
127
+ const unsort_items = remove_indexes.reduce((p, index) => {
128
+ return [
129
+ ...p.slice(0, index),
130
+ ...p.slice(index + 1)
131
+ ];
132
+ }, [
133
+ ...updated_items,
134
+ ...new_items.list
135
+ ]);
136
+ const items = chaos ? unsort_items.sort(sorter) : unsort_items;
137
+ chaos && this.#commit(items);
138
+ event.paging && this.paging.next(event.paging);
139
+ }))).subscribe();
140
+ return this.#subscription;
141
+ }
142
+ async #query(filters, flush) {
143
+ if (!this.ref)
144
+ return;
145
+ this.error.next(null);
146
+ flush && this.#commit([]);
147
+ this.#keys = Object.entries(filters).reduce((p, [k, v]) => {
148
+ if (k.endsWith(':sort')) {
149
+ const field = k.split(':')[0];
150
+ p.set(field, v === 'asc' ? 1 : -1);
151
+ }
152
+ return p;
153
+ }, new Map());
154
+ this.filters.next(filters);
155
+ const cache = await this.core.query({
156
+ ref: this.ref,
157
+ filters,
158
+ collection_id: this.id
159
+ });
160
+ if (cache && cache.documents && flush) {
161
+ this.#commit(cache.documents.map(i => new LivequeryDocument(this, i)));
162
+ }
163
+ }
164
+ async query(filters) {
165
+ await this.#query(filters, true);
166
+ }
167
+ async debounceQuery(filters) {
168
+ this.#filters.next(filters);
169
+ }
170
+ async loadMore() {
171
+ const next = this.paging.value.next;
172
+ if (!next)
173
+ return;
174
+ const filters = {
175
+ ...this.filters.value,
176
+ ':after': next.cursor
177
+ };
178
+ await this.#query(filters || {}, false);
179
+ }
180
+ async loadPrev() {
181
+ const prev = this.paging.value.prev;
182
+ if (!prev)
183
+ return;
184
+ const filters = {
185
+ ...this.filters.value,
186
+ ':before': prev.cursor
187
+ };
188
+ await this.#query(filters || {}, false);
189
+ }
190
+ async loadAround(cursor) {
191
+ const filters = {
192
+ ...this.filters.value,
193
+ ':after': cursor,
194
+ ':before': cursor
195
+ };
196
+ await this.#query(filters || {}, false);
197
+ }
198
+ async add(payload) {
199
+ if (!this.collection_ref)
200
+ throw new Error('LivequeryCollection is not initialized with a ref');
201
+ return await this.core.add(this.collection_ref, payload);
202
+ }
203
+ update(id, payload) {
204
+ if (!this.collection_ref)
205
+ throw new Error('LivequeryCollection is not initialized with a ref');
206
+ return this.core.update(this.collection_ref, id, payload);
207
+ }
208
+ delete(id) {
209
+ if (!this.collection_ref)
210
+ throw new Error('LivequeryCollection is not initialized with a ref');
211
+ return this.core.delete(this.collection_ref, id);
212
+ }
213
+ trigger(action, payload) {
214
+ if (!this.ref)
215
+ throw new Error('LivequeryCollection is not initialized with a ref');
216
+ return this.core.trigger({
217
+ action,
218
+ payload,
219
+ ref: this.ref
220
+ });
221
+ }
222
+ resetError() {
223
+ this.error.next(null);
224
+ }
225
+ watch(check) {
226
+ return this.items.pipe(switchMap(items => merge(...items.map(item => item.pipe(pairwise(), filter(([p, n]) => {
227
+ return check(p, n);
228
+ }))))));
229
+ }
230
+ }
231
+ //# sourceMappingURL=LivequeryCollection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LivequeryCollection.js","sourceRoot":"","sources":["../src/LivequeryCollection.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ import { Observable, Subject } from "rxjs";
2
+ import type { LivequeryStorge } from "./LivequeryStorge.js";
3
+ import type { LivequeryQueryResult, LivequeryTransporter } from "./LivequeryTransporter.js";
4
+ import type { DataChangeEvent, LivequeryAction, Doc, LivequeryQueryParams, LivequeryFilters, RealtimeChangeSource } from "./types.js";
5
+ export type LivequeryCoreOptions = {
6
+ transporters: Record<string, LivequeryTransporter>;
7
+ storage: LivequeryStorge;
8
+ };
9
+ export type LivequeryLoadingState = null | 'next' | 'prev' | 'all';
10
+ export type SyncRequest = DataChangeEvent & {
11
+ ref: string;
12
+ collection_ref: string;
13
+ source: RealtimeChangeSource;
14
+ };
15
+ export type ConflictResolverFunction = <T extends Doc>(e: {
16
+ from: Record<string, string | number | boolean>;
17
+ old_document: T;
18
+ change: DataChangeEvent;
19
+ }) => {
20
+ approved: boolean;
21
+ document: T;
22
+ };
23
+ export type LivequeryCoreConfig = {
24
+ storage: LivequeryStorge;
25
+ transporters: Record<string, LivequeryTransporter>;
26
+ };
27
+ export type CollectionMetadata = {
28
+ collection_id: string;
29
+ document_id?: string;
30
+ data$: Subject<Partial<LivequeryQueryResult> & {
31
+ from: RealtimeChangeSource;
32
+ }>;
33
+ collection_ref: string;
34
+ mode: 'server-first' | 'local-first' | 'cache-first';
35
+ filters: Partial<LivequeryFilters<any>>;
36
+ };
37
+ export declare class LivequeryCore {
38
+ #private;
39
+ private readonly config;
40
+ constructor(config: LivequeryCoreConfig);
41
+ watch(ref: string, collection_id: string, mode: CollectionMetadata['mode']): Observable<Partial<LivequeryQueryResult> & {
42
+ from: RealtimeChangeSource;
43
+ }>;
44
+ query<T extends Doc>(req: LivequeryQueryParams<T> & {
45
+ collection_id: string;
46
+ }): Promise<{
47
+ documents: T[];
48
+ paging: import("./types.js").LivequeryPaging;
49
+ } | {
50
+ documents: T[];
51
+ } | undefined>;
52
+ add<T extends Doc>(collection_ref: string, doc: Record<string, any>): Promise<{
53
+ [key: string]: T;
54
+ }>;
55
+ update<T extends Doc>(collection_ref: string, id: string, data: Record<string, any>): Promise<{
56
+ [key: string]: {
57
+ id: string;
58
+ } & Partial<T>;
59
+ } | undefined>;
60
+ delete<T extends Doc>(collection_ref: string, id: string): Promise<{
61
+ [key: string]: {
62
+ id: string;
63
+ };
64
+ } | undefined>;
65
+ trigger<Response>(action: LivequeryAction): Observable<Response>;
66
+ }
67
+ //# sourceMappingURL=LivequeryCore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LivequeryCore.d.ts","sourceRoot":"","sources":["../src/LivequeryCore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmH,UAAU,EAAiC,OAAO,EAAiD,MAAM,MAAM,CAAA;AACzO,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAA;AAC3D,OAAO,KAAK,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAA;AAC3F,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,GAAG,EAAE,oBAAoB,EAAY,gBAAgB,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAA;AAM/I,MAAM,MAAM,oBAAoB,GAAG;IAC/B,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;IAClD,OAAO,EAAE,eAAe,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,qBAAqB,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,KAAK,CAAA;AAKlE,MAAM,MAAM,WAAW,GAAG,eAAe,GAAG;IACxC,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAA;IACtB,MAAM,EAAE,oBAAoB,CAAA;CAC/B,CAAA;AAID,MAAM,MAAM,wBAAwB,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE,CAAC,EAAE;IACtD,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAA;IAC/C,YAAY,EAAE,CAAC,CAAA;IACf,MAAM,EAAE,eAAe,CAAA;CAC1B,KAAK;IACF,QAAQ,EAAE,OAAO,CAAA;IACjB,QAAQ,EAAE,CAAC,CAAA;CACd,CAAA;AAGD,MAAM,MAAM,mBAAmB,GAAG;IAC9B,OAAO,EAAE,eAAe,CAAA;IACxB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;CACrD,CAAA;AAED,MAAM,MAAM,kBAAkB,GAAG;IAC7B,aAAa,EAAE,MAAM,CAAA;IACrB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,EAAE,OAAO,CAAC,OAAO,CAAC,oBAAoB,CAAC,GAAG;QAC3C,IAAI,EAAE,oBAAoB,CAAA;KAC7B,CAAC,CAAA;IACF,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,EAAE,cAAc,GAAG,aAAa,GAAG,aAAa,CAAA;IACpD,OAAO,EAAE,OAAO,CAAC,gBAAgB,CAAC,GAAG,CAAC,CAAC,CAAA;CAC1C,CAAA;AAMD,qBAAa,aAAa;;IAOV,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAN,MAAM,EAAE,mBAAmB;IA+HxD,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,EAAE,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAC;cAjJhE,oBAAoB;;IA4KxB,KAAK,CAAC,CAAC,SAAS,GAAG,EAAE,GAAG,EAAE,oBAAoB,CAAC,CAAC,CAAC,GAAG;QAAE,aAAa,EAAE,MAAM,CAAA;KAAE;;;;;;IAoL7E,GAAG,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;;IAkBnE,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;;gBAyB5C,MAAM;;;IAG7C,MAAM,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM;;gBAsBjB,MAAM;;;IAGnD,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe;CAK5C"}
@@ -0,0 +1,343 @@
1
+ import { concatMap, defer, EMPTY, expand, filter, finalize, forkJoin, from, groupBy, lastValueFrom, map, merge, mergeMap, Observable, of, reduce, scan, shareReplay, Subject, switchMap, takeUntil, takeWhile, tap, toArray } from "rxjs";
2
+ import { tryCatch } from "./helpers/tryCatch.js";
3
+ import { whenCompleted } from "./helpers/whenCompleted.js";
4
+ import { matchesAllFilters } from "./helpers/filterDocs.js";
5
+ export class LivequeryCore {
6
+ config;
7
+ #collections = new Map();
8
+ #refs = new Map();
9
+ #queries$ = new Subject();
10
+ #adding = new Map();
11
+ constructor(config) {
12
+ this.config = config;
13
+ this.#start();
14
+ }
15
+ #cache = new Map();
16
+ #query(e, deduplicate_key) {
17
+ const clear = () => deduplicate_key && this.#cache.delete(deduplicate_key);
18
+ const cached = deduplicate_key && this.#cache.get(deduplicate_key);
19
+ if (cached)
20
+ return Object.assign(cached, { clear });
21
+ const $ = from(Object.values(this.config.transporters)).pipe(mergeMap(transporter => (transporter.query(e).pipe(tap(result => {
22
+ for (const change of result.changes || []) {
23
+ change.type == 'added' && change.data && this.config.storage.add(change.collection_ref, {
24
+ id: change.data.id,
25
+ ...change.data
26
+ });
27
+ change.type == 'modified' && change.data && this.config.storage.update(change.collection_ref, change.id, change.data);
28
+ change.type == 'removed' && this.config.storage.delete(change.collection_ref, change.id);
29
+ }
30
+ }), map((result, index) => ({ result, index })), mergeMap(({ result, index }) => {
31
+ if (index == 0)
32
+ return of(result);
33
+ const changes = result.changes || [];
34
+ if (changes.length === 0)
35
+ return EMPTY;
36
+ const lock$ = this.#adding.get(e.collection.collection_ref);
37
+ if (!lock$) {
38
+ this.#broadcast(e.collection.collection_ref, 'realtime', changes);
39
+ return EMPTY;
40
+ }
41
+ const ok_changes = changes.filter(c => c.type != 'added');
42
+ const delay_changes = changes.filter(c => c.type == 'added');
43
+ this.#broadcast(e.collection.collection_ref, 'realtime', ok_changes);
44
+ return lock$.pipe(tap(() => this.#broadcast(e.collection.collection_ref, 'realtime', delay_changes)), switchMap(() => EMPTY));
45
+ })))), finalize(clear), shareReplay());
46
+ deduplicate_key && this.#cache.set(deduplicate_key, $);
47
+ return Object.assign($, { clear });
48
+ }
49
+ #start() {
50
+ lastValueFrom(merge(
51
+ // Server queries
52
+ this.#queries$.pipe(filter(req => req.collection.mode == 'server-first' || req.collection.mode == 'cache-first'), mergeMap(e => {
53
+ const deduplicate_key = `${e.collection.collection_id}:${JSON.stringify(e.filters)}`;
54
+ const before = e.filters?.[':before'];
55
+ const after = e.filters?.[':after'];
56
+ const around = e.filters?.[':around'];
57
+ const loading = ((!before && !after) || (before && after) || around) ? 'all' : (before ? 'prev' : 'next');
58
+ e.collection.data$.next({
59
+ from: 'query',
60
+ loading: e.collection.document_id ? 'all' : loading
61
+ });
62
+ return this.#query(e, deduplicate_key).pipe(takeUntil(whenCompleted(e.collection.data$)), tap(result => {
63
+ e.collection.data$.next({
64
+ ...result,
65
+ from: 'query',
66
+ loading: null
67
+ });
68
+ }));
69
+ })),
70
+ // Local queries
71
+ this.#queries$.pipe(filter(req => req.collection.mode == 'local-first'), groupBy(e => `${e.collection.collection_ref}/${e.collection.document_id || '::'}`), mergeMap($ => $.pipe(mergeMap((e, index) => {
72
+ index == 0 && e.collection.data$.next({
73
+ from: 'query',
74
+ loading: 'all'
75
+ });
76
+ return merge(of(e), index > 0 ? EMPTY : defer(() => {
77
+ return this.#query(e).pipe(expand(res => {
78
+ const next = res.paging?.next;
79
+ if (!next)
80
+ return EMPTY;
81
+ return this.#query({
82
+ ...e,
83
+ filters: { ':after': next.cursor }
84
+ });
85
+ }), tap(result => {
86
+ this.#broadcast(e.collection.collection_ref, 'query', result.changes || []);
87
+ }));
88
+ }).pipe(switchMap(() => EMPTY)));
89
+ }), scan((p, c) => new Set([...p, c.collection.data$].filter($ => !$.closed)), new Set()), map(set => [...set].map($ => whenCompleted($))), switchMap(list => forkJoin(list)), takeWhile(() => false))))));
90
+ }
91
+ watch(ref, collection_id, mode) {
92
+ const refs = ref.split('/');
93
+ const document_id = refs.length % 2 == 0 ? refs[refs.length - 1] : undefined;
94
+ const collection_ref = refs.length % 2 == 0 ? refs.slice(0, -1).join('/') : ref;
95
+ const collections = this.#refs.get(collection_ref) || new Set();
96
+ collections.add(collection_id);
97
+ this.#refs.set(collection_ref, collections);
98
+ const data$ = new Subject();
99
+ this.#collections.set(collection_id, {
100
+ data$,
101
+ document_id,
102
+ collection_id,
103
+ collection_ref,
104
+ mode,
105
+ filters: {}
106
+ });
107
+ return data$.pipe(finalize(() => {
108
+ this.#collections.delete(collection_id);
109
+ collections.delete(collection_id);
110
+ if (collections.size === 0) {
111
+ this.#refs.delete(collection_ref);
112
+ }
113
+ }));
114
+ }
115
+ async query(req) {
116
+ const collection = this.#collections.get(req.collection_id);
117
+ if (!collection)
118
+ throw new Error(`Collection with id ${req.collection_id} not found`);
119
+ // If document
120
+ if (collection.document_id) {
121
+ const ids = this.#refs.get(collection.collection_ref);
122
+ const collections = ids ? [...ids].map(id => this.#collections.get(id)).filter(c => c && c.document_id) : [];
123
+ const doc = await this.config.storage.get(collection.collection_ref, collection.document_id);
124
+ if (collections.length > 0 && doc)
125
+ return {
126
+ documents: [doc]
127
+ };
128
+ }
129
+ setTimeout(() => this.#queries$.next({
130
+ ...req,
131
+ filters: collection.mode == 'local-first' ? {} : req.filters,
132
+ collection
133
+ }));
134
+ // If collection
135
+ collection.filters = req.filters || {};
136
+ if (collection.mode == 'local-first') {
137
+ return await this.config.storage.query(req.ref, req.filters);
138
+ }
139
+ if (collection.mode == 'cache-first') {
140
+ const before = req.filters?.[':before'];
141
+ const after = req.filters?.[':after'];
142
+ const is_first_query = !before && !after;
143
+ if (is_first_query) {
144
+ return await this.config.storage.query(req.ref, req.filters);
145
+ }
146
+ }
147
+ }
148
+ #broadcast(collection_ref, from, events) {
149
+ const collections = this.#refs.get(collection_ref) || new Set();
150
+ for (const collection_id of collections) {
151
+ const collection = this.#collections.get(collection_id);
152
+ if (!collection)
153
+ continue;
154
+ if (collection.document_id) {
155
+ // Is document
156
+ const change = events.find(c => c.id == collection.document_id);
157
+ change && collection.data$.next({
158
+ changes: [change],
159
+ from,
160
+ loading: null
161
+ });
162
+ continue;
163
+ }
164
+ // If local first collection
165
+ if (collection.mode == 'local-first') {
166
+ const changes = events.filter(e => {
167
+ if (e.type == 'added')
168
+ return e.data && matchesAllFilters(e.data, collection.filters);
169
+ // if (e.type == 'modified') {
170
+ // if (!e.data) return false
171
+ // // TODO: Delete on data not matched
172
+ // if (!matchesAllFilters(e.data, collection.filters)) {
173
+ // e.type = 'removed'
174
+ // }
175
+ // }
176
+ return true;
177
+ });
178
+ // Is collection
179
+ collection.data$.next({
180
+ changes,
181
+ from,
182
+ ...from == 'query' ? { loading: null } : {}
183
+ });
184
+ continue;
185
+ }
186
+ collection.data$.next({
187
+ changes: events,
188
+ from,
189
+ ...from == 'query' ? { loading: null } : {}
190
+ });
191
+ }
192
+ }
193
+ #push(collection_ref, id, doc) {
194
+ const cleanDoc = Object.entries(doc).reduce((p, [k, v]) => {
195
+ if (k.startsWith('_'))
196
+ return p;
197
+ return { ...p, [k]: v };
198
+ }, {});
199
+ return lastValueFrom(from(Object.entries(this.config.transporters)).pipe(concatMap(async ([tid, transporter]) => {
200
+ if (String(id).startsWith('local:')) {
201
+ // lock by collection_ref
202
+ const o = new Subject();
203
+ this.#adding.set(collection_ref, o);
204
+ const [e, data] = await tryCatch(() => transporter.add(collection_ref, cleanDoc));
205
+ // unlock
206
+ if (data && data.id) {
207
+ const fnd = {
208
+ ...data,
209
+ _adding: undefined,
210
+ ...e ? { _adding_error: e } : {}
211
+ };
212
+ await this.config.storage.update(collection_ref, id, fnd);
213
+ this.#broadcast(collection_ref, 'action', [{
214
+ collection_ref,
215
+ type: 'modified',
216
+ id,
217
+ data: fnd
218
+ }]);
219
+ }
220
+ o.next();
221
+ o.complete();
222
+ this.#adding.delete(collection_ref);
223
+ return { [tid]: data };
224
+ }
225
+ // _deleting flag → soft-delete on remote then hard-delete locally
226
+ if (doc._deleting) {
227
+ const [e, data] = await tryCatch(() => transporter.delete(collection_ref, id));
228
+ if (e) {
229
+ const fnd = {
230
+ _deleting: undefined,
231
+ _deleting_error: e
232
+ };
233
+ await this.config.storage.update(collection_ref, id, fnd);
234
+ this.#broadcast(collection_ref, 'action', [{
235
+ collection_ref,
236
+ type: 'modified',
237
+ id,
238
+ data: fnd
239
+ }]);
240
+ }
241
+ else {
242
+ await this.config.storage.delete(collection_ref, id);
243
+ this.#broadcast(collection_ref, 'action', [{
244
+ collection_ref,
245
+ type: 'removed',
246
+ id
247
+ }]);
248
+ }
249
+ return { [tid]: data };
250
+ }
251
+ // _prev present → document was updated locally, push changed fields to remote
252
+ if (doc._prev && Object.keys(doc._prev).length > 0) {
253
+ const changedFields = Object.keys(doc._prev).reduce((acc, key) => ({
254
+ ...acc,
255
+ [key]: doc[key]
256
+ }), {});
257
+ const [e, data] = await tryCatch(() => transporter.update(collection_ref, id, changedFields));
258
+ const fnd = {
259
+ _prev: undefined,
260
+ _updating: undefined,
261
+ _updating_error: e
262
+ };
263
+ await this.config.storage.update(collection_ref, id, fnd);
264
+ this.#broadcast(collection_ref, 'action', [{
265
+ collection_ref,
266
+ type: 'modified',
267
+ id,
268
+ data: fnd
269
+ }]);
270
+ return { [tid]: data };
271
+ }
272
+ return {};
273
+ }), reduce((acc, curr) => ({ ...acc, ...curr }), {})), { defaultValue: {} });
274
+ }
275
+ async add(collection_ref, doc) {
276
+ const local = await this.config.storage.add(collection_ref, { ...doc, _adding: true });
277
+ this.#broadcast(collection_ref, 'action', [{
278
+ collection_ref,
279
+ id: local.id,
280
+ type: 'added',
281
+ data: local
282
+ }]);
283
+ const remotes = await this.#push(collection_ref, local.id, local);
284
+ return {
285
+ local,
286
+ ...remotes
287
+ };
288
+ }
289
+ async update(collection_ref, id, data) {
290
+ const old = await this.config.storage.get(collection_ref, id);
291
+ if (!old)
292
+ return;
293
+ const _prev = Object.keys(data).reduce((acc, key) => {
294
+ if (key in (old._prev || {}))
295
+ return acc;
296
+ return {
297
+ ...acc,
298
+ [key]: old[key]
299
+ };
300
+ }, old._prev || {});
301
+ await this.config.storage.update(collection_ref, id, { _prev, _updating: true, ...data, });
302
+ await this.#broadcast(collection_ref, 'action', [{
303
+ collection_ref,
304
+ id,
305
+ type: 'modified',
306
+ data: {
307
+ _prev,
308
+ _updating: true,
309
+ ...data,
310
+ }
311
+ }]);
312
+ const updated = await this.#push(collection_ref, id, { ...data, _prev, _updating: true });
313
+ return updated;
314
+ }
315
+ async delete(collection_ref, id) {
316
+ const soft = Object.keys(this.config.transporters).length > 0;
317
+ const is_local_doc = id.startsWith('local:');
318
+ if (!soft || is_local_doc) {
319
+ await this.config.storage.delete(collection_ref, id);
320
+ await this.#broadcast(collection_ref, 'action', [{
321
+ collection_ref,
322
+ id,
323
+ type: 'removed'
324
+ }]);
325
+ return;
326
+ }
327
+ await this.config.storage.update(collection_ref, id, { _deleting: true });
328
+ const doc = await this.#broadcast(collection_ref, 'action', [{
329
+ collection_ref,
330
+ id,
331
+ type: 'modified',
332
+ data: {
333
+ _deleting: true
334
+ }
335
+ }]);
336
+ const deleted = await this.#push(collection_ref, id, { _deleting: true });
337
+ return deleted;
338
+ }
339
+ trigger(action) {
340
+ return from(Object.values(this.config.transporters)).pipe(mergeMap(transporter => transporter.trigger(action)));
341
+ }
342
+ }
343
+ //# sourceMappingURL=LivequeryCore.js.map