@instantdb/core 0.22.88 → 0.22.89-experimental.drewh-ssr.20277611943.1

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 (102) hide show
  1. package/__tests__/src/Reactor.test.js +18 -11
  2. package/__tests__/src/{datalog.test.js → datalog.test.ts} +17 -5
  3. package/__tests__/src/{instaml.test.js → instaml.test.ts} +183 -119
  4. package/__tests__/src/instaql.bench.ts +34 -0
  5. package/__tests__/src/{instaql.test.js → instaql.test.ts} +342 -455
  6. package/__tests__/src/instaqlInference.test.js +13 -9
  7. package/__tests__/src/serializeSchema.test.ts +123 -0
  8. package/__tests__/src/{store.test.js → store.test.ts} +215 -212
  9. package/dist/commonjs/Reactor.d.ts +36 -7
  10. package/dist/commonjs/Reactor.d.ts.map +1 -1
  11. package/dist/commonjs/Reactor.js +176 -47
  12. package/dist/commonjs/Reactor.js.map +1 -1
  13. package/dist/commonjs/SyncTable.d.ts +4 -1
  14. package/dist/commonjs/SyncTable.d.ts.map +1 -1
  15. package/dist/commonjs/SyncTable.js +35 -37
  16. package/dist/commonjs/SyncTable.js.map +1 -1
  17. package/dist/commonjs/createRouteHandler.d.ts +8 -0
  18. package/dist/commonjs/createRouteHandler.d.ts.map +1 -0
  19. package/dist/commonjs/createRouteHandler.js +57 -0
  20. package/dist/commonjs/createRouteHandler.js.map +1 -0
  21. package/dist/commonjs/framework.d.ts +77 -0
  22. package/dist/commonjs/framework.d.ts.map +1 -0
  23. package/dist/commonjs/framework.js +209 -0
  24. package/dist/commonjs/framework.js.map +1 -0
  25. package/dist/commonjs/index.d.ts +5 -1
  26. package/dist/commonjs/index.d.ts.map +1 -1
  27. package/dist/commonjs/index.js +7 -1
  28. package/dist/commonjs/index.js.map +1 -1
  29. package/dist/commonjs/instaml.d.ts +17 -4
  30. package/dist/commonjs/instaml.d.ts.map +1 -1
  31. package/dist/commonjs/instaml.js +115 -82
  32. package/dist/commonjs/instaml.js.map +1 -1
  33. package/dist/commonjs/instaql.d.ts +4 -3
  34. package/dist/commonjs/instaql.d.ts.map +1 -1
  35. package/dist/commonjs/instaql.js +65 -63
  36. package/dist/commonjs/instaql.js.map +1 -1
  37. package/dist/commonjs/parseSchemaFromJSON.d.ts +3 -0
  38. package/dist/commonjs/parseSchemaFromJSON.d.ts.map +1 -0
  39. package/dist/commonjs/parseSchemaFromJSON.js +148 -0
  40. package/dist/commonjs/parseSchemaFromJSON.js.map +1 -0
  41. package/dist/commonjs/reactorTypes.d.ts +30 -0
  42. package/dist/commonjs/reactorTypes.d.ts.map +1 -0
  43. package/dist/commonjs/reactorTypes.js +3 -0
  44. package/dist/commonjs/reactorTypes.js.map +1 -0
  45. package/dist/commonjs/store.d.ts +67 -25
  46. package/dist/commonjs/store.d.ts.map +1 -1
  47. package/dist/commonjs/store.js +177 -81
  48. package/dist/commonjs/store.js.map +1 -1
  49. package/dist/esm/Reactor.d.ts +36 -7
  50. package/dist/esm/Reactor.d.ts.map +1 -1
  51. package/dist/esm/Reactor.js +177 -48
  52. package/dist/esm/Reactor.js.map +1 -1
  53. package/dist/esm/SyncTable.d.ts +4 -1
  54. package/dist/esm/SyncTable.d.ts.map +1 -1
  55. package/dist/esm/SyncTable.js +35 -37
  56. package/dist/esm/SyncTable.js.map +1 -1
  57. package/dist/esm/createRouteHandler.d.ts +8 -0
  58. package/dist/esm/createRouteHandler.d.ts.map +1 -0
  59. package/dist/esm/createRouteHandler.js +53 -0
  60. package/dist/esm/createRouteHandler.js.map +1 -0
  61. package/dist/esm/framework.d.ts +77 -0
  62. package/dist/esm/framework.d.ts.map +1 -0
  63. package/dist/esm/framework.js +169 -0
  64. package/dist/esm/framework.js.map +1 -0
  65. package/dist/esm/index.d.ts +5 -1
  66. package/dist/esm/index.d.ts.map +1 -1
  67. package/dist/esm/index.js +5 -2
  68. package/dist/esm/index.js.map +1 -1
  69. package/dist/esm/instaml.d.ts +17 -4
  70. package/dist/esm/instaml.d.ts.map +1 -1
  71. package/dist/esm/instaml.js +112 -77
  72. package/dist/esm/instaml.js.map +1 -1
  73. package/dist/esm/instaql.d.ts +4 -3
  74. package/dist/esm/instaql.d.ts.map +1 -1
  75. package/dist/esm/instaql.js +65 -63
  76. package/dist/esm/instaql.js.map +1 -1
  77. package/dist/esm/parseSchemaFromJSON.d.ts +3 -0
  78. package/dist/esm/parseSchemaFromJSON.d.ts.map +1 -0
  79. package/dist/esm/parseSchemaFromJSON.js +144 -0
  80. package/dist/esm/parseSchemaFromJSON.js.map +1 -0
  81. package/dist/esm/reactorTypes.d.ts +30 -0
  82. package/dist/esm/reactorTypes.d.ts.map +1 -0
  83. package/dist/esm/reactorTypes.js +2 -0
  84. package/dist/esm/reactorTypes.js.map +1 -0
  85. package/dist/esm/store.d.ts +67 -25
  86. package/dist/esm/store.d.ts.map +1 -1
  87. package/dist/esm/store.js +174 -81
  88. package/dist/esm/store.js.map +1 -1
  89. package/dist/standalone/index.js +2899 -2389
  90. package/dist/standalone/index.umd.cjs +3 -3
  91. package/package.json +2 -2
  92. package/src/Reactor.js +232 -77
  93. package/src/SyncTable.ts +85 -45
  94. package/src/createRouteHandler.ts +44 -0
  95. package/src/framework.ts +294 -0
  96. package/src/index.ts +9 -0
  97. package/src/{instaml.js → instaml.ts} +201 -96
  98. package/src/instaql.ts +88 -62
  99. package/src/parseSchemaFromJSON.ts +176 -0
  100. package/src/reactorTypes.ts +33 -0
  101. package/src/store.ts +257 -101
  102. package/__tests__/src/instaql.bench.js +0 -29
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@instantdb/core",
3
- "version": "0.22.88",
3
+ "version": "0.22.89-experimental.drewh-ssr.20277611943.1",
4
4
  "description": "Instant's core local abstraction",
