atom.io 0.40.6 → 0.40.8

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 (186) hide show
  1. package/README.md +1 -1
  2. package/dist/data/index.d.ts +1 -1
  3. package/dist/data/index.js +1 -2
  4. package/dist/data/index.js.map +1 -1
  5. package/dist/employ-socket-D6wgByWh.js +12 -0
  6. package/dist/employ-socket-D6wgByWh.js.map +1 -0
  7. package/dist/eslint-plugin/index.js.map +1 -1
  8. package/dist/has-role-CMlaUlaf.js +1133 -0
  9. package/dist/has-role-CMlaUlaf.js.map +1 -0
  10. package/dist/internal/index.d.ts +248 -248
  11. package/dist/internal/index.d.ts.map +1 -1
  12. package/dist/internal/index.js +590 -1803
  13. package/dist/internal/index.js.map +1 -1
  14. package/dist/introspection/index.d.ts +1 -1
  15. package/dist/introspection/index.d.ts.map +1 -1
  16. package/dist/introspection/index.js +13 -32
  17. package/dist/introspection/index.js.map +1 -1
  18. package/dist/is-fn-DY1wZ-md.js +10 -0
  19. package/dist/is-fn-DY1wZ-md.js.map +1 -0
  20. package/dist/json/index.d.ts.map +1 -1
  21. package/dist/json/index.js.map +1 -1
  22. package/dist/main/index.d.ts +33 -33
  23. package/dist/main/index.d.ts.map +1 -1
  24. package/dist/main/index.js +3 -4
  25. package/dist/main/index.js.map +1 -1
  26. package/dist/mutex-store-CSvxY9i3.js +11 -0
  27. package/dist/mutex-store-CSvxY9i3.js.map +1 -0
  28. package/dist/react/index.d.ts +5 -5
  29. package/dist/react/index.d.ts.map +1 -1
  30. package/dist/react/index.js.map +1 -1
  31. package/dist/react-devtools/index.d.ts.map +1 -1
  32. package/dist/react-devtools/index.js +9 -11
  33. package/dist/react-devtools/index.js.map +1 -1
  34. package/dist/realtime/index.d.ts +7 -15
  35. package/dist/realtime/index.d.ts.map +1 -1
  36. package/dist/realtime/index.js +4 -35
  37. package/dist/realtime/index.js.map +1 -1
  38. package/dist/realtime-client/index.d.ts +6 -9
  39. package/dist/realtime-client/index.d.ts.map +1 -1
  40. package/dist/realtime-client/index.js +96 -88
  41. package/dist/realtime-client/index.js.map +1 -1
  42. package/dist/realtime-react/index.d.ts +17 -13
  43. package/dist/realtime-react/index.d.ts.map +1 -1
  44. package/dist/realtime-react/index.js +39 -50
  45. package/dist/realtime-react/index.js.map +1 -1
  46. package/dist/realtime-server/index.d.ts +83 -84
  47. package/dist/realtime-server/index.d.ts.map +1 -1
  48. package/dist/realtime-server/index.js +604 -543
  49. package/dist/realtime-server/index.js.map +1 -1
  50. package/dist/realtime-testing/index.d.ts +5 -4
  51. package/dist/realtime-testing/index.d.ts.map +1 -1
  52. package/dist/realtime-testing/index.js +35 -22
  53. package/dist/realtime-testing/index.js.map +1 -1
  54. package/dist/shared-room-store-BfW3nWif.js +31 -0
  55. package/dist/shared-room-store-BfW3nWif.js.map +1 -0
  56. package/dist/shared-room-store-D2o4ZLjC.d.ts +15 -0
  57. package/dist/shared-room-store-D2o4ZLjC.d.ts.map +1 -0
  58. package/dist/transceivers/set-rtx/index.d.ts.map +1 -1
  59. package/dist/transceivers/set-rtx/index.js +4 -8
  60. package/dist/transceivers/set-rtx/index.js.map +1 -1
  61. package/dist/web/index.d.ts +3 -3
  62. package/dist/web/index.d.ts.map +1 -1
  63. package/dist/web/index.js +4 -3
  64. package/dist/web/index.js.map +1 -1
  65. package/package.json +13 -13
  66. package/src/internal/atom/create-regular-atom.ts +5 -4
  67. package/src/internal/atom/dispose-atom.ts +7 -2
  68. package/src/internal/atom/has-role.ts +3 -3
  69. package/src/internal/caching.ts +4 -2
  70. package/src/internal/families/create-readonly-held-selector-family.ts +2 -1
  71. package/src/internal/families/create-readonly-pure-selector-family.ts +5 -2
  72. package/src/internal/families/create-regular-atom-family.ts +2 -1
  73. package/src/internal/families/create-writable-held-selector-family.ts +2 -1
  74. package/src/internal/families/create-writable-pure-selector-family.ts +5 -2
  75. package/src/internal/families/dispose-from-store.ts +4 -4
  76. package/src/internal/families/find-in-store.ts +10 -10
  77. package/src/internal/families/get-family-of-token.ts +2 -2
  78. package/src/internal/families/index.ts +1 -0
  79. package/src/internal/families/mint-in-store.ts +54 -19
  80. package/src/internal/families/seek-in-store.ts +1 -1
  81. package/src/internal/get-state/get-fallback.ts +2 -2
  82. package/src/internal/get-state/get-from-store.ts +5 -5
  83. package/src/internal/get-state/read-or-compute-value.ts +1 -1
  84. package/src/internal/get-state/reduce-reference.ts +8 -6
  85. package/src/internal/index.ts +2 -220
  86. package/src/internal/molecule.ts +1 -2
  87. package/src/internal/mutable/create-mutable-atom-family.ts +3 -2
  88. package/src/internal/mutable/create-mutable-atom.ts +4 -2
  89. package/src/internal/mutable/get-json-family.ts +1 -1
  90. package/src/internal/mutable/get-update-family.ts +1 -1
  91. package/src/internal/mutable/tracker-family.ts +2 -1
  92. package/src/internal/mutable/tracker.ts +71 -59
  93. package/src/internal/safe-compute.ts +1 -1
  94. package/src/internal/selector/create-readonly-held-selector.ts +2 -1
  95. package/src/internal/selector/create-readonly-pure-selector.ts +2 -1
  96. package/src/internal/selector/create-writable-held-selector.ts +2 -1
  97. package/src/internal/selector/create-writable-pure-selector.ts +2 -1
  98. package/src/internal/selector/dispose-selector.ts +3 -2
  99. package/src/internal/selector/register-selector.ts +8 -5
  100. package/src/internal/selector/trace-selector-atoms.ts +2 -1
  101. package/src/internal/set-state/dispatch-state-update.ts +3 -2
  102. package/src/internal/set-state/evict-downstream.ts +1 -1
  103. package/src/internal/set-state/operate-on-store.ts +16 -22
  104. package/src/internal/set-state/reset-atom-or-selector.ts +5 -3
  105. package/src/internal/set-state/reset-in-store.ts +5 -5
  106. package/src/internal/set-state/set-atom-or-selector.ts +2 -2
  107. package/src/internal/set-state/set-atom.ts +4 -2
  108. package/src/internal/set-state/set-into-store.ts +21 -39
  109. package/src/internal/set-state/set-selector.ts +3 -2
  110. package/src/internal/state-types.ts +228 -0
  111. package/src/internal/store/deposit.ts +4 -4
  112. package/src/internal/store/index.ts +0 -1
  113. package/src/internal/store/store.ts +9 -9
  114. package/src/internal/store/withdraw.ts +4 -4
  115. package/src/internal/subscribe/recall-state.ts +1 -1
  116. package/src/internal/subscribe/subscribe-to-root-atoms.ts +1 -12
  117. package/src/internal/subscribe/subscribe-to-state.ts +9 -0
  118. package/src/internal/subscribe/subscribe-to-transaction.ts +3 -2
  119. package/src/internal/transaction/build-transaction.ts +3 -2
  120. package/src/internal/transaction/index.ts +1 -23
  121. package/src/internal/transaction/is-root-store.ts +4 -1
  122. package/src/internal/transaction/transaction-meta-progress.ts +22 -0
  123. package/src/main/atom.ts +1 -2
  124. package/src/main/find-state.ts +5 -5
  125. package/src/main/get-state.ts +4 -4
  126. package/src/main/realm.ts +2 -2
  127. package/src/main/set-state.ts +10 -10
  128. package/src/react/parse-state-overloads.ts +3 -3
  129. package/src/react/use-i.ts +6 -4
  130. package/src/react/use-loadable.ts +4 -10
  131. package/src/react/use-o.ts +6 -4
  132. package/src/react-devtools/store.ts +6 -6
  133. package/src/realtime/index.ts +1 -0
  134. package/src/realtime/mutex-store.ts +11 -0
  135. package/src/realtime/realtime-continuity.ts +1 -5
  136. package/src/realtime-client/index.ts +0 -1
  137. package/src/realtime-client/pull-atom-family-member.ts +14 -17
  138. package/src/realtime-client/pull-atom.ts +1 -1
  139. package/src/realtime-client/pull-mutable-atom-family-member.ts +16 -12
  140. package/src/realtime-client/pull-selector-family-member.ts +8 -35
  141. package/src/realtime-client/pull-selector-roots.ts +90 -0
  142. package/src/realtime-client/pull-selector.ts +2 -27
  143. package/src/realtime-client/push-state.ts +33 -5
  144. package/src/realtime-client/realtime-client-stores/client-main-store.ts +2 -5
  145. package/src/realtime-react/index.ts +2 -2
  146. package/src/realtime-react/realtime-context.tsx +9 -5
  147. package/src/realtime-react/use-pull-atom-family-member.ts +2 -3
  148. package/src/realtime-react/use-pull-mutable-family-member.ts +2 -3
  149. package/src/realtime-react/use-pull-selector-family-member.ts +5 -6
  150. package/src/realtime-react/use-push.ts +7 -3
  151. package/src/realtime-react/use-realtime-service.ts +11 -11
  152. package/src/realtime-react/use-single-effect.ts +11 -14
  153. package/src/realtime-server/{realtime-server-stores/server-sync-store.ts → continuity/continuity-store.ts} +2 -27
  154. package/src/realtime-server/continuity/provide-continuity.ts +50 -0
  155. package/src/realtime-server/continuity/{subscribe-to-continuity-actions.ts → provide-outcomes.ts} +15 -13
  156. package/src/realtime-server/continuity/{subscribe-to-continuity-perpectives.ts → provide-perspectives.ts} +10 -8
  157. package/src/realtime-server/continuity/{prepare-to-send-initial-payload.ts → provide-startup-payloads.ts} +6 -4
  158. package/src/realtime-server/continuity/receive-action-requests.ts +68 -0
  159. package/src/realtime-server/continuity/track-acknowledgements.ts +46 -0
  160. package/src/realtime-server/employ-socket.ts +14 -0
  161. package/src/realtime-server/index.ts +3 -22
  162. package/src/realtime-server/ipc-sockets/child-socket.ts +125 -66
  163. package/src/realtime-server/ipc-sockets/custom-socket.ts +16 -14
  164. package/src/realtime-server/ipc-sockets/parent-socket.ts +98 -69
  165. package/src/realtime-server/realtime-family-provider.ts +78 -29
  166. package/src/realtime-server/realtime-mutable-family-provider.ts +80 -31
  167. package/src/realtime-server/realtime-mutable-provider.ts +30 -22
  168. package/src/realtime-server/realtime-server-stores/index.ts +0 -2
  169. package/src/realtime-server/realtime-server-stores/server-room-external-store.ts +77 -36
  170. package/src/realtime-server/realtime-server-stores/server-user-store.ts +12 -1
  171. package/src/realtime-server/realtime-state-provider.ts +30 -29
  172. package/src/realtime-server/realtime-state-receiver.ts +62 -16
  173. package/src/realtime-server/server-config.ts +8 -0
  174. package/src/realtime-server/socket-interface.ts +14 -0
  175. package/src/realtime-testing/setup-realtime-test.tsx +70 -31
  176. package/src/web/index.ts +1 -1
  177. package/src/web/{persist-sync.ts → storage-sync.ts} +5 -2
  178. package/src/internal/store/mint-or-counterfeit.ts +0 -108
  179. package/src/realtime-client/server-action.ts +0 -23
  180. package/src/realtime-react/on-mount.ts +0 -5
  181. package/src/realtime-react/use-server-action.ts +0 -19
  182. package/src/realtime-server/continuity/prepare-to-serve-transaction-request.ts +0 -59
  183. package/src/realtime-server/continuity/prepare-to-sync-realtime-continuity.ts +0 -145
  184. package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +0 -41
  185. package/src/realtime-server/realtime-action-receiver.ts +0 -40
  186. package/src/realtime-server/realtime-server-stores/server-room-external-actions.ts +0 -79
