atom.io 0.6.8 → 0.6.9
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/index.d.mts +226 -258
- package/dist/index.d.ts +226 -258
- package/dist/index.js +28 -1917
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -1877
- package/dist/index.mjs.map +1 -1
- package/introspection/dist/index.d.mts +117 -171
- package/introspection/dist/index.d.ts +117 -171
- package/introspection/dist/index.js +6 -346
- package/introspection/dist/index.js.map +1 -1
- package/introspection/dist/index.mjs +5 -324
- package/introspection/dist/index.mjs.map +1 -1
- package/json/dist/index.d.mts +32 -1
- package/json/dist/index.d.ts +32 -1
- package/json/dist/index.js +31 -48
- package/json/dist/index.js.map +1 -1
- package/json/dist/index.mjs +6 -14
- package/json/dist/index.mjs.map +1 -1
- package/package.json +22 -14
- package/react/dist/index.js +34 -83
- package/react/dist/index.js.map +1 -1
- package/react/dist/index.mjs +7 -43
- package/react/dist/index.mjs.map +1 -1
- package/react-devtools/dist/index.css +1 -50
- package/react-devtools/dist/index.css.map +1 -1
- package/react-devtools/dist/index.d.mts +124 -188
- package/react-devtools/dist/index.d.ts +124 -188
- package/react-devtools/dist/index.js +56 -4674
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/dist/index.mjs +19 -4642
- package/react-devtools/dist/index.mjs.map +1 -1
- package/realtime/dist/index.d.mts +1 -3
- package/realtime/dist/index.d.ts +1 -3
- package/realtime/dist/index.js +26 -184
- package/realtime/dist/index.js.map +1 -1
- package/realtime/dist/index.mjs +4 -148
- package/realtime/dist/index.mjs.map +1 -1
- package/realtime-react/dist/index.d.mts +2 -4
- package/realtime-react/dist/index.d.ts +2 -4
- package/realtime-react/dist/index.js +41 -214
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/dist/index.mjs +9 -169
- package/realtime-react/dist/index.mjs.map +1 -1
- package/src/atom.ts +4 -3
- package/src/index.ts +12 -9
- package/src/logger.ts +5 -5
- package/src/selector.ts +3 -3
- package/src/silo.ts +36 -39
- package/src/subscribe.ts +24 -19
- package/src/timeline.ts +9 -4
- package/src/transaction.ts +3 -4
- package/src/internal/atom-internal.ts +0 -54
- package/src/internal/families-internal.ts +0 -144
- package/src/internal/get.ts +0 -129
- package/src/internal/index.ts +0 -15
- package/src/internal/is-default.ts +0 -35
- package/src/internal/operation.ts +0 -139
- package/src/internal/selector/create-read-write-selector.ts +0 -68
- package/src/internal/selector/create-readonly-selector.ts +0 -48
- package/src/internal/selector/index.ts +0 -4
- package/src/internal/selector/lookup-selector-sources.ts +0 -16
- package/src/internal/selector/register-selector.ts +0 -57
- package/src/internal/selector/trace-selector-atoms.ts +0 -43
- package/src/internal/selector/update-selector-atoms.ts +0 -33
- package/src/internal/selector-internal.ts +0 -58
- package/src/internal/set.ts +0 -99
- package/src/internal/store.ts +0 -151
- package/src/internal/subscribe-internal.ts +0 -88
- package/src/internal/time-travel-internal.ts +0 -91
- package/src/internal/timeline/add-atom-to-timeline.ts +0 -168
- package/src/internal/timeline/index.ts +0 -1
- package/src/internal/timeline-internal.ts +0 -107
- package/src/internal/transaction/abort-transaction.ts +0 -12
- package/src/internal/transaction/apply-transaction.ts +0 -57
- package/src/internal/transaction/build-transaction.ts +0 -33
- package/src/internal/transaction/index.ts +0 -25
- package/src/internal/transaction/redo-transaction.ts +0 -23
- package/src/internal/transaction/undo-transaction.ts +0 -23
- package/src/internal/transaction-internal.ts +0 -61
- package/src/introspection/attach-atom-index.ts +0 -73
- package/src/introspection/attach-introspection-states.ts +0 -42
- package/src/introspection/attach-selector-index.ts +0 -77
- package/src/introspection/attach-timeline-family.ts +0 -59
- package/src/introspection/attach-timeline-index.ts +0 -36
- package/src/introspection/attach-transaction-index.ts +0 -38
- package/src/introspection/attach-transaction-logs.ts +0 -40
- package/src/introspection/index.ts +0 -20
- package/src/json/index.ts +0 -1
- package/src/json/select-json.ts +0 -18
- package/src/react/index.ts +0 -2
- package/src/react/store-context.tsx +0 -13
- package/src/react/store-hooks.ts +0 -47
- package/src/react-devtools/AtomIODevtools.tsx +0 -107
- package/src/react-devtools/Button.tsx +0 -24
- package/src/react-devtools/StateEditor.tsx +0 -74
- package/src/react-devtools/StateIndex.tsx +0 -156
- package/src/react-devtools/TimelineIndex.tsx +0 -92
- package/src/react-devtools/TransactionIndex.tsx +0 -70
- package/src/react-devtools/Updates.tsx +0 -145
- package/src/react-devtools/devtools.scss +0 -310
- package/src/react-devtools/index.ts +0 -72
- package/src/react-explorer/AtomIOExplorer.tsx +0 -218
- package/src/react-explorer/explorer-effects.ts +0 -20
- package/src/react-explorer/explorer-states.ts +0 -217
- package/src/react-explorer/index.ts +0 -23
- package/src/react-explorer/space-states.ts +0 -72
- package/src/react-explorer/view-states.ts +0 -41
- package/src/realtime/README.md +0 -33
- package/src/realtime/hook-composition/expose-family.ts +0 -101
- package/src/realtime/hook-composition/expose-single.ts +0 -38
- package/src/realtime/hook-composition/expose-timeline.ts +0 -60
- package/src/realtime/hook-composition/index.ts +0 -12
- package/src/realtime/hook-composition/receive-state.ts +0 -29
- package/src/realtime/hook-composition/receive-transaction.ts +0 -18
- package/src/realtime/index.ts +0 -1
- package/src/realtime-react/index.ts +0 -3
- package/src/realtime-react/realtime-context.tsx +0 -30
- package/src/realtime-react/realtime-hooks.ts +0 -39
- package/src/realtime-react/realtime-state.ts +0 -10
- package/src/realtime-react/use-pull-family-member.ts +0 -26
- package/src/realtime-react/use-pull-family.ts +0 -24
- package/src/realtime-react/use-pull.ts +0 -24
- package/src/realtime-react/use-push.ts +0 -27
- package/src/realtime-react/use-server-action.ts +0 -33
- package/src/realtime-testing/index.ts +0 -1
- package/src/realtime-testing/setup-realtime-test.tsx +0 -159
- package/src/tracker/index.ts +0 -3
- package/src/tracker/tracker.ts +0 -61
- package/src/web-effects/index.ts +0 -1
- package/src/web-effects/storage.ts +0 -30
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
import { lastOf } from "~/packages/anvl/src/array"
|
|
2
|
-
import { now } from "~/packages/anvl/src/id"
|
|
3
|
-
import { Join } from "~/packages/anvl/src/join"
|
|
4
|
-
import type { Entries } from "~/packages/anvl/src/object"
|
|
5
|
-
|
|
6
|
-
import { addToIndex, removeFromIndex } from "."
|
|
7
|
-
import {
|
|
8
|
-
makeSpaceLayoutNodeFamily,
|
|
9
|
-
makeSpaceFamily,
|
|
10
|
-
makeSpaceIndex,
|
|
11
|
-
makeSpaceLayoutState,
|
|
12
|
-
} from "./space-states"
|
|
13
|
-
import type { View } from "./view-states"
|
|
14
|
-
import {
|
|
15
|
-
makeViewFocusedFamily,
|
|
16
|
-
makeViewFamily,
|
|
17
|
-
makeViewIndex,
|
|
18
|
-
} from "./view-states"
|
|
19
|
-
import type {
|
|
20
|
-
AtomFamily,
|
|
21
|
-
AtomToken,
|
|
22
|
-
ReadonlySelectorFamily,
|
|
23
|
-
SelectorFamily,
|
|
24
|
-
Write,
|
|
25
|
-
} from ".."
|
|
26
|
-
import { selectorFamily, selector, transaction, atom } from ".."
|
|
27
|
-
import { persistAtom } from "../web-effects"
|
|
28
|
-
|
|
29
|
-
export const makeViewsPerSpaceState = (
|
|
30
|
-
key: string,
|
|
31
|
-
): AtomToken<Join<null, `viewId`, `spaceId`>> =>
|
|
32
|
-
atom<Join<null, `viewId`, `spaceId`>>({
|
|
33
|
-
key: `${key}:views_per_space`,
|
|
34
|
-
default: new Join({ relationType: `1:n` }).from(`viewId`).to(`spaceId`),
|
|
35
|
-
effects: [
|
|
36
|
-
persistAtom<Join<null, `viewId`, `spaceId`>>(localStorage)({
|
|
37
|
-
stringify: (index) => JSON.stringify(index.toJSON()),
|
|
38
|
-
parse: (json) =>
|
|
39
|
-
Join.fromJSON(JSON.parse(json), {
|
|
40
|
-
from: `viewId`,
|
|
41
|
-
to: `spaceId`,
|
|
42
|
-
}),
|
|
43
|
-
})(`${key}:views_per_space`),
|
|
44
|
-
],
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
export const makeSpaceViewsFamily = (
|
|
48
|
-
key: string,
|
|
49
|
-
viewsPerSpaceState: AtomToken<Join<null, `viewId`, `spaceId`>>,
|
|
50
|
-
): ReadonlySelectorFamily<string[], string> =>
|
|
51
|
-
selectorFamily<string[], string>({
|
|
52
|
-
key: `${key}:space_views`,
|
|
53
|
-
get: (spaceId) => ({ get }) => {
|
|
54
|
-
const join = get(viewsPerSpaceState)
|
|
55
|
-
const viewIds = join.getRelatedIds(spaceId)
|
|
56
|
-
return viewIds
|
|
57
|
-
},
|
|
58
|
-
})
|
|
59
|
-
|
|
60
|
-
export const makeSpaceFocusedViewFamily = (
|
|
61
|
-
key: string,
|
|
62
|
-
findSpaceViewsState: ReadonlySelectorFamily<string[], string>,
|
|
63
|
-
findViewFocusedState: AtomFamily<number, string>,
|
|
64
|
-
): SelectorFamily<string | null, string> =>
|
|
65
|
-
selectorFamily<string | null, string>({
|
|
66
|
-
key: `${key}:space_focused_view`,
|
|
67
|
-
get: (spaceKey) => ({ get }) => {
|
|
68
|
-
const views = get(findSpaceViewsState(spaceKey))
|
|
69
|
-
const viewsLastFocused = views.map((viewKey): [string, number] => [
|
|
70
|
-
viewKey,
|
|
71
|
-
get(findViewFocusedState(viewKey)),
|
|
72
|
-
])
|
|
73
|
-
const lastFocused = lastOf(viewsLastFocused.sort((a, b) => b[1] - a[1]))
|
|
74
|
-
return lastFocused ? lastFocused[0] : null
|
|
75
|
-
},
|
|
76
|
-
set: (spaceKey) => ({ get, set }, viewKey) => {
|
|
77
|
-
if (viewKey === null) {
|
|
78
|
-
return
|
|
79
|
-
}
|
|
80
|
-
const views = get(findSpaceViewsState(spaceKey))
|
|
81
|
-
if (views.includes(viewKey)) {
|
|
82
|
-
set(findViewFocusedState(viewKey), Date.now())
|
|
83
|
-
} else {
|
|
84
|
-
console.warn(`View ${viewKey} not found in space ${spaceKey}`)
|
|
85
|
-
}
|
|
86
|
-
},
|
|
87
|
-
})
|
|
88
|
-
|
|
89
|
-
type AddViewOptions = { spaceId?: string; path?: string }
|
|
90
|
-
type SplitSpaceOptions = { parentId?: string }
|
|
91
|
-
|
|
92
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
93
|
-
export const attachExplorerState = (key: string) => {
|
|
94
|
-
const findSpaceState = makeSpaceFamily(key)
|
|
95
|
-
const findViewState = makeViewFamily(key)
|
|
96
|
-
const findViewFocusedState = makeViewFocusedFamily(key)
|
|
97
|
-
const spaceIndexState = makeSpaceIndex(key)
|
|
98
|
-
const spaceLayoutState = makeSpaceLayoutState(key)
|
|
99
|
-
const viewIndexState = makeViewIndex(key)
|
|
100
|
-
const viewsPerSpaceState = makeViewsPerSpaceState(key)
|
|
101
|
-
|
|
102
|
-
const findSpaceLayoutNode = makeSpaceLayoutNodeFamily(key, spaceLayoutState)
|
|
103
|
-
const findSpaceViewsState = makeSpaceViewsFamily(key, viewsPerSpaceState)
|
|
104
|
-
const findSpaceFocusedViewState = makeSpaceFocusedViewFamily(
|
|
105
|
-
key,
|
|
106
|
-
findSpaceViewsState,
|
|
107
|
-
findViewFocusedState,
|
|
108
|
-
)
|
|
109
|
-
|
|
110
|
-
const allViewsState = selector<Entries<string, View>>({
|
|
111
|
-
key: `${key}:all_views`,
|
|
112
|
-
get: ({ get }) => {
|
|
113
|
-
const viewIndex = get(viewIndexState)
|
|
114
|
-
return [...viewIndex].map((id) => [id, get(findViewState(id))])
|
|
115
|
-
},
|
|
116
|
-
})
|
|
117
|
-
|
|
118
|
-
const writeOperationAddSpace: Write<(options?: SplitSpaceOptions) => string> =
|
|
119
|
-
(transactors, { parentId = `root` } = {}) => {
|
|
120
|
-
const { set } = transactors
|
|
121
|
-
const key = `s-${now()}`
|
|
122
|
-
addToIndex(transactors, { indexAtom: spaceIndexState, id: key })
|
|
123
|
-
set(spaceLayoutState, (current) =>
|
|
124
|
-
current.set({ parent: `parent:${parentId}`, child: key }, { size: 1 }),
|
|
125
|
-
)
|
|
126
|
-
set(findSpaceState(key), 1)
|
|
127
|
-
return key
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
const writeOperationRemoveSpace: Write<(id: string) => void> = (
|
|
131
|
-
transactors,
|
|
132
|
-
id,
|
|
133
|
-
) => {
|
|
134
|
-
removeFromIndex(transactors, { indexAtom: spaceIndexState, id })
|
|
135
|
-
transactors.set(findSpaceState(id), null)
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const writeOperationAddView: Write<(options?: AddViewOptions) => void> = (
|
|
139
|
-
transactors,
|
|
140
|
-
{ spaceId: maybeSpaceId, path } = {},
|
|
141
|
-
) => {
|
|
142
|
-
const { get, set } = transactors
|
|
143
|
-
const id = `v-${now()}`
|
|
144
|
-
|
|
145
|
-
addToIndex(transactors, { indexAtom: viewIndexState, id })
|
|
146
|
-
set(
|
|
147
|
-
findViewState(id),
|
|
148
|
-
(current): View => ({
|
|
149
|
-
...current,
|
|
150
|
-
location: {
|
|
151
|
-
...current.location,
|
|
152
|
-
pathname: path ?? `/`,
|
|
153
|
-
},
|
|
154
|
-
}),
|
|
155
|
-
)
|
|
156
|
-
const spaceId =
|
|
157
|
-
maybeSpaceId ??
|
|
158
|
-
lastOf([...get(spaceIndexState)]) ??
|
|
159
|
-
writeOperationAddSpace(transactors)
|
|
160
|
-
set(findViewFocusedState(id), Date.now())
|
|
161
|
-
|
|
162
|
-
set(viewsPerSpaceState, (current) => current.set({ spaceId, viewId: id }))
|
|
163
|
-
set(findViewFocusedState(id), Date.now())
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
const writeOperationRemoveView: Write<(viewId: string) => void> = (
|
|
167
|
-
transactors,
|
|
168
|
-
viewId,
|
|
169
|
-
) => {
|
|
170
|
-
const { set } = transactors
|
|
171
|
-
removeFromIndex(transactors, { indexAtom: viewIndexState, id: viewId })
|
|
172
|
-
set(viewsPerSpaceState, (current) => current.remove({ viewId }))
|
|
173
|
-
set(findViewState(viewId), null)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const addView = transaction<(options?: AddViewOptions) => void>({
|
|
177
|
-
key: `${key}:add_view`,
|
|
178
|
-
do: writeOperationAddView,
|
|
179
|
-
})
|
|
180
|
-
|
|
181
|
-
const removeView = transaction({
|
|
182
|
-
key: `${key}:remove_view`,
|
|
183
|
-
do: writeOperationRemoveView,
|
|
184
|
-
})
|
|
185
|
-
|
|
186
|
-
const addSpace = transaction({
|
|
187
|
-
key: `${key}:add_space`,
|
|
188
|
-
do: writeOperationAddSpace,
|
|
189
|
-
})
|
|
190
|
-
|
|
191
|
-
const removeSpace = transaction({
|
|
192
|
-
key: `${key}:remove_space`,
|
|
193
|
-
do: writeOperationRemoveSpace,
|
|
194
|
-
})
|
|
195
|
-
|
|
196
|
-
return {
|
|
197
|
-
addSpace,
|
|
198
|
-
addView,
|
|
199
|
-
allViewsState,
|
|
200
|
-
findSpaceLayoutNode,
|
|
201
|
-
findSpaceFocusedViewState,
|
|
202
|
-
findSpaceState,
|
|
203
|
-
findSpaceViewsState,
|
|
204
|
-
findViewState,
|
|
205
|
-
findViewFocusedState,
|
|
206
|
-
removeSpace,
|
|
207
|
-
removeView,
|
|
208
|
-
spaceIndexState,
|
|
209
|
-
spaceLayoutState,
|
|
210
|
-
viewIndexState,
|
|
211
|
-
viewsPerSpaceState,
|
|
212
|
-
writeOperationAddSpace,
|
|
213
|
-
writeOperationAddView,
|
|
214
|
-
writeOperationRemoveSpace,
|
|
215
|
-
writeOperationRemoveView,
|
|
216
|
-
}
|
|
217
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import type { AtomToken, Write } from "atom.io"
|
|
2
|
-
|
|
3
|
-
export * from "./AtomIOExplorer"
|
|
4
|
-
|
|
5
|
-
export type AtomicIndexOptions = {
|
|
6
|
-
indexAtom: AtomToken<Set<string>>
|
|
7
|
-
id: string
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export const addToIndex: Write<(options: AtomicIndexOptions) => void> = (
|
|
11
|
-
{ set },
|
|
12
|
-
{ indexAtom, id },
|
|
13
|
-
): void => set(indexAtom, (currentSet) => new Set(currentSet).add(id))
|
|
14
|
-
|
|
15
|
-
export const removeFromIndex: Write<(options: AtomicIndexOptions) => void> = (
|
|
16
|
-
{ set },
|
|
17
|
-
{ indexAtom, id },
|
|
18
|
-
): void =>
|
|
19
|
-
set(indexAtom, (currentSet) => {
|
|
20
|
-
const newSet = new Set(currentSet)
|
|
21
|
-
newSet.delete(id)
|
|
22
|
-
return newSet
|
|
23
|
-
})
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
import { Join } from "~/packages/anvl/src/join"
|
|
2
|
-
import { parseJson, stringifyJson } from "~/packages/anvl/src/json"
|
|
3
|
-
import { hasExactProperties } from "~/packages/anvl/src/object"
|
|
4
|
-
|
|
5
|
-
import { persistStringSetAtom } from "./explorer-effects"
|
|
6
|
-
import type { AtomToken, ReadonlySelectorFamily } from ".."
|
|
7
|
-
import { SelectorFamily, selectorFamily } from ".."
|
|
8
|
-
import type { AtomFamily } from "../atom"
|
|
9
|
-
import { atom, atomFamily } from "../atom"
|
|
10
|
-
import { lazyLocalStorageEffect, persistAtom } from "../web-effects"
|
|
11
|
-
|
|
12
|
-
export const makeSpaceIndex = (key: string): AtomToken<Set<string>> =>
|
|
13
|
-
atom<Set<string>>({
|
|
14
|
-
key: `${key}:space_index`,
|
|
15
|
-
default: new Set([`root`]),
|
|
16
|
-
effects: [persistStringSetAtom(`${key}:space_index`)],
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
export const makeSpaceLayoutState = (
|
|
20
|
-
key: string,
|
|
21
|
-
): AtomToken<Join<{ size: number }, `parent`, `child`>> =>
|
|
22
|
-
atom({
|
|
23
|
-
key: `${key}:space_layout`,
|
|
24
|
-
default: new Join<{ size: number }>({ relationType: `1:n` })
|
|
25
|
-
.from(`parent`)
|
|
26
|
-
.to(`child`),
|
|
27
|
-
effects: [
|
|
28
|
-
persistAtom<Join<{ size: number }, `parent`, `child`>>(localStorage)({
|
|
29
|
-
stringify: (join) => stringifyJson(join.toJSON()),
|
|
30
|
-
parse: (string) => {
|
|
31
|
-
try {
|
|
32
|
-
const json = parseJson(string)
|
|
33
|
-
const join = Join.fromJSON(json, {
|
|
34
|
-
isContent: hasExactProperties({
|
|
35
|
-
size: (v): v is number => typeof v === `number`,
|
|
36
|
-
}),
|
|
37
|
-
from: `parent`,
|
|
38
|
-
to: `child`,
|
|
39
|
-
})
|
|
40
|
-
return join
|
|
41
|
-
} catch (thrown) {
|
|
42
|
-
console.error(`Error parsing spaceLayoutState from localStorage`)
|
|
43
|
-
return new Join({ relationType: `1:n` })
|
|
44
|
-
}
|
|
45
|
-
},
|
|
46
|
-
})(`${key}:space_layout`),
|
|
47
|
-
],
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
export const makeSpaceLayoutNodeFamily = (
|
|
51
|
-
key: string,
|
|
52
|
-
spaceLayoutState: AtomToken<Join<{ size: number }, `parent`, `child`>>,
|
|
53
|
-
): ReadonlySelectorFamily<{ childSpaceIds: string[]; size: number }, string> =>
|
|
54
|
-
selectorFamily<{ childSpaceIds: string[]; size: number }, string>({
|
|
55
|
-
key: `${key}:explorer_space`,
|
|
56
|
-
get: (me) => ({ get }) => {
|
|
57
|
-
const join = get(spaceLayoutState)
|
|
58
|
-
const myFollowers = join.getRelatedIds(`parent:${me}`)
|
|
59
|
-
const myLeader = join.getRelatedId(me)
|
|
60
|
-
const { size } = myLeader
|
|
61
|
-
? join.getContent(myLeader, me) ?? { size: NaN }
|
|
62
|
-
: { size: NaN }
|
|
63
|
-
return { childSpaceIds: myFollowers, size }
|
|
64
|
-
},
|
|
65
|
-
})
|
|
66
|
-
|
|
67
|
-
export const makeSpaceFamily = (key: string): AtomFamily<number, string> =>
|
|
68
|
-
atomFamily<number, string>({
|
|
69
|
-
key: `${key}:space`,
|
|
70
|
-
default: 1,
|
|
71
|
-
effects: (subKey) => [lazyLocalStorageEffect(`${key}:${subKey}`)],
|
|
72
|
-
})
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import type { Location } from "react-router-dom"
|
|
2
|
-
|
|
3
|
-
import { persistStringSetAtom } from "./explorer-effects"
|
|
4
|
-
import type { AtomToken } from ".."
|
|
5
|
-
import type { AtomFamily } from "../atom"
|
|
6
|
-
import { atom, atomFamily } from "../atom"
|
|
7
|
-
import { lazyLocalStorageEffect } from "../web-effects"
|
|
8
|
-
|
|
9
|
-
export type View = {
|
|
10
|
-
title: string
|
|
11
|
-
location: Omit<Location, `state`>
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const makeViewFamily = (key: string): AtomFamily<View, string> =>
|
|
15
|
-
atomFamily<View, string>({
|
|
16
|
-
key: `${key}:view`,
|
|
17
|
-
default: {
|
|
18
|
-
title: ``,
|
|
19
|
-
location: {
|
|
20
|
-
pathname: ``,
|
|
21
|
-
search: ``,
|
|
22
|
-
hash: ``,
|
|
23
|
-
key: ``,
|
|
24
|
-
},
|
|
25
|
-
},
|
|
26
|
-
effects: (subKey) => [lazyLocalStorageEffect(`${key}:${subKey}`)],
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
export const makeViewIndex = (key: string): AtomToken<Set<string>> =>
|
|
30
|
-
atom<Set<string>>({
|
|
31
|
-
key: `${key}:view_index`,
|
|
32
|
-
default: new Set(),
|
|
33
|
-
effects: [persistStringSetAtom(`${key}:view_index`)],
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
export const makeViewFocusedFamily = (key: string): AtomFamily<number, string> =>
|
|
37
|
-
atomFamily<number, string>({
|
|
38
|
-
key: `${key}:view_focused`,
|
|
39
|
-
default: 0,
|
|
40
|
-
effects: (subKey) => [lazyLocalStorageEffect(`${key}:${subKey}`)],
|
|
41
|
-
})
|
package/src/realtime/README.md
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# CLIENT ACTS AND REPORTS
|
|
2
|
-
- [x] input event fires
|
|
3
|
-
- [x] event handler runs transaction
|
|
4
|
-
- [x] client store updates optimistically
|
|
5
|
-
- [ ] on success
|
|
6
|
-
- [ ] client generates transactionId and optimistic TransactionUpdate
|
|
7
|
-
- [ ] client pushes TransactionUpdate to TimelineData.history
|
|
8
|
-
- [ ] client sets TransactionUpdate in optimisticTransactions map by transactionId
|
|
9
|
-
- [ ] client emits TransactionRequest { key, params, transactionId }
|
|
10
|
-
|
|
11
|
-
# SERVER VALIDATES, INTEGRATES, AND BROADCASTS
|
|
12
|
-
## use
|
|
13
|
-
- [x] server receives TransactionRequest
|
|
14
|
-
- `{ key, params, transactionId }`
|
|
15
|
-
- [ ] verify `transactionId` is unique
|
|
16
|
-
- [ ] server adds timestamp to `TransactionRequest`
|
|
17
|
-
- `{ key, params, transactionId, timestamp }`
|
|
18
|
-
- [ ] server runs transaction, computing `TransactionUpdate` in the process
|
|
19
|
-
- [ ] emit `TransactionUpdate`
|
|
20
|
-
- `{ key, params, transactionId, timestamp, atomUpdates, output }`
|
|
21
|
-
- [ ] server adds `TransactionUpdate` to TimelineData.history
|
|
22
|
-
|
|
23
|
-
# CLIENT BEHOLDS AND REACTS
|
|
24
|
-
- [ ] client receives official TransactionUpdate
|
|
25
|
-
- [ ] client retrieves its own TransactionUpdate from optimisticTransactions map
|
|
26
|
-
- [ ] client compares official and optimistic TransactionUpdates
|
|
27
|
-
- [ ] (stringify atomUpdates and compare strict)
|
|
28
|
-
- [ ] if match, client removes TransactionUpdate from optimisticTransactions map
|
|
29
|
-
- [ ] if mismatch
|
|
30
|
-
- [ ] client undoes timeline until it finds its own TransactionUpdate
|
|
31
|
-
- [ ] client replaces its own TransactionUpdate with official TransactionUpdate
|
|
32
|
-
- [ ] client removes its own TransactionUpdate from optimisticTransactions map
|
|
33
|
-
- [ ] client redoes timeline until it reaches the "HEAD"
|
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
import type { Json } from "anvl/json"
|
|
2
|
-
import { parseJson } from "anvl/json"
|
|
3
|
-
import * as AtomIO from "atom.io"
|
|
4
|
-
|
|
5
|
-
import type { ServerConfig } from ".."
|
|
6
|
-
|
|
7
|
-
const subscribeToTokenCreation = <T>(
|
|
8
|
-
family: AtomIO.AtomFamily<T> | AtomIO.SelectorFamily<T>,
|
|
9
|
-
handleTokenCreation: (token: AtomIO.StateToken<T>) => void,
|
|
10
|
-
): (() => void) => {
|
|
11
|
-
const subscription =
|
|
12
|
-
family.type === `atom_family`
|
|
13
|
-
? family.subject.subscribe(handleTokenCreation)
|
|
14
|
-
: family.subject.subscribe(handleTokenCreation)
|
|
15
|
-
return () => subscription.unsubscribe()
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
19
|
-
export const useExposeFamily = ({ socket, store }: ServerConfig) => {
|
|
20
|
-
return function exposeFamily<J extends Json.Serializable>(
|
|
21
|
-
family: AtomIO.AtomFamily<J> | AtomIO.SelectorFamily<J>,
|
|
22
|
-
index: AtomIO.StateToken<Set<string>>,
|
|
23
|
-
): () => void {
|
|
24
|
-
const unsubSingleCallbacksByKey = new Map<string, () => void>()
|
|
25
|
-
const unsubFamilyCallbacksByKey = new Map<string, () => void>()
|
|
26
|
-
|
|
27
|
-
const fillFamilyUnsubRequest = () => {
|
|
28
|
-
unsubFamilyCallbacksByKey.forEach((unsub) => unsub())
|
|
29
|
-
unsubFamilyCallbacksByKey.clear()
|
|
30
|
-
socket.off(`unsub:${family.key}`, fillFamilyUnsubRequest)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const fillSingleUnsubRequest = (key: string) => {
|
|
34
|
-
socket.off(`unsub:${key}`, fillSingleUnsubRequest)
|
|
35
|
-
const unsub = unsubSingleCallbacksByKey.get(key)
|
|
36
|
-
if (unsub) {
|
|
37
|
-
unsub()
|
|
38
|
-
unsubSingleCallbacksByKey.delete(key)
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const fillSubRequest = (subKey?: AtomIO.Json.Serializable) => {
|
|
43
|
-
if (subKey === undefined) {
|
|
44
|
-
const keys = AtomIO.getState(index, store)
|
|
45
|
-
keys.forEach((key) => {
|
|
46
|
-
const token = family(key)
|
|
47
|
-
socket.emit(
|
|
48
|
-
`serve:${family.key}`,
|
|
49
|
-
parseJson(token.family?.subKey || `null`),
|
|
50
|
-
AtomIO.getState(token, store),
|
|
51
|
-
)
|
|
52
|
-
})
|
|
53
|
-
|
|
54
|
-
const unsubscribeFromTokenCreation = subscribeToTokenCreation(
|
|
55
|
-
family,
|
|
56
|
-
(token) => {
|
|
57
|
-
const unsub = AtomIO.subscribe(
|
|
58
|
-
token,
|
|
59
|
-
({ newValue }) => {
|
|
60
|
-
socket.emit(
|
|
61
|
-
`serve:${family.key}`,
|
|
62
|
-
parseJson(token.family?.subKey || `null`),
|
|
63
|
-
newValue,
|
|
64
|
-
)
|
|
65
|
-
},
|
|
66
|
-
store,
|
|
67
|
-
)
|
|
68
|
-
unsubFamilyCallbacksByKey.set(token.key, unsub)
|
|
69
|
-
},
|
|
70
|
-
)
|
|
71
|
-
unsubFamilyCallbacksByKey.set(family.key, unsubscribeFromTokenCreation)
|
|
72
|
-
|
|
73
|
-
socket.on(`unsub:${family.key}`, fillFamilyUnsubRequest)
|
|
74
|
-
} else {
|
|
75
|
-
const token = family(subKey)
|
|
76
|
-
socket.emit(`serve:${token.key}`, AtomIO.getState(token, store))
|
|
77
|
-
const unsubscribe = AtomIO.subscribe(
|
|
78
|
-
token,
|
|
79
|
-
({ newValue }) => {
|
|
80
|
-
socket.emit(`serve:${token.key}`, newValue)
|
|
81
|
-
},
|
|
82
|
-
store,
|
|
83
|
-
)
|
|
84
|
-
unsubSingleCallbacksByKey.set(token.key, unsubscribe)
|
|
85
|
-
socket.on(`unsub:${token.key}`, () => {
|
|
86
|
-
fillSingleUnsubRequest(token.key)
|
|
87
|
-
})
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
socket.on(`sub:${family.key}`, fillSubRequest)
|
|
92
|
-
|
|
93
|
-
return () => {
|
|
94
|
-
socket.off(`sub:${family.key}`, fillSubRequest)
|
|
95
|
-
unsubFamilyCallbacksByKey.forEach((unsub) => unsub())
|
|
96
|
-
unsubSingleCallbacksByKey.forEach((unsub) => unsub())
|
|
97
|
-
unsubFamilyCallbacksByKey.clear()
|
|
98
|
-
unsubSingleCallbacksByKey.clear()
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
}
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import type { Json } from "anvl/json"
|
|
2
|
-
import * as AtomIO from "atom.io"
|
|
3
|
-
|
|
4
|
-
import type { ServerConfig } from ".."
|
|
5
|
-
|
|
6
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
7
|
-
export const useExposeSingle = ({ socket, store }: ServerConfig) => {
|
|
8
|
-
return function exposeSingle<J extends Json.Serializable>(
|
|
9
|
-
token: AtomIO.StateToken<J>,
|
|
10
|
-
): () => void {
|
|
11
|
-
let unsubscribeFromStateUpdates: (() => void) | null = null
|
|
12
|
-
|
|
13
|
-
const fillUnsubRequest = () => {
|
|
14
|
-
socket.off(`unsub:${token.key}`, fillUnsubRequest)
|
|
15
|
-
unsubscribeFromStateUpdates?.()
|
|
16
|
-
unsubscribeFromStateUpdates = null
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const fillSubRequest = () => {
|
|
20
|
-
socket.emit(`serve:${token.key}`, AtomIO.getState(token, store))
|
|
21
|
-
unsubscribeFromStateUpdates = AtomIO.subscribe(
|
|
22
|
-
token,
|
|
23
|
-
({ newValue }) => {
|
|
24
|
-
socket.emit(`serve:${token.key}`, newValue)
|
|
25
|
-
},
|
|
26
|
-
store,
|
|
27
|
-
)
|
|
28
|
-
socket.on(`unsub:${token.key}`, fillUnsubRequest)
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
socket.on(`sub:${token.key}`, fillSubRequest)
|
|
32
|
-
|
|
33
|
-
return () => {
|
|
34
|
-
socket.off(`sub:${token.key}`, fillSubRequest)
|
|
35
|
-
unsubscribeFromStateUpdates?.()
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import * as AtomIO from "atom.io"
|
|
2
|
-
|
|
3
|
-
import { Join } from "~/packages/anvl/src/join"
|
|
4
|
-
|
|
5
|
-
import type { ServerConfig } from "."
|
|
6
|
-
import type { TimelineTransactionUpdate } from "../../internal"
|
|
7
|
-
|
|
8
|
-
export type TransactionRequest = {
|
|
9
|
-
key: string
|
|
10
|
-
params: unknown[]
|
|
11
|
-
transactionId: string
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
export const useExposeTimeline__UNSTABLE = ({
|
|
15
|
-
socket,
|
|
16
|
-
store,
|
|
17
|
-
}: ServerConfig): ((tl: AtomIO.TimelineToken) => () => void) => {
|
|
18
|
-
const timestampsOfTransactionsState = AtomIO.__INTERNAL__.atom__INTERNAL(
|
|
19
|
-
{
|
|
20
|
-
key: `timestampsOfTransactions`,
|
|
21
|
-
default: new Join<null, `transactionId`, `timestamp`>({
|
|
22
|
-
relationType: `1:1`,
|
|
23
|
-
})
|
|
24
|
-
.from(`transactionId`)
|
|
25
|
-
.to(`timestamp`),
|
|
26
|
-
},
|
|
27
|
-
undefined,
|
|
28
|
-
store,
|
|
29
|
-
)
|
|
30
|
-
return function exposeTimeline(tl: AtomIO.TimelineToken): () => void {
|
|
31
|
-
const handleTransactionRequest = (update: TransactionRequest) => {
|
|
32
|
-
AtomIO.runTransaction(
|
|
33
|
-
{ key: update.key, type: `transaction` },
|
|
34
|
-
store,
|
|
35
|
-
)(...update.params)
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
socket.on(`txr:${tl.key}`, handleTransactionRequest)
|
|
39
|
-
|
|
40
|
-
const unsubscribeFromTimeline = AtomIO.subscribeToTimeline(
|
|
41
|
-
tl,
|
|
42
|
-
(update: TimelineTransactionUpdate) => {
|
|
43
|
-
// const timestamp = update.timestamp.toString()
|
|
44
|
-
// AtomIO.setState(
|
|
45
|
-
// timestampsOfTransactionsState,
|
|
46
|
-
// (j) => j.set(update),
|
|
47
|
-
// store
|
|
48
|
-
// )
|
|
49
|
-
if (update.type === `transaction_update`) {
|
|
50
|
-
socket.emit(`tl:${tl.key}`, update)
|
|
51
|
-
}
|
|
52
|
-
},
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
return () => {
|
|
56
|
-
socket.off(`tlu:${tl.key}`, handleTransactionRequest)
|
|
57
|
-
unsubscribeFromTimeline()
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
}
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type * as AtomIO from "atom.io"
|
|
2
|
-
import type * as SocketIO from "socket.io"
|
|
3
|
-
|
|
4
|
-
export * from "./expose-single"
|
|
5
|
-
export * from "./expose-family"
|
|
6
|
-
export * from "./receive-transaction"
|
|
7
|
-
export * from "./receive-state"
|
|
8
|
-
|
|
9
|
-
export type ServerConfig = {
|
|
10
|
-
socket: SocketIO.Socket
|
|
11
|
-
store?: AtomIO.__INTERNAL__.Store
|
|
12
|
-
}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { Json } from "anvl/json"
|
|
2
|
-
import * as AtomIO from "atom.io"
|
|
3
|
-
|
|
4
|
-
import type { ServerConfig } from ".."
|
|
5
|
-
|
|
6
|
-
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
|
|
7
|
-
export const useReceiveState = ({ socket, store }: ServerConfig) => {
|
|
8
|
-
return function receiveState<J extends Json.Serializable>(
|
|
9
|
-
token: AtomIO.StateToken<J>,
|
|
10
|
-
): () => void {
|
|
11
|
-
const publish = (newValue: J) => AtomIO.setState(token, newValue, store)
|
|
12
|
-
|
|
13
|
-
const fillPubUnclaim = () => {
|
|
14
|
-
socket.off(`pub:${token.key}`, publish)
|
|
15
|
-
socket.off(`unclaim:${token.key}`, fillPubUnclaim)
|
|
16
|
-
}
|
|
17
|
-
const fillPubClaim = () => {
|
|
18
|
-
socket.on(`pub:${token.key}`, publish)
|
|
19
|
-
socket.on(`unclaim:${token.key}`, fillPubUnclaim)
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
socket.on(`claim:${token.key}`, fillPubClaim)
|
|
23
|
-
|
|
24
|
-
return () => {
|
|
25
|
-
socket.off(`claim:${token.key}`, fillPubClaim)
|
|
26
|
-
socket.off(`pub:${token.key}`, publish)
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import * as AtomIO from "atom.io"
|
|
2
|
-
|
|
3
|
-
import type { ƒn } from "~/packages/anvl/src/function"
|
|
4
|
-
|
|
5
|
-
import type { ServerConfig } from "."
|
|
6
|
-
|
|
7
|
-
export const useReceiveTransaction = ({ socket, store }: ServerConfig) => {
|
|
8
|
-
return function receiveTransaction<ƒ extends ƒn>(
|
|
9
|
-
tx: AtomIO.TransactionToken<ƒ>,
|
|
10
|
-
): () => void {
|
|
11
|
-
const fillTransactionRequest = (update: AtomIO.TransactionUpdate<ƒ>) =>
|
|
12
|
-
AtomIO.runTransaction<ƒ>(tx, store)(...update.params)
|
|
13
|
-
|
|
14
|
-
socket.on(`tx:${tx.key}`, fillTransactionRequest)
|
|
15
|
-
|
|
16
|
-
return () => socket.off(`tx:${tx.key}`, fillTransactionRequest)
|
|
17
|
-
}
|
|
18
|
-
}
|
package/src/realtime/index.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export * from "./hook-composition"
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import * as AR from "atom.io/react"
|
|
2
|
-
import * as React from "react"
|
|
3
|
-
import type { Socket } from "socket.io-client"
|
|
4
|
-
import { io } from "socket.io-client"
|
|
5
|
-
|
|
6
|
-
import { myIdState__INTERNAL } from "./realtime-state"
|
|
7
|
-
|
|
8
|
-
export const RealtimeContext = React.createContext<{ socket: Socket }>({
|
|
9
|
-
socket: io(),
|
|
10
|
-
})
|
|
11
|
-
|
|
12
|
-
export const RealtimeProvider: React.FC<{
|
|
13
|
-
children: React.ReactNode
|
|
14
|
-
socket: Socket
|
|
15
|
-
}> = ({ children, socket }) => {
|
|
16
|
-
const setMyId = AR.useI(myIdState__INTERNAL)
|
|
17
|
-
React.useEffect(() => {
|
|
18
|
-
socket.on(`connect`, () => {
|
|
19
|
-
setMyId(socket.id)
|
|
20
|
-
})
|
|
21
|
-
socket.on(`disconnect`, () => {
|
|
22
|
-
setMyId(null)
|
|
23
|
-
})
|
|
24
|
-
}, [socket, setMyId])
|
|
25
|
-
return (
|
|
26
|
-
<RealtimeContext.Provider value={{ socket }}>
|
|
27
|
-
{children}
|
|
28
|
-
</RealtimeContext.Provider>
|
|
29
|
-
)
|
|
30
|
-
}
|