@instantdb/core 0.22.56 → 0.22.57

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 (57) hide show
  1. package/dist/commonjs/Reactor.d.ts +5 -0
  2. package/dist/commonjs/Reactor.d.ts.map +1 -1
  3. package/dist/commonjs/Reactor.js +43 -5
  4. package/dist/commonjs/Reactor.js.map +1 -1
  5. package/dist/commonjs/SyncTable.d.ts +140 -0
  6. package/dist/commonjs/SyncTable.d.ts.map +1 -0
  7. package/dist/commonjs/SyncTable.js +538 -0
  8. package/dist/commonjs/SyncTable.js.map +1 -0
  9. package/dist/commonjs/index.d.ts +21 -1
  10. package/dist/commonjs/index.d.ts.map +1 -1
  11. package/dist/commonjs/index.js +19 -1
  12. package/dist/commonjs/index.js.map +1 -1
  13. package/dist/commonjs/instaql.d.ts +1 -0
  14. package/dist/commonjs/instaql.d.ts.map +1 -1
  15. package/dist/commonjs/instaql.js +9 -5
  16. package/dist/commonjs/instaql.js.map +1 -1
  17. package/dist/commonjs/store.d.ts +5 -0
  18. package/dist/commonjs/store.d.ts.map +1 -1
  19. package/dist/commonjs/store.js +11 -0
  20. package/dist/commonjs/store.js.map +1 -1
  21. package/dist/commonjs/utils/PersistedObject.d.ts +11 -5
  22. package/dist/commonjs/utils/PersistedObject.d.ts.map +1 -1
  23. package/dist/commonjs/utils/PersistedObject.js +12 -2
  24. package/dist/commonjs/utils/PersistedObject.js.map +1 -1
  25. package/dist/esm/Reactor.d.ts +5 -0
  26. package/dist/esm/Reactor.d.ts.map +1 -1
  27. package/dist/esm/Reactor.js +43 -5
  28. package/dist/esm/Reactor.js.map +1 -1
  29. package/dist/esm/SyncTable.d.ts +140 -0
  30. package/dist/esm/SyncTable.d.ts.map +1 -0
  31. package/dist/esm/SyncTable.js +498 -0
  32. package/dist/esm/SyncTable.js.map +1 -0
  33. package/dist/esm/index.d.ts +21 -1
  34. package/dist/esm/index.d.ts.map +1 -1
  35. package/dist/esm/index.js +19 -1
  36. package/dist/esm/index.js.map +1 -1
  37. package/dist/esm/instaql.d.ts +1 -0
  38. package/dist/esm/instaql.d.ts.map +1 -1
  39. package/dist/esm/instaql.js +8 -5
  40. package/dist/esm/instaql.js.map +1 -1
  41. package/dist/esm/store.d.ts +5 -0
  42. package/dist/esm/store.d.ts.map +1 -1
  43. package/dist/esm/store.js +9 -3
  44. package/dist/esm/store.js.map +1 -1
  45. package/dist/esm/utils/PersistedObject.d.ts +11 -5
  46. package/dist/esm/utils/PersistedObject.d.ts.map +1 -1
  47. package/dist/esm/utils/PersistedObject.js +12 -2
  48. package/dist/esm/utils/PersistedObject.js.map +1 -1
  49. package/dist/standalone/index.js +1579 -1135
  50. package/dist/standalone/index.umd.cjs +3 -3
  51. package/package.json +2 -2
  52. package/src/Reactor.js +60 -4
  53. package/src/SyncTable.ts +821 -0
  54. package/src/index.ts +48 -0
  55. package/src/instaql.js +11 -5
  56. package/src/store.js +11 -3
  57. package/src/utils/PersistedObject.ts +15 -6