@@ -1,48 +1,89 @@
1
1
  import type { ChildProcessWithoutNullStreams } from "node:child_process"
2
2
  import { spawn } from "node:child_process"
3
3
 
4
- import type {
5
- Loadable,
6
- ReadonlyPureSelectorFamilyToken,
7
- RegularAtomFamilyToken,
8
- } from "atom.io"
9
- import { atomFamily, selectorFamily } from "atom.io"
4
+ import type { TransactionIO, TransactionToken } from "atom.io"
5
+ import { transaction } from "atom.io"
6
+ import { editRelationsInStore } from "atom.io/internal"
7
+ import type { UserInRoomMeta } from "atom.io/realtime/shared-room-store"
8
+ import { roomIndex, usersInRooms } from "atom.io/realtime/shared-room-store"
10
9
 
11
10
  import { ChildSocket } from "../ipc-sockets"
11
+ import type { RoomKey } from "./server-user-store"
12
12
 
13
- export type RoomArguments =
14
- | [script: string, options: string[]]
15
- | [script: string]
13
+ export const ROOMS: Map<
14
+ string,
15
+ ChildSocket<any, any, ChildProcessWithoutNullStreams>
16
+ > = new Map()
16
17
 
17
- export const roomArgumentsAtoms: RegularAtomFamilyToken<RoomArguments, string> =
18
- atomFamily<RoomArguments, string>({
19
- key: `roomArguments`,
20
- default: [`echo`, [`Hello World!`]],
18
+ export async function spawnRoom(
19
+ roomId: string,
20
+ script: string,
21
+ options: string[],
22
+ ): Promise<ChildSocket<any, any>> {
23
+ const child = await new Promise<ChildProcessWithoutNullStreams>((resolve) => {
24
+ const room = spawn(script, options, { env: process.env })
25
+ const resolver = (data: Buffer) => {
26
+ if (data.toString() === `ALIVE`) {
27
+ room.stdout.off(`data`, resolver)
28
+ resolve(room)
29
+ }
30
+ }
31
+ room.stdout.on(`data`, resolver)
21
32
  })
33
+ ROOMS.set(roomId, new ChildSocket(child, roomId))
34
+ return new ChildSocket(child, roomId)
35
+ }
22
36
 
23
- export const roomSelectors: ReadonlyPureSelectorFamilyToken<
24
- Loadable<ChildSocket<any, any>>,
25
- string
26
- > = selectorFamily<Loadable<ChildSocket<any, any>>, string>({
27
- key: `room`,
28
- get:
29
- (roomId) =>
30
- async ({ get, find }) => {
31
- const argumentsState = find(roomArgumentsAtoms, roomId)
32
- const args = get(argumentsState)
33
- const [script, options] = args
34
- const child = await new Promise<ChildProcessWithoutNullStreams>(
35
- (resolve) => {
36
- const room = spawn(script, options, { env: process.env })
37
- const resolver = (data: Buffer) => {
38
- if (data.toString() === `ALIVE`) {
39
- room.stdout.off(`data`, resolver)
40
- resolve(room)
41
- }
42
- }
43
- room.stdout.on(`data`, resolver)
37
+ export const joinRoomTX: TransactionToken<
38
+ (roomId: string, userId: string, enteredAtEpoch: number) => UserInRoomMeta
39
+ > = transaction({
40
+ key: `joinRoom`,
41
+ do: (tools, roomId, userId, enteredAtEpoch) => {
42
+ const meta = { enteredAtEpoch }
43
+ editRelationsInStore(
44
+ usersInRooms,
45
+ (relations) => {
46
+ relations.set({ room: roomId, user: userId }, meta)
47
+ },
48
+ tools.env().store,
49
+ )
50
+ return meta
51
+ },
52
+ })
53
+ export type JoinRoomIO = TransactionIO<typeof joinRoomTX>
54
+
55
+ export const leaveRoomTX: TransactionToken<
56
+ (roomId: string, userId: string) => void
57
+ > = transaction({
58
+ key: `leaveRoom`,
59
+ do: ({ env }, roomId, userId) => {
60
+ editRelationsInStore(
61
+ usersInRooms,
62
+ (relations) => {
63
+ relations.delete({ room: roomId, user: userId })
64
+ },
65
+ env().store,
66
+ )
67
+ },
68
+ })
69
+ export type LeaveRoomIO = TransactionIO<typeof leaveRoomTX>
70
+
71
+ export const destroyRoomTX: TransactionToken<(roomKey: RoomKey) => void> =
72
+ transaction({
73
+ key: `destroyRoom`,
74
+ do: ({ set, env }, roomId) => {
75
+ editRelationsInStore(
76
+ usersInRooms,
77
+ (relations) => {
78
+ relations.delete({ room: roomId })
44
79
  },
80
+ env().store,
45
81
  )
46
- return new ChildSocket(child, roomId)
82
+ set(roomIndex, (s) => (s.delete(roomId), s))
83
+ const room = ROOMS.get(roomId)
84
+ if (room) {
85
+ room.emit(`exit`)
86
+ ROOMS.delete(roomId)
87
+ }
47
88
  },
48
- })
89
+ })
@@ -2,9 +2,10 @@ import type {
2
2
  Hierarchy,
3
3
  JoinToken,
4
4
  MutableAtomToken,
5
+ PureSelectorFamilyToken,
5
6
  RegularAtomFamilyToken,
6
7
  } from "atom.io"
7
- import { atomFamily, join, mutableAtom } from "atom.io"
8
+ import { atomFamily, join, mutableAtom, selectorFamily } from "atom.io"
8
9
  import { SetRTX } from "atom.io/transceivers/set-rtx"
9
10
 
10
11
  import type { Socket } from ".."
@@ -53,3 +54,13 @@ export const usersOfSockets: JoinToken<
53
54
  isAType: (s): s is UserKey => s.startsWith(`user::`),
54
55
  isBType: (s): s is SocketKey => s.startsWith(`socket::`),
55
56
  })
57
+
58
+ export const userMutualSituationalAwarenessIndexes: PureSelectorFamilyToken<
59
+ UserKey[],
60
+ UserKey
61
+ > = selectorFamily<UserKey[], UserKey>({
62
+ key: `userMutualSituationalAwarenessIndexes`,
63
+ get: (userId) => () => {
64
+ return [userId]
65
+ },
66
+ })
@@ -3,6 +3,7 @@ import { getFromStore, IMPLICIT, subscribeToState } from "atom.io/internal"
3
3
  import type { Json } from "atom.io/json"
4
4
 
5
5
  import type { ServerConfig } from "."
6
+ import { employSocket } from "./employ-socket"
6
7
 
7
8
  export type StateProvider = ReturnType<typeof realtimeStateProvider>
8
9
  export function realtimeStateProvider({
@@ -12,39 +13,39 @@ export function realtimeStateProvider({
12
13
  return function stateProvider<J extends Json.Serializable>(
13
14
  token: AtomIO.WritableToken<J>,
14
15
  ): () => void {
15
- let unsubscribeFromStateUpdates: (() => void) | undefined
16
-
17
- const fillSubRequest = () => {
18
- socket.emit(`serve:${token.key}`, getFromStore(store, token))
16
+ const subscriptions = new Set<() => void>()
17
+ const clearSubscriptions = () => {
18
+ for (const unsub of subscriptions) unsub()
19
+ subscriptions.clear()
20
+ }
19
21
 
20
- unsubscribeFromStateUpdates = subscribeToState(
21
- store,
22
- token,
23
- `expose-single:${socket.id}`,
24
- ({ newValue }) => {
25
- socket.emit(`serve:${token.key}`, newValue)
26
- },
22
+ const start = () => {
23
+ subscriptions.add(
24
+ employSocket(socket, `sub:${token.key}`, () => {
25
+ clearSubscriptions()
26
+ socket.emit(`serve:${token.key}`, getFromStore(store, token))
27
+ subscriptions.add(
28
+ subscribeToState(
29
+ store,
30
+ token,
31
+ `expose-single:${socket.id}`,
32
+ ({ newValue }) => {
33
+ socket.emit(`serve:${token.key}`, newValue)
34
+ },
35
+ ),
36
+ )
37
+ subscriptions.add(
38
+ employSocket(socket, `unsub:${token.key}`, () => {
39
+ clearSubscriptions()
40
+ start()
41
+ }),
42
+ )
43
+ }),
27
44
  )
28
-
29
- const fillUnsubRequest = () => {
30
- socket.off(`unsub:${token.key}`, fillUnsubRequest)
31
- if (unsubscribeFromStateUpdates) {
32
- unsubscribeFromStateUpdates()
33
- unsubscribeFromStateUpdates = undefined
34
- }
35
- }
36
-
37
- socket.on(`unsub:${token.key}`, fillUnsubRequest)
38
45
  }
39
46
 
40
- socket.on(`sub:${token.key}`, fillSubRequest)
47
+ start()
41
48
 
42
- return () => {
43
- socket.off(`sub:${token.key}`, fillSubRequest)
44
- if (unsubscribeFromStateUpdates) {
45
- unsubscribeFromStateUpdates()
46
- unsubscribeFromStateUpdates = undefined
47
- }
48
- }
49
+ return clearSubscriptions
49
50
  }
50
51
  }
@@ -1,35 +1,81 @@
1
1
  import type { WritableToken } from "atom.io"
2
- import { IMPLICIT, setIntoStore } from "atom.io/internal"
2
+ import {
3
+ findInStore,
4
+ getFromStore,
5
+ IMPLICIT,
6
+ setIntoStore,
7
+ subscribeToState,
8
+ } from "atom.io/internal"
9
+ import {
10
+ operateOnStore,
11
+ OWN_OP,
12
+ } from "atom.io/internal/set-state/operate-on-store"
3
13
  import type { Json } from "atom.io/json"
14
+ import { mutexAtoms } from "atom.io/realtime/mutex-store"
4
15
 
5
16
  import type { ServerConfig } from "."
17
+ import { employSocket } from "./employ-socket"
6
18
 
7
19
  export type StateReceiver = ReturnType<typeof realtimeStateReceiver>
8
20
  export function realtimeStateReceiver({
9
21
  socket,
10
22
  store = IMPLICIT.STORE,
11
23
  }: ServerConfig) {
12
- return function stateReceiver<J extends Json.Serializable>(
13
- token: WritableToken<J>,
24
+ return function stateReceiver<S extends Json.Serializable, C extends S>(
25
+ clientToken: WritableToken<C>,
26
+ serverToken: WritableToken<S> = clientToken,
14
27
  ): () => void {
15
- const publish = (newValue: J) => {
16
- setIntoStore(store, token, newValue)
28
+ const mutexAtom = findInStore(store, mutexAtoms, serverToken.key)
29
+
30
+ const subscriptions = new Set<() => void>()
31
+ const clearSubscriptions = () => {
32
+ for (const unsub of subscriptions) unsub()
33
+ subscriptions.clear()
17
34
  }
18
35
 
19
- const fillPubUnclaim = () => {
20
- socket.off(`pub:${token.key}`, publish)
21
- socket.off(`unclaim:${token.key}`, fillPubUnclaim)
36
+ const permitPublish = () => {
37
+ clearSubscriptions()
38
+ subscriptions.add(
39
+ employSocket(socket, `pub:${clientToken.key}`, (newValue) => {
40
+ setIntoStore(store, serverToken, newValue as C)
41
+ }),
42
+ )
43
+ subscriptions.add(
44
+ employSocket(socket, `unclaim:${clientToken.key}`, () => {
45
+ setIntoStore(store, mutexAtom, false)
46
+ clearSubscriptions()
47
+ start()
48
+ }),
49
+ )
22
50
  }
23
- const fillPubClaim = () => {
24
- socket.on(`pub:${token.key}`, publish)
25
- socket.on(`unclaim:${token.key}`, fillPubUnclaim)
51
+
52
+ const start = () => {
53
+ subscriptions.add(
54
+ employSocket(socket, `claim:${clientToken.key}`, () => {
55
+ if (getFromStore(store, mutexAtom)) {
56
+ clearSubscriptions()
57
+ subscriptions.add(
58
+ subscribeToState(store, mutexAtom, socket.id!, () => {
59
+ const currentValue = getFromStore(store, mutexAtom)
60
+ if (currentValue === false) {
61
+ operateOnStore(OWN_OP, store, mutexAtom, true)
62
+ permitPublish()
63
+ socket.emit(`claim-result:${clientToken.key}`, true)
64
+ }
65
+ }),
66
+ )
67
+ socket.emit(`claim-result:${clientToken.key}`, false)
68
+ return
69
+ }
70
+ setIntoStore(store, mutexAtom, true)
71
+ permitPublish()
72
+ socket.emit(`claim-result:${clientToken.key}`, true)
73
+ }),
74
+ )
26
75
  }
27
76
 
28
- socket.on(`claim:${token.key}`, fillPubClaim)
77
+ start()
29
78
 
30
- return () => {
31
- socket.off(`claim:${token.key}`, fillPubClaim)
32
- socket.off(`pub:${token.key}`, publish)
33
- }
79
+ return clearSubscriptions
34
80
  }
35
81
  }
@@ -0,0 +1,8 @@
1
+ import type { RootStore } from "atom.io/internal"
2
+
3
+ import type { Socket } from "./socket-interface"
4
+
5
+ export type ServerConfig = {
6
+ socket: Socket
7
+ store?: RootStore
8
+ }
@@ -0,0 +1,14 @@
1
+ import type { Json } from "atom.io/json"
2
+
3
+ export type Socket = {
4
+ id: string | undefined
5
+ on: (event: string, listener: (...args: Json.Serializable[]) => void) => void
6
+ onAny: (
7
+ listener: (event: string, ...args: Json.Serializable[]) => void,
8
+ ) => void
9
+ off: (event: string, listener: (...args: Json.Serializable[]) => void) => void
10
+ offAny: (
11
+ listener: (event: string, ...args: Json.Serializable[]) => void,
12
+ ) => void
13
+ emit: (event: string, ...args: Json.Serializable[]) => void
14
+ }
@@ -1,3 +1,4 @@
1
+ import { ChildProcess } from "node:child_process"
1
2
  import * as http from "node:http"
2
3
 
3
4
  import type { RenderResult } from "@testing-library/react"
@@ -15,10 +16,10 @@ import {
15
16
  } from "atom.io/internal"
16
17
  import { toEntries } from "atom.io/json"
17
18
  import * as AR from "atom.io/react"
18
- import * as RT from "atom.io/realtime"
19
19
  import * as RTC from "atom.io/realtime-client"
20
20
  import * as RTR from "atom.io/realtime-react"
21
21
  import * as RTS from "atom.io/realtime-server"
22
+ import { SetRTX } from "atom.io/transceivers/set-rtx"
22
23
  import * as Happy from "happy-dom"
23
24
  import * as React from "react"
24
25
  import * as SocketIO from "socket.io"
@@ -30,27 +31,50 @@ let testNumber = 0
30
31
  /* eslint-disable no-console */
31
32
 
32
33
  function prefixLogger(store: Store, prefix: string) {
33
- store.loggers[0] = new AtomIO.AtomIOLogger(`info`, undefined, {
34
- info: (...args) => {
35
- console.info(prefix, ...args)
36
- },
37
- warn: (...args) => {
38
- console.warn(prefix, ...args)
34
+ store.loggers[0] = new AtomIO.AtomIOLogger(
35
+ `info`,
36
+ (...params) => {
37
+ let idx = 0
38
+ for (const param of params) {
39
+ if (param instanceof SocketIO.Socket) {
40
+ params[idx] = `Socket:${param.id}`
41
+ }
42
+ if (param instanceof RTS.ChildSocket) {
43
+ params[idx] = `ChildSocket:${param.id}`
44
+ }
45
+ if (param instanceof ChildProcess) {
46
+ params[idx] = `ChildProcess:${param.pid}`
47
+ }
48
+ if (param instanceof SetRTX) {
49
+ params[idx] =
50
+ `SetRTX(${param.size}) {${[...param].join(`, `)}} at ${param.cacheIdx}`
51
+ }
52
+ idx++
53
+ }
54
+ return params
39
55
  },
40
- error: (...args) => {
41
- console.error(prefix, ...args)
56
+ {
57
+ info: (...params) => {
58
+ console.info(prefix, ...params)
59
+ },
60
+ warn: (...params) => {
61
+ console.warn(prefix, ...params)
62
+ },
63
+ error: (...params) => {
64
+ console.error(prefix, ...params)
65
+ },
42
66
  },
43
- })
67
+ )
44
68
  }
45
69
 
46
70
  export type TestSetupOptions = {
47
- port: number
48
71
  immortal?: { server?: boolean }
49
72
  server: (tools: {
50
73
  socket: SocketIO.Socket
51
74
  silo: AtomIO.Silo
75
+ userKey: RTS.UserKey
52
76
  enableLogging: () => void
53
- }) => void
77
+ }) => (() => void) | void
54
78
  }
55
79
  export type TestSetupOptions__SingleClient = TestSetupOptions & {
56
80
  client: React.FC
@@ -105,10 +129,11 @@ export const setupRealtimeTestServer = (
105
129
  },
106
130
  IMPLICIT.STORE,
107
131
  )
132
+ // prefixLogger(silo.store, `server`)
108
133
  const socketRealm = new AtomIO.Realm<RTS.SocketSystemHierarchy>(silo.store)
109
134
 
110
135
  const httpServer = http.createServer((_, res) => res.end(`Hello World!`))
111
- const address = httpServer.listen(options.port).address()
136
+ const address = httpServer.listen().address()
112
137
  const port =
113
138
  typeof address === `string` ? null : address === null ? null : address.port
114
139
  if (port === null) throw new Error(`Could not determine port for test server`)
@@ -131,22 +156,25 @@ export const setupRealtimeTestServer = (
131
156
  setIntoStore(silo.store, RTS.socketIndex, (index) =>
132
157
  index.add(socketClaim),
133
158
  )
134
- // console.log(`${username} connected on ${socket.id}`)
135
159
  next()
136
160
  } else {
137
161
  next(new Error(`Authentication error`))
138
162
  }
139
163
  })
140
164
 
165
+ const socketServices = new Set<() => void>()
166
+ const disposeAllSocketServices = () => {
167
+ for (const disposeService of socketServices) disposeService()
168
+ }
169
+
141
170
  server.on(`connection`, (socket: SocketIO.Socket) => {
142
- let userKey: string | null = null
171
+ const userKeyState = findRelationsInStore(
172
+ RTS.usersOfSockets,
173
+ `socket::${socket.id}`,
174
+ silo.store,
175
+ ).userKeyOfSocket
176
+ const userKey = getFromStore(silo.store, userKeyState)!
143
177
  function enableLogging() {
144
- const userKeyState = findRelationsInStore(
145
- RTS.usersOfSockets,
146
- `socket::${socket.id}`,
147
- silo.store,
148
- ).userKeyOfSocket
149
- userKey = getFromStore(silo.store, userKeyState)
150
178
  prefixLogger(silo.store, `server`)
151
179
  socket.onAny((event, ...args) => {
152
180
  console.log(`🛰 `, userKey, event, ...args)
@@ -158,19 +186,30 @@ export const setupRealtimeTestServer = (
158
186
  console.log(`${userKey} disconnected`)
159
187
  })
160
188
  }
161
- options.server({ socket, enableLogging, silo })
189
+ const disposeServices = options.server({
190
+ socket,
191
+ enableLogging,
192
+ silo,
193
+ userKey,
194
+ })
195
+ if (disposeServices) {
196
+ socketServices.add(disposeServices)
197
+ socket.on(`disconnect`, disposeServices)
198
+ }
162
199
  })
163
200
 
164
201
  const dispose = async () => {
202
+ disposeAllSocketServices()
165
203
  await server.close()
166
- const roomKeys = getFromStore(silo.store, RT.roomIndex)
167
- for (const roomKey of roomKeys) {
168
- const roomState = findInStore(silo.store, RTS.roomSelectors, roomKey)
169
- const room = getFromStore(silo.store, roomState)
170
- if (room && !(room instanceof Promise)) {
171
- room.process.kill()
172
- }
173
- }
204
+
205
+ // const roomKeys = getFromStore(silo.store, RT.roomIndex)
206
+ // for (const roomKey of roomKeys) {
207
+ // const roomState = findInStore(silo.store, RTS.roomSelectors, roomKey)
208
+ // const room = getFromStore(silo.store, roomState)
209
+ // if (room && !(room instanceof Promise)) {
210
+ // room.process.kill()
211
+ // }
212
+ // } // ❗ POSSIBLY STILL NEEDED
174
213
  silo.store.valueMap.clear()
175
214
  }
176
215
 
@@ -212,7 +251,7 @@ export const setupRealtimeTestClient = (
212
251
  }
213
252
 
214
253
  const enableLogging = () => {
215
- prefixLogger(silo.store, name)
254
+ // prefixLogger(silo.store, name)
216
255
  socket.onAny((event, ...args) => {
217
256
  console.log(`📡 `, name, event, ...args)
218
257
  })
package/src/web/index.ts CHANGED
@@ -1 +1 @@
1
- export * from "./persist-sync"
1
+ export * from "./storage-sync"
@@ -5,13 +5,16 @@ export type StringInterface<T> = {
5
5
  parse: (s: string) => T
6
6
  }
7
7
 
8
- export const persistSync =
8
+ export const storageSync =
9
9
  <T>(
10
- storage: Storage,
10
+ storage: Storage | undefined,
11
11
  { stringify, parse }: StringInterface<T>,
12
12
  key: string,
13
13
  ): AtomEffect<T> =>
14
14
  ({ setSelf, onSet }) => {
15
+ if (!storage) {
16
+ return
17
+ }
15
18
  const savedValue = storage.getItem(key)
16
19
  if (savedValue != null) setSelf(parse(savedValue))
17
20
 
@@ -1,108 +0,0 @@
1
- import type {
2
- AtomFamilyToken,
3
- AtomToken,
4
- MutableAtomFamilyToken,
5
- MutableAtomToken,
6
- ReadableFamilyToken,
7
- ReadableToken,
8
- ReadonlyPureSelectorFamilyToken,
9
- ReadonlyPureSelectorToken,
10
- RegularAtomFamilyToken,
11
- RegularAtomToken,
12
- SelectorFamilyToken,
13
- SelectorToken,
14
- WritableFamilyToken,
15
- WritablePureSelectorFamilyToken,
16
- WritablePureSelectorToken,
17
- WritableToken,
18
- } from "atom.io"
19
- import type { Canonical } from "atom.io/json"
20
- import { stringifyJson } from "atom.io/json"
21
-
22
- import type { Transceiver } from "../mutable"
23
-
24
- export const COUNTERFEIT: unique symbol = Symbol(`counterfeit`)
25
-
26
- export const FAMILY_MEMBER_TOKEN_TYPES = {
27
- atom_family: `atom`,
28
- molecule_family: `molecule`,
29
- mutable_atom_family: `mutable_atom`,
30
- readonly_held_selector_family: `readonly_held_selector`,
31
- readonly_pure_selector_family: `readonly_pure_selector`,
32
- writable_held_selector_family: `writable_held_selector`,
33
- writable_pure_selector_family: `writable_pure_selector`,
34
- } as const
35
-
36
- export function mint<
37
- T extends Transceiver<any, any, any>,
38
- K extends Canonical,
39
- Key extends K,
40
- >(token: MutableAtomFamilyToken<T, K>, key: Key): MutableAtomToken<T>
41
-
42
- export function mint<T, K extends Canonical, Key extends K, E>(
43
- token: RegularAtomFamilyToken<T, K, E>,
44
- key: Key,
45
- counterfeit?: typeof COUNTERFEIT,
46
- ): RegularAtomToken<T, Key, E>
47
-
48
- export function mint<T, K extends Canonical, Key extends K, E>(
49
- token: AtomFamilyToken<T, K, E>,
50
- key: Key,
51
- counterfeit?: typeof COUNTERFEIT,
52
- ): AtomToken<T, Key, E>
53
-
54
- export function mint<T, K extends Canonical, Key extends K, E>(
55
- token: WritablePureSelectorFamilyToken<T, K, E>,
56
- key: Key,
57
- counterfeit?: typeof COUNTERFEIT,
58
- ): WritablePureSelectorToken<T, Key, E>
59
-
60
- export function mint<T, K extends Canonical, Key extends K, E>(
61
- token: ReadonlyPureSelectorFamilyToken<T, K, E>,
62
- key: Key,
63
- counterfeit?: typeof COUNTERFEIT,
64
- ): ReadonlyPureSelectorToken<T, Key, E>
65
-
66
- export function mint<T, K extends Canonical, Key extends K, E>(
67
- token: SelectorFamilyToken<T, K, E>,
68
- key: Key,
69
- counterfeit?: typeof COUNTERFEIT,
70
- ): SelectorToken<T, Key, E>
71
-
72
- export function mint<T, K extends Canonical, Key extends K, E>(
73
- token: WritableFamilyToken<T, K, E>,
74
- key: Key,
75
- counterfeit?: typeof COUNTERFEIT,
76
- ): WritableToken<T, Key, E>
77
-
78
- export function mint<T, K extends Canonical, Key extends K, E>(
79
- token: ReadableFamilyToken<T, K, E>,
80
- key: Key,
81
- counterfeit?: typeof COUNTERFEIT,
82
- ): ReadableToken<T, Key, E>
83
-
84
- export function mint(
85
- token: ReadableFamilyToken<any, any, any>,
86
- key: Canonical,
87
- counterfeit?: typeof COUNTERFEIT,
88
- ): ReadableToken<any, any, any> {
89
- const subKey = stringifyJson(key)
90
- const fullKey = `${token.key}(${subKey})`
91
- const type = FAMILY_MEMBER_TOKEN_TYPES[token.type]
92
- const stateToken: ReadableToken<any> & {
93
- counterfeit?: boolean
94
- } = {
95
- key: fullKey,
96
- type,
97
- family: {
98
- key: token.key,
99
- subKey,
100
- },
101
- }
102
-
103
- if (counterfeit) {
104
- stateToken.counterfeit = true
105
- }
106
-
107
- return stateToken
108
- }
@@ -1,23 +0,0 @@
1
- import type * as AtomIO from "atom.io"
2
- import type { Fn, Store } from "atom.io/internal"
3
- import { subscribeToTransaction } from "atom.io/internal"
4
- import type { Socket } from "socket.io-client"
5
-
6
- export function serverAction<F extends Fn>(
7
- store: Store,
8
- socket: Socket,
9
- token: AtomIO.TransactionToken<F>,
10
- ): () => void {
11
- const unsubscribeFromLocalUpdates = subscribeToTransaction(
12
- store,
13
- token,
14
- `tx-run:${token.key}:${socket.id}`,
15
- (clientUpdate) => {
16
- socket.emit(`tx-run:${token.key}`, clientUpdate)
17
- },
18
- )
19
-
20
- return () => {
21
- unsubscribeFromLocalUpdates()
22
- }
23
- }