atom.io 0.2.0 → 0.3.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.
@@ -1,14 +1,58 @@
1
- import type { Atom, ReadonlySelector, Selector } from "."
2
- import { getState__INTERNAL, withdraw } from "./get"
3
- import { recallState } from "./operation"
4
- import { traceAllSelectorAtoms } from "./selector-internal"
5
- import type { Store } from "./store"
6
- import { IMPLICIT } from "./store"
7
- import { __INTERNAL__ } from ".."
1
+ import {
2
+ getState__INTERNAL,
3
+ withdraw,
4
+ recallState,
5
+ traceAllSelectorAtoms,
6
+ } from "."
7
+ import type { Atom, ReadonlySelector, Selector, Store } from "."
8
+ import type { StateUpdate } from ".."
8
9
 
9
- export const subscribeToRootAtoms = <T>(
10
+ export const prepareUpdate = <T>(
10
11
  state: Atom<T> | ReadonlySelector<T> | Selector<T>,
11
- store: Store = IMPLICIT.STORE
12
+ store: Store
13
+ ): StateUpdate<T> => {
14
+ const oldValue = recallState(state, store)
15
+ const newValue = getState__INTERNAL(state, store)
16
+ return { newValue, oldValue }
17
+ }
18
+
19
+ export const stowUpdate = <T>(
20
+ state: Atom<T>,
21
+ update: StateUpdate<T>,
22
+ store: Store
23
+ ): void => {
24
+ const { key } = state
25
+ const { logger } = store.config
26
+ if (store.transactionStatus.phase !== `building`) {
27
+ store.config.logger?.warn(
28
+ `stowUpdate called outside of a transaction. This is probably a bug.`
29
+ )
30
+ return
31
+ }
32
+ store.transactionStatus.atomUpdates.push({ key, ...update })
33
+ logger?.info(`📝 ${key} stowed (`, update.oldValue, `->`, update.newValue, `)`)
34
+ }
35
+
36
+ export const emitUpdate = <T>(
37
+ state: Atom<T> | ReadonlySelector<T> | Selector<T>,
38
+ update: StateUpdate<T>,
39
+ store: Store
40
+ ): void => {
41
+ const { key } = state
42
+ const { logger } = store.config
43
+ logger?.info(
44
+ `📢 ${state.type} "${key}" went (`,
45
+ update.oldValue,
46
+ `->`,
47
+ update.newValue,
48
+ `)`
49
+ )
50
+ state.subject.next(update)
51
+ }
52
+
53
+ export const subscribeToRootAtoms = <T>(
54
+ state: ReadonlySelector<T> | Selector<T>,
55
+ store: Store
12
56
  ): { unsubscribe: () => void }[] | null => {
13
57
  const dependencySubscriptions =
14
58
  `default` in state
@@ -17,11 +61,11 @@ export const subscribeToRootAtoms = <T>(
17
61
  const atom = withdraw(atomToken, store)
18
62
  return atom.subject.subscribe((atomChange) => {
19
63
  store.config.logger?.info(
20
- `📢 atom changed: "${atomToken.key}" (`,
64
+ `📢 selector "${state.key}" saw root "${atomToken.key}" go (`,
21
65
  atomChange.oldValue,
22
66
  `->`,
23
67
  atomChange.newValue,
24
- `) re-evaluating "${state.key}"`
68
+ `)`
25
69
  )
26
70
  const oldValue = recallState(state, store)
27
71
  const newValue = getState__INTERNAL(state, store)
@@ -0,0 +1,293 @@
1
+ /* eslint-disable max-lines */
2
+
3
+ import HAMT from "hamt_plus"
4
+
5
+ import type { KeyedStateUpdate, TransactionUpdate, Store } from "."
6
+ import { target, IMPLICIT, withdraw } from "."
7
+ import { setState } from ".."
8
+ import type { AtomToken, TimelineOptions, TimelineToken, ƒn } from ".."
9
+
10
+ export type Timeline = {
11
+ key: string
12
+ type: `timeline`
13
+ next: () => void
14
+ prev: () => void
15
+ }
16
+
17
+ export type TimelineAtomUpdate = KeyedStateUpdate<unknown> & {
18
+ type: `atom_update`
19
+ }
20
+ export type TimelineSelectorUpdate = {
21
+ key: string
22
+ type: `selector_update`
23
+ atomUpdates: TimelineAtomUpdate[]
24
+ }
25
+ export type TimelineTransactionUpdate = TransactionUpdate<ƒn> & {
26
+ type: `transaction_update`
27
+ }
28
+
29
+ export type TimelineData = {
30
+ at: number
31
+ timeTraveling: boolean
32
+ history: (
33
+ | TimelineAtomUpdate
34
+ | TimelineSelectorUpdate
35
+ | TimelineTransactionUpdate
36
+ )[]
37
+ }
38
+
39
+ export function timeline__INTERNAL(
40
+ options: TimelineOptions,
41
+ store: Store = IMPLICIT.STORE
42
+ ): TimelineToken {
43
+ let incompleteSelectorTime: number | null = null
44
+ // let selectorAtomUpdates: TimelineAtomUpdate[] = []
45
+ let incompleteTransactionKey: string | null = null
46
+ const timelineData: TimelineData = {
47
+ at: 0,
48
+ timeTraveling: false,
49
+ history: [],
50
+ }
51
+
52
+ const subscribeToAtom = (token: AtomToken<any>) => {
53
+ const state = withdraw(token, store)
54
+ state.subject.subscribe((update) => {
55
+ const storeCurrentSelectorKey =
56
+ store.operation.open && store.operation.token.type === `selector`
57
+ ? store.operation.token.key
58
+ : null
59
+ const storeCurrentSelectorTime =
60
+ store.operation.open && store.operation.token.type === `selector`
61
+ ? store.operation.time
62
+ : null
63
+
64
+ const storeCurrentTransactionKey =
65
+ store.transactionStatus.phase === `applying`
66
+ ? store.transactionStatus.key
67
+ : null
68
+ store.config.logger?.info(
69
+ `⏳ timeline "${options.key}" saw atom "${token.key}" go (`,
70
+ update.oldValue,
71
+ `->`,
72
+ update.newValue,
73
+ storeCurrentTransactionKey
74
+ ? `) in "${storeCurrentTransactionKey}"`
75
+ : `) independently`
76
+ )
77
+
78
+ if (
79
+ storeCurrentTransactionKey &&
80
+ store.transactionStatus.phase === `applying`
81
+ ) {
82
+ const currentTransaction = withdraw(
83
+ { key: storeCurrentTransactionKey, type: `transaction` },
84
+ store
85
+ )
86
+ if (incompleteTransactionKey !== storeCurrentTransactionKey) {
87
+ if (incompleteTransactionKey) {
88
+ store.config.logger?.error(
89
+ `Timeline "${options.key}" was unable to resolve transaction "${incompleteTransactionKey}. This is probably a bug.`
90
+ )
91
+ }
92
+ incompleteTransactionKey = storeCurrentTransactionKey
93
+ const subscription = currentTransaction.subject.subscribe((update) => {
94
+ if (timelineData.timeTraveling === false) {
95
+ if (timelineData.at !== timelineData.history.length) {
96
+ timelineData.history.splice(timelineData.at)
97
+ }
98
+ timelineData.history.push({
99
+ type: `transaction_update`,
100
+ ...update,
101
+ atomUpdates: update.atomUpdates.filter((atomUpdate) =>
102
+ options.atoms.some((atom) => atom.key === atomUpdate.key)
103
+ ),
104
+ })
105
+ }
106
+ timelineData.at = timelineData.history.length
107
+ subscription.unsubscribe()
108
+ incompleteTransactionKey = null
109
+ store.config.logger?.info(
110
+ `⌛ timeline "${options.key}" got a transaction_update "${update.key}"`
111
+ )
112
+ })
113
+ }
114
+ } else if (storeCurrentSelectorKey) {
115
+ if (timelineData.timeTraveling === false) {
116
+ if (storeCurrentSelectorTime !== incompleteSelectorTime) {
117
+ const newSelectorUpdate: TimelineSelectorUpdate = {
118
+ type: `selector_update`,
119
+ key: storeCurrentSelectorKey,
120
+ atomUpdates: [],
121
+ }
122
+ newSelectorUpdate.atomUpdates.push({
123
+ key: token.key,
124
+ type: `atom_update`,
125
+ ...update,
126
+ })
127
+ if (timelineData.at !== timelineData.history.length) {
128
+ timelineData.history.splice(timelineData.at)
129
+ }
130
+ timelineData.history.push(newSelectorUpdate)
131
+
132
+ store.config.logger?.info(
133
+ `⌛ timeline "${options.key}" got a selector_update "${storeCurrentSelectorKey}" with`,
134
+ newSelectorUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key)
135
+ )
136
+ timelineData.at = timelineData.history.length
137
+ incompleteSelectorTime = storeCurrentSelectorTime
138
+ } else {
139
+ const latestUpdate = timelineData.history.at(-1)
140
+ if (latestUpdate?.type === `selector_update`) {
141
+ latestUpdate.atomUpdates.push({
142
+ key: token.key,
143
+ type: `atom_update`,
144
+ ...update,
145
+ })
146
+ store.config.logger?.info(
147
+ ` ⌛ timeline "${options.key}" set selector_update "${storeCurrentSelectorKey}" to`,
148
+ latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key)
149
+ )
150
+ }
151
+ }
152
+ }
153
+ } else {
154
+ if (timelineData.timeTraveling === false) {
155
+ incompleteSelectorTime = null
156
+ if (timelineData.at !== timelineData.history.length) {
157
+ timelineData.history.splice(timelineData.at)
158
+ }
159
+ timelineData.history.push({
160
+ type: `atom_update`,
161
+ key: token.key,
162
+ oldValue: update.oldValue,
163
+ newValue: update.newValue,
164
+ })
165
+ store.config.logger?.info(
166
+ `⌛ timeline "${options.key}" got a state_update to "${token.key}"`
167
+ )
168
+ timelineData.at = timelineData.history.length
169
+ }
170
+ }
171
+ })
172
+ }
173
+ const core = target(store)
174
+ for (const tokenOrFamily of options.atoms) {
175
+ const timelineKey = core.timelineAtoms.getRelatedId(tokenOrFamily.key)
176
+ if (timelineKey) {
177
+ store.config.logger?.error(
178
+ `❌ Failed to add atom "${tokenOrFamily.key}" to timeline "${options.key}" because it belongs to timeline "${timelineKey}"`
179
+ )
180
+ continue
181
+ }
182
+ if (tokenOrFamily.type === `atom_family`) {
183
+ const family = tokenOrFamily
184
+ family.subject.subscribe((token) => subscribeToAtom(token))
185
+ } else {
186
+ const token = tokenOrFamily
187
+ if (`family` in token && token.family) {
188
+ const familyTimelineKey = core.timelineAtoms.getRelatedId(
189
+ token.family.key
190
+ )
191
+ if (familyTimelineKey) {
192
+ store.config.logger?.error(
193
+ `❌ Failed to add atom "${token.key}" to timeline "${options.key}" because its family "${token.family.key}" belongs to timeline "${familyTimelineKey}"`
194
+ )
195
+ continue
196
+ }
197
+ }
198
+ subscribeToAtom(token)
199
+ }
200
+ core.timelineAtoms = core.timelineAtoms.set(tokenOrFamily.key, options.key)
201
+ }
202
+
203
+ store.timelineStore = HAMT.set(options.key, timelineData, store.timelineStore)
204
+ return {
205
+ key: options.key,
206
+ type: `timeline`,
207
+ }
208
+ }
209
+
210
+ export const redo__INTERNAL = (
211
+ token: TimelineToken,
212
+ store: Store = IMPLICIT.STORE
213
+ ): void => {
214
+ store.config.logger?.info(`⏩ redo "${token.key}"`)
215
+ const timelineData = store.timelineStore.get(token.key)
216
+ if (!timelineData) {
217
+ store.config.logger?.error(
218
+ `Failed to redo on timeline "${token.key}". This timeline has not been initialized.`
219
+ )
220
+ return
221
+ }
222
+ if (timelineData.at === timelineData.history.length) {
223
+ store.config.logger?.warn(
224
+ `Failed to redo at the end of timeline "${token.key}". There is nothing to redo.`
225
+ )
226
+ return
227
+ }
228
+ timelineData.timeTraveling = true
229
+ const update = timelineData.history[timelineData.at]
230
+ switch (update.type) {
231
+ case `atom_update`: {
232
+ const { key, newValue } = update
233
+ setState({ key, type: `atom` }, newValue)
234
+ break
235
+ }
236
+ case `selector_update`:
237
+ case `transaction_update`: {
238
+ for (const atomUpdate of update.atomUpdates) {
239
+ const { key, newValue } = atomUpdate
240
+ setState({ key, type: `atom` }, newValue)
241
+ }
242
+ break
243
+ }
244
+ }
245
+ ++timelineData.at
246
+ timelineData.timeTraveling = false
247
+ store.config.logger?.info(
248
+ `⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
249
+ )
250
+ }
251
+
252
+ export const undo__INTERNAL = (
253
+ token: TimelineToken,
254
+ store: Store = IMPLICIT.STORE
255
+ ): void => {
256
+ store.config.logger?.info(`⏪ undo "${token.key}"`)
257
+ const timelineData = store.timelineStore.get(token.key)
258
+ if (!timelineData) {
259
+ store.config.logger?.error(
260
+ `Failed to undo on timeline "${token.key}". This timeline has not been initialized.`
261
+ )
262
+ return
263
+ }
264
+ if (timelineData.at === 0) {
265
+ store.config.logger?.warn(
266
+ `Failed to undo at the beginning of timeline "${token.key}". There is nothing to undo.`
267
+ )
268
+ return
269
+ }
270
+ timelineData.timeTraveling = true
271
+
272
+ --timelineData.at
273
+ const update = timelineData.history[timelineData.at]
274
+ switch (update.type) {
275
+ case `atom_update`: {
276
+ const { key, oldValue } = update
277
+ setState({ key, type: `atom` }, oldValue)
278
+ break
279
+ }
280
+ case `selector_update`:
281
+ case `transaction_update`: {
282
+ for (const atomUpdate of update.atomUpdates) {
283
+ const { key, oldValue } = atomUpdate
284
+ setState({ key, type: `atom` }, oldValue)
285
+ }
286
+ break
287
+ }
288
+ }
289
+ timelineData.timeTraveling = false
290
+ store.config.logger?.info(
291
+ `⏹️ "${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
292
+ )
293
+ }
@@ -1,34 +1,175 @@
1
- import type { Store } from "./store"
1
+ import HAMT from "hamt_plus"
2
+ import * as Rx from "rxjs"
2
3
 
3
- export const finishTransaction = (store: Store): void => {
4
- store.transaction = { open: false }
5
- store.config.logger?.info(`🛬`, `transaction done`)
4
+ import type { Store, StoreCore } from "."
5
+ import { deposit, withdraw, IMPLICIT } from "."
6
+ import { getState, setState } from ".."
7
+ import type {
8
+ AtomToken,
9
+ StateUpdate,
10
+ Transaction,
11
+ TransactionOptions,
12
+ TransactionToken,
13
+ ƒn,
14
+ } from ".."
15
+
16
+ export const TRANSACTION_PHASES = [`idle`, `building`, `applying`] as const
17
+ export type TransactionPhase = (typeof TRANSACTION_PHASES)[number]
18
+
19
+ export type KeyedStateUpdate<T> = StateUpdate<T> & {
20
+ key: string
21
+ }
22
+ export type TransactionUpdate<ƒ extends ƒn> = {
23
+ key: string
24
+ atomUpdates: KeyedStateUpdate<unknown>[]
25
+ params: Parameters<ƒ>
26
+ output: ReturnType<ƒ>
27
+ }
28
+
29
+ export type TransactionUpdateInProgress<ƒ extends ƒn> = TransactionUpdate<ƒ> & {
30
+ phase: `applying` | `building`
31
+ core: StoreCore
32
+ }
33
+ export type TransactionIdle = {
34
+ phase: `idle`
6
35
  }
7
- export const startTransaction = (store: Store): void => {
8
- store.transaction = {
9
- open: true,
10
- prev: {
36
+ export type TransactionStatus<ƒ extends ƒn> =
37
+ | TransactionIdle
38
+ | TransactionUpdateInProgress<ƒ>
39
+
40
+ export const buildTransaction = (
41
+ key: string,
42
+ params: any[],
43
+ store: Store
44
+ ): void => {
45
+ store.transactionStatus = {
46
+ key,
47
+ phase: `building`,
48
+ core: {
11
49
  atoms: store.atoms,
50
+ atomsThatAreDefault: store.atomsThatAreDefault,
51
+ operation: { open: false },
12
52
  readonlySelectors: store.readonlySelectors,
53
+ timelines: store.timelines,
54
+ timelineAtoms: store.timelineAtoms,
55
+ transactions: store.transactions,
56
+ selectorAtoms: store.selectorAtoms,
13
57
  selectorGraph: store.selectorGraph,
14
58
  selectors: store.selectors,
15
59
  valueMap: store.valueMap,
16
60
  },
61
+ atomUpdates: [],
62
+ params,
63
+ output: undefined,
64
+ }
65
+ store.config.logger?.info(`🛫`, `transaction "${key}" started`)
66
+ }
67
+ export const applyTransaction = <ƒ extends ƒn>(
68
+ output: ReturnType<ƒ>,
69
+ store: Store
70
+ ): void => {
71
+ if (store.transactionStatus.phase !== `building`) {
72
+ store.config.logger?.warn(
73
+ `abortTransaction called outside of a transaction. This is probably a bug.`
74
+ )
75
+ return
76
+ }
77
+ store.config.logger?.info(
78
+ ` ▶️ apply transaction "${store.transactionStatus.key}" (init)`
79
+ )
80
+ store.transactionStatus.phase = `applying`
81
+ store.transactionStatus.output = output
82
+ const { atomUpdates } = store.transactionStatus
83
+ for (const { key, oldValue, newValue } of atomUpdates) {
84
+ const token: AtomToken<unknown> = { key, type: `atom` }
85
+ const state = withdraw(token, store)
86
+ setState(state, newValue, store)
87
+ }
88
+ const myTransaction = withdraw<ƒ>(
89
+ { key: store.transactionStatus.key, type: `transaction` },
90
+ store
91
+ )
92
+ myTransaction.subject.next({
93
+ key: store.transactionStatus.key,
94
+ atomUpdates,
95
+ output,
96
+ params: store.transactionStatus.params as Parameters<ƒ>,
97
+ })
98
+ store.transactionStatus = { phase: `idle` }
99
+ store.config.logger?.info(`🛬`, `transaction done`)
100
+ }
101
+ export const undoTransactionUpdate = <ƒ extends ƒn>(
102
+ update: TransactionUpdate<ƒ>,
103
+ store: Store
104
+ ): void => {
105
+ store.config.logger?.info(` ⏮ undo transaction "${update.key}" (undo)`)
106
+ for (const { key, oldValue, newValue } of update.atomUpdates) {
107
+ const token: AtomToken<unknown> = { key, type: `atom` }
108
+ const state = withdraw(token, store)
109
+ setState(state, oldValue, store)
110
+ }
111
+ }
112
+ export const redoTransactionUpdate = <ƒ extends ƒn>(
113
+ update: TransactionUpdate<ƒ>,
114
+ store: Store
115
+ ): void => {
116
+ store.config.logger?.info(` ⏭ redo transaction "${update.key}" (redo)`)
117
+ for (const { key, oldValue, newValue } of update.atomUpdates) {
118
+ const token: AtomToken<unknown> = { key, type: `atom` }
119
+ const state = withdraw(token, store)
120
+ setState(state, newValue, store)
17
121
  }
18
- store.config.logger?.info(`🛫`, `transaction start`)
19
122
  }
123
+
20
124
  export const abortTransaction = (store: Store): void => {
21
- if (!store.transaction.open) {
125
+ if (store.transactionStatus.phase === `idle`) {
22
126
  store.config.logger?.warn(
23
127
  `abortTransaction called outside of a transaction. This is probably a bug.`
24
128
  )
25
129
  return
26
130
  }
27
- store.atoms = store.transaction.prev.atoms
28
- store.readonlySelectors = store.transaction.prev.readonlySelectors
29
- store.selectorGraph = store.transaction.prev.selectorGraph
30
- store.selectors = store.transaction.prev.selectors
31
- store.valueMap = store.transaction.prev.valueMap
32
- store.transaction = { open: false }
131
+ store.transactionStatus = { phase: `idle` }
33
132
  store.config.logger?.info(`🪂`, `transaction fail`)
34
133
  }
134
+
135
+ export function transaction__INTERNAL<ƒ extends ƒn>(
136
+ options: TransactionOptions<ƒ>,
137
+ store: Store = IMPLICIT.STORE
138
+ ): TransactionToken<ƒ> {
139
+ const newTransaction: Transaction<ƒ> = {
140
+ key: options.key,
141
+ type: `transaction`,
142
+ run: (...params: Parameters<ƒ>) => {
143
+ buildTransaction(options.key, params, store)
144
+ try {
145
+ const output = options.do(
146
+ {
147
+ get: (token) => getState(token, store),
148
+ set: (token, value) => setState(token, value, store),
149
+ },
150
+ ...params
151
+ )
152
+ applyTransaction(output, store)
153
+ return output
154
+ } catch (thrown) {
155
+ abortTransaction(store)
156
+ store.config.logger?.error(`Transaction ${options.key} failed`, thrown)
157
+ throw thrown
158
+ }
159
+ },
160
+ subject: new Rx.Subject(),
161
+ }
162
+ const core = target(store)
163
+ core.transactions = HAMT.set(
164
+ newTransaction.key,
165
+ newTransaction,
166
+ core.transactions
167
+ )
168
+ const token = deposit(newTransaction)
169
+ return token
170
+ }
171
+
172
+ export const target = (store: Store = IMPLICIT.STORE): StoreCore =>
173
+ store.transactionStatus.phase === `building`
174
+ ? store.transactionStatus.core
175
+ : store
package/src/logger.ts ADDED
@@ -0,0 +1,46 @@
1
+ import { doNothing } from "~/packages/anvl/src/function"
2
+
3
+ import type { Store } from "./internal/store"
4
+ import { IMPLICIT } from "./internal/store"
5
+
6
+ export type Logger = Pick<Console, `error` | `info` | `warn`>
7
+ export const LOG_LEVELS: ReadonlyArray<keyof Logger> = [
8
+ `info`,
9
+ `warn`,
10
+ `error`,
11
+ ] as const
12
+
13
+ export const setLogLevel = (
14
+ preferredLevel: `error` | `info` | `warn` | null,
15
+ store: Store = IMPLICIT.STORE
16
+ ): void => {
17
+ const { logger__INTERNAL } = store.config
18
+ if (preferredLevel === null) {
19
+ store.config.logger = null
20
+ } else {
21
+ store.config.logger = { ...console }
22
+ LOG_LEVELS.forEach((logLevel) => {
23
+ if (LOG_LEVELS.indexOf(logLevel) < LOG_LEVELS.indexOf(preferredLevel)) {
24
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
25
+ store.config.logger![logLevel] = doNothing
26
+ } else {
27
+ /* eslint-disable-next-line @typescript-eslint/no-non-null-assertion */
28
+ store.config.logger![logLevel] = logger__INTERNAL[logLevel]
29
+ }
30
+ })
31
+ }
32
+ }
33
+
34
+ export const useLogger = (
35
+ logger: Logger,
36
+ store: Store = IMPLICIT.STORE
37
+ ): void => {
38
+ const currentLogLevel =
39
+ store.config.logger === null
40
+ ? null
41
+ : LOG_LEVELS.find(
42
+ (logLevel) => store.config.logger?.[logLevel] !== doNothing
43
+ ) ?? null
44
+ store.config.logger__INTERNAL = { ...logger }
45
+ setLogLevel(currentLogLevel, store)
46
+ }
@@ -2,11 +2,10 @@ import type Preact from "preact/hooks"
2
2
 
3
3
  import type React from "react"
4
4
 
5
- import type { Modifier } from "~/packages/anvl/src/function"
5
+ import { subscribe, setState, __INTERNAL__ } from "atom.io"
6
+ import type { ReadonlyValueToken, StateToken } from "atom.io"
6
7
 
7
- import type { ReadonlyValueToken, StateToken } from ".."
8
- import { subscribe, setState, __INTERNAL__ } from ".."
9
- import { withdraw } from "../internal"
8
+ import type { Modifier } from "~/packages/anvl/src/function"
10
9
 
11
10
  export type AtomStoreReactConfig = {
12
11
  useState: typeof Preact.useState | typeof React.useState
@@ -26,7 +25,7 @@ export const composeStoreHooks = ({
26
25
  }
27
26
 
28
27
  function useO<T>(token: ReadonlyValueToken<T> | StateToken<T>): T {
29
- const state = withdraw(token, store)
28
+ const state = __INTERNAL__.withdraw(token, store)
30
29
  const initialValue = __INTERNAL__.getState__INTERNAL(state, store)
31
30
  const [current, dispatch] = useState(initialValue)
32
31
  useEffect(() => {
@@ -40,7 +39,7 @@ export const composeStoreHooks = ({
40
39
  store
41
40
  )
42
41
  return unsubscribe
43
- }, [current, dispatch])
42
+ }, [])
44
43
 
45
44
  return current
46
45
  }