atom.io 0.15.6 → 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 +910 -887
  16. package/internal/dist/index.cjs.map +1 -1
  17. package/internal/dist/index.d.ts +157 -162
  18. package/internal/dist/index.js +482 -458
  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 +1 -2
  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,16 +1,15 @@
1
1
  import type {
2
- AtomOptions,
3
- AtomToken,
4
2
  FamilyMetadata,
5
3
  MutableAtomOptions,
4
+ RegularAtomOptions,
5
+ RegularAtomToken,
6
6
  UpdateHandler,
7
7
  } from "atom.io"
8
8
  import { setState } from "atom.io"
9
9
 
10
- import type { Atom } from "."
10
+ import type { RegularAtom } from ".."
11
11
  import { cacheValue } from "../caching"
12
12
  import { newest } from "../lineage"
13
- import { createMutableAtom } from "../mutable"
14
13
  import type { Store } from "../store"
15
14
  import { deposit } from "../store"
16
15
  import { Subject } from "../subject"
@@ -18,10 +17,10 @@ import { subscribeToState } from "../subscribe"
18
17
  import { markAtomAsDefault } from "./is-default"
19
18
 
20
19
  export function createRegularAtom<T>(
21
- options: AtomOptions<T> | MutableAtomOptions<any, any>,
20
+ options: MutableAtomOptions<any, any> | RegularAtomOptions<T>,
22
21
  family: FamilyMetadata | undefined,
23
22
  store: Store,
24
- ): AtomToken<T> {
23
+ ): RegularAtomToken<T> {
25
24
  store.logger.info(
26
25
  `🔨`,
27
26
  `atom`,
@@ -30,7 +29,7 @@ export function createRegularAtom<T>(
30
29
  )
31
30
  const target = newest(store)
32
31
  const existing = target.atoms.get(options.key)
33
- if (existing) {
32
+ if (existing && existing.type === `atom`) {
34
33
  store.logger.error(
35
34
  `❌`,
36
35
  `atom`,
@@ -40,7 +39,7 @@ export function createRegularAtom<T>(
40
39
  return deposit(existing)
41
40
  }
42
41
  const subject = new Subject<{ newValue: T; oldValue: T }>()
43
- const newAtom: Atom<T> = {
42
+ const newAtom: RegularAtom<T> = {
44
43
  ...options,
45
44
  type: `atom`,
46
45
  install: (store: Store) => {
@@ -50,9 +49,7 @@ export function createRegularAtom<T>(
50
49
  options.key,
51
50
  `installing in store "${store.config.name}"`,
52
51
  )
53
- return `mutable` in options
54
- ? createMutableAtom(options, family, store)
55
- : createRegularAtom(options, family, store)
52
+ return createRegularAtom(options, family, store)
56
53
  },
57
54
  subject,
58
55
  } as const
@@ -88,5 +85,5 @@ export function createRegularAtom<T>(
88
85
  }
89
86
  }
90
87
  store.on.atomCreation.next(token)
91
- return token as AtomToken<T>
88
+ return token
92
89
  }
@@ -0,0 +1,33 @@
1
+ import type {
2
+ AtomToken,
3
+ MutableAtomOptions,
4
+ MutableAtomToken,
5
+ RegularAtomOptions,
6
+ RegularAtomToken,
7
+ } from "atom.io"
8
+ import type { Json } from "atom.io/json"
9
+
10
+ import type { Transceiver } from "../mutable"
11
+ import { createMutableAtom } from "../mutable"
12
+ import type { Store } from "../store"
13
+ import { createRegularAtom } from "./create-regular-atom"
14
+
15
+ export function createStandaloneAtom<T>(
16
+ options: RegularAtomOptions<T>,
17
+ store: Store,
18
+ ): RegularAtomToken<T>
19
+ export function createStandaloneAtom<
20
+ T extends Transceiver<any>,
21
+ J extends Json.Serializable,
22
+ >(options: MutableAtomOptions<T, J>, store: Store): MutableAtomToken<T, J>
23
+ export function createStandaloneAtom<T>(
24
+ options: MutableAtomOptions<any, any> | RegularAtomOptions<T>,
25
+ store: Store,
26
+ ): AtomToken<T> {
27
+ const isMutable = `mutable` in options
28
+
29
+ if (isMutable) {
30
+ return createMutableAtom(options, undefined, store)
31
+ }
32
+ return createRegularAtom(options, undefined, store)
33
+ }
@@ -1,9 +1,12 @@
1
- import type { AtomToken } from "atom.io"
1
+ import type { RegularAtomToken } from "atom.io"
2
2
 
3
3
  import type { Store } from ".."
4
4
  import { deleteSelector, newest } from ".."
5
5
 
6
- export function deleteAtom(atomToken: AtomToken<unknown>, store: Store): void {
6
+ export function deleteAtom(
7
+ atomToken: RegularAtomToken<unknown>,
8
+ store: Store,
9
+ ): void {
7
10
  const target = newest(store)
8
11
  const { key } = atomToken
9
12
  const atom = target.atoms.get(key)
@@ -1,19 +1,4 @@
1
- import type { FamilyMetadata } from "~/packages/atom.io/src"
2
- import type { Store } from "../store"
3
- import type { Subject } from "../subject"
4
-
5
- export * from "./create-atom"
1
+ export * from "./create-standalone-atom"
6
2
  export * from "./create-regular-atom"
7
3
  export * from "./delete-atom"
8
4
  export * from "./is-default"
9
-
10
- export type Atom<T> = {
11
- key: string
12
- type: `atom`
13
- mutable?: boolean
14
- family?: FamilyMetadata
15
- install: (store: Store) => void
16
- subject: Subject<{ newValue: T; oldValue: T }>
17
- default: T | (() => T)
18
- cleanup?: () => void
19
- }
@@ -1,5 +1,4 @@
1
1
  import { newest } from "../lineage"
2
- import { traceAllSelectorAtoms } from "../selector"
3
2
  import type { Store } from "../store"
4
3
 
5
4
  export const isAtomDefault = (key: string, store: Store): boolean => {
@@ -1,5 +1,5 @@
1
- import type { ReadableToken, StateUpdate } from "atom.io"
2
- import type { StateNode } from "."
1
+ import type { StateUpdate } from "atom.io"
2
+ import type { ReadableState } from "."
3
3
  import { Future } from "./future"
4
4
  import { copyMutableIfWithinTransaction } from "./set-state/copy-mutable-in-transaction"
5
5
  import type { Store } from "./store"
@@ -49,7 +49,10 @@ export function cacheValue<T>(
49
49
  return value
50
50
  }
51
51
 
52
- export const readCachedValue = <T>(token: StateNode<any>, target: Store): T => {
52
+ export const readCachedValue = <T>(
53
+ token: ReadableState<any>,
54
+ target: Store,
55
+ ): T => {
53
56
  let value = target.valueMap.get(token.key) as T
54
57
  if (token.type === `atom`) {
55
58
  value = copyMutableIfWithinTransaction(value, token, target)
@@ -1,8 +1,8 @@
1
1
  import type {
2
- AtomFamily,
3
- AtomFamilyOptions,
4
2
  MutableAtomFamily,
5
3
  MutableAtomFamilyOptions,
4
+ RegularAtomFamily,
5
+ RegularAtomFamilyOptions,
6
6
  } from "atom.io"
7
7
  import type { Json } from "atom.io/json"
8
8
 
@@ -19,14 +19,18 @@ export function createAtomFamily<
19
19
  store: Store,
20
20
  ): MutableAtomFamily<T, J, K>
21
21
  export function createAtomFamily<T, K extends Json.Serializable>(
22
- options: AtomFamilyOptions<T, K>,
22
+ options: RegularAtomFamilyOptions<T, K>,
23
23
  store: Store,
24
- ): AtomFamily<T, K>
24
+ ): RegularAtomFamily<T, K>
25
25
  export function createAtomFamily<T, K extends Json.Serializable>(
26
- options: AtomFamilyOptions<T, K> | MutableAtomFamilyOptions<any, any, any>,
26
+ options:
27
+ | MutableAtomFamilyOptions<any, any, any>
28
+ | RegularAtomFamilyOptions<T, K>,
27
29
  store: Store,
28
- ): AtomFamily<T, K> | MutableAtomFamily<any, any, any> {
29
- if (`mutable` in options) {
30
+ ): MutableAtomFamily<any, any, any> | RegularAtomFamily<T, K> {
31
+ const isMutable = `mutable` in options
32
+
33
+ if (isMutable) {
30
34
  return createMutableAtomFamily(options, store)
31
35
  }
32
36
  return createRegularAtomFamily<T, K>(options, store)
@@ -8,8 +8,9 @@ import type { Json } from "atom.io/json"
8
8
  import { stringifyJson } from "atom.io/json"
9
9
 
10
10
  import { newest } from "../lineage"
11
- import { createSelector } from "../selector"
12
- import { type Store, deposit } from "../store"
11
+ import { createReadonlySelector } from "../selector"
12
+ import type { Store } from "../store"
13
+ import { deposit } from "../store"
13
14
  import { Subject } from "../subject"
14
15
 
15
16
  export function createReadonlySelectorFamily<T, K extends Json.Serializable>(
@@ -27,7 +28,7 @@ export function createReadonlySelectorFamily<T, K extends Json.Serializable>(
27
28
  if (existing) {
28
29
  return deposit(existing)
29
30
  }
30
- return createSelector<T>(
31
+ return createReadonlySelector(
31
32
  {
32
33
  key: fullKey,
33
34
  get: options.get(key),
@@ -1,37 +1,35 @@
1
1
  import type {
2
- AtomFamily,
3
- AtomFamilyOptions,
4
- AtomOptions,
5
- AtomToken,
6
2
  FamilyMetadata,
7
- MutableAtomFamilyOptions,
3
+ RegularAtomFamily,
4
+ RegularAtomFamilyOptions,
5
+ RegularAtomOptions,
6
+ RegularAtomToken,
8
7
  } from "atom.io"
9
8
  import type { Json } from "atom.io/json"
10
9
  import { stringifyJson } from "atom.io/json"
11
10
 
12
11
  import { createRegularAtom } from "../atom"
13
12
  import { newest } from "../lineage"
14
- import { createMutableAtom } from "../mutable"
15
13
  import { deposit, withdraw } from "../store"
16
14
  import type { Store } from "../store"
17
15
  import { Subject } from "../subject"
18
16
 
19
17
  export function createRegularAtomFamily<T, K extends Json.Serializable>(
20
- options: AtomFamilyOptions<T, K> | MutableAtomFamilyOptions<any, any, K>,
18
+ options: RegularAtomFamilyOptions<T, K>,
21
19
  store: Store,
22
- ): AtomFamily<T, K> {
23
- const subject = new Subject<AtomToken<T>>()
24
- const atomFamily = Object.assign(
25
- (key: K): AtomToken<T> => {
20
+ ): RegularAtomFamily<T, K> {
21
+ const subject = new Subject<RegularAtomToken<T>>()
22
+ const atomFamily: RegularAtomFamily<T, K> = Object.assign(
23
+ (key: K): RegularAtomToken<any> => {
26
24
  const subKey = stringifyJson(key)
27
25
  const family: FamilyMetadata = { key: options.key, subKey }
28
26
  const fullKey = `${options.key}(${subKey})`
29
27
  const existing = withdraw({ key: fullKey, type: `atom` }, store)
30
- let token: AtomToken<any>
28
+ let token: RegularAtomToken<any>
31
29
  if (existing) {
32
30
  token = deposit(existing)
33
31
  } else {
34
- const individualOptions: AtomOptions<any> = {
32
+ const individualOptions: RegularAtomOptions<any> = {
35
33
  key: fullKey,
36
34
  default:
37
35
  options.default instanceof Function
@@ -41,17 +39,7 @@ export function createRegularAtomFamily<T, K extends Json.Serializable>(
41
39
  if (options.effects) {
42
40
  individualOptions.effects = options.effects(key)
43
41
  }
44
- if (`mutable` in options) {
45
- const mutableOptions = {
46
- ...individualOptions,
47
- mutable: true,
48
- toJson: options.toJson,
49
- fromJson: options.fromJson,
50
- } as const
51
- token = createMutableAtom(mutableOptions, family, store)
52
- } else {
53
- token = createRegularAtom<T>(individualOptions, family, store)
54
- }
42
+ token = createRegularAtom(individualOptions, family, store)
55
43
  subject.next(token)
56
44
  }
57
45
  return token
@@ -63,9 +51,6 @@ export function createRegularAtomFamily<T, K extends Json.Serializable>(
63
51
  install: (store: Store) => createRegularAtomFamily(options, store),
64
52
  } as const,
65
53
  )
66
- if (`mutable` in options && typeof options.mutable === `boolean`) {
67
- Object.assign(atomFamily, { mutable: options.mutable })
68
- }
69
54
  const target = newest(store)
70
55
  target.families.set(options.key, atomFamily)
71
56
  return atomFamily
@@ -1,69 +1,33 @@
1
1
  import type {
2
- FamilyMetadata,
3
2
  ReadonlySelectorFamily,
4
3
  ReadonlySelectorFamilyOptions,
5
- SelectorFamily,
6
- SelectorFamilyOptions,
7
- SelectorToken,
4
+ WritableSelectorFamily,
5
+ WritableSelectorFamilyOptions,
8
6
  } from "atom.io"
9
7
  import type { Json } from "atom.io/json"
10
- import { stringifyJson } from "atom.io/json"
11
8
 
12
- import { newest } from "../lineage"
13
- import { createSelector } from "../selector"
14
9
  import type { Store } from "../store"
15
- import { deposit } from "../store"
16
- import { Subject } from "../subject"
17
10
  import { createReadonlySelectorFamily } from "./create-readonly-selector-family"
11
+ import { createWritableSelectorFamily } from "./create-writable-selector-family"
18
12
 
19
13
  export function createSelectorFamily<T, K extends Json.Serializable>(
20
- options: SelectorFamilyOptions<T, K>,
14
+ options: WritableSelectorFamilyOptions<T, K>,
21
15
  store: Store,
22
- ): SelectorFamily<T, K>
16
+ ): WritableSelectorFamily<T, K>
23
17
  export function createSelectorFamily<T, K extends Json.Serializable>(
24
18
  options: ReadonlySelectorFamilyOptions<T, K>,
25
19
  store: Store,
26
20
  ): ReadonlySelectorFamily<T, K>
27
21
  export function createSelectorFamily<T, K extends Json.Serializable>(
28
- options: ReadonlySelectorFamilyOptions<T, K> | SelectorFamilyOptions<T, K>,
22
+ options:
23
+ | ReadonlySelectorFamilyOptions<T, K>
24
+ | WritableSelectorFamilyOptions<T, K>,
29
25
  store: Store,
30
- ): ReadonlySelectorFamily<T, K> | SelectorFamily<T, K> {
31
- const isReadonly = !(`set` in options)
26
+ ): ReadonlySelectorFamily<T, K> | WritableSelectorFamily<T, K> {
27
+ const isWritable = `set` in options
32
28
 
33
- if (isReadonly) {
34
- return createReadonlySelectorFamily(options, store)
29
+ if (isWritable) {
30
+ return createWritableSelectorFamily(options, store)
35
31
  }
36
- const target = newest(store)
37
- const subject = new Subject<SelectorToken<T>>()
38
-
39
- const selectorFamily = Object.assign(
40
- (key: K): SelectorToken<T> => {
41
- const subKey = stringifyJson(key)
42
- const family: FamilyMetadata = { key: options.key, subKey }
43
- const fullKey = `${options.key}(${subKey})`
44
- const existing = target.selectors.get(fullKey)
45
- if (existing) {
46
- return deposit(existing)
47
- }
48
- const token = createSelector<T>(
49
- {
50
- key: fullKey,
51
- get: options.get(key),
52
- set: options.set(key),
53
- },
54
- family,
55
- store,
56
- )
57
- subject.next(token)
58
- return token
59
- },
60
- {
61
- key: options.key,
62
- type: `selector_family`,
63
- subject,
64
- install: (store: Store) => createSelectorFamily(options, store),
65
- } as const,
66
- ) as SelectorFamily<T, K>
67
- target.families.set(options.key, selectorFamily)
68
- return selectorFamily
32
+ return createReadonlySelectorFamily(options, store)
69
33
  }
@@ -0,0 +1,51 @@
1
+ import type {
2
+ FamilyMetadata,
3
+ WritableSelectorFamily,
4
+ WritableSelectorFamilyOptions,
5
+ WritableSelectorToken,
6
+ } from "atom.io"
7
+ import type { Json } from "atom.io/json"
8
+ import { stringifyJson } from "atom.io/json"
9
+
10
+ import { createWritableSelector } from "../selector"
11
+ import type { Store } from "../store"
12
+ import { deposit } from "../store"
13
+ import { Subject } from "../subject"
14
+
15
+ export function createWritableSelectorFamily<T, K extends Json.Serializable>(
16
+ options: WritableSelectorFamilyOptions<T, K>,
17
+ store: Store,
18
+ ): WritableSelectorFamily<T, K> {
19
+ const subject = new Subject<WritableSelectorToken<T>>()
20
+
21
+ const selectorFamily = Object.assign(
22
+ (key: K): WritableSelectorToken<T> => {
23
+ const subKey = stringifyJson(key)
24
+ const family: FamilyMetadata = { key: options.key, subKey }
25
+ const fullKey = `${options.key}(${subKey})`
26
+ const existing = store.selectors.get(fullKey)
27
+ if (existing) {
28
+ return deposit(existing)
29
+ }
30
+ const token = createWritableSelector(
31
+ {
32
+ key: fullKey,
33
+ get: options.get(key),
34
+ set: options.set(key),
35
+ },
36
+ family,
37
+ store,
38
+ )
39
+ subject.next(token)
40
+ return token
41
+ },
42
+ {
43
+ key: options.key,
44
+ type: `selector_family`,
45
+ subject,
46
+ install: (store: Store) => createWritableSelectorFamily(options, store),
47
+ } as const,
48
+ ) as WritableSelectorFamily<T, K>
49
+ store.families.set(options.key, selectorFamily)
50
+ return selectorFamily
51
+ }
@@ -1,5 +1,9 @@
1
- import type { Atom } from "./atom"
2
- import type { ReadonlySelector, Selector } from "./selector"
1
+ import type { FamilyMetadata } from "atom.io"
2
+ import type { Json, JsonInterface } from "atom.io/json"
3
+
4
+ import type { Transceiver } from "./mutable"
5
+ import type { Store } from "./store"
6
+ import type { Subject } from "./subject"
3
7
 
4
8
  export * from "./atom"
5
9
  export * from "./caching"
@@ -22,4 +26,41 @@ export * from "./subscribe"
22
26
  export * from "./timeline"
23
27
  export * from "./transaction"
24
28
 
25
- export type StateNode<T> = Atom<T> | ReadonlySelector<T> | Selector<T>
29
+ export type BaseStateData = {
30
+ key: string
31
+ family?: FamilyMetadata
32
+ install: (store: Store) => void
33
+ subject: Subject<{ newValue: any; oldValue: any }>
34
+ }
35
+
36
+ export type RegularAtom<T> = BaseStateData & {
37
+ type: `atom`
38
+ default: T | (() => T)
39
+ cleanup?: () => void
40
+ }
41
+ export type MutableAtom<
42
+ T extends Transceiver<any>,
43
+ J extends Json.Serializable,
44
+ > = BaseStateData &
45
+ JsonInterface<T, J> & {
46
+ type: `mutable_atom`
47
+ default: T | (() => T)
48
+ cleanup?: () => void
49
+ }
50
+ export type Atom<T> =
51
+ | RegularAtom<T>
52
+ | (T extends Transceiver<any> ? MutableAtom<T, any> : never)
53
+
54
+ export type WritableSelector<T> = BaseStateData & {
55
+ type: `selector`
56
+ get: () => T
57
+ set: (newValue: T | ((oldValue: T) => T)) => void
58
+ }
59
+ export type ReadonlySelector<T> = BaseStateData & {
60
+ type: `readonly_selector`
61
+ get: () => T
62
+ }
63
+ export type Selector<T> = ReadonlySelector<T> | WritableSelector<T>
64
+
65
+ export type WritableState<T> = Atom<T> | WritableSelector<T>
66
+ export type ReadableState<T> = Atom<T> | Selector<T>
@@ -9,10 +9,3 @@ export function newest<T extends Lineage>(scion: T): T {
9
9
  }
10
10
  return scion
11
11
  }
12
-
13
- export function eldest<T extends Lineage>(scion: T): T {
14
- while (scion.parent !== null) {
15
- scion = scion.parent
16
- }
17
- return scion
18
- }
@@ -1,25 +1,71 @@
1
- import type { MutableAtomFamily, MutableAtomFamilyOptions } from "atom.io"
1
+ import type {
2
+ MutableAtomFamily,
3
+ MutableAtomFamilyOptions,
4
+ MutableAtomOptions,
5
+ MutableAtomToken,
6
+ } from "atom.io"
7
+ import type { FamilyMetadata } from "atom.io"
2
8
  import type { Json } from "atom.io/json"
3
9
  import { selectJsonFamily } from "atom.io/json"
10
+ import { stringifyJson } from "atom.io/json"
4
11
 
5
- import type { Store } from ".."
6
- import { createRegularAtomFamily } from ".."
12
+ import { newest } from "../lineage"
13
+ import { createMutableAtom } from "../mutable"
14
+ import { deposit, withdraw } from "../store"
15
+ import type { Store } from "../store"
16
+ import { Subject } from "../subject"
7
17
  import { FamilyTracker } from "./tracker-family"
8
18
  import type { Transceiver } from "./transceiver"
9
19
 
10
20
  export function createMutableAtomFamily<
11
- Core extends Transceiver<any>,
12
- SerializableCore extends Json.Serializable,
13
- Key extends string,
21
+ T extends Transceiver<any>,
22
+ J extends Json.Serializable,
23
+ K extends string,
14
24
  >(
15
- options: MutableAtomFamilyOptions<Core, SerializableCore, Key>,
25
+ options: MutableAtomFamilyOptions<T, J, K>,
16
26
  store: Store,
17
- ): MutableAtomFamily<Core, SerializableCore, Key> {
18
- const coreFamily = Object.assign(
19
- createRegularAtomFamily<Core, Key>(options, store),
20
- options,
21
- ) as MutableAtomFamily<Core, SerializableCore, Key>
22
- selectJsonFamily(coreFamily, options)
23
- new FamilyTracker(coreFamily, store)
24
- return coreFamily
27
+ ): MutableAtomFamily<T, J, K> {
28
+ const subject = new Subject<MutableAtomToken<T, J>>()
29
+ const atomFamily: MutableAtomFamily<T, J, K> = Object.assign(
30
+ (key: K): MutableAtomToken<T, J> => {
31
+ const subKey = stringifyJson(key)
32
+ const family: FamilyMetadata = { key: options.key, subKey }
33
+ const fullKey = `${options.key}(${subKey})`
34
+ const existing = withdraw({ key: fullKey, type: `mutable_atom` }, store)
35
+ let token: MutableAtomToken<T, J>
36
+ if (existing) {
37
+ token = deposit(existing)
38
+ } else {
39
+ const individualOptions: MutableAtomOptions<T, J> = {
40
+ key: fullKey,
41
+ default: () => options.default(key),
42
+ toJson: options.toJson,
43
+ fromJson: options.fromJson,
44
+ mutable: true,
45
+ }
46
+ if (options.effects) {
47
+ individualOptions.effects = options.effects(key)
48
+ }
49
+
50
+ token = createMutableAtom(individualOptions, family, store)
51
+
52
+ subject.next(token)
53
+ }
54
+ return token
55
+ },
56
+ {
57
+ key: options.key,
58
+ type: `mutable_atom_family`,
59
+ subject,
60
+ install: (store: Store) => createMutableAtomFamily(options, store),
61
+ toJson: options.toJson,
62
+ fromJson: options.fromJson,
63
+ } as const,
64
+ )
65
+
66
+ const target = newest(store)
67
+ target.families.set(options.key, atomFamily)
68
+ selectJsonFamily(atomFamily, options, store)
69
+ new FamilyTracker(atomFamily, store)
70
+ return atomFamily
25
71
  }