5
5
  "homepage": "https://github.com/instantdb/instant/tree/main/client/packages/core",
6
6
  "repository": {
@@ -53,7 +53,7 @@
53
53
  "dependencies": {
54
54
  "mutative": "^1.0.10",
55
55
  "uuid": "^11.1.0",
56
- "@instantdb/version": "0.22.88"
56
+ "@instantdb/version": "0.22.89-experimental.drewh-ssr.20277611943.1"
57
57
  },
58
58
  "scripts": {
59
59
  "test": "vitest",
package/src/Reactor.js CHANGED
@@ -1,7 +1,7 @@
1
1
  // @ts-check
2
2
  import weakHash from './utils/weakHash.ts';
3
3
  import instaql from './instaql.ts';
4
- import * as instaml from './instaml.js';
4
+ import * as instaml from './instaml.ts';
5
5
  import * as s from './store.ts';
6
6
  import uuid from './utils/uuid.ts';
7
7
  import IndexedDBStorage from './IndexedDBStorage.ts';
@@ -36,6 +36,8 @@ import { SyncTable } from './SyncTable.ts';
36
36
  /** @typedef {import('./Connection.ts').Connection} Connection */
37
37
  /** @typedef {import('./Connection.ts').TransportType} TransportType */
38
38
  /** @typedef {import('./Connection.ts').EventSourceConstructor} EventSourceConstructor */
39
+ /** @typedef {import('./reactorTypes.ts').QuerySub} QuerySub */
40
+ /** @typedef {import('./reactorTypes.ts').QuerySubInStorage} QuerySubInStorage */
39
41
 
40
42
  const STATUS = {
41
43
  CONNECTING: 'connecting',
@@ -107,27 +109,52 @@ const ignoreLogging = {
107
109
  'patch-presence': true,
108
110
  };
109
111
 
112
+ /**
113
+ * @param {QuerySubInStorage} x
114
+ * @param {boolean | null} useDateObjects
115
+ * @returns {QuerySub}
116
+ */
110
117
  function querySubFromStorage(x, useDateObjects) {
111
118
  const v = typeof x === 'string' ? JSON.parse(x) : x;
112
119
 
113
120
  if (v?.result?.store) {
114
- const storeJSON = v.result.store;
115
- v.result.store = s.fromJSON({
116
- ...storeJSON,
117
- useDateObjects: useDateObjects,
118
- });
121
+ const attrsStore = s.attrsStoreFromJSON(
122
+ v.result.attrsStore,
123
+ v.result.store,
124
+ );
125
+ if (attrsStore) {
126
+ const storeJSON = v.result.store;
127
+ v.result.store = s.fromJSON(attrsStore, {
128
+ ...storeJSON,
129
+ useDateObjects: useDateObjects,
130
+ });
131
+ v.result.attrsStore = attrsStore;
132
+ }
119
133
  }
120
134
 
121
135
  return v;
122
136
  }
123
137
 
138
+ /**
139
+ *
140
+ * @param {string} _key
141
+ * @param {QuerySub} sub
142
+ * @returns QuerySubInStorage
143
+ */
124
144
  function querySubToStorage(_key, sub) {
125
- const jsonSub = { ...sub };
126
- if (sub.result?.store) {
127
- jsonSub.result = {
128
- ...sub.result,
129
- store: s.toJSON(sub.result.store),
145
+ const { result, ...rest } = sub;
146
+ const jsonSub = /** @type {import('./reactorTypes.ts').QuerySubInStorage} */ (
147
+ rest
148
+ );
149
+ if (result) {
150
+ /** @type {import('./reactorTypes.ts').QuerySubResultInStorage} */
151
+ const jsonResult = {
152
+ ...result,
153
+ store: s.toJSON(result.store),
154
+ attrsStore: result.attrsStore.toJSON(),
130
155
  };
156
+
157
+ jsonSub.result = jsonResult;
131
158
  }
132
159
  return jsonSub;
133
160
  }
@@ -176,12 +203,13 @@ function sortedMutationEntries(entries) {
176
203
  * @template {import('./presence.ts').RoomSchemaShape} [RoomSchema = {}]
177
204
  */
178
205
  export default class Reactor {
206
+ /** @type {s.AttrsStore | undefined} */
179
207
  attrs;
180
208
  _isOnline = true;
181
209
  _isShutdown = false;
182
210
  status = STATUS.CONNECTING;
183
211
 
184
- /** @type {PersistedObject} */
212
+ /** @type {PersistedObject<string, QuerySub, QuerySubInStorage>} */
185
213
  querySubs;
186
214
 
187
215
  /** @type {PersistedObject} */
@@ -306,20 +334,31 @@ export default class Reactor {
306
334
  useDateObjects: this.config.useDateObjects,
307
335
  },
308
336
  this._log,
309
- (triples) =>
310
- s.createStore(
311
- this.attrs,
337
+ (triples) => {
338
+ return s.createStore(
339
+ this.ensureAttrs(),
312
340
  triples,
313
341
  this.config.enableCardinalityInference,
314
- this._linkIndex,
315
342
  this.config.useDateObjects,
316
- ),
343
+ );
344
+ },
345
+ () => this.ensureAttrs(),
317
346
  );
318
347
 
319
348
  this._oauthCallbackResponse = this._oauthLoginInit();
320
349
 
321
350
  // kick off a request to cache it
322
- this.getCurrentUser();
351
+ this.getCurrentUser().then((userInfo) => {
352
+ this.syncUserToEndpoint(userInfo.user);
353
+ });
354
+
355
+ setInterval(
356
+ async () => {
357
+ const currentUser = await this.getCurrentUser();
358
+ this.syncUserToEndpoint(currentUser.user);
359
+ },
360
+ 1000 * 60 * 20,
361
+ );
323
362
 
324
363
  NetworkListener.getIsOnline().then((isOnline) => {
325
364
  this._isOnline = isOnline;
@@ -353,6 +392,13 @@ export default class Reactor {
353
392
  }
354
393
  }
355
394
 
395
+ ensureAttrs() {
396
+ if (!this.attrs) {
397
+ throw new Error('attrs have not loaded.');
398
+ }
399
+ return this.attrs;
400
+ }
401
+
356
402
  updateSchema(schema) {
357
403
  this.config = {
358
404
  ...this.config,
@@ -383,7 +429,7 @@ export default class Reactor {
383
429
  serialize: querySubToStorage,
384
430
  parse: (_key, x) => querySubFromStorage(x, this.config.useDateObjects),
385
431
  // objectSize
386
- objectSize: (x) => x.result?.store?.triples?.length ?? 0,
432
+ objectSize: (x) => x?.result?.store?.triples?.length ?? 0,
387
433
  logger: this._log,
388
434
  preloadEntryCount: 10,
389
435
  gc: {
@@ -513,6 +559,43 @@ export default class Reactor {
513
559
  }
514
560
  }
515
561
 
562
+ /**
563
+ * Does the same thing as add-query-ok
564
+ * but called as a result of receiving query info from ssr
565
+ * @param {any} q
566
+ * @param {{ triples: any; pageInfo: any; }} result
567
+ * @param {boolean} enableCardinalityInference
568
+ */
569
+ _addQueryData(q, result, enableCardinalityInference) {
570
+ if (!this.attrs) {
571
+ throw new Error('Attrs in reactor have not been set');
572
+ }
573
+ const queryHash = weakHash(q);
574
+ const attrsStore = this.ensureAttrs();
575
+ const store = s.createStore(
576
+ this.attrs,
577
+ result.triples,
578
+ enableCardinalityInference,
579
+ this.config.useDateObjects,
580
+ );
581
+ this.querySubs.updateInPlace((prev) => {
582
+ prev[queryHash] = {
583
+ result: {
584
+ store,
585
+ attrsStore,
586
+ pageInfo: result.pageInfo,
587
+ processedTxId: undefined,
588
+ isExternal: true,
589
+ },
590
+ q,
591
+ };
592
+ });
593
+ this._cleanupPendingMutationsQueries();
594
+ this.notifyOne(queryHash);
595
+ this.notifyOneQueryOnce(queryHash);
596
+ this._cleanupPendingMutationsTimeout();
597
+ }
598
+
516
599
  _handleReceive(connId, msg) {
517
600
  // opt-out, enabled by default if schema
518
601
  const enableCardinalityInference =
@@ -552,13 +635,14 @@ export default class Reactor {
552
635
  const pageInfo = result?.[0]?.data?.['page-info'];
553
636
  const aggregate = result?.[0]?.data?.['aggregate'];
554
637
  const triples = extractTriples(result);
638
+ const attrsStore = this.ensureAttrs();
555
639
  const store = s.createStore(
556
- this.attrs,
640
+ attrsStore,
557
641
  triples,
558
642
  enableCardinalityInference,
559
- this._linkIndex,
560
643
  this.config.useDateObjects,
561
644
  );
645
+
562
646
  this.querySubs.updateInPlace((prev) => {
563
647
  if (!prev[hash]) {
564
648
  this._log.info('Missing value in querySubs', { hash, q });
@@ -566,6 +650,7 @@ export default class Reactor {
566
650
  }
567
651
  prev[hash].result = {
568
652
  store,
653
+ attrsStore,
569
654
  pageInfo,
570
655
  aggregate,
571
656
  processedTxId: msg['processed-tx-id'],
@@ -603,7 +688,7 @@ export default class Reactor {
603
688
  this._cleanupPendingMutationsTimeout();
604
689
 
605
690
  const rewrittenMutations = this._rewriteMutations(
606
- this.attrs,
691
+ this.ensureAttrs(),
607
692
  this._pendingMutations(),
608
693
  processedTxId,
609
694
  );
@@ -624,32 +709,49 @@ export default class Reactor {
624
709
  const result = x['instaql-result'];
625
710
  const hash = weakHash(q);
626
711
  const triples = extractTriples(result);
712
+ const attrsStore = this.ensureAttrs();
627
713
  const store = s.createStore(
628
- this.attrs,
714
+ attrsStore,
629
715
  triples,
630
716
  enableCardinalityInference,
631
- this._linkIndex,
632
717
  this.config.useDateObjects,
633
718
  );
634
- const newStore = this._applyOptimisticUpdates(
635
- store,
636
- mutations,
637
- processedTxId,
638
- );
719
+ const { store: newStore, attrsStore: newAttrsStore } =
720
+ this._applyOptimisticUpdates(
721
+ store,
722
+ attrsStore,
723
+ mutations,
724
+ processedTxId,
725
+ );
639
726
  const pageInfo = result?.[0]?.data?.['page-info'];
640
727
  const aggregate = result?.[0]?.data?.['aggregate'];
641
- return { q, hash, store: newStore, pageInfo, aggregate };
728
+ return {
729
+ q,
730
+ hash,
731
+ store: newStore,
732
+ attrsStore: newAttrsStore,
733
+ pageInfo,
734
+ aggregate,
735
+ };
642
736
  });
643
737
 
644
- updates.forEach(({ hash, q, store, pageInfo, aggregate }) => {
645
- this.querySubs.updateInPlace((prev) => {
646
- if (!prev[hash]) {
647
- this._log.error('Missing value in querySubs', { hash, q });
648
- return;
649
- }
650
- prev[hash].result = { store, pageInfo, aggregate, processedTxId };
651
- });
652
- });
738
+ updates.forEach(
739
+ ({ hash, q, store, attrsStore, pageInfo, aggregate }) => {
740
+ this.querySubs.updateInPlace((prev) => {
741
+ if (!prev[hash]) {
742
+ this._log.error('Missing value in querySubs', { hash, q });
743
+ return;
744
+ }
745
+ prev[hash].result = {
746
+ store,
747
+ attrsStore,
748
+ pageInfo,
749
+ aggregate,
750
+ processedTxId,
751
+ };
752
+ });
753
+ },
754
+ );
653
755
 
654
756
  this._cleanupPendingMutationsQueries();
655
757
 
@@ -664,7 +766,7 @@ export default class Reactor {
664
766
  this._inFlightMutationEventIds.delete(eventId);
665
767
 
666
768
  const muts = this._rewriteMutations(
667
- this.attrs,
769
+ this.ensureAttrs(),
668
770
  this._pendingMutations(),
669
771
  );
670
772
  const prevMutation = muts.get(eventId);
@@ -681,12 +783,17 @@ export default class Reactor {
681
783
  });
682
784
  });
683
785
 
684
- const newAttrs = prevMutation['tx-steps']
685
- .filter(([action, ..._args]) => action === 'add-attr')
686
- .map(([_action, attr]) => attr)
687
- .concat(Object.values(this.attrs));
688
-
689
- this._setAttrs(newAttrs);
786
+ const newAttrs = [];
787
+ for (const step of prevMutation['tx-steps']) {
788
+ if (step[0] === 'add-attr') {
789
+ const attr = step[1];
790
+ newAttrs.push(attr);
791
+ }
792
+ }
793
+ if (newAttrs.length) {
794
+ const existingAttrs = Object.values(this.ensureAttrs().attrs);
795
+ this._setAttrs([...existingAttrs, ...newAttrs]);
796
+ }
690
797
 
691
798
  this._finishTransaction('synced', eventId);
692
799
 
@@ -870,10 +977,13 @@ export default class Reactor {
870
977
  }
871
978
 
872
979
  _setAttrs(attrs) {
873
- this.attrs = attrs.reduce((acc, attr) => {
874
- acc[attr.id] = attr;
875
- return acc;
876
- }, {});
980
+ this.attrs = new s.AttrsStoreClass(
981
+ attrs.reduce((acc, attr) => {
982
+ acc[attr.id] = attr;
983
+ return acc;
984
+ }, {}),
985
+ this._linkIndex,
986
+ );
877
987
 
878
988
  this.notifyAttrsSubs();
879
989
  }
@@ -1022,17 +1132,23 @@ export default class Reactor {
1022
1132
  // We remove `add-attr` commands for attrs that already exist.
1023
1133
  // We update `add-triple` and `retract-triple` commands to use the
1024
1134
  // server attr-ids.
1135
+ /**
1136
+ *
1137
+ * @param {s.AttrsStore} attrs
1138
+ * @param {any} muts
1139
+ * @param {number} [processedTxId]
1140
+ */
1025
1141
  _rewriteMutations(attrs, muts, processedTxId) {
1026
1142
  if (!attrs) return muts;
1027
1143
  if (!muts) return new Map();
1028
1144
  const findExistingAttr = (attr) => {
1029
1145
  const [_, etype, label] = attr['forward-identity'];
1030
- const existing = instaml.getAttrByFwdIdentName(attrs, etype, label);
1146
+ const existing = s.getAttrByFwdIdentName(attrs, etype, label);
1031
1147
  return existing;
1032
1148
  };
1033
1149
  const findReverseAttr = (attr) => {
1034
1150
  const [_, etype, label] = attr['forward-identity'];
1035
- const revAttr = instaml.getAttrByReverseIdentName(attrs, etype, label);
1151
+ const revAttr = s.getAttrByReverseIdentName(attrs, etype, label);
1036
1152
  return revAttr;
1037
1153
  };
1038
1154
  const mapping = { attrIdMap: {}, refSwapAttrIds: new Set() };
@@ -1109,6 +1225,9 @@ export default class Reactor {
1109
1225
  // ---------------------------
1110
1226
  // Transact
1111
1227
 
1228
+ /**
1229
+ * @returns {s.AttrsStore}
1230
+ */
1112
1231
  optimisticAttrs() {
1113
1232
  const pendingMutationSteps = [...this._pendingMutations().values()] // hack due to Map()
1114
1233
  .flatMap((x) => x['tx-steps']);
@@ -1126,27 +1245,30 @@ export default class Reactor {
1126
1245
  } else if (
1127
1246
  _action === 'update-attr' &&
1128
1247
  attr.id &&
1129
- this.attrs?.[attr.id]
1248
+ this.attrs?.getAttr(attr.id)
1130
1249
  ) {
1131
- const fullAttr = { ...this.attrs[attr.id], ...attr };
1250
+ const fullAttr = { ...this.attrs.getAttr(attr.id), ...attr };
1132
1251
  pendingAttrs.push(fullAttr);
1133
1252
  }
1134
1253
  }
1135
1254
 
1136
- const attrsWithoutDeleted = [
1137
- ...Object.values(this.attrs || {}),
1138
- ...pendingAttrs,
1139
- ].filter((a) => !deletedAttrIds.has(a.id));
1255
+ if (!deletedAttrIds.size && !pendingAttrs.length) {
1256
+ return this.attrs || new s.AttrsStoreClass({}, this._linkIndex);
1257
+ }
1140
1258
 
1141
- const attrsRecord = Object.fromEntries(
1142
- attrsWithoutDeleted.map((a) => [a.id, a]),
1143
- );
1259
+ const attrs = { ...(this.attrs?.attrs || {}) };
1260
+ for (const attr of pendingAttrs) {
1261
+ attrs[attr.id] = attr;
1262
+ }
1263
+ for (const id of deletedAttrIds) {
1264
+ delete attrs[id];
1265
+ }
1144
1266
 
1145
- return attrsRecord;
1267
+ return new s.AttrsStoreClass(attrs, this._linkIndex);
1146
1268
  }
1147
1269
 
1148
1270
  /** Runs instaql on a query and a store */
1149
- dataForQuery(hash) {
1271
+ dataForQuery(hash, applyOptimistic = true) {
1150
1272
  const errorMessage = this._errorMessage;
1151
1273
  if (errorMessage) {
1152
1274
  return { error: errorMessage };
@@ -1170,28 +1292,41 @@ export default class Reactor {
1170
1292
  return cached;
1171
1293
  }
1172
1294
 
1173
- const { store, pageInfo, aggregate, processedTxId } = result;
1295
+ let store = result.store;
1296
+ let attrsStore = result.attrsStore;
1297
+ const { pageInfo, aggregate, processedTxId } = result;
1174
1298
  const mutations = this._rewriteMutationsSorted(
1175
- store.attrs,
1299
+ attrsStore,
1176
1300
  pendingMutations,
1177
1301
  );
1178
- const newStore = this._applyOptimisticUpdates(
1179
- store,
1180
- mutations,
1181
- processedTxId,
1302
+ if (applyOptimistic) {
1303
+ const optimisticResult = this._applyOptimisticUpdates(
1304
+ store,
1305
+ attrsStore,
1306
+ mutations,
1307
+ processedTxId,
1308
+ );
1309
+
1310
+ store = optimisticResult.store;
1311
+ attrsStore = optimisticResult.attrsStore;
1312
+ }
1313
+ const resp = instaql(
1314
+ { store: store, attrsStore: attrsStore, pageInfo, aggregate },
1315
+ q,
1182
1316
  );
1183
- const resp = instaql({ store: newStore, pageInfo, aggregate }, q);
1184
1317
 
1185
1318
  return { data: resp, querySubVersion, pendingMutationsVersion };
1186
1319
  }
1187
1320
 
1188
- _applyOptimisticUpdates(store, mutations, processedTxId) {
1321
+ _applyOptimisticUpdates(store, attrsStore, mutations, processedTxId) {
1189
1322
  for (const [_, mut] of mutations) {
1190
1323
  if (!mut['tx-id'] || (processedTxId && mut['tx-id'] > processedTxId)) {
1191
- store = s.transact(store, mut['tx-steps']);
1324
+ const result = s.transact(store, attrsStore, mut['tx-steps']);
1325
+ store = result.store;
1326
+ attrsStore = result.attrsStore;
1192
1327
  }
1193
1328
  }
1194
- return store;
1329
+ return { store, attrsStore };
1195
1330
  }
1196
1331
 
1197
1332
  /** Re-run instaql and call all callbacks with new data */
@@ -1248,7 +1383,7 @@ export default class Reactor {
1248
1383
  try {
1249
1384
  const txSteps = instaml.transform(
1250
1385
  {
1251
- attrs: this.optimisticAttrs(),
1386
+ attrsStore: this.optimisticAttrs(),
1252
1387
  schema: this.config.schema,
1253
1388
  stores: Object.values(this.querySubs.currentValue).map(
1254
1389
  (sub) => sub?.result?.store,
@@ -1366,7 +1501,7 @@ export default class Reactor {
1366
1501
  });
1367
1502
 
1368
1503
  const muts = this._rewriteMutationsSorted(
1369
- this.attrs,
1504
+ this.ensureAttrs(),
1370
1505
  this._pendingMutations(),
1371
1506
  );
1372
1507
  muts.forEach(([eventId, mut]) => {
@@ -1822,7 +1957,7 @@ export default class Reactor {
1822
1957
  this.attrsCbs.push(cb);
1823
1958
 
1824
1959
  if (this.attrs) {
1825
- cb(this.attrs);
1960
+ cb(this.attrs.attrs);
1826
1961
  }
1827
1962
 
1828
1963
  return () => {
@@ -1841,7 +1976,7 @@ export default class Reactor {
1841
1976
  notifyAttrsSubs() {
1842
1977
  if (!this.attrs) return;
1843
1978
  const oas = this.optimisticAttrs();
1844
- this.attrsCbs.forEach((cb) => cb(oas));
1979
+ this.attrsCbs.forEach((cb) => cb(oas.attrs));
1845
1980
  }
1846
1981
 
1847
1982
  notifyConnectionStatusSubs(status) {
@@ -1912,7 +2047,27 @@ export default class Reactor {
1912
2047
  }
1913
2048
  }
1914
2049
 
2050
+ async syncUserToEndpoint(user) {
2051
+ if (this.config.cookieEndpoint) {
2052
+ try {
2053
+ fetch(this.config.cookieEndpoint + '/sync-auth', {
2054
+ method: 'POST',
2055
+ body: JSON.stringify({
2056
+ user: user,
2057
+ }),
2058
+ headers: {
2059
+ 'Content-Type': 'application/json',
2060
+ },
2061
+ });
2062
+ } catch (error) {
2063
+ console.error('Error syncing user with external endpoint', error);
2064
+ }
2065
+ }
2066
+ }
2067
+
1915
2068
  updateUser(newUser) {
2069
+ this.syncUserToEndpoint(newUser);
2070
+
1916
2071
  const newV = { error: undefined, user: newUser };
1917
2072
  this._currentUserCached = { isLoading: false, ...newV };
1918
2073
  this._dataForQueryCache = {};