@osdk/client 2.2.0-beta.3 → 2.2.0-beta.4

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 (88) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/build/browser/Logger.js.map +1 -1
  3. package/build/browser/observable/ObservableClient.js.map +1 -1
  4. package/build/browser/observable/internal/ActionApplication.js +102 -0
  5. package/build/browser/observable/internal/ActionApplication.js.map +1 -0
  6. package/build/browser/observable/internal/CacheKey.js +38 -1
  7. package/build/browser/observable/internal/CacheKey.js.map +1 -1
  8. package/build/browser/observable/internal/CacheKeys.js +4 -4
  9. package/build/browser/observable/internal/CacheKeys.js.map +1 -1
  10. package/build/browser/observable/internal/ChangedObjects.js +24 -1
  11. package/build/browser/observable/internal/ChangedObjects.js.map +1 -1
  12. package/build/browser/observable/internal/Layer.js +3 -3
  13. package/build/browser/observable/internal/Layer.js.map +1 -1
  14. package/build/browser/observable/internal/ListQuery.js +188 -66
  15. package/build/browser/observable/internal/ListQuery.js.map +1 -1
  16. package/build/browser/observable/internal/ObjectQuery.js +16 -3
  17. package/build/browser/observable/internal/ObjectQuery.js.map +1 -1
  18. package/build/browser/observable/internal/ObservableClientImpl.js +2 -2
  19. package/build/browser/observable/internal/ObservableClientImpl.js.map +1 -1
  20. package/build/browser/observable/internal/OptimisticJob.js +30 -29
  21. package/build/browser/observable/internal/OptimisticJob.js.map +1 -1
  22. package/build/browser/observable/internal/Query.js +42 -2
  23. package/build/browser/observable/internal/Query.js.map +1 -1
  24. package/build/browser/observable/internal/Store.js +259 -126
  25. package/build/browser/observable/internal/Store.js.map +1 -1
  26. package/build/browser/observable/internal/Store.test.js +416 -76
  27. package/build/browser/observable/internal/Store.test.js.map +1 -1
  28. package/build/browser/observable/internal/testUtils.js +142 -6
  29. package/build/browser/observable/internal/testUtils.js.map +1 -1
  30. package/build/browser/util/UserAgent.js +1 -1
  31. package/build/cjs/index.cjs +1 -1
  32. package/build/cjs/public/unstable-do-not-use.cjs +657 -268
  33. package/build/cjs/public/unstable-do-not-use.cjs.map +1 -1
  34. package/build/cjs/public/unstable-do-not-use.d.cts +13 -4
  35. package/build/esm/Logger.js.map +1 -1
  36. package/build/esm/observable/ObservableClient.js.map +1 -1
  37. package/build/esm/observable/internal/ActionApplication.js +102 -0
  38. package/build/esm/observable/internal/ActionApplication.js.map +1 -0
  39. package/build/esm/observable/internal/CacheKey.js +38 -1
  40. package/build/esm/observable/internal/CacheKey.js.map +1 -1
  41. package/build/esm/observable/internal/CacheKeys.js +4 -4
  42. package/build/esm/observable/internal/CacheKeys.js.map +1 -1
  43. package/build/esm/observable/internal/ChangedObjects.js +24 -1
  44. package/build/esm/observable/internal/ChangedObjects.js.map +1 -1
  45. package/build/esm/observable/internal/Layer.js +3 -3
  46. package/build/esm/observable/internal/Layer.js.map +1 -1
  47. package/build/esm/observable/internal/ListQuery.js +188 -66
  48. package/build/esm/observable/internal/ListQuery.js.map +1 -1
  49. package/build/esm/observable/internal/ObjectQuery.js +16 -3
  50. package/build/esm/observable/internal/ObjectQuery.js.map +1 -1
  51. package/build/esm/observable/internal/ObservableClientImpl.js +2 -2
  52. package/build/esm/observable/internal/ObservableClientImpl.js.map +1 -1
  53. package/build/esm/observable/internal/OptimisticJob.js +30 -29
  54. package/build/esm/observable/internal/OptimisticJob.js.map +1 -1
  55. package/build/esm/observable/internal/Query.js +42 -2
  56. package/build/esm/observable/internal/Query.js.map +1 -1
  57. package/build/esm/observable/internal/Store.js +259 -126
  58. package/build/esm/observable/internal/Store.js.map +1 -1
  59. package/build/esm/observable/internal/Store.test.js +416 -76
  60. package/build/esm/observable/internal/Store.test.js.map +1 -1
  61. package/build/esm/observable/internal/testUtils.js +142 -6
  62. package/build/esm/observable/internal/testUtils.js.map +1 -1
  63. package/build/esm/util/UserAgent.js +1 -1
  64. package/build/types/Logger.d.ts +1 -2
  65. package/build/types/Logger.d.ts.map +1 -1
  66. package/build/types/observable/ObservableClient.d.ts +10 -3
  67. package/build/types/observable/ObservableClient.d.ts.map +1 -1
  68. package/build/types/observable/internal/ActionApplication.d.ts +9 -0
  69. package/build/types/observable/internal/ActionApplication.d.ts.map +1 -0
  70. package/build/types/observable/internal/CacheKeys.d.ts +2 -1
  71. package/build/types/observable/internal/CacheKeys.d.ts.map +1 -1
  72. package/build/types/observable/internal/ChangedObjects.d.ts +6 -2
  73. package/build/types/observable/internal/ChangedObjects.d.ts.map +1 -1
  74. package/build/types/observable/internal/Layer.d.ts +1 -1
  75. package/build/types/observable/internal/Layer.d.ts.map +1 -1
  76. package/build/types/observable/internal/ListQuery.d.ts +18 -17
  77. package/build/types/observable/internal/ListQuery.d.ts.map +1 -1
  78. package/build/types/observable/internal/ObjectQuery.d.ts +3 -3
  79. package/build/types/observable/internal/ObjectQuery.d.ts.map +1 -1
  80. package/build/types/observable/internal/OptimisticJob.d.ts +2 -2
  81. package/build/types/observable/internal/OptimisticJob.d.ts.map +1 -1
  82. package/build/types/observable/internal/Query.d.ts +6 -5
  83. package/build/types/observable/internal/Query.d.ts.map +1 -1
  84. package/build/types/observable/internal/Store.d.ts +47 -19
  85. package/build/types/observable/internal/Store.d.ts.map +1 -1
  86. package/build/types/observable/internal/testUtils.d.ts +13 -3
  87. package/build/types/observable/internal/testUtils.d.ts.map +1 -1
  88. package/package.json +8 -7
