atom.io 0.35.0 → 0.36.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/dist/eslint-plugin/index.d.ts +2 -18
  2. package/dist/eslint-plugin/index.d.ts.map +1 -1
  3. package/dist/eslint-plugin/index.js +4 -141
  4. package/dist/eslint-plugin/index.js.map +1 -1
  5. package/dist/internal/index.d.ts +47 -41
  6. package/dist/internal/index.d.ts.map +1 -1
  7. package/dist/internal/index.js +95 -78
  8. package/dist/internal/index.js.map +1 -1
  9. package/dist/json/index.d.ts +2 -10
  10. package/dist/json/index.d.ts.map +1 -1
  11. package/dist/json/index.js +1 -31
  12. package/dist/json/index.js.map +1 -1
  13. package/dist/main/index.d.ts +24 -23
  14. package/dist/main/index.d.ts.map +1 -1
  15. package/dist/main/index.js +9 -9
  16. package/dist/main/index.js.map +1 -1
  17. package/dist/react/index.d.ts +4 -4
  18. package/dist/react/index.d.ts.map +1 -1
  19. package/dist/react/index.js.map +1 -1
  20. package/dist/react-devtools/index.d.ts.map +1 -1
  21. package/dist/realtime/index.d.ts +4 -4
  22. package/dist/realtime/index.d.ts.map +1 -1
  23. package/dist/realtime/index.js +2 -6
  24. package/dist/realtime/index.js.map +1 -1
  25. package/dist/realtime-client/index.d.ts +2 -2
  26. package/dist/realtime-client/index.d.ts.map +1 -1
  27. package/dist/realtime-client/index.js.map +1 -1
  28. package/dist/realtime-react/index.d.ts +2 -2
  29. package/dist/realtime-react/index.d.ts.map +1 -1
  30. package/dist/realtime-react/index.js.map +1 -1
  31. package/dist/realtime-server/index.d.ts +18 -18
  32. package/dist/realtime-server/index.d.ts.map +1 -1
  33. package/dist/realtime-server/index.js +5 -9
  34. package/dist/realtime-server/index.js.map +1 -1
  35. package/dist/transceivers/set-rtx/index.d.ts +1 -1
  36. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  37. package/dist/transceivers/set-rtx/index.js.map +1 -1
  38. package/package.json +5 -5
  39. package/src/eslint-plugin/index.ts +0 -1
  40. package/src/eslint-plugin/rules/explicit-state-types.ts +8 -1
  41. package/src/eslint-plugin/rules/index.ts +0 -1
  42. package/src/internal/atom/dispose-atom.ts +1 -0
  43. package/src/internal/families/find-in-store.ts +4 -5
  44. package/src/internal/families/get-family-of-token.ts +4 -5
  45. package/src/internal/families/init-family-member.ts +3 -4
  46. package/src/internal/families/seek-in-store.ts +4 -5
  47. package/src/internal/get-state/read-or-compute-value.ts +14 -2
  48. package/src/internal/index.ts +19 -21
  49. package/src/internal/ingest-updates/ingest-creation-disposal.ts +18 -15
  50. package/src/internal/ingest-updates/ingest-selector-update.ts +9 -5
  51. package/src/internal/join/get-internal-relations-from-store.ts +2 -2
  52. package/src/internal/join/join-internal.ts +3 -14
  53. package/src/internal/molecule.ts +1 -0
  54. package/src/internal/mutable/create-mutable-atom-family.ts +37 -20
  55. package/src/internal/mutable/create-mutable-atom.ts +16 -12
  56. package/src/internal/mutable/get-json-family.ts +7 -6
  57. package/src/internal/mutable/get-json-token.ts +6 -13
  58. package/src/internal/mutable/get-update-family.ts +7 -8
  59. package/src/internal/mutable/get-update-token.ts +5 -9
  60. package/src/internal/mutable/tracker-family.ts +10 -13
  61. package/src/internal/mutable/tracker.ts +66 -90
  62. package/src/internal/mutable/transceiver.ts +35 -8
  63. package/src/internal/selector/dispose-selector.ts +9 -9
  64. package/src/internal/set-state/copy-mutable-if-needed.ts +8 -6
  65. package/src/internal/set-state/reset-atom-or-selector.ts +11 -4
  66. package/src/internal/set-state/set-atom.ts +1 -1
  67. package/src/internal/store/counterfeit.ts +3 -4
  68. package/src/internal/store/deposit.ts +7 -9
  69. package/src/internal/store/store.ts +2 -2
  70. package/src/internal/store/withdraw.ts +7 -11
  71. package/src/json/index.ts +0 -2
  72. package/src/main/atom.ts +24 -36
  73. package/src/main/dispose-state.ts +4 -4
  74. package/src/main/find-state.ts +3 -4
  75. package/src/main/join.ts +2 -2
  76. package/src/main/logger.ts +7 -7
  77. package/src/main/tokens.ts +9 -11
  78. package/src/main/transaction.ts +11 -5
  79. package/src/main/validators.ts +1 -1
  80. package/src/react/use-json.ts +15 -25
  81. package/src/realtime/shared-room-store.ts +11 -22
  82. package/src/realtime-client/pull-mutable-atom-family-member.ts +5 -9
  83. package/src/realtime-client/pull-mutable-atom.ts +5 -9
  84. package/src/realtime-react/use-pull-mutable-atom.ts +3 -5
  85. package/src/realtime-react/use-pull-mutable-family-member.ts +3 -4
  86. package/src/realtime-server/realtime-mutable-family-provider.ts +3 -4
  87. package/src/realtime-server/realtime-mutable-provider.ts +2 -3
  88. package/src/realtime-server/realtime-server-stores/server-room-external-actions.ts +6 -5
  89. package/src/realtime-server/realtime-server-stores/server-user-store.ts +8 -15
  90. package/src/transceivers/set-rtx/set-rtx.ts +1 -1
  91. package/src/eslint-plugin/rules/synchronous-selector-dependencies.ts +0 -140
  92. package/src/eslint-plugin/walk.ts +0 -81
  93. package/src/json/select-json-family.ts +0 -55
  94. package/src/json/select-json.ts +0 -19
