atom.io 0.35.0 → 0.36.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 (133) 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 +100 -78
  6. package/dist/internal/index.d.ts.map +1 -1
  7. package/dist/internal/index.js +180 -163
  8. package/dist/internal/index.js.map +1 -1
  9. package/dist/introspection/index.d.ts +5 -6
  10. package/dist/introspection/index.d.ts.map +1 -1
  11. package/dist/introspection/index.js +2 -3
  12. package/dist/introspection/index.js.map +1 -1
  13. package/dist/json/index.d.ts +2 -10
  14. package/dist/json/index.d.ts.map +1 -1
  15. package/dist/json/index.js +1 -31
  16. package/dist/json/index.js.map +1 -1
  17. package/dist/main/index.d.ts +38 -39
  18. package/dist/main/index.d.ts.map +1 -1
  19. package/dist/main/index.js +15 -16
  20. package/dist/main/index.js.map +1 -1
  21. package/dist/react/index.d.ts +4 -4
  22. package/dist/react/index.d.ts.map +1 -1
  23. package/dist/react/index.js.map +1 -1
  24. package/dist/react-devtools/index.js.map +1 -1
  25. package/dist/realtime/index.d.ts +4 -4
  26. package/dist/realtime/index.d.ts.map +1 -1
  27. package/dist/realtime/index.js +2 -6
  28. package/dist/realtime/index.js.map +1 -1
  29. package/dist/realtime-client/index.d.ts +7 -8
  30. package/dist/realtime-client/index.d.ts.map +1 -1
  31. package/dist/realtime-client/index.js +3 -4
  32. package/dist/realtime-client/index.js.map +1 -1
  33. package/dist/realtime-react/index.d.ts +4 -4
  34. package/dist/realtime-react/index.d.ts.map +1 -1
  35. package/dist/realtime-react/index.js.map +1 -1
  36. package/dist/realtime-server/index.d.ts +18 -18
  37. package/dist/realtime-server/index.d.ts.map +1 -1
  38. package/dist/realtime-server/index.js +5 -9
  39. package/dist/realtime-server/index.js.map +1 -1
  40. package/dist/transceivers/set-rtx/index.d.ts +9 -2
  41. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  42. package/dist/transceivers/set-rtx/index.js +3 -0
  43. package/dist/transceivers/set-rtx/index.js.map +1 -1
  44. package/package.json +6 -6
  45. package/src/eslint-plugin/index.ts +0 -1
  46. package/src/eslint-plugin/rules/explicit-state-types.ts +8 -1
  47. package/src/eslint-plugin/rules/index.ts +0 -1
  48. package/src/internal/atom/create-regular-atom.ts +5 -5
  49. package/src/internal/atom/dispose-atom.ts +1 -0
  50. package/src/internal/atom/has-role.ts +12 -0
  51. package/src/internal/atom/index.ts +1 -0
  52. package/src/internal/caching.ts +38 -16
  53. package/src/internal/families/find-in-store.ts +4 -5
  54. package/src/internal/families/get-family-of-token.ts +4 -5
  55. package/src/internal/families/init-family-member.ts +3 -4
  56. package/src/internal/families/seek-in-store.ts +4 -5
  57. package/src/internal/get-state/read-or-compute-value.ts +37 -16
  58. package/src/internal/index.ts +19 -21
  59. package/src/internal/ingest-updates/ingest-creation-disposal.ts +18 -15
  60. package/src/internal/ingest-updates/ingest-selector-update.ts +9 -5
  61. package/src/internal/join/get-internal-relations-from-store.ts +2 -2
  62. package/src/internal/join/join-internal.ts +10 -18
  63. package/src/internal/molecule.ts +1 -0
  64. package/src/internal/mutable/create-mutable-atom-family.ts +40 -22
  65. package/src/internal/mutable/create-mutable-atom.ts +16 -12
  66. package/src/internal/mutable/get-json-family.ts +7 -6
  67. package/src/internal/mutable/get-json-token.ts +6 -13
  68. package/src/internal/mutable/get-update-family.ts +7 -8
  69. package/src/internal/mutable/get-update-token.ts +5 -9
  70. package/src/internal/mutable/tracker-family.ts +31 -38
  71. package/src/internal/mutable/tracker.ts +86 -104
  72. package/src/internal/mutable/transceiver.ts +37 -9
  73. package/src/internal/selector/create-readonly-held-selector.ts +2 -2
  74. package/src/internal/selector/create-readonly-pure-selector.ts +2 -2
  75. package/src/internal/selector/create-writable-held-selector.ts +3 -3
  76. package/src/internal/selector/create-writable-pure-selector.ts +3 -3
  77. package/src/internal/selector/dispose-selector.ts +9 -9
  78. package/src/internal/set-state/reset-atom-or-selector.ts +11 -4
  79. package/src/internal/set-state/set-atom.ts +15 -22
  80. package/src/internal/set-state/set-into-store.ts +5 -4
  81. package/src/internal/store/counterfeit.ts +3 -4
  82. package/src/internal/store/deposit.ts +8 -11
  83. package/src/internal/store/store.ts +7 -7
  84. package/src/internal/store/withdraw.ts +8 -12
  85. package/src/internal/subscribe/subscribe-in-store.ts +2 -2
  86. package/src/internal/subscribe/subscribe-to-transaction.ts +2 -2
  87. package/src/internal/timeline/create-timeline.ts +3 -3
  88. package/src/internal/transaction/act-upon-store.ts +2 -2
  89. package/src/internal/transaction/apply-transaction.ts +2 -2
  90. package/src/internal/transaction/build-transaction.ts +2 -2
  91. package/src/internal/transaction/create-transaction.ts +3 -3
  92. package/src/internal/transaction/index.ts +2 -2
  93. package/src/internal/transaction/is-root-store.ts +4 -2
  94. package/src/internal/utility-types.ts +1 -1
  95. package/src/introspection/attach-introspection-states.ts +3 -3
  96. package/src/introspection/attach-transaction-index.ts +4 -4
  97. package/src/introspection/attach-transaction-logs.ts +4 -4
  98. package/src/introspection/auditor.ts +3 -3
  99. package/src/json/index.ts +0 -2
  100. package/src/main/atom.ts +24 -36
  101. package/src/main/dispose-state.ts +6 -5
  102. package/src/main/find-state.ts +3 -4
  103. package/src/main/get-state.ts +6 -5
  104. package/src/main/join.ts +2 -2
  105. package/src/main/logger.ts +7 -7
  106. package/src/main/reset-state.ts +3 -3
  107. package/src/main/set-state.ts +3 -3
  108. package/src/main/subscribe.ts +3 -3
  109. package/src/main/tokens.ts +8 -14
  110. package/src/main/transaction.ts +17 -13
  111. package/src/main/validators.ts +1 -1
  112. package/src/react/use-json.ts +14 -24
  113. package/src/react-devtools/TransactionIndex.tsx +3 -3
  114. package/src/react-devtools/Updates.tsx +2 -2
  115. package/src/realtime/shared-room-store.ts +11 -22
  116. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +2 -2
  117. package/src/realtime-client/pull-mutable-atom-family-member.ts +8 -17
  118. package/src/realtime-client/pull-mutable-atom.ts +7 -14
  119. package/src/realtime-client/push-state.ts +6 -5
  120. package/src/realtime-client/server-action.ts +5 -4
  121. package/src/realtime-react/use-pull-mutable-atom.ts +3 -5
  122. package/src/realtime-react/use-pull-mutable-family-member.ts +3 -4
  123. package/src/realtime-react/use-server-action.ts +2 -2
  124. package/src/realtime-server/realtime-mutable-family-provider.ts +3 -4
  125. package/src/realtime-server/realtime-mutable-provider.ts +2 -3
  126. package/src/realtime-server/realtime-server-stores/server-room-external-actions.ts +6 -5
  127. package/src/realtime-server/realtime-server-stores/server-user-store.ts +8 -15
  128. package/src/transceivers/set-rtx/set-rtx.ts +14 -1
  129. package/src/eslint-plugin/rules/synchronous-selector-dependencies.ts +0 -140
  130. package/src/eslint-plugin/walk.ts +0 -81
  131. package/src/internal/set-state/copy-mutable-if-needed.ts +0 -27
  132. package/src/json/select-json-family.ts +0 -55
  133. package/src/json/select-json.ts +0 -19
