atom.io 0.35.0 → 0.36.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/eslint-plugin/index.d.ts +2 -18
  2. package/dist/eslint-plugin/index.d.ts.map +1 -1
  3. package/dist/eslint-plugin/index.js +4 -141
  4. package/dist/eslint-plugin/index.js.map +1 -1
  5. package/dist/internal/index.d.ts +100 -78
  6. package/dist/internal/index.d.ts.map +1 -1
  7. package/dist/internal/index.js +180 -163
  8. package/dist/internal/index.js.map +1 -1
  9. package/dist/introspection/index.d.ts +5 -6
  10. package/dist/introspection/index.d.ts.map +1 -1
  11. package/dist/introspection/index.js +2 -3
  12. package/dist/introspection/index.js.map +1 -1
  13. package/dist/json/index.d.ts +2 -10
  14. package/dist/json/index.d.ts.map +1 -1
  15. package/dist/json/index.js +1 -31
  16. package/dist/json/index.js.map +1 -1
  17. package/dist/main/index.d.ts +38 -39
  18. package/dist/main/index.d.ts.map +1 -1
  19. package/dist/main/index.js +15 -16
  20. package/dist/main/index.js.map +1 -1
  21. package/dist/react/index.d.ts +4 -4
  22. package/dist/react/index.d.ts.map +1 -1
  23. package/dist/react/index.js.map +1 -1
  24. package/dist/react-devtools/index.js.map +1 -1
  25. package/dist/realtime/index.d.ts +4 -4
  26. package/dist/realtime/index.d.ts.map +1 -1
  27. package/dist/realtime/index.js +2 -6
  28. package/dist/realtime/index.js.map +1 -1
  29. package/dist/realtime-client/index.d.ts +7 -8
  30. package/dist/realtime-client/index.d.ts.map +1 -1
  31. package/dist/realtime-client/index.js +3 -4
  32. package/dist/realtime-client/index.js.map +1 -1
  33. package/dist/realtime-react/index.d.ts +4 -4
  34. package/dist/realtime-react/index.d.ts.map +1 -1
  35. package/dist/realtime-react/index.js.map +1 -1
  36. package/dist/realtime-server/index.d.ts +18 -18
  37. package/dist/realtime-server/index.d.ts.map +1 -1
  38. package/dist/realtime-server/index.js +5 -9
  39. package/dist/realtime-server/index.js.map +1 -1
  40. package/dist/transceivers/set-rtx/index.d.ts +9 -2
  41. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  42. package/dist/transceivers/set-rtx/index.js +3 -0
  43. package/dist/transceivers/set-rtx/index.js.map +1 -1
  44. package/package.json +6 -6
  45. package/src/eslint-plugin/index.ts +0 -1
  46. package/src/eslint-plugin/rules/explicit-state-types.ts +8 -1
  47. package/src/eslint-plugin/rules/index.ts +0 -1
  48. package/src/internal/atom/create-regular-atom.ts +5 -5
  49. package/src/internal/atom/dispose-atom.ts +1 -0
  50. package/src/internal/atom/has-role.ts +12 -0
  51. package/src/internal/atom/index.ts +1 -0
  52. package/src/internal/caching.ts +38 -16
  53. package/src/internal/families/find-in-store.ts +4 -5
  54. package/src/internal/families/get-family-of-token.ts +4 -5
  55. package/src/internal/families/init-family-member.ts +3 -4
  56. package/src/internal/families/seek-in-store.ts +4 -5
  57. package/src/internal/get-state/read-or-compute-value.ts +37 -16
  58. package/src/internal/index.ts +19 -21
  59. package/src/internal/ingest-updates/ingest-creation-disposal.ts +18 -15
  60. package/src/internal/ingest-updates/ingest-selector-update.ts +9 -5
  61. package/src/internal/join/get-internal-relations-from-store.ts +2 -2
  62. package/src/internal/join/join-internal.ts +10 -18
  63. package/src/internal/molecule.ts +1 -0
  64. package/src/internal/mutable/create-mutable-atom-family.ts +40 -22
  65. package/src/internal/mutable/create-mutable-atom.ts +16 -12
  66. package/src/internal/mutable/get-json-family.ts +7 -6
  67. package/src/internal/mutable/get-json-token.ts +6 -13
  68. package/src/internal/mutable/get-update-family.ts +7 -8
  69. package/src/internal/mutable/get-update-token.ts +5 -9
  70. package/src/internal/mutable/tracker-family.ts +31 -38
  71. package/src/internal/mutable/tracker.ts +86 -104
  72. package/src/internal/mutable/transceiver.ts +37 -9
  73. package/src/internal/selector/create-readonly-held-selector.ts +2 -2
  74. package/src/internal/selector/create-readonly-pure-selector.ts +2 -2
  75. package/src/internal/selector/create-writable-held-selector.ts +3 -3
  76. package/src/internal/selector/create-writable-pure-selector.ts +3 -3
  77. package/src/internal/selector/dispose-selector.ts +9 -9
  78. package/src/internal/set-state/reset-atom-or-selector.ts +11 -4
  79. package/src/internal/set-state/set-atom.ts +15 -22
  80. package/src/internal/set-state/set-into-store.ts +5 -4
  81. package/src/internal/store/counterfeit.ts +3 -4
  82. package/src/internal/store/deposit.ts +8 -11
  83. package/src/internal/store/store.ts +7 -7
  84. package/src/internal/store/withdraw.ts +8 -12
  85. package/src/internal/subscribe/subscribe-in-store.ts +2 -2
  86. package/src/internal/subscribe/subscribe-to-transaction.ts +2 -2
  87. package/src/internal/timeline/create-timeline.ts +3 -3
  88. package/src/internal/transaction/act-upon-store.ts +2 -2
  89. package/src/internal/transaction/apply-transaction.ts +2 -2
  90. package/src/internal/transaction/build-transaction.ts +2 -2
  91. package/src/internal/transaction/create-transaction.ts +3 -3
  92. package/src/internal/transaction/index.ts +2 -2
  93. package/src/internal/transaction/is-root-store.ts +4 -2
  94. package/src/internal/utility-types.ts +1 -1
  95. package/src/introspection/attach-introspection-states.ts +3 -3
  96. package/src/introspection/attach-transaction-index.ts +4 -4
  97. package/src/introspection/attach-transaction-logs.ts +4 -4
  98. package/src/introspection/auditor.ts +3 -3
  99. package/src/json/index.ts +0 -2
  100. package/src/main/atom.ts +24 -36
  101. package/src/main/dispose-state.ts +6 -5
  102. package/src/main/find-state.ts +3 -4
  103. package/src/main/get-state.ts +6 -5
  104. package/src/main/join.ts +2 -2
  105. package/src/main/logger.ts +7 -7
  106. package/src/main/reset-state.ts +3 -3
  107. package/src/main/set-state.ts +3 -3
  108. package/src/main/subscribe.ts +3 -3
  109. package/src/main/tokens.ts +8 -14
  110. package/src/main/transaction.ts +17 -13
  111. package/src/main/validators.ts +1 -1
  112. package/src/react/use-json.ts +14 -24
  113. package/src/react-devtools/TransactionIndex.tsx +3 -3
  114. package/src/react-devtools/Updates.tsx +2 -2
  115. package/src/realtime/shared-room-store.ts +11 -22
  116. package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +2 -2
  117. package/src/realtime-client/pull-mutable-atom-family-member.ts +8 -17
  118. package/src/realtime-client/pull-mutable-atom.ts +7 -14
  119. package/src/realtime-client/push-state.ts +6 -5
  120. package/src/realtime-client/server-action.ts +5 -4
  121. package/src/realtime-react/use-pull-mutable-atom.ts +3 -5
  122. package/src/realtime-react/use-pull-mutable-family-member.ts +3 -4
  123. package/src/realtime-react/use-server-action.ts +2 -2
  124. package/src/realtime-server/realtime-mutable-family-provider.ts +3 -4
  125. package/src/realtime-server/realtime-mutable-provider.ts +2 -3
  126. package/src/realtime-server/realtime-server-stores/server-room-external-actions.ts +6 -5
  127. package/src/realtime-server/realtime-server-stores/server-user-store.ts +8 -15
  128. package/src/transceivers/set-rtx/set-rtx.ts +14 -1
  129. package/src/eslint-plugin/rules/synchronous-selector-dependencies.ts +0 -140
  130. package/src/eslint-plugin/walk.ts +0 -81
  131. package/src/internal/set-state/copy-mutable-if-needed.ts +0 -27
  132. package/src/json/select-json-family.ts +0 -55
  133. package/src/json/select-json.ts +0 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atom.io",
