atom.io 0.39.1 → 0.40.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/internal/index.d.ts +68 -63
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +171 -161
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.d.ts +2 -2
- package/dist/introspection/index.d.ts.map +1 -1
- package/dist/introspection/index.js.map +1 -1
- package/dist/main/index.d.ts +19 -15
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js +16 -13
- package/dist/main/index.js.map +1 -1
- package/dist/react/index.d.ts +3 -3
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.js +9 -6
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime-client/index.d.ts +3 -3
- package/dist/realtime-client/index.d.ts.map +1 -1
- package/dist/realtime-client/index.js +3 -4
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts +2 -2
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/internal/atom/create-regular-atom.ts +3 -2
- package/src/internal/atom/dispose-atom.ts +6 -6
- package/src/internal/events/ingest-selector-update.ts +13 -4
- package/src/internal/families/create-readonly-held-selector-family.ts +3 -4
- package/src/internal/families/create-readonly-pure-selector-family.ts +4 -9
- package/src/internal/families/create-regular-atom-family.ts +3 -4
- package/src/internal/families/create-selector-family.ts +6 -6
- package/src/internal/families/create-writable-held-selector-family.ts +2 -2
- package/src/internal/families/create-writable-pure-selector-family.ts +3 -7
- package/src/internal/families/dispose-from-store.ts +9 -2
- package/src/internal/get-state/get-from-store.ts +10 -3
- package/src/internal/get-state/reduce-reference.ts +15 -2
- package/src/internal/index.ts +8 -8
- package/src/internal/install-into-store.ts +2 -1
- package/src/internal/join/create-join.ts +2 -2
- package/src/internal/join/find-relations-in-store.ts +2 -2
- package/src/internal/join/get-internal-relations-from-store.ts +2 -2
- package/src/internal/join/get-join.ts +5 -2
- package/src/internal/join/join-internal.ts +15 -20
- package/src/internal/lineage.ts +12 -1
- package/src/internal/molecule.ts +64 -36
- package/src/internal/mutable/create-mutable-atom-family.ts +4 -4
- package/src/internal/mutable/create-mutable-atom.ts +2 -2
- package/src/internal/mutable/tracker-family.ts +3 -3
- package/src/internal/operation.ts +3 -1
- package/src/internal/selector/create-readonly-held-selector.ts +2 -2
- package/src/internal/selector/create-readonly-pure-selector.ts +2 -2
- package/src/internal/selector/create-writable-held-selector.ts +2 -2
- package/src/internal/selector/create-writable-pure-selector.ts +2 -2
- package/src/internal/set-state/become.ts +1 -3
- package/src/internal/set-state/dispatch-state-update.ts +13 -11
- package/src/internal/set-state/reset-in-store.ts +11 -13
- package/src/internal/set-state/set-into-store.ts +27 -3
- package/src/internal/store/store.ts +14 -12
- package/src/internal/timeline/create-timeline.ts +136 -100
- package/src/internal/timeline/time-travel.ts +43 -31
- package/src/internal/transaction/abort-transaction.ts +3 -15
- package/src/internal/transaction/act-upon-store.ts +1 -5
- package/src/internal/transaction/apply-transaction.ts +5 -17
- package/src/internal/transaction/assign-transaction-to-continuity.ts +2 -7
- package/src/internal/transaction/build-transaction.ts +3 -4
- package/src/internal/transaction/create-transaction.ts +5 -6
- package/src/internal/transaction/get-epoch-number.ts +1 -7
- package/src/internal/transaction/set-epoch-number.ts +4 -12
- package/src/introspection/attach-introspection-states.ts +4 -2
- package/src/introspection/attach-timeline-family.ts +2 -2
- package/src/introspection/attach-transaction-logs.ts +2 -2
- package/src/introspection/attach-type-selectors.ts +2 -2
- package/src/main/dispose-state.ts +1 -5
- package/src/main/events.ts +8 -4
- package/src/main/get-state.ts +3 -6
- package/src/main/logger.ts +1 -1
- package/src/main/realm.ts +36 -12
- package/src/main/reset-state.ts +1 -5
- package/src/main/set-state.ts +4 -11
- package/src/main/silo.ts +4 -3
- package/src/main/timeline.ts +1 -7
- package/src/react/store-context.tsx +3 -3
- package/src/react-devtools/Button.tsx +3 -2
- package/src/react-devtools/TimelineIndex.tsx +0 -2
- package/src/react-devtools/Updates.tsx +14 -9
- package/src/react-devtools/store.ts +2 -2
- package/src/realtime-client/continuity/register-and-attempt-confirmed-update.ts +4 -8
- package/src/realtime-client/sync-continuity.ts +2 -2
- package/src/realtime-server/index.ts +2 -2
|
@@ -23,12 +23,36 @@ export function setIntoStore<
|
|
|
23
23
|
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
24
24
|
): void
|
|
25
25
|
|
|
26
|
-
export function setIntoStore<
|
|
26
|
+
export function setIntoStore<
|
|
27
|
+
T,
|
|
28
|
+
K extends Canonical,
|
|
29
|
+
New extends T,
|
|
30
|
+
Key extends K,
|
|
31
|
+
>(
|
|
32
|
+
store: Store,
|
|
33
|
+
...params:
|
|
34
|
+
| [
|
|
35
|
+
token: WritableFamilyToken<T, K>,
|
|
36
|
+
key: Key,
|
|
37
|
+
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
38
|
+
]
|
|
39
|
+
| [
|
|
40
|
+
token: WritableToken<T>,
|
|
41
|
+
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
42
|
+
]
|
|
43
|
+
): void
|
|
44
|
+
|
|
45
|
+
export function setIntoStore<
|
|
46
|
+
T,
|
|
47
|
+
K extends Canonical,
|
|
48
|
+
New extends T,
|
|
49
|
+
Key extends K,
|
|
50
|
+
>(
|
|
27
51
|
store: Store,
|
|
28
52
|
...params:
|
|
29
53
|
| [
|
|
30
|
-
token: WritableFamilyToken<T,
|
|
31
|
-
key:
|
|
54
|
+
token: WritableFamilyToken<T, K>,
|
|
55
|
+
key: Key,
|
|
32
56
|
value: New | typeof RESET_STATE | ((oldValue: T) => New),
|
|
33
57
|
]
|
|
34
58
|
| [
|
|
@@ -30,6 +30,8 @@ import type { OperationProgress } from "../operation"
|
|
|
30
30
|
import { StatefulSubject, Subject } from "../subject"
|
|
31
31
|
import type { Timeline } from "../timeline"
|
|
32
32
|
import type {
|
|
33
|
+
ChildStore,
|
|
34
|
+
RootStore,
|
|
33
35
|
Transaction,
|
|
34
36
|
TransactionEpoch,
|
|
35
37
|
TransactionProgress,
|
|
@@ -39,8 +41,8 @@ import type { Fn } from "../utility-types"
|
|
|
39
41
|
import { CircularBuffer } from "./circular-buffer"
|
|
40
42
|
|
|
41
43
|
export class Store implements Lineage {
|
|
42
|
-
public parent:
|
|
43
|
-
public child:
|
|
44
|
+
public parent: ChildStore | RootStore | null = null
|
|
45
|
+
public child: ChildStore | null = null
|
|
44
46
|
|
|
45
47
|
public valueMap: Map<string, any> = new Map()
|
|
46
48
|
public defaults: Map<string, any> = new Map()
|
|
@@ -210,14 +212,14 @@ export class Store implements Lineage {
|
|
|
210
212
|
) {
|
|
211
213
|
continue
|
|
212
214
|
}
|
|
213
|
-
family.install(this)
|
|
215
|
+
family.install(this as RootStore)
|
|
214
216
|
}
|
|
215
217
|
const mutableHelpers = new Set<string>()
|
|
216
218
|
for (const [, atom] of store.atoms) {
|
|
217
219
|
if (mutableHelpers.has(atom.key)) {
|
|
218
220
|
continue
|
|
219
221
|
}
|
|
220
|
-
atom.install(this)
|
|
222
|
+
atom.install(this as RootStore)
|
|
221
223
|
if (atom.type === `mutable_atom`) {
|
|
222
224
|
const originalJsonToken = getJsonToken(store, atom)
|
|
223
225
|
const originalUpdateToken = getUpdateToken(atom)
|
|
@@ -226,19 +228,19 @@ export class Store implements Lineage {
|
|
|
226
228
|
}
|
|
227
229
|
}
|
|
228
230
|
for (const [, selector] of store.readonlySelectors) {
|
|
229
|
-
selector.install(this)
|
|
231
|
+
selector.install(this as RootStore)
|
|
230
232
|
}
|
|
231
233
|
for (const [, selector] of store.writableSelectors) {
|
|
232
234
|
if (mutableHelpers.has(selector.key)) {
|
|
233
235
|
continue
|
|
234
236
|
}
|
|
235
|
-
selector.install(this)
|
|
237
|
+
selector.install(this as RootStore)
|
|
236
238
|
}
|
|
237
239
|
for (const [, tx] of store.transactions) {
|
|
238
|
-
tx.install(this)
|
|
240
|
+
tx.install(this as RootStore)
|
|
239
241
|
}
|
|
240
242
|
for (const [, timeline] of store.timelines) {
|
|
241
|
-
timeline.install(this)
|
|
243
|
+
timeline.install(this as RootStore)
|
|
242
244
|
}
|
|
243
245
|
}
|
|
244
246
|
}
|
|
@@ -258,15 +260,15 @@ export type StoreEventCarrier = {
|
|
|
258
260
|
}
|
|
259
261
|
|
|
260
262
|
declare global {
|
|
261
|
-
var ATOM_IO_IMPLICIT_STORE:
|
|
263
|
+
var ATOM_IO_IMPLICIT_STORE: RootStore | undefined
|
|
262
264
|
}
|
|
263
265
|
|
|
264
|
-
export const IMPLICIT: { readonly STORE:
|
|
265
|
-
get STORE():
|
|
266
|
+
export const IMPLICIT: { readonly STORE: RootStore } = {
|
|
267
|
+
get STORE(): RootStore {
|
|
266
268
|
globalThis.ATOM_IO_IMPLICIT_STORE ??= new Store({
|
|
267
269
|
name: `IMPLICIT_STORE`,
|
|
268
270
|
lifespan: `ephemeral`,
|
|
269
|
-
})
|
|
271
|
+
}) as RootStore
|
|
270
272
|
return globalThis.ATOM_IO_IMPLICIT_STORE
|
|
271
273
|
},
|
|
272
274
|
}
|
|
@@ -4,13 +4,16 @@ import type {
|
|
|
4
4
|
AtomUpdateEvent,
|
|
5
5
|
StateCreationEvent,
|
|
6
6
|
StateDisposalEvent,
|
|
7
|
+
StateUpdate,
|
|
7
8
|
TimelineEvent,
|
|
8
9
|
TimelineManageable,
|
|
9
10
|
TimelineOptions,
|
|
11
|
+
TimelineSelectorUpdateEvent,
|
|
10
12
|
TimelineToken,
|
|
11
13
|
TransactionOutcomeEvent,
|
|
12
14
|
TransactionSubEvent,
|
|
13
15
|
TransactionToken,
|
|
16
|
+
WritablePureSelectorToken,
|
|
14
17
|
} from "atom.io"
|
|
15
18
|
|
|
16
19
|
import { reduceReference } from "../get-state/reduce-reference"
|
|
@@ -18,27 +21,24 @@ import { newest } from "../lineage"
|
|
|
18
21
|
import { getUpdateToken } from "../mutable"
|
|
19
22
|
import { deposit, type Store, withdraw } from "../store"
|
|
20
23
|
import { Subject } from "../subject"
|
|
24
|
+
import type { RootStore } from "../transaction"
|
|
21
25
|
import { isChildStore } from "../transaction"
|
|
22
26
|
|
|
23
27
|
export type Timeline<ManagedAtom extends TimelineManageable> = {
|
|
24
28
|
type: `timeline`
|
|
25
29
|
key: string
|
|
26
30
|
at: number
|
|
27
|
-
shouldCapture?: (
|
|
28
|
-
update: TimelineEvent<ManagedAtom>,
|
|
29
|
-
timeline: Timeline<ManagedAtom>,
|
|
30
|
-
) => boolean
|
|
31
31
|
timeTraveling: `into_future` | `into_past` | null
|
|
32
32
|
history: TimelineEvent<ManagedAtom>[]
|
|
33
33
|
selectorTime: number | null
|
|
34
34
|
transactionKey: string | null
|
|
35
|
-
install: (store:
|
|
35
|
+
install: (store: RootStore) => void
|
|
36
36
|
subject: Subject<TimelineEvent<ManagedAtom> | `redo` | `undo`>
|
|
37
37
|
subscriptions: Map<string, () => void>
|
|
38
38
|
}
|
|
39
39
|
|
|
40
40
|
export function createTimeline<ManagedAtom extends TimelineManageable>(
|
|
41
|
-
store:
|
|
41
|
+
store: RootStore,
|
|
42
42
|
options: TimelineOptions<ManagedAtom>,
|
|
43
43
|
data?: Timeline<ManagedAtom>,
|
|
44
44
|
): TimelineToken<ManagedAtom> {
|
|
@@ -46,7 +46,6 @@ export function createTimeline<ManagedAtom extends TimelineManageable>(
|
|
|
46
46
|
type: `timeline`,
|
|
47
47
|
key: options.key,
|
|
48
48
|
at: 0,
|
|
49
|
-
|
|
50
49
|
timeTraveling: null,
|
|
51
50
|
selectorTime: null,
|
|
52
51
|
transactionKey: null,
|
|
@@ -56,9 +55,7 @@ export function createTimeline<ManagedAtom extends TimelineManageable>(
|
|
|
56
55
|
subject: new Subject(),
|
|
57
56
|
subscriptions: new Map(),
|
|
58
57
|
}
|
|
59
|
-
|
|
60
|
-
tl.shouldCapture = options.shouldCapture
|
|
61
|
-
}
|
|
58
|
+
|
|
62
59
|
const timelineKey = options.key
|
|
63
60
|
const target = newest(store)
|
|
64
61
|
for (const initialTopic of options.scope) {
|
|
@@ -182,93 +179,32 @@ function addAtomToTimeline(
|
|
|
182
179
|
if (txUpdateInProgress) {
|
|
183
180
|
joinTransaction(store, tl, txUpdateInProgress)
|
|
184
181
|
} else if (currentSelectorToken && currentSelectorTime) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
atomUpdates: [],
|
|
194
|
-
}
|
|
195
|
-
latestUpdate.atomUpdates.push({
|
|
196
|
-
type: `atom_update`,
|
|
197
|
-
token: atomToken,
|
|
198
|
-
update,
|
|
199
|
-
timestamp: Date.now(), // 👺 use store operation
|
|
200
|
-
})
|
|
201
|
-
if (tl.at !== tl.history.length) {
|
|
202
|
-
tl.history.splice(tl.at)
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
tl.history.push(latestUpdate)
|
|
206
|
-
|
|
207
|
-
store.logger.info(
|
|
208
|
-
`⌛`,
|
|
209
|
-
`timeline`,
|
|
210
|
-
tl.key,
|
|
211
|
-
`got a selector_update "${currentSelectorToken.key}" with`,
|
|
212
|
-
latestUpdate.atomUpdates.map(
|
|
213
|
-
(atomUpdate) => atomUpdate.token.key,
|
|
214
|
-
),
|
|
215
|
-
)
|
|
216
|
-
|
|
217
|
-
tl.at = tl.history.length
|
|
218
|
-
tl.selectorTime = currentSelectorTime
|
|
219
|
-
} else {
|
|
220
|
-
if (latestUpdate?.type === `selector_update`) {
|
|
221
|
-
latestUpdate.atomUpdates.push({
|
|
222
|
-
type: `atom_update`,
|
|
223
|
-
token: atomToken,
|
|
224
|
-
update,
|
|
225
|
-
timestamp: Date.now(), // 👺 use store operation
|
|
226
|
-
})
|
|
227
|
-
store.logger.info(
|
|
228
|
-
`⌛`,
|
|
229
|
-
`timeline`,
|
|
230
|
-
tl.key,
|
|
231
|
-
`set selector_update "${currentSelectorToken.key}" to`,
|
|
232
|
-
latestUpdate?.atomUpdates.map(
|
|
233
|
-
(atomUpdate) => atomUpdate.token.key,
|
|
234
|
-
),
|
|
235
|
-
)
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
if (latestUpdate) {
|
|
239
|
-
const willCaptureSelectorUpdate =
|
|
240
|
-
tl.shouldCapture?.(latestUpdate, tl) ?? true
|
|
241
|
-
if (willCaptureSelectorUpdate) {
|
|
242
|
-
tl.subject.next(latestUpdate)
|
|
243
|
-
} else {
|
|
244
|
-
tl.history.pop()
|
|
245
|
-
tl.at = tl.history.length
|
|
246
|
-
}
|
|
247
|
-
}
|
|
182
|
+
buildSelectorUpdate(
|
|
183
|
+
store,
|
|
184
|
+
tl,
|
|
185
|
+
atomToken,
|
|
186
|
+
update,
|
|
187
|
+
currentSelectorToken,
|
|
188
|
+
currentSelectorTime,
|
|
189
|
+
)
|
|
248
190
|
} else {
|
|
249
191
|
const timestamp = Date.now()
|
|
250
192
|
tl.selectorTime = null
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
const atomUpdate: AtomUpdateEvent<any> = {
|
|
193
|
+
|
|
194
|
+
const atomUpdate: AtomUpdateEvent<any> & TimelineEvent<any> = {
|
|
195
|
+
checkpoint: true,
|
|
255
196
|
type: `atom_update`,
|
|
256
197
|
token: deposit(atom),
|
|
257
198
|
update,
|
|
258
199
|
timestamp,
|
|
259
200
|
}
|
|
260
|
-
const willCapture = tl.shouldCapture?.(atomUpdate, tl) ?? true
|
|
261
201
|
store.logger.info(
|
|
262
202
|
`⌛`,
|
|
263
203
|
`timeline`,
|
|
264
204
|
tl.key,
|
|
265
205
|
`got an atom_update to "${atom.key}"`,
|
|
266
206
|
)
|
|
267
|
-
|
|
268
|
-
tl.history.push(atomUpdate)
|
|
269
|
-
tl.at = tl.history.length
|
|
270
|
-
tl.subject.next(atomUpdate)
|
|
271
|
-
}
|
|
207
|
+
addToHistory(tl, atomUpdate)
|
|
272
208
|
}
|
|
273
209
|
}
|
|
274
210
|
},
|
|
@@ -322,10 +258,6 @@ function joinTransaction(
|
|
|
322
258
|
unsubscribe()
|
|
323
259
|
tl.transactionKey = null
|
|
324
260
|
if (tl.timeTraveling === null && currentTxInstanceId) {
|
|
325
|
-
if (tl.at !== tl.history.length) {
|
|
326
|
-
tl.history.splice(tl.at)
|
|
327
|
-
}
|
|
328
|
-
|
|
329
261
|
// biome-ignore lint/style/noNonNullAssertion: we are in the context of this timeline
|
|
330
262
|
const timelineTopics = store.timelineTopics.getRelatedKeys(tl.key)!
|
|
331
263
|
|
|
@@ -334,22 +266,96 @@ function joinTransaction(
|
|
|
334
266
|
timelineTopics,
|
|
335
267
|
)
|
|
336
268
|
|
|
337
|
-
const timelineTransactionUpdate:
|
|
338
|
-
TransactionToken<any
|
|
339
|
-
|
|
269
|
+
const timelineTransactionUpdate: TimelineEvent<any> &
|
|
270
|
+
TransactionOutcomeEvent<TransactionToken<any>> = {
|
|
271
|
+
checkpoint: true,
|
|
340
272
|
...transactionUpdate,
|
|
341
273
|
subEvents: subEventsFiltered,
|
|
342
274
|
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
275
|
+
|
|
276
|
+
addToHistory(tl, timelineTransactionUpdate)
|
|
277
|
+
}
|
|
278
|
+
},
|
|
279
|
+
)
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function buildSelectorUpdate(
|
|
284
|
+
store: Store,
|
|
285
|
+
tl: Timeline<any>,
|
|
286
|
+
atomToken: AtomToken<any>,
|
|
287
|
+
eventOrUpdate: StateCreationEvent<any> | StateUpdate<any>,
|
|
288
|
+
currentSelectorToken: WritablePureSelectorToken<any>,
|
|
289
|
+
currentSelectorTime: number,
|
|
290
|
+
) {
|
|
291
|
+
let latestUpdate: TimelineEvent<any> | undefined = tl.history.at(-1)
|
|
292
|
+
if (currentSelectorTime !== tl.selectorTime) {
|
|
293
|
+
const selectorUpdate: TimelineEvent<any> & TimelineSelectorUpdateEvent<any> =
|
|
294
|
+
(latestUpdate = {
|
|
295
|
+
checkpoint: true,
|
|
296
|
+
type: `selector_update`,
|
|
297
|
+
timestamp: currentSelectorTime,
|
|
298
|
+
token: currentSelectorToken,
|
|
299
|
+
subEvents: [],
|
|
300
|
+
})
|
|
301
|
+
if (`type` in eventOrUpdate) {
|
|
302
|
+
latestUpdate.subEvents.push(eventOrUpdate)
|
|
303
|
+
} else {
|
|
304
|
+
latestUpdate.subEvents.push({
|
|
305
|
+
type: `atom_update`,
|
|
306
|
+
token: atomToken,
|
|
307
|
+
update: eventOrUpdate,
|
|
308
|
+
timestamp: Date.now(), // 👺 use store operation
|
|
309
|
+
})
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
addToHistory(tl, latestUpdate)
|
|
313
|
+
tl.selectorTime = currentSelectorTime
|
|
314
|
+
|
|
315
|
+
store.logger.info(
|
|
316
|
+
`⌛`,
|
|
317
|
+
`timeline`,
|
|
318
|
+
tl.key,
|
|
319
|
+
`got a selector_update "${currentSelectorToken.key}" with`,
|
|
320
|
+
latestUpdate.subEvents.map((event) => event.token.key),
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
const operation = store.operation
|
|
324
|
+
const unsub = store.on.operationClose.subscribe(
|
|
325
|
+
`timeline:${tl.key} (needs to gather nested selector creations)`,
|
|
326
|
+
() => {
|
|
327
|
+
unsub()
|
|
328
|
+
if (operation.open) {
|
|
329
|
+
selectorUpdate.subEvents = [
|
|
330
|
+
...operation.subEvents,
|
|
331
|
+
...selectorUpdate.subEvents,
|
|
332
|
+
]
|
|
350
333
|
}
|
|
351
334
|
},
|
|
352
335
|
)
|
|
336
|
+
} else {
|
|
337
|
+
if (latestUpdate?.type === `selector_update`) {
|
|
338
|
+
if (`type` in eventOrUpdate) {
|
|
339
|
+
latestUpdate.subEvents.push(eventOrUpdate)
|
|
340
|
+
} else {
|
|
341
|
+
latestUpdate.subEvents.push({
|
|
342
|
+
type: `atom_update`,
|
|
343
|
+
token: atomToken,
|
|
344
|
+
update: eventOrUpdate,
|
|
345
|
+
timestamp: Date.now(), // 👺 use store operation
|
|
346
|
+
})
|
|
347
|
+
}
|
|
348
|
+
store.logger.info(
|
|
349
|
+
`⌛`,
|
|
350
|
+
`timeline`,
|
|
351
|
+
tl.key,
|
|
352
|
+
`set selector_update "${currentSelectorToken.key}" to`,
|
|
353
|
+
latestUpdate?.subEvents.map((event) => event.token.key),
|
|
354
|
+
)
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
if (latestUpdate) {
|
|
358
|
+
tl.subject.next(latestUpdate)
|
|
353
359
|
}
|
|
354
360
|
}
|
|
355
361
|
|
|
@@ -402,6 +408,16 @@ function handleStateLifecycleEvent(
|
|
|
402
408
|
event: StateCreationEvent<any> | StateDisposalEvent<any>,
|
|
403
409
|
tl: Timeline<any>,
|
|
404
410
|
): void {
|
|
411
|
+
const currentSelectorToken =
|
|
412
|
+
store.operation.open &&
|
|
413
|
+
store.operation.token.type === `writable_pure_selector`
|
|
414
|
+
? store.operation.token
|
|
415
|
+
: null
|
|
416
|
+
const currentSelectorTime =
|
|
417
|
+
store.operation.open &&
|
|
418
|
+
store.operation.token.type === `writable_pure_selector`
|
|
419
|
+
? store.operation.timestamp
|
|
420
|
+
: null
|
|
405
421
|
if (!tl.timeTraveling) {
|
|
406
422
|
const target = newest(store)
|
|
407
423
|
if (isChildStore(target)) {
|
|
@@ -410,10 +426,21 @@ function handleStateLifecycleEvent(
|
|
|
410
426
|
const txUpdateInProgress = target.on.transactionApplying.state
|
|
411
427
|
if (txUpdateInProgress) {
|
|
412
428
|
joinTransaction(store, tl, txUpdateInProgress.update)
|
|
429
|
+
} else if (
|
|
430
|
+
currentSelectorToken &&
|
|
431
|
+
currentSelectorTime &&
|
|
432
|
+
event.type === `state_creation`
|
|
433
|
+
) {
|
|
434
|
+
buildSelectorUpdate(
|
|
435
|
+
store,
|
|
436
|
+
tl,
|
|
437
|
+
event.token,
|
|
438
|
+
event,
|
|
439
|
+
currentSelectorToken,
|
|
440
|
+
currentSelectorTime,
|
|
441
|
+
)
|
|
413
442
|
} else {
|
|
414
|
-
tl
|
|
415
|
-
tl.at = tl.history.length
|
|
416
|
-
tl.subject.next(event)
|
|
443
|
+
addToHistory(tl, event)
|
|
417
444
|
}
|
|
418
445
|
}
|
|
419
446
|
}
|
|
@@ -427,3 +454,12 @@ function handleStateLifecycleEvent(
|
|
|
427
454
|
break
|
|
428
455
|
}
|
|
429
456
|
}
|
|
457
|
+
|
|
458
|
+
function addToHistory(tl: Timeline<any>, event: TimelineEvent<any>): void {
|
|
459
|
+
if (tl.at !== tl.history.length) {
|
|
460
|
+
tl.history.splice(tl.at)
|
|
461
|
+
}
|
|
462
|
+
tl.history.push(event)
|
|
463
|
+
tl.at = tl.history.length
|
|
464
|
+
tl.subject.next(event)
|
|
465
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TimelineToken } from "atom.io"
|
|
1
|
+
import type { TimelineEvent, TimelineToken } from "atom.io"
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
ingestAtomUpdateEvent,
|
|
@@ -30,6 +30,7 @@ export const timeTravel = (
|
|
|
30
30
|
)
|
|
31
31
|
return
|
|
32
32
|
}
|
|
33
|
+
|
|
33
34
|
if (
|
|
34
35
|
(action === `redo` && timelineData.at === timelineData.history.length) ||
|
|
35
36
|
(action === `undo` && timelineData.at === 0)
|
|
@@ -46,46 +47,57 @@ export const timeTravel = (
|
|
|
46
47
|
}
|
|
47
48
|
|
|
48
49
|
timelineData.timeTraveling = action === `redo` ? `into_future` : `into_past`
|
|
49
|
-
|
|
50
|
-
|
|
50
|
+
let nextIndex = timelineData.at
|
|
51
|
+
let events: TimelineEvent<any>[]
|
|
52
|
+
switch (action) {
|
|
53
|
+
case `undo`:
|
|
54
|
+
--nextIndex
|
|
55
|
+
while (
|
|
56
|
+
nextIndex !== 0 &&
|
|
57
|
+
timelineData.history[nextIndex].checkpoint !== true
|
|
58
|
+
) {
|
|
59
|
+
--nextIndex
|
|
60
|
+
}
|
|
61
|
+
events = timelineData.history.slice(nextIndex, timelineData.at).reverse()
|
|
62
|
+
|
|
63
|
+
break
|
|
64
|
+
case `redo`:
|
|
65
|
+
++nextIndex
|
|
66
|
+
events = timelineData.history.slice(timelineData.at, nextIndex)
|
|
51
67
|
}
|
|
68
|
+
timelineData.at = nextIndex
|
|
52
69
|
|
|
53
|
-
const event = timelineData.history[timelineData.at]
|
|
54
70
|
const applying = action === `redo` ? `newValue` : `oldValue`
|
|
55
71
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
for (const event of events) {
|
|
73
|
+
switch (event.type) {
|
|
74
|
+
case `atom_update`: {
|
|
75
|
+
ingestAtomUpdateEvent(store, event, applying)
|
|
76
|
+
break
|
|
77
|
+
}
|
|
78
|
+
case `selector_update`: {
|
|
79
|
+
ingestSelectorUpdateEvent(store, event, applying)
|
|
80
|
+
break
|
|
81
|
+
}
|
|
82
|
+
case `transaction_outcome`: {
|
|
83
|
+
ingestTransactionOutcomeEvent(store, event, applying)
|
|
84
|
+
break
|
|
85
|
+
}
|
|
86
|
+
case `state_creation`: {
|
|
87
|
+
ingestCreationEvent(store, event, applying)
|
|
88
|
+
break
|
|
89
|
+
}
|
|
90
|
+
case `state_disposal`: {
|
|
91
|
+
ingestDisposalEvent(store, event, applying)
|
|
92
|
+
break
|
|
93
|
+
}
|
|
72
94
|
}
|
|
73
|
-
case `state_disposal`: {
|
|
74
|
-
ingestDisposalEvent(store, event, applying)
|
|
75
|
-
break
|
|
76
|
-
}
|
|
77
|
-
case `molecule_creation`:
|
|
78
|
-
case `molecule_disposal`:
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
if (action === `redo`) {
|
|
82
|
-
++timelineData.at
|
|
83
95
|
}
|
|
84
96
|
|
|
85
97
|
timelineData.subject.next(action)
|
|
86
98
|
timelineData.timeTraveling = null
|
|
87
99
|
store.logger.info(
|
|
88
|
-
|
|
100
|
+
`⏸️`,
|
|
89
101
|
`timeline`,
|
|
90
102
|
token.key,
|
|
91
103
|
`"${token.key}" is now at ${timelineData.at} / ${timelineData.history.length}`,
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import type { Store } from "../store"
|
|
3
|
-
import { isChildStore } from "./is-root-store"
|
|
1
|
+
import type { ChildStore } from "./is-root-store"
|
|
4
2
|
|
|
5
|
-
export const abortTransaction = (
|
|
6
|
-
|
|
7
|
-
if (!isChildStore(target)) {
|
|
8
|
-
store.logger.warn(
|
|
9
|
-
`🐞`,
|
|
10
|
-
`transaction`,
|
|
11
|
-
`???`,
|
|
12
|
-
`abortTransaction called outside of a transaction. This is probably a bug in AtomIO.`,
|
|
13
|
-
)
|
|
14
|
-
return
|
|
15
|
-
}
|
|
16
|
-
store.logger.info(
|
|
3
|
+
export const abortTransaction = (target: ChildStore): void => {
|
|
4
|
+
target.logger.info(
|
|
17
5
|
`🪂`,
|
|
18
6
|
`transaction`,
|
|
19
7
|
target.transactionMeta.update.token.key,
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { TransactionToken } from "atom.io"
|
|
2
2
|
|
|
3
|
-
import { NotFoundError } from "../not-found-error"
|
|
4
3
|
import type { Store } from "../store"
|
|
5
4
|
import { withdraw } from "../store"
|
|
6
5
|
import type { Fn } from "../utility-types"
|
|
@@ -12,9 +11,6 @@ export function actUponStore<F extends Fn>(
|
|
|
12
11
|
): (...parameters: Parameters<F>) => ReturnType<F> {
|
|
13
12
|
return (...parameters: Parameters<F>): ReturnType<F> => {
|
|
14
13
|
const tx = withdraw(store, token)
|
|
15
|
-
|
|
16
|
-
return tx.run(parameters, id)
|
|
17
|
-
}
|
|
18
|
-
throw new NotFoundError(token, store)
|
|
14
|
+
return tx.run(parameters, id)
|
|
19
15
|
}
|
|
20
16
|
}
|
|
@@ -1,30 +1,18 @@
|
|
|
1
1
|
import { ingestTransactionOutcomeEvent } from "../events"
|
|
2
2
|
import { newest } from "../lineage"
|
|
3
|
-
import type { Store } from "../store"
|
|
4
3
|
import { withdraw } from "../store"
|
|
5
4
|
import type { Fn } from "../utility-types"
|
|
5
|
+
import type { ChildStore } from "./is-root-store"
|
|
6
6
|
import { isChildStore, isRootStore } from "./is-root-store"
|
|
7
7
|
import { setEpochNumberOfAction } from "./set-epoch-number"
|
|
8
8
|
|
|
9
9
|
export function applyTransaction<F extends Fn>(
|
|
10
|
-
store:
|
|
10
|
+
store: ChildStore,
|
|
11
11
|
output: ReturnType<F>,
|
|
12
12
|
): void {
|
|
13
13
|
const child = newest(store)
|
|
14
14
|
const { parent } = child
|
|
15
|
-
|
|
16
|
-
parent === null ||
|
|
17
|
-
!isChildStore(child) ||
|
|
18
|
-
child.transactionMeta?.phase !== `building`
|
|
19
|
-
) {
|
|
20
|
-
store.logger.warn(
|
|
21
|
-
`🐞`,
|
|
22
|
-
`transaction`,
|
|
23
|
-
`???`,
|
|
24
|
-
`applyTransaction called outside of a transaction. This is probably a bug in AtomIO.`,
|
|
25
|
-
)
|
|
26
|
-
return
|
|
27
|
-
}
|
|
15
|
+
|
|
28
16
|
child.transactionMeta.phase = `applying`
|
|
29
17
|
child.transactionMeta.update.output = output
|
|
30
18
|
parent.child = null
|
|
@@ -34,7 +22,7 @@ export function applyTransaction<F extends Fn>(
|
|
|
34
22
|
`🛄`,
|
|
35
23
|
`transaction`,
|
|
36
24
|
child.transactionMeta.update.token.key,
|
|
37
|
-
`
|
|
25
|
+
`applying ${updates.length} subEvents:`,
|
|
38
26
|
updates,
|
|
39
27
|
)
|
|
40
28
|
|
|
@@ -55,7 +43,7 @@ export function applyTransaction<F extends Fn>(
|
|
|
55
43
|
`🛬`,
|
|
56
44
|
`transaction`,
|
|
57
45
|
child.transactionMeta.update.token.key,
|
|
58
|
-
`
|
|
46
|
+
`applied`,
|
|
59
47
|
)
|
|
60
48
|
} else if (isChildStore(parent)) {
|
|
61
49
|
parent.transactionMeta.update.subEvents.push(child.transactionMeta.update)
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import { isRootStore } from "./is-root-store"
|
|
1
|
+
import type { RootStore } from "./is-root-store"
|
|
3
2
|
|
|
4
3
|
export function assignTransactionToContinuity(
|
|
5
|
-
store:
|
|
4
|
+
store: RootStore,
|
|
6
5
|
continuityKey: string,
|
|
7
6
|
transactionKey: string,
|
|
8
7
|
): void {
|
|
9
|
-
const isRoot = isRootStore(store)
|
|
10
|
-
if (!isRoot) {
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
8
|
const { epoch, actionContinuities } = store.transactionMeta
|
|
14
9
|
actionContinuities.set(continuityKey, transactionKey)
|
|
15
10
|
if (!epoch.has(continuityKey)) {
|