@@ -1,5 +1,5 @@
1
1
  import { Join as Join$1, arbitrary as arbitrary$1, subscribeToState as subscribeToState$1, subscribeToTimeline as subscribeToTimeline$1, subscribeToTransaction as subscribeToTransaction$1 } from "atom.io/internal";
2
- import { parseJson, selectJson, selectJsonFamily, stringifyJson } from "atom.io/json";
2
+ import { parseJson, stringifyJson } from "atom.io/json";
3
3
  import { Anarchy, AtomIOLogger } from "atom.io";
4
4
  import { SetRTX } from "atom.io/transceivers/set-rtx";
5
5
 
@@ -460,10 +460,10 @@ function copyMutableIfNeeded(target, atom, origin) {
460
460
  const originValue = origin.valueMap.get(atom.key);
461
461
  const targetValue = target.valueMap.get(atom.key);
462
462
  if (originValue !== targetValue) return targetValue;
463
- if (originValue === void 0) return atom.default();
463
+ if (originValue === void 0) return new atom.class();
464
464
  origin.logger.info(`📃`, `atom`, atom.key, `copying`);
465
- const jsonValue = atom.toJson(originValue);
466
- const copiedValue = atom.fromJson(jsonValue);
465
+ const jsonValue = originValue.toJSON();
466
+ const copiedValue = atom.class.fromJSON(jsonValue);
467
467
  target.valueMap.set(atom.key, copiedValue);
468
468
  new Tracker(atom, origin);
469
469
  return copiedValue;
@@ -619,8 +619,7 @@ const readOrComputeValue = (target, state) => {
619
619
  case `writable_pure_selector`:
620
620
  target.logger.info(`🧮`, state.type, state.key, `computing value`);
621
621
  return state.get();
622
- case `atom`:
623
- case `mutable_atom`: {
622
+ case `atom`: {
624
623
  const def = state.default;
625
624
  let defaultValue;
626
625
  if (def instanceof Function) defaultValue = def();
@@ -629,6 +628,13 @@ const readOrComputeValue = (target, state) => {
629
628
  target.logger.info(`💁`, `atom`, state.key, `could not find cached value; using default`, defaultValue);
630
629
  return cachedValue;
631
630
  }
631
+ case `mutable_atom`: {
632
+ const Ctor = state.class;
633
+ const instance = new Ctor();
634
+ const cachedValue = cacheValue(target, state.key, instance, state.subject);
635
+ target.logger.info(`💁`, `mutable_atom`, state.key, `could not find cached value; using default`, instance);
636
+ return cachedValue;
637
+ }
632
638
  }
633
639
  };
634
640
 
@@ -718,9 +724,16 @@ const setAtom = (target, atom, next) => {
718
724
  //#endregion
719
725
  //#region src/internal/set-state/reset-atom-or-selector.ts
720
726
  function resetAtom(store, state) {
721
- let def = state.default;
722
- if (def instanceof Function) def = def();
723
- setAtom(store, state, def);
727
+ switch (state.type) {
728
+ case `mutable_atom`:
729
+ setAtom(store, state, new state.class());
730
+ return;
731
+ case `atom`: {
732
+ let def = state.default;
733
+ if (def instanceof Function) def = def();
734
+ setAtom(store, state, def);
735
+ }
736
+ }
724
737
  }
725
738
  function resetAtomOrSelector(store, state) {
726
739
  switch (state.type) {
@@ -1210,6 +1223,7 @@ function claimWithinStore(store, newProvenance, claim, exclusive) {
1210
1223
  const transferEvent = {
1211
1224
  type: `molecule_transfer`,
1212
1225
  key: molecule.key,
1226
+ exclusive: Boolean(exclusive),
1213
1227
  from: priorProvenance,
1214
1228
  to: [newProvenanceMolecule.key]
1215
1229
  };
@@ -1282,15 +1296,15 @@ function ingestMoleculeDisposalEvent(update, applying, store) {
1282
1296
  function ingestMoleculeTransferEvent(update, applying, store) {
1283
1297
  switch (applying) {
1284
1298
  case `newValue`:
1285
- {
1286
- const provenance = update.to.length === 1 ? update.to[0] : update.to;
1287
- claimWithinStore(store, provenance, update.key, `exclusive`);
1288
- }
1299
+ for (const newOwner of update.to) claimWithinStore(store, newOwner, update.key, update.exclusive ? `exclusive` : void 0);
1289
1300
  break;
1290
1301
  case `oldValue`:
1291
1302
  {
1292
- const provenance = update.from.length === 1 ? update.from[0] : update.from;
1293
- claimWithinStore(store, provenance, update.key, `exclusive`);
1303
+ let exclusivity = `exclusive`;
1304
+ for (const previousOwner of update.from) {
1305
+ claimWithinStore(store, previousOwner, update.key, exclusivity);
1306
+ exclusivity = void 0;
1307
+ }
1294
1308
  }
1295
1309
  break;
1296
1310
  }
@@ -1299,7 +1313,9 @@ function ingestMoleculeTransferEvent(update, applying, store) {
1299
1313
  //#endregion
1300
1314
  //#region src/internal/ingest-updates/ingest-selector-update.ts
1301
1315
  function ingestSelectorUpdate(applying, selectorUpdate, store) {
1302
- const updates = applying === `newValue` ? selectorUpdate.atomUpdates : selectorUpdate.atomUpdates.toReversed();
1316
+ let updates;
1317
+ if (applying === `newValue`) updates = selectorUpdate.atomUpdates;
1318
+ else updates = selectorUpdate.atomUpdates.toReversed();
1303
1319
  for (const atomUpdate of updates) ingestAtomUpdate(applying, atomUpdate, store);
1304
1320
  }
1305
1321
 
@@ -1693,19 +1709,18 @@ function createStandaloneSelector(store, options) {
1693
1709
  //#region src/internal/selector/dispose-selector.ts
1694
1710
  function disposeSelector(store, selectorToken) {
1695
1711
  const target = newest(store);
1696
- const { key, type } = selectorToken;
1697
- const selector = withdraw(target, selectorToken);
1698
- if (!selector.family) store.logger.error(`❌`, type, key, `Standalone selectors cannot be disposed.`);
1712
+ const { key, type, family: familyMeta } = selectorToken;
1713
+ if (!familyMeta) store.logger.error(`❌`, type, key, `Standalone selectors cannot be disposed.`);
1699
1714
  else {
1700
- const molecule = target.molecules.get(selector.family.subKey);
1701
- if (molecule) target.moleculeData.delete(selector.family.subKey, selector.family.key);
1715
+ const molecule = target.molecules.get(familyMeta.subKey);
1716
+ if (molecule) target.moleculeData.delete(familyMeta.subKey, familyMeta.key);
1702
1717
  let familyToken;
1703
1718
  switch (selectorToken.type) {
1704
1719
  case `writable_held_selector`:
1705
1720
  {
1706
1721
  target.writableSelectors.delete(key);
1707
1722
  familyToken = {
1708
- key: selector.family.key,
1723
+ key: familyMeta.key,
1709
1724
  type: `writable_held_selector_family`
1710
1725
  };
1711
1726
  const family = withdraw(store, familyToken);
@@ -1720,7 +1735,7 @@ function disposeSelector(store, selectorToken) {
1720
1735
  {
1721
1736
  target.writableSelectors.delete(key);
1722
1737
  familyToken = {
1723
- key: selector.family.key,
1738
+ key: familyMeta.key,
1724
1739
  type: `writable_pure_selector_family`
1725
1740
  };
1726
1741
  const family = withdraw(store, familyToken);
@@ -1735,7 +1750,7 @@ function disposeSelector(store, selectorToken) {
1735
1750
  {
1736
1751
  target.readonlySelectors.delete(key);
1737
1752
  familyToken = {
1738
- key: selector.family.key,
1753
+ key: familyMeta.key,
1739
1754
  type: `readonly_held_selector_family`
1740
1755
  };
1741
1756
  const family = withdraw(store, familyToken);
@@ -1750,7 +1765,7 @@ function disposeSelector(store, selectorToken) {
1750
1765
  {
1751
1766
  target.readonlySelectors.delete(key);
1752
1767
  familyToken = {
1753
- key: selector.family.key,
1768
+ key: familyMeta.key,
1754
1769
  type: `readonly_pure_selector_family`
1755
1770
  };
1756
1771
  const family = withdraw(store, familyToken);
@@ -1765,6 +1780,7 @@ function disposeSelector(store, selectorToken) {
1765
1780
  target.valueMap.delete(key);
1766
1781
  target.selectorAtoms.delete(key);
1767
1782
  target.selectorGraph.delete(key);
1783
+ target.moleculeData.delete(familyMeta.key, familyMeta.subKey);
1768
1784
  store.logger.info(`🔥`, selectorToken.type, key, `deleted`);
1769
1785
  if (isChildStore(target) && target.transactionMeta.phase === `building`) target.transactionMeta.update.updates.push({
1770
1786
  type: `state_disposal`,
@@ -2237,66 +2253,60 @@ var Tracker = class {
2237
2253
  }
2238
2254
  unsubscribeFromInnerValue;
2239
2255
  unsubscribeFromState;
2240
- observeCore(mutableState, latestUpdateState, target) {
2256
+ captureSignalsFromCore(mutableState, latestUpdateState, target) {
2241
2257
  const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2242
- const originalInnerValue = getFromStore(target, mutableState);
2243
- this.unsubscribeFromInnerValue = originalInnerValue.subscribe(subscriptionKey, (update) => {
2258
+ const trackerCapturesOutboundSignal = (update) => {
2244
2259
  setIntoStore(target, latestUpdateState, update);
2245
- });
2246
- this.unsubscribeFromState = subscribeToState(target, mutableState, subscriptionKey, (update) => {
2260
+ };
2261
+ const originalInnerValue = getFromStore(target, mutableState);
2262
+ this.unsubscribeFromInnerValue = originalInnerValue.subscribe(subscriptionKey, trackerCapturesOutboundSignal);
2263
+ this.unsubscribeFromState = subscribeToState(target, mutableState, subscriptionKey, function trackerLooksForNewReference(update) {
2247
2264
  if (update.newValue !== update.oldValue) {
2248
2265
  this.unsubscribeFromInnerValue();
2249
- this.unsubscribeFromInnerValue = update.newValue.subscribe(subscriptionKey, (transceiverUpdate) => {
2250
- setIntoStore(target, latestUpdateState, transceiverUpdate);
2251
- });
2266
+ this.unsubscribeFromInnerValue = update.newValue.subscribe(subscriptionKey, trackerCapturesOutboundSignal);
2252
2267
  }
2253
- });
2268
+ }.bind(this));
2254
2269
  }
2255
- updateCore(mutableState, latestUpdateState, target) {
2270
+ supplySignalsToCore(mutableState, latestUpdateState, target) {
2256
2271
  const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
2257
- subscribeToState(target, latestUpdateState, subscriptionKey, ({ newValue, oldValue }) => {
2272
+ subscribeToState(target, latestUpdateState, subscriptionKey, function trackerCapturesInboundSignal({ newValue, oldValue }) {
2258
2273
  const timelineId = target.timelineTopics.getRelatedKey(latestUpdateState.key);
2259
- if (timelineId) {
2260
- const timelineData = target.timelines.get(timelineId);
2261
- if (timelineData?.timeTraveling) {
2262
- const unsubscribe$1 = subscribeToTimeline(target, {
2263
- key: timelineId,
2264
- type: `timeline`
2265
- }, subscriptionKey, (update) => {
2266
- unsubscribe$1();
2267
- setIntoStore(target, mutableState, (transceiver) => {
2268
- if (update === `redo` && newValue) transceiver.do(newValue);
2269
- else if (update === `undo` && oldValue) transceiver.undo(oldValue);
2270
- return transceiver;
2271
- });
2274
+ if (timelineId && target.timelines.get(timelineId)?.timeTraveling) {
2275
+ const unsubscribe = subscribeToTimeline(target, {
2276
+ key: timelineId,
2277
+ type: `timeline`
2278
+ }, subscriptionKey, function trackerWaitsForTimeTravelToFinish(update) {
2279
+ unsubscribe();
2280
+ setIntoStore(target, mutableState, (transceiver) => {
2281
+ if (update === `redo` && newValue) transceiver.do(newValue);
2282
+ else if (update === `undo` && oldValue) transceiver.undo(oldValue);
2283
+ return transceiver;
2272
2284
  });
2273
- return;
2274
- }
2285
+ });
2286
+ return;
2275
2287
  }
2276
- const unsubscribe = target.on.operationClose.subscribe(subscriptionKey, () => {
2277
- unsubscribe();
2278
- const mutable = getFromStore(target, mutableState);
2279
- const updateNumber = newValue === null ? -1 : mutable.getUpdateNumber(newValue);
2280
- const eventOffset = updateNumber - mutable.cacheUpdateNumber;
2281
- if (newValue && eventOffset === 1) setIntoStore(target, mutableState, (transceiver) => (transceiver.do(newValue), transceiver));
2282
- else target.logger.info(`❌`, `mutable_atom`, mutableState.key, `could not be updated. Expected update number ${mutable.cacheUpdateNumber + 1}, but got ${updateNumber}`);
2283
- });
2288
+ const mutable = getFromStore(target, mutableState);
2289
+ const updateNumber = mutable.getUpdateNumber(newValue);
2290
+ const eventOffset = updateNumber - mutable.cacheUpdateNumber;
2291
+ if (newValue && eventOffset === 1) setIntoStore(target, mutableState, (transceiver) => (transceiver.do(newValue), transceiver));
2292
+ else target.logger.info(`❌`, `mutable_atom`, mutableState.key, `could not be updated. Expected update number ${mutable.cacheUpdateNumber + 1}, but got ${updateNumber}`);
2284
2293
  });
2285
2294
  }
2286
- mutableState;
2287
- latestUpdateState;
2295
+ mutableAtomToken;
2296
+ latestSignalToken;
2288
2297
  [Symbol.dispose];
2289
- constructor(mutableState, store) {
2290
- this.mutableState = mutableState;
2298
+ constructor(mutableAtomToken, store) {
2291
2299
  const target = newest(store);
2292
- this.latestUpdateState = this.initializeState(mutableState, target);
2293
- this.observeCore(mutableState, this.latestUpdateState, target);
2294
- this.updateCore(mutableState, this.latestUpdateState, target);
2295
- target.trackers.set(mutableState.key, this);
2300
+ const latestSignalToken = this.initializeState(mutableAtomToken, target);
2301
+ this.mutableAtomToken = mutableAtomToken;
2302
+ this.latestSignalToken = latestSignalToken;
2303
+ this.captureSignalsFromCore(mutableAtomToken, latestSignalToken, target);
2304
+ this.supplySignalsToCore(mutableAtomToken, latestSignalToken, target);
2305
+ target.trackers.set(mutableAtomToken.key, this);
2296
2306
  this[Symbol.dispose] = () => {
2297
2307
  this.unsubscribeFromInnerValue();
2298
2308
  this.unsubscribeFromState();
2299
- target.trackers.delete(mutableState.key);
2309
+ target.trackers.delete(mutableAtomToken.key);
2300
2310
  };
2301
2311
  }
2302
2312
  };
@@ -2347,7 +2357,13 @@ function createMutableAtom(store, options, family) {
2347
2357
  };
2348
2358
  }
2349
2359
  new Tracker(token, store);
2350
- if (!family) selectJson(token, options, store);
2360
+ if (!family) createStandaloneSelector(store, {
2361
+ key: `${key}:JSON`,
2362
+ get: ({ get }) => get(token).toJSON(),
2363
+ set: ({ set }, newValue) => {
2364
+ set(token, options.class.fromJSON(newValue));
2365
+ }
2366
+ });
2351
2367
  store.on.atomCreation.next(token);
2352
2368
  return token;
2353
2369
  }
@@ -2408,9 +2424,7 @@ function createMutableAtomFamily(store, options, internalRoles) {
2408
2424
  const target = newest(store);
2409
2425
  const individualOptions = {
2410
2426
  key: fullKey,
2411
- default: () => options.default(key),
2412
- toJson: options.toJson,
2413
- fromJson: options.fromJson
2427
+ class: options.class
2414
2428
  };
2415
2429
  if (options.effects) individualOptions.effects = options.effects(key);
2416
2430
  const token = createMutableAtom(target, individualOptions, family);
@@ -2423,12 +2437,16 @@ function createMutableAtomFamily(store, options, internalRoles) {
2423
2437
  const atomFamily$1 = Object.assign(familyFunction, familyToken, {
2424
2438
  subject,
2425
2439
  install: (s) => createMutableAtomFamily(s, options),
2426
- toJson: options.toJson,
2427
- fromJson: options.fromJson,
2428
2440
  internalRoles
2429
2441
  });
2430
2442
  store.families.set(options.key, atomFamily$1);
2431
- selectJsonFamily(store, atomFamily$1, options);
2443
+ createWritablePureSelectorFamily(store, {
2444
+ key: `${options.key}:JSON`,
2445
+ get: (key) => ({ get }) => get(familyToken, key).toJSON(),
2446
+ set: (key) => ({ set }, newValue) => {
2447
+ set(familyToken, key, options.class.fromJSON(newValue));
2448
+ }
2449
+ }, [`mutable`, `json`]);
2432
2450
  new FamilyTracker(atomFamily$1, store);
2433
2451
  return familyToken;
2434
2452
  }
@@ -2738,6 +2756,7 @@ function disposeAtom(store, atomToken) {
2738
2756
  target.valueMap.delete(key);
2739
2757
  target.selectorAtoms.delete(key);
2740
2758
  target.atomsThatAreDefault.delete(key);
2759
+ target.moleculeData.delete(family.key, family.subKey);
2741
2760
  store.timelineTopics.delete(key);
2742
2761
  if (atomToken.type === `mutable_atom`) {
2743
2762
  const updateToken = getUpdateToken(atomToken);
@@ -2833,9 +2852,7 @@ var Join = class {
2833
2852
  const bSide = options.between[1];
2834
2853
  const relatedKeysAtoms = createMutableAtomFamily(store, {
2835
2854
  key: `${options.key}/relatedKeys`,
2836
- default: () => new SetRTX(),
2837
- fromJson: (json) => SetRTX.fromJSON(json),
2838
- toJson: (set) => set.toJSON()
2855
+ class: SetRTX
2839
2856
  }, [`join`, `relations`]);
2840
2857
  this.core = { relatedKeysAtoms };
2841
2858
  const getRelatedKeys = ({ get }, key) => get(relatedKeysAtoms, key);