@@ -7,30 +7,34 @@ import type {
7
7
  StateCreation,
8
8
  StateDisposal,
9
9
  } from "atom.io"
10
- import type { Canonical, Json } from "atom.io/json"
11
- import { selectJsonFamily, stringifyJson } from "atom.io/json"
10
+ import type { Canonical } from "atom.io/json"
11
+ import { stringifyJson } from "atom.io/json"
12
12
 
13
- import { type MutableAtomFamily, prettyPrintTokenType } from ".."
13
+ import {
14
+ createWritablePureSelectorFamily,
15
+ type MutableAtomFamily,
16
+ prettyPrintTokenType,
17
+ } from ".."
14
18
  import { newest } from "../lineage"
15
19
  import { createMutableAtom } from "../mutable"
16
20
  import type { Store } from "../store"
17
21
  import { Subject } from "../subject"
18
22
  import { FamilyTracker } from "./tracker-family"
19
- import type { Transceiver } from "./transceiver"
23
+ import type { AsJSON, Transceiver } from "./transceiver"
20
24
 
21
25
  export function createMutableAtomFamily<
22
- T extends Transceiver<any>,
23
- J extends Json.Serializable,
26
+ T extends Transceiver<any, any, any>,
24
27
  K extends Canonical,
25
28
  >(
26
29
  store: Store,
27
- options: MutableAtomFamilyOptions<T, J, K>,
30
+ options: MutableAtomFamilyOptions<T, K>,
28
31
  internalRoles?: string[],
29
- ): MutableAtomFamilyToken<T, J, K> {
30
- const familyToken = {
31
- key: options.key,
32
- type: `mutable_atom_family`,
33
- } as const satisfies MutableAtomFamilyToken<T, J, K>
32
+ ): MutableAtomFamilyToken<T, K> {
33
+ const familyToken: MutableAtomFamilyToken<T & Transceiver<any, any, any>, K> =
34
+ {
35
+ key: options.key,
36
+ type: `mutable_atom_family`,
37
+ }
34
38
 
35
39
  const existing = store.families.get(options.key)
36
40
  if (existing) {
@@ -45,20 +49,18 @@ export function createMutableAtomFamily<
45
49
  }
46
50
 
47
51
  const subject = new Subject<
48
- StateCreation<MutableAtomToken<T, J>> | StateDisposal<MutableAtomToken<T, J>>
52
+ StateCreation<MutableAtomToken<T>> | StateDisposal<MutableAtomToken<T>>
49
53
  >()
50
54
 
51
- const familyFunction = (key: K): MutableAtomToken<T, J> => {
55
+ const familyFunction = (key: K): MutableAtomToken<T> => {
52
56
  const subKey = stringifyJson(key)
53
57
  const family: FamilyMetadata = { key: options.key, subKey }
54
58
  const fullKey = `${options.key}(${subKey})`
55
59
  const target = newest(store)
56
60
 
57
- const individualOptions: MutableAtomOptions<T, J> = {
61
+ const individualOptions: MutableAtomOptions<T> = {
58
62
  key: fullKey,
59
- default: () => options.default(key),
60
- toJson: options.toJson,
61
- fromJson: options.fromJson,
63
+ class: options.class,
62
64
  }
63
65
  if (options.effects) {
64
66
  individualOptions.effects = options.effects(key)
@@ -73,13 +75,29 @@ export function createMutableAtomFamily<
73
75
  const atomFamily = Object.assign(familyFunction, familyToken, {
74
76
  subject,
75
77
  install: (s: Store) => createMutableAtomFamily(s, options),
76
- toJson: options.toJson,
77
- fromJson: options.fromJson,
78
78
  internalRoles,
79
- }) satisfies MutableAtomFamily<T, J, K>
79
+ }) satisfies MutableAtomFamily<T, K>
80
80
 
81
81
  store.families.set(options.key, atomFamily)
82
- selectJsonFamily(store, atomFamily, options)
82
+
83
+ createWritablePureSelectorFamily<AsJSON<T>, K>(
84
+ store,
85
+ {
86
+ key: `${options.key}:JSON`,
87
+ get:
88
+ (key) =>
89
+ ({ get }) =>
90
+ get(familyToken, key).toJSON(),
91
+ set:
92
+ (key) =>
93
+ ({ set }, newValue) => {
94
+ set(familyToken, key, options.class.fromJSON(newValue))
95
+ },
96
+ },
97
+ [`mutable`, `json`],
98
+ )
99
+
83
100
  new FamilyTracker(atomFamily, store)
101
+
84
102
  return familyToken
85
103
  }
@@ -4,11 +4,9 @@ import type {
4
4
  MutableAtomToken,
5
5
  UpdateHandler,
6
6
  } from "atom.io"
7
- import type { Json } from "atom.io/json"
8
- import { selectJson } from "atom.io/json"
9
7
 
10
8
  import type { MutableAtom } from ".."
11
- import { resetInStore, setIntoStore } from ".."
9
+ import { createStandaloneSelector, resetInStore, setIntoStore } from ".."
12
10
  import { newest } from "../lineage"
13
11
  import { deposit, type Store } from "../store"
14
12
  import { Subject } from "../subject"
@@ -16,14 +14,11 @@ import { subscribeToState } from "../subscribe"
16
14
  import { Tracker } from "./tracker"
17
15
  import type { Transceiver } from "./transceiver"
18
16
 
19
- export function createMutableAtom<
20
- T extends Transceiver<any>,
21
- J extends Json.Serializable,
22
- >(
17
+ export function createMutableAtom<T extends Transceiver<any, any, any>>(
23
18
  store: Store,
24
- options: MutableAtomOptions<T, J>,
19
+ options: MutableAtomOptions<T>,
25
20
  family: FamilyMetadata | undefined,
26
- ): MutableAtomToken<T, J> {
21
+ ): MutableAtomToken<T> {
27
22
  store.logger.info(
28
23
  `🔨`,
29
24
  `atom`,
@@ -43,8 +38,11 @@ export function createMutableAtom<
43
38
  )
44
39
  return deposit(existing)
45
40
  }
46
- const subject = new Subject<{ newValue: T; oldValue: T }>()
47
- const newAtom: MutableAtom<T, J> = {
41
+ const subject = new Subject<{
42
+ newValue: T
43
+ oldValue: T
44
+ }>()
45
+ const newAtom: MutableAtom<T> = {
48
46
  ...options,
49
47
  type,
50
48
  install: (s: Store) => {
@@ -86,7 +84,13 @@ export function createMutableAtom<
86
84
 
87
85
  new Tracker(token, store)
88
86
  if (!family) {
89
- selectJson(token, options, store)
87
+ createStandaloneSelector(store, {
88
+ key: `${key}:JSON`,
89
+ get: ({ get }) => get(token).toJSON(),
90
+ set: ({ set }, newValue) => {
91
+ set(token, options.class.fromJSON(newValue))
92
+ },
93
+ })
90
94
  }
91
95
  store.on.atomCreation.next(token)
92
96
  return token
@@ -7,16 +7,17 @@ import type { Store } from "../store"
7
7
  import type { Transceiver } from "./transceiver"
8
8
 
9
9
  export const getJsonFamily = <
10
- Core extends Transceiver<Json.Serializable>,
11
- SerializableCore extends Json.Serializable,
10
+ Core extends Transceiver<any, Json.Serializable, Json.Serializable>,
12
11
  Key extends Canonical,
13
12
  >(
14
- mutableAtomFamily: MutableAtomFamilyToken<Core, SerializableCore, Key>,
13
+ mutableAtomFamily: MutableAtomFamilyToken<Core, Key>,
15
14
  store: Store,
16
- ): WritablePureSelectorFamily<SerializableCore, Key> => {
15
+ ): WritablePureSelectorFamily<ReturnType<Core[`toJSON`]>, Key> => {
17
16
  const target = newest(store)
18
17
  const key = `${mutableAtomFamily.key}:JSON`
19
- const jsonFamily: WritablePureSelectorFamily<SerializableCore, Key> =
20
- target.families.get(key) as WritablePureSelectorFamily<SerializableCore, Key>
18
+ const jsonFamily = target.families.get(key) as WritablePureSelectorFamily<
19
+ ReturnType<Core[`toJSON`]>,
20
+ Key
21
+ >
21
22
  return jsonFamily
22
23
  }
@@ -3,27 +3,20 @@ import type {
3
3
  WritablePureSelectorFamilyToken,
4
4
  WritablePureSelectorToken,
5
5
  } from "atom.io"
6
- import type { Json } from "atom.io/json"
7
6
 
8
7
  import { findInStore } from "../families"
9
8
  import { newest } from "../lineage"
10
9
  import { type Store, withdraw } from "../store"
11
- import type { Transceiver } from "./transceiver"
10
+ import type { AsJSON, Transceiver } from "./transceiver"
12
11
 
13
- export const getJsonToken = <
14
- Core extends Transceiver<any>,
15
- SerializableCore extends Json.Serializable,
16
- >(
12
+ export const getJsonToken = <T extends Transceiver<any, any, any>>(
17
13
  store: Store,
18
- mutableAtomToken: MutableAtomToken<Core, SerializableCore>,
19
- ): WritablePureSelectorToken<SerializableCore> => {
14
+ mutableAtomToken: MutableAtomToken<T>,
15
+ ): WritablePureSelectorToken<AsJSON<T>> => {
20
16
  if (mutableAtomToken.family) {
21
17
  const target = newest(store)
22
18
  const jsonFamilyKey = `${mutableAtomToken.family.key}:JSON`
23
- const jsonFamilyToken: WritablePureSelectorFamilyToken<
24
- SerializableCore,
25
- string
26
- > = {
19
+ const jsonFamilyToken: WritablePureSelectorFamilyToken<AsJSON<T>, string> = {
27
20
  key: jsonFamilyKey,
28
21
  type: `writable_pure_selector_family`,
29
22
  }
@@ -32,7 +25,7 @@ export const getJsonToken = <
32
25
  const jsonToken = findInStore(store, family, subKey)
33
26
  return jsonToken
34
27
  }
35
- const token: WritablePureSelectorToken<SerializableCore> = {
28
+ const token: WritablePureSelectorToken<AsJSON<T>> = {
36
29
  type: `writable_pure_selector`,
37
30
  key: `${mutableAtomToken.key}:JSON`,
38
31
  }
@@ -4,20 +4,19 @@ import type { Json } from "atom.io/json"
4
4
  import type { AtomFamily } from ".."
5
5
  import { newest } from "../lineage"
6
6
  import type { Store } from "../store"
7
- import type { Signal, Transceiver } from "./transceiver"
7
+ import type { SignalFrom, Transceiver } from "./transceiver"
8
8
 
9
9
  export const getUpdateFamily = <
10
- Core extends Transceiver<Json.Serializable>,
11
- SerializableCore extends Json.Serializable,
12
- Key extends string,
10
+ T extends Transceiver<any, Json.Serializable, Json.Serializable>,
11
+ K extends string,
13
12
  >(
14
- mutableAtomFamily: MutableAtomFamilyToken<Core, SerializableCore, Key>,
13
+ mutableAtomFamily: MutableAtomFamilyToken<T, K>,
15
14
  store: Store,
16
- ): AtomFamily<Signal<Core>, Key> => {
15
+ ): AtomFamily<SignalFrom<T>, K> => {
17
16
  const target = newest(store)
18
17
  const key = `*${mutableAtomFamily.key}`
19
- const updateFamily: AtomFamily<Signal<Core>, Key> = target.families.get(
18
+ const updateFamily: AtomFamily<SignalFrom<T>, K> = target.families.get(
20
19
  key,
21
- ) as AtomFamily<Signal<Core>, Key>
20
+ ) as AtomFamily<SignalFrom<T>, K>
22
21
  return updateFamily
23
22
  }
@@ -1,16 +1,12 @@
1
1
  import type { MutableAtomToken, RegularAtomToken } from "atom.io"
2
- import type { Json } from "atom.io/json"
3
2
 
4
- import type { Signal, Transceiver } from "./transceiver"
3
+ import type { SignalFrom, Transceiver } from "./transceiver"
5
4
 
6
- export const getUpdateToken = <
7
- Core extends Transceiver<any>,
8
- SerializableCore extends Json.Serializable,
9
- >(
10
- mutableAtomToken: MutableAtomToken<Core, SerializableCore>,
11
- ): RegularAtomToken<Signal<Core>> => {
5
+ export const getUpdateToken = <T extends Transceiver<any, any, any>>(
6
+ mutableAtomToken: MutableAtomToken<T>,
7
+ ): RegularAtomToken<SignalFrom<T>> => {
12
8
  const key = `*${mutableAtomToken.key}`
13
- const updateToken: RegularAtomToken<Signal<Core>> = { type: `atom`, key }
9
+ const updateToken: RegularAtomToken<SignalFrom<T>> = { type: `atom`, key }
14
10
  if (mutableAtomToken.family) {
15
11
  updateToken.family = {
16
12
  key: `*${mutableAtomToken.family.key}`,
@@ -1,3 +1,4 @@
1
+ import type { MutableAtomToken, StateLifecycleEvent } from "atom.io"
1
2
  import type { Canonical } from "atom.io/json"
2
3
  import { parseJson } from "atom.io/json"
3
4
 
@@ -5,28 +6,19 @@ import type { MutableAtomFamily, RegularAtomFamily } from ".."
5
6
  import { createRegularAtomFamily } from "../families"
6
7
  import { type Store, withdraw } from "../store"
7
8
  import { Tracker } from "./tracker"
8
- import type { Transceiver } from "./transceiver"
9
+ import type { SignalFrom, Transceiver } from "./transceiver"
9
10
 
10
11
  export class FamilyTracker<
11
- Core extends Transceiver<any>,
12
- FamilyMemberKey extends Canonical,
12
+ T extends Transceiver<any, any, any>,
13
+ K extends Canonical,
13
14
  > {
14
- private trackers: Map<FamilyMemberKey, Tracker<Core>> = new Map()
15
+ private trackers: Map<K, Tracker<T>> = new Map()
15
16
 
16
- public readonly latestUpdateAtoms: RegularAtomFamily<
17
- (Core extends Transceiver<infer Signal> ? Signal : never) | null,
18
- FamilyMemberKey
19
- >
20
- public readonly mutableAtoms: MutableAtomFamily<Core, any, FamilyMemberKey>
17
+ public readonly latestSignalAtoms: RegularAtomFamily<SignalFrom<T> | null, K>
18
+ public readonly mutableAtoms: MutableAtomFamily<T, K>
21
19
 
22
- public constructor(
23
- mutableAtoms: MutableAtomFamily<Core, any, FamilyMemberKey>,
24
- store: Store,
25
- ) {
26
- const updateAtoms = createRegularAtomFamily<
27
- (Core extends Transceiver<infer Signal> ? Signal : never) | null,
28
- FamilyMemberKey
29
- >(
20
+ public constructor(mutableAtoms: MutableAtomFamily<T, K>, store: Store) {
21
+ const latestSignalAtoms = createRegularAtomFamily<SignalFrom<T> | null, K>(
30
22
  store,
31
23
  {
32
24
  key: `*${mutableAtoms.key}`,
@@ -34,30 +26,31 @@ export class FamilyTracker<
34
26
  },
35
27
  [`mutable`, `updates`],
36
28
  )
37
- this.latestUpdateAtoms = withdraw(store, updateAtoms)
29
+ this.latestSignalAtoms = withdraw(store, latestSignalAtoms)
38
30
  this.mutableAtoms = mutableAtoms
39
- this.mutableAtoms.subject.subscribe(
40
- `store=${store.config.name}::tracker-atom-family`,
41
- (event) => {
42
- const { type, token } = event
43
- if (token.family) {
44
- const key = parseJson(token.family.subKey)
45
- switch (type) {
46
- case `state_creation`:
47
- this.trackers.set(key, new Tracker<Core>(token, store))
48
- break
49
- case `state_disposal`:
50
- {
51
- const tracker = this.trackers.get(key)
52
- if (tracker) {
53
- tracker[Symbol.dispose]()
54
- this.trackers.delete(key)
55
- }
56
- }
57
- break
31
+ const trackerFamilyWatchesForCreationAndDisposalEvents = (
32
+ event: StateLifecycleEvent<MutableAtomToken<T>>,
33
+ ) => {
34
+ const { type, token } = event
35
+ if (token.family) {
36
+ const key = parseJson(token.family.subKey)
37
+ switch (type) {
38
+ case `state_creation`:
39
+ this.trackers.set(key, new Tracker<T>(token, store))
40
+ break
41
+ case `state_disposal`: {
42
+ const tracker = this.trackers.get(key)
43
+ if (tracker) {
44
+ tracker[Symbol.dispose]()
45
+ this.trackers.delete(key)
46
+ }
58
47
  }
59
48
  }
60
- },
49
+ }
50
+ }
51
+ this.mutableAtoms.subject.subscribe(
52
+ `store=${store.config.name}::tracker-atom-family`,
53
+ trackerFamilyWatchesForCreationAndDisposalEvents,
61
54
  )
62
55
  }
63
56
  }
@@ -1,5 +1,4 @@
1
1
  import type { FamilyMetadata, MutableAtomToken, RegularAtomToken } from "atom.io"
2
- import type { Json } from "atom.io/json"
3
2
 
4
3
  import type { Store } from ".."
5
4
  import {
@@ -11,89 +10,84 @@ import {
11
10
  } from ".."
12
11
  import { createRegularAtom } from "../atom"
13
12
  import { isChildStore } from "../transaction/is-root-store"
14
- import type { Transceiver } from "./transceiver"
13
+ import type { SignalFrom, Transceiver } from "./transceiver"
15
14
 
16
15
  /**
17
16
  * @internal Give the tracker a transceiver state and a store, and it will
18
17
  * subscribe to the transceiver's inner value. When the inner value changes,
19
18
  * the tracker will update its own state to reflect the change.
20
19
  */
21
- export class Tracker<Mutable extends Transceiver<any>> {
22
- private initializeState(
23
- mutableState: MutableAtomToken<Mutable, Json.Serializable>,
20
+ export class Tracker<T extends Transceiver<any, any, any>> {
21
+ private initializeSignalAtom(
22
+ mutableState: MutableAtomToken<T>,
24
23
  store: Store,
25
- ): RegularAtomToken<
26
- (Mutable extends Transceiver<infer Signal> ? Signal : never) | null
27
- > {
28
- const latestUpdateStateKey = `*${mutableState.key}`
29
- store.atoms.delete(latestUpdateStateKey)
30
- store.valueMap.delete(latestUpdateStateKey)
24
+ ): RegularAtomToken<SignalFrom<T> | null> {
25
+ const latestSignalStateKey = `*${mutableState.key}`
26
+ store.atoms.delete(latestSignalStateKey)
27
+ store.valueMap.delete(latestSignalStateKey)
31
28
  const familyMetaData: FamilyMetadata | undefined = mutableState.family
32
29
  ? {
33
30
  key: `*${mutableState.family.key}`,
34
31
  subKey: mutableState.family.subKey,
35
32
  }
36
33
  : undefined
37
- const latestUpdateState = createRegularAtom<
38
- (Mutable extends Transceiver<infer Signal> ? Signal : never) | null
39
- >(
34
+ const latestSignalState = createRegularAtom<SignalFrom<T> | null>(
40
35
  store,
41
36
  {
42
- key: latestUpdateStateKey,
37
+ key: latestSignalStateKey,
43
38
  default: null,
44
39
  },
45
40
  familyMetaData,
41
+ [`tracker:signal`],
46
42
  )
47
- if (store.parent?.valueMap.has(latestUpdateStateKey)) {
48
- const parentValue = store.parent.valueMap.get(latestUpdateStateKey)
49
- store.valueMap.set(latestUpdateStateKey, parentValue)
43
+ if (store.parent?.valueMap.has(latestSignalStateKey)) {
44
+ const parentValue = store.parent.valueMap.get(latestSignalStateKey)
45
+ store.valueMap.set(latestSignalStateKey, parentValue)
50
46
  }
51
47
 
52
- return latestUpdateState
48
+ return latestSignalState
53
49
  }
54
50
 
55
51
  private unsubscribeFromInnerValue!: () => void
56
52
  private unsubscribeFromState!: () => void
57
- private observeCore(
58
- mutableState: MutableAtomToken<Mutable, any>,
59
- latestUpdateState: RegularAtomToken<
60
- (Mutable extends Transceiver<infer Signal> ? Signal : never) | null
61
- >,
53
+ private captureSignalsFromCore(
54
+ mutableState: MutableAtomToken<T, any>,
55
+ latestSignalState: RegularAtomToken<SignalFrom<T> | null>,
62
56
  target: Store,
63
57
  ): void {
64
- const subscriptionKey = `tracker:${target.config.name}:${
65
- isChildStore(target) ? target.transactionMeta.update.key : `main`
66
- }:${mutableState.key}`
58
+ const stateKey = mutableState.key
59
+ const storeName = target.config.name
60
+ const storeStatus = isChildStore(target)
61
+ ? target.transactionMeta.update.key
62
+ : `main`
63
+ const subscriptionKey = `tracker:${storeName}:${storeStatus}:${stateKey}`
64
+ const trackerCapturesOutboundSignal = (update: SignalFrom<T>) => {
65
+ setIntoStore(target, latestSignalState, update)
66
+ }
67
67
  const originalInnerValue = getFromStore(target, mutableState)
68
68
  this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
69
69
  subscriptionKey,
70
- (update) => {
71
- setIntoStore(target, latestUpdateState, update)
72
- },
70
+ trackerCapturesOutboundSignal,
73
71
  )
74
72
  this.unsubscribeFromState = subscribeToState(
75
73
  target,
76
74
  mutableState,
77
75
  subscriptionKey,
78
- (update) => {
76
+ function trackerLooksForNewReference(update: SignalFrom<T>) {
79
77
  if (update.newValue !== update.oldValue) {
80
78
  this.unsubscribeFromInnerValue()
81
79
  this.unsubscribeFromInnerValue = update.newValue.subscribe(
82
80
  subscriptionKey,
83
- (transceiverUpdate) => {
84
- setIntoStore(target, latestUpdateState, transceiverUpdate)
85
- },
81
+ trackerCapturesOutboundSignal,
86
82
  )
87
83
  }
88
- },
84
+ }.bind(this),
89
85
  )
90
86
  }
91
87
 
92
- private updateCore<Core extends Transceiver<any>>(
93
- mutableState: MutableAtomToken<Core, Json.Serializable>,
94
- latestUpdateState: RegularAtomToken<
95
- (Mutable extends Transceiver<infer Signal> ? Signal : never) | null
96
- >,
88
+ private supplySignalsToCore(
89
+ mutableState: MutableAtomToken<T>,
90
+ latestSignalState: RegularAtomToken<SignalFrom<T> | null>,
97
91
  target: Store,
98
92
  ): void {
99
93
  const subscriptionKey = `tracker:${target.config.name}:${
@@ -101,87 +95,75 @@ export class Tracker<Mutable extends Transceiver<any>> {
101
95
  }:${mutableState.key}`
102
96
  subscribeToState(
103
97
  target,
104
- latestUpdateState,
98
+ latestSignalState,
105
99
  subscriptionKey,
106
- ({ newValue, oldValue }) => {
100
+ function trackerCapturesInboundSignal({ newValue, oldValue }) {
107
101
  const timelineId = target.timelineTopics.getRelatedKey(
108
- latestUpdateState.key,
102
+ latestSignalState.key,
109
103
  )
110
104
 
111
- if (timelineId) {
112
- const timelineData = target.timelines.get(timelineId)
113
- if (timelineData?.timeTraveling) {
114
- const unsubscribe = subscribeToTimeline(
115
- target,
116
- { key: timelineId, type: `timeline` },
117
- subscriptionKey,
118
- (update) => {
119
- unsubscribe()
120
- setIntoStore(target, mutableState, (transceiver) => {
121
- if (update === `redo` && newValue) {
122
- transceiver.do(newValue)
123
- } else if (update === `undo` && oldValue) {
124
- transceiver.undo(oldValue)
125
- }
126
- return transceiver
127
- })
128
- },
129
- )
130
- return
131
- }
105
+ if (timelineId && target.timelines.get(timelineId)?.timeTraveling) {
106
+ const unsubscribe = subscribeToTimeline(
107
+ target,
108
+ { key: timelineId, type: `timeline` },
109
+ subscriptionKey,
110
+ function trackerWaitsForTimeTravelToFinish(update) {
111
+ unsubscribe()
112
+ setIntoStore(target, mutableState, (transceiver) => {
113
+ if (update === `redo` && newValue) {
114
+ transceiver.do(newValue)
115
+ } else if (update === `undo` && oldValue) {
116
+ transceiver.undo(oldValue)
117
+ }
118
+ return transceiver
119
+ })
120
+ },
121
+ )
122
+ return
132
123
  }
133
124
 
134
- const unsubscribe = target.on.operationClose.subscribe(
135
- subscriptionKey,
136
- () => {
137
- unsubscribe()
138
- const mutable = getFromStore(target, mutableState)
139
- const updateNumber =
140
- newValue === null ? -1 : mutable.getUpdateNumber(newValue)
141
- const eventOffset = updateNumber - mutable.cacheUpdateNumber
142
- if (newValue && eventOffset === 1) {
143
- setIntoStore(
144
- target,
145
- mutableState,
146
- (transceiver) => (transceiver.do(newValue), transceiver),
147
- )
148
- } else {
149
- target.logger.info(
150
- `❌`,
151
- `mutable_atom`,
152
- mutableState.key,
153
- `could not be updated. Expected update number ${
154
- mutable.cacheUpdateNumber + 1
155
- }, but got ${updateNumber}`,
156
- )
157
- }
158
- },
159
- )
125
+ const mutable = getFromStore(target, mutableState)
126
+ const updateNumber = mutable.getUpdateNumber(newValue)
127
+ const eventOffset = updateNumber - mutable.cacheUpdateNumber
128
+ if (newValue && eventOffset === 1) {
129
+ setIntoStore(
130
+ target,
131
+ mutableState,
132
+ (transceiver) => (transceiver.do(newValue), transceiver),
133
+ )
134
+ } else {
135
+ const expected = mutable.cacheUpdateNumber + 1
136
+ target.logger.info(
137
+ `❌`,
138
+ `mutable_atom`,
139
+ mutableState.key,
140
+ `could not be updated. Expected update number`,
141
+ expected,
142
+ `but got`,
143
+ updateNumber,
144
+ )
145
+ }
160
146
  },
161
147
  )
162
148
  }
163
149
 
164
- public mutableState: MutableAtomToken<Mutable, Json.Serializable>
165
- public latestUpdateState: RegularAtomToken<
166
- (Mutable extends Transceiver<infer Signal> ? Signal : never) | null
167
- >
150
+ public mutableAtomToken: MutableAtomToken<T>
151
+ public latestSignalToken: RegularAtomToken<SignalFrom<T> | null>
168
152
 
169
153
  public [Symbol.dispose]!: () => void
170
154
 
171
- public constructor(
172
- mutableState: MutableAtomToken<Mutable, Json.Serializable>,
173
- store: Store,
174
- ) {
175
- this.mutableState = mutableState
155
+ public constructor(mutableAtomToken: MutableAtomToken<T>, store: Store) {
176
156
  const target = newest(store)
177
- this.latestUpdateState = this.initializeState(mutableState, target)
178
- this.observeCore(mutableState, this.latestUpdateState, target)
179
- this.updateCore(mutableState, this.latestUpdateState, target)
180
- target.trackers.set(mutableState.key, this)
157
+ const latestSignalToken = this.initializeSignalAtom(mutableAtomToken, target)
158
+ this.mutableAtomToken = mutableAtomToken
159
+ this.latestSignalToken = latestSignalToken
160
+ this.captureSignalsFromCore(mutableAtomToken, latestSignalToken, target)
161
+ this.supplySignalsToCore(mutableAtomToken, latestSignalToken, target)
162
+ target.trackers.set(mutableAtomToken.key, this)
181
163
  this[Symbol.dispose] = () => {
182
164
  this.unsubscribeFromInnerValue()
183
165
  this.unsubscribeFromState()
184
- target.trackers.delete(mutableState.key)
166
+ target.trackers.delete(mutableAtomToken.key)
185
167
  }
186
168
  }
187
169
  }