atom.io 0.13.0 → 0.14.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 (64) hide show
  1. package/dist/index.cjs +9 -74
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +4 -4
  4. package/dist/index.d.ts +4 -4
  5. package/dist/index.js +11 -74
  6. package/dist/index.js.map +1 -1
  7. package/dist/metafile-cjs.json +1 -1
  8. package/dist/metafile-esm.json +1 -1
  9. package/internal/dist/index.cjs +802 -730
  10. package/internal/dist/index.cjs.map +1 -1
  11. package/internal/dist/index.d.cts +9 -2
  12. package/internal/dist/index.d.ts +9 -2
  13. package/internal/dist/index.js +800 -731
  14. package/internal/dist/index.js.map +1 -1
  15. package/internal/dist/metafile-cjs.json +1 -1
  16. package/internal/dist/metafile-esm.json +1 -1
  17. package/internal/src/atom/create-atom.ts +3 -2
  18. package/internal/src/mutable/create-mutable-atom.ts +3 -2
  19. package/internal/src/mutable/tracker.ts +6 -4
  20. package/internal/src/selector/register-selector.ts +1 -1
  21. package/internal/src/selector/update-selector-atoms.ts +3 -3
  22. package/internal/src/subscribe/index.ts +3 -0
  23. package/internal/src/subscribe/recall-state.ts +0 -6
  24. package/internal/src/subscribe/subscribe-to-state.ts +47 -0
  25. package/internal/src/subscribe/subscribe-to-timeline.ts +28 -0
  26. package/internal/src/subscribe/subscribe-to-transaction.ts +33 -0
  27. package/package.json +8 -8
  28. package/react/dist/index.cjs +39 -1
  29. package/react/dist/index.cjs.map +1 -1
  30. package/react/dist/index.d.cts +9 -2
  31. package/react/dist/index.d.ts +9 -2
  32. package/react/dist/index.js +41 -4
  33. package/react/dist/index.js.map +1 -1
  34. package/react/dist/metafile-cjs.json +1 -1
  35. package/react/dist/metafile-esm.json +1 -1
  36. package/react/src/store-hooks.ts +52 -3
  37. package/react-devtools/dist/index.cjs.map +1 -1
  38. package/react-devtools/dist/index.js.map +1 -1
  39. package/react-devtools/dist/metafile-cjs.json +1 -1
  40. package/react-devtools/dist/metafile-esm.json +1 -1
  41. package/realtime-client/dist/index.cjs +8 -7
  42. package/realtime-client/dist/index.cjs.map +1 -1
  43. package/realtime-client/dist/index.d.cts +3 -2
  44. package/realtime-client/dist/index.d.ts +3 -2
  45. package/realtime-client/dist/index.js +3 -2
  46. package/realtime-client/dist/index.js.map +1 -1
  47. package/realtime-client/dist/metafile-cjs.json +1 -1
  48. package/realtime-client/dist/metafile-esm.json +1 -1
  49. package/realtime-client/src/use-push.ts +4 -4
  50. package/realtime-client/src/use-server-action.ts +4 -4
  51. package/realtime-server/dist/index.cjs +46 -25
  52. package/realtime-server/dist/index.cjs.map +1 -1
  53. package/realtime-server/dist/index.d.cts +5 -5
  54. package/realtime-server/dist/index.d.ts +5 -5
  55. package/realtime-server/dist/index.js +38 -17
  56. package/realtime-server/dist/index.js.map +1 -1
  57. package/realtime-server/dist/metafile-cjs.json +1 -1
  58. package/realtime-server/dist/metafile-esm.json +1 -1
  59. package/realtime-server/src/hook-composition/expose-family.ts +7 -3
  60. package/realtime-server/src/hook-composition/expose-mutable-family.ts +13 -5
  61. package/realtime-server/src/hook-composition/expose-mutable.ts +11 -3
  62. package/realtime-server/src/hook-composition/expose-single.ts +6 -2
  63. package/realtime-server/src/hook-composition/receive-transaction.ts +14 -5
  64. package/src/subscribe.ts +37 -91
@@ -1,5 +1,6 @@
1
- import { getState, setState, subscribe, subscribeToTimeline, AtomIOLogger, runTransaction } from 'atom.io';
1
+ import { AtomIOLogger, getState, setState, runTransaction } from 'atom.io';
2
2
  import { selectJson, stringifyJson, parseJson, selectJsonFamily } from 'atom.io/json';
3
+ import { withdraw as withdraw$1, subscribeToRootAtoms as subscribeToRootAtoms$1 } from 'atom.io/internal';
3
4
 
4
5
  var __defProp = Object.defineProperty;
5
6
  var __defProps = Object.defineProperties;
@@ -98,151 +99,296 @@ var evictCachedValue = (key, store) => {
98
99
  core.valueMap.delete(key);
99
100
  store.logger.info(`\u{1F5D1}`, `state`, key, `evicted`);
100
101
  };