@@ -14,19 +14,19 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
- import { delay } from "msw";
18
17
  import { BehaviorSubject } from "rxjs";
19
18
  import invariant from "tiny-invariant";
19
+ import { additionalContext } from "../../Client.js";
20
20
  import { DEBUG_REFCOUNTS } from "../DebugFlags.js";
21
+ import { ActionApplication } from "./ActionApplication.js";
21
22
  import { CacheKeys } from "./CacheKeys.js";
22
- import { createChangedObjects } from "./ChangedObjects.js";
23
- import { Layer } from "./Layer.js";
23
+ import { createChangedObjects, DEBUG_ONLY__changesToString } from "./ChangedObjects.js";
24
+ import { Entry, Layer } from "./Layer.js";
24
25
  import { isListCacheKey, ListQuery } from "./ListQuery.js";
25
26
  import { ObjectQuery } from "./ObjectQuery.js";
26
- import { runOptimisticJob } from "./OptimisticJob.js";
27
27
  import { RefCounts } from "./RefCounts.js";
28
+ import { WeakMapWithEntries } from "./WeakMapWithEntries.js";
28
29
  import { WhereClauseCanonicalizer } from "./WhereClauseCanonicalizer.js";
29
- const ACTION_DELAY = process.env.NODE_ENV === "production" ? 0 : 1000;
30
30
 
31
31
  /*
32
32
  Work still to do:
@@ -35,9 +35,9 @@ const ACTION_DELAY = process.env.NODE_ENV === "production" ? 0 : 1000;
35
35
  - [x] automatic optimistic list updates
36
36
  - [x] useOsdkObjects
37
37
  - [x] imply offline for objects passed directly
38
- - [ ] websocket subscriptions
38
+ - [x] websocket subscriptions
39
39
  - [ ] links
40
- - [ ] add pagination
40
+ - [x] add pagination
41
41
  - [ ] sub-selection support
42
42
  - [ ] interfaces
43
43
  - [ ] setup defaults
@@ -59,19 +59,38 @@ function createInitEntry(cacheKey) {
59
59
  - Data is one per layer per cache key
60
60
  */
