atom.io 0.27.1 → 0.27.3
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.
- package/data/dist/index.d.ts +12 -12
- package/data/dist/index.js +20 -14
- package/data/src/dict.ts +4 -4
- package/data/src/join.ts +23 -18
- package/data/src/struct-family.ts +2 -2
- package/dist/chunk-ETCFHO7J.js +3087 -0
- package/dist/index.d.ts +4 -31
- package/eslint-plugin/dist/index.js +8 -0
- package/eslint-plugin/src/walk.ts +8 -0
- package/internal/dist/index.d.ts +52 -19
- package/internal/dist/index.js +2 -3044
- package/internal/src/families/create-atom-family.ts +6 -5
- package/internal/src/families/create-readonly-selector-family.ts +38 -29
- package/internal/src/families/create-regular-atom-family.ts +40 -31
- package/internal/src/families/create-selector-family.ts +6 -5
- package/internal/src/families/create-writable-selector-family.ts +39 -30
- package/internal/src/families/throw-in-case-of-conflicting-family.ts +18 -0
- package/internal/src/index.ts +76 -2
- package/internal/src/ingest-updates/ingest-creation-disposal.ts +0 -1
- package/internal/src/ingest-updates/ingest-selector-update.ts +1 -1
- package/internal/src/molecule/dispose-molecule.ts +0 -1
- package/internal/src/molecule/grow-molecule-in-store.ts +27 -17
- package/internal/src/mutable/create-mutable-atom-family.ts +41 -32
- package/internal/src/mutable/get-json-family.ts +2 -1
- package/internal/src/mutable/get-update-family.ts +23 -0
- package/internal/src/mutable/index.ts +1 -0
- package/internal/src/mutable/tracker-family.ts +5 -3
- package/internal/src/not-found-error.ts +2 -35
- package/internal/src/pretty-print.ts +37 -0
- package/internal/src/store/store.ts +10 -4
- package/internal/src/store/withdraw.ts +8 -8
- package/introspection/dist/index.js +3 -3
- package/introspection/src/attach-timeline-family.ts +1 -1
- package/introspection/src/attach-transaction-logs.ts +2 -2
- package/json/dist/index.d.ts +2 -2
- package/json/dist/index.js +16 -12
- package/json/src/select-json-family.ts +21 -18
- package/package.json +4 -4
- package/realtime-server/dist/index.d.ts +1 -1
- package/src/atom.ts +2 -32
- package/src/get-state.ts +2 -2
- package/src/index.ts +1 -10
- package/src/selector.ts +1 -26
- package/src/set-state.ts +2 -2
- package/src/silo.ts +7 -5
package/internal/dist/index.js
CHANGED
|
@@ -1,3045 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
export { FamilyTracker, Future, IMPLICIT, LazyMap, Molecule, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, actUponStore, applyTransaction, arbitrary, assignTransactionToContinuity, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtomFamily, createMoleculeFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelector, createReadonlySelectorFamily, createRegularAtom, createRegularAtomFamily, createSelectorFamily, createStandaloneAtom, createStandaloneSelector, createTimeline, createTransaction, createWritableSelector, deposit, disposeAtom, disposeFromStore, disposeMolecule, disposeSelector, eldest, evictCachedValue, findInStore, getContinuityKey, getEnvironmentData, getEpochNumberOfAction, getEpochNumberOfContinuity, getFromStore, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateFamily, getUpdateToken, growMoleculeInStore, ingestAtomUpdate, ingestCreationEvent, ingestDisposalEvent, ingestMoleculeCreationEvent, ingestMoleculeDisposalEvent, ingestSelectorUpdate, ingestTransactionUpdate, initFamilyMemberInStore, isAtomDefault, isAtomKey, isChildStore, isDone, isReadonlySelectorKey, isRootStore, isSelectorKey, isStateKey, isTransceiver, makeMoleculeInStore, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, prettyPrintTokenType, readCachedValue, readOrComputeValue, registerSelector, seekInStore, setAtomOrSelector, setEpochNumberOfAction, setEpochNumberOfContinuity, setIntoStore, subscribeToRootAtoms, subscribeToState, subscribeToTimeline, subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, updateSelectorAtoms, withdraw } from '../../dist/chunk-ETCFHO7J.js';
|
|
2
|
+
import '../../dist/chunk-IBTHB2PI.js';
|
|
2
3
|
import '../../dist/chunk-XWL6SNVU.js';
|
|
3
|
-
import { stringifyJson, parseJson, selectJson, selectJsonFamily } from 'atom.io/json';
|
|
4
|
-
import { AtomIOLogger } from 'atom.io';
|
|
5
|
-
import { getJoin, findRelations } from 'atom.io/data';
|
|
6
|
-
|
|
7
|
-
// internal/src/arbitrary.ts
|
|
8
|
-
function arbitrary(random = Math.random) {
|
|
9
|
-
return random().toString(36).slice(2);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
// internal/src/future.ts
|
|
13
|
-
var Future = class extends Promise {
|
|
14
|
-
fate;
|
|
15
|
-
resolve;
|
|
16
|
-
reject;
|
|
17
|
-
constructor(executor) {
|
|
18
|
-
let superResolve;
|
|
19
|
-
let superReject;
|
|
20
|
-
super((resolve, reject) => {
|
|
21
|
-
superResolve = resolve;
|
|
22
|
-
superReject = reject;
|
|
23
|
-
});
|
|
24
|
-
this.resolve = superResolve;
|
|
25
|
-
this.reject = superReject;
|
|
26
|
-
this.use(executor instanceof Promise ? executor : new Promise(executor));
|
|
27
|
-
}
|
|
28
|
-
pass(promise, value) {
|
|
29
|
-
if (promise === this.fate) {
|
|
30
|
-
this.resolve(value);
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
fail(promise, reason) {
|
|
34
|
-
if (promise === this.fate) {
|
|
35
|
-
this.reject(reason);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
use(value) {
|
|
39
|
-
if (value instanceof Promise) {
|
|
40
|
-
const promise = value;
|
|
41
|
-
this.fate = promise;
|
|
42
|
-
promise.then(
|
|
43
|
-
(resolved) => {
|
|
44
|
-
this.pass(promise, resolved);
|
|
45
|
-
},
|
|
46
|
-
(reason) => {
|
|
47
|
-
this.fail(promise, reason);
|
|
48
|
-
}
|
|
49
|
-
);
|
|
50
|
-
} else {
|
|
51
|
-
this.resolve(value);
|
|
52
|
-
this.fate = void 0;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
// internal/src/lineage.ts
|
|
58
|
-
function newest(scion) {
|
|
59
|
-
while (scion.child !== null) {
|
|
60
|
-
scion = scion.child;
|
|
61
|
-
}
|
|
62
|
-
return scion;
|
|
63
|
-
}
|
|
64
|
-
function eldest(scion) {
|
|
65
|
-
while (scion.parent !== null) {
|
|
66
|
-
scion = scion.parent;
|
|
67
|
-
}
|
|
68
|
-
return scion;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// internal/src/store/deposit.ts
|
|
72
|
-
function deposit(state) {
|
|
73
|
-
const token = {
|
|
74
|
-
key: state.key,
|
|
75
|
-
type: state.type
|
|
76
|
-
};
|
|
77
|
-
if (`family` in state) {
|
|
78
|
-
token.family = state.family;
|
|
79
|
-
}
|
|
80
|
-
return token;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
// internal/src/subject.ts
|
|
84
|
-
var Subject = class {
|
|
85
|
-
Subscriber;
|
|
86
|
-
subscribers = /* @__PURE__ */ new Map();
|
|
87
|
-
subscribe(key, subscriber) {
|
|
88
|
-
this.subscribers.set(key, subscriber);
|
|
89
|
-
const unsubscribe = () => {
|
|
90
|
-
this.unsubscribe(key);
|
|
91
|
-
};
|
|
92
|
-
return unsubscribe;
|
|
93
|
-
}
|
|
94
|
-
unsubscribe(key) {
|
|
95
|
-
this.subscribers.delete(key);
|
|
96
|
-
}
|
|
97
|
-
next(value) {
|
|
98
|
-
const subscribers = this.subscribers.values();
|
|
99
|
-
for (const subscriber of subscribers) {
|
|
100
|
-
subscriber(value);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
var StatefulSubject = class extends Subject {
|
|
105
|
-
state;
|
|
106
|
-
constructor(initialState) {
|
|
107
|
-
super();
|
|
108
|
-
this.state = initialState;
|
|
109
|
-
}
|
|
110
|
-
next(value) {
|
|
111
|
-
this.state = value;
|
|
112
|
-
super.next(value);
|
|
113
|
-
}
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
// internal/src/transaction/is-root-store.ts
|
|
117
|
-
function isRootStore(store) {
|
|
118
|
-
return `epoch` in store.transactionMeta;
|
|
119
|
-
}
|
|
120
|
-
function isChildStore(store) {
|
|
121
|
-
return `phase` in store.transactionMeta;
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
// internal/src/transaction/abort-transaction.ts
|
|
125
|
-
var abortTransaction = (store) => {
|
|
126
|
-
const target = newest(store);
|
|
127
|
-
if (!isChildStore(target)) {
|
|
128
|
-
store.logger.warn(
|
|
129
|
-
`\u{1F41E}`,
|
|
130
|
-
`transaction`,
|
|
131
|
-
`???`,
|
|
132
|
-
`abortTransaction called outside of a transaction. This is probably a bug in AtomIO.`
|
|
133
|
-
);
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
store.logger.info(
|
|
137
|
-
`\u{1FA82}`,
|
|
138
|
-
`transaction`,
|
|
139
|
-
target.transactionMeta.update.key,
|
|
140
|
-
`Aborting transaction`
|
|
141
|
-
);
|
|
142
|
-
target.parent.child = null;
|
|
143
|
-
};
|
|
144
|
-
var capitalize = (str) => str[0].toUpperCase() + str.slice(1);
|
|
145
|
-
function prettyPrintTokenType(token) {
|
|
146
|
-
switch (token.type) {
|
|
147
|
-
case `atom_family`:
|
|
148
|
-
return `Atom Family`;
|
|
149
|
-
case `molecule_family`:
|
|
150
|
-
return `Molecule Family`;
|
|
151
|
-
case `readonly_selector`:
|
|
152
|
-
return `Readonly Selector`;
|
|
153
|
-
case `readonly_selector_family`:
|
|
154
|
-
return `Readonly Selector Family`;
|
|
155
|
-
case `selector_family`:
|
|
156
|
-
return `Selector Family`;
|
|
157
|
-
default:
|
|
158
|
-
return capitalize(token.type);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
var NotFoundError = class extends Error {
|
|
162
|
-
constructor(...params) {
|
|
163
|
-
const token = params[0];
|
|
164
|
-
const store = params.length === 2 ? params[1] : params[2];
|
|
165
|
-
if (params.length === 2) {
|
|
166
|
-
super(
|
|
167
|
-
`${prettyPrintTokenType(token)} ${stringifyJson(token.key)} not found in store "${store.config.name}".`
|
|
168
|
-
);
|
|
169
|
-
} else {
|
|
170
|
-
const key = params[1];
|
|
171
|
-
super(
|
|
172
|
-
`${prettyPrintTokenType(token)} "${token.key}" member ${stringifyJson(key)} not found in store "${store.config.name}".`
|
|
173
|
-
);
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
};
|
|
177
|
-
|
|
178
|
-
// internal/src/transaction/act-upon-store.ts
|
|
179
|
-
function actUponStore(token, id, store) {
|
|
180
|
-
return (...parameters) => {
|
|
181
|
-
const tx = withdraw(token, store);
|
|
182
|
-
if (tx) {
|
|
183
|
-
return tx.run(parameters, id);
|
|
184
|
-
}
|
|
185
|
-
throw new NotFoundError(token, store);
|
|
186
|
-
};
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
// internal/src/set-state/become.ts
|
|
190
|
-
var become = (nextVersionOfThing) => (originalThing) => nextVersionOfThing instanceof Function ? nextVersionOfThing(
|
|
191
|
-
originalThing instanceof Function ? originalThing() : originalThing
|
|
192
|
-
) : nextVersionOfThing;
|
|
193
|
-
|
|
194
|
-
// internal/src/get-state/read-or-compute-value.ts
|
|
195
|
-
var readOrComputeValue = (state, target) => {
|
|
196
|
-
if (target.valueMap.has(state.key)) {
|
|
197
|
-
target.logger.info(`\u{1F4D6}`, state.type, state.key, `reading cached value`);
|
|
198
|
-
return readCachedValue(state, target);
|
|
199
|
-
}
|
|
200
|
-
if (state.type !== `atom` && state.type !== `mutable_atom`) {
|
|
201
|
-
target.logger.info(`\u{1F9EE}`, state.type, state.key, `computing value`);
|
|
202
|
-
return state.get();
|
|
203
|
-
}
|
|
204
|
-
const fallback = state.default instanceof Function ? state.default() : state.default;
|
|
205
|
-
target.logger.info(
|
|
206
|
-
`\u{1F481}`,
|
|
207
|
-
`atom`,
|
|
208
|
-
state.key,
|
|
209
|
-
`could not find cached value; using default`,
|
|
210
|
-
fallback
|
|
211
|
-
);
|
|
212
|
-
return state.default instanceof Function ? state.default() : state.default;
|
|
213
|
-
};
|
|
214
|
-
|
|
215
|
-
// internal/src/operation.ts
|
|
216
|
-
var openOperation = (token, store) => {
|
|
217
|
-
if (store.operation.open) {
|
|
218
|
-
const rejectionTime = performance.now();
|
|
219
|
-
store.logger.info(
|
|
220
|
-
`\u2757`,
|
|
221
|
-
token.type,
|
|
222
|
-
token.key,
|
|
223
|
-
`deferring setState at T-${rejectionTime} until setState for "${store.operation.token.key}" is done`
|
|
224
|
-
);
|
|
225
|
-
return rejectionTime;
|
|
226
|
-
}
|
|
227
|
-
store.operation = {
|
|
228
|
-
open: true,
|
|
229
|
-
done: /* @__PURE__ */ new Set(),
|
|
230
|
-
prev: /* @__PURE__ */ new Map(),
|
|
231
|
-
time: Date.now(),
|
|
232
|
-
token
|
|
233
|
-
};
|
|
234
|
-
store.logger.info(
|
|
235
|
-
`\u2B55`,
|
|
236
|
-
token.type,
|
|
237
|
-
token.key,
|
|
238
|
-
`operation start in store "${store.config.name}"${!isChildStore(store) ? `` : ` ${store.transactionMeta.phase} "${store.transactionMeta.update.key}"`}`
|
|
239
|
-
);
|
|
240
|
-
};
|
|
241
|
-
var closeOperation = (store) => {
|
|
242
|
-
if (store.operation.open) {
|
|
243
|
-
store.logger.info(
|
|
244
|
-
`\u{1F534}`,
|
|
245
|
-
store.operation.token.type,
|
|
246
|
-
store.operation.token.key,
|
|
247
|
-
`operation done in store "${store.config.name}"`
|
|
248
|
-
);
|
|
249
|
-
}
|
|
250
|
-
store.operation = { open: false };
|
|
251
|
-
store.on.operationClose.next(store.operation);
|
|
252
|
-
};
|
|
253
|
-
var isDone = (key, store) => {
|
|
254
|
-
if (!store.operation.open) {
|
|
255
|
-
store.logger.warn(
|
|
256
|
-
`\u{1F41E}`,
|
|
257
|
-
`unknown`,
|
|
258
|
-
key,
|
|
259
|
-
`isDone called outside of an operation. This is probably a bug.`
|
|
260
|
-
);
|
|
261
|
-
return true;
|
|
262
|
-
}
|
|
263
|
-
return store.operation.done.has(key);
|
|
264
|
-
};
|
|
265
|
-
var markDone = (key, store) => {
|
|
266
|
-
if (!store.operation.open) {
|
|
267
|
-
store.logger.warn(
|
|
268
|
-
`\u{1F41E}`,
|
|
269
|
-
`unknown`,
|
|
270
|
-
key,
|
|
271
|
-
`markDone called outside of an operation. This is probably a bug.`
|
|
272
|
-
);
|
|
273
|
-
return;
|
|
274
|
-
}
|
|
275
|
-
store.operation.done.add(key);
|
|
276
|
-
};
|
|
277
|
-
|
|
278
|
-
// internal/src/set-state/emit-update.ts
|
|
279
|
-
var emitUpdate = (state, update, store) => {
|
|
280
|
-
switch (state.type) {
|
|
281
|
-
case `mutable_atom`:
|
|
282
|
-
store.logger.info(
|
|
283
|
-
`\u{1F4E2}`,
|
|
284
|
-
state.type,
|
|
285
|
-
state.key,
|
|
286
|
-
`is now (`,
|
|
287
|
-
update.newValue,
|
|
288
|
-
`) subscribers:`,
|
|
289
|
-
state.subject.subscribers
|
|
290
|
-
);
|
|
291
|
-
break;
|
|
292
|
-
default:
|
|
293
|
-
store.logger.info(
|
|
294
|
-
`\u{1F4E2}`,
|
|
295
|
-
state.type,
|
|
296
|
-
state.key,
|
|
297
|
-
`went (`,
|
|
298
|
-
update.oldValue,
|
|
299
|
-
`->`,
|
|
300
|
-
update.newValue,
|
|
301
|
-
`) subscribers:`,
|
|
302
|
-
state.subject.subscribers
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
state.subject.next(update);
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
// internal/src/set-state/evict-downstream.ts
|
|
309
|
-
var evictDownStream = (atom, store) => {
|
|
310
|
-
const target = newest(store);
|
|
311
|
-
const downstreamKeys = target.selectorAtoms.getRelatedKeys(atom.key);
|
|
312
|
-
target.logger.info(
|
|
313
|
-
`\u{1F9F9}`,
|
|
314
|
-
atom.type,
|
|
315
|
-
atom.key,
|
|
316
|
-
downstreamKeys ? `evicting ${downstreamKeys.size} states downstream:` : `no downstream states`,
|
|
317
|
-
downstreamKeys ?? `to evict`
|
|
318
|
-
);
|
|
319
|
-
if (downstreamKeys) {
|
|
320
|
-
if (target.operation.open) {
|
|
321
|
-
target.logger.info(
|
|
322
|
-
`\u{1F9F9}`,
|
|
323
|
-
atom.type,
|
|
324
|
-
atom.key,
|
|
325
|
-
`[ ${[...target.operation.done].join(`, `)} ] already done`
|
|
326
|
-
);
|
|
327
|
-
}
|
|
328
|
-
for (const key of downstreamKeys) {
|
|
329
|
-
if (isDone(key, target)) {
|
|
330
|
-
continue;
|
|
331
|
-
}
|
|
332
|
-
evictCachedValue(key, target);
|
|
333
|
-
markDone(key, target);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
};
|
|
337
|
-
|
|
338
|
-
// internal/src/set-state/stow-update.ts
|
|
339
|
-
function shouldUpdateBeStowed(key, update) {
|
|
340
|
-
if (isTransceiver(update.newValue)) {
|
|
341
|
-
return false;
|
|
342
|
-
}
|
|
343
|
-
if (key.includes(`\u{1F441}\u200D\u{1F5E8}`)) {
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
return true;
|
|
347
|
-
}
|
|
348
|
-
var stowUpdate = (state, update, store) => {
|
|
349
|
-
const { key } = state;
|
|
350
|
-
const target = newest(store);
|
|
351
|
-
if (!isChildStore(target) || target.transactionMeta.phase !== `building`) {
|
|
352
|
-
store.logger.error(
|
|
353
|
-
`\u{1F41E}`,
|
|
354
|
-
`atom`,
|
|
355
|
-
key,
|
|
356
|
-
`stowUpdate called outside of a transaction. This is probably a bug.`
|
|
357
|
-
);
|
|
358
|
-
return;
|
|
359
|
-
}
|
|
360
|
-
const shouldStow = shouldUpdateBeStowed(key, update);
|
|
361
|
-
if (!shouldStow) {
|
|
362
|
-
return;
|
|
363
|
-
}
|
|
364
|
-
const atomUpdate = {
|
|
365
|
-
type: `atom_update`,
|
|
366
|
-
key,
|
|
367
|
-
...update
|
|
368
|
-
};
|
|
369
|
-
if (state.family) {
|
|
370
|
-
atomUpdate.family = state.family;
|
|
371
|
-
}
|
|
372
|
-
target.transactionMeta.update.updates.push(atomUpdate);
|
|
373
|
-
store.logger.info(
|
|
374
|
-
`\u{1F4C1}`,
|
|
375
|
-
`atom`,
|
|
376
|
-
key,
|
|
377
|
-
`stowed (`,
|
|
378
|
-
update.oldValue,
|
|
379
|
-
`->`,
|
|
380
|
-
update.newValue,
|
|
381
|
-
`)`
|
|
382
|
-
);
|
|
383
|
-
};
|
|
384
|
-
|
|
385
|
-
// internal/src/set-state/set-atom.ts
|
|
386
|
-
var setAtom = (atom, next, target) => {
|
|
387
|
-
const oldValue = readOrComputeValue(atom, target);
|
|
388
|
-
let newValue = oldValue;
|
|
389
|
-
if (atom.type === `mutable_atom` && isChildStore(target)) {
|
|
390
|
-
const { parent } = target;
|
|
391
|
-
const copiedValue = copyMutableIfNeeded(atom, parent, target);
|
|
392
|
-
newValue = copiedValue;
|
|
393
|
-
}
|
|
394
|
-
newValue = become(next)(newValue);
|
|
395
|
-
target.logger.info(`\u{1F4DD}`, `atom`, atom.key, `set to`, newValue);
|
|
396
|
-
newValue = cacheValue(atom.key, newValue, atom.subject, target);
|
|
397
|
-
if (isAtomDefault(atom.key, target)) {
|
|
398
|
-
markAtomAsNotDefault(atom.key, target);
|
|
399
|
-
}
|
|
400
|
-
markDone(atom.key, target);
|
|
401
|
-
evictDownStream(atom, target);
|
|
402
|
-
const update = { oldValue, newValue };
|
|
403
|
-
if (isRootStore(target)) {
|
|
404
|
-
emitUpdate(atom, update, target);
|
|
405
|
-
} else if (target.parent) {
|
|
406
|
-
if (target.on.transactionApplying.state === null) {
|
|
407
|
-
stowUpdate(atom, update, target);
|
|
408
|
-
} else if (atom.key.startsWith(`*`)) {
|
|
409
|
-
const mutableKey = atom.key.slice(1);
|
|
410
|
-
const mutableAtom = target.atoms.get(mutableKey);
|
|
411
|
-
let transceiver = target.valueMap.get(mutableKey);
|
|
412
|
-
if (mutableAtom.type === `mutable_atom` && isChildStore(target)) {
|
|
413
|
-
const { parent } = target;
|
|
414
|
-
const copiedValue = copyMutableIfNeeded(mutableAtom, parent, target);
|
|
415
|
-
transceiver = copiedValue;
|
|
416
|
-
}
|
|
417
|
-
const accepted = transceiver.do(update.newValue) === null;
|
|
418
|
-
if (accepted) evictDownStream(mutableAtom, target);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
|
|
423
|
-
// internal/src/set-state/set-atom-or-selector.ts
|
|
424
|
-
var setAtomOrSelector = (state, value, store) => {
|
|
425
|
-
switch (state.type) {
|
|
426
|
-
case `atom`:
|
|
427
|
-
case `mutable_atom`:
|
|
428
|
-
setAtom(state, value, store);
|
|
429
|
-
break;
|
|
430
|
-
case `selector`:
|
|
431
|
-
state.set(value);
|
|
432
|
-
break;
|
|
433
|
-
}
|
|
434
|
-
};
|
|
435
|
-
function createRegularAtomFamily(options, store) {
|
|
436
|
-
const subject = new Subject();
|
|
437
|
-
const atomFamily = Object.assign(
|
|
438
|
-
(key) => {
|
|
439
|
-
const subKey = stringifyJson(key);
|
|
440
|
-
const family = { key: options.key, subKey };
|
|
441
|
-
const fullKey = `${options.key}(${subKey})`;
|
|
442
|
-
const target = newest(store);
|
|
443
|
-
const def = options.default;
|
|
444
|
-
const individualOptions = {
|
|
445
|
-
key: fullKey,
|
|
446
|
-
default: def instanceof Function ? def(key) : def
|
|
447
|
-
};
|
|
448
|
-
if (options.effects) {
|
|
449
|
-
individualOptions.effects = options.effects(key);
|
|
450
|
-
}
|
|
451
|
-
const token = createRegularAtom(individualOptions, family, target);
|
|
452
|
-
subject.next({ type: `state_creation`, token });
|
|
453
|
-
return token;
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
key: options.key,
|
|
457
|
-
type: `atom_family`,
|
|
458
|
-
subject,
|
|
459
|
-
install: (s) => createRegularAtomFamily(options, s)
|
|
460
|
-
}
|
|
461
|
-
);
|
|
462
|
-
store.families.set(options.key, atomFamily);
|
|
463
|
-
return atomFamily;
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
// internal/src/families/create-atom-family.ts
|
|
467
|
-
function createAtomFamily(options, store) {
|
|
468
|
-
const isMutable = `mutable` in options;
|
|
469
|
-
if (isMutable) {
|
|
470
|
-
return createMutableAtomFamily(options, store);
|
|
471
|
-
}
|
|
472
|
-
return createRegularAtomFamily(options, store);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
// internal/src/get-state/get-from-store.ts
|
|
476
|
-
function getFromStore(...params) {
|
|
477
|
-
let token;
|
|
478
|
-
let store;
|
|
479
|
-
if (params.length === 2) {
|
|
480
|
-
token = params[0];
|
|
481
|
-
store = params[1];
|
|
482
|
-
} else {
|
|
483
|
-
const family = params[0];
|
|
484
|
-
const key = params[1];
|
|
485
|
-
store = params[2];
|
|
486
|
-
const maybeToken = family.type === `molecule_family` ? seekInStore(family, key, store) : store.config.lifespan === `immortal` ? seekInStore(family, key, store) : findInStore(family, key, store);
|
|
487
|
-
if (!maybeToken) {
|
|
488
|
-
throw new NotFoundError(family, key, store);
|
|
489
|
-
}
|
|
490
|
-
token = maybeToken;
|
|
491
|
-
}
|
|
492
|
-
switch (token.type) {
|
|
493
|
-
case `atom`:
|
|
494
|
-
case `mutable_atom`:
|
|
495
|
-
case `selector`:
|
|
496
|
-
case `readonly_selector`:
|
|
497
|
-
return readOrComputeValue(withdraw(token, store), store);
|
|
498
|
-
case `molecule`:
|
|
499
|
-
return withdraw(token, store).instance;
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// internal/src/keys.ts
|
|
504
|
-
var isAtomKey = (key, store) => newest(store).atoms.has(key);
|
|
505
|
-
var isSelectorKey = (key, store) => newest(store).selectors.has(key);
|
|
506
|
-
var isReadonlySelectorKey = (key, store) => newest(store).readonlySelectors.has(key);
|
|
507
|
-
var isStateKey = (key, store) => isAtomKey(key, store) || isSelectorKey(key, store) || isReadonlySelectorKey(key, store);
|
|
508
|
-
|
|
509
|
-
// internal/src/selector/get-selector-dependency-keys.ts
|
|
510
|
-
var getSelectorDependencyKeys = (key, store) => {
|
|
511
|
-
const sources = newest(store).selectorGraph.getRelationEntries({ downstreamSelectorKey: key }).filter(([_, { source }]) => source !== key).map(([_, { source }]) => source).filter((source) => isStateKey(source, store));
|
|
512
|
-
return sources;
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
// internal/src/selector/trace-selector-atoms.ts
|
|
516
|
-
var traceSelectorAtoms = (directDependencyKey, covered, store) => {
|
|
517
|
-
const rootKeys = [];
|
|
518
|
-
const indirectDependencyKeys = getSelectorDependencyKeys(
|
|
519
|
-
directDependencyKey,
|
|
520
|
-
store
|
|
521
|
-
);
|
|
522
|
-
while (indirectDependencyKeys.length > 0) {
|
|
523
|
-
const indirectDependencyKey = indirectDependencyKeys.shift();
|
|
524
|
-
if (covered.has(indirectDependencyKey)) {
|
|
525
|
-
continue;
|
|
526
|
-
}
|
|
527
|
-
covered.add(indirectDependencyKey);
|
|
528
|
-
if (!isAtomKey(indirectDependencyKey, store)) {
|
|
529
|
-
indirectDependencyKeys.push(
|
|
530
|
-
...getSelectorDependencyKeys(indirectDependencyKey, store)
|
|
531
|
-
);
|
|
532
|
-
} else if (!rootKeys.includes(indirectDependencyKey)) {
|
|
533
|
-
rootKeys.push(indirectDependencyKey);
|
|
534
|
-
}
|
|
535
|
-
}
|
|
536
|
-
return rootKeys;
|
|
537
|
-
};
|
|
538
|
-
var traceAllSelectorAtoms = (selector, store) => {
|
|
539
|
-
const selectorKey = selector.key;
|
|
540
|
-
const directDependencyKeys = getSelectorDependencyKeys(selectorKey, store);
|
|
541
|
-
const covered = /* @__PURE__ */ new Set();
|
|
542
|
-
return directDependencyKeys.flatMap(
|
|
543
|
-
(depKey) => isAtomKey(depKey, store) ? depKey : traceSelectorAtoms(depKey, covered, store)
|
|
544
|
-
);
|
|
545
|
-
};
|
|
546
|
-
|
|
547
|
-
// internal/src/selector/update-selector-atoms.ts
|
|
548
|
-
var updateSelectorAtoms = (selectorKey, dependency, covered, store) => {
|
|
549
|
-
const target = newest(store);
|
|
550
|
-
if (dependency.type === `atom` || dependency.type === `mutable_atom`) {
|
|
551
|
-
target.selectorAtoms.set({
|
|
552
|
-
selectorKey,
|
|
553
|
-
atomKey: dependency.key
|
|
554
|
-
});
|
|
555
|
-
store.logger.info(
|
|
556
|
-
`\u{1F50D}`,
|
|
557
|
-
`selector`,
|
|
558
|
-
selectorKey,
|
|
559
|
-
`discovers root atom "${dependency.key}"`
|
|
560
|
-
);
|
|
561
|
-
} else {
|
|
562
|
-
const rootKeys = traceSelectorAtoms(dependency.key, covered, store);
|
|
563
|
-
store.logger.info(
|
|
564
|
-
`\u{1F50D}`,
|
|
565
|
-
`selector`,
|
|
566
|
-
selectorKey,
|
|
567
|
-
`discovers root atoms: [ ${rootKeys.map((key) => `"${key}"`).join(`, `)} ]`
|
|
568
|
-
);
|
|
569
|
-
for (const atomKey of rootKeys) {
|
|
570
|
-
target.selectorAtoms = target.selectorAtoms.set({
|
|
571
|
-
selectorKey,
|
|
572
|
-
atomKey
|
|
573
|
-
});
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
covered.add(dependency.key);
|
|
577
|
-
};
|
|
578
|
-
|
|
579
|
-
// internal/src/selector/register-selector.ts
|
|
580
|
-
var registerSelector = (selectorKey, covered, store) => ({
|
|
581
|
-
get: (...params) => {
|
|
582
|
-
const target = newest(store);
|
|
583
|
-
let dependency;
|
|
584
|
-
if (params.length === 2) {
|
|
585
|
-
const [family, key] = params;
|
|
586
|
-
switch (family.type) {
|
|
587
|
-
case `molecule_family`:
|
|
588
|
-
return getFromStore(family, key, store);
|
|
589
|
-
default:
|
|
590
|
-
if (store.config.lifespan === `ephemeral`) {
|
|
591
|
-
dependency = findInStore(family, key, store);
|
|
592
|
-
} else {
|
|
593
|
-
const maybeDependency = seekInStore(family, key, store);
|
|
594
|
-
if (maybeDependency) {
|
|
595
|
-
dependency = maybeDependency;
|
|
596
|
-
} else {
|
|
597
|
-
throw new NotFoundError(family, key, store);
|
|
598
|
-
}
|
|
599
|
-
}
|
|
600
|
-
}
|
|
601
|
-
} else {
|
|
602
|
-
[dependency] = params;
|
|
603
|
-
}
|
|
604
|
-
if (dependency.type === `molecule`) {
|
|
605
|
-
return getFromStore(dependency, store);
|
|
606
|
-
}
|
|
607
|
-
const dependencyState = withdraw(dependency, store);
|
|
608
|
-
const dependencyValue = readOrComputeValue(dependencyState, store);
|
|
609
|
-
store.logger.info(
|
|
610
|
-
`\u{1F50C}`,
|
|
611
|
-
`selector`,
|
|
612
|
-
selectorKey,
|
|
613
|
-
`registers dependency ( "${dependency.key}" =`,
|
|
614
|
-
dependencyValue,
|
|
615
|
-
`)`
|
|
616
|
-
);
|
|
617
|
-
target.selectorGraph.set(
|
|
618
|
-
{
|
|
619
|
-
upstreamSelectorKey: dependency.key,
|
|
620
|
-
downstreamSelectorKey: selectorKey
|
|
621
|
-
},
|
|
622
|
-
{
|
|
623
|
-
source: dependency.key
|
|
624
|
-
}
|
|
625
|
-
);
|
|
626
|
-
updateSelectorAtoms(selectorKey, dependency, covered, store);
|
|
627
|
-
return dependencyValue;
|
|
628
|
-
},
|
|
629
|
-
set: (...params) => {
|
|
630
|
-
let token;
|
|
631
|
-
let value;
|
|
632
|
-
if (params.length === 2) {
|
|
633
|
-
token = params[0];
|
|
634
|
-
value = params[1];
|
|
635
|
-
} else {
|
|
636
|
-
const family = params[0];
|
|
637
|
-
const key = params[1];
|
|
638
|
-
value = params[2];
|
|
639
|
-
const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(family, key, store) : seekInStore(family, key, store);
|
|
640
|
-
if (!maybeToken) {
|
|
641
|
-
throw new NotFoundError(family, key, store);
|
|
642
|
-
}
|
|
643
|
-
token = maybeToken;
|
|
644
|
-
}
|
|
645
|
-
const target = newest(store);
|
|
646
|
-
const state = withdraw(token, target);
|
|
647
|
-
setAtomOrSelector(state, value, target);
|
|
648
|
-
},
|
|
649
|
-
find: (token, key) => findInStore(token, key, store),
|
|
650
|
-
seek: (token, key) => seekInStore(token, key, store),
|
|
651
|
-
json: (token) => getJsonToken(token, store)
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
// internal/src/selector/create-readonly-selector.ts
|
|
655
|
-
var createReadonlySelector = (options, family, store) => {
|
|
656
|
-
const target = newest(store);
|
|
657
|
-
const subject = new Subject();
|
|
658
|
-
const covered = /* @__PURE__ */ new Set();
|
|
659
|
-
const { get, find, seek, json } = registerSelector(
|
|
660
|
-
options.key,
|
|
661
|
-
covered,
|
|
662
|
-
target
|
|
663
|
-
);
|
|
664
|
-
const getSelf = () => {
|
|
665
|
-
const value = options.get({ get, find, seek, json });
|
|
666
|
-
cacheValue(options.key, value, subject, newest(store));
|
|
667
|
-
covered.clear();
|
|
668
|
-
return value;
|
|
669
|
-
};
|
|
670
|
-
const readonlySelector = {
|
|
671
|
-
...options,
|
|
672
|
-
subject,
|
|
673
|
-
install: (s) => createReadonlySelector(options, family, s),
|
|
674
|
-
get: getSelf,
|
|
675
|
-
type: `readonly_selector`,
|
|
676
|
-
...family && { family }
|
|
677
|
-
};
|
|
678
|
-
target.readonlySelectors.set(options.key, readonlySelector);
|
|
679
|
-
const initialValue = getSelf();
|
|
680
|
-
store.logger.info(
|
|
681
|
-
`\u2728`,
|
|
682
|
-
readonlySelector.type,
|
|
683
|
-
readonlySelector.key,
|
|
684
|
-
`=`,
|
|
685
|
-
initialValue
|
|
686
|
-
);
|
|
687
|
-
const token = {
|
|
688
|
-
key: options.key,
|
|
689
|
-
type: `readonly_selector`
|
|
690
|
-
};
|
|
691
|
-
if (family) {
|
|
692
|
-
token.family = family;
|
|
693
|
-
}
|
|
694
|
-
return token;
|
|
695
|
-
};
|
|
696
|
-
|
|
697
|
-
// internal/src/selector/create-writable-selector.ts
|
|
698
|
-
var createWritableSelector = (options, family, store) => {
|
|
699
|
-
const target = newest(store);
|
|
700
|
-
const subject = new Subject();
|
|
701
|
-
const covered = /* @__PURE__ */ new Set();
|
|
702
|
-
const toolkit = registerSelector(options.key, covered, target);
|
|
703
|
-
const { find, get, seek, json } = toolkit;
|
|
704
|
-
const getterToolkit = { find, get, seek, json };
|
|
705
|
-
const getSelf = (innerTarget = newest(store)) => {
|
|
706
|
-
const value = options.get(getterToolkit);
|
|
707
|
-
cacheValue(options.key, value, subject, innerTarget);
|
|
708
|
-
covered.clear();
|
|
709
|
-
return value;
|
|
710
|
-
};
|
|
711
|
-
const setSelf = (next) => {
|
|
712
|
-
const innerTarget = newest(store);
|
|
713
|
-
const oldValue = getSelf(innerTarget);
|
|
714
|
-
const newValue = become(next)(oldValue);
|
|
715
|
-
store.logger.info(
|
|
716
|
-
`\u{1F4DD}`,
|
|
717
|
-
`selector`,
|
|
718
|
-
options.key,
|
|
719
|
-
`set (`,
|
|
720
|
-
oldValue,
|
|
721
|
-
`->`,
|
|
722
|
-
newValue,
|
|
723
|
-
`)`
|
|
724
|
-
);
|
|
725
|
-
cacheValue(options.key, newValue, subject, innerTarget);
|
|
726
|
-
markDone(options.key, innerTarget);
|
|
727
|
-
if (isRootStore(innerTarget)) {
|
|
728
|
-
subject.next({ newValue, oldValue });
|
|
729
|
-
}
|
|
730
|
-
options.set(toolkit, newValue);
|
|
731
|
-
};
|
|
732
|
-
const mySelector = {
|
|
733
|
-
...options,
|
|
734
|
-
subject,
|
|
735
|
-
install: (s) => createWritableSelector(options, family, s),
|
|
736
|
-
get: getSelf,
|
|
737
|
-
set: setSelf,
|
|
738
|
-
type: `selector`,
|
|
739
|
-
...family && { family }
|
|
740
|
-
};
|
|
741
|
-
target.selectors.set(options.key, mySelector);
|
|
742
|
-
const initialValue = getSelf();
|
|
743
|
-
store.logger.info(`\u2728`, mySelector.type, mySelector.key, `=`, initialValue);
|
|
744
|
-
const token = {
|
|
745
|
-
key: options.key,
|
|
746
|
-
type: `selector`
|
|
747
|
-
};
|
|
748
|
-
if (family) {
|
|
749
|
-
token.family = family;
|
|
750
|
-
}
|
|
751
|
-
return token;
|
|
752
|
-
};
|
|
753
|
-
|
|
754
|
-
// internal/src/selector/create-standalone-selector.ts
|
|
755
|
-
function createStandaloneSelector(options, store) {
|
|
756
|
-
const isWritable = `set` in options;
|
|
757
|
-
if (isWritable) {
|
|
758
|
-
const state2 = createWritableSelector(options, void 0, store);
|
|
759
|
-
store.on.selectorCreation.next(state2);
|
|
760
|
-
return state2;
|
|
761
|
-
}
|
|
762
|
-
const state = createReadonlySelector(options, void 0, store);
|
|
763
|
-
store.on.selectorCreation.next(state);
|
|
764
|
-
return state;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
// internal/src/selector/dispose-selector.ts
|
|
768
|
-
function disposeSelector(selectorToken, store) {
|
|
769
|
-
const target = newest(store);
|
|
770
|
-
const { key } = selectorToken;
|
|
771
|
-
const selector = target.selectors.get(key) ?? target.readonlySelectors.get(key);
|
|
772
|
-
if (!selector) {
|
|
773
|
-
store.logger.info(
|
|
774
|
-
`\u274C`,
|
|
775
|
-
`selector`,
|
|
776
|
-
key,
|
|
777
|
-
`Tried to dispose selector, but it does not exist in the store.`
|
|
778
|
-
);
|
|
779
|
-
} else if (!selector.family) {
|
|
780
|
-
store.logger.error(
|
|
781
|
-
`\u274C`,
|
|
782
|
-
`selector`,
|
|
783
|
-
key,
|
|
784
|
-
`Standalone selectors cannot be disposed.`
|
|
785
|
-
);
|
|
786
|
-
} else {
|
|
787
|
-
const molecule = target.molecules.get(selector.family.subKey);
|
|
788
|
-
if (molecule) {
|
|
789
|
-
molecule.tokens.delete(key);
|
|
790
|
-
}
|
|
791
|
-
switch (selectorToken.type) {
|
|
792
|
-
case `selector`:
|
|
793
|
-
{
|
|
794
|
-
target.selectors.delete(key);
|
|
795
|
-
const family = withdraw(
|
|
796
|
-
{ key: selector.family.key, type: `selector_family` },
|
|
797
|
-
store
|
|
798
|
-
);
|
|
799
|
-
family.subject.next({
|
|
800
|
-
type: `state_disposal`,
|
|
801
|
-
token: selectorToken
|
|
802
|
-
});
|
|
803
|
-
}
|
|
804
|
-
break;
|
|
805
|
-
case `readonly_selector`:
|
|
806
|
-
{
|
|
807
|
-
target.readonlySelectors.delete(key);
|
|
808
|
-
const family = withdraw(
|
|
809
|
-
{ key: selector.family.key, type: `readonly_selector_family` },
|
|
810
|
-
store
|
|
811
|
-
);
|
|
812
|
-
family.subject.next({
|
|
813
|
-
type: `state_disposal`,
|
|
814
|
-
token: selectorToken
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
break;
|
|
818
|
-
}
|
|
819
|
-
target.valueMap.delete(key);
|
|
820
|
-
target.selectorAtoms.delete(key);
|
|
821
|
-
const downstreamTokens = target.selectorGraph.getRelationEntries({ upstreamSelectorKey: key }).filter(([_, { source }]) => source === key).map(
|
|
822
|
-
([downstreamSelectorKey]) => target.selectors.get(downstreamSelectorKey) ?? target.readonlySelectors.get(downstreamSelectorKey)
|
|
823
|
-
);
|
|
824
|
-
for (const downstreamToken of downstreamTokens) {
|
|
825
|
-
if (downstreamToken) {
|
|
826
|
-
disposeSelector(downstreamToken, store);
|
|
827
|
-
}
|
|
828
|
-
}
|
|
829
|
-
target.selectorGraph.delete(key);
|
|
830
|
-
store.logger.info(`\u{1F525}`, selectorToken.type, key, `deleted`);
|
|
831
|
-
if (isChildStore(target) && target.transactionMeta.phase === `building`) {
|
|
832
|
-
target.transactionMeta.update.updates.push({
|
|
833
|
-
type: `state_disposal`,
|
|
834
|
-
token: selectorToken
|
|
835
|
-
});
|
|
836
|
-
} else {
|
|
837
|
-
store.on.selectorDisposal.next(selectorToken);
|
|
838
|
-
}
|
|
839
|
-
}
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// internal/src/families/create-readonly-selector-family.ts
|
|
843
|
-
function createReadonlySelectorFamily(options, store) {
|
|
844
|
-
const subject = new Subject();
|
|
845
|
-
const readonlySelectorFamily = Object.assign(
|
|
846
|
-
(key) => {
|
|
847
|
-
const subKey = stringifyJson(key);
|
|
848
|
-
const family = { key: options.key, subKey };
|
|
849
|
-
const fullKey = `${options.key}(${subKey})`;
|
|
850
|
-
const target = newest(store);
|
|
851
|
-
const token = createReadonlySelector(
|
|
852
|
-
{
|
|
853
|
-
key: fullKey,
|
|
854
|
-
get: options.get(key)
|
|
855
|
-
},
|
|
856
|
-
family,
|
|
857
|
-
target
|
|
858
|
-
);
|
|
859
|
-
subject.next({ type: `state_creation`, token });
|
|
860
|
-
return token;
|
|
861
|
-
},
|
|
862
|
-
{
|
|
863
|
-
key: options.key,
|
|
864
|
-
type: `readonly_selector_family`,
|
|
865
|
-
subject,
|
|
866
|
-
install: (s) => createReadonlySelectorFamily(options, s)
|
|
867
|
-
}
|
|
868
|
-
);
|
|
869
|
-
store.families.set(options.key, readonlySelectorFamily);
|
|
870
|
-
return readonlySelectorFamily;
|
|
871
|
-
}
|
|
872
|
-
function createWritableSelectorFamily(options, store) {
|
|
873
|
-
const subject = new Subject();
|
|
874
|
-
const selectorFamily = Object.assign(
|
|
875
|
-
(key) => {
|
|
876
|
-
const subKey = stringifyJson(key);
|
|
877
|
-
const family = { key: options.key, subKey };
|
|
878
|
-
const fullKey = `${options.key}(${subKey})`;
|
|
879
|
-
const target = newest(store);
|
|
880
|
-
const token = createWritableSelector(
|
|
881
|
-
{
|
|
882
|
-
key: fullKey,
|
|
883
|
-
get: options.get(key),
|
|
884
|
-
set: options.set(key)
|
|
885
|
-
},
|
|
886
|
-
family,
|
|
887
|
-
target
|
|
888
|
-
);
|
|
889
|
-
subject.next({ type: `state_creation`, token });
|
|
890
|
-
return token;
|
|
891
|
-
},
|
|
892
|
-
{
|
|
893
|
-
key: options.key,
|
|
894
|
-
type: `selector_family`,
|
|
895
|
-
subject,
|
|
896
|
-
install: (s) => createWritableSelectorFamily(options, s)
|
|
897
|
-
}
|
|
898
|
-
);
|
|
899
|
-
store.families.set(options.key, selectorFamily);
|
|
900
|
-
return selectorFamily;
|
|
901
|
-
}
|
|
902
|
-
|
|
903
|
-
// internal/src/families/create-selector-family.ts
|
|
904
|
-
function createSelectorFamily(options, store) {
|
|
905
|
-
const isWritable = `set` in options;
|
|
906
|
-
if (isWritable) {
|
|
907
|
-
return createWritableSelectorFamily(options, store);
|
|
908
|
-
}
|
|
909
|
-
return createReadonlySelectorFamily(options, store);
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
// internal/src/molecule/dispose-molecule.ts
|
|
913
|
-
function disposeMolecule(token, store) {
|
|
914
|
-
let molecule;
|
|
915
|
-
try {
|
|
916
|
-
molecule = withdraw(token, store);
|
|
917
|
-
} catch (thrown) {
|
|
918
|
-
if (thrown instanceof Error) {
|
|
919
|
-
store.logger.error(
|
|
920
|
-
`\u{1F41E}`,
|
|
921
|
-
`molecule`,
|
|
922
|
-
JSON.stringify(token.key),
|
|
923
|
-
`Failed to dispose molecule, because it was not found in the store.`,
|
|
924
|
-
thrown.message
|
|
925
|
-
);
|
|
926
|
-
}
|
|
927
|
-
return;
|
|
928
|
-
}
|
|
929
|
-
const { family } = token;
|
|
930
|
-
const context = [];
|
|
931
|
-
for (const above of molecule.above.values()) {
|
|
932
|
-
context.push(deposit(above));
|
|
933
|
-
}
|
|
934
|
-
const values = [];
|
|
935
|
-
for (const stateToken of molecule.tokens.values()) {
|
|
936
|
-
const tokenFamily = stateToken.family;
|
|
937
|
-
values.push([tokenFamily.key, store.valueMap.get(stateToken.key)]);
|
|
938
|
-
}
|
|
939
|
-
if (family) {
|
|
940
|
-
const Formula = withdraw(family, store);
|
|
941
|
-
const disposalEvent = {
|
|
942
|
-
type: `molecule_disposal`,
|
|
943
|
-
token,
|
|
944
|
-
family,
|
|
945
|
-
context,
|
|
946
|
-
values
|
|
947
|
-
};
|
|
948
|
-
if (token.family) {
|
|
949
|
-
disposalEvent.family = token.family;
|
|
950
|
-
}
|
|
951
|
-
for (const state of molecule.tokens.values()) {
|
|
952
|
-
disposeFromStore(state, store);
|
|
953
|
-
}
|
|
954
|
-
for (const child of molecule.below.values()) {
|
|
955
|
-
if (child.family?.dependsOn === `all`) {
|
|
956
|
-
disposeMolecule(child, store);
|
|
957
|
-
} else {
|
|
958
|
-
child.above.delete(molecule.stringKey);
|
|
959
|
-
if (child.above.size === 0) {
|
|
960
|
-
disposeMolecule(child, store);
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
}
|
|
964
|
-
molecule.below.clear();
|
|
965
|
-
const isTransaction = isChildStore(store) && store.transactionMeta.phase === `building`;
|
|
966
|
-
if (isTransaction) {
|
|
967
|
-
store.transactionMeta.update.updates.push(disposalEvent);
|
|
968
|
-
} else {
|
|
969
|
-
Formula.subject.next(disposalEvent);
|
|
970
|
-
}
|
|
971
|
-
store.molecules.delete(molecule.stringKey);
|
|
972
|
-
}
|
|
973
|
-
for (const join of molecule.joins.values()) {
|
|
974
|
-
join.molecules.delete(molecule.stringKey);
|
|
975
|
-
}
|
|
976
|
-
for (const parent of molecule.above.values()) {
|
|
977
|
-
parent.below.delete(molecule.stringKey);
|
|
978
|
-
}
|
|
979
|
-
}
|
|
980
|
-
|
|
981
|
-
// internal/src/families/init-family-member.ts
|
|
982
|
-
function initFamilyMemberInStore(token, key, store) {
|
|
983
|
-
const familyKey = token.key;
|
|
984
|
-
const family = store.families.get(familyKey);
|
|
985
|
-
if (family === void 0) {
|
|
986
|
-
throw new NotFoundError(token, store);
|
|
987
|
-
}
|
|
988
|
-
const state = family(key);
|
|
989
|
-
const target = newest(store);
|
|
990
|
-
if (state.family && target.moleculeInProgress === null) {
|
|
991
|
-
if (isRootStore(target)) {
|
|
992
|
-
switch (state.type) {
|
|
993
|
-
case `atom`:
|
|
994
|
-
case `mutable_atom`:
|
|
995
|
-
store.on.atomCreation.next(state);
|
|
996
|
-
break;
|
|
997
|
-
case `selector`:
|
|
998
|
-
case `readonly_selector`:
|
|
999
|
-
store.on.selectorCreation.next(state);
|
|
1000
|
-
break;
|
|
1001
|
-
}
|
|
1002
|
-
} else if (isChildStore(target) && target.on.transactionApplying.state === null) {
|
|
1003
|
-
target.transactionMeta.update.updates.push({
|
|
1004
|
-
type: `state_creation`,
|
|
1005
|
-
token: state
|
|
1006
|
-
});
|
|
1007
|
-
}
|
|
1008
|
-
}
|
|
1009
|
-
return state;
|
|
1010
|
-
}
|
|
1011
|
-
function seekInStore(token, key, store) {
|
|
1012
|
-
const subKey = stringifyJson(key);
|
|
1013
|
-
const fullKey = `${token.key}(${subKey})`;
|
|
1014
|
-
const target = newest(store);
|
|
1015
|
-
let state;
|
|
1016
|
-
switch (token.type) {
|
|
1017
|
-
case `atom_family`:
|
|
1018
|
-
case `mutable_atom_family`:
|
|
1019
|
-
state = target.atoms.get(fullKey);
|
|
1020
|
-
break;
|
|
1021
|
-
case `selector_family`:
|
|
1022
|
-
state = target.selectors.get(fullKey);
|
|
1023
|
-
break;
|
|
1024
|
-
case `readonly_selector_family`:
|
|
1025
|
-
state = target.readonlySelectors.get(fullKey);
|
|
1026
|
-
break;
|
|
1027
|
-
case `molecule_family`:
|
|
1028
|
-
state = target.molecules.get(stringifyJson(key));
|
|
1029
|
-
if (state) {
|
|
1030
|
-
return deposit(state);
|
|
1031
|
-
}
|
|
1032
|
-
}
|
|
1033
|
-
if (state) {
|
|
1034
|
-
return deposit(state);
|
|
1035
|
-
}
|
|
1036
|
-
return state;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
// internal/src/families/find-in-store.ts
|
|
1040
|
-
function findInStore(token, key, store) {
|
|
1041
|
-
if (store.config.lifespan === `immortal`) {
|
|
1042
|
-
throw new Error(
|
|
1043
|
-
`Do not use \`find\` or \`findState\` in an immortal store. Prefer \`seek\` or \`seekState\`.`
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
let state = seekInStore(token, key, store);
|
|
1047
|
-
if (state) {
|
|
1048
|
-
return state;
|
|
1049
|
-
}
|
|
1050
|
-
state = initFamilyMemberInStore(token, key, store);
|
|
1051
|
-
return state;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
// internal/src/families/dispose-from-store.ts
|
|
1055
|
-
function disposeFromStore(...params) {
|
|
1056
|
-
let token;
|
|
1057
|
-
let store;
|
|
1058
|
-
if (params.length === 2) {
|
|
1059
|
-
token = params[0];
|
|
1060
|
-
store = params[1];
|
|
1061
|
-
} else {
|
|
1062
|
-
const family = params[0];
|
|
1063
|
-
const key = params[1];
|
|
1064
|
-
store = params[2];
|
|
1065
|
-
const maybeToken = family.type === `molecule_family` ? seekInStore(family, key, store) : store.config.lifespan === `immortal` ? seekInStore(family, key, store) : findInStore(family, key, store);
|
|
1066
|
-
if (!maybeToken) {
|
|
1067
|
-
throw new NotFoundError(family, key, store);
|
|
1068
|
-
}
|
|
1069
|
-
token = maybeToken;
|
|
1070
|
-
}
|
|
1071
|
-
switch (token.type) {
|
|
1072
|
-
case `atom`:
|
|
1073
|
-
case `mutable_atom`:
|
|
1074
|
-
disposeAtom(token, store);
|
|
1075
|
-
break;
|
|
1076
|
-
case `selector`:
|
|
1077
|
-
case `readonly_selector`:
|
|
1078
|
-
disposeSelector(token, store);
|
|
1079
|
-
break;
|
|
1080
|
-
case `molecule`:
|
|
1081
|
-
disposeMolecule(token, store);
|
|
1082
|
-
break;
|
|
1083
|
-
}
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
// internal/src/set-state/set-into-store.ts
|
|
1087
|
-
function setIntoStore(...params) {
|
|
1088
|
-
let token;
|
|
1089
|
-
let value;
|
|
1090
|
-
let store;
|
|
1091
|
-
if (params.length === 3) {
|
|
1092
|
-
token = params[0];
|
|
1093
|
-
value = params[1];
|
|
1094
|
-
store = params[2];
|
|
1095
|
-
} else {
|
|
1096
|
-
const family = params[0];
|
|
1097
|
-
const key = params[1];
|
|
1098
|
-
value = params[2];
|
|
1099
|
-
store = params[3];
|
|
1100
|
-
const maybeToken = store.config.lifespan === `ephemeral` ? findInStore(family, key, store) : seekInStore(family, key, store);
|
|
1101
|
-
if (!maybeToken) {
|
|
1102
|
-
throw new NotFoundError(family, key, store);
|
|
1103
|
-
}
|
|
1104
|
-
token = maybeToken;
|
|
1105
|
-
}
|
|
1106
|
-
const rejectionTime = openOperation(token, store);
|
|
1107
|
-
if (rejectionTime) {
|
|
1108
|
-
const unsubscribe = store.on.operationClose.subscribe(
|
|
1109
|
-
`waiting to set "${token.key}" at T-${rejectionTime}`,
|
|
1110
|
-
() => {
|
|
1111
|
-
unsubscribe();
|
|
1112
|
-
store.logger.info(
|
|
1113
|
-
`\u{1F7E2}`,
|
|
1114
|
-
token.type,
|
|
1115
|
-
token.key,
|
|
1116
|
-
`resuming deferred setState from T-${rejectionTime}`
|
|
1117
|
-
);
|
|
1118
|
-
setIntoStore(token, value, store);
|
|
1119
|
-
}
|
|
1120
|
-
);
|
|
1121
|
-
return;
|
|
1122
|
-
}
|
|
1123
|
-
const state = withdraw(token, store);
|
|
1124
|
-
setAtomOrSelector(state, value, store);
|
|
1125
|
-
closeOperation(store);
|
|
1126
|
-
}
|
|
1127
|
-
|
|
1128
|
-
// internal/src/ingest-updates/ingest-atom-update.ts
|
|
1129
|
-
function ingestAtomUpdate(applying, atomUpdate, store) {
|
|
1130
|
-
const { key, newValue, oldValue } = atomUpdate;
|
|
1131
|
-
const value = applying === `newValue` ? newValue : oldValue;
|
|
1132
|
-
const token = { key, type: `atom` };
|
|
1133
|
-
if (atomUpdate.family) {
|
|
1134
|
-
Object.assign(token, { family: atomUpdate.family });
|
|
1135
|
-
}
|
|
1136
|
-
setIntoStore(token, value, store);
|
|
1137
|
-
}
|
|
1138
|
-
|
|
1139
|
-
// internal/src/molecule/create-molecule-family.ts
|
|
1140
|
-
function createMoleculeFamily(options, store) {
|
|
1141
|
-
const subject = new Subject();
|
|
1142
|
-
const token = {
|
|
1143
|
-
type: `molecule_family`,
|
|
1144
|
-
key: options.key,
|
|
1145
|
-
dependsOn: options.dependsOn ?? `all`
|
|
1146
|
-
};
|
|
1147
|
-
const family = {
|
|
1148
|
-
...token,
|
|
1149
|
-
subject,
|
|
1150
|
-
new: options.new
|
|
1151
|
-
};
|
|
1152
|
-
store.moleculeFamilies.set(options.key, family);
|
|
1153
|
-
return token;
|
|
1154
|
-
}
|
|
1155
|
-
|
|
1156
|
-
// internal/src/molecule/grow-molecule-in-store.ts
|
|
1157
|
-
function growMoleculeInStore(molecule, family, store) {
|
|
1158
|
-
const stateToken = initFamilyMemberInStore(family, molecule.key, store);
|
|
1159
|
-
molecule.tokens.set(stateToken.key, stateToken);
|
|
1160
|
-
const isTransaction = isChildStore(store) && store.transactionMeta.phase === `building`;
|
|
1161
|
-
const moleculeInProgress = store.moleculeInProgress === molecule.key;
|
|
1162
|
-
if (!isTransaction && !moleculeInProgress) {
|
|
1163
|
-
molecule.subject.next({ type: `state_creation`, token: stateToken });
|
|
1164
|
-
}
|
|
1165
|
-
return stateToken;
|
|
1166
|
-
}
|
|
1167
|
-
|
|
1168
|
-
// internal/src/get-environment-data.ts
|
|
1169
|
-
function getEnvironmentData(store) {
|
|
1170
|
-
return {
|
|
1171
|
-
store
|
|
1172
|
-
};
|
|
1173
|
-
}
|
|
1174
|
-
var Molecule = class {
|
|
1175
|
-
constructor(ctx, key, family) {
|
|
1176
|
-
this.key = key;
|
|
1177
|
-
this.stringKey = stringifyJson(key);
|
|
1178
|
-
if (family) {
|
|
1179
|
-
this.family = family;
|
|
1180
|
-
}
|
|
1181
|
-
if (ctx) {
|
|
1182
|
-
if (Array.isArray(ctx)) {
|
|
1183
|
-
for (const molecule of ctx) {
|
|
1184
|
-
this.above.set(molecule.stringKey, molecule);
|
|
1185
|
-
}
|
|
1186
|
-
} else {
|
|
1187
|
-
this.above.set(ctx.stringKey, ctx);
|
|
1188
|
-
}
|
|
1189
|
-
}
|
|
1190
|
-
}
|
|
1191
|
-
type = `molecule`;
|
|
1192
|
-
stringKey;
|
|
1193
|
-
family;
|
|
1194
|
-
subject = new Subject();
|
|
1195
|
-
tokens = /* @__PURE__ */ new Map();
|
|
1196
|
-
above = /* @__PURE__ */ new Map();
|
|
1197
|
-
below = /* @__PURE__ */ new Map();
|
|
1198
|
-
joins = /* @__PURE__ */ new Map();
|
|
1199
|
-
instance;
|
|
1200
|
-
};
|
|
1201
|
-
|
|
1202
|
-
// internal/src/molecule/make-molecule-in-store.ts
|
|
1203
|
-
function capitalize2(string) {
|
|
1204
|
-
return string[0].toUpperCase() + string.slice(1);
|
|
1205
|
-
}
|
|
1206
|
-
function makeMoleculeInStore(store, context, familyToken, key, ...params) {
|
|
1207
|
-
const rootStore = eldest(store);
|
|
1208
|
-
const target = newest(store);
|
|
1209
|
-
const stringKey = stringifyJson(key);
|
|
1210
|
-
target.moleculeInProgress = stringKey;
|
|
1211
|
-
const contextArray = Array.isArray(context) ? context : [context];
|
|
1212
|
-
const owners = contextArray.map((ctx) => {
|
|
1213
|
-
if (ctx instanceof Molecule) {
|
|
1214
|
-
return ctx;
|
|
1215
|
-
}
|
|
1216
|
-
const ctxStringKey = stringifyJson(ctx.key);
|
|
1217
|
-
const molecule2 = store.molecules.get(ctxStringKey);
|
|
1218
|
-
if (!molecule2) {
|
|
1219
|
-
throw new Error(
|
|
1220
|
-
`Molecule ${ctxStringKey} not found in store "${store.config.name}"`
|
|
1221
|
-
);
|
|
1222
|
-
}
|
|
1223
|
-
return molecule2;
|
|
1224
|
-
});
|
|
1225
|
-
const molecule = new Molecule(owners, key, familyToken);
|
|
1226
|
-
target.molecules.set(stringKey, molecule);
|
|
1227
|
-
for (const owner of owners) {
|
|
1228
|
-
owner.below.set(molecule.stringKey, molecule);
|
|
1229
|
-
}
|
|
1230
|
-
const toolkit = {
|
|
1231
|
-
get: (...ps) => getFromStore(...ps, newest(rootStore)),
|
|
1232
|
-
set: (...ps) => {
|
|
1233
|
-
setIntoStore(...ps, newest(rootStore));
|
|
1234
|
-
},
|
|
1235
|
-
seek: (t, k) => seekInStore(t, k, newest(rootStore)),
|
|
1236
|
-
json: (t) => getJsonToken(t, newest(rootStore)),
|
|
1237
|
-
run: (t, i = arbitrary()) => actUponStore(t, i, newest(store)),
|
|
1238
|
-
make: (ctx, f, k, ...args) => makeMoleculeInStore(newest(rootStore), ctx, f, k, ...args),
|
|
1239
|
-
dispose: (t) => {
|
|
1240
|
-
disposeFromStore(t, newest(rootStore));
|
|
1241
|
-
},
|
|
1242
|
-
env: () => getEnvironmentData(newest(rootStore)),
|
|
1243
|
-
bond: (token2, maybeRole) => {
|
|
1244
|
-
if (token2.type === `join`) {
|
|
1245
|
-
const { as: role } = maybeRole;
|
|
1246
|
-
const join = getJoin(token2, rootStore);
|
|
1247
|
-
join.molecules.set(stringKey, molecule);
|
|
1248
|
-
molecule.joins.set(token2.key, join);
|
|
1249
|
-
const unsubFromFamily = family.subject.subscribe(
|
|
1250
|
-
`join:${token2.key}-${stringKey}`,
|
|
1251
|
-
(event) => {
|
|
1252
|
-
if (event.type === `molecule_disposal` && stringifyJson(event.token.key) === stringKey) {
|
|
1253
|
-
unsubFromFamily();
|
|
1254
|
-
join.molecules.delete(stringKey);
|
|
1255
|
-
}
|
|
1256
|
-
}
|
|
1257
|
-
);
|
|
1258
|
-
if (role === null) {
|
|
1259
|
-
return;
|
|
1260
|
-
}
|
|
1261
|
-
const otherRole = token2.a === role ? token2.b : token2.a;
|
|
1262
|
-
const relations = findRelations(token2, key);
|
|
1263
|
-
const relatedKeys = relations[`${otherRole}KeysOf${capitalize2(role)}`];
|
|
1264
|
-
const relatedEntries = relations[`${otherRole}EntriesOf${capitalize2(role)}`];
|
|
1265
|
-
let tokens = { relatedKeys };
|
|
1266
|
-
if (relatedEntries) {
|
|
1267
|
-
tokens = Object.assign(tokens, { relatedEntries });
|
|
1268
|
-
}
|
|
1269
|
-
return tokens;
|
|
1270
|
-
}
|
|
1271
|
-
return growMoleculeInStore(
|
|
1272
|
-
molecule,
|
|
1273
|
-
withdraw(token2, rootStore),
|
|
1274
|
-
newest(rootStore)
|
|
1275
|
-
);
|
|
1276
|
-
},
|
|
1277
|
-
claim: (below, options) => {
|
|
1278
|
-
const { exclusive } = options;
|
|
1279
|
-
const belowMolecule = newest(store).molecules.get(stringifyJson(below.key));
|
|
1280
|
-
if (belowMolecule) {
|
|
1281
|
-
if (exclusive) {
|
|
1282
|
-
for (const value of belowMolecule.above.values()) {
|
|
1283
|
-
value.below.delete(belowMolecule.stringKey);
|
|
1284
|
-
}
|
|
1285
|
-
belowMolecule.above.clear();
|
|
1286
|
-
belowMolecule.above.set(molecule.stringKey, molecule);
|
|
1287
|
-
molecule.below.set(belowMolecule.stringKey, belowMolecule);
|
|
1288
|
-
} else {
|
|
1289
|
-
belowMolecule.above.set(molecule.stringKey, molecule);
|
|
1290
|
-
molecule.below.set(belowMolecule.stringKey, belowMolecule);
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
},
|
|
1294
|
-
spawn: (f, k, ...p) => makeMoleculeInStore(
|
|
1295
|
-
newest(store),
|
|
1296
|
-
[molecule],
|
|
1297
|
-
withdraw(f, store),
|
|
1298
|
-
k,
|
|
1299
|
-
...p
|
|
1300
|
-
)
|
|
1301
|
-
};
|
|
1302
|
-
const family = withdraw(familyToken, store);
|
|
1303
|
-
const Constructor = family.new;
|
|
1304
|
-
molecule.instance = new Constructor(toolkit, key, ...params);
|
|
1305
|
-
const token = {
|
|
1306
|
-
type: `molecule`,
|
|
1307
|
-
key,
|
|
1308
|
-
family: familyToken
|
|
1309
|
-
};
|
|
1310
|
-
const update = {
|
|
1311
|
-
type: `molecule_creation`,
|
|
1312
|
-
token,
|
|
1313
|
-
family: familyToken,
|
|
1314
|
-
context: contextArray,
|
|
1315
|
-
params
|
|
1316
|
-
};
|
|
1317
|
-
if (isRootStore(target)) {
|
|
1318
|
-
family.subject.next(update);
|
|
1319
|
-
} else if (isChildStore(target) && target.on.transactionApplying.state === null) {
|
|
1320
|
-
target.transactionMeta.update.updates.push(update);
|
|
1321
|
-
}
|
|
1322
|
-
target.moleculeInProgress = null;
|
|
1323
|
-
return token;
|
|
1324
|
-
}
|
|
1325
|
-
|
|
1326
|
-
// internal/src/ingest-updates/ingest-creation-disposal.ts
|
|
1327
|
-
function ingestCreationEvent(update, applying, store) {
|
|
1328
|
-
switch (applying) {
|
|
1329
|
-
case `newValue`: {
|
|
1330
|
-
createInStore(update.token, store);
|
|
1331
|
-
break;
|
|
1332
|
-
}
|
|
1333
|
-
case `oldValue`: {
|
|
1334
|
-
disposeFromStore(update.token, store);
|
|
1335
|
-
break;
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
}
|
|
1339
|
-
function ingestDisposalEvent(update, applying, store) {
|
|
1340
|
-
switch (applying) {
|
|
1341
|
-
case `newValue`: {
|
|
1342
|
-
disposeFromStore(update.token, store);
|
|
1343
|
-
break;
|
|
1344
|
-
}
|
|
1345
|
-
case `oldValue`: {
|
|
1346
|
-
createInStore(update.token, store);
|
|
1347
|
-
store.valueMap.set(update.token.key, update.value);
|
|
1348
|
-
break;
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
function createInStore(token, store) {
|
|
1353
|
-
if (token.family) {
|
|
1354
|
-
const family = store.families.get(token.family.key);
|
|
1355
|
-
if (family) {
|
|
1356
|
-
const molecule = store.molecules.get(token.family.subKey);
|
|
1357
|
-
if (molecule) {
|
|
1358
|
-
growMoleculeInStore(molecule, family, store);
|
|
1359
|
-
return;
|
|
1360
|
-
}
|
|
1361
|
-
if (store.config.lifespan === `immortal`) {
|
|
1362
|
-
throw new Error(`No molecule found for key "${token.family.subKey}"`);
|
|
1363
|
-
}
|
|
1364
|
-
initFamilyMemberInStore(family, parseJson(token.family.subKey), store);
|
|
1365
|
-
}
|
|
1366
|
-
}
|
|
1367
|
-
}
|
|
1368
|
-
function ingestMoleculeCreationEvent(update, applying, store) {
|
|
1369
|
-
switch (applying) {
|
|
1370
|
-
case `newValue`:
|
|
1371
|
-
makeMoleculeInStore(
|
|
1372
|
-
store,
|
|
1373
|
-
update.context,
|
|
1374
|
-
update.family,
|
|
1375
|
-
update.token.key,
|
|
1376
|
-
...update.params
|
|
1377
|
-
);
|
|
1378
|
-
break;
|
|
1379
|
-
case `oldValue`:
|
|
1380
|
-
disposeFromStore(update.token, store);
|
|
1381
|
-
break;
|
|
1382
|
-
}
|
|
1383
|
-
}
|
|
1384
|
-
function ingestMoleculeDisposalEvent(update, applying, store) {
|
|
1385
|
-
switch (applying) {
|
|
1386
|
-
case `newValue`:
|
|
1387
|
-
disposeFromStore(update.token, store);
|
|
1388
|
-
break;
|
|
1389
|
-
case `oldValue`:
|
|
1390
|
-
{
|
|
1391
|
-
const moleculeToken = makeMoleculeInStore(
|
|
1392
|
-
store,
|
|
1393
|
-
update.context,
|
|
1394
|
-
update.family,
|
|
1395
|
-
update.token.key
|
|
1396
|
-
);
|
|
1397
|
-
for (const [familyKey, value] of update.values) {
|
|
1398
|
-
const memberKey = `${familyKey}(${stringifyJson(moleculeToken.key)})`;
|
|
1399
|
-
const molecule = withdraw(moleculeToken, store);
|
|
1400
|
-
const alreadyCreated = molecule.tokens.has(memberKey);
|
|
1401
|
-
const family = store.families.get(familyKey);
|
|
1402
|
-
if (family && !alreadyCreated) {
|
|
1403
|
-
growMoleculeInStore(molecule, family, store);
|
|
1404
|
-
}
|
|
1405
|
-
store.valueMap.set(memberKey, value);
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
break;
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// internal/src/ingest-updates/ingest-selector-update.ts
|
|
1413
|
-
function ingestSelectorUpdate(applying, selectorUpdate, store) {
|
|
1414
|
-
const updates = applying === `newValue` ? selectorUpdate.atomUpdates : [...selectorUpdate.atomUpdates].reverse();
|
|
1415
|
-
for (const atomUpdate of updates) {
|
|
1416
|
-
ingestAtomUpdate(applying, atomUpdate, store);
|
|
1417
|
-
}
|
|
1418
|
-
}
|
|
1419
|
-
|
|
1420
|
-
// internal/src/ingest-updates/ingest-transaction-update.ts
|
|
1421
|
-
function ingestTransactionUpdate(applying, transactionUpdate, store) {
|
|
1422
|
-
const updates = applying === `newValue` ? transactionUpdate.updates : [...transactionUpdate.updates].reverse();
|
|
1423
|
-
for (const updateFromTransaction of updates) {
|
|
1424
|
-
switch (updateFromTransaction.type) {
|
|
1425
|
-
case `atom_update`:
|
|
1426
|
-
case `selector_update`:
|
|
1427
|
-
ingestAtomUpdate(applying, updateFromTransaction, store);
|
|
1428
|
-
break;
|
|
1429
|
-
case `state_creation`:
|
|
1430
|
-
ingestCreationEvent(updateFromTransaction, applying, store);
|
|
1431
|
-
break;
|
|
1432
|
-
case `state_disposal`:
|
|
1433
|
-
ingestDisposalEvent(updateFromTransaction, applying, store);
|
|
1434
|
-
break;
|
|
1435
|
-
case `molecule_creation`:
|
|
1436
|
-
ingestMoleculeCreationEvent(updateFromTransaction, applying, store);
|
|
1437
|
-
break;
|
|
1438
|
-
case `molecule_disposal`:
|
|
1439
|
-
ingestMoleculeDisposalEvent(updateFromTransaction, applying, store);
|
|
1440
|
-
break;
|
|
1441
|
-
case `transaction_update`:
|
|
1442
|
-
ingestTransactionUpdate(applying, updateFromTransaction, store);
|
|
1443
|
-
break;
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
}
|
|
1447
|
-
|
|
1448
|
-
// internal/src/transaction/set-epoch-number.ts
|
|
1449
|
-
function setEpochNumberOfContinuity(continuityKey, newEpoch, store) {
|
|
1450
|
-
const isRoot = isRootStore(store);
|
|
1451
|
-
if (isRoot && continuityKey) {
|
|
1452
|
-
store.transactionMeta.epoch.set(continuityKey, newEpoch);
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
function setEpochNumberOfAction(transactionKey, newEpoch, store) {
|
|
1456
|
-
const isRoot = isRootStore(store);
|
|
1457
|
-
if (!isRoot) {
|
|
1458
|
-
return;
|
|
1459
|
-
}
|
|
1460
|
-
const continuityKey = store.transactionMeta.actionContinuities.getRelatedKey(transactionKey);
|
|
1461
|
-
if (continuityKey !== void 0) {
|
|
1462
|
-
store.transactionMeta.epoch.set(continuityKey, newEpoch);
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
|
|
1466
|
-
// internal/src/transaction/apply-transaction.ts
|
|
1467
|
-
var applyTransaction = (output, store) => {
|
|
1468
|
-
const child = newest(store);
|
|
1469
|
-
const { parent } = child;
|
|
1470
|
-
if (parent === null || !isChildStore(child) || child.transactionMeta?.phase !== `building`) {
|
|
1471
|
-
store.logger.warn(
|
|
1472
|
-
`\u{1F41E}`,
|
|
1473
|
-
`transaction`,
|
|
1474
|
-
`???`,
|
|
1475
|
-
`applyTransaction called outside of a transaction. This is probably a bug in AtomIO.`
|
|
1476
|
-
);
|
|
1477
|
-
return;
|
|
1478
|
-
}
|
|
1479
|
-
child.transactionMeta.phase = `applying`;
|
|
1480
|
-
child.transactionMeta.update.output = output;
|
|
1481
|
-
parent.child = null;
|
|
1482
|
-
parent.on.transactionApplying.next(child.transactionMeta);
|
|
1483
|
-
const { updates } = child.transactionMeta.update;
|
|
1484
|
-
store.logger.info(
|
|
1485
|
-
`\u{1F6C4}`,
|
|
1486
|
-
`transaction`,
|
|
1487
|
-
child.transactionMeta.update.key,
|
|
1488
|
-
`Applying transaction with ${updates.length} updates:`,
|
|
1489
|
-
updates
|
|
1490
|
-
);
|
|
1491
|
-
ingestTransactionUpdate(`newValue`, child.transactionMeta.update, parent);
|
|
1492
|
-
if (isRootStore(parent)) {
|
|
1493
|
-
setEpochNumberOfAction(
|
|
1494
|
-
child.transactionMeta.update.key,
|
|
1495
|
-
child.transactionMeta.update.epoch,
|
|
1496
|
-
parent
|
|
1497
|
-
);
|
|
1498
|
-
const myTransaction = withdraw(
|
|
1499
|
-
{ key: child.transactionMeta.update.key, type: `transaction` },
|
|
1500
|
-
store
|
|
1501
|
-
);
|
|
1502
|
-
myTransaction?.subject.next(child.transactionMeta.update);
|
|
1503
|
-
store.logger.info(
|
|
1504
|
-
`\u{1F6EC}`,
|
|
1505
|
-
`transaction`,
|
|
1506
|
-
child.transactionMeta.update.key,
|
|
1507
|
-
`Finished applying transaction.`
|
|
1508
|
-
);
|
|
1509
|
-
} else if (isChildStore(parent)) {
|
|
1510
|
-
parent.transactionMeta.update.updates.push(child.transactionMeta.update);
|
|
1511
|
-
}
|
|
1512
|
-
parent.on.transactionApplying.next(null);
|
|
1513
|
-
};
|
|
1514
|
-
|
|
1515
|
-
// internal/src/transaction/assign-transaction-to-continuity.ts
|
|
1516
|
-
function assignTransactionToContinuity(continuityKey, transactionKey, store) {
|
|
1517
|
-
const isRoot = isRootStore(store);
|
|
1518
|
-
if (!isRoot) {
|
|
1519
|
-
return;
|
|
1520
|
-
}
|
|
1521
|
-
const { epoch, actionContinuities } = store.transactionMeta;
|
|
1522
|
-
actionContinuities.set(continuityKey, transactionKey);
|
|
1523
|
-
if (!epoch.has(continuityKey)) {
|
|
1524
|
-
epoch.set(continuityKey, -1);
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1527
|
-
|
|
1528
|
-
// internal/src/lazy-map.ts
|
|
1529
|
-
var LazyMap = class extends Map {
|
|
1530
|
-
constructor(source) {
|
|
1531
|
-
super();
|
|
1532
|
-
this.source = source;
|
|
1533
|
-
}
|
|
1534
|
-
deleted = /* @__PURE__ */ new Set();
|
|
1535
|
-
get(key) {
|
|
1536
|
-
const has = super.has(key);
|
|
1537
|
-
if (has) {
|
|
1538
|
-
return super.get(key);
|
|
1539
|
-
}
|
|
1540
|
-
if (!this.deleted.has(key) && this.source.has(key)) {
|
|
1541
|
-
const value = this.source.get(key);
|
|
1542
|
-
return value;
|
|
1543
|
-
}
|
|
1544
|
-
return void 0;
|
|
1545
|
-
}
|
|
1546
|
-
set(key, value) {
|
|
1547
|
-
this.deleted.delete(key);
|
|
1548
|
-
return super.set(key, value);
|
|
1549
|
-
}
|
|
1550
|
-
hasOwn(key) {
|
|
1551
|
-
return super.has(key);
|
|
1552
|
-
}
|
|
1553
|
-
has(key) {
|
|
1554
|
-
return !this.deleted.has(key) && (super.has(key) || this.source.has(key));
|
|
1555
|
-
}
|
|
1556
|
-
delete(key) {
|
|
1557
|
-
this.deleted.add(key);
|
|
1558
|
-
return super.delete(key);
|
|
1559
|
-
}
|
|
1560
|
-
};
|
|
1561
|
-
|
|
1562
|
-
// internal/src/transaction/build-transaction.ts
|
|
1563
|
-
var buildTransaction = (key, params, store, id) => {
|
|
1564
|
-
const parent = newest(store);
|
|
1565
|
-
const childBase = {
|
|
1566
|
-
parent,
|
|
1567
|
-
child: null,
|
|
1568
|
-
on: parent.on,
|
|
1569
|
-
loggers: parent.loggers,
|
|
1570
|
-
logger: parent.logger,
|
|
1571
|
-
config: parent.config,
|
|
1572
|
-
atoms: new LazyMap(parent.atoms),
|
|
1573
|
-
atomsThatAreDefault: new Set(parent.atomsThatAreDefault),
|
|
1574
|
-
families: new LazyMap(parent.families),
|
|
1575
|
-
operation: { open: false },
|
|
1576
|
-
readonlySelectors: new LazyMap(parent.readonlySelectors),
|
|
1577
|
-
timelines: new LazyMap(parent.timelines),
|
|
1578
|
-
timelineTopics: new Junction(parent.timelineTopics.toJSON()),
|
|
1579
|
-
trackers: /* @__PURE__ */ new Map(),
|
|
1580
|
-
transactions: new LazyMap(parent.transactions),
|
|
1581
|
-
selectorAtoms: new Junction(parent.selectorAtoms.toJSON()),
|
|
1582
|
-
selectorGraph: new Junction(parent.selectorGraph.toJSON(), {
|
|
1583
|
-
makeContentKey: (...keys) => keys.sort().join(`:`)
|
|
1584
|
-
}),
|
|
1585
|
-
selectors: new LazyMap(parent.selectors),
|
|
1586
|
-
valueMap: new LazyMap(parent.valueMap),
|
|
1587
|
-
molecules: new LazyMap(parent.molecules),
|
|
1588
|
-
moleculeFamilies: new LazyMap(parent.moleculeFamilies),
|
|
1589
|
-
moleculeInProgress: parent.moleculeInProgress,
|
|
1590
|
-
miscResources: new LazyMap(parent.miscResources)
|
|
1591
|
-
};
|
|
1592
|
-
const epoch = getEpochNumberOfAction(key, store);
|
|
1593
|
-
const transactionMeta = {
|
|
1594
|
-
phase: `building`,
|
|
1595
|
-
update: {
|
|
1596
|
-
type: `transaction_update`,
|
|
1597
|
-
key,
|
|
1598
|
-
id,
|
|
1599
|
-
epoch: epoch === void 0 ? Number.NaN : epoch + 1,
|
|
1600
|
-
updates: [],
|
|
1601
|
-
params,
|
|
1602
|
-
output: void 0
|
|
1603
|
-
},
|
|
1604
|
-
toolkit: {
|
|
1605
|
-
get: (...ps) => getFromStore(...ps, child),
|
|
1606
|
-
set: (...ps) => {
|
|
1607
|
-
setIntoStore(...ps, child);
|
|
1608
|
-
},
|
|
1609
|
-
run: (token, identifier = arbitrary()) => actUponStore(token, identifier, child),
|
|
1610
|
-
find: (token, k) => findInStore(token, k, child),
|
|
1611
|
-
seek: (token, k) => seekInStore(token, k, child),
|
|
1612
|
-
json: (token) => getJsonToken(token, child),
|
|
1613
|
-
make: (context, family, k, ...args) => makeMoleculeInStore(child, context, family, k, ...args),
|
|
1614
|
-
dispose: (...ps) => {
|
|
1615
|
-
disposeFromStore(...ps, child);
|
|
1616
|
-
},
|
|
1617
|
-
env: () => getEnvironmentData(child)
|
|
1618
|
-
}
|
|
1619
|
-
};
|
|
1620
|
-
const child = Object.assign(childBase, {
|
|
1621
|
-
transactionMeta
|
|
1622
|
-
});
|
|
1623
|
-
parent.child = child;
|
|
1624
|
-
store.logger.info(
|
|
1625
|
-
`\u{1F6EB}`,
|
|
1626
|
-
`transaction`,
|
|
1627
|
-
key,
|
|
1628
|
-
`Building transaction with params:`,
|
|
1629
|
-
params
|
|
1630
|
-
);
|
|
1631
|
-
return child;
|
|
1632
|
-
};
|
|
1633
|
-
|
|
1634
|
-
// internal/src/transaction/create-transaction.ts
|
|
1635
|
-
function createTransaction(options, store) {
|
|
1636
|
-
const newTransaction = {
|
|
1637
|
-
key: options.key,
|
|
1638
|
-
type: `transaction`,
|
|
1639
|
-
run: (params, id) => {
|
|
1640
|
-
const childStore = buildTransaction(options.key, params, store, id);
|
|
1641
|
-
try {
|
|
1642
|
-
const target2 = newest(store);
|
|
1643
|
-
const { toolkit } = childStore.transactionMeta;
|
|
1644
|
-
const output = options.do(toolkit, ...params);
|
|
1645
|
-
applyTransaction(output, target2);
|
|
1646
|
-
return output;
|
|
1647
|
-
} catch (thrown) {
|
|
1648
|
-
abortTransaction(target);
|
|
1649
|
-
store.logger.warn(`\u{1F4A5}`, `transaction`, options.key, `caught:`, thrown);
|
|
1650
|
-
throw thrown;
|
|
1651
|
-
}
|
|
1652
|
-
},
|
|
1653
|
-
install: (s) => createTransaction(options, s),
|
|
1654
|
-
subject: new Subject()
|
|
1655
|
-
};
|
|
1656
|
-
const target = newest(store);
|
|
1657
|
-
target.transactions.set(newTransaction.key, newTransaction);
|
|
1658
|
-
const token = deposit(newTransaction);
|
|
1659
|
-
store.on.transactionCreation.next(token);
|
|
1660
|
-
return token;
|
|
1661
|
-
}
|
|
1662
|
-
|
|
1663
|
-
// internal/src/transaction/get-epoch-number.ts
|
|
1664
|
-
function getContinuityKey(transactionKey, store) {
|
|
1665
|
-
const isRoot = isRootStore(store);
|
|
1666
|
-
const continuity = isRoot ? store.transactionMeta.actionContinuities.getRelatedKey(transactionKey) : void 0;
|
|
1667
|
-
return continuity;
|
|
1668
|
-
}
|
|
1669
|
-
function getEpochNumberOfContinuity(continuityKey, store) {
|
|
1670
|
-
const isRoot = isRootStore(store);
|
|
1671
|
-
const epoch = isRoot && continuityKey ? store.transactionMeta.epoch.get(continuityKey) : void 0;
|
|
1672
|
-
return epoch;
|
|
1673
|
-
}
|
|
1674
|
-
function getEpochNumberOfAction(transactionKey, store) {
|
|
1675
|
-
const isRoot = isRootStore(store);
|
|
1676
|
-
const continuity = isRoot ? store.transactionMeta.actionContinuities.getRelatedKey(transactionKey) : void 0;
|
|
1677
|
-
const epoch = isRoot && continuity !== void 0 ? store.transactionMeta.epoch.get(continuity) : void 0;
|
|
1678
|
-
return epoch;
|
|
1679
|
-
}
|
|
1680
|
-
|
|
1681
|
-
// internal/src/transaction/index.ts
|
|
1682
|
-
var TRANSACTION_PHASES = [`idle`, `building`, `applying`];
|
|
1683
|
-
|
|
1684
|
-
// internal/src/store/store.ts
|
|
1685
|
-
var Store = class {
|
|
1686
|
-
parent = null;
|
|
1687
|
-
child = null;
|
|
1688
|
-
valueMap = /* @__PURE__ */ new Map();
|
|
1689
|
-
atoms = /* @__PURE__ */ new Map();
|
|
1690
|
-
selectors = /* @__PURE__ */ new Map();
|
|
1691
|
-
readonlySelectors = /* @__PURE__ */ new Map();
|
|
1692
|
-
atomsThatAreDefault = /* @__PURE__ */ new Set();
|
|
1693
|
-
selectorAtoms = new Junction({
|
|
1694
|
-
between: [`selectorKey`, `atomKey`],
|
|
1695
|
-
cardinality: `n:n`
|
|
1696
|
-
});
|
|
1697
|
-
selectorGraph = new Junction(
|
|
1698
|
-
{
|
|
1699
|
-
between: [`upstreamSelectorKey`, `downstreamSelectorKey`],
|
|
1700
|
-
cardinality: `n:n`
|
|
1701
|
-
},
|
|
1702
|
-
{
|
|
1703
|
-
makeContentKey: (...keys) => keys.sort().join(`:`)
|
|
1704
|
-
}
|
|
1705
|
-
);
|
|
1706
|
-
trackers = /* @__PURE__ */ new Map();
|
|
1707
|
-
families = /* @__PURE__ */ new Map();
|
|
1708
|
-
transactions = /* @__PURE__ */ new Map();
|
|
1709
|
-
transactionMeta = {
|
|
1710
|
-
epoch: /* @__PURE__ */ new Map(),
|
|
1711
|
-
actionContinuities: new Junction({
|
|
1712
|
-
between: [`continuity`, `action`],
|
|
1713
|
-
cardinality: `1:n`
|
|
1714
|
-
})
|
|
1715
|
-
};
|
|
1716
|
-
timelines = /* @__PURE__ */ new Map();
|
|
1717
|
-
timelineTopics = new Junction({
|
|
1718
|
-
between: [`timelineKey`, `topicKey`],
|
|
1719
|
-
cardinality: `1:n`
|
|
1720
|
-
});
|
|
1721
|
-
molecules = /* @__PURE__ */ new Map();
|
|
1722
|
-
moleculeFamilies = /* @__PURE__ */ new Map();
|
|
1723
|
-
moleculeInProgress = null;
|
|
1724
|
-
miscResources = /* @__PURE__ */ new Map();
|
|
1725
|
-
on = {
|
|
1726
|
-
atomCreation: new Subject(),
|
|
1727
|
-
atomDisposal: new Subject(),
|
|
1728
|
-
selectorCreation: new Subject(),
|
|
1729
|
-
selectorDisposal: new Subject(),
|
|
1730
|
-
timelineCreation: new Subject(),
|
|
1731
|
-
transactionCreation: new Subject(),
|
|
1732
|
-
transactionApplying: new StatefulSubject(
|
|
1733
|
-
null
|
|
1734
|
-
),
|
|
1735
|
-
operationClose: new Subject(),
|
|
1736
|
-
moleculeCreationStart: new Subject(),
|
|
1737
|
-
moleculeCreationDone: new Subject(),
|
|
1738
|
-
moleculeDisposal: new Subject()
|
|
1739
|
-
};
|
|
1740
|
-
operation = { open: false };
|
|
1741
|
-
config = {
|
|
1742
|
-
name: `IMPLICIT_STORE`,
|
|
1743
|
-
lifespan: `ephemeral`
|
|
1744
|
-
};
|
|
1745
|
-
loggers = [
|
|
1746
|
-
new AtomIOLogger(`warn`, (_, __, key) => !key.includes(`\u{1F441}\u200D\u{1F5E8}`))
|
|
1747
|
-
];
|
|
1748
|
-
logger = {
|
|
1749
|
-
error: (...messages) => {
|
|
1750
|
-
for (const logger of this.loggers) logger.error(...messages);
|
|
1751
|
-
},
|
|
1752
|
-
info: (...messages) => {
|
|
1753
|
-
for (const logger of this.loggers) logger.info(...messages);
|
|
1754
|
-
},
|
|
1755
|
-
warn: (...messages) => {
|
|
1756
|
-
for (const logger of this.loggers) logger.warn(...messages);
|
|
1757
|
-
}
|
|
1758
|
-
};
|
|
1759
|
-
constructor(config, store = null) {
|
|
1760
|
-
this.config = {
|
|
1761
|
-
...store?.config,
|
|
1762
|
-
...config
|
|
1763
|
-
};
|
|
1764
|
-
if (store !== null) {
|
|
1765
|
-
this.valueMap = new Map(store?.valueMap);
|
|
1766
|
-
this.operation = { ...store?.operation };
|
|
1767
|
-
if (isRootStore(store)) {
|
|
1768
|
-
this.transactionMeta = {
|
|
1769
|
-
epoch: new Map(store?.transactionMeta.epoch),
|
|
1770
|
-
actionContinuities: new Junction(
|
|
1771
|
-
store?.transactionMeta.actionContinuities.toJSON()
|
|
1772
|
-
)
|
|
1773
|
-
};
|
|
1774
|
-
}
|
|
1775
|
-
for (const [, family] of store.families) {
|
|
1776
|
-
family.install(this);
|
|
1777
|
-
}
|
|
1778
|
-
const mutableHelpers = /* @__PURE__ */ new Set();
|
|
1779
|
-
for (const [, atom] of store.atoms) {
|
|
1780
|
-
if (mutableHelpers.has(atom.key)) {
|
|
1781
|
-
continue;
|
|
1782
|
-
}
|
|
1783
|
-
atom.install(this);
|
|
1784
|
-
if (atom.type === `mutable_atom`) {
|
|
1785
|
-
const originalJsonToken = getJsonToken(atom, store);
|
|
1786
|
-
const originalUpdateToken = getUpdateToken(atom);
|
|
1787
|
-
mutableHelpers.add(originalJsonToken.key);
|
|
1788
|
-
mutableHelpers.add(originalUpdateToken.key);
|
|
1789
|
-
}
|
|
1790
|
-
}
|
|
1791
|
-
for (const [, selector] of store.readonlySelectors) {
|
|
1792
|
-
selector.install(this);
|
|
1793
|
-
}
|
|
1794
|
-
for (const [, selector] of store.selectors) {
|
|
1795
|
-
if (mutableHelpers.has(selector.key)) {
|
|
1796
|
-
continue;
|
|
1797
|
-
}
|
|
1798
|
-
selector.install(this);
|
|
1799
|
-
}
|
|
1800
|
-
for (const [, tx] of store.transactions) {
|
|
1801
|
-
tx.install(this);
|
|
1802
|
-
}
|
|
1803
|
-
for (const [, timeline] of store.timelines) {
|
|
1804
|
-
timeline.install(this);
|
|
1805
|
-
}
|
|
1806
|
-
}
|
|
1807
|
-
}
|
|
1808
|
-
};
|
|
1809
|
-
var IMPLICIT = {
|
|
1810
|
-
get STORE() {
|
|
1811
|
-
if (!globalThis.ATOM_IO_IMPLICIT_STORE) {
|
|
1812
|
-
globalThis.ATOM_IO_IMPLICIT_STORE = new Store({
|
|
1813
|
-
name: `IMPLICIT_STORE`,
|
|
1814
|
-
lifespan: `ephemeral`
|
|
1815
|
-
});
|
|
1816
|
-
}
|
|
1817
|
-
return globalThis.ATOM_IO_IMPLICIT_STORE;
|
|
1818
|
-
}
|
|
1819
|
-
};
|
|
1820
|
-
var clearStore = (store) => {
|
|
1821
|
-
const { config } = store;
|
|
1822
|
-
for (const disposable of store.miscResources.values()) {
|
|
1823
|
-
disposable[Symbol.dispose]();
|
|
1824
|
-
}
|
|
1825
|
-
Object.assign(store, new Store(config));
|
|
1826
|
-
store.config = config;
|
|
1827
|
-
};
|
|
1828
|
-
function withdraw(token, store) {
|
|
1829
|
-
let withdrawn;
|
|
1830
|
-
let target = store;
|
|
1831
|
-
while (target !== null) {
|
|
1832
|
-
switch (token.type) {
|
|
1833
|
-
case `atom`:
|
|
1834
|
-
case `mutable_atom`:
|
|
1835
|
-
withdrawn = target.atoms.get(token.key);
|
|
1836
|
-
break;
|
|
1837
|
-
case `selector`:
|
|
1838
|
-
withdrawn = target.selectors.get(token.key);
|
|
1839
|
-
break;
|
|
1840
|
-
case `readonly_selector`:
|
|
1841
|
-
withdrawn = target.readonlySelectors.get(token.key);
|
|
1842
|
-
break;
|
|
1843
|
-
case `atom_family`:
|
|
1844
|
-
case `mutable_atom_family`:
|
|
1845
|
-
case `selector_family`:
|
|
1846
|
-
case `readonly_selector_family`:
|
|
1847
|
-
withdrawn = target.families.get(token.key);
|
|
1848
|
-
break;
|
|
1849
|
-
case `timeline`:
|
|
1850
|
-
withdrawn = target.timelines.get(token.key);
|
|
1851
|
-
break;
|
|
1852
|
-
case `transaction`:
|
|
1853
|
-
withdrawn = target.transactions.get(token.key);
|
|
1854
|
-
break;
|
|
1855
|
-
case `molecule`:
|
|
1856
|
-
withdrawn = target.molecules.get(stringifyJson(token.key));
|
|
1857
|
-
break;
|
|
1858
|
-
case `molecule_family`:
|
|
1859
|
-
withdrawn = target.moleculeFamilies.get(token.key);
|
|
1860
|
-
break;
|
|
1861
|
-
}
|
|
1862
|
-
if (withdrawn) {
|
|
1863
|
-
return withdrawn;
|
|
1864
|
-
}
|
|
1865
|
-
target = target.child;
|
|
1866
|
-
}
|
|
1867
|
-
throw new NotFoundError(token, store);
|
|
1868
|
-
}
|
|
1869
|
-
|
|
1870
|
-
// internal/src/subscribe/recall-state.ts
|
|
1871
|
-
var recallState = (state, store) => {
|
|
1872
|
-
const target = newest(store);
|
|
1873
|
-
if (target.operation.open) {
|
|
1874
|
-
return target.operation.prev.get(state.key);
|
|
1875
|
-
}
|
|
1876
|
-
return target.valueMap.get(state.key);
|
|
1877
|
-
};
|
|
1878
|
-
|
|
1879
|
-
// internal/src/subscribe/subscribe-to-root-atoms.ts
|
|
1880
|
-
var subscribeToRootAtoms = (selector, store) => {
|
|
1881
|
-
const target = newest(store);
|
|
1882
|
-
const dependencySubscriptions = traceAllSelectorAtoms(selector, store).map(
|
|
1883
|
-
(atomKey) => {
|
|
1884
|
-
const atom = target.atoms.get(atomKey);
|
|
1885
|
-
if (atom === void 0) {
|
|
1886
|
-
throw new Error(
|
|
1887
|
-
`Atom "${atomKey}", a dependency of selector "${selector.key}", not found in store "${store.config.name}".`
|
|
1888
|
-
);
|
|
1889
|
-
}
|
|
1890
|
-
return atom.subject.subscribe(
|
|
1891
|
-
`${selector.type}:${selector.key}`,
|
|
1892
|
-
(atomChange) => {
|
|
1893
|
-
store.logger.info(
|
|
1894
|
-
`\u{1F4E2}`,
|
|
1895
|
-
selector.type,
|
|
1896
|
-
selector.key,
|
|
1897
|
-
`root`,
|
|
1898
|
-
atomKey,
|
|
1899
|
-
`went`,
|
|
1900
|
-
atomChange.oldValue,
|
|
1901
|
-
`->`,
|
|
1902
|
-
atomChange.newValue
|
|
1903
|
-
);
|
|
1904
|
-
const oldValue = recallState(selector, target);
|
|
1905
|
-
const newValue = readOrComputeValue(selector, target);
|
|
1906
|
-
store.logger.info(
|
|
1907
|
-
`\u2728`,
|
|
1908
|
-
selector.type,
|
|
1909
|
-
selector.key,
|
|
1910
|
-
`went`,
|
|
1911
|
-
oldValue,
|
|
1912
|
-
`->`,
|
|
1913
|
-
newValue
|
|
1914
|
-
);
|
|
1915
|
-
selector.subject.next({ newValue, oldValue });
|
|
1916
|
-
}
|
|
1917
|
-
);
|
|
1918
|
-
}
|
|
1919
|
-
);
|
|
1920
|
-
return dependencySubscriptions;
|
|
1921
|
-
};
|
|
1922
|
-
|
|
1923
|
-
// internal/src/subscribe/subscribe-to-state.ts
|
|
1924
|
-
function subscribeToState(token, handleUpdate, key, store) {
|
|
1925
|
-
function safelyHandleUpdate(update) {
|
|
1926
|
-
if (store.operation.open) {
|
|
1927
|
-
const unsubscribe2 = store.on.operationClose.subscribe(
|
|
1928
|
-
`state subscription ${key}`,
|
|
1929
|
-
() => {
|
|
1930
|
-
unsubscribe2();
|
|
1931
|
-
handleUpdate(update);
|
|
1932
|
-
}
|
|
1933
|
-
);
|
|
1934
|
-
} else {
|
|
1935
|
-
handleUpdate(update);
|
|
1936
|
-
}
|
|
1937
|
-
}
|
|
1938
|
-
const state = withdraw(token, store);
|
|
1939
|
-
store.logger.info(`\u{1F440}`, state.type, state.key, `Adding subscription "${key}"`);
|
|
1940
|
-
const isSelector = state.type === `selector` || state.type === `readonly_selector`;
|
|
1941
|
-
let dependencyUnsubFunctions = null;
|
|
1942
|
-
let updateHandler = safelyHandleUpdate;
|
|
1943
|
-
if (isSelector) {
|
|
1944
|
-
dependencyUnsubFunctions = subscribeToRootAtoms(state, store);
|
|
1945
|
-
updateHandler = (update) => {
|
|
1946
|
-
if (dependencyUnsubFunctions) {
|
|
1947
|
-
dependencyUnsubFunctions.length = 0;
|
|
1948
|
-
dependencyUnsubFunctions.push(...subscribeToRootAtoms(state, store));
|
|
1949
|
-
}
|
|
1950
|
-
safelyHandleUpdate(update);
|
|
1951
|
-
};
|
|
1952
|
-
}
|
|
1953
|
-
const mainUnsubFunction = state.subject.subscribe(key, updateHandler);
|
|
1954
|
-
const unsubscribe = () => {
|
|
1955
|
-
store.logger.info(
|
|
1956
|
-
`\u{1F648}`,
|
|
1957
|
-
state.type,
|
|
1958
|
-
state.key,
|
|
1959
|
-
`Removing subscription "${key}"`
|
|
1960
|
-
);
|
|
1961
|
-
mainUnsubFunction();
|
|
1962
|
-
if (dependencyUnsubFunctions) {
|
|
1963
|
-
for (const unsubFromDependency of dependencyUnsubFunctions) {
|
|
1964
|
-
unsubFromDependency();
|
|
1965
|
-
}
|
|
1966
|
-
}
|
|
1967
|
-
};
|
|
1968
|
-
return unsubscribe;
|
|
1969
|
-
}
|
|
1970
|
-
|
|
1971
|
-
// internal/src/subscribe/subscribe-to-timeline.ts
|
|
1972
|
-
var subscribeToTimeline = (token, handleUpdate, key, store) => {
|
|
1973
|
-
const tl = withdraw(token, store);
|
|
1974
|
-
store.logger.info(`\u{1F440}`, `timeline`, token.key, `Adding subscription "${key}"`);
|
|
1975
|
-
const unsubscribe = tl.subject.subscribe(key, handleUpdate);
|
|
1976
|
-
return () => {
|
|
1977
|
-
store.logger.info(
|
|
1978
|
-
`\u{1F648}`,
|
|
1979
|
-
`timeline`,
|
|
1980
|
-
token.key,
|
|
1981
|
-
`Removing subscription "${key}" from timeline`
|
|
1982
|
-
);
|
|
1983
|
-
unsubscribe();
|
|
1984
|
-
};
|
|
1985
|
-
};
|
|
1986
|
-
|
|
1987
|
-
// internal/src/subscribe/subscribe-to-transaction.ts
|
|
1988
|
-
var subscribeToTransaction = (token, handleUpdate, key, store) => {
|
|
1989
|
-
const tx = withdraw(token, store);
|
|
1990
|
-
store.logger.info(
|
|
1991
|
-
`\u{1F440}`,
|
|
1992
|
-
`transaction`,
|
|
1993
|
-
token.key,
|
|
1994
|
-
`Adding subscription "${key}"`
|
|
1995
|
-
);
|
|
1996
|
-
const unsubscribe = tx.subject.subscribe(key, handleUpdate);
|
|
1997
|
-
return () => {
|
|
1998
|
-
store.logger.info(
|
|
1999
|
-
`\u{1F648}`,
|
|
2000
|
-
`transaction`,
|
|
2001
|
-
token.key,
|
|
2002
|
-
`Removing subscription "${key}"`
|
|
2003
|
-
);
|
|
2004
|
-
unsubscribe();
|
|
2005
|
-
};
|
|
2006
|
-
};
|
|
2007
|
-
|
|
2008
|
-
// internal/src/mutable/tracker.ts
|
|
2009
|
-
var Tracker = class {
|
|
2010
|
-
Update;
|
|
2011
|
-
initializeState(mutableState, store) {
|
|
2012
|
-
const latestUpdateStateKey = `*${mutableState.key}`;
|
|
2013
|
-
store.atoms.delete(latestUpdateStateKey);
|
|
2014
|
-
store.valueMap.delete(latestUpdateStateKey);
|
|
2015
|
-
const familyMetaData = mutableState.family ? {
|
|
2016
|
-
key: `*${mutableState.family.key}`,
|
|
2017
|
-
subKey: mutableState.family.subKey
|
|
2018
|
-
} : void 0;
|
|
2019
|
-
const latestUpdateState = createRegularAtom(
|
|
2020
|
-
{
|
|
2021
|
-
key: latestUpdateStateKey,
|
|
2022
|
-
default: null
|
|
2023
|
-
},
|
|
2024
|
-
familyMetaData,
|
|
2025
|
-
store
|
|
2026
|
-
);
|
|
2027
|
-
if (store.parent?.valueMap.has(latestUpdateStateKey)) {
|
|
2028
|
-
const parentValue = store.parent.valueMap.get(latestUpdateStateKey);
|
|
2029
|
-
store.valueMap.set(latestUpdateStateKey, parentValue);
|
|
2030
|
-
}
|
|
2031
|
-
return latestUpdateState;
|
|
2032
|
-
}
|
|
2033
|
-
unsubscribeFromInnerValue;
|
|
2034
|
-
unsubscribeFromState;
|
|
2035
|
-
observeCore(mutableState, latestUpdateState, target) {
|
|
2036
|
-
const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
|
|
2037
|
-
const originalInnerValue = getFromStore(mutableState, target);
|
|
2038
|
-
this.unsubscribeFromInnerValue = originalInnerValue.subscribe(
|
|
2039
|
-
subscriptionKey,
|
|
2040
|
-
(update) => {
|
|
2041
|
-
setIntoStore(latestUpdateState, update, target);
|
|
2042
|
-
}
|
|
2043
|
-
);
|
|
2044
|
-
this.unsubscribeFromState = subscribeToState(
|
|
2045
|
-
mutableState,
|
|
2046
|
-
(update) => {
|
|
2047
|
-
if (update.newValue !== update.oldValue) {
|
|
2048
|
-
this.unsubscribeFromInnerValue();
|
|
2049
|
-
this.unsubscribeFromInnerValue = update.newValue.subscribe(
|
|
2050
|
-
subscriptionKey,
|
|
2051
|
-
(transceiverUpdate) => {
|
|
2052
|
-
setIntoStore(latestUpdateState, transceiverUpdate, target);
|
|
2053
|
-
}
|
|
2054
|
-
);
|
|
2055
|
-
}
|
|
2056
|
-
},
|
|
2057
|
-
subscriptionKey,
|
|
2058
|
-
target
|
|
2059
|
-
);
|
|
2060
|
-
}
|
|
2061
|
-
updateCore(mutableState, latestUpdateState, target) {
|
|
2062
|
-
const subscriptionKey = `tracker:${target.config.name}:${isChildStore(target) ? target.transactionMeta.update.key : `main`}:${mutableState.key}`;
|
|
2063
|
-
subscribeToState(
|
|
2064
|
-
latestUpdateState,
|
|
2065
|
-
({ newValue, oldValue }) => {
|
|
2066
|
-
const timelineId = target.timelineTopics.getRelatedKey(
|
|
2067
|
-
latestUpdateState.key
|
|
2068
|
-
);
|
|
2069
|
-
if (timelineId) {
|
|
2070
|
-
const timelineData = target.timelines.get(timelineId);
|
|
2071
|
-
if (timelineData?.timeTraveling) {
|
|
2072
|
-
const unsubscribe2 = subscribeToTimeline(
|
|
2073
|
-
{ key: timelineId, type: `timeline` },
|
|
2074
|
-
(update) => {
|
|
2075
|
-
unsubscribe2();
|
|
2076
|
-
setIntoStore(
|
|
2077
|
-
mutableState,
|
|
2078
|
-
(transceiver) => {
|
|
2079
|
-
if (update === `redo` && newValue) {
|
|
2080
|
-
transceiver.do(newValue);
|
|
2081
|
-
} else if (update === `undo` && oldValue) {
|
|
2082
|
-
transceiver.undo(oldValue);
|
|
2083
|
-
}
|
|
2084
|
-
return transceiver;
|
|
2085
|
-
},
|
|
2086
|
-
target
|
|
2087
|
-
);
|
|
2088
|
-
},
|
|
2089
|
-
subscriptionKey,
|
|
2090
|
-
target
|
|
2091
|
-
);
|
|
2092
|
-
return;
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
const unsubscribe = target.on.operationClose.subscribe(
|
|
2096
|
-
subscriptionKey,
|
|
2097
|
-
() => {
|
|
2098
|
-
unsubscribe();
|
|
2099
|
-
const mutable = getFromStore(mutableState, target);
|
|
2100
|
-
const updateNumber = newValue === null ? -1 : mutable.getUpdateNumber(newValue);
|
|
2101
|
-
const eventOffset = updateNumber - mutable.cacheUpdateNumber;
|
|
2102
|
-
if (newValue && eventOffset === 1) {
|
|
2103
|
-
setIntoStore(
|
|
2104
|
-
mutableState,
|
|
2105
|
-
(transceiver) => (transceiver.do(newValue), transceiver),
|
|
2106
|
-
target
|
|
2107
|
-
);
|
|
2108
|
-
} else {
|
|
2109
|
-
target.logger.info(
|
|
2110
|
-
`\u274C`,
|
|
2111
|
-
`mutable_atom`,
|
|
2112
|
-
mutableState.key,
|
|
2113
|
-
`could not be updated. Expected update number ${mutable.cacheUpdateNumber + 1}, but got ${updateNumber}`
|
|
2114
|
-
);
|
|
2115
|
-
}
|
|
2116
|
-
}
|
|
2117
|
-
);
|
|
2118
|
-
},
|
|
2119
|
-
subscriptionKey,
|
|
2120
|
-
target
|
|
2121
|
-
);
|
|
2122
|
-
}
|
|
2123
|
-
mutableState;
|
|
2124
|
-
latestUpdateState;
|
|
2125
|
-
dispose;
|
|
2126
|
-
constructor(mutableState, store) {
|
|
2127
|
-
this.mutableState = mutableState;
|
|
2128
|
-
const target = newest(store);
|
|
2129
|
-
this.latestUpdateState = this.initializeState(mutableState, target);
|
|
2130
|
-
this.observeCore(mutableState, this.latestUpdateState, target);
|
|
2131
|
-
this.updateCore(mutableState, this.latestUpdateState, target);
|
|
2132
|
-
target.trackers.set(mutableState.key, this);
|
|
2133
|
-
this.dispose = () => {
|
|
2134
|
-
this.unsubscribeFromInnerValue();
|
|
2135
|
-
this.unsubscribeFromState();
|
|
2136
|
-
target.trackers.delete(mutableState.key);
|
|
2137
|
-
};
|
|
2138
|
-
}
|
|
2139
|
-
};
|
|
2140
|
-
|
|
2141
|
-
// internal/src/mutable/create-mutable-atom.ts
|
|
2142
|
-
function createMutableAtom(options, family, store) {
|
|
2143
|
-
store.logger.info(
|
|
2144
|
-
`\u{1F528}`,
|
|
2145
|
-
`atom`,
|
|
2146
|
-
options.key,
|
|
2147
|
-
`creating in store "${store.config.name}"`
|
|
2148
|
-
);
|
|
2149
|
-
const target = newest(store);
|
|
2150
|
-
const existing = target.atoms.get(options.key);
|
|
2151
|
-
if (existing && existing.type === `mutable_atom`) {
|
|
2152
|
-
store.logger.error(
|
|
2153
|
-
`\u274C`,
|
|
2154
|
-
`atom`,
|
|
2155
|
-
options.key,
|
|
2156
|
-
`Tried to create atom, but it already exists in the store.`
|
|
2157
|
-
);
|
|
2158
|
-
return deposit(existing);
|
|
2159
|
-
}
|
|
2160
|
-
const subject = new Subject();
|
|
2161
|
-
const newAtom = {
|
|
2162
|
-
...options,
|
|
2163
|
-
type: `mutable_atom`,
|
|
2164
|
-
install: (s) => {
|
|
2165
|
-
s.logger.info(
|
|
2166
|
-
`\u{1F6E0}\uFE0F`,
|
|
2167
|
-
`atom`,
|
|
2168
|
-
options.key,
|
|
2169
|
-
`installing in store "${s.config.name}"`
|
|
2170
|
-
);
|
|
2171
|
-
return createMutableAtom(options, family, s);
|
|
2172
|
-
},
|
|
2173
|
-
subject
|
|
2174
|
-
};
|
|
2175
|
-
if (family) {
|
|
2176
|
-
newAtom.family = family;
|
|
2177
|
-
}
|
|
2178
|
-
const initialValue = options.default();
|
|
2179
|
-
target.atoms.set(newAtom.key, newAtom);
|
|
2180
|
-
markAtomAsDefault(options.key, store);
|
|
2181
|
-
cacheValue(options.key, initialValue, subject, target);
|
|
2182
|
-
const token = deposit(newAtom);
|
|
2183
|
-
if (options.effects) {
|
|
2184
|
-
let effectIndex = 0;
|
|
2185
|
-
const cleanupFunctions = [];
|
|
2186
|
-
for (const effect of options.effects) {
|
|
2187
|
-
const cleanup = effect({
|
|
2188
|
-
setSelf: (next) => {
|
|
2189
|
-
setIntoStore(token, next, store);
|
|
2190
|
-
},
|
|
2191
|
-
onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
|
|
2192
|
-
});
|
|
2193
|
-
if (cleanup) {
|
|
2194
|
-
cleanupFunctions.push(cleanup);
|
|
2195
|
-
}
|
|
2196
|
-
++effectIndex;
|
|
2197
|
-
}
|
|
2198
|
-
newAtom.cleanup = () => {
|
|
2199
|
-
for (const cleanup of cleanupFunctions) {
|
|
2200
|
-
cleanup();
|
|
2201
|
-
}
|
|
2202
|
-
};
|
|
2203
|
-
}
|
|
2204
|
-
new Tracker(token, store);
|
|
2205
|
-
if (!family) {
|
|
2206
|
-
selectJson(token, options, store);
|
|
2207
|
-
}
|
|
2208
|
-
return token;
|
|
2209
|
-
}
|
|
2210
|
-
var FamilyTracker = class {
|
|
2211
|
-
Update;
|
|
2212
|
-
latestUpdateAtoms;
|
|
2213
|
-
mutableAtoms;
|
|
2214
|
-
constructor(mutableAtoms, store) {
|
|
2215
|
-
this.latestUpdateAtoms = createRegularAtomFamily(
|
|
2216
|
-
{
|
|
2217
|
-
key: `*${mutableAtoms.key}`,
|
|
2218
|
-
default: null
|
|
2219
|
-
},
|
|
2220
|
-
store
|
|
2221
|
-
);
|
|
2222
|
-
this.mutableAtoms = mutableAtoms;
|
|
2223
|
-
this.mutableAtoms.subject.subscribe(
|
|
2224
|
-
`store=${store.config.name}::tracker-atom-family`,
|
|
2225
|
-
(event) => {
|
|
2226
|
-
if (event.token.family) {
|
|
2227
|
-
const key = parseJson(event.token.family.subKey);
|
|
2228
|
-
seekInStore(this.latestUpdateAtoms, key, store);
|
|
2229
|
-
new Tracker(event.token, store);
|
|
2230
|
-
}
|
|
2231
|
-
}
|
|
2232
|
-
);
|
|
2233
|
-
this.latestUpdateAtoms.subject.subscribe(
|
|
2234
|
-
`store=${store.config.name}::tracker-atom-family`,
|
|
2235
|
-
(event) => {
|
|
2236
|
-
if (event.token.family) {
|
|
2237
|
-
const key = parseJson(event.token.family.subKey);
|
|
2238
|
-
const mutableAtomToken = seekInStore(this.mutableAtoms, key, store);
|
|
2239
|
-
if (mutableAtomToken) {
|
|
2240
|
-
new Tracker(mutableAtomToken, store);
|
|
2241
|
-
}
|
|
2242
|
-
}
|
|
2243
|
-
}
|
|
2244
|
-
);
|
|
2245
|
-
}
|
|
2246
|
-
};
|
|
2247
|
-
|
|
2248
|
-
// internal/src/mutable/create-mutable-atom-family.ts
|
|
2249
|
-
function createMutableAtomFamily(options, store) {
|
|
2250
|
-
const subject = new Subject();
|
|
2251
|
-
const atomFamily = Object.assign(
|
|
2252
|
-
(key) => {
|
|
2253
|
-
const subKey = stringifyJson(key);
|
|
2254
|
-
const family = { key: options.key, subKey };
|
|
2255
|
-
const fullKey = `${options.key}(${subKey})`;
|
|
2256
|
-
const target = newest(store);
|
|
2257
|
-
const individualOptions = {
|
|
2258
|
-
key: fullKey,
|
|
2259
|
-
default: () => options.default(key),
|
|
2260
|
-
toJson: options.toJson,
|
|
2261
|
-
fromJson: options.fromJson,
|
|
2262
|
-
mutable: true
|
|
2263
|
-
};
|
|
2264
|
-
if (options.effects) {
|
|
2265
|
-
individualOptions.effects = options.effects(key);
|
|
2266
|
-
}
|
|
2267
|
-
const token = createMutableAtom(individualOptions, family, target);
|
|
2268
|
-
subject.next({ type: `state_creation`, token });
|
|
2269
|
-
return token;
|
|
2270
|
-
},
|
|
2271
|
-
{
|
|
2272
|
-
key: options.key,
|
|
2273
|
-
type: `mutable_atom_family`,
|
|
2274
|
-
subject,
|
|
2275
|
-
install: (s) => createMutableAtomFamily(options, s),
|
|
2276
|
-
toJson: options.toJson,
|
|
2277
|
-
fromJson: options.fromJson
|
|
2278
|
-
}
|
|
2279
|
-
);
|
|
2280
|
-
store.families.set(options.key, atomFamily);
|
|
2281
|
-
selectJsonFamily(atomFamily, options, store);
|
|
2282
|
-
new FamilyTracker(atomFamily, store);
|
|
2283
|
-
return atomFamily;
|
|
2284
|
-
}
|
|
2285
|
-
|
|
2286
|
-
// internal/src/mutable/get-json-family.ts
|
|
2287
|
-
var getJsonFamily = (mutableAtomFamily, store) => {
|
|
2288
|
-
const target = newest(store);
|
|
2289
|
-
const key = `${mutableAtomFamily.key}:JSON`;
|
|
2290
|
-
const jsonFamily = target.families.get(key);
|
|
2291
|
-
return jsonFamily;
|
|
2292
|
-
};
|
|
2293
|
-
|
|
2294
|
-
// internal/src/mutable/get-json-token.ts
|
|
2295
|
-
var getJsonToken = (mutableAtomToken, store) => {
|
|
2296
|
-
if (mutableAtomToken.family) {
|
|
2297
|
-
const target = newest(store);
|
|
2298
|
-
const jsonFamilyKey = `${mutableAtomToken.family.key}:JSON`;
|
|
2299
|
-
const jsonFamilyToken = {
|
|
2300
|
-
key: jsonFamilyKey,
|
|
2301
|
-
type: `selector_family`
|
|
2302
|
-
};
|
|
2303
|
-
const family = withdraw(jsonFamilyToken, target);
|
|
2304
|
-
const subKey = JSON.parse(mutableAtomToken.family.subKey);
|
|
2305
|
-
const jsonToken = findInStore(family, subKey, store);
|
|
2306
|
-
return jsonToken;
|
|
2307
|
-
}
|
|
2308
|
-
const token = {
|
|
2309
|
-
type: `selector`,
|
|
2310
|
-
key: `${mutableAtomToken.key}:JSON`
|
|
2311
|
-
};
|
|
2312
|
-
return token;
|
|
2313
|
-
};
|
|
2314
|
-
|
|
2315
|
-
// internal/src/mutable/get-update-token.ts
|
|
2316
|
-
var getUpdateToken = (mutableAtomToken) => {
|
|
2317
|
-
const key = `*${mutableAtomToken.key}`;
|
|
2318
|
-
const updateToken = { type: `atom`, key };
|
|
2319
|
-
if (mutableAtomToken.family) {
|
|
2320
|
-
updateToken.family = {
|
|
2321
|
-
key: `*${mutableAtomToken.family.key}`,
|
|
2322
|
-
subKey: mutableAtomToken.family.subKey
|
|
2323
|
-
};
|
|
2324
|
-
}
|
|
2325
|
-
return updateToken;
|
|
2326
|
-
};
|
|
2327
|
-
|
|
2328
|
-
// internal/src/mutable/transceiver.ts
|
|
2329
|
-
function isTransceiver(value) {
|
|
2330
|
-
return typeof value === `object` && value !== null && `do` in value && `undo` in value && `subscribe` in value;
|
|
2331
|
-
}
|
|
2332
|
-
|
|
2333
|
-
// internal/src/set-state/copy-mutable-if-needed.ts
|
|
2334
|
-
function copyMutableIfNeeded(atom, origin, target) {
|
|
2335
|
-
const originValue = origin.valueMap.get(atom.key);
|
|
2336
|
-
const targetValue = target.valueMap.get(atom.key);
|
|
2337
|
-
if (originValue === targetValue) {
|
|
2338
|
-
if (originValue === void 0) {
|
|
2339
|
-
return typeof atom.default === `function` ? atom.default() : atom.default;
|
|
2340
|
-
}
|
|
2341
|
-
origin.logger.info(`\u{1F4C3}`, `atom`, atom.key, `copying`);
|
|
2342
|
-
const jsonValue = atom.toJson(originValue);
|
|
2343
|
-
const copiedValue = atom.fromJson(jsonValue);
|
|
2344
|
-
target.valueMap.set(atom.key, copiedValue);
|
|
2345
|
-
new Tracker(atom, origin);
|
|
2346
|
-
return copiedValue;
|
|
2347
|
-
}
|
|
2348
|
-
return targetValue;
|
|
2349
|
-
}
|
|
2350
|
-
|
|
2351
|
-
// internal/src/caching.ts
|
|
2352
|
-
function cacheValue(key, value, subject, target) {
|
|
2353
|
-
const currentValue = target.valueMap.get(key);
|
|
2354
|
-
if (currentValue instanceof Future) {
|
|
2355
|
-
const future = currentValue;
|
|
2356
|
-
future.use(value);
|
|
2357
|
-
}
|
|
2358
|
-
if (value instanceof Promise) {
|
|
2359
|
-
const future = new Future(value);
|
|
2360
|
-
target.valueMap.set(key, future);
|
|
2361
|
-
future.then((resolved) => {
|
|
2362
|
-
cacheValue(key, resolved, subject, target);
|
|
2363
|
-
subject.next({ newValue: resolved, oldValue: future });
|
|
2364
|
-
}).catch((thrown) => {
|
|
2365
|
-
target.logger.error(`\u{1F4A5}`, `state`, key, `rejected:`, thrown);
|
|
2366
|
-
});
|
|
2367
|
-
return future;
|
|
2368
|
-
}
|
|
2369
|
-
target.valueMap.set(key, value);
|
|
2370
|
-
return value;
|
|
2371
|
-
}
|
|
2372
|
-
var readCachedValue = (token, target) => {
|
|
2373
|
-
let value = target.valueMap.get(token.key);
|
|
2374
|
-
if (token.type === `mutable_atom` && isChildStore(target)) {
|
|
2375
|
-
const { parent } = target;
|
|
2376
|
-
const copiedValue = copyMutableIfNeeded(token, parent, target);
|
|
2377
|
-
value = copiedValue;
|
|
2378
|
-
}
|
|
2379
|
-
return value;
|
|
2380
|
-
};
|
|
2381
|
-
var evictCachedValue = (key, target) => {
|
|
2382
|
-
const currentValue = target.valueMap.get(key);
|
|
2383
|
-
if (currentValue instanceof Future) {
|
|
2384
|
-
const future = currentValue;
|
|
2385
|
-
const selector = target.selectors.get(key) ?? target.readonlySelectors.get(key);
|
|
2386
|
-
if (selector) {
|
|
2387
|
-
future.use(selector.get());
|
|
2388
|
-
}
|
|
2389
|
-
return;
|
|
2390
|
-
}
|
|
2391
|
-
if (target.operation.open) {
|
|
2392
|
-
target.operation.prev.set(key, currentValue);
|
|
2393
|
-
}
|
|
2394
|
-
target.valueMap.delete(key);
|
|
2395
|
-
target.logger.info(`\u{1F5D1}`, `state`, key, `evicted`);
|
|
2396
|
-
};
|
|
2397
|
-
|
|
2398
|
-
// internal/src/atom/is-default.ts
|
|
2399
|
-
var isAtomDefault = (key, store) => {
|
|
2400
|
-
const core = newest(store);
|
|
2401
|
-
return core.atomsThatAreDefault.has(key);
|
|
2402
|
-
};
|
|
2403
|
-
var markAtomAsDefault = (key, store) => {
|
|
2404
|
-
const core = newest(store);
|
|
2405
|
-
core.atomsThatAreDefault = new Set(core.atomsThatAreDefault).add(key);
|
|
2406
|
-
};
|
|
2407
|
-
var markAtomAsNotDefault = (key, store) => {
|
|
2408
|
-
const core = newest(store);
|
|
2409
|
-
core.atomsThatAreDefault = new Set(newest(store).atomsThatAreDefault);
|
|
2410
|
-
core.atomsThatAreDefault.delete(key);
|
|
2411
|
-
};
|
|
2412
|
-
|
|
2413
|
-
// internal/src/atom/create-regular-atom.ts
|
|
2414
|
-
function createRegularAtom(options, family, store) {
|
|
2415
|
-
store.logger.info(
|
|
2416
|
-
`\u{1F528}`,
|
|
2417
|
-
`atom`,
|
|
2418
|
-
options.key,
|
|
2419
|
-
`creating in store "${store.config.name}"`
|
|
2420
|
-
);
|
|
2421
|
-
const target = newest(store);
|
|
2422
|
-
const existing = target.atoms.get(options.key);
|
|
2423
|
-
if (existing && existing.type === `atom`) {
|
|
2424
|
-
store.logger.error(
|
|
2425
|
-
`\u274C`,
|
|
2426
|
-
`atom`,
|
|
2427
|
-
options.key,
|
|
2428
|
-
`Tried to create atom, but it already exists in the store.`
|
|
2429
|
-
);
|
|
2430
|
-
return deposit(existing);
|
|
2431
|
-
}
|
|
2432
|
-
const subject = new Subject();
|
|
2433
|
-
const newAtom = {
|
|
2434
|
-
...options,
|
|
2435
|
-
type: `atom`,
|
|
2436
|
-
install: (s) => {
|
|
2437
|
-
s.logger.info(
|
|
2438
|
-
`\u{1F6E0}\uFE0F`,
|
|
2439
|
-
`atom`,
|
|
2440
|
-
options.key,
|
|
2441
|
-
`installing in store "${s.config.name}"`
|
|
2442
|
-
);
|
|
2443
|
-
return createRegularAtom(options, family, s);
|
|
2444
|
-
},
|
|
2445
|
-
subject
|
|
2446
|
-
};
|
|
2447
|
-
if (family) {
|
|
2448
|
-
newAtom.family = family;
|
|
2449
|
-
}
|
|
2450
|
-
let initialValue = options.default;
|
|
2451
|
-
if (options.default instanceof Function) {
|
|
2452
|
-
initialValue = options.default();
|
|
2453
|
-
}
|
|
2454
|
-
target.atoms.set(newAtom.key, newAtom);
|
|
2455
|
-
markAtomAsDefault(options.key, store);
|
|
2456
|
-
cacheValue(options.key, initialValue, subject, target);
|
|
2457
|
-
const token = deposit(newAtom);
|
|
2458
|
-
if (options.effects) {
|
|
2459
|
-
let effectIndex = 0;
|
|
2460
|
-
const cleanupFunctions = [];
|
|
2461
|
-
for (const effect of options.effects) {
|
|
2462
|
-
const cleanup = effect({
|
|
2463
|
-
setSelf: (next) => {
|
|
2464
|
-
setIntoStore(token, next, store);
|
|
2465
|
-
},
|
|
2466
|
-
onSet: (handle) => subscribeToState(token, handle, `effect[${effectIndex}]`, store)
|
|
2467
|
-
});
|
|
2468
|
-
if (cleanup) {
|
|
2469
|
-
cleanupFunctions.push(cleanup);
|
|
2470
|
-
}
|
|
2471
|
-
++effectIndex;
|
|
2472
|
-
}
|
|
2473
|
-
newAtom.cleanup = () => {
|
|
2474
|
-
for (const cleanup of cleanupFunctions) {
|
|
2475
|
-
cleanup();
|
|
2476
|
-
}
|
|
2477
|
-
};
|
|
2478
|
-
}
|
|
2479
|
-
return token;
|
|
2480
|
-
}
|
|
2481
|
-
|
|
2482
|
-
// internal/src/atom/create-standalone-atom.ts
|
|
2483
|
-
function createStandaloneAtom(options, store) {
|
|
2484
|
-
const isMutable = `mutable` in options;
|
|
2485
|
-
if (isMutable) {
|
|
2486
|
-
const state2 = createMutableAtom(options, void 0, store);
|
|
2487
|
-
store.on.atomCreation.next(state2);
|
|
2488
|
-
return state2;
|
|
2489
|
-
}
|
|
2490
|
-
const state = createRegularAtom(options, void 0, store);
|
|
2491
|
-
store.on.atomCreation.next(state);
|
|
2492
|
-
return state;
|
|
2493
|
-
}
|
|
2494
|
-
|
|
2495
|
-
// internal/src/atom/dispose-atom.ts
|
|
2496
|
-
function disposeAtom(atomToken, store) {
|
|
2497
|
-
const target = newest(store);
|
|
2498
|
-
const { key } = atomToken;
|
|
2499
|
-
const atom = target.atoms.get(key);
|
|
2500
|
-
if (!atom) {
|
|
2501
|
-
store.logger.error(
|
|
2502
|
-
`\u274C`,
|
|
2503
|
-
`atom`,
|
|
2504
|
-
key,
|
|
2505
|
-
`Tried to dispose atom, but it does not exist in the store.`
|
|
2506
|
-
);
|
|
2507
|
-
} else if (!atom.family) {
|
|
2508
|
-
store.logger.error(`\u274C`, `atom`, key, `Standalone atoms cannot be disposed.`);
|
|
2509
|
-
} else {
|
|
2510
|
-
atom.cleanup?.();
|
|
2511
|
-
const lastValue = store.valueMap.get(atom.key);
|
|
2512
|
-
const family = withdraw({ key: atom.family.key, type: `atom_family` }, store);
|
|
2513
|
-
family.subject.next({
|
|
2514
|
-
type: `state_disposal`,
|
|
2515
|
-
token: atomToken,
|
|
2516
|
-
value: lastValue
|
|
2517
|
-
});
|
|
2518
|
-
const molecule = target.molecules.get(atom.family.subKey);
|
|
2519
|
-
if (molecule) {
|
|
2520
|
-
molecule.tokens.delete(key);
|
|
2521
|
-
}
|
|
2522
|
-
target.atoms.delete(key);
|
|
2523
|
-
target.valueMap.delete(key);
|
|
2524
|
-
const selectorKeys = target.selectorAtoms.getRelatedKeys(key);
|
|
2525
|
-
if (selectorKeys) {
|
|
2526
|
-
for (const selectorKey of selectorKeys) {
|
|
2527
|
-
const token = target.selectors.get(selectorKey) ?? target.readonlySelectors.get(selectorKey);
|
|
2528
|
-
if (token) {
|
|
2529
|
-
disposeSelector(token, store);
|
|
2530
|
-
}
|
|
2531
|
-
}
|
|
2532
|
-
}
|
|
2533
|
-
target.selectorAtoms.delete(key);
|
|
2534
|
-
target.atomsThatAreDefault.delete(key);
|
|
2535
|
-
target.timelineTopics.delete(key);
|
|
2536
|
-
if (atomToken.type === `mutable_atom`) {
|
|
2537
|
-
const updateToken = getUpdateToken(atomToken);
|
|
2538
|
-
disposeAtom(updateToken, store);
|
|
2539
|
-
store.trackers.delete(key);
|
|
2540
|
-
}
|
|
2541
|
-
store.logger.info(`\u{1F525}`, `atom`, key, `deleted`);
|
|
2542
|
-
if (isChildStore(target) && target.transactionMeta.phase === `building`) {
|
|
2543
|
-
target.transactionMeta.update.updates.push({
|
|
2544
|
-
type: `state_disposal`,
|
|
2545
|
-
token: atomToken
|
|
2546
|
-
});
|
|
2547
|
-
} else {
|
|
2548
|
-
store.on.atomDisposal.next(atomToken);
|
|
2549
|
-
}
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
|
-
function createTimeline(options, store, data) {
|
|
2553
|
-
const tl = {
|
|
2554
|
-
type: `timeline`,
|
|
2555
|
-
key: options.key,
|
|
2556
|
-
at: 0,
|
|
2557
|
-
timeTraveling: null,
|
|
2558
|
-
selectorTime: null,
|
|
2559
|
-
transactionKey: null,
|
|
2560
|
-
...data,
|
|
2561
|
-
history: data?.history.map((update) => ({ ...update })) ?? [],
|
|
2562
|
-
install: (s) => createTimeline(options, s, tl),
|
|
2563
|
-
subject: new Subject(),
|
|
2564
|
-
subscriptions: /* @__PURE__ */ new Map()
|
|
2565
|
-
};
|
|
2566
|
-
if (options.shouldCapture) {
|
|
2567
|
-
tl.shouldCapture = options.shouldCapture;
|
|
2568
|
-
}
|
|
2569
|
-
const timelineKey = options.key;
|
|
2570
|
-
const target = newest(store);
|
|
2571
|
-
for (const initialTopic of options.scope) {
|
|
2572
|
-
switch (initialTopic.type) {
|
|
2573
|
-
case `atom`:
|
|
2574
|
-
case `mutable_atom`:
|
|
2575
|
-
{
|
|
2576
|
-
const atomToken = initialTopic;
|
|
2577
|
-
const atomKey = atomToken.key;
|
|
2578
|
-
let existingTimelineKey = target.timelineTopics.getRelatedKey(atomKey);
|
|
2579
|
-
if (`family` in atomToken) {
|
|
2580
|
-
const familyKey = atomToken.family.key;
|
|
2581
|
-
existingTimelineKey = target.timelineTopics.getRelatedKey(familyKey);
|
|
2582
|
-
if (existingTimelineKey) {
|
|
2583
|
-
store.logger.error(
|
|
2584
|
-
`\u274C`,
|
|
2585
|
-
`timeline`,
|
|
2586
|
-
options.key,
|
|
2587
|
-
`Failed to add atom "${atomKey}" because its family "${familyKey}" already belongs to timeline "${existingTimelineKey}"`
|
|
2588
|
-
);
|
|
2589
|
-
continue;
|
|
2590
|
-
}
|
|
2591
|
-
}
|
|
2592
|
-
if (existingTimelineKey) {
|
|
2593
|
-
store.logger.error(
|
|
2594
|
-
`\u274C`,
|
|
2595
|
-
`timeline`,
|
|
2596
|
-
options.key,
|
|
2597
|
-
`Failed to add atom "${atomKey}" because it already belongs to timeline "${existingTimelineKey}"`
|
|
2598
|
-
);
|
|
2599
|
-
continue;
|
|
2600
|
-
}
|
|
2601
|
-
addAtomToTimeline(atomToken, tl, store);
|
|
2602
|
-
}
|
|
2603
|
-
break;
|
|
2604
|
-
case `atom_family`:
|
|
2605
|
-
case `mutable_atom_family`:
|
|
2606
|
-
{
|
|
2607
|
-
const familyToken = initialTopic;
|
|
2608
|
-
const familyKey = familyToken.key;
|
|
2609
|
-
const existingTimelineKey = target.timelineTopics.getRelatedKey(familyKey);
|
|
2610
|
-
if (existingTimelineKey) {
|
|
2611
|
-
store.logger.error(
|
|
2612
|
-
`\u274C`,
|
|
2613
|
-
`timeline`,
|
|
2614
|
-
options.key,
|
|
2615
|
-
`Failed to add atom family "${familyKey}" because it already belongs to timeline "${existingTimelineKey}"`
|
|
2616
|
-
);
|
|
2617
|
-
continue;
|
|
2618
|
-
}
|
|
2619
|
-
addAtomFamilyToTimeline(familyToken, tl, store);
|
|
2620
|
-
}
|
|
2621
|
-
break;
|
|
2622
|
-
case `molecule_family`:
|
|
2623
|
-
{
|
|
2624
|
-
const familyToken = initialTopic;
|
|
2625
|
-
const familyKey = familyToken.key;
|
|
2626
|
-
const existingTimelineKey = target.timelineTopics.getRelatedKey(familyKey);
|
|
2627
|
-
if (existingTimelineKey) {
|
|
2628
|
-
store.logger.error(
|
|
2629
|
-
`\u274C`,
|
|
2630
|
-
`timeline`,
|
|
2631
|
-
options.key,
|
|
2632
|
-
`Failed to add molecule family "${familyKey}" because it already belongs to timeline "${existingTimelineKey}"`
|
|
2633
|
-
);
|
|
2634
|
-
continue;
|
|
2635
|
-
}
|
|
2636
|
-
addMoleculeFamilyToTimeline(familyToken, tl, store);
|
|
2637
|
-
}
|
|
2638
|
-
break;
|
|
2639
|
-
}
|
|
2640
|
-
}
|
|
2641
|
-
store.timelines.set(options.key, tl);
|
|
2642
|
-
const token = {
|
|
2643
|
-
key: timelineKey,
|
|
2644
|
-
type: `timeline`
|
|
2645
|
-
};
|
|
2646
|
-
store.on.timelineCreation.next(token);
|
|
2647
|
-
return token;
|
|
2648
|
-
}
|
|
2649
|
-
function addAtomToTimeline(atomToken, tl, store) {
|
|
2650
|
-
let maybeAtom = withdraw(atomToken, store);
|
|
2651
|
-
if (maybeAtom.type === `mutable_atom`) {
|
|
2652
|
-
const updateToken = getUpdateToken(maybeAtom);
|
|
2653
|
-
maybeAtom = withdraw(updateToken, store);
|
|
2654
|
-
}
|
|
2655
|
-
const atom = maybeAtom;
|
|
2656
|
-
store.timelineTopics.set(
|
|
2657
|
-
{ topicKey: atom.key, timelineKey: tl.key },
|
|
2658
|
-
{ topicType: `atom` }
|
|
2659
|
-
);
|
|
2660
|
-
tl.subscriptions.set(
|
|
2661
|
-
atom.key,
|
|
2662
|
-
atom.subject.subscribe(`timeline`, (update) => {
|
|
2663
|
-
const target = newest(store);
|
|
2664
|
-
const currentSelectorKey = store.operation.open && store.operation.token.type === `selector` ? store.operation.token.key : null;
|
|
2665
|
-
const currentSelectorTime = store.operation.open && store.operation.token.type === `selector` ? store.operation.time : null;
|
|
2666
|
-
const txUpdateInProgress = target.on.transactionApplying.state?.update;
|
|
2667
|
-
store.logger.info(
|
|
2668
|
-
`\u23F3`,
|
|
2669
|
-
`timeline`,
|
|
2670
|
-
tl.key,
|
|
2671
|
-
`atom`,
|
|
2672
|
-
atomToken.key,
|
|
2673
|
-
`went`,
|
|
2674
|
-
update.oldValue,
|
|
2675
|
-
`->`,
|
|
2676
|
-
update.newValue,
|
|
2677
|
-
txUpdateInProgress ? `in transaction "${txUpdateInProgress.key}"` : currentSelectorKey ? `in selector "${currentSelectorKey}"` : ``
|
|
2678
|
-
);
|
|
2679
|
-
if (tl.timeTraveling === null) {
|
|
2680
|
-
if (txUpdateInProgress) {
|
|
2681
|
-
joinTransaction(tl, txUpdateInProgress, store);
|
|
2682
|
-
} else if (currentSelectorKey && currentSelectorTime) {
|
|
2683
|
-
let latestUpdate = tl.history.at(-1);
|
|
2684
|
-
if (currentSelectorTime !== tl.selectorTime) {
|
|
2685
|
-
latestUpdate = {
|
|
2686
|
-
type: `selector_update`,
|
|
2687
|
-
timestamp: currentSelectorTime,
|
|
2688
|
-
key: currentSelectorKey,
|
|
2689
|
-
atomUpdates: []
|
|
2690
|
-
};
|
|
2691
|
-
latestUpdate.atomUpdates.push({
|
|
2692
|
-
key: atom.key,
|
|
2693
|
-
type: `atom_update`,
|
|
2694
|
-
...update
|
|
2695
|
-
});
|
|
2696
|
-
if (tl.at !== tl.history.length) {
|
|
2697
|
-
tl.history.splice(tl.at);
|
|
2698
|
-
}
|
|
2699
|
-
tl.history.push(latestUpdate);
|
|
2700
|
-
store.logger.info(
|
|
2701
|
-
`\u231B`,
|
|
2702
|
-
`timeline`,
|
|
2703
|
-
tl.key,
|
|
2704
|
-
`got a selector_update "${currentSelectorKey}" with`,
|
|
2705
|
-
latestUpdate.atomUpdates.map((atomUpdate) => atomUpdate.key)
|
|
2706
|
-
);
|
|
2707
|
-
tl.at = tl.history.length;
|
|
2708
|
-
tl.selectorTime = currentSelectorTime;
|
|
2709
|
-
} else {
|
|
2710
|
-
if (latestUpdate?.type === `selector_update`) {
|
|
2711
|
-
latestUpdate.atomUpdates.push({
|
|
2712
|
-
key: atom.key,
|
|
2713
|
-
type: `atom_update`,
|
|
2714
|
-
...update
|
|
2715
|
-
});
|
|
2716
|
-
store.logger.info(
|
|
2717
|
-
`\u231B`,
|
|
2718
|
-
`timeline`,
|
|
2719
|
-
tl.key,
|
|
2720
|
-
`set selector_update "${currentSelectorKey}" to`,
|
|
2721
|
-
latestUpdate?.atomUpdates.map((atomUpdate) => atomUpdate.key)
|
|
2722
|
-
);
|
|
2723
|
-
}
|
|
2724
|
-
}
|
|
2725
|
-
if (latestUpdate) {
|
|
2726
|
-
const willCaptureSelectorUpdate = tl.shouldCapture?.(latestUpdate, tl) ?? true;
|
|
2727
|
-
if (willCaptureSelectorUpdate) {
|
|
2728
|
-
tl.subject.next(latestUpdate);
|
|
2729
|
-
} else {
|
|
2730
|
-
tl.history.pop();
|
|
2731
|
-
tl.at = tl.history.length;
|
|
2732
|
-
}
|
|
2733
|
-
}
|
|
2734
|
-
} else {
|
|
2735
|
-
const timestamp = Date.now();
|
|
2736
|
-
tl.selectorTime = null;
|
|
2737
|
-
if (tl.at !== tl.history.length) {
|
|
2738
|
-
tl.history.splice(tl.at);
|
|
2739
|
-
}
|
|
2740
|
-
const atomUpdate = {
|
|
2741
|
-
type: `atom_update`,
|
|
2742
|
-
timestamp,
|
|
2743
|
-
key: atom.key,
|
|
2744
|
-
oldValue: update.oldValue,
|
|
2745
|
-
newValue: update.newValue
|
|
2746
|
-
};
|
|
2747
|
-
if (atom.family) {
|
|
2748
|
-
atomUpdate.family = atom.family;
|
|
2749
|
-
}
|
|
2750
|
-
const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true;
|
|
2751
|
-
store.logger.info(
|
|
2752
|
-
`\u231B`,
|
|
2753
|
-
`timeline`,
|
|
2754
|
-
tl.key,
|
|
2755
|
-
`got an atom_update to "${atom.key}"`
|
|
2756
|
-
);
|
|
2757
|
-
if (willCapture) {
|
|
2758
|
-
tl.history.push(atomUpdate);
|
|
2759
|
-
tl.at = tl.history.length;
|
|
2760
|
-
tl.subject.next(atomUpdate);
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
})
|
|
2765
|
-
);
|
|
2766
|
-
}
|
|
2767
|
-
function addAtomFamilyToTimeline(atomFamilyToken, tl, store) {
|
|
2768
|
-
const family = withdraw(atomFamilyToken, store);
|
|
2769
|
-
store.timelineTopics.set(
|
|
2770
|
-
{ topicKey: family.key, timelineKey: tl.key },
|
|
2771
|
-
{ topicType: `atom_family` }
|
|
2772
|
-
);
|
|
2773
|
-
tl.subscriptions.set(
|
|
2774
|
-
family.key,
|
|
2775
|
-
family.subject.subscribe(`timeline`, (creationOrDisposal) => {
|
|
2776
|
-
handleStateLifecycleEvent(creationOrDisposal, tl, store);
|
|
2777
|
-
})
|
|
2778
|
-
);
|
|
2779
|
-
for (const atom of store.atoms.values()) {
|
|
2780
|
-
if (atom.family?.key === family.key) {
|
|
2781
|
-
addAtomToTimeline(atom, tl, store);
|
|
2782
|
-
}
|
|
2783
|
-
}
|
|
2784
|
-
}
|
|
2785
|
-
function addMoleculeFamilyToTimeline(familyToken, tl, store) {
|
|
2786
|
-
store.timelineTopics.set(
|
|
2787
|
-
{ topicKey: familyToken.key, timelineKey: tl.key },
|
|
2788
|
-
{ topicType: `molecule_family` }
|
|
2789
|
-
);
|
|
2790
|
-
const family = store.moleculeFamilies.get(familyToken.key);
|
|
2791
|
-
if (family) {
|
|
2792
|
-
tl.subscriptions.set(
|
|
2793
|
-
familyToken.key,
|
|
2794
|
-
family.subject.subscribe(`timeline:${tl.key}`, (creationOrDisposal) => {
|
|
2795
|
-
store.logger.info(
|
|
2796
|
-
`\u{1F41E}`,
|
|
2797
|
-
`timeline`,
|
|
2798
|
-
tl.key,
|
|
2799
|
-
`got a molecule creation or disposal`,
|
|
2800
|
-
creationOrDisposal
|
|
2801
|
-
);
|
|
2802
|
-
switch (creationOrDisposal.type) {
|
|
2803
|
-
case `molecule_creation`:
|
|
2804
|
-
{
|
|
2805
|
-
store.timelineTopics.set(
|
|
2806
|
-
{
|
|
2807
|
-
topicKey: creationOrDisposal.token.key,
|
|
2808
|
-
timelineKey: tl.key
|
|
2809
|
-
},
|
|
2810
|
-
{ topicType: `molecule` }
|
|
2811
|
-
);
|
|
2812
|
-
const txUpdateInProgress = newest(store).on.transactionApplying.state?.update;
|
|
2813
|
-
if (txUpdateInProgress) {
|
|
2814
|
-
joinTransaction(tl, txUpdateInProgress, store);
|
|
2815
|
-
} else if (tl.timeTraveling === null) {
|
|
2816
|
-
const event = Object.assign(creationOrDisposal, {
|
|
2817
|
-
timestamp: Date.now()
|
|
2818
|
-
});
|
|
2819
|
-
tl.history.push(event);
|
|
2820
|
-
tl.at = tl.history.length;
|
|
2821
|
-
tl.subject.next(event);
|
|
2822
|
-
}
|
|
2823
|
-
const molecule = withdraw(creationOrDisposal.token, store);
|
|
2824
|
-
for (const token of molecule.tokens.values()) {
|
|
2825
|
-
switch (token.type) {
|
|
2826
|
-
case `atom`:
|
|
2827
|
-
case `mutable_atom`:
|
|
2828
|
-
addAtomToTimeline(token, tl, store);
|
|
2829
|
-
break;
|
|
2830
|
-
}
|
|
2831
|
-
}
|
|
2832
|
-
tl.subscriptions.set(
|
|
2833
|
-
molecule.key,
|
|
2834
|
-
molecule.subject.subscribe(
|
|
2835
|
-
`timeline:${tl.key}`,
|
|
2836
|
-
(stateCreationOrDisposal) => {
|
|
2837
|
-
handleStateLifecycleEvent(stateCreationOrDisposal, tl, store);
|
|
2838
|
-
}
|
|
2839
|
-
)
|
|
2840
|
-
);
|
|
2841
|
-
}
|
|
2842
|
-
break;
|
|
2843
|
-
case `molecule_disposal`:
|
|
2844
|
-
{
|
|
2845
|
-
const txUpdateInProgress = newest(store).on.transactionApplying.state?.update;
|
|
2846
|
-
if (txUpdateInProgress) {
|
|
2847
|
-
joinTransaction(tl, txUpdateInProgress, store);
|
|
2848
|
-
} else if (tl.timeTraveling === null) {
|
|
2849
|
-
const event = Object.assign(creationOrDisposal, {
|
|
2850
|
-
timestamp: Date.now()
|
|
2851
|
-
});
|
|
2852
|
-
tl.history.push(event);
|
|
2853
|
-
tl.at = tl.history.length;
|
|
2854
|
-
tl.subject.next(event);
|
|
2855
|
-
}
|
|
2856
|
-
const moleculeKey = creationOrDisposal.token.key;
|
|
2857
|
-
tl.subscriptions.get(moleculeKey)?.();
|
|
2858
|
-
tl.subscriptions.delete(moleculeKey);
|
|
2859
|
-
for (const [familyKey] of creationOrDisposal.values) {
|
|
2860
|
-
const stateKey = `${familyKey}(${stringifyJson(moleculeKey)})`;
|
|
2861
|
-
tl.subscriptions.get(stateKey)?.();
|
|
2862
|
-
tl.subscriptions.delete(stateKey);
|
|
2863
|
-
store.timelineTopics.delete(stateKey);
|
|
2864
|
-
}
|
|
2865
|
-
}
|
|
2866
|
-
break;
|
|
2867
|
-
}
|
|
2868
|
-
})
|
|
2869
|
-
);
|
|
2870
|
-
}
|
|
2871
|
-
}
|
|
2872
|
-
function joinTransaction(tl, txUpdateInProgress, store) {
|
|
2873
|
-
const currentTxKey = txUpdateInProgress.key;
|
|
2874
|
-
const currentTxInstanceId = txUpdateInProgress.id;
|
|
2875
|
-
const currentTxToken = {
|
|
2876
|
-
key: currentTxKey,
|
|
2877
|
-
type: `transaction`
|
|
2878
|
-
};
|
|
2879
|
-
const currentTransaction = withdraw(currentTxToken, store);
|
|
2880
|
-
if (currentTxKey && tl.transactionKey === null) {
|
|
2881
|
-
tl.transactionKey = currentTxKey;
|
|
2882
|
-
const unsubscribe = currentTransaction.subject.subscribe(
|
|
2883
|
-
`timeline:${tl.key}`,
|
|
2884
|
-
(transactionUpdate) => {
|
|
2885
|
-
unsubscribe();
|
|
2886
|
-
tl.transactionKey = null;
|
|
2887
|
-
if (tl.timeTraveling === null && currentTxInstanceId) {
|
|
2888
|
-
if (tl.at !== tl.history.length) {
|
|
2889
|
-
tl.history.splice(tl.at);
|
|
2890
|
-
}
|
|
2891
|
-
const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key);
|
|
2892
|
-
const updates = filterTransactionUpdates(
|
|
2893
|
-
transactionUpdate.updates,
|
|
2894
|
-
timelineTopics
|
|
2895
|
-
);
|
|
2896
|
-
const timelineTransactionUpdate = {
|
|
2897
|
-
timestamp: Date.now(),
|
|
2898
|
-
...transactionUpdate,
|
|
2899
|
-
updates
|
|
2900
|
-
};
|
|
2901
|
-
const willCapture = tl.shouldCapture?.(timelineTransactionUpdate, tl) ?? true;
|
|
2902
|
-
if (willCapture) {
|
|
2903
|
-
tl.history.push(timelineTransactionUpdate);
|
|
2904
|
-
tl.at = tl.history.length;
|
|
2905
|
-
tl.subject.next(timelineTransactionUpdate);
|
|
2906
|
-
}
|
|
2907
|
-
}
|
|
2908
|
-
}
|
|
2909
|
-
);
|
|
2910
|
-
}
|
|
2911
|
-
}
|
|
2912
|
-
function filterTransactionUpdates(updates, timelineTopics) {
|
|
2913
|
-
return updates.filter((updateFromTx) => {
|
|
2914
|
-
if (updateFromTx.type === `transaction_update`) {
|
|
2915
|
-
return true;
|
|
2916
|
-
}
|
|
2917
|
-
let key;
|
|
2918
|
-
switch (updateFromTx.type) {
|
|
2919
|
-
case `state_creation`:
|
|
2920
|
-
case `state_disposal`:
|
|
2921
|
-
case `molecule_creation`:
|
|
2922
|
-
case `molecule_disposal`:
|
|
2923
|
-
key = updateFromTx.token.key;
|
|
2924
|
-
break;
|
|
2925
|
-
default:
|
|
2926
|
-
key = updateFromTx.key;
|
|
2927
|
-
break;
|
|
2928
|
-
}
|
|
2929
|
-
return timelineTopics.has(key);
|
|
2930
|
-
}).map((updateFromTx) => {
|
|
2931
|
-
if (`updates` in updateFromTx) {
|
|
2932
|
-
return {
|
|
2933
|
-
...updateFromTx,
|
|
2934
|
-
updates: filterTransactionUpdates(
|
|
2935
|
-
updateFromTx.updates,
|
|
2936
|
-
timelineTopics
|
|
2937
|
-
)
|
|
2938
|
-
};
|
|
2939
|
-
}
|
|
2940
|
-
return updateFromTx;
|
|
2941
|
-
});
|
|
2942
|
-
}
|
|
2943
|
-
function handleStateLifecycleEvent(event, tl, store) {
|
|
2944
|
-
const timestamp = Date.now();
|
|
2945
|
-
const timelineEvent = Object.assign(event, {
|
|
2946
|
-
timestamp
|
|
2947
|
-
});
|
|
2948
|
-
if (!tl.timeTraveling) {
|
|
2949
|
-
const txUpdateInProgress = newest(store).on.transactionApplying.state?.update;
|
|
2950
|
-
if (txUpdateInProgress) {
|
|
2951
|
-
joinTransaction(tl, txUpdateInProgress, store);
|
|
2952
|
-
} else {
|
|
2953
|
-
tl.history.push(timelineEvent);
|
|
2954
|
-
tl.at = tl.history.length;
|
|
2955
|
-
tl.subject.next(timelineEvent);
|
|
2956
|
-
}
|
|
2957
|
-
}
|
|
2958
|
-
switch (event.type) {
|
|
2959
|
-
case `state_creation`:
|
|
2960
|
-
addAtomToTimeline(event.token, tl, store);
|
|
2961
|
-
break;
|
|
2962
|
-
case `state_disposal`:
|
|
2963
|
-
tl.subscriptions.get(event.token.key)?.();
|
|
2964
|
-
tl.subscriptions.delete(event.token.key);
|
|
2965
|
-
break;
|
|
2966
|
-
}
|
|
2967
|
-
}
|
|
2968
|
-
|
|
2969
|
-
// internal/src/timeline/time-travel.ts
|
|
2970
|
-
var timeTravel = (action, token, store) => {
|
|
2971
|
-
store.logger.info(
|
|
2972
|
-
action === `redo` ? `\u23E9` : `\u23EA`,
|
|
2973
|
-
`timeline`,
|
|
2974
|
-
token.key,
|
|
2975
|
-
action
|
|
2976
|
-
);
|
|
2977
|
-
const timelineData = store.timelines.get(token.key);
|
|
2978
|
-
if (!timelineData) {
|
|
2979
|
-
store.logger.error(
|
|
2980
|
-
`\u{1F41E}`,
|
|
2981
|
-
`timeline`,
|
|
2982
|
-
token.key,
|
|
2983
|
-
`Failed to ${action}. This timeline has not been initialized.`
|
|
2984
|
-
);
|
|
2985
|
-
return;
|
|
2986
|
-
}
|
|
2987
|
-
if (action === `redo` && timelineData.at === timelineData.history.length || action === `undo` && timelineData.at === 0) {
|
|
2988
|
-
store.logger.warn(
|
|
2989
|
-
`\u{1F481}`,
|
|
2990
|
-
`timeline`,
|
|
2991
|
-
token.key,
|
|
2992
|
-
`Failed to ${action} at the ${action === `redo` ? `end` : `beginning`} of timeline "${token.key}". There is nothing to ${action}.`
|
|
2993
|
-
);
|
|
2994
|
-
return;
|
|
2995
|
-
}
|
|
2996
|
-
timelineData.timeTraveling = action === `redo` ? `into_future` : `into_past`;
|
|
2997
|
-
if (action === `undo`) {
|
|
2998
|
-
--timelineData.at;
|
|
2999
|
-
}
|
|
3000
|
-
const update = timelineData.history[timelineData.at];
|
|
3001
|
-
const applying = action === `redo` ? `newValue` : `oldValue`;
|
|
3002
|
-
switch (update.type) {
|
|
3003
|
-
case `atom_update`: {
|
|
3004
|
-
ingestAtomUpdate(applying, update, store);
|
|
3005
|
-
break;
|
|
3006
|
-
}
|
|
3007
|
-
case `selector_update`: {
|
|
3008
|
-
ingestSelectorUpdate(applying, update, store);
|
|
3009
|
-
break;
|
|
3010
|
-
}
|
|
3011
|
-
case `transaction_update`: {
|
|
3012
|
-
ingestTransactionUpdate(applying, update, store);
|
|
3013
|
-
break;
|
|
3014
|
-
}
|
|
3015
|
-
case `state_creation`: {
|
|
3016
|
-
ingestCreationEvent(update, applying, store);
|
|
3017
|
-
break;
|
|
3018
|
-
}
|
|
3019
|
-
case `state_disposal`: {
|
|
3020
|
-
ingestDisposalEvent(update, applying, store);
|
|
3021
|
-
break;
|
|
3022
|
-
}
|
|
3023
|
-
case `molecule_creation`: {
|
|
3024
|
-
ingestMoleculeCreationEvent(update, applying, store);
|
|
3025
|
-
break;
|
|
3026
|
-
}
|
|
3027
|
-
case `molecule_disposal`: {
|
|
3028
|
-
ingestMoleculeDisposalEvent(update, applying, store);
|
|
3029
|
-
break;
|
|
3030
|
-
}
|
|
3031
|
-
}
|
|
3032
|
-
if (action === `redo`) {
|
|
3033
|
-
++timelineData.at;
|
|
3034
|
-
}
|
|
3035
|
-
timelineData.subject.next(action);
|
|
3036
|
-
timelineData.timeTraveling = null;
|
|
3037
|
-
store.logger.info(
|
|
3038
|
-
`\u23F9\uFE0F`,
|
|
3039
|
-
`timeline`,
|
|
3040
|
-
token.key,
|
|
3041
|
-
`"${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`
|
|
3042
|
-
);
|
|
3043
|
-
};
|
|
3044
|
-
|
|
3045
|
-
export { FamilyTracker, Future, IMPLICIT, LazyMap, Molecule, NotFoundError, StatefulSubject, Store, Subject, TRANSACTION_PHASES, Tracker, abortTransaction, actUponStore, applyTransaction, arbitrary, assignTransactionToContinuity, become, buildTransaction, cacheValue, clearStore, closeOperation, createAtomFamily, createMoleculeFamily, createMutableAtom, createMutableAtomFamily, createReadonlySelector, createReadonlySelectorFamily, createRegularAtom, createRegularAtomFamily, createSelectorFamily, createStandaloneAtom, createStandaloneSelector, createTimeline, createTransaction, createWritableSelector, deposit, disposeAtom, disposeFromStore, disposeMolecule, disposeSelector, eldest, evictCachedValue, findInStore, getContinuityKey, getEnvironmentData, getEpochNumberOfAction, getEpochNumberOfContinuity, getFromStore, getJsonFamily, getJsonToken, getSelectorDependencyKeys, getUpdateToken, growMoleculeInStore, ingestAtomUpdate, ingestCreationEvent, ingestDisposalEvent, ingestMoleculeCreationEvent, ingestMoleculeDisposalEvent, ingestSelectorUpdate, ingestTransactionUpdate, initFamilyMemberInStore, isAtomDefault, isAtomKey, isChildStore, isDone, isReadonlySelectorKey, isRootStore, isSelectorKey, isStateKey, isTransceiver, makeMoleculeInStore, markAtomAsDefault, markAtomAsNotDefault, markDone, newest, openOperation, readCachedValue, readOrComputeValue, registerSelector, seekInStore, setAtomOrSelector, setEpochNumberOfAction, setEpochNumberOfContinuity, setIntoStore, subscribeToRootAtoms, subscribeToState, subscribeToTimeline, subscribeToTransaction, timeTravel, traceAllSelectorAtoms, traceSelectorAtoms, updateSelectorAtoms, withdraw };
|