atom.io 0.15.5 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (134) hide show
  1. package/data/dist/index.cjs +20 -22
  2. package/data/dist/index.cjs.map +1 -1
  3. package/data/dist/index.d.ts +6 -6
  4. package/data/dist/index.js +21 -23
  5. package/data/dist/index.js.map +1 -1
  6. package/data/src/dict.ts +6 -7
  7. package/data/src/join.ts +23 -23
  8. package/data/src/struct-family.ts +2 -2
  9. package/data/src/struct.ts +4 -5
  10. package/dist/index.cjs +12 -5
  11. package/dist/index.cjs.map +1 -1
  12. package/dist/index.d.ts +67 -60
  13. package/dist/index.js +13 -6
  14. package/dist/index.js.map +1 -1
  15. package/internal/dist/index.cjs +912 -886
  16. package/internal/dist/index.cjs.map +1 -1
  17. package/internal/dist/index.d.ts +157 -162
  18. package/internal/dist/index.js +487 -460
  19. package/internal/dist/index.js.map +1 -1
  20. package/internal/src/atom/create-regular-atom.ts +9 -12
  21. package/internal/src/atom/create-standalone-atom.ts +33 -0
  22. package/internal/src/atom/delete-atom.ts +5 -2
  23. package/internal/src/atom/index.ts +1 -16
  24. package/internal/src/atom/is-default.ts +0 -1
  25. package/internal/src/caching.ts +6 -3
  26. package/internal/src/families/create-atom-family.ts +11 -7
  27. package/internal/src/families/create-readonly-selector-family.ts +4 -3
  28. package/internal/src/families/create-regular-atom-family.ts +12 -27
  29. package/internal/src/families/create-selector-family.ts +13 -49
  30. package/internal/src/families/create-writable-selector-family.ts +51 -0
  31. package/internal/src/index.ts +44 -3
  32. package/internal/src/lineage.ts +0 -7
  33. package/internal/src/mutable/create-mutable-atom-family.ts +61 -15
  34. package/internal/src/mutable/create-mutable-atom.ts +70 -25
  35. package/internal/src/mutable/get-json-family.ts +4 -5
  36. package/internal/src/mutable/get-json-token.ts +6 -3
  37. package/internal/src/mutable/get-update-token.ts +3 -3
  38. package/internal/src/mutable/index.ts +1 -7
  39. package/internal/src/mutable/is-mutable.ts +6 -7
  40. package/internal/src/mutable/tracker-family.ts +4 -4
  41. package/internal/src/mutable/tracker.ts +6 -6
  42. package/internal/src/read-or-compute-value.ts +6 -3
  43. package/internal/src/selector/create-readonly-selector.ts +2 -3
  44. package/internal/src/selector/create-standalone-selector.ts +32 -0
  45. package/internal/src/selector/{create-read-write-selector.ts → create-writable-selector.ts} +12 -9
  46. package/internal/src/selector/delete-selector.ts +2 -2
  47. package/internal/src/selector/index.ts +3 -1
  48. package/internal/src/selector/trace-selector-atoms.ts +3 -2
  49. package/internal/src/selector/update-selector-atoms.ts +1 -1
  50. package/internal/src/set-state/copy-mutable-if-needed.ts +5 -6
  51. package/internal/src/set-state/copy-mutable-in-transaction.ts +4 -36
  52. package/internal/src/set-state/emit-update.ts +2 -3
  53. package/internal/src/set-state/evict-downstream.ts +1 -1
  54. package/internal/src/set-state/set-atom-or-selector.ts +3 -3
  55. package/internal/src/set-state/set-atom.ts +8 -4
  56. package/internal/src/set-state/stow-update.ts +1 -1
  57. package/internal/src/store/deposit.ts +25 -13
  58. package/internal/src/store/store.ts +21 -21
  59. package/internal/src/store/withdraw-new-family-member.ts +16 -9
  60. package/internal/src/store/withdraw.ts +43 -19
  61. package/internal/src/subscribe/recall-state.ts +2 -6
  62. package/internal/src/subscribe/subscribe-to-root-atoms.ts +39 -41
  63. package/internal/src/subscribe/subscribe-to-state.ts +3 -1
  64. package/internal/src/timeline/add-atom-to-timeline.ts +5 -5
  65. package/internal/src/timeline/create-timeline.ts +19 -22
  66. package/introspection/dist/index.cjs +4 -8
  67. package/introspection/dist/index.cjs.map +1 -1
  68. package/introspection/dist/index.d.ts +5 -5
  69. package/introspection/dist/index.js +5 -9
  70. package/introspection/dist/index.js.map +1 -1
  71. package/introspection/src/attach-atom-index.ts +4 -5
  72. package/introspection/src/attach-selector-index.ts +4 -5
  73. package/introspection/src/attach-timeline-index.ts +6 -3
  74. package/introspection/src/attach-transaction-index.ts +6 -3
  75. package/introspection/src/index.ts +9 -5
  76. package/json/dist/index.cjs +3 -4
  77. package/json/dist/index.cjs.map +1 -1
  78. package/json/dist/index.d.ts +4 -3
  79. package/json/dist/index.js +4 -5
  80. package/json/dist/index.js.map +1 -1
  81. package/json/src/select-json-family.ts +24 -4
  82. package/json/src/select-json.ts +3 -4
  83. package/package.json +2 -2
  84. package/react-devtools/dist/index.cjs.map +1 -1
  85. package/react-devtools/dist/index.d.ts +9 -9
  86. package/react-devtools/dist/index.js.map +1 -1
  87. package/react-devtools/src/StateIndex.tsx +18 -10
  88. package/react-devtools/src/TimelineIndex.tsx +6 -2
  89. package/react-devtools/src/TransactionIndex.tsx +2 -2
  90. package/realtime-client/dist/index.cjs +27 -13
  91. package/realtime-client/dist/index.cjs.map +1 -1
  92. package/realtime-client/dist/index.d.ts +6 -4
  93. package/realtime-client/dist/index.js +20 -7
  94. package/realtime-client/dist/index.js.map +1 -1
  95. package/realtime-client/src/index.ts +4 -3
  96. package/realtime-client/src/server-action.ts +2 -55
  97. package/realtime-client/src/sync-server-action.ts +75 -0
  98. package/realtime-react/dist/index.cjs +22 -13
  99. package/realtime-react/dist/index.cjs.map +1 -1
  100. package/realtime-react/dist/index.d.ts +3 -1
  101. package/realtime-react/dist/index.js +20 -12
  102. package/realtime-react/dist/index.js.map +1 -1
  103. package/realtime-react/src/index.ts +1 -0
  104. package/realtime-react/src/use-server-action.ts +2 -4
  105. package/realtime-react/src/use-sync-server-action.ts +19 -0
  106. package/realtime-server/dist/index.cjs +83 -81
  107. package/realtime-server/dist/index.cjs.map +1 -1
  108. package/realtime-server/dist/index.d.ts +8 -8
  109. package/realtime-server/dist/index.js +58 -56
  110. package/realtime-server/dist/index.js.map +1 -1
  111. package/realtime-server/src/index.ts +15 -1
  112. package/realtime-server/src/{hook-composition/receive-transaction.ts → realtime-action-receiver.ts} +6 -2
  113. package/realtime-server/src/{hook-composition/sync-transaction.ts → realtime-action-synchronizer.ts} +10 -43
  114. package/realtime-server/src/{hook-composition/expose-family.ts → realtime-family-provider.ts} +9 -23
  115. package/realtime-server/src/{hook-composition/expose-mutable-family.ts → realtime-mutable-family-provider.ts} +4 -4
  116. package/realtime-server/src/{hook-composition/expose-mutable.ts → realtime-mutable-provider.ts} +4 -5
  117. package/realtime-server/src/realtime-server-store.ts +39 -0
  118. package/realtime-server/src/{hook-composition/expose-single.ts → realtime-state-provider.ts} +7 -8
  119. package/realtime-server/src/{hook-composition/receive-state.ts → realtime-state-receiver.ts} +7 -4
  120. package/src/atom.ts +39 -24
  121. package/src/find-state.ts +20 -19
  122. package/src/index.ts +41 -28
  123. package/src/logger.ts +1 -0
  124. package/src/selector.ts +31 -16
  125. package/src/silo.ts +45 -6
  126. package/src/subscribe.ts +1 -0
  127. package/src/validators.ts +35 -25
  128. package/internal/src/atom/create-atom.ts +0 -21
  129. package/internal/src/mutable/get-update-family.ts +0 -23
  130. package/internal/src/selector/create-selector.ts +0 -65
  131. package/realtime-server/src/hook-composition/index.ts +0 -15
  132. /package/realtime-client/src/{pull.ts → pull-state.ts} +0 -0
  133. /package/realtime-client/src/{push.ts → push-state.ts} +0 -0
  134. /package/realtime-client/src/{realtime-state.ts → realtime-client-store.ts} +0 -0