61
61
 
62
+ export class OrderByCanonicalizer {
63
+ // crappy version
64
+ #map = new Map();
65
+ canonicalize = orderBy => {
66
+ if (this.#map.has(JSON.stringify(orderBy))) {
67
+ return this.#map.get(JSON.stringify(orderBy));
68
+ } else {
69
+ this.#map.set(JSON.stringify(orderBy), orderBy);
70
+ return orderBy;
71
+ }
72
+ };
73
+ }
62
74
  export class Store {
63
75
  whereCanonicalizer = new WhereClauseCanonicalizer();
76
+ orderByCanonicalizer = new OrderByCanonicalizer();
64
77
  #truthLayer = new Layer(undefined, undefined);
65
78
  #topLayer;
66
- #queries = new WeakMap();
79
+
80
+ /** @internal */
81
+
82
+ #queries = new WeakMapWithEntries();
67
83
  #cacheKeyToSubject = new WeakMap();
68
84
  #cacheKeys;
69
85
  #refCounts = new RefCounts(DEBUG_REFCOUNTS ? 15_000 : 60_000, k => this.#cleanupCacheKey(k));
70
86
  #finalizationRegistry;
71
87
  constructor(client) {
72
88
  this.client = client;
89
+ this.logger = client[additionalContext].logger?.child({}, {
90
+ msgPrefix: "Store"
91
+ });
73
92
  this.#topLayer = this.#truthLayer;
74
- this.#cacheKeys = new CacheKeys(this.whereCanonicalizer, k => {
93
+ this.#cacheKeys = new CacheKeys(this.whereCanonicalizer, this.orderByCanonicalizer, k => {
75
94
  if (DEBUG_REFCOUNTS) {
76
95
  const cacheKeyType = k.type;
77
96
  const otherKeys = k.otherKeys;
@@ -185,7 +204,16 @@ export class Store {
185
204
  const query = this.getObjectQuery(apiName, pk);
186
205
  this.#refCounts.retain(query.cacheKey);
187
206
  if (options.mode !== "offline") {
188
- void query.revalidate(options.mode === "force");
207
+ query.revalidate(options.mode === "force").catch(e => {
208
+ // we don't want observeObject() to return a promise,
209
+ // so we settle for logging an error here instead of
210
+ // dropping it on the floor.
211
+ if (this.logger) {
212
+ this.logger.error("Unhandled error in observeObject", e);
213
+ } else {
214
+ throw e;
215
+ }
216
+ });
189
217
  }
190
218
  const sub = query.subscribe({
191
219
  next: subFn
@@ -197,11 +225,9 @@ export class Store {
197
225
  }
198
226
  };
199
227
  }
200
- observeList(apiName, where, options, subFn) {
201
- if (typeof apiName !== "string") {
202
- apiName = apiName.apiName;
203
- }
204
- const query = this.getListQuery(apiName, where, options);
228
+ observeList(options, subFn) {
229
+ // the ListQuery represents the shared state of the list
230
+ const query = this.getListQuery(options.objectType, options.where ?? {}, options.orderBy ?? {}, options);
205
231
  this.#refCounts.retain(query.cacheKey);
206
232
  if (options.mode !== "offline") {
207
233
  void query.revalidate(options.mode === "force");
@@ -209,6 +235,109 @@ export class Store {
209
235
  const sub = query.subscribe({
210
236
  next: subFn
211
237
  });
238
+ if (options.streamUpdates) {
239
+ const miniDef = {
240
+ type: "object",
241
+ apiName: typeof options.objectType === "string" ? options.objectType : options.objectType.apiName
242
+ };
243
+ let objectSet = this.client(miniDef);
244
+ if (options.where) {
245
+ objectSet = objectSet.where(options.where ?? {});
246
+ }
247
+ const store = this;
248
+ const websocketSubscription = objectSet.subscribe({
249
+ onChange({
250
+ object,
251
+ state
252
+ }) {
253
+ if (process.env.NODE_ENV !== "production") {
254
+ store.logger?.debug({
255
+ methodName: "onError"
256
+ }, "updates", state, object);
257
+ }
258
+ const cacheKey = store.getCacheKey("object", object.$objectType, object.$primaryKey);
259
+ const type = store.#peekQuery(cacheKey) == null ? "addedObjects" : "modifiedObjects";
260
+ const changes = createChangedObjects();
261
+ changes[type].set(object.$objectType, object);
262
+ if (state === "ADDED_OR_UPDATED") {
263
+ // todo, can we do the update without
264
+ // the extra invalidation? maybe a flag to updateObject
265
+ store.updateObject(object.$objectType, object);
266
+ store.maybeRevalidateLists(changes).catch(err => {
267
+ // eslint-disable-next-line no-console
268
+ console.error("Unhandled error in maybeRevalidateLists", err);
269
+ });
270
+ } else if (state === "REMOVED") {
271
+ const changes = createChangedObjects();
272
+ store.batch({
273
+ changes
274
+ }, batch => {
275
+ const existing = batch.read(query.cacheKey);
276
+ const cacheKeyToRemove = store.getCacheKey("object", object.$objectType, object.$primaryKey);
277
+ if (existing?.status === "loaded") {
278
+ const newObjects = existing.value?.data.filter(o => o !== cacheKeyToRemove);
279
+ if (newObjects?.length !== existing.value?.data.length) {
280
+ batch.changes.modifiedLists.add(query.cacheKey);
281
+ batch.write(query.cacheKey, {
282
+ data: newObjects ?? []
283
+ }, "loaded");
284
+ // Should there be an else for this case? Do we need to invalidate
285
+ // the paging tokens we may have?
286
+ }
287
+ } else {
288
+ // There may be a tiny race here where OSW tells us the object has
289
+ // been removed but an outstanding invalidation of this query is
290
+ // about to return. In this case, its possible that we remove this item
291
+ // from the list and then the returned list load re-adds it.
292
+ // To avoid this, we will just force reload the query to be sure
293
+ // we don't leave things in a bad state.
294
+
295
+ if (process.env.NODE_ENV !== "production") {
296
+ store.logger?.info("Removing an object from an object list that is in the middle of being loaded.", existing);
297
+ }
298
+ query.revalidate(/* force */true).catch(e => {
299
+ if (store.logger) {
300
+ store.logger?.error("Uncaught error while revalidating list", e);
301
+ } else {
302
+ // eslint-disable-next-line no-console
303
+ console.error("Uncaught error while revalidating list", e);
304
+ }
305
+ });
306
+ }
307
+ });
308
+ }
309
+ },
310
+ onError(errors) {
311
+ if (process.env.NODE_ENV !== "production") {
312
+ store.logger?.info({
313
+ methodName: "onError"
314
+ }, "subscription errors", errors);
315
+ }
316
+ },
317
+ onOutOfDate() {
318
+ if (process.env.NODE_ENV !== "production") {
319
+ store.logger?.info({
320
+ methodName: "onOutOfDate"
321
+ });
322
+ }
323
+ },
324
+ onSuccessfulSubscription() {
325
+ if (process.env.NODE_ENV !== "production") {
326
+ store.logger?.info({
327
+ methodName: "onSuccessfulSubscription"
328
+ });
329
+ }
330
+ }
331
+ });
332
+ sub.add(() => {
333
+ if (process.env.NODE_ENV !== "production") {
334
+ store.logger?.info({
335
+ methodName: "observeList"
336
+ }, "Unsubscribing from websocket");
337
+ }
338
+ websocketSubscription.unsubscribe();
339
+ });
340
+ }
212
341
  return {
213
342
  unsubscribe: () => {
214
343
  sub.unsubscribe();
@@ -227,14 +356,15 @@ export class Store {
227
356
  }
228
357
  return query;
229
358
  }
230
- getListQuery(apiName, where, opts, peek = false) {
359
+ getListQuery(apiName, where, orderBy, opts) {
231
360
  if (typeof apiName !== "string") {
232
361
  apiName = apiName.apiName;
233
362
  }
234
363
  const canonWhere = this.whereCanonicalizer.canonicalize(where);
235
- const listCacheKey = this.getCacheKey("list", apiName, canonWhere);
364
+ const canonOrderBy = this.orderByCanonicalizer.canonicalize(orderBy);
365
+ const listCacheKey = this.getCacheKey("list", apiName, canonWhere, canonOrderBy);
236
366
  return this.#getQuery(listCacheKey, () => {
237
- return new ListQuery(this, this.getSubject(listCacheKey), apiName, canonWhere, listCacheKey, opts);
367
+ return new ListQuery(this, this.getSubject(listCacheKey), apiName, canonWhere, canonOrderBy, listCacheKey, opts);
238
368
  });
239
369
  }
240
370
  getObjectQuery(apiName, pk) {
@@ -255,14 +385,13 @@ export class Store {
255
385
  return objEntry?.value;
256
386
  }
257
387
  batch = ({
258
- optimisticId
388
+ optimisticId,
389
+ changes = createChangedObjects()
259
390
  }, batchFn) => {
260
391
  !(optimisticId === undefined || !!optimisticId) ? process.env.NODE_ENV !== "production" ? invariant(false, "optimistic must be undefined or not falsy") : invariant(false) : void 0;
261
392
  let needsLayer = optimisticId !== undefined;
262
393
  const batchContext = {
263
- addedObjects: new Set(),
264
- modifiedObjects: new Set(),
265
- modifiedLists: new Set(),
394
+ changes,
266
395
  createLayerIfNeeded: () => {
267
396
  if (needsLayer) {
268
397
  this.#topLayer = this.#topLayer.addLayer(optimisticId);
@@ -274,16 +403,12 @@ export class Store {
274
403
  const oldTopValue = this.#topLayer.get(cacheKey);
275
404
  if (optimisticId) batchContext.createLayerIfNeeded();
276
405
  const writeLayer = optimisticId ? this.#topLayer : this.#truthLayer;
277
- const newValue = {
278
- cacheKey,
279
- value,
280
- lastUpdated: Date.now(),
281
- status
282
- };
406
+ const newValue = new Entry(cacheKey, value, Date.now(), status);
283
407
  writeLayer.set(cacheKey, newValue);
284
408
  const newTopValue = this.#topLayer.get(cacheKey);
285
409
  if (oldTopValue !== newTopValue) {
286
410
  this.#cacheKeyToSubject.get(cacheKey)?.next({
411
+ // eslint-disable-next-line @typescript-eslint/no-misused-spread
287
412
  ...newValue,
288
413
  isOptimistic: newTopValue?.value !== this.#truthLayer.get(cacheKey)?.value
289
414
  });
@@ -295,6 +420,7 @@ export class Store {
295
420
  }
296
421
  };
297
422
  const retVal = batchFn(batchContext);
423
+ void this.maybeUpdateLists(changes, optimisticId);
298
424
  return {
299
425
  batchResult: batchContext,
300
426
  retVal: retVal
@@ -315,37 +441,93 @@ export class Store {
315
441
  // TODO
316
442
  // could we detect that a list WOULD include it?
317
443
  }
318
- maybeRevalidateLists(changes) {
319
- for (const [cacheKey, v] of this.#truthLayer.entries()) {
320
- if (isListCacheKey(cacheKey)) {
321
- // fixme promise
322
- void this.#peekQuery(cacheKey)?.maybeRevalidate(changes);
444
+ async maybeRevalidateLists(changes) {
445
+ if (process.env.NODE_ENV !== "production") {
446
+ // todo
447
+ this.logger?.trace({
448
+ methodName: "maybeRevalidateList"
449
+ }, DEBUG_ONLY__changesToString(changes));
450
+ }
451
+ try {
452
+ const promises = [];
453
+ for (const [cacheKey, v] of this.#truthLayer.entries()) {
454
+ if (isListCacheKey(cacheKey)) {
455
+ const promise = this.#peekQuery(cacheKey)?.maybeUpdateAndRevalidate(changes, undefined);
456
+ if (promise) promises.push(promise);
457
+ }
458
+ }
459
+ await Promise.all(promises);
460
+ } finally {
461
+ if (process.env.NODE_ENV !== "production") {
462
+ // todo
463
+ this.logger?.trace({
464
+ methodName: "maybeRevalidateList"
465
+ }, "in finally", DEBUG_ONLY__changesToString(changes));
323
466
  }
324
467
  }
325
468
  }
326
469
  maybeUpdateLists(changes, optimisticId) {
327
- for (const [cacheKey, v] of this.#truthLayer.entries()) {
470
+ if (process.env.NODE_ENV !== "production") {
471
+ this.logger?.trace({
472
+ methodName: "maybeUpdateLists"
473
+ }, DEBUG_ONLY__changesToString(changes), {
474
+ optimisticId
475
+ });
476
+ }
477
+ if (changes.addedObjects.size === 0 && changes.modifiedObjects.size === 0) {
478
+ return Promise.resolve([]);
479
+ }
480
+ const promises = [];
481
+ for (const cacheKey of this.#queries.keys()) {
328
482
  if (isListCacheKey(cacheKey)) {
329
- // fixme promise
330
- void this.#peekQuery(cacheKey)?.maybeUpdate(changes, optimisticId);
483
+ if (!changes.modifiedLists.has(cacheKey)) {
484
+ const promise = this.#peekQuery(cacheKey)?.maybeUpdateAndRevalidate(changes, optimisticId);
485
+ if (promise) promises.push(promise);
486
+ }
331
487
  }
332
488
  }
489
+ return Promise.all(promises);
333
490
  }
334
- invalidateObjectType(apiName) {
491
+
492
+ /**
493
+ * @param apiName
494
+ * @param changes The changes we know about / to update
495
+ * @returns
496
+ */
497
+ invalidateObjectType(apiName, changes) {
335
498
  if (typeof apiName !== "string") {
336
499
  apiName = apiName.apiName;
337
500
  }
501
+ if (process.env.NODE_ENV !== "production") {
502
+ this.logger?.info({
503
+ methodName: "invalidateObjectType"
504
+ }, changes ? DEBUG_ONLY__changesToString(changes) : void 0);
505
+ }
506
+ const promises = [];
338
507
  for (const [cacheKey, v] of this.#truthLayer.entries()) {
339
508
  if (isListCacheKey(cacheKey, apiName)) {
340
- void this.#peekQuery(cacheKey)?.revalidate(true);
509
+ if (!changes || !changes.modifiedLists.has(cacheKey)) {
510
+ const promise = this.#peekQuery(cacheKey)?.revalidate(true);
511
+ if (promise) {
512
+ promises.push(promise);
513
+ changes?.modifiedLists.add(cacheKey);
514
+ }
515
+ }
341
516
  }
342
517
  }
518
+ return Promise.all(promises);
343
519
  }
344
- invalidateList(apiName, where) {
345
- if (typeof apiName !== "string") {
346
- apiName = apiName.apiName;
520
+ invalidateList({
521
+ objectType,
522
+ where,
523
+ orderBy
524
+ }) {
525
+ if (typeof objectType !== "string") {
526
+ objectType = objectType.apiName;
347
527
  }
348
- const cacheKey = this.getCacheKey("list", apiName, where);
528
+ where = this.whereCanonicalizer.canonicalize(where ?? {});
529
+ orderBy = this.orderByCanonicalizer.canonicalize(orderBy ?? {});
530
+ const cacheKey = this.getCacheKey("list", objectType, where, orderBy);
349
531
  void this.#peekQuery(cacheKey)?.revalidate(true);
350
532
  }
351
533
  updateObject(apiName, value, {
@@ -361,19 +543,48 @@ export class Store {
361
543
  return query.writeToStore(value, "loaded", batch);
362
544
  }).retVal.value;
363
545
  }
364
- updateList(apiName, where, values, {
546
+ updateObjects(values, batch) {
547
+ // update the cache for any object that has changed
548
+ // and save the mapped values to return
549
+ return values.map(v => {
550
+ return this.getObjectQuery(v.$apiName, v.$primaryKey).writeToStore(v, "loaded", batch).cacheKey;
551
+ });
552
+ }
553
+
554
+ /**
555
+ * Updates the internal state of a list and will create a new internal query if needed.
556
+ *
557
+ * Helper method only for tests right now. May be removed later.
558
+ *
559
+ * @param apiName
560
+ * @param where
561
+ * @param orderBy
562
+ * @param objects
563
+ * @param param4
564
+ * @param opts
565
+ */
566
+ updateList({
567
+ objectType: apiName,
568
+ where,
569
+ orderBy
570
+ }, objects, {
365
571
  optimisticId
366
572
  } = {}, opts = {
367
573
  dedupeInterval: 0
368
574
  }) {
369
- if (typeof apiName !== "string") {
370
- apiName = apiName.apiName;
575
+ if (process.env.NODE_ENV !== "production") {
576
+ this.logger?.info({
577
+ methodName: "updateList"
578
+ }, "", {
579
+ optimisticId
580
+ });
371
581
  }
372
- const query = this.getListQuery(apiName, where, opts);
582
+ const query = this.getListQuery(apiName, where ?? {}, orderBy ?? {}, opts);
373
583
  this.batch({
374
584
  optimisticId
375
- }, b => {
376
- query.updateList(values, false, "loaded", b);
585
+ }, batch => {
586
+ const objectCacheKeys = this.updateObjects(objects, batch);
587
+ query.updateList(objectCacheKeys, false, "loaded", batch);
377
588
  });
378
589
  }
379
590
  retain(cacheKey) {
@@ -383,82 +594,4 @@ export class Store {
383
594
  this.#refCounts.release(cacheKey);
384
595
  }
385
596
  }
386
- class ActionApplication {
387
- constructor(store) {
388
- this.store = store;
389
- }
390
- applyAction = (action, args, {
391
- optimisticUpdate
392
- } = {}) => {
393
- const removeOptimisticResult = runOptimisticJob(this.store, optimisticUpdate);
394
- return (async () => {
395
- try {
396
- // The types for client get confused when we dynamically applyAction so we
397
- // have to deal with the `any` here and force cast it to what it should be.
398
- // TODO: Update the types so this doesn't happen!
399
- // eslint-disable-next-line @typescript-eslint/no-unsafe-call
400
- const actionResults = await this.store.client(action).applyAction(args, {
401
- $returnEdits: true
402
- });
403
- if (ACTION_DELAY > 0) {
404
- // eslint-disable-next-line no-console
405
- console.log("action done, pausing");
406
- await delay(ACTION_DELAY);
407
- // eslint-disable-next-line no-console
408
- console.log("action done, pausing done");
409
- }
410
- await this.#invalidateActionEditResponse(actionResults);
411
- return actionResults;
412
- } finally {
413
- // make sure this happens even if the action fails
414
- await removeOptimisticResult();
415
- }
416
- })();
417
- };
418
- #invalidateActionEditResponse = value => {
419
- const typesToInvalidate = new Set();
420
- let promisesToWait = [];
421
- if (value.type === "edits") {
422
- // TODO we need an backend update for deletes
423
- for (const obj of value.modifiedObjects) {
424
- promisesToWait.push(this.store.invalidateObject(obj.objectType, obj.primaryKey));
425
- }
426
- for (const obj of value.addedObjects) {
427
- promisesToWait.push(this.store.invalidateObject(obj.objectType, obj.primaryKey));
428
- typesToInvalidate.add(obj.objectType);
429
- }
430
- promisesToWait = [Promise.allSettled(promisesToWait).then(() => {
431
- const changes2 = this.#changesFromActionEditResponse(value);
432
- this.store.maybeRevalidateLists(changes2);
433
- })];
434
- } else {
435
- for (const apiName of value.editedObjectTypes) {
436
- typesToInvalidate.add(apiName.toString());
437
- }
438
- }
439
- return Promise.allSettled(promisesToWait).then(() => {
440
- // after the single object invalidations are done we can decide if we need to updates any lists
441
- for (const objectType of typesToInvalidate) {
442
- // TODO make sure this covers individual object loads too
443
- this.store.invalidateObjectType(objectType);
444
- }
445
- return value;
446
- });
447
- };
448
- #changesFromActionEditResponse = value => {
449
- const changes = createChangedObjects();
450
- for (const changeType of ["addedObjects", "modifiedObjects"]) {
451
- for (const {
452
- objectType,
453
- primaryKey
454
- } of value[changeType] ?? []) {
455
- const obj = this.store.getObject(objectType, primaryKey);
456
- if (obj) {
457
- changes[changeType].set(objectType, obj);
458
- }
459
- }
460
- }
461
- return changes;
462
- };
463
- }
464
597
  //# sourceMappingURL=Store.js.map