@@ -0,0 +1,140 @@
1
+ import { Logger } from './Reactor.js';
2
+ import { InstaQLResponse, ValidQuery } from './queryTypes.ts';
3
+ import { EntitiesDef, IContainEntitiesAndLinks } from './schemaTypes.ts';
4
+ type StartMsg = {
5
+ op: 'start-sync';
6
+ q: string;
7
+ };
8
+ type EndMsg = {
9
+ op: 'remove-sync';
10
+ 'subscription-id': string;
11
+ };
12
+ type ResyncMsg = {
13
+ op: 'resync-table';
14
+ 'subscription-id': string;
15
+ 'tx-id': number;
16
+ token: string;
17
+ };
18
+ type SendMsg = StartMsg | EndMsg | ResyncMsg;
19
+ type StartSyncOkMsg = {
20
+ 'subscription-id': string;
21
+ 'client-event-id': string;
22
+ q: string;
23
+ token: string;
24
+ };
25
+ type Triple = [string, string, any, number];
26
+ type SyncLoadBatchMsg = {
27
+ 'subscription-id': string;
28
+ 'join-rows': Array<Triple[]>;
29
+ };
30
+ type SyncInitFinishMsg = {
31
+ 'subscription-id': string;
32
+ 'tx-id': number;
33
+ };
34
+ type SyncUpdateTriplesMsg = {
35
+ 'subscription-id': string;
36
+ txes: {
37
+ 'tx-id': number;
38
+ changes: {
39
+ action: 'added' | 'removed';
40
+ triple: Triple;
41
+ }[];
42
+ }[];
43
+ };
44
+ type TrySend = (eventId: string, msg: SendMsg) => void;
45
+ type Config = {
46
+ useDateObjects: boolean;
47
+ };
48
+ export declare enum CallbackEventType {
49
+ InitialSyncBatch = "InitialSyncBatch",
50
+ InitialSyncComplete = "InitialSyncComplete",
51
+ LoadFromStorage = "LoadFromStorage",
52
+ SyncTransaction = "SyncTransaction",
53
+ Error = "Error"
54
+ }
55
+ type QueryEntities<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> = InstaQLResponse<Schema, Q, UseDates>[keyof InstaQLResponse<Schema, Q, UseDates>];
56
+ type QueryEntity<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> = QueryEntities<Schema, Q, UseDates> extends (infer E)[] ? E : never;
57
+ type ChangedFields<Entity> = {
58
+ [K in keyof Entity]?: {
59
+ oldValue: Entity[K];
60
+ newValue: Entity[K];
61
+ };
62
+ };
63
+ export interface BaseCallbackEvent<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> {
64
+ type: CallbackEventType;
65
+ data: InstaQLResponse<Schema, Q, UseDates>;
66
+ }
67
+ export interface InitialSyncBatch<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> extends BaseCallbackEvent<Schema, Q, UseDates> {
68
+ type: CallbackEventType.InitialSyncBatch;
69
+ batch: QueryEntities<Schema, Q, UseDates>;
70
+ }
71
+ export interface InitialSyncComplete<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> extends BaseCallbackEvent<Schema, Q, UseDates> {
72
+ type: CallbackEventType.InitialSyncComplete;
73
+ }
74
+ export interface SyncTransaction<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> extends BaseCallbackEvent<Schema, Q, UseDates> {
75
+ type: CallbackEventType.SyncTransaction;
76
+ added: QueryEntities<Schema, Q, UseDates>;
77
+ removed: QueryEntities<Schema, Q, UseDates>;
78
+ updated: {
79
+ oldEntity: QueryEntity<Schema, Q, UseDates>;
80
+ newEntity: QueryEntity<Schema, Q, UseDates>;
81
+ changedFields: ChangedFields<QueryEntity<Schema, Q, UseDates>>;
82
+ }[];
83
+ }
84
+ export interface LoadFromStorage<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> extends BaseCallbackEvent<Schema, Q, UseDates> {
85
+ type: CallbackEventType.LoadFromStorage;
86
+ }
87
+ export interface SetupError<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> extends BaseCallbackEvent<Schema, Q, UseDates> {
88
+ type: CallbackEventType.Error;
89
+ error: {
90
+ message: string;
91
+ hint?: any;
92
+ type: string;
93
+ status: number;
94
+ };
95
+ }
96
+ export type CallbackEvent<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> = InitialSyncBatch<Schema, Q, UseDates> | InitialSyncComplete<Schema, Q, UseDates> | SyncTransaction<Schema, Q, UseDates> | LoadFromStorage<Schema, Q, UseDates> | SetupError<Schema, Q, UseDates>;
97
+ export type SyncTableCallback<Schema extends IContainEntitiesAndLinks<EntitiesDef, any>, Q extends ValidQuery<Q, Schema>, UseDates extends boolean> = (event: CallbackEvent<Schema, Q, UseDates>) => void;
98
+ export declare class SyncTable {
99
+ private trySend;
100
+ private subs;
101
+ private callbacks;
102
+ private config;
103
+ private idToHash;
104
+ private log;
105
+ private createStore;
106
+ constructor(trySend: TrySend, persister: Storage, config: Config, log: Logger, createStore: (triples: Triple[]) => any);
107
+ beforeUnload(): void;
108
+ subscribe(q: any, cb: SyncTableCallback<any, any, any>): (opts?: {
109
+ keepSubscription?: boolean | null | undefined;
110
+ } | null | undefined) => void;
111
+ private unsubscribe;
112
+ private sendStart;
113
+ private sendResync;
114
+ private sendRemove;
115
+ private initSubscription;
116
+ flushPending(): Promise<void>;
117
+ onStartSyncOk(msg: StartSyncOkMsg): void;
118
+ private notifyCbs;
119
+ onSyncLoadBatch(msg: SyncLoadBatchMsg): void;
120
+ onSyncInitFinish(msg: SyncInitFinishMsg): void;
121
+ onSyncUpdateTriples(msg: SyncUpdateTriplesMsg): void;
122
+ private clearSubscriptionData;
123
+ onStartSyncError(msg: {
124
+ op: 'error';
125
+ 'original-event': StartMsg;
126
+ 'client-event-id': string;
127
+ status: number;
128
+ type: string;
129
+ message?: string;
130
+ hint?: any;
131
+ }): void;
132
+ onResyncError(msg: {
133
+ op: 'error';
134
+ 'original-event': ResyncMsg;
135
+ status: number;
136
+ type: string;
137
+ }): void;
138
+ }
139
+ export {};
140
+ //# sourceMappingURL=SyncTable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SyncTable.d.ts","sourceRoot":"","sources":["../../src/SyncTable.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,498 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import { PersistedObject } from "./utils/PersistedObject.js";
11
+ import * as s from './store.js';
12
+ import weakHash from "./utils/weakHash.js";
13
+ import uuid from "./utils/uuid.js";
14
+ import instaql, { compareOrder } from './instaql.js';
15
+ // Modifies the data in place because it comes directly from storage
16
+ function syncSubsFromStorage(parsed, useDateObjects) {
17
+ for (const key in parsed) {
18
+ const sub = parsed[key];
19
+ for (const e of sub.entities || []) {
20
+ e.store.useDateObjects = useDateObjects;
21
+ e.store = s.fromJSON(e.store);
22
+ }
23
+ }
24
+ return parsed;
25
+ }
26
+ function syncSubsToStorage(subs) {
27
+ const jsonSubs = {};
28
+ for (const key in subs) {
29
+ const sub = subs[key];
30
+ if (sub.entities) {
31
+ const entities = [];
32
+ for (const e of sub.entities) {
33
+ entities.push(Object.assign(Object.assign({}, e), { store: s.toJSON(e.store) }));
34
+ }
35
+ jsonSubs[key] = Object.assign(Object.assign({}, sub), { entities });
36
+ }
37
+ else {
38
+ jsonSubs[key] = sub;
39
+ }
40
+ }
41
+ return jsonSubs;
42
+ }
43
+ function onMergeSubs(storageSubs, inMemorySubs) {
44
+ const subs = {};
45
+ for (const [k, v] of Object.entries(inMemorySubs)) {
46
+ subs[k] = v;
47
+ }
48
+ if (storageSubs) {
49
+ for (const [k, v] of Object.entries(storageSubs)) {
50
+ subs[k] = v;
51
+ }
52
+ }
53
+ return subs;
54
+ }
55
+ function queryEntity(sub, store) {
56
+ const res = instaql({ store, pageInfo: null, aggregate: null }, sub.query);
57
+ return res.data[sub.table][0];
58
+ }
59
+ function getServerCreatedAt(sub, store, entityId) {
60
+ var _a;
61
+ const aid = (_a = s.getAttrByFwdIdentName(store, sub.table, 'id')) === null || _a === void 0 ? void 0 : _a.id;
62
+ if (!aid) {
63
+ return -1;
64
+ }
65
+ const t = s.getInMap(store.eav, [entityId, aid, entityId]);
66
+ if (!t) {
67
+ return -1;
68
+ }
69
+ return t[3];
70
+ }
71
+ function applyChangesToStore(store, changes) {
72
+ for (const { action, triple } of changes) {
73
+ switch (action) {
74
+ case 'added':
75
+ s.addTriple(store, triple);
76
+ break;
77
+ case 'removed':
78
+ s.retractTriple(store, triple);
79
+ break;
80
+ }
81
+ }
82
+ }
83
+ function changedFieldsOfChanges(store, changes) {
84
+ var _a, _b, _c, _d;
85
+ // This will be more complicated when we include links, we can either add a
86
+ // changedLinks field or we can have something like 'bookshelves.title`
87
+ const changedFields = {};
88
+ for (const { action, triple } of changes) {
89
+ const [e, a, v] = triple;
90
+ const field = (_b = (_a = store.attrs[a]) === null || _a === void 0 ? void 0 : _a['forward-identity']) === null || _b === void 0 ? void 0 : _b[2];
91
+ if (!field)
92
+ continue;
93
+ const fields = (_c = changedFields[e]) !== null && _c !== void 0 ? _c : {};
94
+ changedFields[e] = fields;
95
+ const oldNew = (_d = fields[field]) !== null && _d !== void 0 ? _d : {};
96
+ fields[field] = oldNew;
97
+ switch (action) {
98
+ case 'added':
99
+ oldNew.newValue = v;
100
+ break;
101
+ case 'removed':
102
+ // Only take the first thing that was removed, in case we modified things in the middle
103
+ if (oldNew.oldValue === undefined) {
104
+ oldNew.oldValue = v;
105
+ }
106
+ break;
107
+ }
108
+ }
109
+ return changedFields;
110
+ }
111
+ function subData(sub, entities) {
112
+ return { [sub.table]: entities.map((e) => e.entity) };
113
+ }
114
+ function sortEntitiesInPlace(sub, entities) {
115
+ const dataType = sub.orderFieldType;
116
+ if (sub.orderField === 'serverCreatedAt') {
117
+ entities.sort(sub.orderDirection === 'asc'
118
+ ? function compareEntities(a, b) {
119
+ return compareOrder(a.entity.id, a.serverCreatedAt, b.entity.id, b.serverCreatedAt, dataType);
120
+ }
121
+ : function compareEntities(b, a) {
122
+ return compareOrder(a.entity.id, a.serverCreatedAt, b.entity.id, b.serverCreatedAt, dataType);
123
+ });
124
+ return;
125
+ }
126
+ const field = sub.orderField;
127
+ entities.sort(sub.orderDirection === 'asc'
128
+ ? function compareEntities(a, b) {
129
+ return compareOrder(a.entity.id, a.entity[field], b.entity.id, b.entity[field], dataType);
130
+ }
131
+ : function compareEntities(b, a) {
132
+ return compareOrder(a.entity.id, a.entity[field], b.entity.id, b.entity[field], dataType);
133
+ });
134
+ }
135
+ export var CallbackEventType;
136
+ (function (CallbackEventType) {
137
+ CallbackEventType["InitialSyncBatch"] = "InitialSyncBatch";
138
+ CallbackEventType["InitialSyncComplete"] = "InitialSyncComplete";
139
+ CallbackEventType["LoadFromStorage"] = "LoadFromStorage";
140
+ CallbackEventType["SyncTransaction"] = "SyncTransaction";
141
+ CallbackEventType["Error"] = "Error";
142
+ })(CallbackEventType || (CallbackEventType = {}));
143
+ export class SyncTable {
144
+ constructor(trySend, persister, config, log, createStore) {
145
+ // Using any for the SyncCallback because we'd need Reactor to be typed
146
+ this.callbacks = {};
147
+ this.idToHash = {};
148
+ this.trySend = trySend;
149
+ this.config = config;
150
+ this.log = log;
151
+ this.createStore = createStore;
152
+ this.subs = new PersistedObject(persister, 'subs', {}, onMergeSubs, syncSubsToStorage, (x) => syncSubsFromStorage(x, this.config.useDateObjects));
153
+ }
154
+ beforeUnload() {
155
+ this.subs.flush();
156
+ }
157
+ subscribe(q, cb) {
158
+ const hash = weakHash(q);
159
+ this.callbacks[hash] = this.callbacks[hash] || [];
160
+ this.callbacks[hash].push(cb);
161
+ this.initSubscription(q, hash, cb);
162
+ return (opts) => {
163
+ this.unsubscribe(hash, cb, opts === null || opts === void 0 ? void 0 : opts.keepSubscription);
164
+ };
165
+ }
166
+ unsubscribe(hash, cb, keepSubscription) {
167
+ const cbs = (this.callbacks[hash] || []).filter((x) => x !== cb);
168
+ this.callbacks[hash] = cbs;
169
+ if (!cbs.length) {
170
+ delete this.callbacks[hash];
171
+ if (keepSubscription) {
172
+ return;
173
+ }
174
+ const sub = this.subs.currentValue[hash];
175
+ if (sub === null || sub === void 0 ? void 0 : sub.state) {
176
+ this.clearSubscriptionData(sub.state.subscriptionId);
177
+ }
178
+ this.subs.set((prev) => {
179
+ delete prev[hash];
180
+ return prev;
181
+ });
182
+ }
183
+ }
184
+ sendStart(query) {
185
+ this.trySend(uuid(), {
186
+ op: 'start-sync',
187
+ q: query,
188
+ });
189
+ }
190
+ sendResync(sub, state) {
191
+ // Make sure we can find the hash from the subscriptionId
192
+ this.idToHash[state.subscriptionId] = sub.hash;
193
+ this.trySend(state.subscriptionId, {
194
+ op: 'resync-table',
195
+ 'subscription-id': state.subscriptionId,
196
+ 'tx-id': state.txId,
197
+ token: state.token,
198
+ });
199
+ }
200
+ sendRemove(state) {
201
+ this.trySend(uuid(), {
202
+ op: 'remove-sync',
203
+ 'subscription-id': state.subscriptionId,
204
+ });
205
+ }
206
+ initSubscription(query, hash, cb) {
207
+ return __awaiter(this, void 0, void 0, function* () {
208
+ var _a, _b, _c;
209
+ // Wait for storage to load so that we know if we already have an existing subscription
210
+ yield this.subs.waitForLoaded();
211
+ const existingSub = this.subs.currentValue[hash];
212
+ if (existingSub && existingSub.state && existingSub.state.txId) {
213
+ this.sendResync(existingSub, existingSub.state);
214
+ if (existingSub.entities && cb) {
215
+ const k = Object.keys(query)[0];
216
+ cb({
217
+ type: CallbackEventType.LoadFromStorage,
218
+ data: subData(existingSub, existingSub.entities),
219
+ });
220
+ }
221
+ return;
222
+ }
223
+ const table = Object.keys(query)[0];
224
+ const orderBy = ((_b = (_a = query[table]) === null || _a === void 0 ? void 0 : _a.$) === null || _b === void 0 ? void 0 : _b.order) || { serverCreatedAt: 'asc' };
225
+ const [orderField, orderDirection] = Object.entries(orderBy)[0];
226
+ const orderFieldType = orderField === 'serverCreatedAt'
227
+ ? 'number'
228
+ : (_c = s.getAttrByFwdIdentName(this.createStore([]), table, orderField)) === null || _c === void 0 ? void 0 : _c['checked-data-type'];
229
+ this.subs.set((prev) => {
230
+ prev[hash] = {
231
+ query,
232
+ hash: hash,
233
+ table,
234
+ orderDirection,
235
+ orderField,
236
+ orderFieldType,
237
+ createdAt: Date.now(),
238
+ updatedAt: Date.now(),
239
+ };
240
+ return prev;
241
+ });
242
+ this.sendStart(query);
243
+ });
244
+ }
245
+ flushPending() {
246
+ return __awaiter(this, void 0, void 0, function* () {
247
+ yield this.subs.waitForLoaded();
248
+ for (const hash of Object.keys(this.callbacks)) {
249
+ const sub = this.subs.currentValue[hash];
250
+ if (sub) {
251
+ yield this.initSubscription(sub.query, sub.hash);
252
+ }
253
+ else {
254
+ this.log.error('Missing sub for hash in flushPending', hash);
255
+ }
256
+ }
257
+ });
258
+ }
259
+ onStartSyncOk(msg) {
260
+ const subscriptionId = msg['subscription-id'];
261
+ const q = msg.q;
262
+ const hash = weakHash(q);
263
+ this.idToHash[subscriptionId] = hash;
264
+ this.subs.set((prev) => {
265
+ const sub = prev[hash];
266
+ if (!sub) {
267
+ this.log.error('Missing sub for hash', hash, 'subscription-id', subscriptionId, 'query', q);
268
+ return prev;
269
+ }
270
+ sub.state = {
271
+ subscriptionId: subscriptionId,
272
+ token: msg.token,
273
+ };
274
+ return prev;
275
+ });
276
+ }
277
+ notifyCbs(hash, event) {
278
+ for (const cb of this.callbacks[hash] || []) {
279
+ cb(event);
280
+ }
281
+ }
282
+ onSyncLoadBatch(msg) {
283
+ const subscriptionId = msg['subscription-id'];
284
+ const joinRows = msg['join-rows'];
285
+ const hash = this.idToHash[subscriptionId];
286
+ if (!hash) {
287
+ this.log.error('Missing hash for subscription', msg);
288
+ return;
289
+ }
290
+ const batch = [];
291
+ const currentValue = this.subs.set((prev) => {
292
+ var _a;
293
+ const sub = prev[hash];
294
+ if (!sub) {
295
+ this.log.error('Missing sub for hash', hash, msg);
296
+ return prev;
297
+ }
298
+ const entities = (_a = sub.entities) !== null && _a !== void 0 ? _a : [];
299
+ sub.entities = entities;
300
+ for (const entRows of joinRows) {
301
+ const store = this.createStore(entRows);
302
+ const entity = queryEntity(sub, store);
303
+ entities.push({
304
+ store,
305
+ entity,
306
+ serverCreatedAt: getServerCreatedAt(sub, store, entity.id),
307
+ });
308
+ batch.push(entity);
309
+ }
310
+ sub.updatedAt = Date.now();
311
+ return prev;
312
+ });
313
+ const sub = currentValue[hash];
314
+ if (sub.entities) {
315
+ this.notifyCbs(hash, {
316
+ type: CallbackEventType.InitialSyncBatch,
317
+ data: subData(sub, sub.entities),
318
+ batch,
319
+ });
320
+ }
321
+ }
322
+ onSyncInitFinish(msg) {
323
+ const subscriptionId = msg['subscription-id'];
324
+ const hash = this.idToHash[subscriptionId];
325
+ if (!hash) {
326
+ this.log.error('Missing hash for subscription', msg);
327
+ return;
328
+ }
329
+ this.subs.set((prev) => {
330
+ const sub = prev[hash];
331
+ if (!sub) {
332
+ this.log.error('Missing sub for hash', hash, msg);
333
+ return prev;
334
+ }
335
+ const state = sub.state;
336
+ if (!state) {
337
+ this.log.error('Sub never set init, missing result', sub, msg);
338
+ return prev;
339
+ }
340
+ state.txId = msg['tx-id'];
341
+ sub.updatedAt = Date.now();
342
+ return prev;
343
+ });
344
+ const sub = this.subs.currentValue[hash];
345
+ if (sub) {
346
+ this.notifyCbs(hash, {
347
+ type: CallbackEventType.InitialSyncComplete,
348
+ data: subData(sub, sub.entities || []),
349
+ });
350
+ }
351
+ }
352
+ onSyncUpdateTriples(msg) {
353
+ const subscriptionId = msg['subscription-id'];
354
+ const hash = this.idToHash[subscriptionId];
355
+ if (!hash) {
356
+ this.log.error('Missing hash for subscription', msg);
357
+ return;
358
+ }
359
+ this.subs.set((prev) => {
360
+ var _a;
361
+ const sub = prev[hash];
362
+ if (!sub) {
363
+ this.log.error('Missing sub for hash', hash, msg);
364
+ return prev;
365
+ }
366
+ const state = sub.state;
367
+ if (!state) {
368
+ this.log.error('Missing state for sub', sub, msg);
369
+ return prev;
370
+ }
371
+ for (const tx of msg.txes) {
372
+ if (state.txId >= tx['tx-id']) {
373
+ continue;
374
+ }
375
+ state.txId = tx['tx-id'];
376
+ const idxesToDelete = [];
377
+ // Note: this won't work as well when links are involved
378
+ const byEid = {};
379
+ for (const change of tx.changes) {
380
+ const eidChanges = (_a = byEid[change.triple[0]]) !== null && _a !== void 0 ? _a : [];
381
+ byEid[change.triple[0]] = eidChanges;
382
+ eidChanges.push(change);
383
+ }
384
+ const entities = sub.entities || [];
385
+ sub.entities = entities;
386
+ const updated = [];
387
+ // Update the existing stores, if we already know about this entity
388
+ eidLoop: for (const [eid, changes] of Object.entries(byEid)) {
389
+ for (const [entIdx, ent] of Object.entries(entities)) {
390
+ if (s.hasEntity(ent.store, eid)) {
391
+ applyChangesToStore(ent.store, changes);
392
+ const entity = queryEntity(sub, ent.store);
393
+ const changedFields = changedFieldsOfChanges(ent.store, changes)[eid];
394
+ for (const [k, { oldValue, newValue }] of Object.entries(changedFields || {})) {
395
+ if (oldValue === newValue) {
396
+ delete changedFields[k];
397
+ }
398
+ }
399
+ if (entity) {
400
+ updated.push({
401
+ oldEntity: ent.entity,
402
+ newEntity: entity,
403
+ changedFields: changedFields || {},
404
+ });
405
+ ent.entity = entity;
406
+ }
407
+ else {
408
+ idxesToDelete.push(entIdx);
409
+ }
410
+ delete byEid[eid];
411
+ continue eidLoop;
412
+ }
413
+ }
414
+ }
415
+ const added = [];
416
+ // If we have anything left in byEid, then this must be a new entity we don't know about
417
+ for (const [_eid, changes] of Object.entries(byEid)) {
418
+ const store = this.createStore([]);
419
+ applyChangesToStore(store, changes);
420
+ const entity = queryEntity(sub, store);
421
+ if (!entity) {
422
+ this.log.error('No entity found after applying change', {
423
+ sub,
424
+ changes,
425
+ store,
426
+ });
427
+ 1;
428
+ continue;
429
+ }
430
+ entities.push({
431
+ store,
432
+ entity,
433
+ serverCreatedAt: getServerCreatedAt(sub, store, entity.id),
434
+ });
435
+ added.push(entity);
436
+ }
437
+ const removed = [];
438
+ for (const idx of idxesToDelete.sort().reverse()) {
439
+ removed.push(entities[idx].entity);
440
+ entities.splice(idx, 1);
441
+ }
442
+ sortEntitiesInPlace(sub, entities);
443
+ this.notifyCbs(hash, {
444
+ type: CallbackEventType.SyncTransaction,
445
+ data: subData(sub, sub.entities),
446
+ added,
447
+ removed,
448
+ updated,
449
+ });
450
+ sub.updatedAt = Date.now();
451
+ }
452
+ return prev;
453
+ });
454
+ }
455
+ clearSubscriptionData(subscriptionId) {
456
+ const hash = this.idToHash[subscriptionId];
457
+ if (hash) {
458
+ delete this.idToHash[subscriptionId];
459
+ const sub = this.subs.currentValue[hash];
460
+ if (sub.state) {
461
+ this.sendRemove(sub.state);
462
+ }
463
+ this.subs.set((prev) => {
464
+ delete prev[hash];
465
+ return prev;
466
+ });
467
+ if (sub) {
468
+ return sub;
469
+ }
470
+ }
471
+ }
472
+ onStartSyncError(msg) {
473
+ const hash = weakHash(msg['original-event']['q']);
474
+ const error = {
475
+ message: msg.message || 'Uh-oh, something went wrong. Ping Joe & Stopa.',
476
+ status: msg.status,
477
+ type: msg.type,
478
+ hint: msg.hint,
479
+ };
480
+ const k = Object.keys(msg['original-event']['q'])[0];
481
+ this.notifyCbs(hash, {
482
+ type: CallbackEventType.Error,
483
+ data: { [k]: [] },
484
+ error,
485
+ });
486
+ }
487
+ onResyncError(msg) {
488
+ // Clear the subscription and start from scrath on any resync error
489
+ // This can happen if the auth changed and we need to refetch with the
490
+ // new auth or if the subscription is too far behind.
491
+ const subscriptionId = msg['original-event']['subscription-id'];
492
+ const removedSub = this.clearSubscriptionData(subscriptionId);
493
+ if (removedSub) {
494
+ this.initSubscription(removedSub.query, removedSub.hash);
495
+ }
496
+ }
497
+ }
498
+ //# sourceMappingURL=SyncTable.js.map