@@ -1,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,562 +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.transactionMeta.phase === `applying` && target.parent) {
376
- emitUpdate(atom, update, target.parent);
377
- } else {
378
- stowUpdate(atom, update, target);
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;
497
+ }
379
498
  }
380
- };
499
+ return void 0;
500
+ }
381
501
 
382
- // internal/src/set-state/set-atom-or-selector.ts
383
- var setAtomOrSelector = (state, value, store) => {
384
- switch (state.type) {
385
- case `atom`:
386
- setAtom(state, value, store);
387
- break;
388
- case `selector`:
389
- state.set(value);
390
- 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;
391
518
  }
392
519
  };
393
520
 
394
- // internal/src/store/deposit.ts
395
- function deposit(state) {
396
- const token = {
397
- key: state.key,
398
- type: state.type
399
- };
400
- if (`family` in state) {
401
- 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;
402
532
  }
403
- return token;
533
+ return targetValue;
404
534
  }
405
535
 
406
- // ../rel8/junction/src/junction.ts
407
- var Junction = class {
408
- constructor(data, config) {
409
- this.relations = /* @__PURE__ */ new Map();
410
- this.contents = /* @__PURE__ */ new Map();
411
- this.makeContentKey = (a, b) => `${a}:${b}`;
412
- var _a, _b, _c, _d;
413
- this.a = data.between[0];
414
- this.b = data.between[1];
415
- this.cardinality = data.cardinality;
416
- if (!(config == null ? void 0 : config.externalStore)) {
417
- this.relations = new Map((_a = data.relations) == null ? void 0 : _a.map(([a, b]) => [a, new Set(b)]));
418
- this.contents = new Map(data.contents);
419
- }
420
- this.isContent = (_b = config == null ? void 0 : config.isContent) != null ? _b : null;
421
- if (config == null ? void 0 : config.makeContentKey) {
422
- this.makeContentKey = config.makeContentKey;
423
- }
424
- if (config == null ? void 0 : config.externalStore) {
425
- const externalStore = config.externalStore;
426
- this.has = (a, b) => externalStore.has(a, b);
427
- this.addRelation = (a, b) => {
428
- externalStore.addRelation(a, b);
429
- };
430
- this.deleteRelation = (a, b) => {
431
- externalStore.deleteRelation(a, b);
432
- };
433
- this.replaceRelationsSafely = (a, bs) => {
434
- externalStore.replaceRelationsSafely(a, bs);
435
- };
436
- this.replaceRelationsUnsafely = (a, bs) => {
437
- externalStore.replaceRelationsUnsafely(a, bs);
438
- };
439
- this.getRelatedKeys = (key) => externalStore.getRelatedKeys(key);
440
- if (externalStore.getContent) {
441
- this.getContentInternal = (contentKey) => {
442
- return externalStore.getContent(contentKey);
443
- };
444
- this.setContent = (contentKey, content) => {
445
- externalStore.setContent(contentKey, content);
446
- };
447
- this.deleteContent = (contentKey) => {
448
- externalStore.deleteContent(contentKey);
449
- };
450
- }
451
- for (const [x, ys] of (_c = data.relations) != null ? _c : []) {
452
- for (const y of ys)
453
- this.addRelation(x, y);
454
- }
455
- for (const [contentKey, content] of (_d = data.contents) != null ? _d : []) {
456
- this.setContent(contentKey, content);
457
- }
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;
458
544
  }
459
545
  }
460
- getRelatedKeys(key) {
461
- return this.relations.get(key);
462
- }
463
- addRelation(a, b) {
464
- let aRelations = this.relations.get(a);
465
- let bRelations = this.relations.get(b);
466
- if (aRelations) {
467
- aRelations.add(b);
468
- } else {
469
- aRelations = /* @__PURE__ */ new Set([b]);
470
- this.relations.set(a, aRelations);
471
- }
472
- if (bRelations) {
473
- bRelations.add(a);
474
- } else {
475
- bRelations = /* @__PURE__ */ new Set([a]);
476
- this.relations.set(b, bRelations);
477
- }
478
- }
479
- deleteRelation(a, b) {
480
- const aRelations = this.relations.get(a);
481
- if (aRelations) {
482
- aRelations.delete(b);
483
- if (aRelations.size === 0) {
484
- this.relations.delete(a);
485
- }
486
- const bRelations = this.relations.get(b);
487
- if (bRelations) {
488
- bRelations.delete(a);
489
- if (bRelations.size === 0) {
490
- this.relations.delete(b);
491
- }
492
- }
493
- }
494
- }
495
- replaceRelationsUnsafely(a, bs) {
496
- this.relations.set(a, new Set(bs));
497
- for (const b of bs) {
498
- const bRelations = /* @__PURE__ */ new Set([a]);
499
- this.relations.set(b, bRelations);
500
- }
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();
501
554
  }
502
- replaceRelationsSafely(a, bs) {
503
- const aRelationsPrev = this.relations.get(a);
504
- if (aRelationsPrev) {
505
- for (const b of aRelationsPrev) {
506
- const bRelations = this.relations.get(b);
507
- if (bRelations) {
508
- if (bRelations.size === 1) {
509
- this.relations.delete(b);
510
- } else {
511
- bRelations.delete(a);
512
- }
513
- this.contents.delete(this.makeContentKey(a, b));
514
- }
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;
515
561
  }
516
- }
517
- this.relations.set(a, new Set(bs));
518
- for (const b of bs) {
519
- let bRelations = this.relations.get(b);
520
- if (bRelations) {
521
- bRelations.add(a);
522
- } else {
523
- bRelations = /* @__PURE__ */ new Set([a]);
524
- this.relations.set(b, bRelations);
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);
525
567
  }
526
- }
568
+ });
569
+ return future;
527
570
  }
