atom.io 0.6.7 → 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.
Files changed (129) hide show
  1. package/dist/index.d.mts +241 -263
  2. package/dist/index.d.ts +241 -263
  3. package/dist/index.js +28 -1911
  4. package/dist/index.js.map +1 -1
  5. package/dist/index.mjs +5 -1871
  6. package/dist/index.mjs.map +1 -1
  7. package/introspection/dist/index.d.mts +121 -176
  8. package/introspection/dist/index.d.ts +121 -176
  9. package/introspection/dist/index.js +6 -346
  10. package/introspection/dist/index.js.map +1 -1
  11. package/introspection/dist/index.mjs +5 -324
  12. package/introspection/dist/index.mjs.map +1 -1
  13. package/json/dist/index.d.mts +37 -8
  14. package/json/dist/index.d.ts +37 -8
  15. package/json/dist/index.js +31 -48
  16. package/json/dist/index.js.map +1 -1
  17. package/json/dist/index.mjs +6 -14
  18. package/json/dist/index.mjs.map +1 -1
  19. package/package.json +30 -14
  20. package/react/dist/index.js +34 -83
  21. package/react/dist/index.js.map +1 -1
  22. package/react/dist/index.mjs +7 -43
  23. package/react/dist/index.mjs.map +1 -1
  24. package/react-devtools/dist/index.css +1 -42
  25. package/react-devtools/dist/index.css.map +1 -1
  26. package/react-devtools/dist/index.d.mts +128 -193
  27. package/react-devtools/dist/index.d.ts +128 -193
  28. package/react-devtools/dist/index.js +56 -4154
  29. package/react-devtools/dist/index.js.map +1 -1
  30. package/react-devtools/dist/index.mjs +19 -4117
  31. package/react-devtools/dist/index.mjs.map +1 -1
  32. package/realtime/dist/index.d.mts +7 -11
  33. package/realtime/dist/index.d.ts +7 -11
  34. package/realtime/dist/index.js +26 -185
  35. package/realtime/dist/index.js.map +1 -1
  36. package/realtime/dist/index.mjs +4 -149
  37. package/realtime/dist/index.mjs.map +1 -1
  38. package/realtime-react/dist/index.d.mts +12 -16
  39. package/realtime-react/dist/index.d.ts +12 -16
  40. package/realtime-react/dist/index.js +41 -214
  41. package/realtime-react/dist/index.js.map +1 -1
  42. package/realtime-react/dist/index.mjs +9 -169
  43. package/realtime-react/dist/index.mjs.map +1 -1
  44. package/src/atom.ts +7 -6
  45. package/src/index.ts +12 -9
  46. package/src/logger.ts +5 -5
  47. package/src/selector.ts +16 -14
  48. package/src/silo.ts +36 -39
  49. package/src/subscribe.ts +25 -20
  50. package/src/timeline.ts +9 -4
  51. package/src/transaction.ts +3 -4
  52. package/src/internal/atom-internal.ts +0 -54
  53. package/src/internal/families-internal.ts +0 -141
  54. package/src/internal/get.ts +0 -129
  55. package/src/internal/index.ts +0 -15
  56. package/src/internal/is-default.ts +0 -35
  57. package/src/internal/operation.ts +0 -139
  58. package/src/internal/selector/create-read-write-selector.ts +0 -66
  59. package/src/internal/selector/create-readonly-selector.ts +0 -46
  60. package/src/internal/selector/index.ts +0 -4
  61. package/src/internal/selector/lookup-selector-sources.ts +0 -16
  62. package/src/internal/selector/register-selector.ts +0 -57
  63. package/src/internal/selector/trace-selector-atoms.ts +0 -43
  64. package/src/internal/selector/update-selector-atoms.ts +0 -33
  65. package/src/internal/selector-internal.ts +0 -58
  66. package/src/internal/set.ts +0 -99
  67. package/src/internal/store.ts +0 -151
  68. package/src/internal/subject.ts +0 -24
  69. package/src/internal/subscribe-internal.ts +0 -88
  70. package/src/internal/time-travel-internal.ts +0 -91
  71. package/src/internal/timeline/add-atom-to-timeline.ts +0 -168
  72. package/src/internal/timeline/index.ts +0 -1
  73. package/src/internal/timeline-internal.ts +0 -107
  74. package/src/internal/transaction/abort-transaction.ts +0 -12
  75. package/src/internal/transaction/apply-transaction.ts +0 -57
  76. package/src/internal/transaction/build-transaction.ts +0 -33
  77. package/src/internal/transaction/index.ts +0 -25
  78. package/src/internal/transaction/redo-transaction.ts +0 -23
  79. package/src/internal/transaction/undo-transaction.ts +0 -23
  80. package/src/internal/transaction-internal.ts +0 -61
  81. package/src/introspection/attach-atom-index.ts +0 -73
  82. package/src/introspection/attach-introspection-states.ts +0 -42
  83. package/src/introspection/attach-selector-index.ts +0 -77
  84. package/src/introspection/attach-timeline-family.ts +0 -59
  85. package/src/introspection/attach-timeline-index.ts +0 -36
  86. package/src/introspection/attach-transaction-index.ts +0 -38
  87. package/src/introspection/attach-transaction-logs.ts +0 -40
  88. package/src/introspection/index.ts +0 -20
  89. package/src/json/index.ts +0 -1
  90. package/src/json/select-json.ts +0 -18
  91. package/src/react/index.ts +0 -2
  92. package/src/react/store-context.tsx +0 -13
  93. package/src/react/store-hooks.ts +0 -47
  94. package/src/react-devtools/AtomIODevtools.tsx +0 -107
  95. package/src/react-devtools/Button.tsx +0 -24
  96. package/src/react-devtools/StateEditor.tsx +0 -70
  97. package/src/react-devtools/StateIndex.tsx +0 -153
  98. package/src/react-devtools/TimelineIndex.tsx +0 -92
  99. package/src/react-devtools/TransactionIndex.tsx +0 -70
  100. package/src/react-devtools/Updates.tsx +0 -145
  101. package/src/react-devtools/devtools.scss +0 -311
  102. package/src/react-devtools/index.ts +0 -72
  103. package/src/react-explorer/AtomIOExplorer.tsx +0 -218
  104. package/src/react-explorer/explorer-effects.ts +0 -20
  105. package/src/react-explorer/explorer-states.ts +0 -217
  106. package/src/react-explorer/index.ts +0 -23
  107. package/src/react-explorer/space-states.ts +0 -72
  108. package/src/react-explorer/view-states.ts +0 -41
  109. package/src/realtime/README.md +0 -33
  110. package/src/realtime/hook-composition/expose-family.ts +0 -101
  111. package/src/realtime/hook-composition/expose-single.ts +0 -38
  112. package/src/realtime/hook-composition/expose-timeline.ts +0 -60
  113. package/src/realtime/hook-composition/index.ts +0 -12
  114. package/src/realtime/hook-composition/receive-state.ts +0 -29
  115. package/src/realtime/hook-composition/receive-transaction.ts +0 -18
  116. package/src/realtime/index.ts +0 -1
  117. package/src/realtime-react/index.ts +0 -3
  118. package/src/realtime-react/realtime-context.tsx +0 -30
  119. package/src/realtime-react/realtime-hooks.ts +0 -39
  120. package/src/realtime-react/realtime-state.ts +0 -10
  121. package/src/realtime-react/use-pull-family-member.ts +0 -26
  122. package/src/realtime-react/use-pull-family.ts +0 -24
  123. package/src/realtime-react/use-pull.ts +0 -22
  124. package/src/realtime-react/use-push.ts +0 -25
  125. package/src/realtime-react/use-server-action.ts +0 -33
  126. package/src/realtime-testing/index.ts +0 -1
  127. package/src/realtime-testing/setup-realtime-test.tsx +0 -159
  128. package/src/web-effects/index.ts +0 -1
  129. package/src/web-effects/storage.ts +0 -30