101
- var Tracker = class {
102
- constructor(mutableState, store) {
103
- this.unsubscribeFromInnerValue = null;
104
- this.mutableState = mutableState;
105
- const target = newest(store);
106
- this.latestUpdateState = this.initializeState(mutableState, target);
107
- this.observeCore(mutableState, this.latestUpdateState, target);
108
- this.updateCore(mutableState, this.latestUpdateState, target);
109
- target.trackers.set(mutableState.key, this);
102
+
103
+ // src/read-or-compute-value.ts
104
+ var readOrComputeValue = (state, store) => {
105
+ if (isValueCached(state.key, store)) {
106
+ store.logger.info(`\u{1F4D6}`, state.type, state.key, `reading cached value`);
107
+ return readCachedValue(state.key, store);
110
108
  }
111
- initializeState(mutableState, store) {
112
- const latestUpdateStateKey = `*${mutableState.key}`;
113
- deleteAtom({ type: `atom`, key: latestUpdateStateKey }, store);
114
- const familyMetaData = mutableState.family ? {
115
- key: `*${mutableState.family.key}`,
116
- subKey: mutableState.family.subKey
117
- } : void 0;
118
- const latestUpdateState = createAtom(
119
- {
120
- key: latestUpdateStateKey,
121
- default: null
122
- },
123
- familyMetaData,
124
- store
109
+ if (state.type !== `atom`) {
110
+ store.logger.info(`\u{1F9EE}`, state.type, state.key, `computing value`);
111
+ return state.get();
112
+ }
113
+ const fallback = state.default instanceof Function ? state.default() : state.default;
114
+ store.logger.info(
115
+ `\u{1F481}`,
116
+ `atom`,
117
+ state.key,
118
+ `could not find cached value; using default`,
119
+ fallback
120
+ );
121
+ return state.default instanceof Function ? state.default() : state.default;
122
+ };
123
+
124
+ // src/operation.ts
125
+ var openOperation = (token, store) => {
126
+ const target = newest(store);
127
+ if (target.operation.open) {
128
+ store.logger.error(
129
+ `\u274C`,
130
+ token.type,
131
+ token.key,
132
+ `failed to setState during a setState for "${target.operation.token.key}"`
125
133
  );
126
- return latestUpdateState;
134
+ return `rejection`;
127
135
  }
128
- observeCore(mutableState, latestUpdateState, store) {
129
- const originalInnerValue = getState(mutableState, store);
130
- const target = newest(store);
131
- this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
132
- `tracker:${store.config.name}:${target.transactionMeta === null ? `main` : target.transactionMeta.update.key}`,
133
- (update) => {
134
- const unsubscribe = store.subject.operationStatus.subscribe(
135
- mutableState.key,
136
- () => {
137
- unsubscribe();
138
- setState(latestUpdateState, update, store);
139
- }
140
- );
141
- }
136
+ target.operation = {
137
+ open: true,
138
+ done: /* @__PURE__ */ new Set(),
139
+ prev: /* @__PURE__ */ new Map(),
140
+ time: Date.now(),
141
+ token
142
+ };
143
+ store.logger.info(
144
+ `\u2B55`,
145
+ token.type,
146
+ token.key,
147
+ `operation start in store "${store.config.name}"${target.transactionMeta === null ? `` : ` ${target.transactionMeta.phase} "${target.transactionMeta.update.key}"`}`
148
+ );
149
+ };
150
+ var closeOperation = (store) => {
151
+ const target = newest(store);
152
+ if (target.operation.open) {
153
+ store.logger.info(
154
+ `\u{1F534}`,
155
+ target.operation.token.type,
156
+ target.operation.token.key,
157
+ `operation done in store "${store.config.name}"`
142
158
  );
143
- subscribe(
144
- mutableState,
145
- (update) => {
146
- var _a;
147
- if (update.newValue !== update.oldValue) {
148
- (_a = this.unsubscribeFromInnerValue) == null ? void 0 : _a.call(this);
149
- const target2 = newest(store);
150
- this.unsubscribeFromInnerValue = update.newValue.subscribe(
151
- `tracker:${store.config.name}:${target2.transactionMeta === null ? `main` : target2.transactionMeta.update.key}`,
152
- (update2) => {
153
- const unsubscribe = store.subject.operationStatus.subscribe(
154
- mutableState.key,
155
- () => {
156
- unsubscribe();
157
- setState(latestUpdateState, update2, store);
158
- }
159
- );
160
- }
161
- );
162
- }
163
- },
164
- `${store.config.name}: tracker observing inner value`,
165
- store
159
+ }
160
+ target.operation = { open: false };
161
+ store.subject.operationStatus.next(target.operation);
162
+ };
163
+ var isDone = (key, store) => {
164
+ const target = newest(store);
165
+ if (!target.operation.open) {
166
+ store.logger.warn(
167
+ `\u{1F41E}`,
168
+ `unknown`,
169
+ key,
170
+ `isDone called outside of an operation. This is probably a bug.`
166
171
  );
172
+ return true;
167
173
  }
168
- updateCore(mutableState, latestUpdateState, store) {
169
- subscribe(
170
- latestUpdateState,
171
- ({ newValue, oldValue }) => {
172
- const timelineId = store.timelineAtoms.getRelatedKey(
173
- latestUpdateState.key
174
- );
175
- if (timelineId) {
176
- const timelineData = store.timelines.get(timelineId);
177
- if (timelineData == null ? void 0 : timelineData.timeTraveling) {
178
- const unsubscribe2 = subscribeToTimeline(
179
- { key: timelineId, type: `timeline` },
180
- (update) => {
181
- unsubscribe2();
182
- setState(
183
- mutableState,
184
- (transceiver) => {
185
- if (update === `redo` && newValue) {
186
- transceiver.do(newValue);
187
- } else if (update === `undo` && oldValue) {
188
- transceiver.undo(oldValue);
189
- }
190
- return transceiver;
191
- },
192
- store
193
- );
194
- }
195
- );
196
- return;
197
- }
198
- }
199
- const unsubscribe = store.subject.operationStatus.subscribe(
200
- latestUpdateState.key,
201
- () => {
202
- unsubscribe();
203
- const mutable = getState(mutableState, store);
204
- const updateNumber = mutable.getUpdateNumber(newValue);
205
- const eventOffset = updateNumber - mutable.cacheUpdateNumber;
206
- if (newValue && eventOffset === 1) {
207
- setState(
208
- mutableState,
209
- (transceiver) => (transceiver.do(newValue), transceiver),
210
- store
211
- );
212
- }
213
- }
214
- );
215
- },
216
- `${store.config.name}: tracker observing latest update`,
217
- store
174
+ return target.operation.done.has(key);
175
+ };
176
+ var markDone = (key, store) => {
177
+ const target = newest(store);
178
+ if (!target.operation.open) {
179
+ store.logger.warn(
180
+ `\u{1F41E}`,
181
+ `unknown`,
182
+ key,
183
+ `markDone called outside of an operation. This is probably a bug.`
218
184
  );
185
+ return;
219
186
  }
187
+ target.operation.done.add(key);
220
188
  };
221
189
 
222
- // src/mutable/create-mutable-atom.ts
223
- function createMutableAtom(options, store) {
190
+ // src/set-state/become.ts
191
+ var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
192
+ originalThing instanceof Function ? originalThing() : originalThing
193
+ ) : nextVersionOfThing;
194
+
195
+ // src/subject.ts
196
+ var Subject = class {
197
+ constructor() {
198
+ this.subscribers = /* @__PURE__ */ new Map();
199
+ }
200
+ subscribe(key, subscriber) {
201
+ this.subscribers.set(key, subscriber);
202
+ const unsubscribe = () => this.unsubscribe(key);
203
+ return unsubscribe;
204
+ }
205
+ unsubscribe(key) {
206
+ this.subscribers.delete(key);
207
+ }
208
+ next(value) {
209
+ for (const subscriber of this.subscribers.values()) {
210
+ subscriber(value);
211
+ }
212
+ }
213
+ };
214
+ var StatefulSubject = class extends Subject {
215
+ constructor(initialState) {
216
+ super();
217
+ this.state = initialState;
218
+ }
219
+ next(value) {
220
+ this.state = value;
221
+ super.next(value);
222
+ }
223
+ };
224
+
225
+ // src/set-state/copy-mutable-if-needed.ts
226
+ function copyMutableIfNeeded(atom, transform, origin, target) {
227
+ const originValue = origin.valueMap.get(atom.key);
228
+ const targetValue = target.valueMap.get(atom.key);
229
+ if (originValue === targetValue) {
230
+ origin.logger.info(`\u{1F4C3}`, `atom`, `${atom.key}`, `copying`);
231
+ const jsonValue = transform.toJson(originValue);
232
+ const copiedValue = transform.fromJson(jsonValue);
233
+ target.valueMap.set(atom.key, copiedValue);
234
+ new Tracker(atom, origin);
235
+ return copiedValue;
236
+ }
237
+ return targetValue;
238
+ }
239
+
240
+ // src/set-state/copy-mutable-in-transaction.ts
241
+ function copyMutableIfWithinTransaction(oldValue, atom, store) {
242
+ const target = newest(store);
243
+ const parent = target.parent;
244
+ if (parent !== null) {
245
+ if (`toJson` in atom && `fromJson` in atom) {
246
+ const copiedValue = copyMutableIfNeeded(atom, atom, parent, target);
247
+ return copiedValue;
248
+ }
249
+ if (`family` in atom) {
250
+ const family = parent.families.get(atom.family.key);
251
+ if (family && family.type === `atom_family`) {
252
+ const result = copyMutableFamilyMemberWithinTransaction(
253
+ atom,
254
+ family,
255
+ parent,
256
+ target
257
+ );
258
+ if (result) {
259
+ return result;
260
+ }
261
+ }
262
+ }
263
+ }
264
+ return oldValue;
265
+ }
266
+ function copyMutableFamilyMemberWithinTransaction(atom, family, origin, target) {
267
+ if (`toJson` in family && `fromJson` in family) {
268
+ const copyCreated = copyMutableIfNeeded(atom, family, origin, target);
269
+ return copyCreated;
270
+ }
271
+ return null;
272
+ }
273
+
274
+ // src/set-state/emit-update.ts
275
+ var emitUpdate = (state, update, store) => {
224
276
  store.logger.info(
225
- `\u{1F527}`,
226
- `atom`,
227
- options.key,
228
- `creating in store "${store.config.name}"`
277
+ `\u{1F4E2}`,
278
+ state.type,
279
+ state.key,
280
+ `went (`,
281
+ update.oldValue,
282
+ `->`,
283
+ update.newValue,
284
+ `) subscribers:`,
285
+ state.subject.subscribers
229
286
  );
230
- const coreState = createAtom(options, void 0, store);
231
- new Tracker(coreState, store);
232
- const jsonState = selectJson(coreState, options, store);
287
+ state.subject.next(update);
288
+ };
289
+
290
+ // src/set-state/evict-downstream.ts
291
+ var evictDownStream = (atom, store) => {
233
292
  const target = newest(store);
234
- subscribe(
235
- jsonState,
236
- () => {
237
- const trackerHasBeenInitialized = newest(store).trackers.has(coreState.key);
238
- if (!trackerHasBeenInitialized) {
239
- new Tracker(coreState, store);
240
- }
241
- },
242
- `tracker-initializer:${store == null ? void 0 : store.config.name}:${target.transactionMeta === null ? `main` : `${target.transactionMeta.update.key}`}`
293
+ const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key);
294
+ store.logger.info(
295
+ `\u{1F9F9}`,
296
+ atom.type,
297
+ atom.key,
298
+ downstreamKeys ? `evicting ${downstreamKeys.size} states downstream:` : `no downstream states`,
299
+ downstreamKeys != null ? downstreamKeys : `to evict`
243
300
  );
244
- return coreState;
301
+ if (downstreamKeys) {
302
+ if (target.operation.open) {
303
+ store.logger.info(
304
+ `\u{1F9F9}`,
305
+ atom.type,
306
+ atom.key,
307
+ `[ ${[...target.operation.done].join(`, `)} ] already done`
308
+ );
309
+ }
310
+ for (const key of downstreamKeys) {
311
+ if (isDone(key, store)) {
312
+ continue;
313
+ }
314
+ evictCachedValue(key, store);
315
+ markDone(key, store);
316
+ }
317
+ }
318
+ };
319
+
320
+ // src/set-state/stow-update.ts
321
+ function shouldUpdateBeStowed(key, update) {
322
+ if (isTransceiver(update.newValue)) {
323
+ return false;
324
+ }
325
+ if (key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
326
+ return false;
327
+ }
328
+ return true;
245
329
  }
330
+ var stowUpdate = (state, update, store) => {
331
+ const { key } = state;
332
+ const target = newest(store);
333
+ if (target.transactionMeta === null || target.transactionMeta.phase !== `building`) {
334
+ store.logger.error(
335
+ `\u{1F41E}`,
336
+ `atom`,
337
+ key,
338
+ `stowUpdate called outside of a transaction. This is probably a bug.`
339
+ );
340
+ return;
341
+ }
342
+ const shouldStow = shouldUpdateBeStowed(key, update);
343
+ if (!shouldStow) {
344
+ return;
345
+ }
346
+ const atomUpdate = __spreadValues({ key }, update);
347
+ if (state.family) {
348
+ atomUpdate.family = state.family;
349
+ }
350
+ target.transactionMeta.update.updates.push(atomUpdate);
351
+ store.logger.info(
352
+ `\u{1F4C1}`,
353
+ `atom`,
354
+ key,
355
+ `stowed (`,
356
+ update.oldValue,
357
+ `->`,
358
+ update.newValue,
359
+ `)`
360
+ );
361
+ };
362
+
363
+ // src/set-state/set-atom.ts
364
+ var setAtom = (atom, next, store) => {
365
+ const target = newest(store);
366
+ const oldValue = readOrComputeValue(atom, store);
367
+ let newValue = copyMutableIfWithinTransaction(oldValue, atom, store);
368
+ newValue = become(next)(newValue);
369
+ store.logger.info(`\u{1F4DD}`, `atom`, atom.key, `set to`, newValue);
370
+ newValue = cacheValue(atom.key, newValue, atom.subject, store);
371
+ if (isAtomDefault(atom.key, store)) {
372
+ markAtomAsNotDefault(atom.key, store);
373
+ }
374
+ markDone(atom.key, store);
375
+ evictDownStream(atom, store);
376
+ const update = { oldValue, newValue };
377
+ if (target.transactionMeta === null || target.transactionMeta.phase === `applying`) {
378
+ emitUpdate(atom, update, store);
379
+ } else {
380
+ stowUpdate(atom, update, store);
381
+ }
382
+ };
383
+
384
+ // src/set-state/set-atom-or-selector.ts
385
+ var setAtomOrSelector = (state, value, store) => {
386
+ if (state.type === `selector`) {
387
+ state.set(value);
388
+ } else {
389
+ setAtom(state, value, store);
390
+ }
391
+ };
246
392
 
247
393
  // src/store/deposit.ts
248
394
  function deposit(state) {
@@ -490,57 +636,27 @@ var Junction = class {
490
636
  return [...aRelations].map((b2) => {
491
637
  var _a;
492
638
  return [b2, (_a = this.getContent(a, b2)) != null ? _a : null];
493
- });
494
- }
495
- }
496
- if (a === void 0 && b !== void 0) {
497
- const bRelations = this.getRelatedKeys(b);
498
- if (bRelations) {
499
- return [...bRelations].map((a2) => {
500
- var _a;
501
- return [a2, (_a = this.getContent(a2, b)) != null ? _a : null];
502
- });
503
- }
504
- }
505
- return [];
506
- }
507
- has(a, b) {
508
- var _a;
509
- if (b) {
510
- const setA = this.getRelatedKeys(a);
511
- return (_a = setA == null ? void 0 : setA.has(b)) != null ? _a : false;
512
- }
513
- return this.relations.has(a);
514
- }
515
- };
516
-
517
- // src/subject.ts
518
- var Subject = class {
519
- constructor() {
520
- this.subscribers = /* @__PURE__ */ new Map();
521
- }
522
- subscribe(key, subscriber) {
523
- this.subscribers.set(key, subscriber);
524
- const unsubscribe = () => this.unsubscribe(key);
525
- return unsubscribe;
526
- }
527
- unsubscribe(key) {
528
- this.subscribers.delete(key);
529
- }
530
- next(value) {
531
- for (const subscriber of this.subscribers.values()) {
532
- subscriber(value);
639
+ });
640
+ }
533
641
  }
642
+ if (a === void 0 && b !== void 0) {
643
+ const bRelations = this.getRelatedKeys(b);
644
+ if (bRelations) {
645
+ return [...bRelations].map((a2) => {
646
+ var _a;
647
+ return [a2, (_a = this.getContent(a2, b)) != null ? _a : null];
648
+ });
649
+ }
650
+ }
651
+ return [];
534
652
  }
535
- };
536
- var StatefulSubject = class extends Subject {
537
- constructor(initialState) {
538
- super();
539
- this.state = initialState;
540
- }
541
- next(value) {
542
- this.state = value;
543
- super.next(value);
653
+ has(a, b) {
654
+ var _a;
655
+ if (b) {
656
+ const setA = this.getRelatedKeys(a);
657
+ return (_a = setA == null ? void 0 : setA.has(b)) != null ? _a : false;
658
+ }
659
+ return this.relations.has(a);
544
660
  }
545
661
  };
546
662
 
@@ -675,559 +791,568 @@ function withdrawNewFamilyMember(token, store) {
675
791
  return void 0;
676
792
  }
677
793
 
678
- // src/families/create-atom-family.ts
679
- function createAtomFamily(options, store) {
680
- const subject = new Subject();
681
- const atomFamily = Object.assign(
682
- (key) => {
683
- const subKey = stringifyJson(key);
684
- const family = { key: options.key, subKey };
685
- const fullKey = `${options.key}(${subKey})`;
686
- const existing = withdraw({ key: fullKey, type: `atom` }, store);
687
- let token;
688
- if (existing) {
689
- token = deposit(existing);
690
- } else {
691
- const individualOptions = {
692
- key: fullKey,
693
- default: options.default instanceof Function ? options.default(key) : options.default
694
- };
695
- if (options.effects) {
696
- individualOptions.effects = options.effects(key);
697
- }
698
- token = createAtom(individualOptions, family, store);
699
- subject.next(token);
700
- }
701
- return token;
702
- },
703
- {
704
- key: options.key,
705
- type: `atom_family`,
706
- subject
707
- }
708
- );
709
- const target = newest(store);
710
- target.families.set(options.key, atomFamily);
711
- return atomFamily;
712
- }
794
+ // src/keys.ts
795
+ var isAtomKey = (key, store) => newest(store).atoms.has(key);
796
+ var isSelectorKey = (key, store) => newest(store).selectors.has(key);
797
+ var isReadonlySelectorKey = (key, store) => newest(store).readonlySelectors.has(key);
798
+ var isStateKey = (key, store) => isAtomKey(key, store) || isSelectorKey(key, store) || isReadonlySelectorKey(key, store);
713
799
 
714
- // src/operation.ts
715
- var openOperation = (token, store) => {
716
- const target = newest(store);
717
- if (target.operation.open) {
718
- store.logger.error(
719
- `\u274C`,
720
- token.type,
721
- token.key,
722
- `failed to setState during a setState for "${target.operation.token.key}"`
723
- );
724
- return `rejection`;
800
+ // src/selector/get-selector-dependency-keys.ts
801
+ var getSelectorDependencyKeys = (key, store) => {
802
+ const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(source, store));
803
+ return sources;
804
+ };
805
+
806
+ // src/selector/trace-selector-atoms.ts
807
+ var traceSelectorAtoms = (selectorKey, directDependencyKey, store) => {
808
+ const rootKeys = [];
809
+ const indirectDependencyKeys = getSelectorDependencyKeys(
810
+ directDependencyKey,
811
+ store
812
+ );
813
+ let depth = 0;
814
+ while (indirectDependencyKeys.length > 0) {
815
+ const indirectDependencyKey = indirectDependencyKeys.shift();
816
+ ++depth;
817
+ if (depth > 99999) {
818
+ throw new Error(
819
+ `Maximum selector dependency depth exceeded (> 99999) in selector "${selectorKey}". This is likely due to a circular dependency.`
820
+ );
821
+ }
822
+ if (!isAtomKey(indirectDependencyKey, store)) {
823
+ indirectDependencyKeys.push(
824
+ ...getSelectorDependencyKeys(indirectDependencyKey, store)
825
+ );
826
+ } else if (!rootKeys.includes(indirectDependencyKey)) {
827
+ rootKeys.push(indirectDependencyKey);
828
+ }
725
829
  }
726
- target.operation = {
727
- open: true,
728
- done: /* @__PURE__ */ new Set(),
729
- prev: /* @__PURE__ */ new Map(),
730
- time: Date.now(),
731
- token
732
- };
733
- store.logger.info(
734
- `\u2B55`,
735
- token.type,
736
- token.key,
737
- `operation start in store "${store.config.name}"${target.transactionMeta === null ? `` : ` ${target.transactionMeta.phase} "${target.transactionMeta.update.key}"`}`
830
+ return rootKeys;
831
+ };
832
+ var traceAllSelectorAtoms = (selectorKey, store) => {
833
+ const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store);
834
+ return directDependencyKeys.flatMap(
835
+ (depKey) => isAtomKey(depKey, store) ? depKey : traceSelectorAtoms(selectorKey, depKey, store)
738
836
  );
739
837
  };
740
- var closeOperation = (store) => {
838
+
839
+ // src/selector/update-selector-atoms.ts
840
+ var updateSelectorAtoms = (selectorKey, dependency, store) => {
741
841
  const target = newest(store);
742
- if (target.operation.open) {
842
+ if (dependency.type === `atom`) {
843
+ target.selectorAtoms.set({
844
+ selectorKey,
845
+ atomKey: dependency.key
846
+ });
743
847
  store.logger.info(
744
- `\u{1F534}`,
745
- target.operation.token.type,
746
- target.operation.token.key,
747
- `operation done in store "${store.config.name}"`
748
- );
749
- }
750
- target.operation = { open: false };
751
- store.subject.operationStatus.next(target.operation);
752
- };
753
- var isDone = (key, store) => {
754
- const target = newest(store);
755
- if (!target.operation.open) {
756
- store.logger.warn(
757
- `\u{1F41E}`,
758
- `unknown`,
759
- key,
760
- `isDone called outside of an operation. This is probably a bug.`
848
+ `\u{1F50D}`,
849
+ `selector`,
850
+ selectorKey,
851
+ `discovers root atom "${dependency.key}"`
761
852
  );
762
- return true;
763
- }
764
- return target.operation.done.has(key);
765
- };
766
- var markDone = (key, store) => {
767
- const target = newest(store);
768
- if (!target.operation.open) {
769
- store.logger.warn(
770
- `\u{1F41E}`,
771
- `unknown`,
772
- key,
773
- `markDone called outside of an operation. This is probably a bug.`
853
+ } else {
854
+ const rootKeys = traceSelectorAtoms(selectorKey, dependency.key, store);
855
+ store.logger.info(
856
+ `\u{1F50D}`,
857
+ `selector`,
858
+ selectorKey,
859
+ `discovers root atoms: [ ${rootKeys.map((key) => `"${key}"`).join(`, `)} ]`
774
860
  );
775
- return;
776
- }
777
- target.operation.done.add(key);
778
- };
779
-
780
- // src/set-state/become.ts
781
- var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
782
- originalThing instanceof Function ? originalThing() : originalThing
783
- ) : nextVersionOfThing;
784
-
785
- // src/read-or-compute-value.ts
786
- var readOrComputeValue = (state, store) => {
787
- if (isValueCached(state.key, store)) {
788
- store.logger.info(`\u{1F4D6}`, state.type, state.key, `reading cached value`);
789
- return readCachedValue(state.key, store);
790
- }
791
- if (state.type !== `atom`) {
792
- store.logger.info(`\u{1F9EE}`, state.type, state.key, `computing value`);
793
- return state.get();
861
+ for (const atomKey of rootKeys) {
862
+ target.selectorAtoms = target.selectorAtoms.set({
863
+ selectorKey,
864
+ atomKey
865
+ });
866
+ }
794
867
  }
795
- const fallback = state.default instanceof Function ? state.default() : state.default;
796
- store.logger.info(
797
- `\u{1F481}`,
798
- `atom`,
799
- state.key,
800
- `could not find cached value; using default`,
801
- fallback
802
- );
803
- return state.default instanceof Function ? state.default() : state.default;
804
868
  };
805
869
 
806
- // src/set-state/copy-mutable-if-needed.ts
807
- function copyMutableIfNeeded(atom, transform, origin, target) {
808
- const originValue = origin.valueMap.get(atom.key);
809
- const targetValue = target.valueMap.get(atom.key);
810
- if (originValue === targetValue) {
811
- origin.logger.info(`\u{1F4C3}`, `atom`, `${atom.key}`, `copying`);
812
- const jsonValue = transform.toJson(originValue);
813
- const copiedValue = transform.fromJson(jsonValue);
814
- target.valueMap.set(atom.key, copiedValue);
815
- new Tracker(atom, origin);
816
- return copiedValue;
870
+ // src/selector/register-selector.ts
871
+ var registerSelector = (selectorKey, store) => ({
872
+ get: (dependency) => {
873
+ const target = newest(store);
874
+ const alreadyRegistered = target.selectorGraph.getRelationEntries({ downstreamSelectorKey: selectorKey }).some(([_, { source }]) => source === dependency.key);
875
+ const dependencyState = withdraw(dependency, store);
876
+ if (dependencyState === void 0) {
877
+ throw new Error(
878
+ `State "${dependency.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
879
+ );
880
+ }
881
+ const dependencyValue = readOrComputeValue(dependencyState, store);
882
+ store.logger.info(
883
+ `\u{1F50C}`,
884
+ `selector`,
885
+ selectorKey,
886
+ `registers dependency ( "${dependency.key}" =`,
887
+ dependencyValue,
888
+ `)`
889
+ );
890
+ if (!alreadyRegistered) {
891
+ target.selectorGraph.set(
892
+ {
893
+ upstreamSelectorKey: dependency.key,
894
+ downstreamSelectorKey: selectorKey
895
+ },
896
+ {
897
+ source: dependency.key
898
+ }
899
+ );
900
+ }
901
+ updateSelectorAtoms(selectorKey, dependency, store);
902
+ return dependencyValue;
903
+ },
904
+ set: (stateToken, newValue) => {
905
+ const state = withdraw(stateToken, store);
906
+ if (state === void 0) {
907
+ throw new Error(
908
+ `State "${stateToken.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
909
+ );
910
+ }
911
+ setAtomOrSelector(state, newValue, store);
817
912
  }
818
- return targetValue;
819
- }
913
+ });
820
914
 
821
- // src/set-state/copy-mutable-in-transaction.ts
822
- function copyMutableIfWithinTransaction(oldValue, atom, store) {
915
+ // src/selector/create-read-write-selector.ts
916
+ var createReadWriteSelector = (options, family, store) => {
823
917
  const target = newest(store);
824
- const parent = target.parent;
825
- if (parent !== null) {
826
- if (`toJson` in atom && `fromJson` in atom) {
827
- const copiedValue = copyMutableIfNeeded(atom, atom, parent, target);
828
- return copiedValue;
829
- }
830
- if (`family` in atom) {
831
- const family = parent.families.get(atom.family.key);
832
- if (family && family.type === `atom_family`) {
833
- const result = copyMutableFamilyMemberWithinTransaction(
834
- atom,
835
- family,
836
- parent,
837
- target
838
- );
839
- if (result) {
840
- return result;
841
- }
842
- }
918
+ const subject = new Subject();
919
+ const { get, set } = registerSelector(options.key, store);
920
+ const getSelf = () => {
921
+ const value = options.get({ get });
922
+ cacheValue(options.key, value, subject, store);
923
+ return value;
924
+ };
925
+ const setSelf = (next) => {
926
+ const oldValue = getSelf();
927
+ const newValue = become(next)(oldValue);
928
+ store.logger.info(
929
+ `\u{1F4DD}`,
930
+ `selector`,
931
+ options.key,
932
+ `set (`,
933
+ oldValue,
934
+ `->`,
935
+ newValue,
936
+ `)`
937
+ );
938
+ cacheValue(options.key, newValue, subject, store);
939
+ markDone(options.key, store);
940
+ if (target.transactionMeta === null) {
941
+ subject.next({ newValue, oldValue });
843
942
  }
943
+ options.set({ get, set }, newValue);
944
+ };
945
+ const mySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
946
+ subject,
947
+ install: (s) => createSelector(options, family, s),
948
+ get: getSelf,
949
+ set: setSelf,
950
+ type: `selector`
951
+ }), family && { family });
952
+ target.selectors.set(options.key, mySelector);
953
+ const initialValue = getSelf();
954
+ store.logger.info(`\u2728`, mySelector.type, mySelector.key, `=`, initialValue);
955
+ const token = {
956
+ key: options.key,
957
+ type: `selector`
958
+ };
959
+ if (family) {
960
+ token.family = family;
844
961
  }
845
- return oldValue;
846
- }
847
- function copyMutableFamilyMemberWithinTransaction(atom, family, origin, target) {
848
- if (`toJson` in family && `fromJson` in family) {
849
- const copyCreated = copyMutableIfNeeded(atom, family, origin, target);
850
- return copyCreated;
851
- }
852
- return null;
853
- }
854
-
855
- // src/set-state/emit-update.ts
856
- var emitUpdate = (state, update, store) => {
857
- store.logger.info(
858
- `\u{1F4E2}`,
859
- state.type,
860
- state.key,
861
- `went (`,
862
- update.oldValue,
863
- `->`,
864
- update.newValue,
865
- `) subscribers:`,
866
- state.subject.subscribers
867
- );
868
- state.subject.next(update);
962
+ store.subject.selectorCreation.next(token);
963
+ return token;
869
964
  };
870
965
 
871
- // src/set-state/evict-downstream.ts
872
- var evictDownStream = (atom, store) => {
966
+ // src/selector/create-readonly-selector.ts
967
+ var createReadonlySelector = (options, family, store) => {
873
968
  const target = newest(store);
874
- const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key);
969
+ const subject = new Subject();
970
+ const { get } = registerSelector(options.key, store);
971
+ const getSelf = () => {
972
+ const value = options.get({ get });
973
+ cacheValue(options.key, value, subject, store);
974
+ return value;
975
+ };
976
+ const readonlySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
977
+ subject,
978
+ install: (s) => createSelector(options, family, s),
979
+ get: getSelf,
980
+ type: `readonly_selector`
981
+ }), family && { family });
982
+ target.readonlySelectors.set(options.key, readonlySelector);
983
+ const initialValue = getSelf();
875
984
  store.logger.info(
876
- `\u{1F9F9}`,
877
- atom.type,
878
- atom.key,
879
- downstreamKeys ? `evicting ${downstreamKeys.size} states downstream:` : `no downstream states`,
880
- downstreamKeys != null ? downstreamKeys : `to evict`
985
+ `\u2728`,
986
+ readonlySelector.type,
987
+ readonlySelector.key,
988
+ `=`,
989
+ initialValue
881
990
  );
882
- if (downstreamKeys) {
883
- if (target.operation.open) {
884
- store.logger.info(
885
- `\u{1F9F9}`,
886
- atom.type,
887
- atom.key,
888
- `[ ${[...target.operation.done].join(`, `)} ] already done`
889
- );
890
- }
891
- for (const key of downstreamKeys) {
892
- if (isDone(key, store)) {
893
- continue;
894
- }
895
- evictCachedValue(key, store);
896
- markDone(key, store);
897
- }
991
+ const token = {
992
+ key: options.key,
993
+ type: `readonly_selector`
994
+ };
995
+ if (family) {
996
+ token.family = family;
898
997
  }
998
+ store.subject.selectorCreation.next(token);
999
+ return token;
899
1000
  };
900
1001
 
901
- // src/set-state/stow-update.ts
902
- function shouldUpdateBeStowed(key, update) {
903
- if (isTransceiver(update.newValue)) {
904
- return false;
905
- }
906
- if (key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
907
- return false;
908
- }
909
- return true;
910
- }
911
- var stowUpdate = (state, update, store) => {
912
- const { key } = state;
1002
+ // src/selector/create-selector.ts
1003
+ function createSelector(options, family, store) {
913
1004
  const target = newest(store);
914
- if (target.transactionMeta === null || target.transactionMeta.phase !== `building`) {
1005
+ const existingWritable = target.selectors.get(options.key);
1006
+ const existingReadonly = target.readonlySelectors.get(options.key);
1007
+ if (existingWritable || existingReadonly) {
915
1008
  store.logger.error(
916
- `\u{1F41E}`,
917
- `atom`,
918
- key,
919
- `stowUpdate called outside of a transaction. This is probably a bug.`
1009
+ `\u274C`,
1010
+ existingReadonly ? `readonly_selector` : `selector`,
1011
+ options.key,
1012
+ `Tried to create selector, but it already exists in the store. (Ignore if you are in development using hot module replacement.)`
920
1013
  );
921
- return;
922
- }
923
- const shouldStow = shouldUpdateBeStowed(key, update);
924
- if (!shouldStow) {
925
- return;
926
1014
  }
927
- const atomUpdate = __spreadValues({ key }, update);
928
- if (state.family) {
929
- atomUpdate.family = state.family;
1015
+ if (`set` in options) {
1016
+ return createReadWriteSelector(options, family, store);
930
1017
  }
931
- target.transactionMeta.update.updates.push(atomUpdate);
932
- store.logger.info(
933
- `\u{1F4C1}`,
934
- `atom`,
935
- key,
936
- `stowed (`,
937
- update.oldValue,
938
- `->`,
939
- update.newValue,
940
- `)`
941
- );
942
- };
1018
+ return createReadonlySelector(options, family, store);
1019
+ }
943
1020
 
944
- // src/set-state/set-atom.ts
945
- var setAtom = (atom, next, store) => {
1021
+ // src/selector/delete-selector.ts
1022
+ function deleteSelector(selectorToken, store) {
946
1023
  const target = newest(store);
947
- const oldValue = readOrComputeValue(atom, store);
948
- let newValue = copyMutableIfWithinTransaction(oldValue, atom, store);
949
- newValue = become(next)(newValue);
950
- store.logger.info(`\u{1F4DD}`, `atom`, atom.key, `set to`, newValue);
951
- newValue = cacheValue(atom.key, newValue, atom.subject, store);
952
- if (isAtomDefault(atom.key, store)) {
953
- markAtomAsNotDefault(atom.key, store);
954
- }
955
- markDone(atom.key, store);
956
- evictDownStream(atom, store);
957
- const update = { oldValue, newValue };
958
- if (target.transactionMeta === null || target.transactionMeta.phase === `applying`) {
959
- emitUpdate(atom, update, store);
960
- } else {
961
- stowUpdate(atom, update, store);
962
- }
963
- };
964
-
965
- // src/set-state/set-atom-or-selector.ts
966
- var setAtomOrSelector = (state, value, store) => {
967
- if (state.type === `selector`) {
968
- state.set(value);
969
- } else {
970
- setAtom(state, value, store);
1024
+ const { key } = selectorToken;
1025
+ switch (selectorToken.type) {
1026
+ case `selector`:
1027
+ target.selectors.delete(key);
1028
+ break;
1029
+ case `readonly_selector`:
1030
+ target.readonlySelectors.delete(key);
1031
+ break;
971
1032
  }
972
- };
973
-
974
- // src/keys.ts
975
- var isAtomKey = (key, store) => newest(store).atoms.has(key);
976
- var isSelectorKey = (key, store) => newest(store).selectors.has(key);
977
- var isReadonlySelectorKey = (key, store) => newest(store).readonlySelectors.has(key);
978
- var isStateKey = (key, store) => isAtomKey(key, store) || isSelectorKey(key, store) || isReadonlySelectorKey(key, store);
1033
+ target.valueMap.delete(key);
1034
+ target.selectorAtoms.delete(key);
1035
+ const downstreamTokens = target.selectorGraph.getRelationEntries({ upstreamSelectorKey: key }).filter(([_, { source }]) => source === key).map(
1036
+ ([downstreamSelectorKey]) => {
1037
+ var _a;
1038
+ return (_a = target.selectors.get(downstreamSelectorKey)) != null ? _a : target.readonlySelectors.get(downstreamSelectorKey);
1039
+ }
1040
+ );
1041
+ for (const downstreamToken of downstreamTokens) {
1042
+ if (downstreamToken) {
1043
+ deleteSelector(downstreamToken, store);
1044
+ }
1045
+ }
1046
+ target.selectorGraph.delete(key);
1047
+ store.logger.info(`\u{1F525}`, selectorToken.type, `${key}`, `deleted`);
1048
+ }
979
1049
 
980
- // src/selector/get-selector-dependency-keys.ts
981
- var getSelectorDependencyKeys = (key, store) => {
982
- const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(source, store));
983
- return sources;
1050
+ // src/subscribe/recall-state.ts
1051
+ var recallState = (state, store) => {
1052
+ const target = newest(store);
1053
+ if (!target.operation.open) {
1054
+ return target.valueMap.get(state.key);
1055
+ }
1056
+ return target.operation.prev.get(state.key);
984
1057
  };
985
1058
 
986
- // src/selector/trace-selector-atoms.ts
987
- var traceSelectorAtoms = (selectorKey, directDependencyKey, store) => {
988
- const rootKeys = [];
989
- const indirectDependencyKeys = getSelectorDependencyKeys(
990
- directDependencyKey,
991
- store
992
- );
993
- let depth = 0;
994
- while (indirectDependencyKeys.length > 0) {
995
- const indirectDependencyKey = indirectDependencyKeys.shift();
996
- ++depth;
997
- if (depth > 99999) {
1059
+ // src/subscribe/subscribe-to-root-atoms.ts
1060
+ var subscribeToRootAtoms = (state, store) => {
1061
+ const dependencySubscriptions = `default` in state ? null : traceAllSelectorAtoms(state.key, store).map((atomKey) => {
1062
+ const atom = store.atoms.get(atomKey);
1063
+ if (atom === void 0) {
998
1064
  throw new Error(
999
- `Maximum selector dependency depth exceeded (> 99999) in selector "${selectorKey}". This is likely due to a circular dependency.`
1000
- );
1001
- }
1002
- if (!isAtomKey(indirectDependencyKey, store)) {
1003
- indirectDependencyKeys.push(
1004
- ...getSelectorDependencyKeys(indirectDependencyKey, store)
1065
+ `Atom "${atomKey}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`
1005
1066
  );
1006
- } else if (!rootKeys.includes(indirectDependencyKey)) {
1007
- rootKeys.push(indirectDependencyKey);
1008
1067
  }
1009
- }
1010
- return rootKeys;
1011
- };
1012
- var traceAllSelectorAtoms = (selectorKey, store) => {
1013
- const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store);
1014
- return directDependencyKeys.flatMap(
1015
- (depKey) => isAtomKey(depKey, store) ? depKey : traceSelectorAtoms(selectorKey, depKey, store)
1016
- );
1068
+ return atom.subject.subscribe(
1069
+ `${state.type}:${state.key}`,
1070
+ (atomChange) => {
1071
+ store.logger.info(
1072
+ `\u{1F4E2}`,
1073
+ state.type,
1074
+ state.key,
1075
+ `root`,
1076
+ atomKey,
1077
+ `went`,
1078
+ atomChange.oldValue,
1079
+ `->`,
1080
+ atomChange.newValue
1081
+ );
1082
+ const oldValue = recallState(state, store);
1083
+ const newValue = readOrComputeValue(state, store);
1084
+ store.logger.info(
1085
+ `\u2728`,
1086
+ state.type,
1087
+ state.key,
1088
+ `went`,
1089
+ oldValue,
1090
+ `->`,
1091
+ newValue
1092
+ );
1093
+ state.subject.next({ newValue, oldValue });
1094
+ }
1095
+ );
1096
+ });
1097
+ return dependencySubscriptions;
1017
1098
  };
1018
-
1019
- // src/selector/update-selector-atoms.ts
1020
- var updateSelectorAtoms = (selectorKey, dependency, store) => {
1021
- const core = newest(store);
1022
- if (dependency.type === `atom`) {
1023
- core.selectorAtoms = core.selectorAtoms.set({
1024
- selectorKey,
1025
- atomKey: dependency.key
1026
- });
1099
+ function subscribeToState(token, handleUpdate, key, store) {
1100
+ const state = withdraw$1(token, store);
1101
+ if (state === void 0) {
1102
+ throw new Error(
1103
+ `State "${token.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
1104
+ );
1105
+ }
1106
+ const unsubFunction = state.subject.subscribe(key, handleUpdate);
1107
+ store.logger.info(`\u{1F440}`, state.type, state.key, `Adding subscription "${key}"`);
1108
+ const dependencyUnsubFunctions = state.type !== `atom` ? subscribeToRootAtoms$1(state, store) : null;
1109
+ const unsubscribe = dependencyUnsubFunctions === null ? () => {
1027
1110
  store.logger.info(
1028
- `\u{1F50D}`,
1029
- `selector`,
1030
- selectorKey,
1031
- `discovers root atom "${dependency.key}"`
1111
+ `\u{1F648}`,
1112
+ state.type,
1113
+ state.key,
1114
+ `Removing subscription "${key}"`
1032
1115
  );
1033
- } else {
1034
- const rootKeys = traceSelectorAtoms(selectorKey, dependency.key, store);
1116
+ unsubFunction();
1117
+ } : () => {
1035
1118
  store.logger.info(
1036
- `\u{1F50D}`,
1037
- `selector`,
1038
- selectorKey,
1039
- `discovers root atoms: [ ${rootKeys.map((key) => `"${key}"`).join(`, `)} ]`
1119
+ `\u{1F648}`,
1120
+ state.type,
1121
+ state.key,
1122
+ `Removing subscription "${key}"`
1040
1123
  );
1041
- for (const atomKey of rootKeys) {
1042
- core.selectorAtoms = core.selectorAtoms.set({
1043
- selectorKey,
1044
- atomKey
1045
- });
1124
+ unsubFunction();
1125
+ for (const unsubFromDependency of dependencyUnsubFunctions) {
1126
+ unsubFromDependency();
1046
1127
  }
1128
+ };
1129
+ return unsubscribe;
1130
+ }
1131
+ var subscribeToTimeline = (token, handleUpdate, key, store) => {
1132
+ const tl = withdraw$1(token, store);
1133
+ if (tl === void 0) {
1134
+ throw new Error(
1135
+ `Cannot subscribe to timeline "${token.key}": timeline not found in store "${store.config.name}".`
1136
+ );
1047
1137
  }
1048
- };
1049
-
1050
- // src/selector/register-selector.ts
1051
- var registerSelector = (selectorKey, store) => ({
1052
- get: (dependency) => {
1053
- const target = newest(store);
1054
- const alreadyRegistered = target.selectorGraph.getRelationEntries({ downstreamSelectorKey: selectorKey }).some(([_, { source }]) => source === dependency.key);
1055
- const dependencyState = withdraw(dependency, store);
1056
- if (dependencyState === void 0) {
1057
- throw new Error(
1058
- `State "${dependency.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
1059
- );
1060
- }
1061
- const dependencyValue = readOrComputeValue(dependencyState, store);
1138
+ store.logger.info(`\u{1F440}`, `timeline`, token.key, `Adding subscription "${key}"`);
1139
+ const unsubscribe = tl.subject.subscribe(key, handleUpdate);
1140
+ return () => {
1062
1141
  store.logger.info(
1063
- `\u{1F50C}`,
1064
- `selector`,
1065
- selectorKey,
1066
- `registers dependency ( "${dependency.key}" =`,
1067
- dependencyValue,
1068
- `)`
1142
+ `\u{1F648}`,
1143
+ `timeline`,
1144
+ token.key,
1145
+ `Removing subscription "${key}" from timeline`
1069
1146
  );
1070
- if (!alreadyRegistered) {
1071
- target.selectorGraph = target.selectorGraph.set(
1072
- {
1073
- upstreamSelectorKey: dependency.key,
1074
- downstreamSelectorKey: selectorKey
1075
- },
1076
- {
1077
- source: dependency.key
1078
- }
1079
- );
1080
- }
1081
- updateSelectorAtoms(selectorKey, dependency, store);
1082
- return dependencyValue;
1083
- },
1084
- set: (stateToken, newValue) => {
1085
- const state = withdraw(stateToken, store);
1086
- if (state === void 0) {
1087
- throw new Error(
1088
- `State "${stateToken.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`
1089
- );
1090
- }
1091
- setAtomOrSelector(state, newValue, store);
1092
- }
1093
- });
1094
-
1095
- // src/selector/create-read-write-selector.ts
1096
- var createReadWriteSelector = (options, family, store) => {
1097
- const target = newest(store);
1098
- const subject = new Subject();
1099
- const { get, set } = registerSelector(options.key, store);
1100
- const getSelf = () => {
1101
- const value = options.get({ get });
1102
- cacheValue(options.key, value, subject, store);
1103
- return value;
1147
+ unsubscribe();
1104
1148
  };
1105
- const setSelf = (next) => {
1106
- const oldValue = getSelf();
1107
- const newValue = become(next)(oldValue);
1149
+ };
1150
+ var subscribeToTransaction = (token, handleUpdate, key, store) => {
1151
+ const tx = withdraw$1(token, store);
1152
+ if (tx === void 0) {
1153
+ throw new Error(
1154
+ `Cannot subscribe to transaction "${token.key}": transaction not found in store "${store.config.name}".`
1155
+ );
1156
+ }
1157
+ store.logger.info(
1158
+ `\u{1F440}`,
1159
+ `transaction`,
1160
+ token.key,
1161
+ `Adding subscription "${key}"`
1162
+ );
1163
+ const unsubscribe = tx.subject.subscribe(key, handleUpdate);
1164
+ return () => {
1108
1165
  store.logger.info(
1109
- `\u{1F4DD}`,
1110
- `selector`,
1111
- options.key,
1112
- `set (`,
1113
- oldValue,
1114
- `->`,
1115
- newValue,
1116
- `)`
1166
+ `\u{1F648}`,
1167
+ `transaction`,
1168
+ token.key,
1169
+ `Removing subscription "${key}"`
1170
+ );
1171
+ unsubscribe();
1172
+ };
1173
+ };
1174
+ var Tracker = class {
1175
+ constructor(mutableState, store) {
1176
+ this.unsubscribeFromInnerValue = null;
1177
+ this.mutableState = mutableState;
1178
+ const target = newest(store);
1179
+ this.latestUpdateState = this.initializeState(mutableState, target);
1180
+ this.observeCore(mutableState, this.latestUpdateState, target);
1181
+ this.updateCore(mutableState, this.latestUpdateState, target);
1182
+ target.trackers.set(mutableState.key, this);
1183
+ }
1184
+ initializeState(mutableState, store) {
1185
+ const latestUpdateStateKey = `*${mutableState.key}`;
1186
+ deleteAtom({ type: `atom`, key: latestUpdateStateKey }, store);
1187
+ const familyMetaData = mutableState.family ? {
1188
+ key: `*${mutableState.family.key}`,
1189
+ subKey: mutableState.family.subKey
1190
+ } : void 0;
1191
+ const latestUpdateState = createAtom(
1192
+ {
1193
+ key: latestUpdateStateKey,
1194
+ default: null
1195
+ },
1196
+ familyMetaData,
1197
+ store
1198
+ );
1199
+ return latestUpdateState;
1200
+ }
1201
+ observeCore(mutableState, latestUpdateState, store) {
1202
+ const originalInnerValue = getState(mutableState, store);
1203
+ const target = newest(store);
1204
+ this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
1205
+ `tracker:${store.config.name}:${target.transactionMeta === null ? `main` : target.transactionMeta.update.key}`,
1206
+ (update) => {
1207
+ const unsubscribe = store.subject.operationStatus.subscribe(
1208
+ mutableState.key,
1209
+ () => {
1210
+ unsubscribe();
1211
+ setState(latestUpdateState, update, store);
1212
+ }
1213
+ );
1214
+ }
1215
+ );
1216
+ subscribeToState(
1217
+ mutableState,
1218
+ (update) => {
1219
+ var _a;
1220
+ if (update.newValue !== update.oldValue) {
1221
+ (_a = this.unsubscribeFromInnerValue) == null ? void 0 : _a.call(this);
1222
+ const target2 = newest(store);
1223
+ this.unsubscribeFromInnerValue = update.newValue.subscribe(
1224
+ `tracker:${store.config.name}:${target2.transactionMeta === null ? `main` : target2.transactionMeta.update.key}`,
1225
+ (update2) => {
1226
+ const unsubscribe = store.subject.operationStatus.subscribe(
1227
+ mutableState.key,
1228
+ () => {
1229
+ unsubscribe();
1230
+ setState(latestUpdateState, update2, store);
1231
+ }
1232
+ );
1233
+ }
1234
+ );
1235
+ }
1236
+ },
1237
+ `${store.config.name}: tracker observing inner value`,
1238
+ store
1239
+ );
1240
+ }
1241
+ updateCore(mutableState, latestUpdateState, store) {
1242
+ subscribeToState(
1243
+ latestUpdateState,
1244
+ ({ newValue, oldValue }) => {
1245
+ const timelineId = store.timelineAtoms.getRelatedKey(
1246
+ latestUpdateState.key
1247
+ );
1248
+ if (timelineId) {
1249
+ const timelineData = store.timelines.get(timelineId);
1250
+ if (timelineData == null ? void 0 : timelineData.timeTraveling) {
1251
+ const unsubscribe2 = subscribeToTimeline(
1252
+ { key: timelineId, type: `timeline` },
1253
+ (update) => {
1254
+ unsubscribe2();
1255
+ setState(
1256
+ mutableState,
1257
+ (transceiver) => {
1258
+ if (update === `redo` && newValue) {
1259
+ transceiver.do(newValue);
1260
+ } else if (update === `undo` && oldValue) {
1261
+ transceiver.undo(oldValue);
1262
+ }
1263
+ return transceiver;
1264
+ },
1265
+ store
1266
+ );
1267
+ },
1268
+ `${mutableState.key}: tracker observing timeline`,
1269
+ store
1270
+ );
1271
+ return;
1272
+ }
1273
+ }
1274
+ const unsubscribe = store.subject.operationStatus.subscribe(
1275
+ latestUpdateState.key,
1276
+ () => {
1277
+ unsubscribe();
1278
+ const mutable = getState(mutableState, store);
1279
+ const updateNumber = mutable.getUpdateNumber(newValue);
1280
+ const eventOffset = updateNumber - mutable.cacheUpdateNumber;
1281
+ if (newValue && eventOffset === 1) {
1282
+ setState(
1283
+ mutableState,
1284
+ (transceiver) => (transceiver.do(newValue), transceiver),
1285
+ store
1286
+ );
1287
+ }
1288
+ }
1289
+ );
1290
+ },
1291
+ `${store.config.name}: tracker observing latest update`,
1292
+ store
1117
1293
  );
1118
- cacheValue(options.key, newValue, subject, store);
1119
- markDone(options.key, store);
1120
- if (target.transactionMeta === null) {
1121
- subject.next({ newValue, oldValue });
1122
- }
1123
- options.set({ get, set }, newValue);
1124
- };
1125
- const mySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
1126
- subject,
1127
- install: (s) => createSelector(options, family, s),
1128
- get: getSelf,
1129
- set: setSelf,
1130
- type: `selector`
1131
- }), family && { family });
1132
- target.selectors.set(options.key, mySelector);
1133
- const initialValue = getSelf();
1134
- store.logger.info(`\u2728`, mySelector.type, mySelector.key, `=`, initialValue);
1135
- const token = {
1136
- key: options.key,
1137
- type: `selector`
1138
- };
1139
- if (family) {
1140
- token.family = family;
1141
1294
  }
1142
- store.subject.selectorCreation.next(token);
1143
- return token;
1144
1295
  };
1145
1296
 
1146
- // src/selector/create-readonly-selector.ts
1147
- var createReadonlySelector = (options, family, store) => {
1148
- const target = newest(store);
1149
- const subject = new Subject();
1150
- const { get } = registerSelector(options.key, store);
1151
- const getSelf = () => {
1152
- const value = options.get({ get });
1153
- cacheValue(options.key, value, subject, store);
1154
- return value;
1155
- };
1156
- const readonlySelector = __spreadValues(__spreadProps(__spreadValues({}, options), {
1157
- subject,
1158
- install: (s) => createSelector(options, family, s),
1159
- get: getSelf,
1160
- type: `readonly_selector`
1161
- }), family && { family });
1162
- target.readonlySelectors.set(options.key, readonlySelector);
1163
- const initialValue = getSelf();
1297
+ // src/mutable/create-mutable-atom.ts
1298
+ function createMutableAtom(options, store) {
1164
1299
  store.logger.info(
1165
- `\u2728`,
1166
- readonlySelector.type,
1167
- readonlySelector.key,
1168
- `=`,
1169
- initialValue
1300
+ `\u{1F527}`,
1301
+ `atom`,
1302
+ options.key,
1303
+ `creating in store "${store.config.name}"`
1170
1304
  );
1171
- const token = {
1172
- key: options.key,
1173
- type: `readonly_selector`
1174
- };
1175
- if (family) {
1176
- token.family = family;
1177
- }
1178
- store.subject.selectorCreation.next(token);
1179
- return token;
1180
- };
1181
-
1182
- // src/selector/create-selector.ts
1183
- function createSelector(options, family, store) {
1305
+ const coreState = createAtom(options, void 0, store);
1306
+ new Tracker(coreState, store);
1307
+ const jsonState = selectJson(coreState, options, store);
1184
1308
  const target = newest(store);
1185
- const existingWritable = target.selectors.get(options.key);
1186
- const existingReadonly = target.readonlySelectors.get(options.key);
1187
- if (existingWritable || existingReadonly) {
1188
- store.logger.error(
1189
- `\u274C`,
1190
- existingReadonly ? `readonly_selector` : `selector`,
1191
- options.key,
1192
- `Tried to create selector, but it already exists in the store. (Ignore if you are in development using hot module replacement.)`
1193
- );
1194
- }
1195
- if (`set` in options) {
1196
- return createReadWriteSelector(options, family, store);
1197
- }
1198
- return createReadonlySelector(options, family, store);
1309
+ subscribeToState(
1310
+ jsonState,
1311
+ () => {
1312
+ const trackerHasBeenInitialized = newest(store).trackers.has(coreState.key);
1313
+ if (!trackerHasBeenInitialized) {
1314
+ new Tracker(coreState, store);
1315
+ }
1316
+ },
1317
+ `tracker-initializer:${store == null ? void 0 : store.config.name}:${target.transactionMeta === null ? `main` : `${target.transactionMeta.update.key}`}`,
1318
+ store
1319
+ );
1320
+ return coreState;
1199
1321
  }
1200
-
1201
- // src/selector/delete-selector.ts
1202
- function deleteSelector(selectorToken, store) {
1203
- const target = newest(store);
1204
- const { key } = selectorToken;
1205
- switch (selectorToken.type) {
1206
- case `selector`:
1207
- target.selectors.delete(key);
1208
- break;
1209
- case `readonly_selector`:
1210
- target.readonlySelectors.delete(key);
1211
- break;
1212
- }
1213
- target.valueMap.delete(key);
1214
- target.selectorAtoms.delete(key);
1215
- const downstreamTokens = target.selectorGraph.getRelationEntries({ upstreamSelectorKey: key }).filter(([_, { source }]) => source === key).map(
1216
- ([downstreamSelectorKey]) => {
1217
- var _a;
1218
- return (_a = target.selectors.get(downstreamSelectorKey)) != null ? _a : target.readonlySelectors.get(downstreamSelectorKey);
1322
+ function createAtomFamily(options, store) {
1323
+ const subject = new Subject();
1324
+ const atomFamily = Object.assign(
1325
+ (key) => {
1326
+ const subKey = stringifyJson(key);
1327
+ const family = { key: options.key, subKey };
1328
+ const fullKey = `${options.key}(${subKey})`;
1329
+ const existing = withdraw({ key: fullKey, type: `atom` }, store);
1330
+ let token;
1331
+ if (existing) {
1332
+ token = deposit(existing);
1333
+ } else {
1334
+ const individualOptions = {
1335
+ key: fullKey,
1336
+ default: options.default instanceof Function ? options.default(key) : options.default
1337
+ };
1338
+ if (options.effects) {
1339
+ individualOptions.effects = options.effects(key);
1340
+ }
1341
+ token = createAtom(individualOptions, family, store);
1342
+ subject.next(token);
1343
+ }
1344
+ return token;
1345
+ },
1346
+ {
1347
+ key: options.key,
1348
+ type: `atom_family`,
1349
+ subject
1219
1350
  }
1220
1351
  );
1221
- for (const downstreamToken of downstreamTokens) {
1222
- if (downstreamToken) {
1223
- deleteSelector(downstreamToken, store);
1224
- }
1225
- }
1226
- target.selectorGraph.delete(key);
1227
- store.logger.info(`\u{1F525}`, selectorToken.type, `${key}`, `deleted`);
1352
+ const target = newest(store);
1353
+ target.families.set(options.key, atomFamily);
1354
+ return atomFamily;
1228
1355
  }
1229
-
1230
- // src/families/create-readonly-selector-family.ts
1231
1356
  function createReadonlySelectorFamily(options, store) {
1232
1357
  const subject = new Subject();
1233
1358
  return Object.assign(
@@ -1454,7 +1579,7 @@ function createAtom(options, family, store) {
1454
1579
  for (const effect of options.effects) {
1455
1580
  const cleanup = effect({
1456
1581
  setSelf: (next) => setState(token, next, store),
1457
- onSet: (handle) => subscribe(token, handle, `effect[${effectIndex}]`, store)
1582
+ onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
1458
1583
  });
1459
1584
  if (cleanup) {
1460
1585
  cleanupFunctions.push(cleanup);
@@ -1553,62 +1678,6 @@ var NotFoundError = class extends Error {
1553
1678
  }
1554
1679
  };
1555
1680
 
1556
- // src/subscribe/recall-state.ts
1557
- var recallState = (state, store) => {
1558
- const target = newest(store);
1559
- if (!target.operation.open) {
1560
- store.logger.warn(
1561
- `\u{1F41E}`,
1562
- state.type,
1563
- state.key,
1564
- `recall called outside of an operation. This is probably a bug.`
1565
- );
1566
- return target.valueMap.get(state.key);
1567
- }
1568
- return target.operation.prev.get(state.key);
1569
- };
1570
-
1571
- // src/subscribe/subscribe-to-root-atoms.ts
1572
- var subscribeToRootAtoms = (state, store) => {
1573
- const dependencySubscriptions = `default` in state ? null : traceAllSelectorAtoms(state.key, store).map((atomKey) => {
1574
- const atom = store.atoms.get(atomKey);
1575
- if (atom === void 0) {
1576
- throw new Error(
1577
- `Atom "${atomKey}", a dependency of selector "${state.key}", not found in store "${store.config.name}".`
1578
- );
1579
- }
1580
- return atom.subject.subscribe(
1581
- `${state.type}:${state.key}`,
1582
- (atomChange) => {
1583
- store.logger.info(
1584
- `\u{1F4E2}`,
1585
- state.type,
1586
- state.key,
1587
- `root`,
1588
- atomKey,
1589
- `went`,
1590
- atomChange.oldValue,
1591
- `->`,
1592
- atomChange.newValue
1593
- );
1594
- const oldValue = recallState(state, store);
1595
- const newValue = readOrComputeValue(state, store);
1596
- store.logger.info(
1597
- `\u2728`,
1598
- state.type,
1599
- state.key,
1600
- `went`,
1601
- oldValue,
1602
- `->`,
1603
- newValue
1604
- );
1605
- state.subject.next({ newValue, oldValue });
1606
- }
1607
- );
1608
- });
1609
- return dependencySubscriptions;
1610
- };
1611
-
1612
1681
  // src/timeline/add-atom-to-timeline.ts
1613
1682
  var addAtomToTimeline = (atomToken, tl, store) => {
1614
1683
  const atom = withdraw(atomToken, store);
@@ -2168,6 +2237,6 @@ var undoTransactionUpdate = (transactionUpdate, store) => {
2168
2237
  // src/transaction/index.ts
2169
2238
  var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
2170
2239
 
2171
- export { FamilyTracker, Future, IMPLICIT, LazyMap, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, addAtomToTimeline, applyTransaction, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtom, createAtomFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelectorFamily, createSelector, createSelectorFamily, createTimeline, createTransaction, deleteAtom, deleteSelector, deposit, eldest, evictCachedValue, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateToken, isAtomDefault, isAtomKey, isAtomMutable, isAtomTokenMutable, isDone, isReadonlySelectorKey, isSelectorDefault, isSelectorKey, isStateKey, isTransceiver, isValueCached, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, readCachedValue, readOrComputeValue, redoTransactionUpdate, registerSelector, setAtomOrSelector, subscribeToRootAtoms, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, undoTransactionUpdate, updateSelectorAtoms, withdraw, withdrawNewFamilyMember };
2240
+ export { FamilyTracker, Future, IMPLICIT, LazyMap, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, addAtomToTimeline, applyTransaction, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtom, createAtomFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelectorFamily, createSelector, createSelectorFamily, createTimeline, createTransaction, deleteAtom, deleteSelector, deposit, eldest, evictCachedValue, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateToken, isAtomDefault, isAtomKey, isAtomMutable, isAtomTokenMutable, isDone, isReadonlySelectorKey, isSelectorDefault, isSelectorKey, isStateKey, isTransceiver, isValueCached, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, readCachedValue, readOrComputeValue, redoTransactionUpdate, registerSelector, setAtomOrSelector, subscribeToRootAtoms, subscribeToState, subscribeToTimeline, subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, undoTransactionUpdate, updateSelectorAtoms, withdraw, withdrawNewFamilyMember };
2172
2241
  //# sourceMappingURL=out.js.map
2173
2242
  //# sourceMappingURL=index.js.map