528
- getContentInternal(contentKey) {
529
- return this.contents.get(contentKey);
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);
530
578
  }
531
- setContent(contentKey, content) {
532
- this.contents.set(contentKey, content);
579
+ return value;
580
+ };
581
+ var evictCachedValue = (key, target) => {
582
+ const currentValue = target.valueMap.get(key);
583
+ if (currentValue instanceof Future) {
584
+ currentValue.cancel();
533
585
  }
534
- deleteContent(contentKey) {
535
- this.contents.delete(contentKey);
586
+ if (target.operation.open) {
587
+ target.operation.prev.set(key, currentValue);
536
588
  }
537
- toJSON() {
538
- return {
539
- between: [this.a, this.b],
540
- cardinality: this.cardinality,
541
- relations: [...this.relations.entries()].map(([a, b]) => [a, [...b]]),
542
- contents: [...this.contents.entries()]
543
- };
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);
544
598
  }
545
- set(a, ...rest) {
546
- var _a;
547
- const b = typeof rest[0] === `string` ? rest[0] : a[this.b];
548
- const content = ((_a = rest[1]) != null ? _a : typeof rest[0] === `string`) ? void 0 : rest[0];
549
- a = typeof a === `string` ? a : a[this.a];
550
- switch (this.cardinality) {
551
- case `1:1`: {
552
- const bPrev = this.getRelatedKey(a);
553
- if (bPrev && bPrev !== b)
554
- this.delete(bPrev, a);
555
- }
556
- case `1:n`: {
557
- const aPrev = this.getRelatedKey(b);
558
- if (aPrev && aPrev !== a)
559
- this.delete(aPrev, b);
560
- }
561
- }
562
- if (content) {
563
- const contentKey = this.makeContentKey(a, b);
564
- this.setContent(contentKey, content);
565
- }
566
- this.addRelation(a, b);
567
- return this;
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();
568
602
  }
569
- delete(x, b) {
570
- b = typeof b === `string` ? b : x[this.b];
571
- const a = typeof x === `string` ? x : x[this.a];
572
- if (a === void 0 && typeof b === `string`) {
573
- const bRelations = this.getRelatedKeys(b);
574
- if (bRelations) {
575
- for (const a2 of bRelations) {
576
- this.delete(a2, b);
577
- }
578
- }
579
- }
580
- if (typeof a === `string` && b === void 0) {
581
- const aRelations = this.getRelatedKeys(a);
582
- if (aRelations) {
583
- for (const b2 of aRelations) {
584
- this.delete(a, b2);
585
- }
586
- }
587
- }
588
- if (typeof a === `string` && typeof b === `string`) {
589
- this.deleteRelation(a, b);
590
- const contentKey = this.makeContentKey(a, b);
591
- this.deleteContent(contentKey);
592
- }
593
- return this;
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`;
594
629
  }
595
- getRelatedKey(key) {
596
- const relations = this.getRelatedKeys(key);
597
- if (relations) {
598
- if (relations.size > 1) {
599
- console.warn(
600
- `${relations.size} related keys were found for key "${key}": (${[
601
- ...relations
602
- ].map((k) => `"${k}"`).join(`, `)}). Only one related key was expected.`
603
- );
604
- }
605
- for (const relation of relations) {
606
- return relation;
607
- }
608
- }
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
+ );
609
652
  }
610
- replaceRelations(a, relations, config) {
611
- const hasContent = !Array.isArray(relations);
612
- const bs = hasContent ? Object.keys(relations) : relations;
613
- if (config == null ? void 0 : config.reckless) {
614
- this.replaceRelationsUnsafely(a, bs);
615
- } else {
616
- this.replaceRelationsSafely(a, bs);
617
- }
618
- if (hasContent) {
619
- for (const b of bs) {
620
- const contentKey = this.makeContentKey(a, b);
621
- const content = relations[b];
622
- this.setContent(contentKey, content);
623
- }
624
- }
625
- 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;
626
665
  }
627
- getContent(a, b) {
628
- const contentKey = this.makeContentKey(a, b);
629
- return this.getContentInternal(contentKey);
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;
630
677
  }
631
- getRelationEntries(input) {
632
- const a = input[this.a];
633
- const b = input[this.b];
634
- if (a !== void 0 && b === void 0) {
635
- const aRelations = this.getRelatedKeys(a);
636
- if (aRelations) {
637
- return [...aRelations].map((b2) => {
638
- var _a;
639
- return [b2, (_a = this.getContent(a, b2)) != null ? _a : null];
640
- });
641
- }
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
+ );
642
715
  }
643
- if (a === void 0 && b !== void 0) {
644
- const bRelations = this.getRelatedKeys(b);
645
- if (bRelations) {
646
- return [...bRelations].map((a2) => {
647
- var _a;
648
- return [a2, (_a = this.getContent(a2, b)) != null ? _a : null];
649
- });
716
+ for (const key of downstreamKeys) {
717
+ if (isDone(key, store)) {
718
+ continue;
650
719
  }
720
+ evictCachedValue(key, store);
721
+ markDone(key, store);
651
722
  }
652
- return [];
653
- }
654
- has(a, b) {
655
- var _a;
656
- if (b) {
657
- const setA = this.getRelatedKeys(a);
658
- return (_a = setA == null ? void 0 : setA.has(b)) != null ? _a : false;
659
- }
660
- return this.relations.has(a);
661
723
  }
662
724
  };
663
725
 
664
- // internal/src/store/store.ts
665
- var Store = class {
666
- constructor(name, store = null) {
667
- this.parent = null;
668
- this.child = null;
669
- this.valueMap = /* @__PURE__ */ new Map();
670
- this.atoms = /* @__PURE__ */ new Map();
671
- this.selectors = /* @__PURE__ */ new Map();
672
- this.readonlySelectors = /* @__PURE__ */ new Map();
673
- this.trackers = /* @__PURE__ */ new Map();
674
- this.families = /* @__PURE__ */ new Map();
675
- this.timelines = /* @__PURE__ */ new Map();
676
- this.transactions = /* @__PURE__ */ new Map();
677
- this.atomsThatAreDefault = /* @__PURE__ */ new Set();
678
- this.timelineAtoms = new Junction({
679
- between: [`timelineKey`, `atomKey`],
680
- cardinality: `1:n`
681
- });
682
- this.selectorAtoms = new Junction({
683
- between: [`selectorKey`, `atomKey`],
684
- cardinality: `n:n`
685
- });
686
- this.selectorGraph = new Junction(
687
- {
688
- between: [`upstreamSelectorKey`, `downstreamSelectorKey`],
689
- cardinality: `n:n`
690
- },
691
- {
692
- makeContentKey: (...keys) => keys.sort().join(`:`)
693
- }
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.`
694
745
  );
695
- this.on = {
696
- atomCreation: new Subject(),
697
- selectorCreation: new Subject(),
698
- transactionCreation: new Subject(),
699
- timelineCreation: new Subject(),
700
- transactionApplying: new StatefulSubject(null),
701
- operationClose: new Subject()
702
- };
703
- this.operation = { open: false };
704
- this.transactionMeta = null;
705
- this.config = {
706
- name: `IMPLICIT_STORE`
707
- };
708
- this.loggers = [
709
- new atom_io.AtomIOLogger(`warn`, (_, __, key) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`))
710
- ];
711
- this.logger = {
712
- error: (...messages) => {
713
- for (const logger of this.loggers)
714
- logger.error(...messages);
715
- },
716
- info: (...messages) => {
717
- for (const logger of this.loggers)
718
- logger.info(...messages);
719
- },
720
- warn: (...messages) => {
721
- for (const logger of this.loggers)
722
- logger.warn(...messages);
723
- }
724
- };
725
- if (store !== null) {
726
- this.valueMap = new Map(store == null ? void 0 : store.valueMap);
727
- this.operation = __spreadValues({}, store == null ? void 0 : store.operation);
728
- this.transactionMeta = (store == null ? void 0 : store.transactionMeta) ? __spreadValues({}, store == null ? void 0 : store.transactionMeta) : null;
729
- this.config = __spreadProps(__spreadValues({}, store == null ? void 0 : store.config), {
730
- name
731
- });
732
- for (const [, family] of store.families) {
733
- family.install(this);
734
- }
735
- const mutableHelpers = /* @__PURE__ */ new Set();
736
- for (const [, atom] of store.atoms) {
737
- if (mutableHelpers.has(atom.key)) {
738
- continue;
739
- }
740
- atom.install(this);
741
- if (`mutable` in atom) {
742
- const originalJsonToken = getJsonToken(atom);
743
- const originalUpdateToken = getUpdateToken(atom);
744
- mutableHelpers.add(originalJsonToken.key);
745
- mutableHelpers.add(originalUpdateToken.key);
746
- }
747
- }
748
- for (const [, selector] of store.readonlySelectors) {
749
- selector.install(this);
750
- }
751
- for (const [, selector] of store.selectors) {
752
- if (mutableHelpers.has(selector.key)) {
753
- continue;
754
- }
755
- selector.install(this);
756
- }
757
- for (const [, tx] of store.transactions) {
758
- tx.install(this);
759
- }
760
- for (const [, timeline] of store.timelines) {
761
- timeline.install(this);
762
- }
763
- }
746
+ return;
764
747
  }
765
- };
766
- var IMPLICIT = {
767
- STORE_INTERNAL: void 0,
768
- get STORE() {
769
- var _a;
770
- 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;
771
751
  }
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
+ );
772
767
  };
773
- var clearStore = (store) => {
774
- const { config } = store;
775
- Object.assign(store, new Store(config.name));
776
- store.config = config;
777
- };
778
-
779
- // internal/src/store/withdraw.ts
780
- function withdraw(token, store) {
781
- let withdrawn;
782
- let target = store;
783
- while (target !== null) {
784
- switch (token.type) {
785
- case `atom`:
786
- withdrawn = target.atoms.get(token.key);
787
- break;
788
- case `selector`:
789
- withdrawn = target.selectors.get(token.key);
790
- break;
791
- case `readonly_selector`:
792
- withdrawn = target.readonlySelectors.get(token.key);
793
- break;
794
- case `timeline`:
795
- withdrawn = target.timelines.get(token.key);
796
- break;
797
- case `transaction`:
798
- withdrawn = target.transactions.get(token.key);
799
- break;
800
- }
801
- if (withdrawn) {
802
- return withdrawn;
768
+
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);
803
790
  }
804
- target = target.child;
805
791
  }
806
- }
792
+ };
807
793
 
808
- // internal/src/store/withdraw-new-family-member.ts
809
- function withdrawNewFamilyMember(token, store) {
810
- if (token.family) {
811
- store.logger.info(
812
- `\u{1F46A}`,
813
- token.type,
814
- token.key,
815
- `creating new family member in store "${store.config.name}"`
816
- );
817
- const target = newest(store);
818
- const family = target.families.get(token.family.key);
819
- if (family) {
820
- const jsonSubKey = JSON.parse(token.family.subKey);
821
- family(jsonSubKey);
822
- const state = withdraw(token, store);
823
- return state;
824
- }
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;
825
804
  }
826
- return void 0;
827
- }
805
+ };
828
806
 
829
807
  // internal/src/keys.ts
830
808
  var isAtomKey = (key, store) => newest(store).atoms.has(key);
@@ -864,7 +842,8 @@ var traceSelectorAtoms = (selectorKey, directDependencyKey, store) => {
864
842
  }
865
843
  return rootKeys;
866
844
  };
867
- var traceAllSelectorAtoms = (selectorKey, store) => {
845
+ var traceAllSelectorAtoms = (selector, store) => {
846
+ const selectorKey = selector.key;
868
847
  const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store);
869
848
  return directDependencyKeys.flatMap(
870
849
  (depKey) => isAtomKey(depKey, store) ? depKey : traceSelectorAtoms(selectorKey, depKey, store)
@@ -874,7 +853,7 @@ var traceAllSelectorAtoms = (selectorKey, store) => {
874
853
  // internal/src/selector/update-selector-atoms.ts
875
854
  var updateSelectorAtoms = (selectorKey, dependency, store) => {
876
855
  const target = newest(store);
877
- if (dependency.type === `atom`) {
856
+ if (dependency.type === `atom` || dependency.type === `mutable_atom`) {
878
857
  target.selectorAtoms.set({
879
858
  selectorKey,
880
859
  atomKey: dependency.key
@@ -945,8 +924,44 @@ var registerSelector = (selectorKey, store) => ({
945
924
  find: (token, key) => atom_io.findInStore(token, key, store)
946
925
  });
947
926
 
948
- // internal/src/selector/create-read-write-selector.ts
949
- 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) => {
950
965
  const target = newest(store);
951
966
  const subject = new Subject();
952
967
  const transactors = registerSelector(options.key, store);
@@ -979,7 +994,7 @@ var createReadWriteSelector = (options, family, store) => {
979
994
  };
980
995
  const mySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
981
996
  subject,
982
- install: (s) => createSelector(options, family, s),
997
+ install: (s) => createWritableSelector(options, family, s),
983
998
  get: getSelf,
984
999
  set: setSelf,
985
1000
  type: `selector`
@@ -998,59 +1013,13 @@ var createReadWriteSelector = (options, family, store) => {
998
1013
  return token;
999
1014
  };
1000
1015
 
1001
- // internal/src/selector/create-readonly-selector.ts
1002
- var createReadonlySelector = (options, family, store) => {
1003
- const target = newest(store);
1004
- const subject = new Subject();
1005
- const { get, find } = registerSelector(options.key, store);
1006
- const getSelf = () => {
1007
- const value = options.get({ get, find });
1008
- cacheValue(options.key, value, subject, store);
1009
- return value;
1010
- };
1011
- const readonlySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
1012
- subject,
1013
- install: (s) => createSelector(options, family, s),
1014
- get: getSelf,
1015
- type: `readonly_selector`
1016
- }), family && { family });
1017
- target.readonlySelectors.set(options.key, readonlySelector);
1018
- const initialValue = getSelf();
1019
- store.logger.info(
1020
- `\u2728`,
1021
- readonlySelector.type,
1022
- readonlySelector.key,
1023
- `=`,
1024
- initialValue
1025
- );
1026
- const token = {
1027
- key: options.key,
1028
- type: `readonly_selector`
1029
- };
1030
- if (family) {
1031
- token.family = family;
1032
- }
1033
- store.on.selectorCreation.next(token);
1034
- return token;
1035
- };
1036
-
1037
- // internal/src/selector/create-selector.ts
1038
- function createSelector(options, family, store) {
1039
- const target = newest(store);
1040
- const existingWritable = target.selectors.get(options.key);
1041
- const existingReadonly = target.readonlySelectors.get(options.key);
1042
- if (existingWritable || existingReadonly) {
1043
- store.logger.error(
1044
- `\u274C`,
1045
- existingReadonly ? `readonly_selector` : `selector`,
1046
- options.key,
1047
- `Tried to create selector, but it already exists in the store.`
1048
- );
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);
1049
1021
  }
1050
- if (`set` in options) {
1051
- return createReadWriteSelector(options, family, store);
1052
- }
1053
- return createReadonlySelector(options, family, store);
1022
+ return createReadonlySelector(options, void 0, store);
1054
1023
  }
1055
1024
 
1056
1025
  // internal/src/selector/delete-selector.ts
@@ -1092,44 +1061,46 @@ var recallState = (state, store) => {
1092
1061
  };
1093
1062
 
1094
1063
  // internal/src/subscribe/subscribe-to-root-atoms.ts
1095
- var subscribeToRootAtoms = (state, store) => {
1064
+ var subscribeToRootAtoms = (selector, store) => {
1096
1065
  const target = newest(store);
1097
- const dependencySubscriptions = `default` in state ? null : traceAllSelectorAtoms(state.key, store).map((atomKey) => {
1098
- const atom = target.atoms.get(atomKey);
1099
- if (atom === void 0) {
1100
- throw new Error(
1101
- `Atom "${atomKey}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`
1102
- );
1103
- }
1104
- return atom.subject.subscribe(
1105
- `${state.type}:${state.key}`,
1106
- (atomChange) => {
1107
- store.logger.info(
1108
- `\u{1F4E2}`,
1109
- state.type,
1110
- state.key,
1111
- `root`,
1112
- atomKey,
1113
- `went`,
1114
- atomChange.oldValue,
1115
- `->`,
1116
- atomChange.newValue
1117
- );
1118
- const oldValue = recallState(state, target);
1119
- const newValue = readOrComputeValue(state, target);
1120
- store.logger.info(
1121
- `\u2728`,
1122
- state.type,
1123
- state.key,
1124
- `went`,
1125
- oldValue,
1126
- `->`,
1127
- 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}".`
1128
1072
  );
1129
- state.subject.next({ newValue, oldValue });
1130
1073
  }
1131
- );
1132
- });
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
+ );
1133
1104
  return dependencySubscriptions;