@@ -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>(
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.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>(
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>(
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
- }
@@ -1 +0,0 @@
1
- export * from "./hook-composition"
@@ -1,3 +0,0 @@
1
- export * from "./realtime-context"
2
- export * from "./realtime-hooks"
3
- export * from "./realtime-state"
@@ -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
- }
@@ -1,39 +0,0 @@
1
- import type * as AtomIO from "atom.io"
2
-
3
- import type { ƒn } from "~/packages/anvl/src/function"
4
- import type { Json } from "~/packages/anvl/src/json"
5
-
6
- import { usePull } from "./use-pull"
7
- import { usePullFamily } from "./use-pull-family"
8
- import { usePullFamilyMember } from "./use-pull-family-member"
9
- import { usePush } from "./use-push"
10
- import { useServerAction } from "./use-server-action"
11
-
12
- export type RealtimeHooks = {
13
- usePull: <J extends Json>(token: AtomIO.StateToken<J>) => void
14
- usePullFamily: <J extends Json>(
15
- family: AtomIO.AtomFamily<J> | AtomIO.SelectorFamily<J>,
16
- ) => void
17
- usePullFamilyMember: <J extends Json>(
18
- family: AtomIO.AtomFamily<J> | AtomIO.SelectorFamily<J>,
19
- subKey: string,
20
- ) => void
21
- usePush: <J extends Json>(token: AtomIO.StateToken<J>) => void
22
- useServerAction: <ƒ extends ƒn>(
23
- token: AtomIO.TransactionToken<ƒ>,
24
- ) => (...parameters: Parameters<ƒ>) => ReturnType<ƒ>
25
- }
26
-
27
- export const realtimeHooks: RealtimeHooks = {
28
- usePull,
29
- usePullFamily,
30
- usePullFamilyMember,
31
- usePush,
32
- useServerAction,
33
- }
34
-
35
- export * from "./use-pull"
36
- export * from "./use-pull-family"
37
- export * from "./use-pull-family-member"
38
- export * from "./use-push"
39
- export * from "./use-server-action"
@@ -1,10 +0,0 @@
1
- import * as AtomIO from "atom.io"
2
-
3
- export const myIdState__INTERNAL = AtomIO.atom<string | null>({
4
- key: `myId__INTERNAL`,
5
- default: null,
6
- })
7
- export const myIdState = AtomIO.selector<string | null>({
8
- key: `myId`,
9
- get: ({ get }) => get(myIdState__INTERNAL),
10
- })
@@ -1,26 +0,0 @@
1
- import * as AtomIO from "atom.io"
2
- import * as React from "react"
3
-
4
- import type { Json } from "~/packages/anvl/src/json"
5
-
6
- import { RealtimeContext } from "./realtime-context"
7
- import { StoreContext } from "../react"
8
-
9
- export function usePullFamilyMember<J extends Json>(
10
- family: AtomIO.AtomFamily<J> | AtomIO.SelectorFamily<J>,
11
- subKey: AtomIO.Serializable,
12
- ): void {
13
- const token = family(subKey)
14
- const { socket } = React.useContext(RealtimeContext)
15
- const store = React.useContext(StoreContext)
16
- React.useEffect(() => {
17
- socket?.on(`serve:${token.key}`, (data: J) => {
18
- AtomIO.setState(family(subKey), data, store)
19
- })
20
- socket?.emit(`sub:${family.key}`, subKey)
21
- return () => {
22
- socket?.off(`serve:${token.key}`)
23
- socket?.emit(`unsub:${token.key}`)
24
- }
25
- }, [family.key])
26
- }
@@ -1,24 +0,0 @@
1
- import * as AtomIO from "atom.io"
2
- import * as React from "react"
3
-
4
- import type { Json } from "~/packages/anvl/src/json"
5
-
6
- import { RealtimeContext } from "./realtime-context"
7
- import { StoreContext } from "../react"
8
-
9
- export function usePullFamily<J extends Json>(
10
- family: AtomIO.AtomFamily<J> | AtomIO.SelectorFamily<J>,
11
- ): void {
12
- const { socket } = React.useContext(RealtimeContext)
13
- const store = React.useContext(StoreContext)
14
- React.useEffect(() => {
15
- socket.on(`serve:${family.key}`, (key: Json, data: J) => {
16
- AtomIO.setState(family(key), data, store)
17
- })
18
- socket?.emit(`sub:${family.key}`)
19
- return () => {
20
- socket?.off(`serve:${family.key}`)
21
- socket?.emit(`unsub:${family.key}`)
22
- }
23
- }, [family.key])
24
- }
@@ -1,22 +0,0 @@
1
- import * as AtomIO from "atom.io"
2
- import * as React from "react"
3
-
4
- import type { Json } from "~/packages/anvl/src/json"
5
-
6
- import { RealtimeContext } from "./realtime-context"
7
- import { StoreContext } from "../react"
8
-
9
- export function usePull<J extends Json>(token: AtomIO.StateToken<J>): void {
10
- const { socket } = React.useContext(RealtimeContext)
11
- const store = React.useContext(StoreContext)
12
- React.useEffect(() => {
13
- socket.on(`serve:${token.key}`, (data: J) => {
14
- AtomIO.setState(token, data, store)
15
- })
16
- socket.emit(`sub:${token.key}`)
17
- return () => {
18
- socket.off(`serve:${token.key}`)
19
- socket.emit(`unsub:${token.key}`)
20
- }
21
- }, [token.key])
22
- }
@@ -1,25 +0,0 @@
1
- import * as AtomIO from "atom.io"
2
- import * as React from "react"
3
-
4
- import type { Json } from "~/packages/anvl/src/json"
5
-
6
- import { RealtimeContext } from "./realtime-context"
7
- import { StoreContext } from "../react"
8
-
9
- export function usePush<J extends Json>(token: AtomIO.StateToken<J>): void {
10
- const { socket } = React.useContext(RealtimeContext)
11
- const store = React.useContext(StoreContext)
12
- React.useEffect(() => {
13
- socket.emit(`claim:${token.key}`)
14
- AtomIO.subscribe(
15
- token,
16
- ({ newValue }) => {
17
- socket.emit(`pub:${token.key}`, newValue)
18
- },
19
- store,
20
- )
21
- return () => {
22
- socket.emit(`unclaim:${token.key}`)
23
- }
24
- }, [token.key])
25
- }
@@ -1,33 +0,0 @@
1
- import * as AtomIO from "atom.io"
2
- import { StoreContext } from "atom.io/react"
3
- import * as React from "react"
4
-
5
- import type { ƒn } from "~/packages/anvl/src/function"
6
-
7
- import { RealtimeContext } from "./realtime-context"
8
-
9
- const TX_SUBS = new Map<string, number>()
10
- export function useServerAction<ƒ extends ƒn>(
11
- token: AtomIO.TransactionToken<ƒ>,
12
- ): (...parameters: Parameters<ƒ>) => ReturnType<ƒ> {
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)
33
- }
@@ -1 +0,0 @@
1
- export * from "./setup-realtime-test"
@@ -1,159 +0,0 @@
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
- }
@@ -1 +0,0 @@
1
- export * from "./storage"
@@ -1,30 +0,0 @@
1
- import type { Json } from "~/packages/anvl/src/json"
2
-
3
- import type { AtomEffect } from "../index"
4
-
5
- export type StringInterface<T> = {
6
- stringify: (t: T) => string
7
- parse: (s: string) => T
8
- }
9
-
10
- export const persistAtom =
11
- <T>(storage: Storage) =>
12
- ({ stringify, parse }: StringInterface<T>) =>
13
- (key: string): AtomEffect<T> =>
14
- ({ setSelf, onSet }) => {
15
- const savedValue = storage.getItem(key)
16
-
17
- if (savedValue != null) setSelf(parse(savedValue))
18
-
19
- onSet(({ newValue }) => {
20
- if (newValue == null) {
21
- storage.removeItem(key)
22
- return
23
- }
24
- storage.setItem(key, stringify(newValue))
25
- })
26
- }
27
-
28
- export const lazyLocalStorageEffect: <J extends Json>(
29
- key: string,
30
- ) => AtomEffect<J> = persistAtom(localStorage)(JSON)