atom.io 0.12.1 → 0.14.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 (120) hide show
  1. package/dist/index.cjs +9 -74
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +9 -6
  4. package/dist/index.d.ts +9 -6
  5. package/dist/index.js +11 -74
  6. package/dist/index.js.map +1 -1
  7. package/dist/metafile-cjs.json +1 -1
  8. package/dist/metafile-esm.json +1 -1
  9. package/internal/dist/index.cjs +1700 -1579
  10. package/internal/dist/index.cjs.map +1 -1
  11. package/internal/dist/index.d.cts +32 -15
  12. package/internal/dist/index.d.ts +32 -15
  13. package/internal/dist/index.js +1695 -1579
  14. package/internal/dist/index.js.map +1 -1
  15. package/internal/dist/metafile-cjs.json +1 -1
  16. package/internal/dist/metafile-esm.json +1 -1
  17. package/internal/src/atom/create-atom.ts +7 -6
  18. package/internal/src/atom/delete-atom.ts +11 -11
  19. package/internal/src/atom/is-default.ts +5 -5
  20. package/internal/src/caching.ts +12 -10
  21. package/internal/src/families/create-atom-family.ts +3 -3
  22. package/internal/src/families/create-readonly-selector-family.ts +3 -3
  23. package/internal/src/families/create-selector-family.ts +4 -4
  24. package/internal/src/index.ts +1 -0
  25. package/internal/src/keys.ts +4 -4
  26. package/internal/src/lazy-map.ts +6 -2
  27. package/internal/src/lineage.ts +18 -0
  28. package/internal/src/mutable/create-mutable-atom.ts +8 -6
  29. package/internal/src/mutable/get-json-family.ts +3 -3
  30. package/internal/src/mutable/tracker.ts +18 -13
  31. package/internal/src/operation.ts +19 -19
  32. package/internal/src/selector/create-read-write-selector.ts +5 -4
  33. package/internal/src/selector/create-readonly-selector.ts +4 -3
  34. package/internal/src/selector/create-selector.ts +6 -6
  35. package/internal/src/selector/delete-selector.ts +10 -10
  36. package/internal/src/selector/get-selector-dependency-keys.ts +2 -2
  37. package/internal/src/selector/register-selector.ts +4 -4
  38. package/internal/src/selector/update-selector-atoms.ts +4 -4
  39. package/internal/src/set-state/copy-mutable-if-needed.ts +4 -3
  40. package/internal/src/set-state/copy-mutable-in-transaction.ts +10 -16
  41. package/internal/src/set-state/copy-mutable-into-new-store.ts +1 -1
  42. package/internal/src/set-state/evict-downstream.ts +5 -5
  43. package/internal/src/set-state/set-atom.ts +6 -1
  44. package/internal/src/set-state/stow-update.ts +7 -2
  45. package/internal/src/store/store.ts +31 -24
  46. package/internal/src/store/withdraw-new-family-member.ts +3 -4
  47. package/internal/src/store/withdraw.ts +58 -59
  48. package/internal/src/subject.ts +14 -0
  49. package/internal/src/subscribe/index.ts +3 -0
  50. package/internal/src/subscribe/recall-state.ts +5 -11
  51. package/internal/src/subscribe/subscribe-to-state.ts +47 -0
  52. package/internal/src/subscribe/subscribe-to-timeline.ts +28 -0
  53. package/internal/src/subscribe/subscribe-to-transaction.ts +33 -0
  54. package/internal/src/timeline/add-atom-to-timeline.ts +37 -27
  55. package/internal/src/timeline/create-timeline.ts +6 -8
  56. package/internal/src/timeline/time-travel.ts +22 -4
  57. package/internal/src/transaction/abort-transaction.ts +5 -3
  58. package/internal/src/transaction/apply-transaction.ts +80 -58
  59. package/internal/src/transaction/build-transaction.ts +33 -23
  60. package/internal/src/transaction/create-transaction.ts +6 -9
  61. package/internal/src/transaction/index.ts +2 -10
  62. package/internal/src/transaction/redo-transaction.ts +15 -10
  63. package/internal/src/transaction/undo-transaction.ts +15 -16
  64. package/introspection/dist/index.cjs +2 -2
  65. package/introspection/dist/index.cjs.map +1 -1
  66. package/introspection/dist/index.js +3 -3
  67. package/introspection/dist/index.js.map +1 -1
  68. package/introspection/src/attach-atom-index.ts +2 -2
  69. package/introspection/src/attach-selector-index.ts +2 -2
  70. package/package.json +8 -8
  71. package/react/dist/index.cjs +39 -1
  72. package/react/dist/index.cjs.map +1 -1
  73. package/react/dist/index.d.cts +9 -2
  74. package/react/dist/index.d.ts +9 -2
  75. package/react/dist/index.js +41 -4
  76. package/react/dist/index.js.map +1 -1
  77. package/react/dist/metafile-cjs.json +1 -1
  78. package/react/dist/metafile-esm.json +1 -1
  79. package/react/src/store-hooks.ts +52 -3
  80. package/react-devtools/dist/index.cjs +22 -8
  81. package/react-devtools/dist/index.cjs.map +1 -1
  82. package/react-devtools/dist/index.d.cts +17 -9
  83. package/react-devtools/dist/index.d.ts +17 -9
  84. package/react-devtools/dist/index.js +22 -8
  85. package/react-devtools/dist/index.js.map +1 -1
  86. package/react-devtools/dist/metafile-cjs.json +1 -1
  87. package/react-devtools/dist/metafile-esm.json +1 -1
  88. package/react-devtools/src/Updates.tsx +22 -10
  89. package/realtime-client/dist/index.cjs +8 -7
  90. package/realtime-client/dist/index.cjs.map +1 -1
  91. package/realtime-client/dist/index.d.cts +3 -2
  92. package/realtime-client/dist/index.d.ts +3 -2
  93. package/realtime-client/dist/index.js +3 -2
  94. package/realtime-client/dist/index.js.map +1 -1
  95. package/realtime-client/dist/metafile-cjs.json +1 -1
  96. package/realtime-client/dist/metafile-esm.json +1 -1
  97. package/realtime-client/src/use-push.ts +4 -4
  98. package/realtime-client/src/use-server-action.ts +4 -4
  99. package/realtime-server/dist/index.cjs +46 -25
  100. package/realtime-server/dist/index.cjs.map +1 -1
  101. package/realtime-server/dist/index.d.cts +5 -5
  102. package/realtime-server/dist/index.d.ts +5 -5
  103. package/realtime-server/dist/index.js +38 -17
  104. package/realtime-server/dist/index.js.map +1 -1
  105. package/realtime-server/dist/metafile-cjs.json +1 -1
  106. package/realtime-server/dist/metafile-esm.json +1 -1
  107. package/realtime-server/src/hook-composition/expose-family.ts +7 -3
  108. package/realtime-server/src/hook-composition/expose-mutable-family.ts +13 -5
  109. package/realtime-server/src/hook-composition/expose-mutable.ts +11 -3
  110. package/realtime-server/src/hook-composition/expose-single.ts +6 -2
  111. package/realtime-server/src/hook-composition/receive-transaction.ts +14 -5
  112. package/src/subscribe.ts +37 -91
  113. package/src/transaction.ts +7 -2
  114. package/transceivers/set-rtx/dist/index.cjs.map +1 -1
  115. package/transceivers/set-rtx/dist/index.d.cts +2 -2
  116. package/transceivers/set-rtx/dist/index.d.ts +2 -2
  117. package/transceivers/set-rtx/dist/index.js.map +1 -1
  118. package/transceivers/set-rtx/dist/metafile-cjs.json +1 -1
  119. package/transceivers/set-rtx/dist/metafile-esm.json +1 -1
  120. package/transceivers/set-rtx/src/set-rtx.ts +3 -3
