atom.io 0.15.5 → 0.16.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 (134) hide show
  1. package/data/dist/index.cjs +20 -22
  2. package/data/dist/index.cjs.map +1 -1
  3. package/data/dist/index.d.ts +6 -6
  4. package/data/dist/index.js +21 -23
  5. package/data/dist/index.js.map +1 -1
  6. package/data/src/dict.ts +6 -7
  7. package/data/src/join.ts +23 -23
  8. package/data/src/struct-family.ts +2 -2
  9. package/data/src/struct.ts +4 -5
  10. package/dist/index.cjs +12 -5
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts +67 -60
  13. package/dist/index.js +13 -6
  14. package/dist/index.js.map +1 -1
  15. package/internal/dist/index.cjs +912 -886
  16. package/internal/dist/index.cjs.map +1 -1
  17. package/internal/dist/index.d.ts +157 -162
  18. package/internal/dist/index.js +487 -460
  19. package/internal/dist/index.js.map +1 -1
  20. package/internal/src/atom/create-regular-atom.ts +9 -12
  21. package/internal/src/atom/create-standalone-atom.ts +33 -0
  22. package/internal/src/atom/delete-atom.ts +5 -2
  23. package/internal/src/atom/index.ts +1 -16
  24. package/internal/src/atom/is-default.ts +0 -1
  25. package/internal/src/caching.ts +6 -3
  26. package/internal/src/families/create-atom-family.ts +11 -7
  27. package/internal/src/families/create-readonly-selector-family.ts +4 -3
  28. package/internal/src/families/create-regular-atom-family.ts +12 -27
  29. package/internal/src/families/create-selector-family.ts +13 -49
  30. package/internal/src/families/create-writable-selector-family.ts +51 -0
  31. package/internal/src/index.ts +44 -3
  32. package/internal/src/lineage.ts +0 -7
  33. package/internal/src/mutable/create-mutable-atom-family.ts +61 -15
  34. package/internal/src/mutable/create-mutable-atom.ts +70 -25
  35. package/internal/src/mutable/get-json-family.ts +4 -5
  36. package/internal/src/mutable/get-json-token.ts +6 -3
  37. package/internal/src/mutable/get-update-token.ts +3 -3
  38. package/internal/src/mutable/index.ts +1 -7
  39. package/internal/src/mutable/is-mutable.ts +6 -7
  40. package/internal/src/mutable/tracker-family.ts +4 -4
  41. package/internal/src/mutable/tracker.ts +6 -6
  42. package/internal/src/read-or-compute-value.ts +6 -3
  43. package/internal/src/selector/create-readonly-selector.ts +2 -3
  44. package/internal/src/selector/create-standalone-selector.ts +32 -0
  45. package/internal/src/selector/{create-read-write-selector.ts → create-writable-selector.ts} +12 -9
  46. package/internal/src/selector/delete-selector.ts +2 -2
  47. package/internal/src/selector/index.ts +3 -1
  48. package/internal/src/selector/trace-selector-atoms.ts +3 -2
  49. package/internal/src/selector/update-selector-atoms.ts +1 -1
  50. package/internal/src/set-state/copy-mutable-if-needed.ts +5 -6
  51. package/internal/src/set-state/copy-mutable-in-transaction.ts +4 -36
  52. package/internal/src/set-state/emit-update.ts +2 -3
  53. package/internal/src/set-state/evict-downstream.ts +1 -1
  54. package/internal/src/set-state/set-atom-or-selector.ts +3 -3
  55. package/internal/src/set-state/set-atom.ts +8 -4
  56. package/internal/src/set-state/stow-update.ts +1 -1
  57. package/internal/src/store/deposit.ts +25 -13
  58. package/internal/src/store/store.ts +21 -21
  59. package/internal/src/store/withdraw-new-family-member.ts +16 -9
  60. package/internal/src/store/withdraw.ts +43 -19
  61. package/internal/src/subscribe/recall-state.ts +2 -6
  62. package/internal/src/subscribe/subscribe-to-root-atoms.ts +39 -41
  63. package/internal/src/subscribe/subscribe-to-state.ts +3 -1
  64. package/internal/src/timeline/add-atom-to-timeline.ts +5 -5
  65. package/internal/src/timeline/create-timeline.ts +19 -22
  66. package/introspection/dist/index.cjs +4 -8
  67. package/introspection/dist/index.cjs.map +1 -1
  68. package/introspection/dist/index.d.ts +5 -5
  69. package/introspection/dist/index.js +5 -9
  70. package/introspection/dist/index.js.map +1 -1
  71. package/introspection/src/attach-atom-index.ts +4 -5
  72. package/introspection/src/attach-selector-index.ts +4 -5
  73. package/introspection/src/attach-timeline-index.ts +6 -3
  74. package/introspection/src/attach-transaction-index.ts +6 -3
  75. package/introspection/src/index.ts +9 -5
  76. package/json/dist/index.cjs +3 -4
  77. package/json/dist/index.cjs.map +1 -1
  78. package/json/dist/index.d.ts +4 -3
  79. package/json/dist/index.js +4 -5
  80. package/json/dist/index.js.map +1 -1
  81. package/json/src/select-json-family.ts +24 -4
  82. package/json/src/select-json.ts +3 -4
  83. package/package.json +2 -2
  84. package/react-devtools/dist/index.cjs.map +1 -1
  85. package/react-devtools/dist/index.d.ts +9 -9
  86. package/react-devtools/dist/index.js.map +1 -1
  87. package/react-devtools/src/StateIndex.tsx +18 -10
  88. package/react-devtools/src/TimelineIndex.tsx +6 -2
  89. package/react-devtools/src/TransactionIndex.tsx +2 -2
  90. package/realtime-client/dist/index.cjs +27 -13
  91. package/realtime-client/dist/index.cjs.map +1 -1
  92. package/realtime-client/dist/index.d.ts +6 -4
  93. package/realtime-client/dist/index.js +20 -7
  94. package/realtime-client/dist/index.js.map +1 -1
  95. package/realtime-client/src/index.ts +4 -3
  96. package/realtime-client/src/server-action.ts +2 -55
  97. package/realtime-client/src/sync-server-action.ts +75 -0
  98. package/realtime-react/dist/index.cjs +22 -13
  99. package/realtime-react/dist/index.cjs.map +1 -1
  100. package/realtime-react/dist/index.d.ts +3 -1
  101. package/realtime-react/dist/index.js +20 -12
  102. package/realtime-react/dist/index.js.map +1 -1
  103. package/realtime-react/src/index.ts +1 -0
  104. package/realtime-react/src/use-server-action.ts +2 -4
  105. package/realtime-react/src/use-sync-server-action.ts +19 -0
  106. package/realtime-server/dist/index.cjs +83 -81
  107. package/realtime-server/dist/index.cjs.map +1 -1
  108. package/realtime-server/dist/index.d.ts +8 -8
  109. package/realtime-server/dist/index.js +58 -56
  110. package/realtime-server/dist/index.js.map +1 -1
  111. package/realtime-server/src/index.ts +15 -1
  112. package/realtime-server/src/{hook-composition/receive-transaction.ts → realtime-action-receiver.ts} +6 -2
  113. package/realtime-server/src/{hook-composition/sync-transaction.ts → realtime-action-synchronizer.ts} +10 -43
  114. package/realtime-server/src/{hook-composition/expose-family.ts → realtime-family-provider.ts} +9 -23
  115. package/realtime-server/src/{hook-composition/expose-mutable-family.ts → realtime-mutable-family-provider.ts} +4 -4
  116. package/realtime-server/src/{hook-composition/expose-mutable.ts → realtime-mutable-provider.ts} +4 -5
  117. package/realtime-server/src/realtime-server-store.ts +39 -0
  118. package/realtime-server/src/{hook-composition/expose-single.ts → realtime-state-provider.ts} +7 -8
  119. package/realtime-server/src/{hook-composition/receive-state.ts → realtime-state-receiver.ts} +7 -4
  120. package/src/atom.ts +39 -24
  121. package/src/find-state.ts +20 -19
  122. package/src/index.ts +41 -28
  123. package/src/logger.ts +1 -0
  124. package/src/selector.ts +31 -16
  125. package/src/silo.ts +45 -6
  126. package/src/subscribe.ts +1 -0
  127. package/src/validators.ts +35 -25
  128. package/internal/src/atom/create-atom.ts +0 -21
  129. package/internal/src/mutable/get-update-family.ts +0 -23
  130. package/internal/src/selector/create-selector.ts +0 -65
  131. package/realtime-server/src/hook-composition/index.ts +0 -15
  132. /package/realtime-client/src/{pull.ts → pull-state.ts} +0 -0
  133. /package/realtime-client/src/{push.ts → push-state.ts} +0 -0
  134. /package/realtime-client/src/{realtime-state.ts → realtime-client-store.ts} +0 -0