1134
1105
  };
1135
1106
 
@@ -1144,7 +1115,7 @@ function subscribeToState(token, handleUpdate, key, store) {
1144
1115
  }
1145
1116
  const unsubFunction = state.subject.subscribe(key, handleUpdate);
1146
1117
  store.logger.info(`\u{1F440}`, state.type, state.key, `Adding subscription "${key}"`);
1147
- const dependencyUnsubFunctions = state.type !== `atom` ? subscribeToRootAtoms(state, store) : null;
1118
+ const dependencyUnsubFunctions = state.type !== `atom` && state.type !== `mutable_atom` ? subscribeToRootAtoms(state, store) : null;
1148
1119
  const unsubscribe = dependencyUnsubFunctions === null ? () => {
1149
1120
  store.logger.info(
1150
1121
  `\u{1F648}`,
@@ -1355,27 +1326,67 @@ var Tracker = class {
1355
1326
  // internal/src/mutable/create-mutable-atom.ts
1356
1327
  function createMutableAtom(options, family, store) {
1357
1328
  store.logger.info(
1358
- `\u{1F527}`,
1329
+ `\u{1F528}`,
1359
1330
  `atom`,
1360
1331
  options.key,
1361
1332
  `creating in store "${store.config.name}"`
1362
1333
  );
1363
- const coreState = createRegularAtom(options, family, store);
1364
- new Tracker(coreState, store);
1365
- const jsonState = json.selectJson(coreState, options, store);
1366
1334
  const target = newest(store);
1367
- subscribeToState(
1368
- jsonState,
1369
- () => {
1370
- const trackerHasBeenInitialized = newest(store).trackers.has(coreState.key);
1371
- if (!trackerHasBeenInitialized) {
1372
- new Tracker(coreState, store);
1373
- }
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);
1374
1356
  },
1375
- `tracker-initializer:${store == null ? void 0 : store.config.name}:${target.transactionMeta === null ? `main` : `${target.transactionMeta.update.key}`}`,
1376
- store
1377
- );
1378
- 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;
1379
1390
  }
1380
1391
  function createRegularAtomFamily(options, store) {
1381
1392
  const subject = new Subject();
@@ -1396,16 +1407,7 @@ function createRegularAtomFamily(options, store) {
1396
1407
  if (options.effects) {
1397
1408
  individualOptions.effects = options.effects(key);
1398
1409
  }
1399
- if (`mutable` in options) {
1400
- const mutableOptions = __spreadProps(__spreadValues({}, individualOptions), {
1401
- mutable: true,
1402
- toJson: options.toJson,
1403
- fromJson: options.fromJson
1404
- });
1405
- token = createMutableAtom(mutableOptions, family, store);
1406
- } else {
1407
- token = createRegularAtom(individualOptions, family, store);
1408
- }
1410
+ token = createRegularAtom(individualOptions, family, store);
1409
1411
  subject.next(token);
1410
1412
  }
1411
1413
  return token;
@@ -1417,9 +1419,6 @@ function createRegularAtomFamily(options, store) {
1417
1419
  install: (store2) => createRegularAtomFamily(options, store2)
1418
1420
  }
1419
1421
  );
1420
- if (`mutable` in options && typeof options.mutable === `boolean`) {
1421
- Object.assign(atomFamily, { mutable: options.mutable });
1422
- }
1423
1422
  const target = newest(store);
1424
1423
  target.families.set(options.key, atomFamily);
1425
1424
  return atomFamily;
@@ -1427,7 +1426,8 @@ function createRegularAtomFamily(options, store) {
1427
1426
 
1428
1427
  // internal/src/families/create-atom-family.ts
1429
1428
  function createAtomFamily(options, store) {
1430
- if (`mutable` in options) {
1429
+ const isMutable2 = `mutable` in options;
1430
+ if (isMutable2) {
1431
1431
  return createMutableAtomFamily(options, store);
1432
1432
  }
1433
1433
  return createRegularAtomFamily(options, store);
@@ -1444,7 +1444,7 @@ function createReadonlySelectorFamily(options, store) {
1444
1444
  if (existing) {
1445
1445
  return deposit(existing);
1446
1446
  }
1447
- return createSelector(
1447
+ return createReadonlySelector(
1448
1448
  {
1449
1449
  key: fullKey,
1450
1450
  get: options.get(key)
@@ -1463,23 +1463,18 @@ function createReadonlySelectorFamily(options, store) {
1463
1463
  store.families.set(options.key, readonlySelectorFamily);
1464
1464
  return readonlySelectorFamily;
1465
1465
  }
1466
- function createSelectorFamily(options, store) {
1467
- const isReadonly = !(`set` in options);
1468
- if (isReadonly) {
1469
- return createReadonlySelectorFamily(options, store);
1470
- }
1471
- const target = newest(store);
1466
+ function createWritableSelectorFamily(options, store) {
1472
1467
  const subject = new Subject();
1473
1468
  const selectorFamily = Object.assign(
1474
1469
  (key) => {
1475
1470
  const subKey = json.stringifyJson(key);
1476
1471
  const family = { key: options.key, subKey };
1477
1472
  const fullKey = `${options.key}(${subKey})`;
1478
- const existing = target.selectors.get(fullKey);
1473
+ const existing = store.selectors.get(fullKey);
1479
1474
  if (existing) {
1480
1475
  return deposit(existing);
1481
1476
  }
1482
- const token = createSelector(
1477
+ const token = createWritableSelector(
1483
1478
  {
1484
1479
  key: fullKey,
1485
1480
  get: options.get(key),
@@ -1495,13 +1490,22 @@ function createSelectorFamily(options, store) {
1495
1490
  key: options.key,
1496
1491
  type: `selector_family`,
1497
1492
  subject,
1498
- install: (store2) => createSelectorFamily(options, store2)
1493
+ install: (store2) => createWritableSelectorFamily(options, store2)
1499
1494
  }
1500
1495
  );
1501
- target.families.set(options.key, selectorFamily);
1496
+ store.families.set(options.key, selectorFamily);
1502
1497
  return selectorFamily;
1503
1498
  }
1504
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
+
1505
1509
  // internal/src/mutable/tracker-family.ts
1506
1510
  var FamilyTracker = class {
1507
1511
  constructor(findMutableState, store) {
@@ -1538,29 +1542,63 @@ var FamilyTracker = class {
1538
1542
 
1539
1543
  // internal/src/mutable/create-mutable-atom-family.ts
1540
1544
  function createMutableAtomFamily(options, store) {
1541
- const coreFamily = Object.assign(
1542
- createRegularAtomFamily(options, store),
1543
- 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
+ }
1544
1579
  );
1545
- json.selectJsonFamily(coreFamily, options);
1546
- new FamilyTracker(coreFamily, store);
1547
- 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;
1548
1585
  }
1549
1586
 
1550
1587
  // internal/src/mutable/get-json-family.ts
1551
1588
  var getJsonFamily = (mutableAtomFamily, store) => {
1552
1589
  const target = newest(store);
1553
1590
  const key = `${mutableAtomFamily.key}:JSON`;
1554
- const jsonFamily = target.families.get(
1555
- key
1556
- );
1591
+ const jsonFamily = target.families.get(key);
1557
1592
  return jsonFamily;
1558
1593
  };
1559
1594
 
1560
1595
  // internal/src/mutable/get-json-token.ts
1561
1596
  var getJsonToken = (mutableAtomToken) => {
1562
1597
  const key = mutableAtomToken.family ? `${mutableAtomToken.family.key}:JSON(${mutableAtomToken.family.subKey})` : `${mutableAtomToken.key}:JSON`;
1563
- const jsonToken = { type: `selector`, key };
1598
+ const jsonToken = {
1599
+ type: `selector`,
1600
+ key
1601
+ };
1564
1602
  if (mutableAtomToken.family) {
1565
1603
  jsonToken.family = {
1566
1604
  key: `${mutableAtomToken.family.key}:JSON`,
@@ -1583,13 +1621,10 @@ var getUpdateToken = (mutableAtomToken) => {
1583
1621
  return updateToken;
1584
1622
  };
1585
1623
 
1586
- // internal/src/mutable/get-update-family.ts
1587
- var getUpdateFamily = (mutableAtomFamily, store) => {
1588
- const target = newest(store);
1589
- const key = `*${mutableAtomFamily.key}`;
1590
- const updateFamily = target.families.get(key);
1591
- return updateFamily;
1592
- };
1624
+ // internal/src/mutable/is-mutable.ts
1625
+ function isMutable(atomOrTokenOrFamily) {
1626
+ return atomOrTokenOrFamily.type === `mutable_atom` || atomOrTokenOrFamily.type === `mutable_atom_family`;
1627
+ }
1593
1628
 
1594
1629
  // internal/src/mutable/transceiver.ts
1595
1630
  function isTransceiver(value) {
@@ -1621,7 +1656,7 @@ function createRegularAtom(options, family, store) {
1621
1656
  );
1622
1657
  const target = newest(store);
1623
1658
  const existing = target.atoms.get(options.key);
1624
- if (existing) {
1659
+ if (existing && existing.type === `atom`) {
1625
1660
  store.logger.error(
1626
1661
  `\u274C`,
1627
1662
  `atom`,
@@ -1640,7 +1675,7 @@ function createRegularAtom(options, family, store) {
1640
1675
  options.key,
1641
1676
  `installing in store "${store2.config.name}"`
1642
1677
  );
1643
- return `mutable` in options ? createMutableAtom(options, family, store2) : createRegularAtom(options, family, store2);
1678
+ return createRegularAtom(options, family, store2);
1644
1679
  },
1645
1680
  subject
1646
1681
  });
@@ -1678,12 +1713,13 @@ function createRegularAtom(options, family, store) {
1678
1713
  return token;
1679
1714
  }
1680
1715
 
1681
- // internal/src/atom/create-atom.ts
1682
- function createAtom(options, family, store) {
1683
- if (`mutable` in options) {
1684
- 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);
1685
1721
  }
1686
- return createRegularAtom(options, family, store);
1722
+ return createRegularAtom(options, void 0, store);
1687
1723
  }
1688
1724
 
1689
1725
  // internal/src/atom/delete-atom.ts
@@ -1804,9 +1840,8 @@ var NotFoundError = class extends Error {
1804
1840
  // internal/src/timeline/add-atom-to-timeline.ts
1805
1841
  var addAtomToTimeline = (atomToken, tl, store) => {
1806
1842
  let maybeAtom = withdraw(atomToken, store);
1807
- if (maybeAtom == null ? void 0 : maybeAtom.mutable) {
1808
- console.log(`adding transceiver to timeline`, atomToken.key);
1809
- const updateToken = getUpdateToken(atomToken);
1843
+ if ((maybeAtom == null ? void 0 : maybeAtom.type) === `mutable_atom`) {
1844
+ const updateToken = getUpdateToken(maybeAtom);
1810
1845
  maybeAtom = withdraw(updateToken, store);
1811
1846
  }
1812
1847
  const atom = maybeAtom;
@@ -1815,6 +1850,7 @@ var addAtomToTimeline = (atomToken, tl, store) => {
1815
1850
  `Cannot subscribe to atom "${atomToken.key}" because it has not been initialized in store "${store.config.name}"`
1816
1851
  );
1817
1852
  }
1853
+ store.timelineAtoms.set({ atomKey: atom.key, timelineKey: tl.key });
1818
1854
  atom.subject.subscribe(`timeline`, (update) => {
1819
1855
  var _a, _b, _c, _d, _e, _f;
1820
1856
  const target = newest(store);
@@ -1999,14 +2035,6 @@ var addAtomToTimeline = (atomToken, tl, store) => {
1999
2035
  });
2000
2036
  };
2001
2037
 
2002
- // internal/src/mutable/is-mutable.ts
2003
- function isMutable(atomOrTokenOrFamily) {
2004
- if (`mutable` in atomOrTokenOrFamily) {
2005
- return atomOrTokenOrFamily.mutable;
2006
- }
2007
- return false;
2008
- }
2009
-
2010
2038
  // internal/src/timeline/create-timeline.ts
2011
2039
  function createTimeline(options, store, data) {
2012
2040
  var _a, _b;
@@ -2029,27 +2057,15 @@ function createTimeline(options, store, data) {
2029
2057
  const target = newest(store);
2030
2058
  for (const tokenOrFamily of options.atoms) {
2031
2059
  let atomKey = tokenOrFamily.key;
2032
- const existingTimelineKey = target.timelineAtoms.getRelatedKey(atomKey);
2033
- if (existingTimelineKey) {
2034
- store.logger.error(
2035
- `\u274C`,
2036
- `timeline`,
2037
- options.key,
2038
- `Failed to add atom "${atomKey}" because it already belongs to timeline "${existingTimelineKey}"`
2039
- );
2040
- continue;
2041
- }
2042
- if (tokenOrFamily.type === `atom_family`) {
2043
- let family = tokenOrFamily;
2044
- if (isMutable(family)) {
2045
- family = getUpdateFamily(family, store);
2046
- atomKey = family.key;
2047
- }
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 });
2048
2064
  family.subject.subscribe(`timeline:${options.key}`, (token2) => {
2049
2065
  addAtomToTimeline(token2, tl, store);
2050
2066
  });
2051
2067
  for (const atom of target.atoms.values()) {
2052
- if (((_b = atom.family) == null ? void 0 : _b.key) === family.key) {
2068
+ if (((_b = atom.family) == null ? void 0 : _b.key) === familyKey) {
2053
2069
  addAtomToTimeline(atom, tl, store);
2054
2070
  }
2055
2071
  }
@@ -2092,9 +2108,18 @@ function createTimeline(options, store, data) {
2092
2108
  continue;
2093
2109
  }
2094
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
+ }
2095
2121
  addAtomToTimeline(atom, tl, store);
2096
2122
  }
2097
- target.timelineAtoms.set({ atomKey, timelineKey });
2098
2123
  }
2099
2124
  store.timelines.set(options.key, tl);
2100
2125
  const token = {
@@ -2354,27 +2379,27 @@ exports.buildTransaction = buildTransaction;
2354
2379
  exports.cacheValue = cacheValue;
2355
2380
  exports.clearStore = clearStore;
2356
2381
  exports.closeOperation = closeOperation;
2357
- exports.createAtom = createAtom;
2358
2382
  exports.createAtomFamily = createAtomFamily;
2359
2383
  exports.createMutableAtom = createMutableAtom;
2360
2384
  exports.createMutableAtomFamily = createMutableAtomFamily;
2385
+ exports.createReadonlySelector = createReadonlySelector;
2361
2386
  exports.createReadonlySelectorFamily = createReadonlySelectorFamily;
2362
2387
  exports.createRegularAtom = createRegularAtom;
2363
2388
  exports.createRegularAtomFamily = createRegularAtomFamily;
2364
- exports.createSelector = createSelector;
2365
2389
  exports.createSelectorFamily = createSelectorFamily;
2390
+ exports.createStandaloneAtom = createStandaloneAtom;
2391
+ exports.createStandaloneSelector = createStandaloneSelector;
2366
2392
  exports.createTimeline = createTimeline;
2367
2393
  exports.createTransaction = createTransaction;
2394
+ exports.createWritableSelector = createWritableSelector;
2368
2395
  exports.deleteAtom = deleteAtom;
2369
2396
  exports.deleteSelector = deleteSelector;
2370
2397
  exports.deposit = deposit;
2371
- exports.eldest = eldest;
2372
2398
  exports.evictCachedValue = evictCachedValue;
2373
2399
  exports.getEnvironmentData = getEnvironmentData;
2374
2400
  exports.getJsonFamily = getJsonFamily;
2375
2401
  exports.getJsonToken = getJsonToken;
2376
2402
  exports.getSelectorDependencyKeys = getSelectorDependencyKeys;
2377
- exports.getUpdateFamily = getUpdateFamily;
2378
2403
  exports.getUpdateToken = getUpdateToken;
2379
2404
  exports.ingestAtomUpdate = ingestAtomUpdate;
2380
2405
  exports.ingestSelectorUpdate = ingestSelectorUpdate;
@@ -2382,6 +2407,7 @@ exports.ingestTransactionUpdate = ingestTransactionUpdate;
2382
2407
  exports.isAtomDefault = isAtomDefault;
2383
2408
  exports.isAtomKey = isAtomKey;
2384
2409
  exports.isDone = isDone;
2410
+ exports.isMutable = isMutable;
2385
2411
  exports.isReadonlySelectorKey = isReadonlySelectorKey;
2386
2412
  exports.isSelectorKey = isSelectorKey;
2387
2413
  exports.isStateKey = isStateKey;