@@ -1,7 +1,7 @@
1
1
  import type { ReadonlySelectorToken, StateToken } from "atom.io"
2
2
 
3
+ import { newest } from "../lineage"
3
4
  import type { Store } from "../store"
4
- import { target } from "../transaction"
5
5
  import { traceSelectorAtoms } from "./trace-selector-atoms"
6
6
 
7
7
  export const updateSelectorAtoms = (
@@ -9,9 +9,9 @@ export const updateSelectorAtoms = (
9
9
  dependency: ReadonlySelectorToken<unknown> | StateToken<unknown>,
10
10
  store: Store,
11
11
  ): void => {
12
- const core = target(store)
12
+ const target = newest(store)
13
13
  if (dependency.type === `atom`) {
14
- core.selectorAtoms = core.selectorAtoms.set({
14
+ target.selectorAtoms.set({
15
15
  selectorKey,
16
16
  atomKey: dependency.key,
17
17
  })
@@ -32,7 +32,7 @@ export const updateSelectorAtoms = (
32
32
  .join(`, `)} ]`,
33
33
  )
34
34
  for (const atomKey of rootKeys) {
35
- core.selectorAtoms = core.selectorAtoms.set({
35
+ target.selectorAtoms = target.selectorAtoms.set({
36
36
  selectorKey,
37
37
  atomKey,
38
38
  })
@@ -2,19 +2,20 @@ import type { JsonInterface } from "atom.io/json"
2
2
 
3
3
  import type { Atom } from "../atom"
4
4
  import { Tracker } from "../mutable"
5
- import type { Store, StoreCore } from "../store"
5
+ import type { Store } from "../store"
6
6
 
7
7
  export function copyMutableIfNeeded<T>(
8
8
  atom: Atom<T>,
9
9
  transform: JsonInterface<T>,
10
10
  origin: Store,
11
- target: StoreCore,
11
+ target: Store,
12
12
  ): T {
13
13
  const originValue = origin.valueMap.get(atom.key)
14
14
  const targetValue = target.valueMap.get(atom.key)
15
15
  if (originValue === targetValue) {
16
16
  origin.logger.info(`📃`, `atom`, `${atom.key}`, `copying`)
17
- const copiedValue = transform.fromJson(transform.toJson(originValue))
17
+ const jsonValue = transform.toJson(originValue)
18
+ const copiedValue = transform.fromJson(jsonValue)
18
19
  target.valueMap.set(atom.key, copiedValue)
19
20
  new Tracker(atom, origin)
20
21
  return copiedValue
@@ -1,7 +1,7 @@
1
1
  import type { AtomFamily } from "atom.io"
2
2
  import type { Json, JsonInterface } from "atom.io/json"
3
- import { readOrComputeValue } from ".."
4
- import type { Store, StoreCore } from ".."
3
+ import { newest } from ".."
4
+ import type { Store } from ".."
5
5
  import type { Atom } from "../atom"
6
6
  import { copyMutableIfNeeded } from "./copy-mutable-if-needed"
7
7
 
@@ -10,27 +10,21 @@ export function copyMutableIfWithinTransaction<T>(
10
10
  atom: Atom<T> | (Atom<T> & JsonInterface<T, Json.Serializable>),
11
11
  store: Store,
12
12
  ): T {
13
- if (
14
- store.transactionStatus.phase === `building` ||
15
- store.transactionStatus.phase === `applying`
16
- ) {
13
+ const target = newest(store)
14
+ const parent = target.parent
15
+ if (parent !== null) {
17
16
  if (`toJson` in atom && `fromJson` in atom) {
18
- const copiedValue = copyMutableIfNeeded(
19
- atom,
20
- atom,
21
- store,
22
- store.transactionStatus.core,
23
- )
17
+ const copiedValue = copyMutableIfNeeded(atom, atom, parent, target)
24
18
  return copiedValue
25
19
  }
26
20
  if (`family` in atom) {
27
- const family = store.transactionStatus.core.families.get(atom.family.key)
21
+ const family = parent.families.get(atom.family.key)
28
22
  if (family && family.type === `atom_family`) {
29
23
  const result = copyMutableFamilyMemberWithinTransaction<T>(
30
24
  atom,
31
25
  family,
32
- store,
33
- store.transactionStatus.core,
26
+ parent,
27
+ target,
34
28
  )
35
29
  if (result) {
36
30
  return result
@@ -47,7 +41,7 @@ export function copyMutableFamilyMemberWithinTransaction<T>(
47
41
  | AtomFamily<T, any>
48
42
  | (AtomFamily<T, any> & JsonInterface<T, Json.Serializable>),
49
43
  origin: Store,
50
- target: StoreCore,
44
+ target: Store,
51
45
  ): T | null {
52
46
  if (`toJson` in family && `fromJson` in family) {
53
47
  const copyCreated = copyMutableIfNeeded(atom, family, origin, target)
@@ -1,6 +1,6 @@
1
1
  import type { AtomFamily } from "atom.io"
2
2
  import type { Json, JsonInterface } from "atom.io/json"
3
- import type { Store, StoreCore } from ".."
3
+ import type { Store } from ".."
4
4
  import type { Atom } from "../atom"
5
5
  import { copyMutableIfNeeded } from "./copy-mutable-if-needed"
6
6
 
@@ -1,12 +1,12 @@
1
1
  import type { Atom } from "../atom"
2
2
  import { evictCachedValue } from "../caching"
3
+ import { newest } from "../lineage"
3
4
  import { isDone, markDone } from "../operation"
4
5
  import type { Store } from "../store"
5
- import { target } from "../transaction"
6
6
 
7
7
  export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
8
- const core = target(store)
9
- const downstreamKeys = core.selectorAtoms.getRelatedKeys(atom.key)
8
+ const target = newest(store)
9
+ const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key)
10
10
  store.logger.info(
11
11
  `🧹`,
12
12
  atom.type,
@@ -17,12 +17,12 @@ export const evictDownStream = <T>(atom: Atom<T>, store: Store): void => {
17
17
  downstreamKeys ?? `to evict`,
18
18
  )
19
19
  if (downstreamKeys) {
20
- if (core.operation.open) {
20
+ if (target.operation.open) {
21
21
  store.logger.info(
22
22
  `🧹`,
23
23
  atom.type,
24
24
  atom.key,
25
- `[ ${[...core.operation.done].join(`, `)} ] already done`,
25
+ `[ ${[...target.operation.done].join(`, `)} ] already done`,
26
26
  )
27
27
  }
28
28
  for (const key of downstreamKeys) {
@@ -1,6 +1,7 @@
1
1
  import type { Atom } from "../atom"
2
2
  import { isAtomDefault, markAtomAsNotDefault } from "../atom"
3
3
  import { cacheValue } from "../caching"
4
+ import { newest } from "../lineage"
4
5
  import { markDone } from "../operation"
5
6
  import { readOrComputeValue } from "../read-or-compute-value"
6
7
  import type { Store } from "../store"
@@ -15,6 +16,7 @@ export const setAtom = <T>(
15
16
  next: T | ((oldValue: T) => T),
16
17
  store: Store,
17
18
  ): void => {
19
+ const target = newest(store)
18
20
  const oldValue = readOrComputeValue(atom, store)
19
21
  let newValue = copyMutableIfWithinTransaction(oldValue, atom, store)
20
22
  newValue = become(next)(newValue)
@@ -26,7 +28,10 @@ export const setAtom = <T>(
26
28
  markDone(atom.key, store)
27
29
  evictDownStream(atom, store)
28
30
  const update = { oldValue, newValue }
29
- if (store.transactionStatus.phase !== `building`) {
31
+ if (
32
+ target.transactionMeta === null ||
33
+ target.transactionMeta.phase === `applying`
34
+ ) {
30
35
  emitUpdate(atom, update, store)
31
36
  } else {
32
37
  stowUpdate(atom, update, store)
@@ -1,6 +1,7 @@
1
1
  import type { KeyedStateUpdate, StateUpdate } from "atom.io"
2
2
 
3
3
  import type { Atom } from "../atom"
4
+ import { newest } from "../lineage"
4
5
  import { isTransceiver } from "../mutable"
5
6
  import type { Store } from "../store"
6
7
 
@@ -22,7 +23,11 @@ export const stowUpdate = <T>(
22
23
  store: Store,
23
24
  ): void => {
24
25
  const { key } = state
25
- if (store.transactionStatus.phase !== `building`) {
26
+ const target = newest(store)
27
+ if (
28
+ target.transactionMeta === null ||
29
+ target.transactionMeta.phase !== `building`
30
+ ) {
26
31
  store.logger.error(
27
32
  `🐞`,
28
33
  `atom`,
@@ -39,7 +44,7 @@ export const stowUpdate = <T>(
39
44
  if (state.family) {
40
45
  atomUpdate.family = state.family
41
46
  }
42
- store.transactionStatus.atomUpdates.push(atomUpdate)
47
+ target.transactionMeta.update.updates.push(atomUpdate)
43
48
  store.logger.info(
44
49
  `📁`,
45
50
  `atom`,
@@ -1,4 +1,4 @@
1
- import { AtomIOLogger, simpleLogger } from "atom.io"
1
+ import { AtomIOLogger } from "atom.io"
2
2
  import type {
3
3
  AtomFamily,
4
4
  AtomToken,
@@ -15,31 +15,35 @@ import type {
15
15
  import { Junction } from "~/packages/rel8/junction/src"
16
16
 
17
17
  import type { Atom } from "../atom"
18
+ import type { Lineage } from "../lineage"
18
19
  import type { MutableAtom, Tracker, Transceiver } from "../mutable"
19
20
  import type { OperationProgress } from "../operation"
20
21
  import type { ReadonlySelector, Selector } from "../selector"
21
- import { Subject } from "../subject"
22
+ import { StatefulSubject, Subject } from "../subject"
22
23
  import type { Timeline } from "../timeline"
23
- import type { Transaction, TransactionStatus } from "../transaction"
24
-
25
- export type StoreCore = Pick<
26
- Store,
27
- | `atoms`
28
- | `atomsThatAreDefault`
29
- | `families`
30
- | `operation`
31
- | `readonlySelectors`
32
- | `selectorAtoms`
33
- | `selectorGraph`
34
- | `selectors`
35
- | `timelineAtoms`
36
- | `timelines`
37
- | `trackers`
38
- | `transactions`
39
- | `valueMap`
40
- >
41
-
42
- export class Store {
24
+ import type { Transaction, TransactionMeta } from "../transaction"
25
+
26
+ // export type StoreCore = Pick<
27
+ // Store,
28
+ // | `atoms`
29
+ // | `atomsThatAreDefault`
30
+ // | `families`
31
+ // | `operation`
32
+ // | `readonlySelectors`
33
+ // | `selectorAtoms`
34
+ // | `selectorGraph`
35
+ // | `selectors`
36
+ // | `timelineAtoms`
37
+ // | `timelines`
38
+ // | `trackers`
39
+ // | `transactions`
40
+ // | `valueMap`
41
+ // >
42
+
43
+ export class Store implements Lineage {
44
+ public parent: Store | null = null
45
+ public child: Store | null = null
46
+
43
47
  public valueMap = new Map<string, any>()
44
48
 
45
49
  public atoms = new Map<string, Atom<any> | MutableAtom<any>>()
@@ -88,10 +92,11 @@ export class Store {
88
92
  >(),
89
93
  transactionCreation: new Subject<TransactionToken<ƒn>>(),
90
94
  timelineCreation: new Subject<TimelineToken>(),
95
+ transactionApplying: new StatefulSubject<TransactionMeta<ƒn> | null>(null),
91
96
  operationStatus: new Subject<OperationProgress>(),
92
97
  }
93
98
  public operation: OperationProgress = { open: false }
94
- public transactionStatus: TransactionStatus<ƒn> = { phase: `idle` }
99
+ public transactionMeta: TransactionMeta<ƒn> | null = null
95
100
 
96
101
  public config: {
97
102
  name: string
@@ -118,7 +123,9 @@ export class Store {
118
123
  if (store !== null) {
119
124
  this.valueMap = new Map(store?.valueMap)
120
125
  this.operation = { ...store?.operation }
121
- this.transactionStatus = { ...store?.transactionStatus }
126
+ this.transactionMeta = store?.transactionMeta
127
+ ? { ...store?.transactionMeta }
128
+ : null
122
129
  this.config = {
123
130
  ...store?.config,
124
131
  name,
@@ -5,8 +5,7 @@ import type {
5
5
  StateToken,
6
6
  } from "atom.io"
7
7
  import type { Atom, ReadonlySelector, Selector, Store } from ".."
8
- import { withdraw } from ".."
9
- import { target } from "../transaction"
8
+ import { newest, withdraw } from ".."
10
9
 
11
10
  export function withdrawNewFamilyMember<T>(
12
11
  token: AtomToken<T>,
@@ -43,8 +42,8 @@ export function withdrawNewFamilyMember<T>(
43
42
  token.key,
44
43
  `creating new family member in store "${store.config.name}"`,
45
44
  )
46
- const core = target(store)
47
- const family = core.families.get(token.family.key)
45
+ const target = newest(store)
46
+ const family = target.families.get(token.family.key)
48
47
  if (family) {
49
48
  const jsonSubKey = JSON.parse(token.family.subKey)
50
49
  family(jsonSubKey)
@@ -9,11 +9,10 @@ import type {
9
9
  } from "atom.io"
10
10
 
11
11
  import type { Atom } from "../atom"
12
+ import { newest } from "../lineage"
12
13
  import type { ReadonlySelector, Selector } from "../selector"
13
- import { addAtomToTimeline } from "../timeline"
14
14
  import type { Timeline } from "../timeline"
15
15
  import type { Transaction } from "../transaction"
16
- import { target } from "../transaction"
17
16
  import type { Store } from "./store"
18
17
 
19
18
  export function withdraw<T>(
@@ -58,67 +57,67 @@ export function withdraw<T>(
58
57
  | Timeline
59
58
  | Transaction<T extends ƒn ? T : never>
60
59
  | undefined {
61
- let core = target(store)
62
- let state =
63
- core.atoms.get(token.key) ??
64
- core.selectors.get(token.key) ??
65
- core.readonlySelectors.get(token.key) ??
66
- core.transactions.get(token.key) ??
67
- core.timelines.get(token.key)
60
+ const target = newest(store)
61
+ const state =
62
+ target.atoms.get(token.key) ??
63
+ target.selectors.get(token.key) ??
64
+ target.readonlySelectors.get(token.key) ??
65
+ target.transactions.get(token.key) ??
66
+ target.timelines.get(token.key)
68
67
  if (state) {
69
68
  return state
70
69
  }
71
- if (store.transactionStatus.phase === `applying`) {
72
- core = store.transactionStatus.core
73
- state =
74
- core.atoms.get(token.key) ??
75
- core.selectors.get(token.key) ??
76
- core.readonlySelectors.get(token.key) ??
77
- core.transactions.get(token.key) ??
78
- core.timelines.get(token.key)
70
+ // if (target.transactionMeta?.phase === `applying`) {
79
71
 
80
- if (state) {
81
- store.logger.info(
82
- `🛠️`,
83
- token.type,
84
- token.key,
85
- `add ${token.type} "${token.key}"`,
86
- )
87
- switch (state.type) {
88
- case `atom`: {
89
- store.atoms.set(token.key, state)
90
- store.valueMap.set(token.key, state.default)
91
- const stateKey = state.key
92
- const familyKey = state.family?.key
93
- let timelineKey = core.timelineAtoms.getRelatedKey(stateKey)
94
- if (timelineKey === undefined && typeof familyKey === `string`) {
95
- timelineKey = core.timelineAtoms.getRelatedKey(familyKey)
96
- }
97
- const timeline =
98
- typeof timelineKey === `string`
99
- ? store.timelines.get(timelineKey)
100
- : undefined
72
+ // state =
73
+ // target.atoms.get(token.key) ??
74
+ // core.selectors.get(token.key) ??
75
+ // core.readonlySelectors.get(token.key) ??
76
+ // core.transactions.get(token.key) ??
77
+ // core.timelines.get(token.key)
101
78
 
102
- if (timeline) {
103
- addAtomToTimeline(state, timeline, store)
104
- }
105
- break
106
- }
107
- case `selector`:
108
- core.selectors.set(token.key, state)
109
- break
110
- case `readonly_selector`:
111
- core.readonlySelectors.set(token.key, state)
112
- break
113
- case `transaction`:
114
- core.transactions.set(token.key, state)
115
- break
116
- case `timeline`:
117
- core.timelines.set(token.key, state)
118
- break
119
- }
120
- return state
121
- }
122
- }
79
+ // if (state) {
80
+ // store.logger.info(
81
+ // `🛠️`,
82
+ // token.type,
83
+ // token.key,
84
+ // `add ${token.type} "${token.key}"`,
85
+ // )
86
+ // switch (state.type) {
87
+ // case `atom`: {
88
+ // store.atoms.set(token.key, state)
89
+ // store.valueMap.set(token.key, state.default)
90
+ // const stateKey = state.key
91
+ // const familyKey = state.family?.key
92
+ // let timelineKey = core.timelineAtoms.getRelatedKey(stateKey)
93
+ // if (timelineKey === undefined && typeof familyKey === `string`) {
94
+ // timelineKey = core.timelineAtoms.getRelatedKey(familyKey)
95
+ // }
96
+ // const timeline =
97
+ // typeof timelineKey === `string`
98
+ // ? store.timelines.get(timelineKey)
99
+ // : undefined
100
+
101
+ // if (timeline) {
102
+ // addAtomToTimeline(state, timeline, store)
103
+ // }
104
+ // break
105
+ // }
106
+ // case `selector`:
107
+ // core.selectors.set(token.key, state)
108
+ // break
109
+ // case `readonly_selector`:
110
+ // core.readonlySelectors.set(token.key, state)
111
+ // break
112
+ // case `transaction`:
113
+ // core.transactions.set(token.key, state)
114
+ // break
115
+ // case `timeline`:
116
+ // core.timelines.set(token.key, state)
117
+ // break
118
+ // }
119
+ // return state
120
+ // }
121
+ // }
123
122
  return undefined
124
123
  }
@@ -19,3 +19,17 @@ export class Subject<T> {
19
19
  }
20
20
  }
21
21
  }
22
+
23
+ export class StatefulSubject<T> extends Subject<T> {
24
+ public state: T
25
+
26
+ public constructor(initialState: T) {
27
+ super()
28
+ this.state = initialState
29
+ }
30
+
31
+ public next(value: T): void {
32
+ this.state = value
33
+ super.next(value)
34
+ }
35
+ }
@@ -1 +1,4 @@
1
1
  export * from "./subscribe-to-root-atoms"
2
+ export * from "./subscribe-to-state"
3
+ export * from "./subscribe-to-timeline"
4
+ export * from "./subscribe-to-transaction"
@@ -1,21 +1,15 @@
1
1
  import type { Atom } from "../atom"
2
+ import { newest } from "../lineage"
2
3
  import type { ReadonlySelector, Selector } from "../selector"
3
4
  import type { Store } from "../store"
4
- import { target } from "../transaction"
5
5
 
6
6
  export const recallState = <T>(
7
7
  state: Atom<T> | ReadonlySelector<T> | Selector<T>,
8
8
  store: Store,
9
9
  ): T => {
10
- const core = target(store)
11
- if (!core.operation.open) {
12
- store.logger.warn(
13
- `🐞`,
14
- state.type,
15
- state.key,
16
- `recall called outside of an operation. This is probably a bug.`,
17
- )
18
- return core.valueMap.get(state.key)
10
+ const target = newest(store)
11
+ if (!target.operation.open) {
12
+ return target.valueMap.get(state.key)
19
13
  }
20
- return core.operation.prev.get(state.key)
14
+ return target.operation.prev.get(state.key)
21
15
  }
@@ -0,0 +1,47 @@
1
+ import type { ReadonlySelectorToken, StateToken, UpdateHandler } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { subscribeToRootAtoms, withdraw } from "atom.io/internal"
4
+
5
+ export function subscribeToState<T>(
6
+ token: ReadonlySelectorToken<T> | StateToken<T>,
7
+ handleUpdate: UpdateHandler<T>,
8
+ key: string,
9
+ store: Store,
10
+ ): () => void {
11
+ const state = withdraw<T>(token, store)
12
+ if (state === undefined) {
13
+ throw new Error(
14
+ `State "${token.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
15
+ )
16
+ }
17
+ const unsubFunction = state.subject.subscribe(key, handleUpdate)
18
+ store.logger.info(`👀`, state.type, state.key, `Adding subscription "${key}"`)
19
+ const dependencyUnsubFunctions =
20
+ state.type !== `atom` ? subscribeToRootAtoms(state, store) : null
21
+
22
+ const unsubscribe =
23
+ dependencyUnsubFunctions === null
24
+ ? () => {
25
+ store.logger.info(
26
+ `🙈`,
27
+ state.type,
28
+ state.key,
29
+ `Removing subscription "${key}"`,
30
+ )
31
+ unsubFunction()
32
+ }
33
+ : () => {
34
+ store.logger.info(
35
+ `🙈`,
36
+ state.type,
37
+ state.key,
38
+ `Removing subscription "${key}"`,
39
+ )
40
+ unsubFunction()
41
+ for (const unsubFromDependency of dependencyUnsubFunctions) {
42
+ unsubFromDependency()
43
+ }
44
+ }
45
+
46
+ return unsubscribe
47
+ }
@@ -0,0 +1,28 @@
1
+ import type { TimelineToken, TimelineUpdate } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { withdraw } from "atom.io/internal"
4
+
5
+ export const subscribeToTimeline = (
6
+ token: TimelineToken,
7
+ handleUpdate: (update: TimelineUpdate | `redo` | `undo`) => void,
8
+ key: string,
9
+ store: Store,
10
+ ): (() => void) => {
11
+ const tl = withdraw(token, store)
12
+ if (tl === undefined) {
13
+ throw new Error(
14
+ `Cannot subscribe to timeline "${token.key}": timeline not found in store "${store.config.name}".`,
15
+ )
16
+ }
17
+ store.logger.info(`👀`, `timeline`, token.key, `Adding subscription "${key}"`)
18
+ const unsubscribe = tl.subject.subscribe(key, handleUpdate)
19
+ return () => {
20
+ store.logger.info(
21
+ `🙈`,
22
+ `timeline`,
23
+ token.key,
24
+ `Removing subscription "${key}" from timeline`,
25
+ )
26
+ unsubscribe()
27
+ }
28
+ }
@@ -0,0 +1,33 @@
1
+ import type { TransactionToken, TransactionUpdateHandler, ƒn } from "atom.io"
2
+ import type { Store } from "atom.io/internal"
3
+ import { withdraw } from "atom.io/internal"
4
+
5
+ export const subscribeToTransaction = <ƒ extends ƒn>(
6
+ token: TransactionToken<ƒ>,
7
+ handleUpdate: TransactionUpdateHandler<ƒ>,
8
+ key: string,
9
+ store: Store,
10
+ ): (() => void) => {
11
+ const tx = withdraw(token, store)
12
+ if (tx === undefined) {
13
+ throw new Error(
14
+ `Cannot subscribe to transaction "${token.key}": transaction not found in store "${store.config.name}".`,
15
+ )
16
+ }
17
+ store.logger.info(
18
+ `👀`,
19
+ `transaction`,
20
+ token.key,
21
+ `Adding subscription "${key}"`,
22
+ )
23
+ const unsubscribe = tx.subject.subscribe(key, handleUpdate)
24
+ return () => {
25
+ store.logger.info(
26
+ `🙈`,
27
+ `transaction`,
28
+ token.key,
29
+ `Removing subscription "${key}"`,
30
+ )
31
+ unsubscribe()
32
+ }
33
+ }