@@ -1,50 +1,95 @@
1
+ import type { UpdateHandler } from "atom.io"
1
2
  import type {
2
3
  FamilyMetadata,
3
4
  MutableAtomOptions,
4
5
  MutableAtomToken,
5
6
  } from "atom.io"
7
+ import { setState } from "atom.io"
6
8
  import type { Json } from "atom.io/json"
7
9
  import { selectJson } from "atom.io/json"
8
10
 
9
- import { createRegularAtom } from "../atom"
11
+ import { type MutableAtom, cacheValue } from ".."
12
+ import { createRegularAtom, markAtomAsDefault } from "../atom"
10
13
  import { newest } from "../lineage"
11
- import type { Store } from "../store"
14
+ import { type Store, deposit } from "../store"
15
+ import { Subject } from "../subject"
12
16
  import { subscribeToState } from "../subscribe"
13
17
  import { Tracker } from "./tracker"
14
18
  import type { Transceiver } from "./transceiver"
15
19
 
16
20
  export function createMutableAtom<
17
- Core extends Transceiver<any>,
18
- SerializableCore extends Json.Serializable,
21
+ T extends Transceiver<any>,
22
+ J extends Json.Serializable,
19
23
  >(
20
- options: MutableAtomOptions<Core, SerializableCore>,
24
+ options: MutableAtomOptions<T, J>,
21
25
  family: FamilyMetadata | undefined,
22
26
  store: Store,
23
- ): MutableAtomToken<Core, SerializableCore> {
27
+ ): MutableAtomToken<T, J> {
24
28
  store.logger.info(
25
- `🔧`,
29
+ `🔨`,
26
30
  `atom`,
27
31
  options.key,
28
32
  `creating in store "${store.config.name}"`,
29
33
  )
30
- const coreState = createRegularAtom<Core>(options, family, store)
31
- new Tracker(coreState, store)
32
- const jsonState = selectJson(coreState, options, store)
33
34
  const target = newest(store)
34
- subscribeToState(
35
- jsonState,
36
- () => {
37
- const trackerHasBeenInitialized = newest(store).trackers.has(coreState.key)
38
- if (!trackerHasBeenInitialized) {
39
- new Tracker(coreState, store)
40
- }
35
+ const existing = target.atoms.get(options.key)
36
+ if (existing && existing.type === `mutable_atom`) {
37
+ store.logger.error(
38
+ `❌`,
39
+ `atom`,
40
+ options.key,
41
+ `Tried to create atom, but it already exists in the store.`,
42
+ )
43
+ return deposit(existing)
44
+ }
45
+ const subject = new Subject<{ newValue: T; oldValue: T }>()
46
+ const newAtom: MutableAtom<T, J> = {
47
+ ...options,
48
+ type: `mutable_atom`,
49
+ install: (store: Store) => {
50
+ store.logger.info(
51
+ `🛠️`,
52
+ `atom`,
53
+ options.key,
54
+ `installing in store "${store.config.name}"`,
55
+ )
56
+ return createMutableAtom(options, family, store)
41
57
  },
42
- `tracker-initializer:${store?.config.name}:${
43
- target.transactionMeta === null
44
- ? `main`
45
- : `${target.transactionMeta.update.key}`
46
- }`,
47
- store,
48
- )
49
- return coreState as MutableAtomToken<Core, SerializableCore>
58
+ subject,
59
+ } as const
60
+ if (family) {
61
+ newAtom.family = family
62
+ }
63
+ const initialValue = options.default()
64
+ target.atoms.set(newAtom.key, newAtom)
65
+ markAtomAsDefault(options.key, store)
66
+ cacheValue(options.key, initialValue, subject, target)
67
+ const token = deposit(newAtom)
68
+ if (options.effects) {
69
+ let effectIndex = 0
70
+ const cleanupFunctions: (() => void)[] = []
71
+ for (const effect of options.effects) {
72
+ const cleanup = effect({
73
+ setSelf: (next) => setState(token, next, store),
74
+ onSet: (handle: UpdateHandler<T>) =>
75
+ subscribeToState(token, handle, `effect[${effectIndex}]`, store),
76
+ })
77
+ if (cleanup) {
78
+ cleanupFunctions.push(cleanup)
79
+ }
80
+ ++effectIndex
81
+ }
82
+ newAtom.cleanup = () => {
83
+ for (const cleanup of cleanupFunctions) {
84
+ cleanup()
85
+ }
86
+ }
87
+ }
88
+
89
+ new Tracker(token, store)
90
+ selectJson(token, options, store)
91
+
92
+ store.on.atomCreation.next(token)
93
+
94
+ return token
50
95
  }
@@ -1,4 +1,4 @@
1
- import type { MutableAtomFamily, SelectorFamily } from "atom.io"
1
+ import type { MutableAtomFamily, WritableSelectorFamily } from "atom.io"
2
2
  import type { Json } from "atom.io/json"
3
3
 
4
4
  import { newest } from "../lineage"
@@ -12,11 +12,10 @@ export const getJsonFamily = <
12
12
  >(
13
13
  mutableAtomFamily: MutableAtomFamily<Core, SerializableCore, Key>,
14
14
  store: Store,
15
- ): SelectorFamily<SerializableCore, Key> => {
15
+ ): WritableSelectorFamily<SerializableCore, Key> => {
16
16
  const target = newest(store)
17
17
  const key = `${mutableAtomFamily.key}:JSON`
18
- const jsonFamily: SelectorFamily<SerializableCore, Key> = target.families.get(
19
- key,
20
- ) as SelectorFamily<SerializableCore, Key>
18
+ const jsonFamily: WritableSelectorFamily<SerializableCore, Key> =
19
+ target.families.get(key) as WritableSelectorFamily<SerializableCore, Key>
21
20
  return jsonFamily
22
21
  }
@@ -1,4 +1,4 @@
1
- import type { MutableAtomToken, SelectorToken } from "atom.io"
1
+ import type { MutableAtomToken, WritableSelectorToken } from "atom.io"
2
2
  import type { Json } from "atom.io/json"
3
3
 
4
4
  import type { Transceiver } from "./transceiver"
@@ -8,11 +8,14 @@ export const getJsonToken = <
8
8
  SerializableCore extends Json.Serializable,
9
9
  >(
10
10
  mutableAtomToken: MutableAtomToken<Core, SerializableCore>,
11
- ): SelectorToken<SerializableCore> => {
11
+ ): WritableSelectorToken<SerializableCore> => {
12
12
  const key = mutableAtomToken.family
13
13
  ? `${mutableAtomToken.family.key}:JSON(${mutableAtomToken.family.subKey})`
14
14
  : `${mutableAtomToken.key}:JSON`
15
- const jsonToken: SelectorToken<SerializableCore> = { type: `selector`, key }
15
+ const jsonToken: WritableSelectorToken<SerializableCore> = {
16
+ type: `selector`,
17
+ key,
18
+ }
16
19
  if (mutableAtomToken.family) {
17
20
  jsonToken.family = {
18
21
  key: `${mutableAtomToken.family.key}:JSON`,
@@ -1,4 +1,4 @@
1
- import type { AtomToken, MutableAtomToken } from "atom.io"
1
+ import type { MutableAtomToken, RegularAtomToken } from "atom.io"
2
2
  import type { Json } from "atom.io/json"
3
3
  import type { Signal, Transceiver } from "./transceiver"
4
4
 
@@ -7,9 +7,9 @@ export const getUpdateToken = <
7
7
  SerializableCore extends Json.Serializable,
8
8
  >(
9
9
  mutableAtomToken: MutableAtomToken<Core, SerializableCore>,
10
- ): AtomToken<Signal<Core>> => {
10
+ ): RegularAtomToken<Signal<Core>> => {
11
11
  const key = `*${mutableAtomToken.key}`
12
- const updateToken: AtomToken<Signal<Core>> = { type: `atom`, key }
12
+ const updateToken: RegularAtomToken<Signal<Core>> = { type: `atom`, key }
13
13
  if (mutableAtomToken.family) {
14
14
  updateToken.family = {
15
15
  key: `*${mutableAtomToken.family.key}`,
@@ -1,15 +1,9 @@
1
- import type { Atom } from "../atom"
2
-
3
1
  export * from "./create-mutable-atom"
4
2
  export * from "./create-mutable-atom-family"
5
3
  export * from "./get-json-family"
6
4
  export * from "./get-json-token"
7
5
  export * from "./get-update-token"
8
- export * from "./get-update-family"
6
+ export * from "./is-mutable"
9
7
  export * from "./tracker"
10
8
  export * from "./tracker-family"
11
9
  export * from "./transceiver"
12
-
13
- export interface MutableAtom<T> extends Atom<T> {
14
- mutable: true
15
- }
@@ -1,17 +1,16 @@
1
1
  import type { AtomFamily, MutableAtomFamily } from "atom.io"
2
2
 
3
- import type { MutableAtom } from "."
4
- import type { Atom } from "../atom"
3
+ import type { Atom, MutableAtom } from ".."
5
4
 
6
- export function isMutable(atom: Atom<any>): atom is MutableAtom<any>
5
+ export function isMutable(atom: Atom<any>): atom is MutableAtom<any, any>
7
6
  export function isMutable(
8
7
  family: AtomFamily<any, any>,
9
8
  ): family is MutableAtomFamily<any, any, any>
10
9
  export function isMutable(
11
10
  atomOrTokenOrFamily: Atom<any> | AtomFamily<any, any>,
12
11
  ): boolean {
13
- if (`mutable` in atomOrTokenOrFamily) {
14
- return atomOrTokenOrFamily.mutable
15
- }
16
- return false
12
+ return (
13
+ atomOrTokenOrFamily.type === `mutable_atom` ||
14
+ atomOrTokenOrFamily.type === `mutable_atom_family`
15
+ )
17
16
  }
@@ -1,4 +1,4 @@
1
- import type { AtomFamily } from "atom.io"
1
+ import type { MutableAtomFamily, RegularAtomFamily } from "atom.io"
2
2
  import type { Json } from "atom.io/json"
3
3
  import { parseJson } from "atom.io/json"
4
4
 
@@ -15,14 +15,14 @@ export class FamilyTracker<
15
15
  ? Signal
16
16
  : never
17
17
 
18
- public readonly findLatestUpdateState: AtomFamily<
18
+ public readonly findLatestUpdateState: RegularAtomFamily<
19
19
  typeof this.Update | null,
20
20
  FamilyMemberKey
21
21
  >
22
- public readonly findMutableState: AtomFamily<Core, FamilyMemberKey>
22
+ public readonly findMutableState: MutableAtomFamily<Core, any, FamilyMemberKey>
23
23
 
24
24
  public constructor(
25
- findMutableState: AtomFamily<Core, FamilyMemberKey>,
25
+ findMutableState: MutableAtomFamily<Core, any, FamilyMemberKey>,
26
26
  store: Store,
27
27
  ) {
28
28
  this.findLatestUpdateState = createRegularAtomFamily<
@@ -1,4 +1,4 @@
1
- import type { AtomToken, FamilyMetadata, MutableAtomToken } from "atom.io"
1
+ import type { FamilyMetadata, MutableAtomToken, RegularAtomToken } from "atom.io"
2
2
  import { getState, setState } from "atom.io"
3
3
  import type { Json } from "atom.io/json"
4
4
 
@@ -18,7 +18,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
18
18
  private initializeState(
19
19
  mutableState: MutableAtomToken<Mutable, Json.Serializable>,
20
20
  store: Store,
21
- ): AtomToken<typeof this.Update | null> {
21
+ ): RegularAtomToken<typeof this.Update | null> {
22
22
  const latestUpdateStateKey = `*${mutableState.key}`
23
23
  store.atoms.delete(latestUpdateStateKey)
24
24
  store.valueMap.delete(latestUpdateStateKey)
@@ -49,8 +49,8 @@ export class Tracker<Mutable extends Transceiver<any>> {
49
49
  private unsubscribeFromInnerValue: () => void
50
50
  private unsubscribeFromState: () => void
51
51
  private observeCore(
52
- mutableState: MutableAtomToken<Mutable, Json.Serializable>,
53
- latestUpdateState: AtomToken<typeof this.Update | null>,
52
+ mutableState: MutableAtomToken<Mutable, any>,
53
+ latestUpdateState: RegularAtomToken<typeof this.Update | null>,
54
54
  store: Store,
55
55
  ): void {
56
56
  const originalInnerValue = getState(mutableState, store)
@@ -112,7 +112,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
112
112
 
113
113
  private updateCore<Core extends Transceiver<any>>(
114
114
  mutableState: MutableAtomToken<Core, Json.Serializable>,
115
- latestUpdateState: AtomToken<typeof this.Update | null>,
115
+ latestUpdateState: RegularAtomToken<typeof this.Update | null>,
116
116
  store: Store,
117
117
  ): void {
118
118
  subscribeToState(
@@ -174,7 +174,7 @@ export class Tracker<Mutable extends Transceiver<any>> {
174
174
  }
175
175
 
176
176
  public mutableState: MutableAtomToken<Mutable, Json.Serializable>
177
- public latestUpdateState: AtomToken<typeof this.Update | null>
177
+ public latestUpdateState: RegularAtomToken<typeof this.Update | null>
178
178
 
179
179
  public dispose: () => void
180
180
 
@@ -1,13 +1,16 @@
1
- import type { StateNode } from "."
1
+ import type { ReadableState } from "."
2
2
  import { readCachedValue } from "./caching"
3
3
  import type { Store } from "./store"
4
4
 
5
- export const readOrComputeValue = <T>(state: StateNode<T>, target: Store): T => {
5
+ export const readOrComputeValue = <T>(
6
+ state: ReadableState<T>,
7
+ target: Store,
8
+ ): T => {
6
9
  if (target.valueMap.has(state.key)) {
7
10
  target.logger.info(`📖`, state.type, state.key, `reading cached value`)
8
11
  return readCachedValue(state, target)
9
12
  }
10
- if (state.type !== `atom`) {
13
+ if (state.type !== `atom` && state.type !== `mutable_atom`) {
11
14
  target.logger.info(`🧮`, state.type, state.key, `computing value`)
12
15
  return state.get()
13
16
  }
@@ -4,12 +4,11 @@ import type {
4
4
  ReadonlySelectorToken,
5
5
  } from "atom.io"
6
6
 
7
+ import type { ReadonlySelector } from ".."
7
8
  import { cacheValue } from "../caching"
8
9
  import { newest } from "../lineage"
9
10
  import type { Store } from "../store"
10
11
  import { Subject } from "../subject"
11
- import type { ReadonlySelector } from "./create-selector"
12
- import { createSelector } from "./create-selector"
13
12
  import { registerSelector } from "./register-selector"
14
13
 
15
14
  export const createReadonlySelector = <T>(
@@ -30,7 +29,7 @@ export const createReadonlySelector = <T>(
30
29
  const readonlySelector: ReadonlySelector<T> = {
31
30
  ...options,
32
31
  subject,
33
- install: (s: Store) => createSelector(options, family, s),
32
+ install: (s: Store) => createReadonlySelector(options, family, s),
34
33
  get: getSelf,
35
34
  type: `readonly_selector`,
36
35
  ...(family && { family }),
@@ -0,0 +1,32 @@
1
+ import type {
2
+ FamilyMetadata,
3
+ ReadonlySelectorOptions,
4
+ ReadonlySelectorToken,
5
+ WritableSelectorOptions,
6
+ WritableSelectorToken,
7
+ } from "atom.io"
8
+
9
+ import type { Store } from "../store"
10
+ import type { Subject } from "../subject"
11
+ import { createReadonlySelector } from "./create-readonly-selector"
12
+ import { createWritableSelector } from "./create-writable-selector"
13
+
14
+ export function createStandaloneSelector<T>(
15
+ options: WritableSelectorOptions<T>,
16
+ store: Store,
17
+ ): WritableSelectorToken<T>
18
+ export function createStandaloneSelector<T>(
19
+ options: ReadonlySelectorOptions<T>,
20
+ store: Store,
21
+ ): ReadonlySelectorToken<T>
22
+ export function createStandaloneSelector<T>(
23
+ options: ReadonlySelectorOptions<T> | WritableSelectorOptions<T>,
24
+ store: Store,
25
+ ): ReadonlySelectorToken<T> | WritableSelectorToken<T> {
26
+ const isWritable = `set` in options
27
+
28
+ if (isWritable) {
29
+ return createWritableSelector(options, undefined, store)
30
+ }
31
+ return createReadonlySelector(options, undefined, store)
32
+ }
@@ -1,20 +1,23 @@
1
- import type { FamilyMetadata, SelectorOptions, SelectorToken } from "atom.io"
1
+ import type {
2
+ FamilyMetadata,
3
+ WritableSelectorOptions,
4
+ WritableSelectorToken,
5
+ } from "atom.io"
2
6
 
7
+ import type { WritableSelector } from ".."
3
8
  import { cacheValue } from "../caching"
4
9
  import { newest } from "../lineage"
5
10
  import { markDone } from "../operation"
6
11
  import { become } from "../set-state/become"
7
12
  import type { Store } from "../store"
8
13
  import { Subject } from "../subject"
9
- import type { Selector } from "./create-selector"
10
- import { createSelector } from "./create-selector"
11
14
  import { registerSelector } from "./register-selector"
12
15
 
13
- export const createReadWriteSelector = <T>(
14
- options: SelectorOptions<T>,
16
+ export const createWritableSelector = <T>(
17
+ options: WritableSelectorOptions<T>,
15
18
  family: FamilyMetadata | undefined,
16
19
  store: Store,
17
- ): SelectorToken<T> => {
20
+ ): WritableSelectorToken<T> => {
18
21
  const target = newest(store)
19
22
  const subject = new Subject<{ newValue: T; oldValue: T }>()
20
23
  const transactors = registerSelector(options.key, store)
@@ -47,10 +50,10 @@ export const createReadWriteSelector = <T>(
47
50
  }
48
51
  options.set(transactors, newValue)
49
52
  }
50
- const mySelector: Selector<T> = {
53
+ const mySelector: WritableSelector<T> = {
51
54
  ...options,
52
55
  subject,
53
- install: (s: Store) => createSelector(options, family, s),
56
+ install: (s: Store) => createWritableSelector(options, family, s),
54
57
  get: getSelf,
55
58
  set: setSelf,
56
59
  type: `selector`,
@@ -59,7 +62,7 @@ export const createReadWriteSelector = <T>(
59
62
  target.selectors.set(options.key, mySelector)
60
63
  const initialValue = getSelf()
61
64
  store.logger.info(`✨`, mySelector.type, mySelector.key, `=`, initialValue)
62
- const token: SelectorToken<T> = {
65
+ const token: WritableSelectorToken<T> = {
63
66
  key: options.key,
64
67
  type: `selector`,
65
68
  }
@@ -1,10 +1,10 @@
1
- import type { ReadonlySelectorToken, SelectorToken } from "atom.io"
1
+ import type { ReadonlySelectorToken, WritableSelectorToken } from "atom.io"
2
2
 
3
3
  import { newest } from ".."
4
4
  import type { Store } from ".."
5
5
 
6
6
  export function deleteSelector(
7
- selectorToken: ReadonlySelectorToken<unknown> | SelectorToken<unknown>,
7
+ selectorToken: ReadonlySelectorToken<unknown> | WritableSelectorToken<unknown>,
8
8
  store: Store,
9
9
  ): void {
10
10
  const target = newest(store)
@@ -1,4 +1,6 @@
1
- export * from "./create-selector"
1
+ export * from "./create-readonly-selector"
2
+ export * from "./create-standalone-selector"
3
+ export * from "./create-writable-selector"
2
4
  export * from "./delete-selector"
3
5
  export * from "./get-selector-dependency-keys"
4
6
  export * from "./register-selector"
@@ -1,4 +1,4 @@
1
- import type { Store } from ".."
1
+ import type { Selector, Store } from ".."
2
2
  import type { AtomKey, StateKey } from "../keys"
3
3
  import { isAtomKey } from "../keys"
4
4
  import { getSelectorDependencyKeys } from "./get-selector-dependency-keys"
@@ -38,9 +38,10 @@ export const traceSelectorAtoms = (
38
38
  }
39
39
 
40
40
  export const traceAllSelectorAtoms = (
41
- selectorKey: string,
41
+ selector: Selector<any>,
42
42
  store: Store,
43
43
  ): AtomKey<unknown>[] => {
44
+ const selectorKey = selector.key
44
45
  const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store)
45
46
  return directDependencyKeys.flatMap((depKey) =>
46
47
  isAtomKey(depKey, store)
@@ -10,7 +10,7 @@ export const updateSelectorAtoms = (
10
10
  store: Store,
11
11
  ): void => {
12
12
  const target = newest(store)
13
- if (dependency.type === `atom`) {
13
+ if (dependency.type === `atom` || dependency.type === `mutable_atom`) {
14
14
  target.selectorAtoms.set({
15
15
  selectorKey,
16
16
  atomKey: dependency.key,
@@ -1,12 +1,11 @@
1
1
  import type { JsonInterface } from "atom.io/json"
2
2
 
3
- import type { Atom } from "../atom"
3
+ import type { MutableAtom, Transceiver } from ".."
4
4
  import { Tracker } from "../mutable"
5
5
  import type { Store } from "../store"
6
6
 
7
- export function copyMutableIfNeeded<T>(
8
- atom: Atom<T>,
9
- transform: JsonInterface<T>,
7
+ export function copyMutableIfNeeded<T extends Transceiver<any>>(
8
+ atom: MutableAtom<T, any>,
10
9
  origin: Store,
11
10
  target: Store,
12
11
  ): T {
@@ -14,8 +13,8 @@ export function copyMutableIfNeeded<T>(
14
13
  const targetValue = target.valueMap.get(atom.key)
15
14
  if (originValue === targetValue) {
16
15
  origin.logger.info(`📃`, `atom`, `${atom.key}`, `copying`)
17
- const jsonValue = transform.toJson(originValue)
18
- const copiedValue = transform.fromJson(jsonValue)
16
+ const jsonValue = atom.toJson(originValue)
17
+ const copiedValue = atom.fromJson(jsonValue)
19
18
  target.valueMap.set(atom.key, copiedValue)
20
19
  new Tracker(atom, origin)
21
20
  return copiedValue
@@ -1,51 +1,19 @@
1
- import type { AtomFamily } from "atom.io"
2
- import type { Json, JsonInterface } from "atom.io/json"
3
1
  import { newest } from ".."
4
- import type { Store } from ".."
5
- import type { Atom } from "../atom"
2
+ import type { Atom, Store } from ".."
6
3
  import { copyMutableIfNeeded } from "./copy-mutable-if-needed"
7
4
 
8
5
  export function copyMutableIfWithinTransaction<T>(
9
6
  oldValue: T,
10
- atom: Atom<T> | (Atom<T> & JsonInterface<T, Json.Serializable>),
7
+ atom: Atom<T>,
11
8
  store: Store,
12
9
  ): T {
13
10
  const target = newest(store)
14
11
  const parent = target.parent
15
12
  if (parent !== null) {
16
- if (`family` in atom) {
17
- const family = parent.families.get(atom.family.key)
18
- if (family && family.type === `atom_family`) {
19
- const result = copyMutableFamilyMemberWithinTransaction<T>(
20
- atom,
21
- family,
22
- parent,
23
- target,
24
- )
25
- if (result) {
26
- return result
27
- }
28
- }
29
- }
30
- if (`toJson` in atom && `fromJson` in atom) {
31
- const copiedValue = copyMutableIfNeeded(atom, atom, parent, target)
13
+ if (atom.type === `mutable_atom`) {
14
+ const copiedValue = copyMutableIfNeeded(atom, parent, target)
32
15
  return copiedValue
33
16
  }
34
17
  }
35
18
  return oldValue
36
19
  }
37
-
38
- export function copyMutableFamilyMemberWithinTransaction<T>(
39
- atom: Atom<T>,
40
- family:
41
- | AtomFamily<T, any>
42
- | (AtomFamily<T, any> & JsonInterface<T, Json.Serializable>),
43
- origin: Store,
44
- target: Store,
45
- ): T | null {
46
- if (`toJson` in family && `fromJson` in family) {
47
- const copyCreated = copyMutableIfNeeded(atom, family, origin, target)
48
- return copyCreated
49
- }
50
- return null
51
- }
@@ -1,11 +1,10 @@
1
1
  import type { StateUpdate } from "atom.io"
2
2
  import type { Store } from "atom.io/internal"
3
3
 
4
- import type { Atom } from "../atom"
5
- import type { ReadonlySelector, Selector } from "../selector"
4
+ import type { Atom, Selector } from ".."
6
5
 
7
6
  export const emitUpdate = <T>(
8
- state: Atom<T> | ReadonlySelector<T> | Selector<T>,
7
+ state: Atom<T> | Selector<T>,
9
8
  update: StateUpdate<T>,
10
9
  store: Store,
11
10
  ): void => {
@@ -1,4 +1,4 @@
1
- import type { Atom } from "../atom"
1
+ import type { Atom } from ".."
2
2
  import { evictCachedValue } from "../caching"
3
3
  import { isDone, markDone } from "../operation"
4
4
  import type { Store } from "../store"
@@ -1,15 +1,15 @@
1
- import type { Atom } from "../atom"
2
- import type { Selector } from "../selector"
1
+ import type { WritableState } from ".."
3
2
  import type { Store } from "../store"
4
3
  import { setAtom } from "./set-atom"
5
4
 
6
5
  export const setAtomOrSelector = <T>(
7
- state: Atom<T> | Selector<T>,
6
+ state: WritableState<T>,
8
7
  value: T | ((oldValue: T) => T),
9
8
  store: Store,
10
9
  ): void => {
11
10
  switch (state.type) {
12
11
  case `atom`:
12
+ case `mutable_atom`:
13
13
  setAtom(state, value, store)
14
14
  break
15
15
  case `selector`:
@@ -1,6 +1,7 @@
1
- import type { Atom } from "../atom"
1
+ import type { Atom } from ".."
2
2
  import { isAtomDefault, markAtomAsNotDefault } from "../atom"
3
3
  import { cacheValue } from "../caching"
4
+ import type { Transceiver } from "../mutable"
4
5
  import { markDone } from "../operation"
5
6
  import { readOrComputeValue } from "../read-or-compute-value"
6
7
  import type { Store } from "../store"
@@ -28,9 +29,12 @@ export const setAtom = <T>(
28
29
  const update = { oldValue, newValue }
29
30
  if (target.transactionMeta === null) {
30
31
  emitUpdate(atom, update, target)
31
- } else if (target.transactionMeta.phase === `applying` && target.parent) {
32
- emitUpdate(atom, update, target.parent)
33
- } else {
32
+ } else if (target.on.transactionApplying && target.parent) {
34
33
  stowUpdate(atom, update, target)
34
+ if (atom.key.startsWith(`*`)) {
35
+ const mutableKey = atom.key.slice(1)
36
+ const mutable: Transceiver<any> = target.valueMap.get(mutableKey)
37
+ mutable.do(update.newValue)
38
+ }
35
39
  }
36
40
  }
@@ -1,6 +1,6 @@
1
1
  import type { KeyedStateUpdate, StateUpdate } from "atom.io"
2
2
 
3
- import type { Atom } from "../atom"
3
+ import type { Atom } from ".."
4
4
  import { newest } from "../lineage"
5
5
  import { isTransceiver } from "../mutable"
6
6
  import type { Store } from "../store"