atom.io 0.19.0 → 0.19.2
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.cjs +99 -79
- package/data/dist/index.js +2 -2
- package/data/src/join.ts +91 -74
- package/dist/{chunk-YDOGCZ53.js → chunk-ATKDGVTV.js} +29 -29
- package/dist/{chunk-CVBEVTM5.js → chunk-CC7IF7QF.js} +5 -42
- package/dist/{chunk-WX2NCOZR.js → chunk-FTONNX2R.js} +8 -8
- package/dist/{chunk-7ZR244C2.js → chunk-MSCJWACE.js} +92 -72
- package/dist/index.cjs +15 -7
- package/dist/index.d.ts +24 -35
- package/dist/index.js +15 -7
- package/internal/dist/index.cjs +56 -44
- package/internal/dist/index.d.ts +21 -21
- package/internal/dist/index.js +49 -37
- package/internal/src/atom/create-regular-atom.ts +7 -5
- package/internal/src/atom/delete-atom.ts +2 -2
- package/internal/src/families/create-readonly-selector-family.ts +2 -2
- package/internal/src/families/create-regular-atom-family.ts +1 -1
- package/internal/src/families/create-writable-selector-family.ts +1 -1
- package/internal/src/future.ts +4 -2
- package/internal/src/lineage.ts +1 -0
- package/internal/src/mutable/create-mutable-atom-family.ts +1 -1
- package/internal/src/mutable/create-mutable-atom.ts +7 -5
- package/internal/src/mutable/tracker.ts +4 -4
- package/internal/src/mutable/transceiver.ts +2 -2
- package/internal/src/selector/delete-selector.ts +1 -1
- package/internal/src/set-state/become.ts +1 -1
- package/internal/src/set-state/copy-mutable-if-needed.ts +1 -1
- package/internal/src/store/deposit.ts +5 -5
- package/internal/src/store/store.ts +5 -5
- package/internal/src/store/withdraw.ts +4 -5
- package/internal/src/subject.ts +3 -1
- package/internal/src/subscribe/subscribe-to-state.ts +2 -2
- package/internal/src/subscribe/subscribe-to-transaction.ts +4 -4
- package/internal/src/timeline/add-atom-to-timeline.ts +16 -11
- package/internal/src/timeline/create-timeline.ts +3 -4
- package/internal/src/transaction/act-upon-store.ts +5 -5
- package/internal/src/transaction/apply-transaction.ts +4 -4
- package/internal/src/transaction/build-transaction.ts +10 -7
- package/internal/src/transaction/create-transaction.ts +10 -10
- package/internal/src/transaction/index.ts +3 -3
- package/internal/src/transaction/is-root-store.ts +2 -2
- package/introspection/dist/index.cjs +3 -2
- package/introspection/dist/index.d.ts +6 -6
- package/introspection/dist/index.js +3 -2
- package/introspection/src/attach-atom-index.ts +5 -4
- package/introspection/src/attach-introspection-states.ts +3 -3
- package/introspection/src/attach-transaction-index.ts +4 -4
- package/introspection/src/attach-transaction-logs.ts +8 -4
- package/introspection/src/index.ts +3 -3
- package/json/dist/index.cjs +6 -2
- package/json/dist/index.d.ts +1 -1
- package/json/dist/index.js +8 -4
- package/json/src/select-json-family.ts +3 -2
- package/json/src/select-json.ts +3 -1
- package/package.json +243 -242
- package/react/dist/index.cjs +9 -3
- package/react/dist/index.js +9 -3
- package/react/src/use-i.ts +3 -1
- package/react/src/use-tl.ts +6 -2
- package/react-devtools/dist/index.cjs +332 -978
- package/react-devtools/dist/index.css +0 -18
- package/react-devtools/dist/index.d.ts +7 -9
- package/react-devtools/dist/index.js +291 -881
- package/react-devtools/src/AtomIODevtools.tsx +5 -2
- package/react-devtools/src/Button.tsx +6 -2
- package/react-devtools/src/StateEditor.tsx +13 -16
- package/react-devtools/src/StateIndex.tsx +28 -21
- package/react-devtools/src/TimelineIndex.tsx +17 -6
- package/react-devtools/src/TransactionIndex.tsx +13 -6
- package/react-devtools/src/Updates.tsx +24 -9
- package/realtime/dist/index.cjs +1 -0
- package/realtime/dist/index.d.ts +2 -2
- package/realtime/dist/index.js +1 -0
- package/realtime/src/realtime-continuity.ts +4 -3
- package/realtime-client/dist/index.cjs +29 -29
- package/realtime-client/dist/index.d.ts +2 -2
- package/realtime-client/dist/index.js +1 -1
- package/realtime-client/src/server-action.ts +2 -2
- package/realtime-client/src/sync-continuity.ts +23 -23
- package/realtime-react/dist/index.cjs +30 -30
- package/realtime-react/dist/index.d.ts +2 -2
- package/realtime-react/dist/index.js +2 -2
- package/realtime-react/src/use-server-action.ts +3 -3
- package/realtime-react/src/use-single-effect.ts +1 -1
- package/realtime-server/dist/index.cjs +54 -44
- package/realtime-server/dist/index.d.ts +6 -6
- package/realtime-server/dist/index.js +34 -24
- package/realtime-server/src/ipc-sockets/child-socket.ts +7 -7
- package/realtime-server/src/ipc-sockets/custom-socket.ts +4 -8
- package/realtime-server/src/ipc-sockets/parent-socket.ts +13 -7
- package/realtime-server/src/realtime-action-receiver.ts +7 -5
- package/realtime-server/src/realtime-continuity-synchronizer.ts +3 -3
- package/realtime-server/src/realtime-server-stores/server-room-external-store.ts +2 -2
- package/realtime-server/src/realtime-state-receiver.ts +3 -1
- package/realtime-testing/dist/index.cjs +15 -13
- package/realtime-testing/dist/index.js +9 -7
- package/realtime-testing/src/setup-realtime-test.tsx +7 -5
- package/src/atom.ts +4 -8
- package/src/dispose.ts +1 -0
- package/src/index.ts +2 -9
- package/src/selector.ts +4 -8
- package/src/silo.ts +13 -3
- package/src/subscribe.ts +6 -6
- package/src/timeline.ts +4 -4
- package/src/transaction.ts +24 -24
- package/src/validators.ts +2 -2
- package/transceivers/set-rtx/dist/index.cjs +11 -12
- package/transceivers/set-rtx/dist/index.js +11 -12
- package/transceivers/set-rtx/src/set-rtx.ts +10 -10
- /package/dist/{chunk-VAE5OCKN.js → chunk-BF4MVQF6.js} +0 -0
|
@@ -53,7 +53,7 @@ export const AtomIODevtools = (): JSX.Element => {
|
|
|
53
53
|
borderColor: `#0000`,
|
|
54
54
|
maxHeight: 28,
|
|
55
55
|
maxWidth: 33,
|
|
56
|
-
|
|
56
|
+
}
|
|
57
57
|
}
|
|
58
58
|
>
|
|
59
59
|
{devtoolsAreOpen ? (
|
|
@@ -65,8 +65,11 @@ export const AtomIODevtools = (): JSX.Element => {
|
|
|
65
65
|
<button
|
|
66
66
|
key={viewOption}
|
|
67
67
|
type="button"
|
|
68
|
+
data-testid={`view-${viewOption}`}
|
|
68
69
|
className={viewOption === devtoolsView ? `active` : ``}
|
|
69
|
-
onClick={() =>
|
|
70
|
+
onClick={() => {
|
|
71
|
+
setDevtoolsView(viewOption)
|
|
72
|
+
}}
|
|
70
73
|
disabled={viewOption === devtoolsView}
|
|
71
74
|
>
|
|
72
75
|
{viewOption}
|
|
@@ -5,12 +5,16 @@ export const OpenClose: FC<{
|
|
|
5
5
|
isOpen: boolean
|
|
6
6
|
setIsOpen: (next: Modify<boolean> | boolean) => void
|
|
7
7
|
disabled?: boolean
|
|
8
|
-
|
|
8
|
+
testid: string
|
|
9
|
+
}> = ({ isOpen, setIsOpen, disabled, testid }) => {
|
|
9
10
|
return (
|
|
10
11
|
<button
|
|
11
12
|
type="button"
|
|
13
|
+
data-testid={testid}
|
|
12
14
|
className={`carat ${isOpen ? `open` : `closed`}`}
|
|
13
|
-
onClick={() =>
|
|
15
|
+
onClick={() => {
|
|
16
|
+
setIsOpen((prev) => !prev)
|
|
17
|
+
}}
|
|
14
18
|
disabled={disabled}
|
|
15
19
|
>
|
|
16
20
|
▶
|
|
@@ -3,9 +3,7 @@ import { useI, useO } from "atom.io/react"
|
|
|
3
3
|
import type { FC } from "react"
|
|
4
4
|
|
|
5
5
|
import { fallback } from "~/packages/anvl/src/function"
|
|
6
|
-
import { Join } from "~/packages/anvl/src/join"
|
|
7
6
|
import { isJson } from "~/packages/anvl/src/refinement"
|
|
8
|
-
import { RelationEditor } from "~/packages/hamr/react-data-designer/src"
|
|
9
7
|
import { ElasticInput } from "~/packages/hamr/react-elastic-input/src"
|
|
10
8
|
import { JsonEditor } from "~/packages/hamr/react-json-editor/src"
|
|
11
9
|
|
|
@@ -16,19 +14,20 @@ export const StateEditor: FC<{
|
|
|
16
14
|
const data = useO(token)
|
|
17
15
|
return isJson(data) ? (
|
|
18
16
|
<JsonEditor data={data} set={set} schema={true} />
|
|
19
|
-
) : data instanceof Join ? (
|
|
20
|
-
<RelationEditor data={data} set={set} />
|
|
21
17
|
) : (
|
|
22
18
|
<div className="json_editor">
|
|
23
19
|
<ElasticInput
|
|
24
20
|
value={
|
|
25
|
-
data
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
21
|
+
data !== null &&
|
|
22
|
+
typeof data === `object` &&
|
|
23
|
+
`toJson` in data &&
|
|
24
|
+
typeof data.toJson === `function`
|
|
25
|
+
? JSON.stringify(data.toJson())
|
|
26
|
+
: data instanceof Set
|
|
27
|
+
? `Set { ${JSON.stringify([...data]).slice(1, -1)} }`
|
|
28
|
+
: Object.getPrototypeOf(data).constructor.name +
|
|
29
|
+
` ` +
|
|
30
|
+
fallback(() => JSON.stringify(data), `?`)
|
|
32
31
|
}
|
|
33
32
|
disabled={true}
|
|
34
33
|
/>
|
|
@@ -53,11 +52,9 @@ export const ReadonlySelectorViewer: FC<{
|
|
|
53
52
|
value={
|
|
54
53
|
data instanceof Set
|
|
55
54
|
? `Set ` + JSON.stringify([...data])
|
|
56
|
-
: data
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
` ` +
|
|
60
|
-
JSON.stringify(data)
|
|
55
|
+
: Object.getPrototypeOf(data).constructor.name +
|
|
56
|
+
` ` +
|
|
57
|
+
JSON.stringify(data)
|
|
61
58
|
}
|
|
62
59
|
disabled={true}
|
|
63
60
|
/>
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type {
|
|
2
|
+
AtomToken,
|
|
2
3
|
ReadonlySelectorToken,
|
|
3
4
|
RegularAtomToken,
|
|
4
5
|
WritableSelectorToken,
|
|
5
6
|
} from "atom.io"
|
|
6
|
-
import { getState, selectorFamily } from "atom.io"
|
|
7
|
+
import { findState, getState, selectorFamily } from "atom.io"
|
|
7
8
|
import type { FamilyNode, WritableTokenIndex } from "atom.io/introspection"
|
|
8
9
|
import { useI, useO } from "atom.io/react"
|
|
9
10
|
import type { FC } from "react"
|
|
@@ -34,8 +35,8 @@ const findStateTypeState = selectorFamily<string, { key: string }>({
|
|
|
34
35
|
|
|
35
36
|
export const StateIndexLeafNode: FC<{
|
|
36
37
|
node:
|
|
38
|
+
| AtomToken<unknown>
|
|
37
39
|
| ReadonlySelectorToken<unknown>
|
|
38
|
-
| RegularAtomToken<unknown>
|
|
39
40
|
| WritableSelectorToken<unknown>
|
|
40
41
|
isOpenState: RegularAtomToken<boolean>
|
|
41
42
|
typeState: ReadonlySelectorToken<string>
|
|
@@ -53,17 +54,22 @@ export const StateIndexLeafNode: FC<{
|
|
|
53
54
|
<header>
|
|
54
55
|
<button.OpenClose
|
|
55
56
|
isOpen={isOpen && !isPrimitive}
|
|
57
|
+
testid={`open-close-state-${node.key}`}
|
|
56
58
|
setIsOpen={setIsOpen}
|
|
57
59
|
disabled={isPrimitive}
|
|
58
60
|
/>
|
|
59
61
|
<label
|
|
60
|
-
onClick={() =>
|
|
61
|
-
|
|
62
|
+
onClick={() => {
|
|
63
|
+
console.log(node, getState(node))
|
|
64
|
+
}}
|
|
65
|
+
onKeyUp={() => {
|
|
66
|
+
console.log(node, getState(node))
|
|
67
|
+
}}
|
|
62
68
|
>
|
|
63
69
|
<h2>{node.family?.subKey ?? node.key}</h2>
|
|
64
70
|
<span className="type detail">({stateType})</span>
|
|
65
71
|
</label>
|
|
66
|
-
|
|
72
|
+
<StoreEditor token={node} />
|
|
67
73
|
</header>
|
|
68
74
|
{isOpen && !isPrimitive ? (
|
|
69
75
|
<main>
|
|
@@ -75,8 +81,8 @@ export const StateIndexLeafNode: FC<{
|
|
|
75
81
|
}
|
|
76
82
|
export const StateIndexTreeNode: FC<{
|
|
77
83
|
node: FamilyNode<
|
|
84
|
+
| AtomToken<unknown>
|
|
78
85
|
| ReadonlySelectorToken<unknown>
|
|
79
|
-
| RegularAtomToken<unknown>
|
|
80
86
|
| WritableSelectorToken<unknown>
|
|
81
87
|
>
|
|
82
88
|
isOpenState: RegularAtomToken<boolean>
|
|
@@ -84,13 +90,17 @@ export const StateIndexTreeNode: FC<{
|
|
|
84
90
|
const setIsOpen = useI(isOpenState)
|
|
85
91
|
const isOpen = useO(isOpenState)
|
|
86
92
|
for (const [key, childNode] of recordToEntries(node.familyMembers)) {
|
|
87
|
-
findViewIsOpenState
|
|
88
|
-
findStateTypeState
|
|
93
|
+
findState(findViewIsOpenState, key)
|
|
94
|
+
findState(findStateTypeState, childNode)
|
|
89
95
|
}
|
|
90
96
|
return (
|
|
91
97
|
<>
|
|
92
98
|
<header>
|
|
93
|
-
<button.OpenClose
|
|
99
|
+
<button.OpenClose
|
|
100
|
+
isOpen={isOpen}
|
|
101
|
+
testid={`open-close-state-family-${node.key}`}
|
|
102
|
+
setIsOpen={setIsOpen}
|
|
103
|
+
/>
|
|
94
104
|
<label>
|
|
95
105
|
<h2>{node.key}</h2>
|
|
96
106
|
<span className="type detail"> (family)</span>
|
|
@@ -101,10 +111,10 @@ export const StateIndexTreeNode: FC<{
|
|
|
101
111
|
<StateIndexNode
|
|
102
112
|
key={key}
|
|
103
113
|
node={childNode}
|
|
104
|
-
isOpenState={findViewIsOpenState
|
|
105
|
-
typeState={findStateTypeState
|
|
114
|
+
isOpenState={findState(findViewIsOpenState, childNode.key)}
|
|
115
|
+
typeState={findState(findStateTypeState, childNode)}
|
|
106
116
|
/>
|
|
107
|
-
|
|
117
|
+
))
|
|
108
118
|
: null}
|
|
109
119
|
</>
|
|
110
120
|
)
|
|
@@ -112,18 +122,15 @@ export const StateIndexTreeNode: FC<{
|
|
|
112
122
|
|
|
113
123
|
export const StateIndexNode: FC<{
|
|
114
124
|
node: WritableTokenIndex<
|
|
125
|
+
| AtomToken<unknown>
|
|
115
126
|
| ReadonlySelectorToken<unknown>
|
|
116
|
-
| RegularAtomToken<unknown>
|
|
117
127
|
| WritableSelectorToken<unknown>
|
|
118
128
|
>[string]
|
|
119
129
|
isOpenState: RegularAtomToken<boolean>
|
|
120
130
|
typeState: ReadonlySelectorToken<string>
|
|
121
131
|
}> = ({ node, isOpenState, typeState }) => {
|
|
122
|
-
if (node.key.startsWith(`👁🗨`)) {
|
|
123
|
-
return null
|
|
124
|
-
}
|
|
125
132
|
return (
|
|
126
|
-
<section className="node state">
|
|
133
|
+
<section className="node state" data-testid={`state-${node.key}`}>
|
|
127
134
|
{`type` in node ? (
|
|
128
135
|
<StateIndexLeafNode
|
|
129
136
|
node={node}
|
|
@@ -140,15 +147,15 @@ export const StateIndexNode: FC<{
|
|
|
140
147
|
export const StateIndex: FC<{
|
|
141
148
|
tokenIndex: ReadonlySelectorToken<
|
|
142
149
|
WritableTokenIndex<
|
|
150
|
+
| AtomToken<unknown>
|
|
143
151
|
| ReadonlySelectorToken<unknown>
|
|
144
|
-
| RegularAtomToken<unknown>
|
|
145
152
|
| WritableSelectorToken<unknown>
|
|
146
153
|
>
|
|
147
154
|
>
|
|
148
155
|
}> = ({ tokenIndex }) => {
|
|
149
156
|
const tokenIds = useO(tokenIndex)
|
|
150
157
|
return (
|
|
151
|
-
<article className="index state_index">
|
|
158
|
+
<article className="index state_index" data-testid="state-index">
|
|
152
159
|
{Object.entries(tokenIds)
|
|
153
160
|
.filter(([key]) => !key.startsWith(`👁🗨`))
|
|
154
161
|
.sort()
|
|
@@ -157,8 +164,8 @@ export const StateIndex: FC<{
|
|
|
157
164
|
<StateIndexNode
|
|
158
165
|
key={key}
|
|
159
166
|
node={node}
|
|
160
|
-
isOpenState={findViewIsOpenState
|
|
161
|
-
typeState={findStateTypeState
|
|
167
|
+
isOpenState={findState(findViewIsOpenState, node.key)}
|
|
168
|
+
typeState={findState(findStateTypeState, node)}
|
|
162
169
|
/>
|
|
163
170
|
)
|
|
164
171
|
})}
|
|
@@ -26,9 +26,13 @@ export const TimelineLog: FC<{
|
|
|
26
26
|
const setIsOpen = useI(isOpenState)
|
|
27
27
|
|
|
28
28
|
return (
|
|
29
|
-
<section className="node timeline_log">
|
|
29
|
+
<section className="node timeline_log" data-testid={`timeline-${token.key}`}>
|
|
30
30
|
<header>
|
|
31
|
-
<button.OpenClose
|
|
31
|
+
<button.OpenClose
|
|
32
|
+
isOpen={isOpen}
|
|
33
|
+
testid={`open-close-timeline-${token.key}`}
|
|
34
|
+
setIsOpen={setIsOpen}
|
|
35
|
+
/>
|
|
32
36
|
<label>
|
|
33
37
|
<h2>{token.key}</h2>
|
|
34
38
|
<span className="detail length">
|
|
@@ -38,14 +42,18 @@ export const TimelineLog: FC<{
|
|
|
38
42
|
<nav>
|
|
39
43
|
<button
|
|
40
44
|
type="button"
|
|
41
|
-
onClick={() =>
|
|
45
|
+
onClick={() => {
|
|
46
|
+
undo(token)
|
|
47
|
+
}}
|
|
42
48
|
disabled={timeline.at === 0}
|
|
43
49
|
>
|
|
44
50
|
undo
|
|
45
51
|
</button>
|
|
46
52
|
<button
|
|
47
53
|
type="button"
|
|
48
|
-
onClick={() =>
|
|
54
|
+
onClick={() => {
|
|
55
|
+
redo(token)
|
|
56
|
+
}}
|
|
49
57
|
disabled={timeline.at === timeline.history.length}
|
|
50
58
|
>
|
|
51
59
|
redo
|
|
@@ -58,7 +66,10 @@ export const TimelineLog: FC<{
|
|
|
58
66
|
{timeline.history.map((update, index) => (
|
|
59
67
|
<Fragment key={update.key + index + timeline.at}>
|
|
60
68
|
{index === timeline.at ? <YouAreHere /> : null}
|
|
61
|
-
<article.TimelineUpdate
|
|
69
|
+
<article.TimelineUpdate
|
|
70
|
+
timelineUpdate={update}
|
|
71
|
+
serialNumber={index}
|
|
72
|
+
/>
|
|
62
73
|
{index === timeline.history.length - 1 &&
|
|
63
74
|
timeline.at === timeline.history.length ? (
|
|
64
75
|
<YouAreHere />
|
|
@@ -74,7 +85,7 @@ export const TimelineLog: FC<{
|
|
|
74
85
|
export const TimelineIndex: FC = () => {
|
|
75
86
|
const tokenIds = useO(timelineIndex)
|
|
76
87
|
return (
|
|
77
|
-
<article className="index timeline_index">
|
|
88
|
+
<article className="index timeline_index" data-testid="timeline-index">
|
|
78
89
|
{tokenIds
|
|
79
90
|
.filter((token) => !token.key.startsWith(`👁🗨`))
|
|
80
91
|
.map((token) => {
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
type TransactionToken,
|
|
5
5
|
type TransactionUpdate,
|
|
6
6
|
findState,
|
|
7
|
-
type
|
|
7
|
+
type Func,
|
|
8
8
|
} from "atom.io"
|
|
9
9
|
import { useI, useO } from "atom.io/react"
|
|
10
10
|
import type { FC } from "react"
|
|
@@ -18,18 +18,25 @@ import { button } from "./Button"
|
|
|
18
18
|
import { article } from "./Updates"
|
|
19
19
|
|
|
20
20
|
export const TransactionLog: FC<{
|
|
21
|
-
token: TransactionToken
|
|
21
|
+
token: TransactionToken<Func>
|
|
22
22
|
isOpenState: RegularAtomToken<boolean>
|
|
23
|
-
logState: ReadonlySelectorToken<TransactionUpdate
|
|
23
|
+
logState: ReadonlySelectorToken<TransactionUpdate<Func>[]>
|
|
24
24
|
}> = ({ token, isOpenState, logState }) => {
|
|
25
25
|
const log = useO(logState)
|
|
26
26
|
const isOpen = useO(isOpenState)
|
|
27
27
|
const setIsOpen = useI(isOpenState)
|
|
28
28
|
|
|
29
29
|
return (
|
|
30
|
-
<section
|
|
30
|
+
<section
|
|
31
|
+
className="node transaction_log"
|
|
32
|
+
data-testid={`transaction-${token.key}`}
|
|
33
|
+
>
|
|
31
34
|
<header>
|
|
32
|
-
<button.OpenClose
|
|
35
|
+
<button.OpenClose
|
|
36
|
+
isOpen={isOpen}
|
|
37
|
+
testid={`open-close-transaction-${token.key}`}
|
|
38
|
+
setIsOpen={setIsOpen}
|
|
39
|
+
/>
|
|
33
40
|
<label>
|
|
34
41
|
<h2>{token.key}</h2>
|
|
35
42
|
<span className="detail length">({log.length})</span>
|
|
@@ -53,7 +60,7 @@ export const TransactionLog: FC<{
|
|
|
53
60
|
export const TransactionIndex: FC = () => {
|
|
54
61
|
const tokenIds = useO(transactionIndex)
|
|
55
62
|
return (
|
|
56
|
-
<article className="index transaction_index">
|
|
63
|
+
<article className="index transaction_index" data-testid="transaction-index">
|
|
57
64
|
{tokenIds
|
|
58
65
|
.filter((token) => !token.key.startsWith(`👁🗨`))
|
|
59
66
|
.map((token) => {
|
|
@@ -2,7 +2,7 @@ import type {
|
|
|
2
2
|
KeyedStateUpdate,
|
|
3
3
|
TimelineUpdate,
|
|
4
4
|
TransactionUpdate,
|
|
5
|
-
|
|
5
|
+
Func,
|
|
6
6
|
} from "atom.io"
|
|
7
7
|
import * as React from "react"
|
|
8
8
|
|
|
@@ -18,8 +18,12 @@ const AtomUpdateFC: React.FC<{
|
|
|
18
18
|
<article
|
|
19
19
|
key={atomUpdate.key}
|
|
20
20
|
className="node atom_update"
|
|
21
|
-
onClick={() =>
|
|
22
|
-
|
|
21
|
+
onClick={() => {
|
|
22
|
+
console.log(atomUpdate)
|
|
23
|
+
}}
|
|
24
|
+
onKeyUp={() => {
|
|
25
|
+
console.log(atomUpdate)
|
|
26
|
+
}}
|
|
23
27
|
>
|
|
24
28
|
<span className="detail">{atomUpdate.key}: </span>
|
|
25
29
|
<span>
|
|
@@ -33,10 +37,13 @@ const AtomUpdateFC: React.FC<{
|
|
|
33
37
|
|
|
34
38
|
const TransactionUpdateFC: React.FC<{
|
|
35
39
|
serialNumber: number
|
|
36
|
-
transactionUpdate: TransactionUpdate
|
|
40
|
+
transactionUpdate: TransactionUpdate<Func>
|
|
37
41
|
}> = ({ serialNumber, transactionUpdate }) => {
|
|
38
42
|
return (
|
|
39
|
-
<article
|
|
43
|
+
<article
|
|
44
|
+
className="node transaction_update"
|
|
45
|
+
data-testid={`transaction-update-${transactionUpdate.key}-${serialNumber}`}
|
|
46
|
+
>
|
|
40
47
|
<header>
|
|
41
48
|
<h4>{serialNumber}</h4>
|
|
42
49
|
</header>
|
|
@@ -48,8 +55,12 @@ const TransactionUpdateFC: React.FC<{
|
|
|
48
55
|
<article
|
|
49
56
|
key={`param` + index}
|
|
50
57
|
className="node transaction_param"
|
|
51
|
-
onClick={() =>
|
|
52
|
-
|
|
58
|
+
onClick={() => {
|
|
59
|
+
console.log(transactionUpdate)
|
|
60
|
+
}}
|
|
61
|
+
onKeyUp={() => {
|
|
62
|
+
console.log(transactionUpdate)
|
|
63
|
+
}}
|
|
53
64
|
>
|
|
54
65
|
<span className="detail">{discoverType(param)}: </span>
|
|
55
66
|
<span className="summary">
|
|
@@ -104,9 +115,13 @@ const TransactionUpdateFC: React.FC<{
|
|
|
104
115
|
|
|
105
116
|
export const TimelineUpdateFC: React.FC<{
|
|
106
117
|
timelineUpdate: TimelineUpdate<any>
|
|
107
|
-
|
|
118
|
+
serialNumber: number
|
|
119
|
+
}> = ({ timelineUpdate, serialNumber }) => {
|
|
108
120
|
return (
|
|
109
|
-
<article
|
|
121
|
+
<article
|
|
122
|
+
className="node timeline_update"
|
|
123
|
+
data-testid={`timeline-update-${timelineUpdate.key}-${serialNumber}`}
|
|
124
|
+
>
|
|
110
125
|
<header>
|
|
111
126
|
<h4>
|
|
112
127
|
{timelineUpdate.timestamp}: {timelineUpdate.type} ({timelineUpdate.key}
|
package/realtime/dist/index.cjs
CHANGED
|
@@ -24,6 +24,7 @@ var InvariantMap = class extends Map {
|
|
|
24
24
|
var _SyncGroup = class _SyncGroup {
|
|
25
25
|
constructor(key) {
|
|
26
26
|
this.key = key;
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
27
28
|
this.type = `continuity`;
|
|
28
29
|
this.globals = [];
|
|
29
30
|
this.actions = [];
|
package/realtime/dist/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ declare class InvariantMap<K, V> extends Map<K, V> {
|
|
|
8
8
|
set(key: K, value: V): this;
|
|
9
9
|
clear(): void;
|
|
10
10
|
}
|
|
11
|
-
type PerspectiveToken<F extends AtomFamilyToken<any>, T extends F extends AtomFamilyToken<infer
|
|
11
|
+
type PerspectiveToken<F extends AtomFamilyToken<any>, T extends F extends AtomFamilyToken<infer U, any> ? U : never> = {
|
|
12
12
|
type: `realtime_perspective`;
|
|
13
13
|
resourceAtoms: F;
|
|
14
14
|
viewAtoms: ReadableFamilyToken<ReadableToken<T>[], string>;
|
|
@@ -31,7 +31,7 @@ declare class SyncGroup {
|
|
|
31
31
|
static create(key: string, builder: (group: SyncGroup) => SyncGroup): ContinuityToken;
|
|
32
32
|
add(...atoms: AtomToken<any>[]): SyncGroup;
|
|
33
33
|
add(...args: TransactionToken<any>[]): SyncGroup;
|
|
34
|
-
add<F extends AtomFamilyToken<any>, T extends F extends AtomFamilyToken<infer
|
|
34
|
+
add<F extends AtomFamilyToken<any>, T extends F extends AtomFamilyToken<infer U> ? U : never>(family: AtomFamilyToken<T, any>, index: ReadableFamilyToken<Iterable<AtomToken<T>>, string>): SyncGroup;
|
|
35
35
|
}
|
|
36
36
|
type ContinuityOptions = {
|
|
37
37
|
key: string;
|
package/realtime/dist/index.js
CHANGED
|
@@ -22,6 +22,7 @@ var InvariantMap = class extends Map {
|
|
|
22
22
|
var _SyncGroup = class _SyncGroup {
|
|
23
23
|
constructor(key) {
|
|
24
24
|
this.key = key;
|
|
25
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
25
26
|
this.type = `continuity`;
|
|
26
27
|
this.globals = [];
|
|
27
28
|
this.actions = [];
|
|
@@ -32,7 +32,7 @@ export class InvariantMap<K, V> extends Map<K, V> {
|
|
|
32
32
|
|
|
33
33
|
export type PerspectiveToken<
|
|
34
34
|
F extends AtomFamilyToken<any>,
|
|
35
|
-
T extends F extends AtomFamilyToken<infer
|
|
35
|
+
T extends F extends AtomFamilyToken<infer U, any> ? U : never,
|
|
36
36
|
> = {
|
|
37
37
|
type: `realtime_perspective`
|
|
38
38
|
resourceAtoms: F
|
|
@@ -51,6 +51,7 @@ export type ContinuityToken = {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export class SyncGroup {
|
|
54
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
54
55
|
protected type = `continuity` as const
|
|
55
56
|
|
|
56
57
|
protected globals: AtomToken<any>[] = []
|
|
@@ -76,7 +77,7 @@ export class SyncGroup {
|
|
|
76
77
|
public add(...args: TransactionToken<any>[]): SyncGroup
|
|
77
78
|
public add<
|
|
78
79
|
F extends AtomFamilyToken<any>,
|
|
79
|
-
T extends F extends AtomFamilyToken<infer
|
|
80
|
+
T extends F extends AtomFamilyToken<infer U> ? U : never,
|
|
80
81
|
>(
|
|
81
82
|
family: AtomFamilyToken<T, any>,
|
|
82
83
|
index: ReadableFamilyToken<Iterable<AtomToken<T>>, string>,
|
|
@@ -86,7 +87,7 @@ export class SyncGroup {
|
|
|
86
87
|
| readonly AtomToken<any>[]
|
|
87
88
|
| readonly TransactionToken<any>[]
|
|
88
89
|
| [AtomFamilyToken<any, any>, ReadableFamilyToken<Iterable<any>, string>]
|
|
89
|
-
):
|
|
90
|
+
): this {
|
|
90
91
|
const zeroth = args[0]
|
|
91
92
|
if (zeroth.type === `atom` || zeroth.type === `mutable_atom`) {
|
|
92
93
|
const globals = args as AtomToken<any>[]
|
|
@@ -256,8 +256,8 @@ function syncContinuity(continuity, socket, store) {
|
|
|
256
256
|
};
|
|
257
257
|
socket.off(`continuity-init:${continuityKey}`);
|
|
258
258
|
socket.on(`continuity-init:${continuityKey}`, initializeContinuity);
|
|
259
|
-
const registerAndAttemptConfirmedUpdate = (
|
|
260
|
-
function reconcileEpoch(optimisticUpdate,
|
|
259
|
+
const registerAndAttemptConfirmedUpdate = (confirmed) => {
|
|
260
|
+
function reconcileEpoch(optimisticUpdate, confirmedUpdate) {
|
|
261
261
|
store.logger.info(
|
|
262
262
|
`\u{1F9D1}\u200D\u2696\uFE0F`,
|
|
263
263
|
`continuity`,
|
|
@@ -272,9 +272,9 @@ function syncContinuity(continuity, socket, store) {
|
|
|
272
272
|
},
|
|
273
273
|
store
|
|
274
274
|
);
|
|
275
|
-
if (optimisticUpdate.id ===
|
|
275
|
+
if (optimisticUpdate.id === confirmedUpdate.id) {
|
|
276
276
|
const clientResult = JSON.stringify(optimisticUpdate.updates);
|
|
277
|
-
const serverResult = JSON.stringify(
|
|
277
|
+
const serverResult = JSON.stringify(confirmedUpdate.updates);
|
|
278
278
|
if (clientResult === serverResult) {
|
|
279
279
|
store.logger.info(
|
|
280
280
|
`\u2705`,
|
|
@@ -282,7 +282,7 @@ function syncContinuity(continuity, socket, store) {
|
|
|
282
282
|
continuityKey,
|
|
283
283
|
`results for ${optimisticUpdate.id} match between client and server`
|
|
284
284
|
);
|
|
285
|
-
socket.emit(`ack:${continuityKey}`,
|
|
285
|
+
socket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch);
|
|
286
286
|
return;
|
|
287
287
|
}
|
|
288
288
|
} else {
|
|
@@ -290,7 +290,7 @@ function syncContinuity(continuity, socket, store) {
|
|
|
290
290
|
`\u274C`,
|
|
291
291
|
`continuity`,
|
|
292
292
|
continuityKey,
|
|
293
|
-
`thought update #${
|
|
293
|
+
`thought update #${confirmedUpdate.epoch} was ${optimisticUpdate.key}:${optimisticUpdate.id}, but it was actually ${confirmedUpdate.key}:${confirmedUpdate.id}`
|
|
294
294
|
);
|
|
295
295
|
}
|
|
296
296
|
store.logger.info(
|
|
@@ -299,7 +299,7 @@ function syncContinuity(continuity, socket, store) {
|
|
|
299
299
|
continuityKey,
|
|
300
300
|
`updates do not match`,
|
|
301
301
|
optimisticUpdate,
|
|
302
|
-
|
|
302
|
+
confirmedUpdate
|
|
303
303
|
);
|
|
304
304
|
const reversedOptimisticUpdates = optimisticUpdates.toReversed();
|
|
305
305
|
for (const subsequentOptimistic of reversedOptimisticUpdates) {
|
|
@@ -320,15 +320,15 @@ function syncContinuity(continuity, socket, store) {
|
|
|
320
320
|
`undid zeroth optimistic update`,
|
|
321
321
|
optimisticUpdate
|
|
322
322
|
);
|
|
323
|
-
Internal.ingestTransactionUpdate(`newValue`,
|
|
323
|
+
Internal.ingestTransactionUpdate(`newValue`, confirmedUpdate, store);
|
|
324
324
|
store.logger.info(
|
|
325
325
|
`\u23E9`,
|
|
326
326
|
`continuity`,
|
|
327
327
|
continuityKey,
|
|
328
328
|
`applied confirmed update`,
|
|
329
|
-
|
|
329
|
+
confirmedUpdate
|
|
330
330
|
);
|
|
331
|
-
socket.emit(`ack:${continuityKey}`,
|
|
331
|
+
socket.emit(`ack:${continuityKey}`, confirmedUpdate.epoch);
|
|
332
332
|
for (const subsequentOptimistic of optimisticUpdates) {
|
|
333
333
|
const token = {
|
|
334
334
|
type: `transaction`,
|
|
@@ -350,7 +350,7 @@ function syncContinuity(continuity, socket, store) {
|
|
|
350
350
|
`continuity`,
|
|
351
351
|
continuityKey,
|
|
352
352
|
`integrating confirmed update`,
|
|
353
|
-
{ confirmedUpdate, confirmedUpdates, optimisticUpdates }
|
|
353
|
+
{ confirmedUpdate: confirmed, confirmedUpdates, optimisticUpdates }
|
|
354
354
|
);
|
|
355
355
|
const zerothOptimisticUpdate = optimisticUpdates[0];
|
|
356
356
|
if (zerothOptimisticUpdate) {
|
|
@@ -360,14 +360,14 @@ function syncContinuity(continuity, socket, store) {
|
|
|
360
360
|
continuityKey,
|
|
361
361
|
`has optimistic updates to reconcile`
|
|
362
362
|
);
|
|
363
|
-
if (
|
|
363
|
+
if (confirmed.epoch === zerothOptimisticUpdate.epoch) {
|
|
364
364
|
store.logger.info(
|
|
365
365
|
`\u{1F9D1}\u200D\u2696\uFE0F`,
|
|
366
366
|
`continuity`,
|
|
367
367
|
continuityKey,
|
|
368
|
-
`epoch of confirmed update #${
|
|
368
|
+
`epoch of confirmed update #${confirmed.epoch} matches zeroth optimistic update`
|
|
369
369
|
);
|
|
370
|
-
reconcileEpoch(zerothOptimisticUpdate,
|
|
370
|
+
reconcileEpoch(zerothOptimisticUpdate, confirmed);
|
|
371
371
|
for (const nextConfirmed of confirmedUpdates) {
|
|
372
372
|
const nextOptimistic = optimisticUpdates[0];
|
|
373
373
|
if (nextConfirmed.epoch === (nextOptimistic == null ? void 0 : nextOptimistic.epoch)) {
|
|
@@ -381,10 +381,10 @@ function syncContinuity(continuity, socket, store) {
|
|
|
381
381
|
`\u{1F9D1}\u200D\u2696\uFE0F`,
|
|
382
382
|
`continuity`,
|
|
383
383
|
continuityKey,
|
|
384
|
-
`epoch of confirmed update #${
|
|
384
|
+
`epoch of confirmed update #${confirmed.epoch} does not match zeroth optimistic update #${zerothOptimisticUpdate.epoch}`
|
|
385
385
|
);
|
|
386
386
|
const confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(
|
|
387
|
-
(update) => update.epoch ===
|
|
387
|
+
(update) => update.epoch === confirmed.epoch
|
|
388
388
|
);
|
|
389
389
|
if (!confirmedUpdateIsAlreadyEnqueued) {
|
|
390
390
|
store.logger.info(
|
|
@@ -392,12 +392,12 @@ function syncContinuity(continuity, socket, store) {
|
|
|
392
392
|
`continuity`,
|
|
393
393
|
continuityKey,
|
|
394
394
|
`pushing confirmed update to queue`,
|
|
395
|
-
|
|
395
|
+
confirmed
|
|
396
396
|
);
|
|
397
397
|
Internal.setIntoStore(
|
|
398
398
|
realtimeClient.confirmedUpdateQueue,
|
|
399
399
|
(queue) => {
|
|
400
|
-
queue.push(
|
|
400
|
+
queue.push(confirmed);
|
|
401
401
|
queue.sort((a, b) => a.epoch - b.epoch);
|
|
402
402
|
return queue;
|
|
403
403
|
},
|
|
@@ -414,48 +414,48 @@ function syncContinuity(continuity, socket, store) {
|
|
|
414
414
|
);
|
|
415
415
|
const continuityEpoch = Internal.getEpochNumberOfContinuity(continuityKey, store);
|
|
416
416
|
const isRoot = Internal.isRootStore(store);
|
|
417
|
-
if (isRoot && continuityEpoch ===
|
|
417
|
+
if (isRoot && continuityEpoch === confirmed.epoch - 1) {
|
|
418
418
|
store.logger.info(
|
|
419
419
|
`\u2705`,
|
|
420
420
|
`continuity`,
|
|
421
421
|
continuityKey,
|
|
422
|
-
`integrating update #${
|
|
422
|
+
`integrating update #${confirmed.epoch} (${confirmed.key} ${confirmed.id})`
|
|
423
423
|
);
|
|
424
|
-
Internal.ingestTransactionUpdate(`newValue`,
|
|
425
|
-
socket.emit(`ack:${continuityKey}`,
|
|
426
|
-
Internal.setEpochNumberOfContinuity(continuityKey,
|
|
424
|
+
Internal.ingestTransactionUpdate(`newValue`, confirmed, store);
|
|
425
|
+
socket.emit(`ack:${continuityKey}`, confirmed.epoch);
|
|
426
|
+
Internal.setEpochNumberOfContinuity(continuityKey, confirmed.epoch, store);
|
|
427
427
|
} else if (isRoot && continuityEpoch !== void 0) {
|
|
428
428
|
store.logger.info(
|
|
429
429
|
`\u{1F9D1}\u200D\u2696\uFE0F`,
|
|
430
430
|
`continuity`,
|
|
431
431
|
continuityKey,
|
|
432
|
-
`received update #${
|
|
432
|
+
`received update #${confirmed.epoch} but still waiting for update #${continuityEpoch + 1}`,
|
|
433
433
|
{
|
|
434
434
|
clientEpoch: continuityEpoch,
|
|
435
|
-
serverEpoch:
|
|
435
|
+
serverEpoch: confirmed.epoch
|
|
436
436
|
}
|
|
437
437
|
);
|
|
438
438
|
const confirmedUpdateIsAlreadyEnqueued = confirmedUpdates.some(
|
|
439
|
-
(update) => update.epoch ===
|
|
439
|
+
(update) => update.epoch === confirmed.epoch
|
|
440
440
|
);
|
|
441
441
|
if (confirmedUpdateIsAlreadyEnqueued) {
|
|
442
442
|
store.logger.info(
|
|
443
443
|
`\u{1F44D}`,
|
|
444
444
|
`continuity`,
|
|
445
445
|
continuityKey,
|
|
446
|
-
`confirmed update #${
|
|
446
|
+
`confirmed update #${confirmed.epoch} is already enqueued`
|
|
447
447
|
);
|
|
448
448
|
} else {
|
|
449
449
|
store.logger.info(
|
|
450
450
|
`\u{1F448}`,
|
|
451
451
|
`continuity`,
|
|
452
452
|
continuityKey,
|
|
453
|
-
`pushing confirmed update #${
|
|
453
|
+
`pushing confirmed update #${confirmed.epoch} to queue`
|
|
454
454
|
);
|
|
455
455
|
Internal.setIntoStore(
|
|
456
456
|
realtimeClient.confirmedUpdateQueue,
|
|
457
457
|
(queue) => {
|
|
458
|
-
queue.push(
|
|
458
|
+
queue.push(confirmed);
|
|
459
459
|
queue.sort((a, b) => a.epoch - b.epoch);
|
|
460
460
|
return queue;
|
|
461
461
|
},
|