atom.io 0.6.2 → 0.6.4
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 +27 -15
- package/dist/index.d.ts +27 -15
- package/dist/index.js +44 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +44 -24
- package/dist/index.mjs.map +1 -1
- package/json/dist/index.d.mts +18 -0
- package/json/dist/index.d.ts +18 -0
- package/json/dist/index.js +51 -0
- package/json/dist/index.js.map +1 -0
- package/json/dist/index.mjs +15 -0
- package/json/dist/index.mjs.map +1 -0
- package/json/package.json +13 -13
- package/package.json +31 -12
- package/react/dist/index.d.mts +24 -0
- package/react/dist/index.d.ts +24 -0
- package/react/dist/index.js +87 -0
- package/react/dist/index.js.map +1 -0
- package/react/dist/index.mjs +45 -0
- package/react/dist/index.mjs.map +1 -0
- package/react/package.json +13 -13
- package/react-devtools/dist/index.css +26 -0
- package/react-devtools/dist/index.css.map +1 -0
- package/react-devtools/dist/index.d.mts +15 -0
- package/react-devtools/dist/index.d.ts +15 -0
- package/react-devtools/dist/index.js +2108 -0
- package/react-devtools/dist/index.js.map +1 -0
- package/react-devtools/dist/index.mjs +2080 -0
- package/react-devtools/dist/index.mjs.map +1 -0
- package/react-devtools/package.json +13 -13
- package/realtime/dist/index.d.mts +27 -0
- package/realtime/dist/index.d.ts +27 -0
- package/realtime/dist/index.js +191 -0
- package/realtime/dist/index.js.map +1 -0
- package/realtime/dist/index.mjs +152 -0
- package/realtime/dist/index.mjs.map +1 -0
- package/realtime/package.json +13 -13
- package/realtime-react/dist/index.d.mts +45 -0
- package/realtime-react/dist/index.d.ts +45 -0
- package/realtime-react/dist/index.js +217 -0
- package/realtime-react/dist/index.js.map +1 -0
- package/realtime-react/dist/index.mjs +172 -0
- package/realtime-react/dist/index.mjs.map +1 -0
- package/realtime-react/package.json +13 -13
- package/realtime-testing/dist/index.d.mts +49 -0
- package/realtime-testing/dist/index.d.ts +49 -0
- package/realtime-testing/dist/index.js +165 -0
- package/realtime-testing/dist/index.js.map +1 -0
- package/realtime-testing/dist/index.mjs +129 -0
- package/realtime-testing/dist/index.mjs.map +1 -0
- package/realtime-testing/package.json +15 -0
- package/src/atom.ts +16 -17
- package/src/index.ts +59 -59
- package/src/internal/atom-internal.ts +37 -37
- package/src/internal/families-internal.ts +115 -116
- package/src/internal/get.ts +83 -83
- package/src/internal/index.ts +1 -0
- package/src/internal/is-default.ts +17 -17
- package/src/internal/meta/attach-meta.ts +7 -7
- package/src/internal/meta/meta-state.ts +115 -115
- package/src/internal/operation.ts +93 -93
- package/src/internal/selector/create-read-write-selector.ts +47 -47
- package/src/internal/selector/create-readonly-selector.ts +38 -38
- package/src/internal/selector/lookup-selector-sources.ts +9 -9
- package/src/internal/selector/register-selector.ts +44 -44
- package/src/internal/selector/trace-selector-atoms.ts +30 -30
- package/src/internal/selector/update-selector-atoms.ts +25 -25
- package/src/internal/selector-internal.ts +38 -39
- package/src/internal/set.ts +78 -78
- package/src/internal/store.ts +119 -119
- package/src/internal/subject.ts +24 -0
- package/src/internal/subscribe-internal.ts +62 -62
- package/src/internal/time-travel-internal.ts +76 -76
- package/src/internal/timeline/add-atom-to-timeline.ts +158 -153
- package/src/internal/timeline-internal.ts +81 -82
- package/src/internal/transaction/abort-transaction.ts +8 -8
- package/src/internal/transaction/apply-transaction.ts +41 -41
- package/src/internal/transaction/build-transaction.ts +28 -28
- package/src/internal/transaction/index.ts +7 -7
- package/src/internal/transaction/redo-transaction.ts +13 -13
- package/src/internal/transaction/undo-transaction.ts +13 -13
- package/src/internal/transaction-internal.ts +49 -49
- package/src/json/select-json.ts +12 -12
- package/src/logger.ts +30 -30
- package/src/react/store-context.tsx +5 -6
- package/src/react/store-hooks.ts +19 -20
- package/src/react-devtools/AtomIODevtools.tsx +85 -85
- package/src/react-devtools/StateEditor.tsx +54 -55
- package/src/react-devtools/TokenList.tsx +49 -45
- package/src/react-explorer/AtomIOExplorer.tsx +198 -187
- package/src/react-explorer/explorer-effects.ts +11 -11
- package/src/react-explorer/explorer-states.ts +186 -193
- package/src/react-explorer/index.ts +11 -11
- package/src/react-explorer/space-states.ts +48 -50
- package/src/react-explorer/view-states.ts +25 -25
- package/src/realtime/hook-composition/expose-family.ts +81 -81
- package/src/realtime/hook-composition/expose-single.ts +26 -26
- package/src/realtime/hook-composition/expose-timeline.ts +60 -0
- package/src/realtime/hook-composition/index.ts +2 -2
- package/src/realtime/hook-composition/receive-state.ts +18 -18
- package/src/realtime/hook-composition/receive-transaction.ts +8 -8
- package/src/realtime-react/realtime-context.tsx +18 -19
- package/src/realtime-react/realtime-hooks.ts +17 -17
- package/src/realtime-react/realtime-state.ts +4 -4
- package/src/realtime-react/use-pull-family-member.ts +16 -17
- package/src/realtime-react/use-pull-family.ts +14 -15
- package/src/realtime-react/use-pull.ts +13 -14
- package/src/realtime-react/use-push.ts +16 -17
- package/src/realtime-react/use-server-action.ts +22 -23
- package/src/realtime-testing/index.ts +1 -0
- package/src/realtime-testing/setup-realtime-test.tsx +159 -0
- package/src/selector.ts +26 -27
- package/src/silo.ts +38 -38
- package/src/subscribe.ts +68 -68
- package/src/timeline.ts +13 -13
- package/src/transaction.ts +28 -28
- package/src/web-effects/storage.ts +17 -17
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import * as React from "react"
|
|
2
|
-
|
|
3
1
|
import * as AtomIO from "atom.io"
|
|
4
2
|
import { StoreContext } from "atom.io/react"
|
|
3
|
+
import * as React from "react"
|
|
5
4
|
|
|
6
5
|
import type { ƒn } from "~/packages/anvl/src/function"
|
|
7
6
|
|
|
@@ -9,26 +8,26 @@ import { RealtimeContext } from "./realtime-context"
|
|
|
9
8
|
|
|
10
9
|
const TX_SUBS = new Map<string, number>()
|
|
11
10
|
export function useServerAction<ƒ extends ƒn>(
|
|
12
|
-
|
|
11
|
+
token: AtomIO.TransactionToken<ƒ>,
|
|
13
12
|
): (...parameters: Parameters<ƒ>) => ReturnType<ƒ> {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
13
|
+
const store = React.useContext(StoreContext)
|
|
14
|
+
const { socket } = React.useContext(RealtimeContext)
|
|
15
|
+
React.useEffect(() => {
|
|
16
|
+
const count = TX_SUBS.get(token.key) ?? 0
|
|
17
|
+
TX_SUBS.set(token.key, count + 1)
|
|
18
|
+
const unsubscribe =
|
|
19
|
+
count === 0
|
|
20
|
+
? AtomIO.subscribeToTransaction(
|
|
21
|
+
token,
|
|
22
|
+
(update) => socket.emit(`tx:${token.key}`, update),
|
|
23
|
+
store,
|
|
24
|
+
)
|
|
25
|
+
: () => null
|
|
26
|
+
return () => {
|
|
27
|
+
const newCount = TX_SUBS.get(token.key) ?? 0
|
|
28
|
+
TX_SUBS.set(token.key, newCount - 1)
|
|
29
|
+
unsubscribe()
|
|
30
|
+
}
|
|
31
|
+
}, [token.key])
|
|
32
|
+
return AtomIO.runTransaction(token, store)
|
|
34
33
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./setup-realtime-test"
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import * as http from "http"
|
|
2
|
+
|
|
3
|
+
import { prettyDOM, render, type RenderResult } from "@testing-library/react"
|
|
4
|
+
import * as AtomIO from "atom.io"
|
|
5
|
+
import * as AR from "atom.io/react"
|
|
6
|
+
import * as RTC from "atom.io/realtime-react"
|
|
7
|
+
import * as RR from "fp-ts/ReadonlyRecord"
|
|
8
|
+
import * as Happy from "happy-dom"
|
|
9
|
+
import * as React from "react"
|
|
10
|
+
import * as SocketIO from "socket.io"
|
|
11
|
+
import type { Socket as ClientSocket } from "socket.io-client"
|
|
12
|
+
import { io } from "socket.io-client"
|
|
13
|
+
|
|
14
|
+
export type TestSetupOptions = {
|
|
15
|
+
server: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void
|
|
16
|
+
}
|
|
17
|
+
export type TestSetupOptions__SingleClient = TestSetupOptions & {
|
|
18
|
+
client: React.FC
|
|
19
|
+
}
|
|
20
|
+
export type TestSetupOptions__MultiClient<ClientNames extends string> =
|
|
21
|
+
TestSetupOptions & {
|
|
22
|
+
clients: {
|
|
23
|
+
[K in ClientNames]: React.FC
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type RealtimeTestTools = {
|
|
28
|
+
name: string
|
|
29
|
+
silo: AtomIO.Silo
|
|
30
|
+
dispose: () => void
|
|
31
|
+
}
|
|
32
|
+
export type RealtimeTestClient = RealtimeTestTools & {
|
|
33
|
+
renderResult: RenderResult
|
|
34
|
+
prettyPrint: () => void
|
|
35
|
+
reconnect: () => void
|
|
36
|
+
disconnect: () => void
|
|
37
|
+
}
|
|
38
|
+
export type RealtimeTestServer = RealtimeTestTools & {
|
|
39
|
+
port: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type RealtimeTestAPI = {
|
|
43
|
+
server: RealtimeTestServer
|
|
44
|
+
teardown: () => void
|
|
45
|
+
}
|
|
46
|
+
export type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {
|
|
47
|
+
client: RealtimeTestClient
|
|
48
|
+
}
|
|
49
|
+
export type RealtimeTestAPI__MultiClient<ClientNames extends string> =
|
|
50
|
+
RealtimeTestAPI & {
|
|
51
|
+
clients: Record<ClientNames, RealtimeTestClient>
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export const setupRealtimeTestServer = (
|
|
55
|
+
options: TestSetupOptions,
|
|
56
|
+
): RealtimeTestServer => {
|
|
57
|
+
const httpServer = http.createServer((_, res) => res.end(`Hello World!`))
|
|
58
|
+
const address = httpServer.listen().address()
|
|
59
|
+
const port =
|
|
60
|
+
typeof address === `string` ? 80 : address === null ? null : address.port
|
|
61
|
+
if (port === null) throw new Error(`Could not determine port for test server`)
|
|
62
|
+
const server = new SocketIO.Server(httpServer)
|
|
63
|
+
const silo = AtomIO.silo(`SERVER`, AtomIO.__INTERNAL__.IMPLICIT.STORE)
|
|
64
|
+
|
|
65
|
+
server.on(`connection`, (socket: SocketIO.Socket) => {
|
|
66
|
+
options.server({ socket, silo })
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
const dispose = () => {
|
|
70
|
+
server.close()
|
|
71
|
+
AtomIO.__INTERNAL__.clearStore(silo.store)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
name: `SERVER`,
|
|
76
|
+
silo,
|
|
77
|
+
dispose,
|
|
78
|
+
port,
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
export const setupRealtimeTestClient = (
|
|
82
|
+
options: TestSetupOptions__SingleClient,
|
|
83
|
+
name: string,
|
|
84
|
+
port: number,
|
|
85
|
+
): RealtimeTestClient => {
|
|
86
|
+
const socket: ClientSocket = io(`http://localhost:${port}/`)
|
|
87
|
+
const silo = AtomIO.silo(name, AtomIO.__INTERNAL__.IMPLICIT.STORE)
|
|
88
|
+
|
|
89
|
+
const { document } = new Happy.Window()
|
|
90
|
+
document.body.innerHTML = `<div id="app"></div>`
|
|
91
|
+
const renderResult = render(
|
|
92
|
+
<AR.StoreProvider store={silo.store}>
|
|
93
|
+
<RTC.RealtimeProvider socket={socket}>
|
|
94
|
+
<options.client />
|
|
95
|
+
</RTC.RealtimeProvider>
|
|
96
|
+
</AR.StoreProvider>,
|
|
97
|
+
{
|
|
98
|
+
container: document.querySelector(`#app`) as unknown as HTMLElement,
|
|
99
|
+
},
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
const prettyPrint = () => console.log(prettyDOM(renderResult.container))
|
|
103
|
+
|
|
104
|
+
const disconnect = () => socket.disconnect()
|
|
105
|
+
const reconnect = () => socket.connect()
|
|
106
|
+
|
|
107
|
+
const dispose = () => {
|
|
108
|
+
socket.disconnect()
|
|
109
|
+
AtomIO.__INTERNAL__.clearStore(silo.store)
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
name,
|
|
114
|
+
silo,
|
|
115
|
+
renderResult,
|
|
116
|
+
prettyPrint,
|
|
117
|
+
disconnect,
|
|
118
|
+
reconnect,
|
|
119
|
+
dispose,
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
export const singleClient = (
|
|
124
|
+
options: TestSetupOptions__SingleClient,
|
|
125
|
+
): RealtimeTestAPI__SingleClient => {
|
|
126
|
+
const server = setupRealtimeTestServer(options)
|
|
127
|
+
const client = setupRealtimeTestClient(options, `CLIENT`, server.port)
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
client,
|
|
131
|
+
server,
|
|
132
|
+
teardown: () => {
|
|
133
|
+
client.dispose()
|
|
134
|
+
server.dispose()
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const multiClient = <ClientNames extends string>(
|
|
140
|
+
options: TestSetupOptions__MultiClient<ClientNames>,
|
|
141
|
+
): RealtimeTestAPI__MultiClient<ClientNames> => {
|
|
142
|
+
const server = setupRealtimeTestServer(options)
|
|
143
|
+
const clients = RR.toEntries(options.clients).reduce(
|
|
144
|
+
(clients, [name, client]) => ({
|
|
145
|
+
...clients,
|
|
146
|
+
[name]: setupRealtimeTestClient({ ...options, client }, name, server.port),
|
|
147
|
+
}),
|
|
148
|
+
{} as Record<ClientNames, RealtimeTestClient>,
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
return {
|
|
152
|
+
clients,
|
|
153
|
+
server,
|
|
154
|
+
teardown: () => {
|
|
155
|
+
RR.toEntries(clients).forEach(([, client]) => client.dispose())
|
|
156
|
+
server.dispose()
|
|
157
|
+
},
|
|
158
|
+
}
|
|
159
|
+
}
|
package/src/selector.ts
CHANGED
|
@@ -1,65 +1,64 @@
|
|
|
1
|
-
import type * as Rx from "rxjs"
|
|
2
|
-
|
|
3
1
|
import type { Serializable } from "~/packages/anvl/src/json"
|
|
4
2
|
|
|
5
3
|
import type { ReadonlySelectorToken, SelectorToken } from "."
|
|
4
|
+
import type { Subject } from "./internal"
|
|
6
5
|
import { selectorFamily__INTERNAL, selector__INTERNAL } from "./internal"
|
|
7
6
|
import type { Read, Write } from "./transaction"
|
|
8
7
|
|
|
9
8
|
export type SelectorOptions<T> = {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
key: string
|
|
10
|
+
get: Read<() => T>
|
|
11
|
+
set: Write<(newValue: T) => void>
|
|
13
12
|
}
|
|
14
13
|
export type ReadonlySelectorOptions<T> = {
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
key: string
|
|
15
|
+
get: Read<() => T>
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
export function selector<T>(options: SelectorOptions<T>): SelectorToken<T>
|
|
20
19
|
export function selector<T>(
|
|
21
|
-
|
|
20
|
+
options: ReadonlySelectorOptions<T>,
|
|
22
21
|
): ReadonlySelectorToken<T>
|
|
23
22
|
export function selector<T>(
|
|
24
|
-
|
|
23
|
+
options: ReadonlySelectorOptions<T> | SelectorOptions<T>,
|
|
25
24
|
): ReadonlySelectorToken<T> | SelectorToken<T> {
|
|
26
|
-
|
|
25
|
+
return selector__INTERNAL(options)
|
|
27
26
|
}
|
|
28
27
|
|
|
29
28
|
export type SelectorFamilyOptions<T, K extends Serializable> = {
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
key: string
|
|
30
|
+
get: (key: K) => Read<() => T>
|
|
31
|
+
set: (key: K) => Write<(newValue: T) => void>
|
|
33
32
|
}
|
|
34
33
|
export type ReadonlySelectorFamilyOptions<T, K extends Serializable> = {
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
key: string
|
|
35
|
+
get: (key: K) => Read<() => T>
|
|
37
36
|
}
|
|
38
37
|
|
|
39
38
|
export type SelectorFamily<T, K extends Serializable = Serializable> = ((
|
|
40
|
-
|
|
39
|
+
key: K,
|
|
41
40
|
) => SelectorToken<T>) & {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
key: string
|
|
42
|
+
type: `selector_family`
|
|
43
|
+
subject: Subject<SelectorToken<T>>
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
export type ReadonlySelectorFamily<T, K extends Serializable = Serializable> = ((
|
|
48
|
-
|
|
47
|
+
key: K,
|
|
49
48
|
) => ReadonlySelectorToken<T>) & {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
key: string
|
|
50
|
+
type: `readonly_selector_family`
|
|
51
|
+
subject: Subject<ReadonlySelectorToken<T>>
|
|
53
52
|
}
|
|
54
53
|
|
|
55
54
|
export function selectorFamily<T, K extends Serializable>(
|
|
56
|
-
|
|
55
|
+
options: SelectorFamilyOptions<T, K>,
|
|
57
56
|
): SelectorFamily<T, K>
|
|
58
57
|
export function selectorFamily<T, K extends Serializable>(
|
|
59
|
-
|
|
58
|
+
options: ReadonlySelectorFamilyOptions<T, K>,
|
|
60
59
|
): ReadonlySelectorFamily<T, K>
|
|
61
60
|
export function selectorFamily<T, K extends Serializable>(
|
|
62
|
-
|
|
61
|
+
options: ReadonlySelectorFamilyOptions<T, K> | SelectorFamilyOptions<T, K>,
|
|
63
62
|
): ReadonlySelectorFamily<T, K> | SelectorFamily<T, K> {
|
|
64
|
-
|
|
63
|
+
return selectorFamily__INTERNAL(options)
|
|
65
64
|
}
|
package/src/silo.ts
CHANGED
|
@@ -3,15 +3,15 @@ import { getState, setState, subscribe } from "."
|
|
|
3
3
|
import type { atom, atomFamily } from "./atom"
|
|
4
4
|
import type { Store } from "./internal"
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
atomFamily__INTERNAL,
|
|
7
|
+
atom__INTERNAL,
|
|
8
|
+
createStore,
|
|
9
|
+
redo__INTERNAL,
|
|
10
|
+
selectorFamily__INTERNAL,
|
|
11
|
+
selector__INTERNAL,
|
|
12
|
+
timeline__INTERNAL,
|
|
13
|
+
transaction__INTERNAL,
|
|
14
|
+
undo__INTERNAL,
|
|
15
15
|
} from "./internal"
|
|
16
16
|
import type { selector, selectorFamily } from "./selector"
|
|
17
17
|
import type { transaction } from "./transaction"
|
|
@@ -19,35 +19,35 @@ import type { transaction } from "./transaction"
|
|
|
19
19
|
export type Silo = ReturnType<typeof silo>
|
|
20
20
|
|
|
21
21
|
export const silo = (
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
name: string,
|
|
23
|
+
fromStore: Store | null = null,
|
|
24
24
|
): {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
25
|
+
store: Store
|
|
26
|
+
atom: typeof atom
|
|
27
|
+
atomFamily: typeof atomFamily
|
|
28
|
+
selector: typeof selector
|
|
29
|
+
selectorFamily: typeof selectorFamily
|
|
30
|
+
transaction: typeof transaction
|
|
31
|
+
timeline: typeof timeline
|
|
32
|
+
getState: typeof getState
|
|
33
|
+
setState: typeof setState
|
|
34
|
+
subscribe: typeof subscribe
|
|
35
|
+
undo: typeof undo
|
|
36
|
+
redo: typeof redo
|
|
37
37
|
} => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
38
|
+
const store = createStore(name, fromStore)
|
|
39
|
+
return {
|
|
40
|
+
store,
|
|
41
|
+
atom: (options) => atom__INTERNAL(options, undefined, store),
|
|
42
|
+
atomFamily: (options) => atomFamily__INTERNAL(options, store),
|
|
43
|
+
selector: (options) => selector__INTERNAL(options, undefined, store) as any,
|
|
44
|
+
selectorFamily: (options) => selectorFamily__INTERNAL(options, store) as any,
|
|
45
|
+
transaction: (options) => transaction__INTERNAL(options, store),
|
|
46
|
+
timeline: (options) => timeline__INTERNAL(options, store),
|
|
47
|
+
getState: (token) => getState(token, store),
|
|
48
|
+
setState: (token, newValue) => setState(token, newValue, store),
|
|
49
|
+
subscribe: (token, handler) => subscribe(token, handler, store),
|
|
50
|
+
undo: (token) => undo__INTERNAL(token, store),
|
|
51
|
+
redo: (token) => redo__INTERNAL(token, store),
|
|
52
|
+
}
|
|
53
53
|
}
|
package/src/subscribe.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ƒn } from "~/packages/anvl/src/function"
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
4
|
+
ReadonlySelectorToken,
|
|
5
|
+
StateToken,
|
|
6
|
+
TimelineToken,
|
|
7
|
+
TimelineUpdate,
|
|
8
|
+
TransactionToken,
|
|
9
|
+
TransactionUpdate,
|
|
10
10
|
} from "."
|
|
11
11
|
import type { Store } from "./internal"
|
|
12
12
|
import { IMPLICIT, subscribeToRootAtoms, withdraw } from "./internal"
|
|
@@ -16,80 +16,80 @@ export type KeyedStateUpdate<T> = StateUpdate<T> & { key: string }
|
|
|
16
16
|
export type UpdateHandler<T> = (update: StateUpdate<T>) => void
|
|
17
17
|
|
|
18
18
|
export const subscribe = <T>(
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
19
|
+
token: ReadonlySelectorToken<T> | StateToken<T>,
|
|
20
|
+
handleUpdate: UpdateHandler<T>,
|
|
21
|
+
store: Store = IMPLICIT.STORE,
|
|
22
22
|
): (() => void) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
const state = withdraw<T>(token, store)
|
|
24
|
+
if (state === null) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
`State "${token.key}" not found in this store. Did you forget to initialize with the "atom" or "selector" function?`,
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
const subscription = state.subject.subscribe(handleUpdate)
|
|
30
|
+
store.config.logger?.info(`👀 subscribe to "${state.key}"`)
|
|
31
|
+
const dependencySubscriptions =
|
|
32
|
+
state.type !== `atom` ? subscribeToRootAtoms(state, store) : null
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
const unsubscribe =
|
|
35
|
+
dependencySubscriptions === null
|
|
36
|
+
? () => {
|
|
37
|
+
store.config.logger?.info(`🙈 unsubscribe from "${state.key}"`)
|
|
38
|
+
subscription.unsubscribe()
|
|
39
|
+
}
|
|
40
|
+
: () => {
|
|
41
|
+
store.config.logger?.info(
|
|
42
|
+
`🙈 unsubscribe from "${state.key}" and its dependencies`,
|
|
43
|
+
)
|
|
44
|
+
subscription.unsubscribe()
|
|
45
|
+
for (const dependencySubscription of dependencySubscriptions) {
|
|
46
|
+
dependencySubscription.unsubscribe()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
return unsubscribe
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
export type TransactionUpdateHandler<ƒ extends ƒn> = (
|
|
54
|
-
|
|
54
|
+
data: TransactionUpdate<ƒ>,
|
|
55
55
|
) => void
|
|
56
56
|
|
|
57
57
|
export const subscribeToTransaction = <ƒ extends ƒn>(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
58
|
+
token: TransactionToken<ƒ>,
|
|
59
|
+
handleUpdate: TransactionUpdateHandler<ƒ>,
|
|
60
|
+
store = IMPLICIT.STORE,
|
|
61
61
|
): (() => void) => {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
62
|
+
const tx = withdraw(token, store)
|
|
63
|
+
if (tx === null) {
|
|
64
|
+
throw new Error(
|
|
65
|
+
`Cannot subscribe to transaction "${token.key}": transaction not found in store "${store.config.name}".`,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
store.config.logger?.info(`👀 subscribe to transaction "${token.key}"`)
|
|
69
|
+
const subscription = tx.subject.subscribe(handleUpdate)
|
|
70
|
+
const unsubscribe = () => {
|
|
71
|
+
store.config.logger?.info(`🙈 unsubscribe from transaction "${token.key}"`)
|
|
72
|
+
subscription.unsubscribe()
|
|
73
|
+
}
|
|
74
|
+
return unsubscribe
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export const subscribeToTimeline = (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
token: TimelineToken,
|
|
79
|
+
handleUpdate: (update: TimelineUpdate) => void,
|
|
80
|
+
store = IMPLICIT.STORE,
|
|
81
81
|
): (() => void) => {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
82
|
+
const tl = withdraw(token, store)
|
|
83
|
+
if (tl === null) {
|
|
84
|
+
throw new Error(
|
|
85
|
+
`Cannot subscribe to timeline "${token.key}": timeline not found in store "${store.config.name}".`,
|
|
86
|
+
)
|
|
87
|
+
}
|
|
88
|
+
store.config.logger?.info(`👀 subscribe to timeline "${token.key}"`)
|
|
89
|
+
const subscription = tl.subject.subscribe(handleUpdate)
|
|
90
|
+
const unsubscribe = () => {
|
|
91
|
+
store.config.logger?.info(`🙈 unsubscribe from timeline "${token.key}"`)
|
|
92
|
+
subscription.unsubscribe()
|
|
93
|
+
}
|
|
94
|
+
return unsubscribe
|
|
95
95
|
}
|
package/src/timeline.ts
CHANGED
|
@@ -1,35 +1,35 @@
|
|
|
1
1
|
import type { AtomFamily, AtomToken } from "."
|
|
2
2
|
import type {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
TimelineAtomUpdate,
|
|
4
|
+
TimelineSelectorUpdate,
|
|
5
|
+
TimelineTransactionUpdate,
|
|
6
6
|
} from "./internal"
|
|
7
7
|
import { IMPLICIT } from "./internal"
|
|
8
8
|
import { redo__INTERNAL, timeline__INTERNAL, undo__INTERNAL } from "./internal/"
|
|
9
9
|
|
|
10
10
|
export type TimelineToken = {
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
key: string
|
|
12
|
+
type: `timeline`
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export type TimelineOptions = {
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
key: string
|
|
17
|
+
atoms: (AtomFamily<any, any> | AtomToken<any>)[]
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
export type TimelineUpdate =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
| TimelineAtomUpdate
|
|
22
|
+
| TimelineSelectorUpdate
|
|
23
|
+
| TimelineTransactionUpdate
|
|
24
24
|
|
|
25
25
|
export const timeline = (options: TimelineOptions): TimelineToken => {
|
|
26
|
-
|
|
26
|
+
return timeline__INTERNAL(options)
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
export const redo = (token: TimelineToken): void => {
|
|
30
|
-
|
|
30
|
+
redo__INTERNAL(token, IMPLICIT.STORE)
|
|
31
31
|
}
|
|
32
32
|
|
|
33
33
|
export const undo = (token: TimelineToken): void => {
|
|
34
|
-
|
|
34
|
+
undo__INTERNAL(token, IMPLICIT.STORE)
|
|
35
35
|
}
|