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,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var json = require('atom.io/json');
4
3
  var atom_io = require('atom.io');
4
+ var json = require('atom.io/json');
5
5
  var internal = require('atom.io/internal');
6
6
 
7
7
  var __defProp = Object.defineProperty;
@@ -31,213 +31,277 @@ function newest(scion) {
31
31
  }
32
32
  return scion;
33
33
  }
34
- function eldest(scion) {
35
- while (scion.parent !== null) {
36
- scion = scion.parent;
34
+
35
+ // internal/src/store/deposit.ts
36
+ function deposit(state) {
37
+ const token = {
38
+ key: state.key,
39
+ type: state.type
40
+ };
41
+ if (`family` in state) {
42
+ token.family = state.family;
37
43
  }
38
- return scion;
44
+ return token;
39
45
  }
40
46
 
41
- // internal/src/future.ts
42
- var Future = class extends Promise {
43
- constructor(executor) {
44
- super((resolve, reject) => {
45
- const pass = (value) => this.isCanceled ? reject(`canceled`) : resolve(value);
46
- const fail = (reason) => this.isCanceled ? reject(`canceled`) : reject(reason);
47
- if (typeof executor === `function`) {
48
- executor(pass, fail);
49
- } else {
50
- executor.then(pass, fail);
47
+ // ../rel8/junction/src/junction.ts
48
+ var Junction = class {
49
+ constructor(data, config) {
50
+ this.relations = /* @__PURE__ */ new Map();
51
+ this.contents = /* @__PURE__ */ new Map();
52
+ this.makeContentKey = (a, b) => `${a}:${b}`;
53
+ var _a, _b, _c, _d;
54
+ this.a = data.between[0];
55
+ this.b = data.between[1];
56
+ this.cardinality = data.cardinality;
57
+ if (!(config == null ? void 0 : config.externalStore)) {
58
+ this.relations = new Map((_a = data.relations) == null ? void 0 : _a.map(([a, b]) => [a, new Set(b)]));
59
+ this.contents = new Map(data.contents);
60
+ }
61
+ this.isContent = (_b = config == null ? void 0 : config.isContent) != null ? _b : null;
62
+ if (config == null ? void 0 : config.makeContentKey) {
63
+ this.makeContentKey = config.makeContentKey;
64
+ }
65
+ if (config == null ? void 0 : config.externalStore) {
66
+ const externalStore = config.externalStore;
67
+ this.has = (a, b) => externalStore.has(a, b);
68
+ this.addRelation = (a, b) => {
69
+ externalStore.addRelation(a, b);
70
+ };
71
+ this.deleteRelation = (a, b) => {
72
+ externalStore.deleteRelation(a, b);
73
+ };
74
+ this.replaceRelationsSafely = (a, bs) => {
75
+ externalStore.replaceRelationsSafely(a, bs);
76
+ };
77
+ this.replaceRelationsUnsafely = (a, bs) => {
78
+ externalStore.replaceRelationsUnsafely(a, bs);
79
+ };
80
+ this.getRelatedKeys = (key) => externalStore.getRelatedKeys(key);
81
+ if (externalStore.getContent) {
82
+ this.getContentInternal = (contentKey) => {
83
+ return externalStore.getContent(contentKey);
84
+ };
85
+ this.setContent = (contentKey, content) => {
86
+ externalStore.setContent(contentKey, content);
87
+ };
88
+ this.deleteContent = (contentKey) => {
89
+ externalStore.deleteContent(contentKey);
90
+ };
51
91
  }
52
- });
53
- this.isCanceled = false;
92
+ for (const [x, ys] of (_c = data.relations) != null ? _c : []) {
93
+ for (const y of ys)
94
+ this.addRelation(x, y);
95
+ }
96
+ for (const [contentKey, content] of (_d = data.contents) != null ? _d : []) {
97
+ this.setContent(contentKey, content);
98
+ }
99
+ }
54
100
  }
55
- cancel() {
56
- this.isCanceled = true;
101
+ getRelatedKeys(key) {
102
+ return this.relations.get(key);
57
103
  }
58
- };
59
-
60
- // internal/src/set-state/copy-mutable-if-needed.ts
61
- function copyMutableIfNeeded(atom, transform, origin, target) {
62
- const originValue = origin.valueMap.get(atom.key);
63
- const targetValue = target.valueMap.get(atom.key);
64
- if (originValue === targetValue) {
65
- origin.logger.info(`\u{1F4C3}`, `atom`, `${atom.key}`, `copying`);
66
- const jsonValue = transform.toJson(originValue);
67
- const copiedValue = transform.fromJson(jsonValue);
68
- target.valueMap.set(atom.key, copiedValue);
69
- new Tracker(atom, origin);
70
- return copiedValue;
104
+ addRelation(a, b) {
105
+ let aRelations = this.relations.get(a);
106
+ let bRelations = this.relations.get(b);
107
+ if (aRelations) {
108
+ aRelations.add(b);
109
+ } else {
110
+ aRelations = /* @__PURE__ */ new Set([b]);
111
+ this.relations.set(a, aRelations);
112
+ }
113
+ if (bRelations) {
114
+ bRelations.add(a);
115
+ } else {
116
+ bRelations = /* @__PURE__ */ new Set([a]);
117
+ this.relations.set(b, bRelations);
118
+ }
71
119
  }
72
- return targetValue;
73
- }
74
-
75
- // internal/src/set-state/copy-mutable-in-transaction.ts
76
- function copyMutableIfWithinTransaction(oldValue, atom, store) {
77
- const target = newest(store);
78
- const parent = target.parent;
79
- if (parent !== null) {
80
- if (`family` in atom) {
81
- const family = parent.families.get(atom.family.key);
82
- if (family && family.type === `atom_family`) {
83
- const result = copyMutableFamilyMemberWithinTransaction(
84
- atom,
85
- family,
86
- parent,
87
- target
88
- );
89
- if (result) {
90
- return result;
120
+ deleteRelation(a, b) {
121
+ const aRelations = this.relations.get(a);
122
+ if (aRelations) {
123
+ aRelations.delete(b);
124
+ if (aRelations.size === 0) {
125
+ this.relations.delete(a);
126
+ }
127
+ const bRelations = this.relations.get(b);
128
+ if (bRelations) {
129
+ bRelations.delete(a);
130
+ if (bRelations.size === 0) {
131
+ this.relations.delete(b);
91
132
  }
92
133
  }
93
134
  }
94
- if (`toJson` in atom && `fromJson` in atom) {
95
- const copiedValue = copyMutableIfNeeded(atom, atom, parent, target);
96
- return copiedValue;
97
- }
98
- }
99
- return oldValue;
100
- }
101
- function copyMutableFamilyMemberWithinTransaction(atom, family, origin, target) {
102
- if (`toJson` in family && `fromJson` in family) {
103
- const copyCreated = copyMutableIfNeeded(atom, family, origin, target);
104
- return copyCreated;
105
135
  }
106
- return null;
107
- }
108
-
109
- // internal/src/caching.ts
110
- function cacheValue(key, value, subject, target) {
111
- const currentValue = target.valueMap.get(key);
112
- if (currentValue instanceof Future) {
113
- currentValue.cancel();
136
+ replaceRelationsUnsafely(a, bs) {
137
+ this.relations.set(a, new Set(bs));
138
+ for (const b of bs) {
139
+ const bRelations = /* @__PURE__ */ new Set([a]);
140
+ this.relations.set(b, bRelations);
141
+ }
114
142
  }
115
- if (value instanceof Promise) {
116
- const future = new Future(value);
117
- target.valueMap.set(key, future);
118
- future.then((resolved) => {
119
- if (future.isCanceled) {
120
- return;
143
+ replaceRelationsSafely(a, bs) {
144
+ const aRelationsPrev = this.relations.get(a);
145
+ if (aRelationsPrev) {
146
+ for (const b of aRelationsPrev) {
147
+ const bRelations = this.relations.get(b);
148
+ if (bRelations) {
149
+ if (bRelations.size === 1) {
150
+ this.relations.delete(b);
151
+ } else {
152
+ bRelations.delete(a);
153
+ }
154
+ this.contents.delete(this.makeContentKey(a, b));
155
+ }
121
156
  }
122
- cacheValue(key, resolved, subject, target);
123
- subject.next({ newValue: resolved, oldValue: future });
124
- }).catch((thrown) => {
125
- if (thrown !== `canceled`) {
126
- target.logger.error(`\u{1F4A5}`, `state`, key, `rejected:`, thrown);
157
+ }
158
+ this.relations.set(a, new Set(bs));
159
+ for (const b of bs) {
160
+ let bRelations = this.relations.get(b);
161
+ if (bRelations) {
162
+ bRelations.add(a);
163
+ } else {
164
+ bRelations = /* @__PURE__ */ new Set([a]);
165
+ this.relations.set(b, bRelations);
127
166
  }
128
- });
129
- return future;
167
+ }
130
168
  }
131
- target.valueMap.set(key, value);
132
- return value;
133
- }
134
- var readCachedValue = (token, target) => {
135
- let value = target.valueMap.get(token.key);
136
- if (token.type === `atom`) {
137
- value = copyMutableIfWithinTransaction(value, token, target);
169
+ getContentInternal(contentKey) {
170
+ return this.contents.get(contentKey);
138
171
  }
139
- return value;
140
- };
141
- var evictCachedValue = (key, target) => {
142
- const currentValue = target.valueMap.get(key);
143
- if (currentValue instanceof Future) {
144
- currentValue.cancel();
172
+ setContent(contentKey, content) {
173
+ this.contents.set(contentKey, content);
145
174
  }
146
- if (target.operation.open) {
147
- target.operation.prev.set(key, currentValue);
175
+ deleteContent(contentKey) {
176
+ this.contents.delete(contentKey);
148
177
  }
149
- target.valueMap.delete(key);
150
- target.logger.info(`\u{1F5D1}`, `state`, key, `evicted`);
151
- };
152
-
153
- // internal/src/read-or-compute-value.ts
154
- var readOrComputeValue = (state, target) => {
155
- if (target.valueMap.has(state.key)) {
156
- target.logger.info(`\u{1F4D6}`, state.type, state.key, `reading cached value`);
157
- return readCachedValue(state, target);
178
+ toJSON() {
179
+ return {
180
+ between: [this.a, this.b],
181
+ cardinality: this.cardinality,
182
+ relations: [...this.relations.entries()].map(([a, b]) => [a, [...b]]),
183
+ contents: [...this.contents.entries()]
184
+ };
158
185
  }
159
- if (state.type !== `atom`) {
160
- target.logger.info(`\u{1F9EE}`, state.type, state.key, `computing value`);
161
- return state.get();
186
+ set(a, ...rest) {
187
+ var _a;
188
+ const b = typeof rest[0] === `string` ? rest[0] : a[this.b];
189
+ const content = ((_a = rest[1]) != null ? _a : typeof rest[0] === `string`) ? void 0 : rest[0];
190
+ a = typeof a === `string` ? a : a[this.a];
191
+ switch (this.cardinality) {
192
+ case `1:1`: {
193
+ const bPrev = this.getRelatedKey(a);
194
+ if (bPrev && bPrev !== b)
195
+ this.delete(bPrev, a);
196
+ }
197
+ case `1:n`: {
198
+ const aPrev = this.getRelatedKey(b);
199
+ if (aPrev && aPrev !== a)
200
+ this.delete(aPrev, b);
201
+ }
202
+ }
203
+ if (content) {
204
+ const contentKey = this.makeContentKey(a, b);
205
+ this.setContent(contentKey, content);
206
+ }
207
+ this.addRelation(a, b);
208
+ return this;
162
209
  }
163
- const fallback = state.default instanceof Function ? state.default() : state.default;
164
- target.logger.info(
165
- `\u{1F481}`,
166
- `atom`,
167
- state.key,
168
- `could not find cached value; using default`,
169
- fallback
170
- );
171
- return state.default instanceof Function ? state.default() : state.default;
172
- };
173
-
174
- // internal/src/operation.ts
175
- var openOperation = (token, store) => {
176
- if (store.operation.open) {
177
- store.logger.error(
178
- `\u274C`,
179
- token.type,
180
- token.key,
181
- `failed to setState during a setState for "${store.operation.token.key}"`
182
- );
183
- return `rejection`;
210
+ delete(x, b) {
211
+ b = typeof b === `string` ? b : x[this.b];
212
+ const a = typeof x === `string` ? x : x[this.a];
213
+ if (a === void 0 && typeof b === `string`) {
214
+ const bRelations = this.getRelatedKeys(b);
215
+ if (bRelations) {
216
+ for (const a2 of bRelations) {
217
+ this.delete(a2, b);
218
+ }
219
+ }
220
+ }
221
+ if (typeof a === `string` && b === void 0) {
222
+ const aRelations = this.getRelatedKeys(a);
223
+ if (aRelations) {
224
+ for (const b2 of aRelations) {
225
+ this.delete(a, b2);
226
+ }
227
+ }
228
+ }
229
+ if (typeof a === `string` && typeof b === `string`) {
230
+ this.deleteRelation(a, b);
231
+ const contentKey = this.makeContentKey(a, b);
232
+ this.deleteContent(contentKey);
233
+ }
234
+ return this;
184
235
  }
185
- store.operation = {
186
- open: true,
187
- done: /* @__PURE__ */ new Set(),
188
- prev: /* @__PURE__ */ new Map(),
189
- time: Date.now(),
190
- token
191
- };
192
- store.logger.info(
193
- `\u2B55`,
194
- token.type,
195
- token.key,
196
- `operation start in store "${store.config.name}"${store.transactionMeta === null ? `` : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`}`
197
- );
198
- };
199
- var closeOperation = (store) => {
200
- if (store.operation.open) {
201
- store.logger.info(
202
- `\u{1F534}`,
203
- store.operation.token.type,
204
- store.operation.token.key,
205
- `operation done in store "${store.config.name}"`
206
- );
236
+ getRelatedKey(key) {
237
+ const relations = this.getRelatedKeys(key);
238
+ if (relations) {
239
+ if (relations.size > 1) {
240
+ console.warn(
241
+ `${relations.size} related keys were found for key "${key}": (${[
242
+ ...relations
243
+ ].map((k) => `"${k}"`).join(`, `)}). Only one related key was expected.`
244
+ );
245
+ }
246
+ for (const relation of relations) {
247
+ return relation;
248
+ }
249
+ }
207
250
  }
208
- store.operation = { open: false };
209
- store.on.operationClose.next(store.operation);
210
- };
211
- var isDone = (key, store) => {
212
- if (!store.operation.open) {
213
- store.logger.warn(
214
- `\u{1F41E}`,
215
- `unknown`,
216
- key,
217
- `isDone called outside of an operation. This is probably a bug.`
218
- );
219
- return true;
251
+ replaceRelations(a, relations, config) {
252
+ const hasContent = !Array.isArray(relations);
253
+ const bs = hasContent ? Object.keys(relations) : relations;
254
+ if (config == null ? void 0 : config.reckless) {
255
+ this.replaceRelationsUnsafely(a, bs);
256
+ } else {
257
+ this.replaceRelationsSafely(a, bs);
258
+ }
259
+ if (hasContent) {
260
+ for (const b of bs) {
261
+ const contentKey = this.makeContentKey(a, b);
262
+ const content = relations[b];
263
+ this.setContent(contentKey, content);
264
+ }
265
+ }
266
+ return this;
220
267
  }
221
- return store.operation.done.has(key);
222
- };
223
- var markDone = (key, store) => {
224
- if (!store.operation.open) {
225
- store.logger.warn(
226
- `\u{1F41E}`,
227
- `unknown`,
228
- key,
229
- `markDone called outside of an operation. This is probably a bug.`
230
- );
231
- return;
268
+ getContent(a, b) {
269
+ const contentKey = this.makeContentKey(a, b);
270
+ return this.getContentInternal(contentKey);
271
+ }
272
+ getRelationEntries(input) {
273
+ const a = input[this.a];
274
+ const b = input[this.b];
275
+ if (a !== void 0 && b === void 0) {
276
+ const aRelations = this.getRelatedKeys(a);
277
+ if (aRelations) {
278
+ return [...aRelations].map((b2) => {
279
+ var _a;
280
+ return [b2, (_a = this.getContent(a, b2)) != null ? _a : null];
281
+ });
282
+ }
283
+ }
284
+ if (a === void 0 && b !== void 0) {
285
+ const bRelations = this.getRelatedKeys(b);
286
+ if (bRelations) {
287
+ return [...bRelations].map((a2) => {
288
+ var _a;
289
+ return [a2, (_a = this.getContent(a2, b)) != null ? _a : null];
290
+ });
291
+ }
292
+ }
293
+ return [];
294
+ }
295
+ has(a, b) {
296
+ var _a;
297
+ if (b) {
298
+ const setA = this.getRelatedKeys(a);
299
+ return (_a = setA == null ? void 0 : setA.has(b)) != null ? _a : false;
300
+ }
301
+ return this.relations.has(a);
232
302
  }
233
- store.operation.done.add(key);
234
303
  };
235
304
 
236
- // internal/src/set-state/become.ts
237
- var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
238
- originalThing instanceof Function ? originalThing() : originalThing
239
- ) : nextVersionOfThing;
240
-
241
305
  // internal/src/subject.ts
242
306
  var Subject = class {
243
307
  constructor() {
@@ -269,565 +333,476 @@ var StatefulSubject = class extends Subject {
269
333
  }
270
334
  };
271
335
 
272
- // internal/src/set-state/emit-update.ts
273
- var emitUpdate = (state, update, store) => {
274
- store.logger.info(
275
- `\u{1F4E2}`,
276
- state.type,
277
- state.key,
278
- `went (`,
279
- update.oldValue,
280
- `->`,
281
- update.newValue,
282
- `) subscribers:`,
283
- state.subject.subscribers
284
- );
285
- state.subject.next(update);
286
- };
287
-
288
- // internal/src/set-state/evict-downstream.ts
289
- var evictDownStream = (atom, store) => {
290
- const downstreamKeys = store.selectorAtoms.getRelatedKeys(atom.key);
291
- store.logger.info(
292
- `\u{1F9F9}`,
293
- atom.type,
294
- atom.key,
295
- downstreamKeys ? `evicting ${downstreamKeys.size} states downstream:` : `no downstream states`,
296
- downstreamKeys != null ? downstreamKeys : `to evict`
297
- );
298
- if (downstreamKeys) {
299
- if (store.operation.open) {
300
- store.logger.info(
301
- `\u{1F9F9}`,
302
- atom.type,
303
- atom.key,
304
- `[ ${[...store.operation.done].join(`, `)} ] already done`
305
- );
306
- }
307
- for (const key of downstreamKeys) {
308
- if (isDone(key, store)) {
309
- continue;
336
+ // internal/src/store/store.ts
337
+ var Store = class {
338
+ constructor(name, store = null) {
339
+ this.parent = null;
340
+ this.child = null;
341
+ this.valueMap = /* @__PURE__ */ new Map();
342
+ this.atoms = /* @__PURE__ */ new Map();
343
+ this.selectors = /* @__PURE__ */ new Map();
344
+ this.readonlySelectors = /* @__PURE__ */ new Map();
345
+ this.trackers = /* @__PURE__ */ new Map();
346
+ this.families = /* @__PURE__ */ new Map();
347
+ this.timelines = /* @__PURE__ */ new Map();
348
+ this.transactions = /* @__PURE__ */ new Map();
349
+ this.atomsThatAreDefault = /* @__PURE__ */ new Set();
350
+ this.timelineAtoms = new Junction({
351
+ between: [`timelineKey`, `atomKey`],
352
+ cardinality: `1:n`
353
+ });
354
+ this.selectorAtoms = new Junction({
355
+ between: [`selectorKey`, `atomKey`],
356
+ cardinality: `n:n`
357
+ });
358
+ this.selectorGraph = new Junction(
359
+ {
360
+ between: [`upstreamSelectorKey`, `downstreamSelectorKey`],
361
+ cardinality: `n:n`
362
+ },
363
+ {
364
+ makeContentKey: (...keys) => keys.sort().join(`:`)
310
365
  }
311
- evictCachedValue(key, store);
312
- markDone(key, store);
313
- }
314
- }
315
- };
316
-
317
- // internal/src/set-state/stow-update.ts
318
- function shouldUpdateBeStowed(key, update) {
319
- if (isTransceiver(update.newValue)) {
320
- return false;
321
- }
322
- if (key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
323
- return false;
324
- }
325
- return true;
326
- }
327
- var stowUpdate = (state, update, store) => {
328
- const { key } = state;
329
- const target = newest(store);
330
- if (target.transactionMeta === null || target.transactionMeta.phase !== `building`) {
331
- store.logger.error(
332
- `\u{1F41E}`,
333
- `atom`,
334
- key,
335
- `stowUpdate called outside of a transaction. This is probably a bug.`
336
366
  );
337
- return;
338
- }
339
- const shouldStow = shouldUpdateBeStowed(key, update);
340
- if (!shouldStow) {
341
- return;
342
- }
343
- const atomUpdate = __spreadValues({ key }, update);
344
- if (state.family) {
345
- atomUpdate.family = state.family;
346
- }
347
- target.transactionMeta.update.updates.push(atomUpdate);
348
- store.logger.info(
349
- `\u{1F4C1}`,
350
- `atom`,
351
- key,
352
- `stowed (`,
353
- update.oldValue,
354
- `->`,
355
- update.newValue,
356
- `)`
357
- );
367
+ this.on = {
368
+ atomCreation: new Subject(),
369
+ selectorCreation: new Subject(),
370
+ transactionCreation: new Subject(),
371
+ timelineCreation: new Subject(),
372
+ transactionApplying: new StatefulSubject(null),
373
+ operationClose: new Subject()
374
+ };
375
+ this.operation = { open: false };
376
+ this.transactionMeta = null;
377
+ this.config = {
378
+ name: `IMPLICIT_STORE`
379
+ };
380
+ this.loggers = [
381
+ new atom_io.AtomIOLogger(`warn`, (_, __, key) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`))
382
+ ];
383
+ this.logger = {
384
+ error: (...messages) => {
385
+ for (const logger of this.loggers)
386
+ logger.error(...messages);
387
+ },
388
+ info: (...messages) => {
389
+ for (const logger of this.loggers)
390
+ logger.info(...messages);
391
+ },
392
+ warn: (...messages) => {
393
+ for (const logger of this.loggers)
394
+ logger.warn(...messages);
395
+ }
396
+ };
397
+ if (store !== null) {
398
+ this.valueMap = new Map(store == null ? void 0 : store.valueMap);
399
+ this.operation = __spreadValues({}, store == null ? void 0 : store.operation);
400
+ this.transactionMeta = null;
401
+ this.config = __spreadProps(__spreadValues({}, store == null ? void 0 : store.config), {
402
+ name
403
+ });
404
+ for (const [, family] of store.families) {
405
+ family.install(this);
406
+ }
407
+ const mutableHelpers = /* @__PURE__ */ new Set();
408
+ for (const [, atom] of store.atoms) {
409
+ if (mutableHelpers.has(atom.key)) {
410
+ continue;
411
+ }
412
+ atom.install(this);
413
+ if (atom.type === `mutable_atom`) {
414
+ const originalJsonToken = getJsonToken(atom);
415
+ const originalUpdateToken = getUpdateToken(atom);
416
+ mutableHelpers.add(originalJsonToken.key);
417
+ mutableHelpers.add(originalUpdateToken.key);
418
+ }
419
+ }
420
+ for (const [, selector] of store.readonlySelectors) {
421
+ selector.install(this);
422
+ }
423
+ for (const [, selector] of store.selectors) {
424
+ if (mutableHelpers.has(selector.key)) {
425
+ continue;
426
+ }
427
+ selector.install(this);
428
+ }
429
+ for (const [, tx] of store.transactions) {
430
+ tx.install(this);
431
+ }
432
+ for (const [, timeline] of store.timelines) {
433
+ timeline.install(this);
434
+ }
435
+ }
436
+ }
437
+ };
438
+ var IMPLICIT = {
439
+ STORE_INTERNAL: void 0,
440
+ get STORE() {
441
+ var _a;
442
+ return (_a = this.STORE_INTERNAL) != null ? _a : this.STORE_INTERNAL = new Store(`IMPLICIT_STORE`);
443
+ }
444
+ };
445
+ var clearStore = (store) => {
446
+ const { config } = store;
447
+ Object.assign(store, new Store(config.name));
448
+ store.config = config;
358
449
  };
359
450
 
360
- // internal/src/set-state/set-atom.ts
361
- var setAtom = (atom, next, target) => {
362
- const oldValue = readOrComputeValue(atom, target);
363
- let newValue = copyMutableIfWithinTransaction(oldValue, atom, target);
364
- newValue = become(next)(newValue);
365
- target.logger.info(`\u{1F4DD}`, `atom`, atom.key, `set to`, newValue);
366
- newValue = cacheValue(atom.key, newValue, atom.subject, target);
367
- if (isAtomDefault(atom.key, target)) {
368
- markAtomAsNotDefault(atom.key, target);
451
+ // internal/src/store/withdraw.ts
452
+ function withdraw(token, store) {
453
+ let withdrawn;
454
+ let target = store;
455
+ while (target !== null) {
456
+ switch (token.type) {
457
+ case `atom`:
458
+ case `mutable_atom`:
459
+ withdrawn = target.atoms.get(token.key);
460
+ break;
461
+ case `selector`:
462
+ withdrawn = target.selectors.get(token.key);
463
+ break;
464
+ case `readonly_selector`:
465
+ withdrawn = target.readonlySelectors.get(token.key);
466
+ break;
467
+ case `timeline`:
468
+ withdrawn = target.timelines.get(token.key);
469
+ break;
470
+ case `transaction`:
471
+ withdrawn = target.transactions.get(token.key);
472
+ break;
473
+ }
474
+ if (withdrawn) {
475
+ return withdrawn;
476
+ }
477
+ target = target.child;
369
478
  }
370
- markDone(atom.key, target);
371
- evictDownStream(atom, target);
372
- const update = { oldValue, newValue };
373
- if (target.transactionMeta === null) {
374
- emitUpdate(atom, update, target);
375
- } else if (target.on.transactionApplying && target.parent) {
376
- stowUpdate(atom, update, target);
377
- if (atom.key.startsWith(`*`)) {
378
- const mutableKey = atom.key.slice(1);
379
- const mutable = target.valueMap.get(mutableKey);
380
- mutable.do(update.newValue);
479
+ }
480
+
481
+ // internal/src/store/withdraw-new-family-member.ts
482
+ function withdrawNewFamilyMember(token, store) {
483
+ if (token.family) {
484
+ store.logger.info(
485
+ `\u{1F46A}`,
486
+ token.type,
487
+ token.key,
488
+ `creating new family member in store "${store.config.name}"`
489
+ );
490
+ const target = newest(store);
491
+ const family = target.families.get(token.family.key);
492
+ if (family) {
493
+ const jsonSubKey = JSON.parse(token.family.subKey);
494
+ family(jsonSubKey);
495
+ const state = withdraw(token, store);
496
+ return state;
381
497
  }
382
498
  }
383
- };
499
+ return void 0;
500
+ }
384
501
 
385
- // internal/src/set-state/set-atom-or-selector.ts
386
- var setAtomOrSelector = (state, value, store) => {
387
- switch (state.type) {
388
- case `atom`:
389
- setAtom(state, value, store);
390
- break;
391
- case `selector`:
392
- state.set(value);
393
- break;
502
+ // internal/src/future.ts
503
+ var Future = class extends Promise {
504
+ constructor(executor) {
505
+ super((resolve, reject) => {
506
+ const pass = (value) => this.isCanceled ? reject(`canceled`) : resolve(value);
507
+ const fail = (reason) => this.isCanceled ? reject(`canceled`) : reject(reason);
508
+ if (typeof executor === `function`) {
509
+ executor(pass, fail);
510
+ } else {
511
+ executor.then(pass, fail);
512
+ }
513
+ });
514
+ this.isCanceled = false;
515
+ }
516
+ cancel() {
517
+ this.isCanceled = true;
394
518
  }
395
519
  };
396
520
 
397
- // internal/src/store/deposit.ts
398
- function deposit(state) {
399
- const token = {
400
- key: state.key,
401
- type: state.type
402
- };
403
- if (`family` in state) {
404
- token.family = state.family;
521
+ // internal/src/set-state/copy-mutable-if-needed.ts
522
+ function copyMutableIfNeeded(atom, origin, target) {
523
+ const originValue = origin.valueMap.get(atom.key);
524
+ const targetValue = target.valueMap.get(atom.key);
525
+ if (originValue === targetValue) {
526
+ origin.logger.info(`\u{1F4C3}`, `atom`, `${atom.key}`, `copying`);
527
+ const jsonValue = atom.toJson(originValue);
528
+ const copiedValue = atom.fromJson(jsonValue);
529
+ target.valueMap.set(atom.key, copiedValue);
530
+ new Tracker(atom, origin);
531
+ return copiedValue;
405
532
  }
406
- return token;
533
+ return targetValue;
407
534
  }
408
535
 
409
- // ../rel8/junction/src/junction.ts
410
- var Junction = class {
411
- constructor(data, config) {
412
- this.relations = /* @__PURE__ */ new Map();
413
- this.contents = /* @__PURE__ */ new Map();
414
- this.makeContentKey = (a, b) => `${a}:${b}`;
415
- var _a, _b, _c, _d;
416
- this.a = data.between[0];
417
- this.b = data.between[1];
418
- this.cardinality = data.cardinality;
419
- if (!(config == null ? void 0 : config.externalStore)) {
420
- this.relations = new Map((_a = data.relations) == null ? void 0 : _a.map(([a, b]) => [a, new Set(b)]));
421
- this.contents = new Map(data.contents);
422
- }
423
- this.isContent = (_b = config == null ? void 0 : config.isContent) != null ? _b : null;
424
- if (config == null ? void 0 : config.makeContentKey) {
425
- this.makeContentKey = config.makeContentKey;
426
- }
427
- if (config == null ? void 0 : config.externalStore) {
428
- const externalStore = config.externalStore;
429
- this.has = (a, b) => externalStore.has(a, b);
430
- this.addRelation = (a, b) => {
431
- externalStore.addRelation(a, b);
432
- };
433
- this.deleteRelation = (a, b) => {
434
- externalStore.deleteRelation(a, b);
435
- };
436
- this.replaceRelationsSafely = (a, bs) => {
437
- externalStore.replaceRelationsSafely(a, bs);
438
- };
439
- this.replaceRelationsUnsafely = (a, bs) => {
440
- externalStore.replaceRelationsUnsafely(a, bs);
441
- };
442
- this.getRelatedKeys = (key) => externalStore.getRelatedKeys(key);
443
- if (externalStore.getContent) {
444
- this.getContentInternal = (contentKey) => {
445
- return externalStore.getContent(contentKey);
446
- };
447
- this.setContent = (contentKey, content) => {
448
- externalStore.setContent(contentKey, content);
449
- };
450
- this.deleteContent = (contentKey) => {
451
- externalStore.deleteContent(contentKey);
452
- };
453
- }
454
- for (const [x, ys] of (_c = data.relations) != null ? _c : []) {
455
- for (const y of ys)
456
- this.addRelation(x, y);
457
- }
458
- for (const [contentKey, content] of (_d = data.contents) != null ? _d : []) {
459
- this.setContent(contentKey, content);
460
- }
536
+ // internal/src/set-state/copy-mutable-in-transaction.ts
537
+ function copyMutableIfWithinTransaction(oldValue, atom, store) {
538
+ const target = newest(store);
539
+ const parent = target.parent;
540
+ if (parent !== null) {
541
+ if (atom.type === `mutable_atom`) {
542
+ const copiedValue = copyMutableIfNeeded(atom, parent, target);
543
+ return copiedValue;
461
544
  }
462
545
  }
463
- getRelatedKeys(key) {
464
- return this.relations.get(key);
465
- }
466
- addRelation(a, b) {
467
- let aRelations = this.relations.get(a);
468
- let bRelations = this.relations.get(b);
469
- if (aRelations) {
470
- aRelations.add(b);
471
- } else {
472
- aRelations = /* @__PURE__ */ new Set([b]);
473
- this.relations.set(a, aRelations);
474
- }
475
- if (bRelations) {
476
- bRelations.add(a);
477
- } else {
478
- bRelations = /* @__PURE__ */ new Set([a]);
479
- this.relations.set(b, bRelations);
480
- }
546
+ return oldValue;
547
+ }
548
+
549
+ // internal/src/caching.ts
550
+ function cacheValue(key, value, subject, target) {
551
+ const currentValue = target.valueMap.get(key);
552
+ if (currentValue instanceof Future) {
553
+ currentValue.cancel();
481
554
  }
482
- deleteRelation(a, b) {
483
- const aRelations = this.relations.get(a);
484
- if (aRelations) {
485
- aRelations.delete(b);
486
- if (aRelations.size === 0) {
487
- this.relations.delete(a);
555
+ if (value instanceof Promise) {
556
+ const future = new Future(value);
557
+ target.valueMap.set(key, future);
558
+ future.then((resolved) => {
559
+ if (future.isCanceled) {
560
+ return;
488
561
  }
489
- const bRelations = this.relations.get(b);
490
- if (bRelations) {
491
- bRelations.delete(a);
492
- if (bRelations.size === 0) {
493
- this.relations.delete(b);
494
- }
562
+ cacheValue(key, resolved, subject, target);
563
+ subject.next({ newValue: resolved, oldValue: future });
564
+ }).catch((thrown) => {
565
+ if (thrown !== `canceled`) {
566
+ target.logger.error(`\u{1F4A5}`, `state`, key, `rejected:`, thrown);
495
567
  }
496
- }
568
+ });
569
+ return future;
497
570
  }
498
- replaceRelationsUnsafely(a, bs) {
499
- this.relations.set(a, new Set(bs));
500
- for (const b of bs) {
501
- const bRelations = /* @__PURE__ */ new Set([a]);
502
- this.relations.set(b, bRelations);
503
- }
571
+ target.valueMap.set(key, value);
572
+ return value;
573
+ }
574
+ var readCachedValue = (token, target) => {
575
+ let value = target.valueMap.get(token.key);
576
+ if (token.type === `atom`) {
577
+ value = copyMutableIfWithinTransaction(value, token, target);
504
578
  }
505
- replaceRelationsSafely(a, bs) {
506
- const aRelationsPrev = this.relations.get(a);
507
- if (aRelationsPrev) {
508
- for (const b of aRelationsPrev) {
509
- const bRelations = this.relations.get(b);
510
- if (bRelations) {
511
- if (bRelations.size === 1) {
512
- this.relations.delete(b);
513
- } else {
514
- bRelations.delete(a);
515
- }
516
- this.contents.delete(this.makeContentKey(a, b));
517
- }
518
- }
519
- }
520
- this.relations.set(a, new Set(bs));
521
- for (const b of bs) {
522
- let bRelations = this.relations.get(b);
523
- if (bRelations) {
524
- bRelations.add(a);
525
- } else {
526
- bRelations = /* @__PURE__ */ new Set([a]);
527
- this.relations.set(b, bRelations);
528
- }
529
- }
579
+ return value;
580
+ };
581
+ var evictCachedValue = (key, target) => {
582
+ const currentValue = target.valueMap.get(key);
583
+ if (currentValue instanceof Future) {
584
+ currentValue.cancel();
530
585
  }
531
- getContentInternal(contentKey) {
532
- return this.contents.get(contentKey);
586
+ if (target.operation.open) {
587
+ target.operation.prev.set(key, currentValue);
533
588
  }
534
- setContent(contentKey, content) {
535
- this.contents.set(contentKey, content);
589
+ target.valueMap.delete(key);
590
+ target.logger.info(`\u{1F5D1}`, `state`, key, `evicted`);
591
+ };
592
+
593
+ // internal/src/read-or-compute-value.ts
594
+ var readOrComputeValue = (state, target) => {
595
+ if (target.valueMap.has(state.key)) {
596
+ target.logger.info(`\u{1F4D6}`, state.type, state.key, `reading cached value`);
597
+ return readCachedValue(state, target);
536
598
  }
537
- deleteContent(contentKey) {
538
- this.contents.delete(contentKey);
599
+ if (state.type !== `atom` && state.type !== `mutable_atom`) {
600
+ target.logger.info(`\u{1F9EE}`, state.type, state.key, `computing value`);
601
+ return state.get();
539
602
  }
540
- toJSON() {
541
- return {
542
- between: [this.a, this.b],
543
- cardinality: this.cardinality,
544
- relations: [...this.relations.entries()].map(([a, b]) => [a, [...b]]),
545
- contents: [...this.contents.entries()]
546
- };
603
+ const fallback = state.default instanceof Function ? state.default() : state.default;
604
+ target.logger.info(
605
+ `\u{1F481}`,
606
+ `atom`,
607
+ state.key,
608
+ `could not find cached value; using default`,
609
+ fallback
610
+ );
611
+ return state.default instanceof Function ? state.default() : state.default;
612
+ };
613
+
614
+ // internal/src/set-state/become.ts
615
+ var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
616
+ originalThing instanceof Function ? originalThing() : originalThing
617
+ ) : nextVersionOfThing;
618
+
619
+ // internal/src/operation.ts
620
+ var openOperation = (token, store) => {
621
+ if (store.operation.open) {
622
+ store.logger.error(
623
+ `\u274C`,
624
+ token.type,
625
+ token.key,
626
+ `failed to setState during a setState for "${store.operation.token.key}"`
627
+ );
628
+ return `rejection`;
547
629
  }
548
- set(a, ...rest) {
549
- var _a;
550
- const b = typeof rest[0] === `string` ? rest[0] : a[this.b];
551
- const content = ((_a = rest[1]) != null ? _a : typeof rest[0] === `string`) ? void 0 : rest[0];
552
- a = typeof a === `string` ? a : a[this.a];
553
- switch (this.cardinality) {
554
- case `1:1`: {
555
- const bPrev = this.getRelatedKey(a);
556
- if (bPrev && bPrev !== b)
557
- this.delete(bPrev, a);
558
- }
559
- case `1:n`: {
560
- const aPrev = this.getRelatedKey(b);
561
- if (aPrev && aPrev !== a)
562
- this.delete(aPrev, b);
563
- }
564
- }
565
- if (content) {
566
- const contentKey = this.makeContentKey(a, b);
567
- this.setContent(contentKey, content);
568
- }
569
- this.addRelation(a, b);
570
- return this;
630
+ store.operation = {
631
+ open: true,
632
+ done: /* @__PURE__ */ new Set(),
633
+ prev: /* @__PURE__ */ new Map(),
634
+ time: Date.now(),
635
+ token
636
+ };
637
+ store.logger.info(
638
+ `\u2B55`,
639
+ token.type,
640
+ token.key,
641
+ `operation start in store "${store.config.name}"${store.transactionMeta === null ? `` : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`}`
642
+ );
643
+ };
644
+ var closeOperation = (store) => {
645
+ if (store.operation.open) {
646
+ store.logger.info(
647
+ `\u{1F534}`,
648
+ store.operation.token.type,
649
+ store.operation.token.key,
650
+ `operation done in store "${store.config.name}"`
651
+ );
571
652
  }
572
- delete(x, b) {
573
- b = typeof b === `string` ? b : x[this.b];
574
- const a = typeof x === `string` ? x : x[this.a];
575
- if (a === void 0 && typeof b === `string`) {
576
- const bRelations = this.getRelatedKeys(b);
577
- if (bRelations) {
578
- for (const a2 of bRelations) {
579
- this.delete(a2, b);
580
- }
581
- }
582
- }
583
- if (typeof a === `string` && b === void 0) {
584
- const aRelations = this.getRelatedKeys(a);
585
- if (aRelations) {
586
- for (const b2 of aRelations) {
587
- this.delete(a, b2);
588
- }
589
- }
590
- }
591
- if (typeof a === `string` && typeof b === `string`) {
592
- this.deleteRelation(a, b);
593
- const contentKey = this.makeContentKey(a, b);
594
- this.deleteContent(contentKey);
595
- }
596
- return this;
653
+ store.operation = { open: false };
654
+ store.on.operationClose.next(store.operation);
655
+ };
656
+ var isDone = (key, store) => {
657
+ if (!store.operation.open) {
658
+ store.logger.warn(
659
+ `\u{1F41E}`,
660
+ `unknown`,
661
+ key,
662
+ `isDone called outside of an operation. This is probably a bug.`
663
+ );
664
+ return true;
597
665
  }
598
- getRelatedKey(key) {
599
- const relations = this.getRelatedKeys(key);
600
- if (relations) {
601
- if (relations.size > 1) {
602
- console.warn(
603
- `${relations.size} related keys were found for key "${key}": (${[
604
- ...relations
605
- ].map((k) => `"${k}"`).join(`, `)}). Only one related key was expected.`
606
- );
607
- }
608
- for (const relation of relations) {
609
- return relation;
610
- }
611
- }
666
+ return store.operation.done.has(key);
667
+ };
668
+ var markDone = (key, store) => {
669
+ if (!store.operation.open) {
670
+ store.logger.warn(
671
+ `\u{1F41E}`,
672
+ `unknown`,
673
+ key,
674
+ `markDone called outside of an operation. This is probably a bug.`
675
+ );
676
+ return;
612
677
  }
613
- replaceRelations(a, relations, config) {
614
- const hasContent = !Array.isArray(relations);
615
- const bs = hasContent ? Object.keys(relations) : relations;
616
- if (config == null ? void 0 : config.reckless) {
617
- this.replaceRelationsUnsafely(a, bs);
618
- } else {
619
- this.replaceRelationsSafely(a, bs);
620
- }
621
- if (hasContent) {
622
- for (const b of bs) {
623
- const contentKey = this.makeContentKey(a, b);
624
- const content = relations[b];
625
- this.setContent(contentKey, content);
626
- }
627
- }
628
- return this;
629
- }
630
- getContent(a, b) {
631
- const contentKey = this.makeContentKey(a, b);
632
- return this.getContentInternal(contentKey);
633
- }
634
- getRelationEntries(input) {
635
- const a = input[this.a];
636
- const b = input[this.b];
637
- if (a !== void 0 && b === void 0) {
638
- const aRelations = this.getRelatedKeys(a);
639
- if (aRelations) {
640
- return [...aRelations].map((b2) => {
641
- var _a;
642
- return [b2, (_a = this.getContent(a, b2)) != null ? _a : null];
643
- });
644
- }
678
+ store.operation.done.add(key);
679
+ };
680
+
681
+ // internal/src/set-state/emit-update.ts
682
+ var emitUpdate = (state, update, store) => {
683
+ store.logger.info(
684
+ `\u{1F4E2}`,
685
+ state.type,
686
+ state.key,
687
+ `went (`,
688
+ update.oldValue,
689
+ `->`,
690
+ update.newValue,
691
+ `) subscribers:`,
692
+ state.subject.subscribers
693
+ );
694
+ state.subject.next(update);
695
+ };
696
+
697
+ // internal/src/set-state/evict-downstream.ts
698
+ var evictDownStream = (atom, store) => {
699
+ const downstreamKeys = store.selectorAtoms.getRelatedKeys(atom.key);
700
+ store.logger.info(
701
+ `\u{1F9F9}`,
702
+ atom.type,
703
+ atom.key,
704
+ downstreamKeys ? `evicting ${downstreamKeys.size} states downstream:` : `no downstream states`,
705
+ downstreamKeys != null ? downstreamKeys : `to evict`
706
+ );
707
+ if (downstreamKeys) {
708
+ if (store.operation.open) {
709
+ store.logger.info(
710
+ `\u{1F9F9}`,
711
+ atom.type,
712
+ atom.key,
713
+ `[ ${[...store.operation.done].join(`, `)} ] already done`
714
+ );
645
715
  }
646
- if (a === void 0 && b !== void 0) {
647
- const bRelations = this.getRelatedKeys(b);
648
- if (bRelations) {
649
- return [...bRelations].map((a2) => {
650
- var _a;
651
- return [a2, (_a = this.getContent(a2, b)) != null ? _a : null];
652
- });
716
+ for (const key of downstreamKeys) {
717
+ if (isDone(key, store)) {
718
+ continue;
653
719
  }
720
+ evictCachedValue(key, store);
721
+ markDone(key, store);
654
722
  }
655
- return [];
656
- }
657
- has(a, b) {
658
- var _a;
659
- if (b) {
660
- const setA = this.getRelatedKeys(a);
661
- return (_a = setA == null ? void 0 : setA.has(b)) != null ? _a : false;
662
- }
663
- return this.relations.has(a);
664
723
  }
665
724
  };
666
725
 
667
- // internal/src/store/store.ts
668
- var Store = class {
669
- constructor(name, store = null) {
670
- this.parent = null;
671
- this.child = null;
672
- this.valueMap = /* @__PURE__ */ new Map();
673
- this.atoms = /* @__PURE__ */ new Map();
674
- this.selectors = /* @__PURE__ */ new Map();
675
- this.readonlySelectors = /* @__PURE__ */ new Map();
676
- this.trackers = /* @__PURE__ */ new Map();
677
- this.families = /* @__PURE__ */ new Map();
678
- this.timelines = /* @__PURE__ */ new Map();
679
- this.transactions = /* @__PURE__ */ new Map();
680
- this.atomsThatAreDefault = /* @__PURE__ */ new Set();
681
- this.timelineAtoms = new Junction({
682
- between: [`timelineKey`, `atomKey`],
683
- cardinality: `1:n`
684
- });
685
- this.selectorAtoms = new Junction({
686
- between: [`selectorKey`, `atomKey`],
687
- cardinality: `n:n`
688
- });
689
- this.selectorGraph = new Junction(
690
- {
691
- between: [`upstreamSelectorKey`, `downstreamSelectorKey`],
692
- cardinality: `n:n`
693
- },
694
- {
695
- makeContentKey: (...keys) => keys.sort().join(`:`)
696
- }
726
+ // internal/src/set-state/stow-update.ts
727
+ function shouldUpdateBeStowed(key, update) {
728
+ if (isTransceiver(update.newValue)) {
729
+ return false;
730
+ }
731
+ if (key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
732
+ return false;
733
+ }
734
+ return true;
735
+ }
736
+ var stowUpdate = (state, update, store) => {
737
+ const { key } = state;
738
+ const target = newest(store);
739
+ if (target.transactionMeta === null || target.transactionMeta.phase !== `building`) {
740
+ store.logger.error(
741
+ `\u{1F41E}`,
742
+ `atom`,
743
+ key,
744
+ `stowUpdate called outside of a transaction. This is probably a bug.`
697
745
  );
698
- this.on = {
699
- atomCreation: new Subject(),
700
- selectorCreation: new Subject(),
701
- transactionCreation: new Subject(),
702
- timelineCreation: new Subject(),
703
- transactionApplying: new StatefulSubject(null),
704
- operationClose: new Subject()
705
- };
706
- this.operation = { open: false };
707
- this.transactionMeta = null;
708
- this.config = {
709
- name: `IMPLICIT_STORE`
710
- };
711
- this.loggers = [
712
- new atom_io.AtomIOLogger(`warn`, (_, __, key) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`))
713
- ];
714
- this.logger = {
715
- error: (...messages) => {
716
- for (const logger of this.loggers)
717
- logger.error(...messages);
718
- },
719
- info: (...messages) => {
720
- for (const logger of this.loggers)
721
- logger.info(...messages);
722
- },
723
- warn: (...messages) => {
724
- for (const logger of this.loggers)
725
- logger.warn(...messages);
726
- }
727
- };
728
- if (store !== null) {
729
- this.valueMap = new Map(store == null ? void 0 : store.valueMap);
730
- this.operation = __spreadValues({}, store == null ? void 0 : store.operation);
731
- this.transactionMeta = (store == null ? void 0 : store.transactionMeta) ? __spreadValues({}, store == null ? void 0 : store.transactionMeta) : null;
732
- this.config = __spreadProps(__spreadValues({}, store == null ? void 0 : store.config), {
733
- name
734
- });
735
- for (const [, family] of store.families) {
736
- family.install(this);
737
- }
738
- const mutableHelpers = /* @__PURE__ */ new Set();
739
- for (const [, atom] of store.atoms) {
740
- if (mutableHelpers.has(atom.key)) {
741
- continue;
742
- }
743
- atom.install(this);
744
- if (`mutable` in atom) {
745
- const originalJsonToken = getJsonToken(atom);
746
- const originalUpdateToken = getUpdateToken(atom);
747
- mutableHelpers.add(originalJsonToken.key);
748
- mutableHelpers.add(originalUpdateToken.key);
749
- }
750
- }
751
- for (const [, selector] of store.readonlySelectors) {
752
- selector.install(this);
753
- }
754
- for (const [, selector] of store.selectors) {
755
- if (mutableHelpers.has(selector.key)) {
756
- continue;
757
- }
758
- selector.install(this);
759
- }
760
- for (const [, tx] of store.transactions) {
761
- tx.install(this);
762
- }
763
- for (const [, timeline] of store.timelines) {
764
- timeline.install(this);
765
- }
766
- }
746
+ return;
767
747
  }
768
- };
769
- var IMPLICIT = {
770
- STORE_INTERNAL: void 0,
771
- get STORE() {
772
- var _a;
773
- return (_a = this.STORE_INTERNAL) != null ? _a : this.STORE_INTERNAL = new Store(`IMPLICIT_STORE`);
748
+ const shouldStow = shouldUpdateBeStowed(key, update);
749
+ if (!shouldStow) {
750
+ return;
774
751
  }
775
- };
776
- var clearStore = (store) => {
777
- const { config } = store;
778
- Object.assign(store, new Store(config.name));
779
- store.config = config;
752
+ const atomUpdate = __spreadValues({ key }, update);
753
+ if (state.family) {
754
+ atomUpdate.family = state.family;
755
+ }
756
+ target.transactionMeta.update.updates.push(atomUpdate);
757
+ store.logger.info(
758
+ `\u{1F4C1}`,
759
+ `atom`,
760
+ key,
761
+ `stowed (`,
762
+ update.oldValue,
763
+ `->`,
764
+ update.newValue,
765
+ `)`
766
+ );
780
767
  };
781
768
 
782
- // internal/src/store/withdraw.ts
783
- function withdraw(token, store) {
784
- let withdrawn;
785
- let target = store;
786
- while (target !== null) {
787
- switch (token.type) {
788
- case `atom`:
789
- withdrawn = target.atoms.get(token.key);
790
- break;
791
- case `selector`:
792
- withdrawn = target.selectors.get(token.key);
793
- break;
794
- case `readonly_selector`:
795
- withdrawn = target.readonlySelectors.get(token.key);
796
- break;
797
- case `timeline`:
798
- withdrawn = target.timelines.get(token.key);
799
- break;
800
- case `transaction`:
801
- withdrawn = target.transactions.get(token.key);
802
- break;
803
- }
804
- if (withdrawn) {
805
- return withdrawn;
769
+ // internal/src/set-state/set-atom.ts
770
+ var setAtom = (atom, next, target) => {
771
+ const oldValue = readOrComputeValue(atom, target);
772
+ let newValue = copyMutableIfWithinTransaction(oldValue, atom, target);
773
+ newValue = become(next)(newValue);
774
+ target.logger.info(`\u{1F4DD}`, `atom`, atom.key, `set to`, newValue);
775
+ newValue = cacheValue(atom.key, newValue, atom.subject, target);
776
+ if (isAtomDefault(atom.key, target)) {
777
+ markAtomAsNotDefault(atom.key, target);
778
+ }
779
+ markDone(atom.key, target);
780
+ evictDownStream(atom, target);
781
+ const update = { oldValue, newValue };
782
+ if (target.transactionMeta === null) {
783
+ emitUpdate(atom, update, target);
784
+ } else if (target.on.transactionApplying && target.parent) {
785
+ stowUpdate(atom, update, target);
786
+ if (atom.key.startsWith(`*`)) {
787
+ const mutableKey = atom.key.slice(1);
788
+ const mutable = target.valueMap.get(mutableKey);
789
+ mutable.do(update.newValue);
806
790
  }
807
- target = target.child;
808
791
  }
809
- }
792
+ };
810
793
 
811
- // internal/src/store/withdraw-new-family-member.ts
812
- function withdrawNewFamilyMember(token, store) {
813
- if (token.family) {
814
- store.logger.info(
815
- `\u{1F46A}`,
816
- token.type,
817
- token.key,
818
- `creating new family member in store "${store.config.name}"`
819
- );
820
- const target = newest(store);
821
- const family = target.families.get(token.family.key);
822
- if (family) {
823
- const jsonSubKey = JSON.parse(token.family.subKey);
824
- family(jsonSubKey);
825
- const state = withdraw(token, store);
826
- return state;
827
- }
794
+ // internal/src/set-state/set-atom-or-selector.ts
795
+ var setAtomOrSelector = (state, value, store) => {
796
+ switch (state.type) {
797
+ case `atom`:
798
+ case `mutable_atom`:
799
+ setAtom(state, value, store);
800
+ break;
801
+ case `selector`:
802
+ state.set(value);
803
+ break;
828
804
  }
829
- return void 0;
830
- }
805
+ };
831
806
 
832
807
  // internal/src/keys.ts
833
808
  var isAtomKey = (key, store) => newest(store).atoms.has(key);
@@ -867,7 +842,8 @@ var traceSelectorAtoms = (selectorKey, directDependencyKey, store) => {
867
842
  }
868
843
  return rootKeys;
869
844
  };
870
- var traceAllSelectorAtoms = (selectorKey, store) => {
845
+ var traceAllSelectorAtoms = (selector, store) => {
846
+ const selectorKey = selector.key;
871
847
  const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store);
872
848
  return directDependencyKeys.flatMap(
873
849
  (depKey) => isAtomKey(depKey, store) ? depKey : traceSelectorAtoms(selectorKey, depKey, store)
@@ -877,7 +853,7 @@ var traceAllSelectorAtoms = (selectorKey, store) => {
877
853
  // internal/src/selector/update-selector-atoms.ts
878
854
  var updateSelectorAtoms = (selectorKey, dependency, store) => {
879
855
  const target = newest(store);
880
- if (dependency.type === `atom`) {
856
+ if (dependency.type === `atom` || dependency.type === `mutable_atom`) {
881
857
  target.selectorAtoms.set({
882
858
  selectorKey,
883
859
  atomKey: dependency.key
@@ -948,8 +924,44 @@ var registerSelector = (selectorKey, store) => ({
948
924
  find: (token, key) => atom_io.findInStore(token, key, store)
949
925
  });
950
926
 
951
- // internal/src/selector/create-read-write-selector.ts
952
- var createReadWriteSelector = (options, family, store) => {
927
+ // internal/src/selector/create-readonly-selector.ts
928
+ var createReadonlySelector = (options, family, store) => {
929
+ const target = newest(store);
930
+ const subject = new Subject();
931
+ const { get, find } = registerSelector(options.key, store);
932
+ const getSelf = () => {
933
+ const value = options.get({ get, find });
934
+ cacheValue(options.key, value, subject, store);
935
+ return value;
936
+ };
937
+ const readonlySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
938
+ subject,
939
+ install: (s) => createReadonlySelector(options, family, s),
940
+ get: getSelf,
941
+ type: `readonly_selector`
942
+ }), family && { family });
943
+ target.readonlySelectors.set(options.key, readonlySelector);
944
+ const initialValue = getSelf();
945
+ store.logger.info(
946
+ `\u2728`,
947
+ readonlySelector.type,
948
+ readonlySelector.key,
949
+ `=`,
950
+ initialValue
951
+ );
952
+ const token = {
953
+ key: options.key,
954
+ type: `readonly_selector`
955
+ };
956
+ if (family) {
957
+ token.family = family;
958
+ }
959
+ store.on.selectorCreation.next(token);
960
+ return token;
961
+ };
962
+
963
+ // internal/src/selector/create-writable-selector.ts
964
+ var createWritableSelector = (options, family, store) => {
953
965
  const target = newest(store);
954
966
  const subject = new Subject();
955
967
  const transactors = registerSelector(options.key, store);
@@ -982,7 +994,7 @@ var createReadWriteSelector = (options, family, store) => {
982
994
  };
983
995
  const mySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
984
996
  subject,
985
- install: (s) => createSelector(options, family, s),
997
+ install: (s) => createWritableSelector(options, family, s),
986
998
  get: getSelf,
987
999
  set: setSelf,
988
1000
  type: `selector`
@@ -1001,59 +1013,13 @@ var createReadWriteSelector = (options, family, store) => {
1001
1013
  return token;
1002
1014
  };
1003
1015
 
1004
- // internal/src/selector/create-readonly-selector.ts
1005
- var createReadonlySelector = (options, family, store) => {
1006
- const target = newest(store);
1007
- const subject = new Subject();
1008
- const { get, find } = registerSelector(options.key, store);
1009
- const getSelf = () => {
1010
- const value = options.get({ get, find });
1011
- cacheValue(options.key, value, subject, store);
1012
- return value;
1013
- };
1014
- const readonlySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
1015
- subject,
1016
- install: (s) => createSelector(options, family, s),
1017
- get: getSelf,
1018
- type: `readonly_selector`
1019
- }), family && { family });
1020
- target.readonlySelectors.set(options.key, readonlySelector);
1021
- const initialValue = getSelf();
1022
- store.logger.info(
1023
- `\u2728`,
1024
- readonlySelector.type,
1025
- readonlySelector.key,
1026
- `=`,
1027
- initialValue
1028
- );
1029
- const token = {
1030
- key: options.key,
1031
- type: `readonly_selector`
1032
- };
1033
- if (family) {
1034
- token.family = family;
1035
- }
1036
- store.on.selectorCreation.next(token);
1037
- return token;
1038
- };
1039
-
1040
- // internal/src/selector/create-selector.ts
1041
- function createSelector(options, family, store) {
1042
- const target = newest(store);
1043
- const existingWritable = target.selectors.get(options.key);
1044
- const existingReadonly = target.readonlySelectors.get(options.key);
1045
- if (existingWritable || existingReadonly) {
1046
- store.logger.error(
1047
- `\u274C`,
1048
- existingReadonly ? `readonly_selector` : `selector`,
1049
- options.key,
1050
- `Tried to create selector, but it already exists in the store.`
1051
- );
1016
+ // internal/src/selector/create-standalone-selector.ts
1017
+ function createStandaloneSelector(options, store) {
1018
+ const isWritable = `set` in options;
1019
+ if (isWritable) {
1020
+ return createWritableSelector(options, void 0, store);
1052
1021
  }
1053
- if (`set` in options) {
1054
- return createReadWriteSelector(options, family, store);
1055
- }
1056
- return createReadonlySelector(options, family, store);
1022
+ return createReadonlySelector(options, void 0, store);
1057
1023
  }
1058
1024
 
1059
1025
  // internal/src/selector/delete-selector.ts
@@ -1095,44 +1061,46 @@ var recallState = (state, store) => {
1095
1061
  };
1096
1062
 
1097
1063
  // internal/src/subscribe/subscribe-to-root-atoms.ts
1098
- var subscribeToRootAtoms = (state, store) => {
1064
+ var subscribeToRootAtoms = (selector, store) => {
1099
1065
  const target = newest(store);
1100
- const dependencySubscriptions = `default` in state ? null : traceAllSelectorAtoms(state.key, store).map((atomKey) => {
1101
- const atom = target.atoms.get(atomKey);
1102
- if (atom === void 0) {
1103
- throw new Error(
1104
- `Atom "${atomKey}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`
1105
- );
1106
- }
1107
- return atom.subject.subscribe(
1108
- `${state.type}:${state.key}`,
1109
- (atomChange) => {
1110
- store.logger.info(
1111
- `\u{1F4E2}`,
1112
- state.type,
1113
- state.key,
1114
- `root`,
1115
- atomKey,
1116
- `went`,
1117
- atomChange.oldValue,
1118
- `->`,
1119
- atomChange.newValue
1120
- );
1121
- const oldValue = recallState(state, target);
1122
- const newValue = readOrComputeValue(state, target);
1123
- store.logger.info(
1124
- `\u2728`,
1125
- state.type,
1126
- state.key,
1127
- `went`,
1128
- oldValue,
1129
- `->`,
1130
- newValue
1066
+ const dependencySubscriptions = traceAllSelectorAtoms(selector, store).map(
1067
+ (atomKey) => {
1068
+ const atom = target.atoms.get(atomKey);
1069
+ if (atom === void 0) {
1070
+ throw new Error(
1071
+ `Atom "${atomKey}", a dependency of selector "${selector.key}", not found in store "${store.config.name}".`
1131
1072
  );
1132
- state.subject.next({ newValue, oldValue });
1133
1073
  }
1134
- );
1135
- });
1074
+ return atom.subject.subscribe(
1075
+ `${selector.type}:${selector.key}`,
1076
+ (atomChange) => {
1077
+ store.logger.info(
1078
+ `\u{1F4E2}`,
1079
+ selector.type,
1080
+ selector.key,
1081
+ `root`,
1082
+ atomKey,
1083
+ `went`,
1084
+ atomChange.oldValue,
1085
+ `->`,
1086
+ atomChange.newValue
1087
+ );
1088
+ const oldValue = recallState(selector, target);
1089
+ const newValue = readOrComputeValue(selector, target);
1090
+ store.logger.info(
1091
+ `\u2728`,
1092
+ selector.type,
1093
+ selector.key,
1094
+ `went`,
1095
+ oldValue,
1096
+ `->`,
1097
+ newValue
1098
+ );
1099
+ selector.subject.next({ newValue, oldValue });
1100
+ }
1101
+ );
1102
+ }
1103
+ );
1136
1104
  return dependencySubscriptions;
1137
1105
  };
1138
1106
 
@@ -1147,7 +1115,7 @@ function subscribeToState(token, handleUpdate, key, store) {
1147
1115
  }
1148
1116
  const unsubFunction = state.subject.subscribe(key, handleUpdate);
1149
1117
  store.logger.info(`\u{1F440}`, state.type, state.key, `Adding subscription "${key}"`);
1150
- const dependencyUnsubFunctions = state.type !== `atom` ? subscribeToRootAtoms(state, store) : null;
1118
+ const dependencyUnsubFunctions = state.type !== `atom` && state.type !== `mutable_atom` ? subscribeToRootAtoms(state, store) : null;
1151
1119
  const unsubscribe = dependencyUnsubFunctions === null ? () => {
1152
1120
  store.logger.info(
1153
1121
  `\u{1F648}`,
@@ -1358,27 +1326,67 @@ var Tracker = class {
1358
1326
  // internal/src/mutable/create-mutable-atom.ts
1359
1327
  function createMutableAtom(options, family, store) {
1360
1328
  store.logger.info(
1361
- `\u{1F527}`,
1329
+ `\u{1F528}`,
1362
1330
  `atom`,
1363
1331
  options.key,
1364
1332
  `creating in store "${store.config.name}"`
1365
1333
  );
1366
- const coreState = createRegularAtom(options, family, store);
1367
- new Tracker(coreState, store);
1368
- const jsonState = json.selectJson(coreState, options, store);
1369
1334
  const target = newest(store);
1370
- subscribeToState(
1371
- jsonState,
1372
- () => {
1373
- const trackerHasBeenInitialized = newest(store).trackers.has(coreState.key);
1374
- if (!trackerHasBeenInitialized) {
1375
- new Tracker(coreState, store);
1376
- }
1335
+ const existing = target.atoms.get(options.key);
1336
+ if (existing && existing.type === `mutable_atom`) {
1337
+ store.logger.error(
1338
+ `\u274C`,
1339
+ `atom`,
1340
+ options.key,
1341
+ `Tried to create atom, but it already exists in the store.`
1342
+ );
1343
+ return deposit(existing);
1344
+ }
1345
+ const subject = new Subject();
1346
+ const newAtom = __spreadProps(__spreadValues({}, options), {
1347
+ type: `mutable_atom`,
1348
+ install: (store2) => {
1349
+ store2.logger.info(
1350
+ `\u{1F6E0}\uFE0F`,
1351
+ `atom`,
1352
+ options.key,
1353
+ `installing in store "${store2.config.name}"`
1354
+ );
1355
+ return createMutableAtom(options, family, store2);
1377
1356
  },
1378
- `tracker-initializer:${store == null ? void 0 : store.config.name}:${target.transactionMeta === null ? `main` : `${target.transactionMeta.update.key}`}`,
1379
- store
1380
- );
1381
- return coreState;
1357
+ subject
1358
+ });
1359
+ if (family) {
1360
+ newAtom.family = family;
1361
+ }
1362
+ const initialValue = options.default();
1363
+ target.atoms.set(newAtom.key, newAtom);
1364
+ markAtomAsDefault(options.key, store);
1365
+ cacheValue(options.key, initialValue, subject, target);
1366
+ const token = deposit(newAtom);
1367
+ if (options.effects) {
1368
+ let effectIndex = 0;
1369
+ const cleanupFunctions = [];
1370
+ for (const effect of options.effects) {
1371
+ const cleanup = effect({
1372
+ setSelf: (next) => atom_io.setState(token, next, store),
1373
+ onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
1374
+ });
1375
+ if (cleanup) {
1376
+ cleanupFunctions.push(cleanup);
1377
+ }
1378
+ ++effectIndex;
1379
+ }
1380
+ newAtom.cleanup = () => {
1381
+ for (const cleanup of cleanupFunctions) {
1382
+ cleanup();
1383
+ }
1384
+ };
1385
+ }
1386
+ new Tracker(token, store);
1387
+ json.selectJson(token, options, store);
1388
+ store.on.atomCreation.next(token);
1389
+ return token;
1382
1390
  }
1383
1391
  function createRegularAtomFamily(options, store) {
1384
1392
  const subject = new Subject();
@@ -1399,16 +1407,7 @@ function createRegularAtomFamily(options, store) {
1399
1407
  if (options.effects) {
1400
1408
  individualOptions.effects = options.effects(key);
1401
1409
  }
1402
- if (`mutable` in options) {
1403
- const mutableOptions = __spreadProps(__spreadValues({}, individualOptions), {
1404
- mutable: true,
1405
- toJson: options.toJson,
1406
- fromJson: options.fromJson
1407
- });
1408
- token = createMutableAtom(mutableOptions, family, store);
1409
- } else {
1410
- token = createRegularAtom(individualOptions, family, store);
1411
- }
1410
+ token = createRegularAtom(individualOptions, family, store);
1412
1411
  subject.next(token);
1413
1412
  }
1414
1413
  return token;
@@ -1420,9 +1419,6 @@ function createRegularAtomFamily(options, store) {
1420
1419
  install: (store2) => createRegularAtomFamily(options, store2)
1421
1420
  }
1422
1421
  );
1423
- if (`mutable` in options && typeof options.mutable === `boolean`) {
1424
- Object.assign(atomFamily, { mutable: options.mutable });
1425
- }
1426
1422
  const target = newest(store);
1427
1423
  target.families.set(options.key, atomFamily);
1428
1424
  return atomFamily;
@@ -1430,7 +1426,8 @@ function createRegularAtomFamily(options, store) {
1430
1426
 
1431
1427
  // internal/src/families/create-atom-family.ts
1432
1428
  function createAtomFamily(options, store) {
1433
- if (`mutable` in options) {
1429
+ const isMutable2 = `mutable` in options;
1430
+ if (isMutable2) {
1434
1431
  return createMutableAtomFamily(options, store);
1435
1432
  }
1436
1433
  return createRegularAtomFamily(options, store);
@@ -1447,7 +1444,7 @@ function createReadonlySelectorFamily(options, store) {
1447
1444
  if (existing) {
1448
1445
  return deposit(existing);
1449
1446
  }
1450
- return createSelector(
1447
+ return createReadonlySelector(
1451
1448
  {
1452
1449
  key: fullKey,
1453
1450
  get: options.get(key)
@@ -1466,23 +1463,18 @@ function createReadonlySelectorFamily(options, store) {
1466
1463
  store.families.set(options.key, readonlySelectorFamily);
1467
1464
  return readonlySelectorFamily;
1468
1465
  }
1469
- function createSelectorFamily(options, store) {
1470
- const isReadonly = !(`set` in options);
1471
- if (isReadonly) {
1472
- return createReadonlySelectorFamily(options, store);
1473
- }
1474
- const target = newest(store);
1466
+ function createWritableSelectorFamily(options, store) {
1475
1467
  const subject = new Subject();
1476
1468
  const selectorFamily = Object.assign(
1477
1469
  (key) => {
1478
1470
  const subKey = json.stringifyJson(key);
1479
1471
  const family = { key: options.key, subKey };
1480
1472
  const fullKey = `${options.key}(${subKey})`;
1481
- const existing = target.selectors.get(fullKey);
1473
+ const existing = store.selectors.get(fullKey);
1482
1474
  if (existing) {
1483
1475
  return deposit(existing);
1484
1476
  }
1485
- const token = createSelector(
1477
+ const token = createWritableSelector(
1486
1478
  {
1487
1479
  key: fullKey,
1488
1480
  get: options.get(key),
@@ -1498,13 +1490,22 @@ function createSelectorFamily(options, store) {
1498
1490
  key: options.key,
1499
1491
  type: `selector_family`,
1500
1492
  subject,
1501
- install: (store2) => createSelectorFamily(options, store2)
1493
+ install: (store2) => createWritableSelectorFamily(options, store2)
1502
1494
  }
1503
1495
  );
1504
- target.families.set(options.key, selectorFamily);
1496
+ store.families.set(options.key, selectorFamily);
1505
1497
  return selectorFamily;
1506
1498
  }
1507
1499
 
1500
+ // internal/src/families/create-selector-family.ts
1501
+ function createSelectorFamily(options, store) {
1502
+ const isWritable = `set` in options;
1503
+ if (isWritable) {
1504
+ return createWritableSelectorFamily(options, store);
1505
+ }
1506
+ return createReadonlySelectorFamily(options, store);
1507
+ }
1508
+
1508
1509
  // internal/src/mutable/tracker-family.ts
1509
1510
  var FamilyTracker = class {
1510
1511
  constructor(findMutableState, store) {
@@ -1541,29 +1542,63 @@ var FamilyTracker = class {
1541
1542
 
1542
1543
  // internal/src/mutable/create-mutable-atom-family.ts
1543
1544
  function createMutableAtomFamily(options, store) {
1544
- const coreFamily = Object.assign(
1545
- createRegularAtomFamily(options, store),
1546
- options
1545
+ const subject = new Subject();
1546
+ const atomFamily = Object.assign(
1547
+ (key) => {
1548
+ const subKey = json.stringifyJson(key);
1549
+ const family = { key: options.key, subKey };
1550
+ const fullKey = `${options.key}(${subKey})`;
1551
+ const existing = withdraw({ key: fullKey, type: `mutable_atom` }, store);
1552
+ let token;
1553
+ if (existing) {
1554
+ token = deposit(existing);
1555
+ } else {
1556
+ const individualOptions = {
1557
+ key: fullKey,
1558
+ default: () => options.default(key),
1559
+ toJson: options.toJson,
1560
+ fromJson: options.fromJson,
1561
+ mutable: true
1562
+ };
1563
+ if (options.effects) {
1564
+ individualOptions.effects = options.effects(key);
1565
+ }
1566
+ token = createMutableAtom(individualOptions, family, store);
1567
+ subject.next(token);
1568
+ }
1569
+ return token;
1570
+ },
1571
+ {
1572
+ key: options.key,
1573
+ type: `mutable_atom_family`,
1574
+ subject,
1575
+ install: (store2) => createMutableAtomFamily(options, store2),
1576
+ toJson: options.toJson,
1577
+ fromJson: options.fromJson
1578
+ }
1547
1579
  );
1548
- json.selectJsonFamily(coreFamily, options);
1549
- new FamilyTracker(coreFamily, store);
1550
- return coreFamily;
1580
+ const target = newest(store);
1581
+ target.families.set(options.key, atomFamily);
1582
+ json.selectJsonFamily(atomFamily, options, store);
1583
+ new FamilyTracker(atomFamily, store);
1584
+ return atomFamily;
1551
1585
  }
1552
1586
 
1553
1587
  // internal/src/mutable/get-json-family.ts
1554
1588
  var getJsonFamily = (mutableAtomFamily, store) => {
1555
1589
  const target = newest(store);
1556
1590
  const key = `${mutableAtomFamily.key}:JSON`;
1557
- const jsonFamily = target.families.get(
1558
- key
1559
- );
1591
+ const jsonFamily = target.families.get(key);
1560
1592
  return jsonFamily;
1561
1593
  };
1562
1594
 
1563
1595
  // internal/src/mutable/get-json-token.ts
1564
1596
  var getJsonToken = (mutableAtomToken) => {
1565
1597
  const key = mutableAtomToken.family ? `${mutableAtomToken.family.key}:JSON(${mutableAtomToken.family.subKey})` : `${mutableAtomToken.key}:JSON`;
1566
- const jsonToken = { type: `selector`, key };
1598
+ const jsonToken = {
1599
+ type: `selector`,
1600
+ key
1601
+ };
1567
1602
  if (mutableAtomToken.family) {
1568
1603
  jsonToken.family = {
1569
1604
  key: `${mutableAtomToken.family.key}:JSON`,
@@ -1586,13 +1621,10 @@ var getUpdateToken = (mutableAtomToken) => {
1586
1621
  return updateToken;
1587
1622
  };
1588
1623
 
1589
- // internal/src/mutable/get-update-family.ts
1590
- var getUpdateFamily = (mutableAtomFamily, store) => {
1591
- const target = newest(store);
1592
- const key = `*${mutableAtomFamily.key}`;
1593
- const updateFamily = target.families.get(key);
1594
- return updateFamily;
1595
- };
1624
+ // internal/src/mutable/is-mutable.ts
1625
+ function isMutable(atomOrTokenOrFamily) {
1626
+ return atomOrTokenOrFamily.type === `mutable_atom` || atomOrTokenOrFamily.type === `mutable_atom_family`;
1627
+ }
1596
1628
 
1597
1629
  // internal/src/mutable/transceiver.ts
1598
1630
  function isTransceiver(value) {
@@ -1624,7 +1656,7 @@ function createRegularAtom(options, family, store) {
1624
1656
  );
1625
1657
  const target = newest(store);
1626
1658
  const existing = target.atoms.get(options.key);
1627
- if (existing) {
1659
+ if (existing && existing.type === `atom`) {
1628
1660
  store.logger.error(
1629
1661
  `\u274C`,
1630
1662
  `atom`,
@@ -1643,7 +1675,7 @@ function createRegularAtom(options, family, store) {
1643
1675
  options.key,
1644
1676
  `installing in store "${store2.config.name}"`
1645
1677
  );
1646
- return `mutable` in options ? createMutableAtom(options, family, store2) : createRegularAtom(options, family, store2);
1678
+ return createRegularAtom(options, family, store2);
1647
1679
  },
1648
1680
  subject
1649
1681
  });
@@ -1681,12 +1713,13 @@ function createRegularAtom(options, family, store) {
1681
1713
  return token;
1682
1714
  }
1683
1715
 
1684
- // internal/src/atom/create-atom.ts
1685
- function createAtom(options, family, store) {
1686
- if (`mutable` in options) {
1687
- return createMutableAtom(options, family, store);
1716
+ // internal/src/atom/create-standalone-atom.ts
1717
+ function createStandaloneAtom(options, store) {
1718
+ const isMutable2 = `mutable` in options;
1719
+ if (isMutable2) {
1720
+ return createMutableAtom(options, void 0, store);
1688
1721
  }
1689
- return createRegularAtom(options, family, store);
1722
+ return createRegularAtom(options, void 0, store);
1690
1723
  }
1691
1724
 
1692
1725
  // internal/src/atom/delete-atom.ts
@@ -1807,9 +1840,8 @@ var NotFoundError = class extends Error {
1807
1840
  // internal/src/timeline/add-atom-to-timeline.ts
1808
1841
  var addAtomToTimeline = (atomToken, tl, store) => {
1809
1842
  let maybeAtom = withdraw(atomToken, store);
1810
- if (maybeAtom == null ? void 0 : maybeAtom.mutable) {
1811
- console.log(`adding transceiver to timeline`, atomToken.key);
1812
- const updateToken = getUpdateToken(atomToken);
1843
+ if ((maybeAtom == null ? void 0 : maybeAtom.type) === `mutable_atom`) {
1844
+ const updateToken = getUpdateToken(maybeAtom);
1813
1845
  maybeAtom = withdraw(updateToken, store);
1814
1846
  }
1815
1847
  const atom = maybeAtom;
@@ -1818,6 +1850,7 @@ var addAtomToTimeline = (atomToken, tl, store) => {
1818
1850
  `Cannot subscribe to atom "${atomToken.key}" because it has not been initialized in store "${store.config.name}"`
1819
1851
  );
1820
1852
  }
1853
+ store.timelineAtoms.set({ atomKey: atom.key, timelineKey: tl.key });
1821
1854
  atom.subject.subscribe(`timeline`, (update) => {
1822
1855
  var _a, _b, _c, _d, _e, _f;
1823
1856
  const target = newest(store);
@@ -2002,14 +2035,6 @@ var addAtomToTimeline = (atomToken, tl, store) => {
2002
2035
  });
2003
2036
  };
2004
2037
 
2005
- // internal/src/mutable/is-mutable.ts
2006
- function isMutable(atomOrTokenOrFamily) {
2007
- if (`mutable` in atomOrTokenOrFamily) {
2008
- return atomOrTokenOrFamily.mutable;
2009
- }
2010
- return false;
2011
- }
2012
-
2013
2038
  // internal/src/timeline/create-timeline.ts
2014
2039
  function createTimeline(options, store, data) {
2015
2040
  var _a, _b;
@@ -2032,27 +2057,15 @@ function createTimeline(options, store, data) {
2032
2057
  const target = newest(store);
2033
2058
  for (const tokenOrFamily of options.atoms) {
2034
2059
  let atomKey = tokenOrFamily.key;
2035
- const existingTimelineKey = target.timelineAtoms.getRelatedKey(atomKey);
2036
- if (existingTimelineKey) {
2037
- store.logger.error(
2038
- `\u274C`,
2039
- `timeline`,
2040
- options.key,
2041
- `Failed to add atom "${atomKey}" because it already belongs to timeline "${existingTimelineKey}"`
2042
- );
2043
- continue;
2044
- }
2045
- if (tokenOrFamily.type === `atom_family`) {
2046
- let family = tokenOrFamily;
2047
- if (isMutable(family)) {
2048
- family = getUpdateFamily(family, store);
2049
- atomKey = family.key;
2050
- }
2060
+ if (tokenOrFamily.type === `atom_family` || tokenOrFamily.type === `mutable_atom_family`) {
2061
+ const family = tokenOrFamily;
2062
+ const familyKey = family.key;
2063
+ target.timelineAtoms.set({ atomKey: familyKey, timelineKey });
2051
2064
  family.subject.subscribe(`timeline:${options.key}`, (token2) => {
2052
2065
  addAtomToTimeline(token2, tl, store);
2053
2066
  });
2054
2067
  for (const atom of target.atoms.values()) {
2055
- if (((_b = atom.family) == null ? void 0 : _b.key) === family.key) {
2068
+ if (((_b = atom.family) == null ? void 0 : _b.key) === familyKey) {
2056
2069
  addAtomToTimeline(atom, tl, store);
2057
2070
  }
2058
2071
  }
@@ -2095,9 +2108,18 @@ function createTimeline(options, store, data) {
2095
2108
  continue;
2096
2109
  }
2097
2110
  }
2111
+ const existingTimelineKey = target.timelineAtoms.getRelatedKey(atomKey);
2112
+ if (existingTimelineKey) {
2113
+ store.logger.error(
2114
+ `\u274C`,
2115
+ `timeline`,
2116
+ options.key,
2117
+ `Failed to add atom "${atomKey}" because it already belongs to timeline "${existingTimelineKey}"`
2118
+ );
2119
+ continue;
2120
+ }
2098
2121
  addAtomToTimeline(atom, tl, store);
2099
2122
  }
2100
- target.timelineAtoms.set({ atomKey, timelineKey });
2101
2123
  }
2102
2124
  store.timelines.set(options.key, tl);
2103
2125
  const token = {
@@ -2357,27 +2379,27 @@ exports.buildTransaction = buildTransaction;
2357
2379
  exports.cacheValue = cacheValue;
2358
2380
  exports.clearStore = clearStore;
2359
2381
  exports.closeOperation = closeOperation;
2360
- exports.createAtom = createAtom;
2361
2382
  exports.createAtomFamily = createAtomFamily;
2362
2383
  exports.createMutableAtom = createMutableAtom;
2363
2384
  exports.createMutableAtomFamily = createMutableAtomFamily;
2385
+ exports.createReadonlySelector = createReadonlySelector;
2364
2386
  exports.createReadonlySelectorFamily = createReadonlySelectorFamily;
2365
2387
  exports.createRegularAtom = createRegularAtom;
2366
2388
  exports.createRegularAtomFamily = createRegularAtomFamily;
2367
- exports.createSelector = createSelector;
2368
2389
  exports.createSelectorFamily = createSelectorFamily;
2390
+ exports.createStandaloneAtom = createStandaloneAtom;
2391
+ exports.createStandaloneSelector = createStandaloneSelector;
2369
2392
  exports.createTimeline = createTimeline;
2370
2393
  exports.createTransaction = createTransaction;
2394
+ exports.createWritableSelector = createWritableSelector;
2371
2395
  exports.deleteAtom = deleteAtom;
2372
2396
  exports.deleteSelector = deleteSelector;
2373
2397
  exports.deposit = deposit;
2374
- exports.eldest = eldest;
2375
2398
  exports.evictCachedValue = evictCachedValue;
2376
2399
  exports.getEnvironmentData = getEnvironmentData;
2377
2400
  exports.getJsonFamily = getJsonFamily;
2378
2401
  exports.getJsonToken = getJsonToken;
2379
2402
  exports.getSelectorDependencyKeys = getSelectorDependencyKeys;
2380
- exports.getUpdateFamily = getUpdateFamily;
2381
2403
  exports.getUpdateToken = getUpdateToken;
2382
2404
  exports.ingestAtomUpdate = ingestAtomUpdate;
2383
2405
  exports.ingestSelectorUpdate = ingestSelectorUpdate;
@@ -2385,6 +2407,7 @@ exports.ingestTransactionUpdate = ingestTransactionUpdate;
2385
2407
  exports.isAtomDefault = isAtomDefault;
2386
2408
  exports.isAtomKey = isAtomKey;
2387
2409
  exports.isDone = isDone;
2410
+ exports.isMutable = isMutable;
2388
2411
  exports.isReadonlySelectorKey = isReadonlySelectorKey;
2389
2412
  exports.isSelectorKey = isSelectorKey;
2390
2413
  exports.isStateKey = isStateKey;