3
- "version": "0.35.0",
3
+ "version": "0.36.1",
4
4
  "description": "Composable and testable reactive data library.",
5
5
  "homepage": "https://atom.io.fyi",
6
6
  "sideEffects": false,
@@ -60,12 +60,12 @@
60
60
  }
61
61
  },
62
62
  "devDependencies": {
63
- "@eslint/core": "0.15.1",
63
+ "@eslint/core": "0.15.2",
64
64
  "@storybook/addon-docs": "9.1.1",
65
65
  "@storybook/addon-onboarding": "9.1.1",
66
66
  "@storybook/react-vite": "9.1.1",
67
67
  "@testing-library/react": "16.3.0",
68
- "@types/bun": "npm:bun-types@1.2.19",
68
+ "@types/bun": "npm:bun-types@1.2.20",
69
69
  "@types/eslint": "9.6.1",
70
70
  "@types/estree": "1.0.8",
71
71
  "@types/http-proxy": "1.17.16",
@@ -80,7 +80,7 @@
80
80
  "concurrently": "9.2.0",
81
81
  "drizzle-kit": "0.31.4",
82
82
  "drizzle-orm": "0.44.4",
83
- "eslint": "9.32.0",
83
+ "eslint": "9.33.0",
84
84
  "happy-dom": "18.0.1",
85
85
  "http-proxy": "1.18.1",
86
86
  "motion": "12.23.12",
@@ -95,8 +95,8 @@
95
95
  "socket.io": "4.8.1",
96
96
  "socket.io-client": "4.8.1",
97
97
  "storybook": "9.1.1",
98
- "tmp": "0.2.4",
99
- "tsdown": "0.13.3",
98
+ "tmp": "0.2.5",
99
+ "tsdown": "0.14.0",
100
100
  "tsx": "4.20.3",
101
101
  "typescript": "5.9.2",
102
102
  "vite": "7.1.1",
@@ -7,7 +7,6 @@ export { Rules }
7
7
  const plugin: ESLint.Plugin = {
8
8
  rules: {
9
9
  "explicit-state-types": Rules.explicitStateTypes as any,
10
- "synchronous-selector-dependencies": Rules.synchronousSelectorDependencies,
11
10
  },
12
11
  } satisfies ESLint.Plugin
13
12
 
@@ -5,7 +5,14 @@ const createRule = ESLintUtils.RuleCreator(
5
5
  (name) => `https://atom.io.fyi/docs/eslint-plugin#${name}`,
6
6
  )
7
7
 
8
- const STATE_FUNCTIONS = [`atom`, `atomFamily`, `selector`, `selectorFamily`]
8
+ const STATE_FUNCTIONS = [
9
+ `atom`,
10
+ `atomFamily`,
11
+ `mutableAtom`,
12
+ `mutableAtomFamily`,
13
+ `selector`,
14
+ `selectorFamily`,
15
+ ]
9
16
 
10
17
  export const explicitStateTypes: ESLintUtils.RuleModule<
11
18
  `noTypeArgument`,
@@ -1,2 +1 @@
1
1
  export * from "./explicit-state-types"
2
- export * from "./synchronous-selector-dependencies"
@@ -11,11 +11,13 @@ import type { Store } from "../store"
11
11
  import { deposit } from "../store"
12
12
  import { Subject } from "../subject"
13
13
  import { subscribeToState } from "../subscribe"
14
+ import type { internalRole } from "./has-role"
14
15
 
15
16
  export function createRegularAtom<T>(
16
17
  store: Store,
17
18
  options: RegularAtomOptions<T>,
18
19
  family: FamilyMetadata | undefined,
20
+ internalRoles?: internalRole[],
19
21
  ): RegularAtomToken<T> {
20
22
  const type = `atom`
21
23
  const { key } = options
@@ -49,12 +51,10 @@ export function createRegularAtom<T>(
49
51
  if (family) {
50
52
  newAtom.family = family
51
53
  }
52
- // let initialValue = def
53
- // if (def instanceof Function) {
54
- // initialValue = def()
55
- // }
54
+ if (internalRoles) {
55
+ newAtom.internalRoles = internalRoles
56
+ }
56
57
  target.atoms.set(key, newAtom)
57
- // cacheValue(target, key, initialValue, subject)
58
58
  const token = deposit(newAtom)
59
59
  if (options.effects) {
60
60
  let effectIndex = 0
@@ -29,6 +29,7 @@ export function disposeAtom(store: Store, atomToken: AtomToken<unknown>): void {
29
29
  target.valueMap.delete(key)
30
30
  target.selectorAtoms.delete(key)
31
31
  target.atomsThatAreDefault.delete(key)
32
+ target.moleculeData.delete(family.key, family.subKey)
32
33
  store.timelineTopics.delete(key)
33
34
 
34
35
  if (atomToken.type === `mutable_atom`) {
@@ -0,0 +1,12 @@
1
+ import type { Atom } from ".."
2
+
3
+ export const INTERNAL_ROLES = [`tracker:signal`] as const
4
+ export type internalRole = (typeof INTERNAL_ROLES)[number]
5
+
6
+ export function hasRole(atom: Atom<any>, role: internalRole): boolean {
7
+ if (`internalRoles` in atom === false) {
8
+ return false
9
+ }
10
+
11
+ return atom.internalRoles.includes(role)
12
+ }
@@ -1,2 +1,3 @@
1
1
  export * from "./create-regular-atom"
2
2
  export * from "./dispose-atom"
3
+ export * from "./has-role"
@@ -1,9 +1,8 @@
1
1
  import type { StateUpdate } from "atom.io"
2
2
 
3
- import type { ReadableState } from "."
4
- import { closeOperation, isChildStore, openOperation } from "."
3
+ import type { ReadableState, Transceiver } from "."
4
+ import { closeOperation, isChildStore, openOperation, Tracker } from "."
5
5
  import { Future } from "./future"
6
- import { copyMutableIfNeeded } from "./set-state/copy-mutable-if-needed"
7
6
  import {
8
7
  evictDownStream,
9
8
  evictDownStreamFromSelector,
@@ -11,19 +10,19 @@ import {
11
10
  import type { Store } from "./store"
12
11
  import type { Subject } from "./subject"
13
12
 
14
- export function cacheValue<T>(
15
- store: Store,
13
+ export function writeToCache<T>(
14
+ target: Store,
16
15
  key: string,
17
16
  value: T,
18
17
  subject: Subject<StateUpdate<unknown>>,
19
18
  ): T
20
- export function cacheValue<T extends Promise<any>>(
21
- store: Store,
19
+ export function writeToCache<T extends Promise<any>>(
20
+ target: Store,
22
21
  key: string,
23
22
  value: T,
24
23
  subject: Subject<StateUpdate<unknown>>,
25
- ): Future<T>
26
- export function cacheValue<T>(
24
+ ): Future<Awaited<T>>
25
+ export function writeToCache<T>(
27
26
  target: Store,
28
27
  key: string,
29
28
  value: T,
@@ -46,7 +45,7 @@ export function cacheValue<T>(
46
45
  .then(function handleResolvedFuture(resolved) {
47
46
  const current = target.valueMap.get(key)
48
47
  if (current === future) {
49
- cacheValue(target, key, resolved, subject)
48
+ writeToCache(target, key, resolved, subject)
50
49
  const atom = target.atoms.get(key)
51
50
  if (atom) {
52
51
  openOperation(target, atom)
@@ -74,21 +73,44 @@ export function cacheValue<T>(
74
73
  return value
75
74
  }
76
75
 
77
- export const readCachedValue = <T>(
78
- state: ReadableState<any>,
76
+ /**
77
+ * @param target - the newest layer of the store
78
+ * @param state - the state to read from cache
79
+ * @param mut - whether the value is intended to be mutable
80
+ * @returns the state's current value
81
+ */
82
+ export function readFromCache<T>(
79
83
  target: Store,
80
- ): T => {
84
+ state: ReadableState<T>,
85
+ mut: `mut` | undefined,
86
+ ): T {
81
87
  target.logger.info(`📖`, state.type, state.key, `reading cached value`)
82
88
  let value = target.valueMap.get(state.key) as T
83
- if (state.type === `mutable_atom` && isChildStore(target)) {
89
+
90
+ const mayNeedToBeCopied =
91
+ mut === `mut` && state.type === `mutable_atom` && isChildStore(target)
92
+ if (mayNeedToBeCopied) {
93
+ const mutableAtom = state
84
94
  const { parent } = target
85
- const copiedValue = copyMutableIfNeeded(target, state, parent)
95
+
96
+ if (target.valueMap.hasOwn(mutableAtom.key)) {
97
+ return value
98
+ }
99
+
100
+ const parentValue = parent.valueMap.get(mutableAtom.key) as T &
101
+ Transceiver<any, any, any>
102
+
103
+ target.logger.info(`📃`, `atom`, mutableAtom.key, `copying`)
104
+ const jsonValue = parentValue.toJSON()
105
+ const copiedValue = mutableAtom.class.fromJSON(jsonValue)
106
+ target.valueMap.set(mutableAtom.key, copiedValue)
107
+ new Tracker(mutableAtom, parent)
86
108
  value = copiedValue
87
109
  }
88
110
  return value
89
111
  }
90
112
 
91
- export const evictCachedValue = (target: Store, key: string): void => {
113
+ export function evictCachedValue(target: Store, key: string): void {
92
114
  const currentValue = target.valueMap.get(key)
93
115
  if (currentValue instanceof Future) {
94
116
  const selector =
@@ -16,7 +16,7 @@ import type {
16
16
  WritablePureSelectorToken,
17
17
  WritableToken,
18
18
  } from "atom.io"
19
- import { type Canonical, type Json, stringifyJson } from "atom.io/json"
19
+ import { type Canonical, stringifyJson } from "atom.io/json"
20
20
 
21
21
  import { newest } from "../lineage"
22
22
  import type { Transceiver } from "../mutable"
@@ -25,15 +25,14 @@ import { initFamilyMemberInStore } from "./init-family-member"
25
25
  import { seekInStore } from "./seek-in-store"
26
26
 
27
27
  export function findInStore<
28
- T extends Transceiver<any>,
29
- J extends Json.Serializable,
28
+ T extends Transceiver<any, any, any>,
30
29
  K extends Canonical,
31
30
  Key extends K,
32
31
  >(
33
32
  store: Store,
34
- token: MutableAtomFamilyToken<T, J, K>,
33
+ token: MutableAtomFamilyToken<T, K>,
35
34
  key: Key,
36
- ): MutableAtomToken<T, J, K>
35
+ ): MutableAtomToken<T, K>
37
36
 
38
37
  export function findInStore<T, K extends Canonical, Key extends K>(
39
38
  store: Store,
@@ -12,19 +12,18 @@ import type {
12
12
  WritablePureSelectorToken,
13
13
  WritableToken,
14
14
  } from "atom.io"
15
- import type { Canonical, Json } from "atom.io/json"
15
+ import type { Canonical } from "atom.io/json"
16
16
 
17
17
  import type { Transceiver } from "../mutable"
18
18
  import type { Store } from "../store"
19
19
 
20
20
  export function getFamilyOfToken<
21
- T extends Transceiver<any>,
22
- J extends Json.Serializable,
21
+ T extends Transceiver<any, any, any>,
23
22
  K extends Canonical,
24
23
  >(
25
24
  store: Store,
26
- token: MutableAtomToken<T, J, K>,
27
- ): MutableAtomFamilyToken<T, J, K> | undefined
25
+ token: MutableAtomToken<T, K>,
26
+ ): MutableAtomFamilyToken<T, K> | undefined
28
27
 
29
28
  export function getFamilyOfToken<T, K extends Canonical>(
30
29
  store: Store,
@@ -25,15 +25,14 @@ import type { Store } from "../store"
25
25
  import { isChildStore, isRootStore } from "../transaction"
26
26
 
27
27
  export function initFamilyMemberInStore<
28
- T extends Transceiver<any>,
29
- J extends Json.Serializable,
28
+ T extends Transceiver<any, any, any>,
30
29
  K extends Canonical,
31
30
  Key extends K,
32
31
  >(
33
32
  store: Store,
34
- token: MutableAtomFamilyToken<T, J, K>,
33
+ token: MutableAtomFamilyToken<T, K>,
35
34
  key: Key,
36
- ): MutableAtomToken<T, J, K>
35
+ ): MutableAtomToken<T, K>
37
36
 
38
37
  export function initFamilyMemberInStore<T, K extends Canonical, Key extends K>(
39
38
  store: Store,
@@ -16,7 +16,7 @@ import type {
16
16
  WritablePureSelectorToken,
17
17
  WritableToken,
18
18
  } from "atom.io"
19
- import type { Canonical, Json } from "atom.io/json"
19
+ import type { Canonical } from "atom.io/json"
20
20
  import { stringifyJson } from "atom.io/json"
21
21
 
22
22
  import type { Molecule, ReadableState } from ".."
@@ -25,15 +25,14 @@ import type { Transceiver } from "../mutable"
25
25
  import { deposit, type Store } from "../store"
26
26
 
27
27
  export function seekInStore<
28
- T extends Transceiver<any>,
29
- J extends Json.Serializable,
28
+ T extends Transceiver<any, any, any>,
30
29
  K extends Canonical,
31
30
  Key extends K,
32
31
  >(
33
32
  store: Store,
34
- token: MutableAtomFamilyToken<T, J, K>,
33
+ token: MutableAtomFamilyToken<T, K>,
35
34
  key: Key,
36
- ): MutableAtomToken<T, J, K> | undefined
35
+ ): MutableAtomToken<T, K> | undefined
37
36
 
38
37
  export function seekInStore<T, K extends Canonical, Key extends K>(
39
38
  store: Store,
@@ -1,13 +1,24 @@
1
- import type { ReadableState } from ".."
2
- import { cacheValue, readCachedValue } from "../caching"
1
+ import type { ReadableState, ViewOf } from ".."
2
+ import { readFromCache, writeToCache } from "../caching"
3
3
  import type { Store } from "../store"
4
4
 
5
- export const readOrComputeValue = <T>(
5
+ export function readOrComputeValue<T>(
6
6
  target: Store,
7
7
  state: ReadableState<T>,
8
- ): T => {
8
+ mut?: undefined,
9
+ ): ViewOf<T>
10
+ export function readOrComputeValue<T>(
11
+ target: Store,
12
+ state: ReadableState<T>,
13
+ mut: `mut`,
14
+ ): T
15
+ export function readOrComputeValue<T>(
16
+ target: Store,
17
+ state: ReadableState<T>,
18
+ mut: `mut` | undefined,
19
+ ): T {
9
20
  if (target.valueMap.has(state.key)) {
10
- return readCachedValue(state, target)
21
+ return readFromCache(target, state, mut)
11
22
  }
12
23
  switch (state.type) {
13
24
  case `readonly_held_selector`:
@@ -16,27 +27,37 @@ export const readOrComputeValue = <T>(
16
27
  case `writable_pure_selector`:
17
28
  target.logger.info(`🧮`, state.type, state.key, `computing value`)
18
29
  return state.get()
19
- case `atom`:
20
- case `mutable_atom`: {
21
- const def = state.default
22
- let defaultValue: T
23
- if (def instanceof Function) {
24
- defaultValue = def()
30
+ case `atom`: {
31
+ let def: T
32
+ if (state.default instanceof Function) {
33
+ def = state.default()
25
34
  } else {
26
- defaultValue = def
35
+ def = state.default
27
36
  }
28
- const cachedValue = cacheValue(
37
+ const cachedValue = writeToCache(target, state.key, def, state.subject)
38
+ target.logger.info(
39
+ `💁`,
40
+ `atom`,
41
+ state.key,
42
+ `could not find cached value; using default`,
43
+ def,
44
+ )
45
+ return cachedValue
46
+ }
47
+ case `mutable_atom`: {
48
+ const instance = new state.class()
49
+ const cachedValue = writeToCache(
29
50
  target,
30
51
  state.key,
31
- defaultValue,
52
+ instance,
32
53
  state.subject,
33
54
  )
34
55
  target.logger.info(
35
56
  `💁`,
36
- `atom`,
57
+ `mutable_atom`,
37
58
  state.key,
38
59
  `could not find cached value; using default`,
39
- defaultValue,
60
+ instance,
40
61
  )
41
62
  return cachedValue
42
63
  }
@@ -11,14 +11,16 @@ import type {
11
11
  RegularAtomToken,
12
12
  StateCreation,
13
13
  StateDisposal,
14
+ StateLifecycleEvent,
14
15
  WritableHeldSelectorFamilyToken,
15
16
  WritableHeldSelectorToken,
16
17
  WritablePureSelectorFamilyToken,
17
18
  WritablePureSelectorToken,
18
19
  } from "atom.io"
19
- import type { Canonical, Json, JsonInterface } from "atom.io/json"
20
+ import type { Canonical } from "atom.io/json"
20
21
 
21
- import type { Transceiver } from "./mutable"
22
+ import type { internalRole } from "./atom/has-role"
23
+ import type { ConstructorOf, Transceiver } from "./mutable"
22
24
  import type { Store } from "./store"
23
25
  import type { Subject } from "./subject"
24
26
  import type { Timeline } from "./timeline"
@@ -67,22 +69,19 @@ export type RegularAtom<T> = Flat<
67
69
  type: `atom`
68
70
  default: T | (() => T)
69
71
  cleanup?: () => void
72
+ internalRoles?: internalRole[]
70
73
  }
71
74
  >
72
- export type MutableAtom<
73
- T extends Transceiver<any>,
74
- J extends Json.Serializable,
75
- > = Flat<
76
- AtomIOState &
77
- JsonInterface<T, J> & {
78
- type: `mutable_atom`
79
- default: () => T
80
- cleanup?: () => void
81
- }
75
+ export type MutableAtom<T extends Transceiver<any, any, any>> = Flat<
76
+ AtomIOState & {
77
+ type: `mutable_atom`
78
+ class: ConstructorOf<T>
79
+ cleanup?: () => void
80
+ }
82
81
  >
83
82
  export type Atom<T> =
84
83
  | RegularAtom<T>
85
- | (T extends Transceiver<any> ? MutableAtom<T, any> : never)
84
+ | (T extends Transceiver<any, any, any> ? MutableAtom<T> : never)
86
85
 
87
86
  export type WritableHeldSelector<T> = Flat<
88
87
  AtomIOState & {
@@ -141,23 +140,22 @@ export type RegularAtomFamily<T, K extends Canonical> =
141
140
 
142
141
  // biome-ignore format: intersection
143
142
  export type MutableAtomFamily<
144
- T extends Transceiver<any>,
145
- J extends Json.Serializable,
146
- K extends Canonical,
143
+ // C extends TransceiverConstructor<any,any>,
144
+ T extends Transceiver<any, any, any>,
145
+ K extends Canonical,
147
146
  > =
148
147
  & Flat<
149
- & JsonInterface<T, J>
150
- & MutableAtomFamilyToken<T, J, K>
148
+ & MutableAtomFamilyToken<T, K>
151
149
  & {
152
150
  install: (store: Store) => void
153
151
  internalRoles: string[] | undefined
154
- subject: Subject<StateCreation<MutableAtomToken<T, J>> | StateDisposal<MutableAtomToken<T, J>>>
152
+ subject: Subject<StateLifecycleEvent<MutableAtomToken<T>>>
155
153
  }
156
154
  >
157
- & ((key: K) => MutableAtomToken<T, J>)
155
+ & ((key: K) => MutableAtomToken<T>)
158
156
 
159
157
  export type AtomFamily<T, K extends Canonical = Canonical> =
160
- | MutableAtomFamily<T extends Transceiver<any> ? T : never, any, K>
158
+ | MutableAtomFamily<T extends Transceiver<any, any, any> ? T : never, K>
161
159
  | RegularAtomFamily<T, K>
162
160
 
163
161
  // biome-ignore format: intersection
@@ -115,25 +115,28 @@ export function ingestMoleculeTransferEvent(
115
115
  switch (applying) {
116
116
  case `newValue`:
117
117
  {
118
- const provenance = update.to.length === 1 ? update.to[0] : update.to
119
- claimWithinStore<any, any, any>(
120
- store,
121
- provenance,
122
- update.key,
123
- `exclusive`,
124
- )
118
+ for (const newOwner of update.to) {
119
+ claimWithinStore<any, any, any>(
120
+ store,
121
+ newOwner,
122
+ update.key,
123
+ update.exclusive ? `exclusive` : undefined,
124
+ )
125
+ }
125
126
  }
126
127
  break
127
128
  case `oldValue`:
128
129
  {
129
- const provenance =
130
- update.from.length === 1 ? update.from[0] : update.from
131
- claimWithinStore<any, any, any>(
132
- store,
133
- provenance,
134
- update.key,
135
- `exclusive`,
136
- )
130
+ let exclusivity: `exclusive` | undefined = `exclusive`
131
+ for (const previousOwner of update.from) {
132
+ claimWithinStore<any, any, any>(
133
+ store,
134
+ previousOwner,
135
+ update.key,
136
+ exclusivity,
137
+ )
138
+ exclusivity = undefined
139
+ }
137
140
  }
138
141
  break
139
142
  }
@@ -1,5 +1,7 @@
1
+ import type { TimelineManageable } from "atom.io"
2
+
1
3
  import type { Store } from "../store"
2
- import type { TimelineSelectorUpdate } from "../timeline"
4
+ import type { TimelineAtomUpdate, TimelineSelectorUpdate } from "../timeline"
3
5
  import { ingestAtomUpdate } from "./ingest-atom-update"
4
6
 
5
7
  export function ingestSelectorUpdate(
@@ -7,10 +9,12 @@ export function ingestSelectorUpdate(
7
9
  selectorUpdate: TimelineSelectorUpdate<any>,
8
10
  store: Store,
9
11
  ): void {
10
- const updates =
11
- applying === `newValue`
12
- ? selectorUpdate.atomUpdates
13
- : selectorUpdate.atomUpdates.toReversed()
12
+ let updates: Omit<TimelineAtomUpdate<TimelineManageable>, `timestamp`>[]
13
+ if (applying === `newValue`) {
14
+ updates = selectorUpdate.atomUpdates
15
+ } else {
16
+ updates = selectorUpdate.atomUpdates.toReversed()
17
+ }
14
18
  for (const atomUpdate of updates) {
15
19
  ingestAtomUpdate(applying, atomUpdate, store)
16
20
  }
@@ -1,5 +1,5 @@
1
1
  import type { JoinToken, MutableAtomFamilyToken } from "atom.io"
2
- import type { SetRTX, SetRTXJson } from "atom.io/transceivers/set-rtx"
2
+ import type { SetRTX } from "atom.io/transceivers/set-rtx"
3
3
 
4
4
  import type { Store } from "../store"
5
5
  import { getJoin } from "./get-join"
@@ -7,7 +7,7 @@ import { getJoin } from "./get-join"
7
7
  export function getInternalRelationsFromStore(
8
8
  token: JoinToken<any, any, any, any, any, any>,
9
9
  store: Store,
10
- ): MutableAtomFamilyToken<SetRTX<string>, SetRTXJson<string>, string> {
10
+ ): MutableAtomFamilyToken<SetRTX<string>, string> {
11
11
  const myJoin = getJoin(token, store)
12
12
  const family = myJoin.core.relatedKeysAtoms
13
13
  return family
@@ -14,7 +14,6 @@ import type {
14
14
  import { Anarchy } from "atom.io"
15
15
  import type { Canonical, Json, stringified } from "atom.io/json"
16
16
  import { stringifyJson } from "atom.io/json"
17
- import type { SetRTXJson } from "atom.io/transceivers/set-rtx"
18
17
  import { SetRTX } from "atom.io/transceivers/set-rtx"
19
18
 
20
19
  import { capitalize } from "../capitalize"
@@ -30,6 +29,7 @@ import type {
30
29
  } from "../junction"
31
30
  import { Junction } from "../junction"
32
31
  import type { Molecule } from "../molecule"
32
+ import type { ViewOf } from "../mutable"
33
33
  import { createMutableAtomFamily, getJsonFamily, getJsonToken } from "../mutable"
34
34
  import { setIntoStore } from "../set-state"
35
35
  import type { Store } from "../store"
@@ -143,11 +143,7 @@ export class Join<
143
143
  Content
144
144
  >
145
145
  public core: {
146
- relatedKeysAtoms: MutableAtomFamilyToken<
147
- SetRTX<string>,
148
- SetRTXJson<string>,
149
- string
150
- >
146
+ relatedKeysAtoms: MutableAtomFamilyToken<SetRTX<string>, string>
151
147
  }
152
148
  public transact(
153
149
  toolkit: WriterToolkit,
@@ -193,17 +189,11 @@ export class Join<
193
189
 
194
190
  const aSide: ASide = options.between[0]
195
191
  const bSide: BSide = options.between[1]
196
- const relatedKeysAtoms = createMutableAtomFamily<
197
- SetRTX<string>,
198
- SetRTXJson<string>,
199
- string
200
- >(
192
+ const relatedKeysAtoms = createMutableAtomFamily<SetRTX<string>, string>(
201
193
  store,
202
194
  {
203
195
  key: `${options.key}/relatedKeys`,
204
- default: () => new SetRTX(),
205
- fromJson: (json) => SetRTX.fromJSON(json),
206
- toJson: (set) => set.toJSON(),
196
+ class: SetRTX,
207
197
  },
208
198
  [`join`, `relations`],
209
199
  )
@@ -354,8 +344,10 @@ export class Join<
354
344
  [`join`, `content`],
355
345
  )
356
346
 
357
- const getContent: Read<(key: string) => Content | null> = ({ get }, key) =>
358
- get(contentAtoms, key)
347
+ const getContent: Read<(key: string) => ViewOf<Content> | null> = (
348
+ { get },
349
+ key,
350
+ ) => get(contentAtoms, key)
359
351
  const setContent: Write<(key: string, content: Content) => void> = (
360
352
  { set },
361
353
  key,
@@ -444,7 +436,7 @@ export class Join<
444
436
  )
445
437
  }
446
438
  const createSingleEntrySelectorFamily = () =>
447
- createReadonlyPureSelectorFamily<[string, Content] | null, string>(
439
+ createReadonlyPureSelectorFamily<[string, ViewOf<Content>] | null, string>(
448
440
  store,
449
441
  {
450
442
  key: `${options.key}/singleRelatedEntry`,
@@ -467,7 +459,7 @@ export class Join<
467
459
  [`join`, `entries`],
468
460
  )
469
461
  const getMultipleEntrySelectorFamily = () =>
470
- createReadonlyPureSelectorFamily<[string, Content][], string>(
462
+ createReadonlyPureSelectorFamily<[string, ViewOf<Content>][], string>(
471
463
  store,
472
464
  {
473
465
  key: `${options.key}/multipleRelatedEntries`,
@@ -293,6 +293,7 @@ export function claimWithinStore<
293
293
  const transferEvent: MoleculeTransfer = {
294
294
  type: `molecule_transfer`,
295
295
  key: molecule.key,
296
+ exclusive: Boolean(exclusive),
296
297
  from: priorProvenance,
297
298
  to: [newProvenanceMolecule.key],
298
299
  }