atom.io 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/dist/index.cjs +62 -40
- package/data/dist/index.cjs.map +1 -1
- package/data/dist/index.d.ts +8 -2
- package/data/dist/index.js +64 -42
- package/data/dist/index.js.map +1 -1
- package/data/src/dict.ts +8 -4
- package/data/src/join.ts +74 -33
- package/data/src/struct-family.ts +18 -17
- package/dist/chunk-OEVFAUPE.js +289 -0
- package/dist/chunk-OEVFAUPE.js.map +1 -0
- package/dist/index.cjs +4 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +62 -51
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/internal/dist/index.cjs +163 -64
- package/internal/dist/index.cjs.map +1 -1
- package/internal/dist/index.d.ts +94 -70
- package/internal/dist/index.js +155 -59
- package/internal/dist/index.js.map +1 -1
- package/internal/src/arbitrary.ts +3 -0
- package/internal/src/caching.ts +8 -6
- package/internal/src/families/find-in-store.ts +16 -0
- package/internal/src/get-environment-data.ts +4 -7
- package/internal/src/index.ts +6 -5
- package/internal/src/ingest-updates/ingest-transaction-update.ts +0 -1
- package/internal/src/selector/create-standalone-selector.ts +0 -2
- package/internal/src/set-state/set-atom.ts +14 -18
- package/internal/src/store/store.ts +14 -2
- package/internal/src/store/withdraw.ts +72 -2
- package/internal/src/subscribe/subscribe-to-timeline.ts +2 -2
- package/internal/src/subscribe/subscribe-to-transaction.ts +2 -2
- package/internal/src/timeline/create-timeline.ts +12 -1
- package/internal/src/transaction/act-upon-store.ts +19 -0
- package/internal/src/transaction/apply-transaction.ts +7 -1
- package/internal/src/transaction/assign-transaction-to-continuity.ts +18 -0
- package/internal/src/transaction/build-transaction.ts +7 -6
- package/internal/src/transaction/create-transaction.ts +1 -1
- package/internal/src/transaction/get-epoch-number.ts +40 -0
- package/internal/src/transaction/index.ts +10 -1
- package/internal/src/transaction/set-epoch-number.ts +31 -0
- package/introspection/dist/index.cjs.map +1 -1
- package/introspection/dist/index.d.ts +3 -3
- package/introspection/dist/index.js.map +1 -1
- package/introspection/src/attach-introspection-states.ts +6 -2
- package/introspection/src/attach-timeline-family.ts +5 -2
- package/introspection/src/attach-transaction-logs.ts +2 -2
- package/json/dist/index.d.ts +3 -1
- package/json/src/index.ts +6 -2
- package/package.json +24 -13
- package/react/dist/index.cjs.map +1 -1
- package/react/dist/index.d.ts +1 -1
- package/react/dist/index.js.map +1 -1
- package/react/src/use-json.ts +1 -1
- package/react-devtools/dist/index.cjs +131 -134
- package/react-devtools/dist/index.cjs.map +1 -1
- package/react-devtools/dist/index.css +2 -2
- package/react-devtools/dist/index.css.map +1 -1
- package/react-devtools/dist/index.d.ts +3 -3
- package/react-devtools/dist/index.js +103 -106
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/src/StateEditor.tsx +6 -6
- package/react-devtools/src/StateIndex.tsx +2 -5
- package/react-devtools/src/TimelineIndex.tsx +3 -3
- package/react-devtools/src/TransactionIndex.tsx +9 -8
- package/react-devtools/src/Updates.tsx +1 -1
- package/react-devtools/src/index.ts +4 -4
- package/realtime/dist/index.cjs +72 -0
- package/realtime/dist/index.cjs.map +1 -0
- package/realtime/dist/index.d.ts +39 -0
- package/realtime/dist/index.js +68 -0
- package/realtime/dist/index.js.map +1 -0
- package/realtime/package.json +16 -0
- package/realtime/src/index.ts +1 -0
- package/realtime/src/realtime-continuity.ts +152 -0
- package/realtime-client/dist/index.cjs +389 -48
- package/realtime-client/dist/index.cjs.map +1 -1
- package/realtime-client/dist/index.d.ts +16 -9
- package/realtime-client/dist/index.js +100 -37
- package/realtime-client/dist/index.js.map +1 -1
- package/realtime-client/src/index.ts +8 -5
- package/realtime-client/src/{pull-family-member.ts → pull-atom-family-member.ts} +2 -2
- package/realtime-client/src/{pull-state.ts → pull-atom.ts} +2 -2
- package/realtime-client/src/{pull-mutable-family-member.ts → pull-mutable-atom-family-member.ts} +1 -1
- package/realtime-client/src/{pull-mutable.ts → pull-mutable-atom.ts} +1 -1
- package/realtime-client/src/pull-selector-family-member.ts +42 -0
- package/realtime-client/src/pull-selector.ts +38 -0
- package/realtime-client/src/realtime-client-stores/client-main-store.ts +2 -2
- package/realtime-client/src/realtime-client-stores/client-sync-store.ts +7 -7
- package/realtime-client/src/sync-continuity.ts +321 -0
- package/realtime-client/src/sync-server-action.ts +18 -20
- package/realtime-react/dist/index.cjs +330 -15
- package/realtime-react/dist/index.cjs.map +1 -1
- package/realtime-react/dist/index.d.ts +26 -6
- package/realtime-react/dist/index.js +43 -12
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/src/index.ts +6 -3
- package/realtime-react/src/use-pull-atom-family-member.ts +21 -0
- package/realtime-react/src/{use-pull-family-member.ts → use-pull-atom.ts} +6 -5
- package/realtime-react/src/{use-pull-mutable.ts → use-pull-mutable-atom.ts} +4 -3
- package/realtime-react/src/use-pull-mutable-family-member.ts +9 -4
- package/realtime-react/src/use-pull-selector-family-member.ts +21 -0
- package/realtime-react/src/{use-pull.ts → use-pull-selector.ts} +7 -5
- package/realtime-react/src/use-push.ts +3 -2
- package/realtime-react/src/use-server-action.ts +3 -2
- package/realtime-react/src/use-sync-continuity.ts +12 -0
- package/realtime-react/src/use-sync-server-action.ts +3 -2
- package/realtime-server/dist/index.cjs +568 -242
- package/realtime-server/dist/index.cjs.map +1 -1
- package/realtime-server/dist/index.d.ts +124 -49
- package/realtime-server/dist/index.js +555 -238
- package/realtime-server/dist/index.js.map +1 -1
- package/realtime-server/src/index.ts +18 -2
- package/realtime-server/src/ipc-socket.ts +230 -0
- package/realtime-server/src/realtime-action-receiver.ts +8 -5
- package/realtime-server/src/realtime-action-synchronizer.ts +40 -28
- package/realtime-server/src/realtime-continuity-synchronizer.ts +247 -0
- package/realtime-server/src/realtime-family-provider.ts +30 -71
- package/realtime-server/src/realtime-mutable-family-provider.ts +24 -86
- package/realtime-server/src/realtime-server-stores/index.ts +3 -1
- package/realtime-server/src/realtime-server-stores/realtime-continuity-store.ts +90 -0
- package/realtime-server/src/realtime-server-stores/server-room-store.ts +97 -0
- package/realtime-server/src/realtime-server-stores/server-sync-store.ts +2 -72
- package/realtime-server/src/realtime-server-stores/server-user-store.ts +14 -29
- package/realtime-server/src/realtime-state-receiver.ts +0 -1
- package/realtime-testing/dist/index.cjs +28 -28
- package/realtime-testing/dist/index.cjs.map +1 -1
- package/realtime-testing/dist/index.js +28 -27
- package/realtime-testing/dist/index.js.map +1 -1
- package/realtime-testing/src/setup-realtime-test.tsx +38 -28
- package/src/atom.ts +49 -31
- package/src/logger.ts +10 -5
- package/src/selector.ts +44 -25
- package/src/subscribe.ts +2 -1
- package/src/timeline.ts +4 -4
- package/src/transaction.ts +13 -17
- package/src/validators.ts +15 -9
- package/dist/chunk-H4Q5FTPZ.js +0 -11
- package/dist/chunk-H4Q5FTPZ.js.map +0 -1
- package/internal/src/set-state/copy-mutable-in-transaction.ts +0 -19
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { selectorFamily } from "atom.io"
|
|
2
|
+
import type { TransactionUpdate } from "atom.io"
|
|
3
|
+
import type { JsonIO } from "atom.io/json"
|
|
4
|
+
import { SyncGroup } from "atom.io/realtime"
|
|
5
|
+
import { completeUpdateAtoms } from "atom.io/realtime-server"
|
|
6
|
+
|
|
7
|
+
const redactorAtoms = selectorFamily<
|
|
8
|
+
(update: TransactionUpdate<any>) => TransactionUpdate<any>,
|
|
9
|
+
{ userId: string; syncGroupKey: string }
|
|
10
|
+
>({
|
|
11
|
+
key: `perspectiveRedactor`,
|
|
12
|
+
get:
|
|
13
|
+
({ userId, syncGroupKey }) =>
|
|
14
|
+
({ get, find }) => {
|
|
15
|
+
const syncGroup = SyncGroup.existing.get(syncGroupKey)
|
|
16
|
+
if (!syncGroup) {
|
|
17
|
+
throw new Error(
|
|
18
|
+
`Tried to create a synchronizer for a sync group that does not exist.`,
|
|
19
|
+
)
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const userPerspectiveTokens = syncGroup.perspectives.flatMap(
|
|
23
|
+
({ perspectiveAtoms, resourceAtoms }) => {
|
|
24
|
+
const userPerspectiveToken = find(perspectiveAtoms, userId)
|
|
25
|
+
const userPerspective = get(userPerspectiveToken)
|
|
26
|
+
const visibleTokens = [...userPerspective].map((subKey) => {
|
|
27
|
+
const resourceToken = find(resourceAtoms, subKey)
|
|
28
|
+
return resourceToken.key
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
return visibleTokens
|
|
32
|
+
},
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const filterTransactionUpdate = (
|
|
36
|
+
visible: string[],
|
|
37
|
+
transactionUpdate: TransactionUpdate<any>,
|
|
38
|
+
): TransactionUpdate<any> => {
|
|
39
|
+
const updates = transactionUpdate.updates
|
|
40
|
+
.filter((update) => {
|
|
41
|
+
if (`newValue` in update) {
|
|
42
|
+
return visible.includes(update.key)
|
|
43
|
+
}
|
|
44
|
+
return true
|
|
45
|
+
})
|
|
46
|
+
.map((update) => {
|
|
47
|
+
if (`updates` in update) {
|
|
48
|
+
return filterTransactionUpdate(visible, update)
|
|
49
|
+
}
|
|
50
|
+
return update
|
|
51
|
+
})
|
|
52
|
+
const filtered: TransactionUpdate<any> = {
|
|
53
|
+
...transactionUpdate,
|
|
54
|
+
updates,
|
|
55
|
+
}
|
|
56
|
+
return filtered
|
|
57
|
+
}
|
|
58
|
+
const filter: (updates: TransactionUpdate<any>) => TransactionUpdate<any> =
|
|
59
|
+
(update) => {
|
|
60
|
+
const visibleKeys: string[] = syncGroup.globals.map(
|
|
61
|
+
(atomToken) => atomToken.key,
|
|
62
|
+
)
|
|
63
|
+
visibleKeys.push(...userPerspectiveTokens)
|
|
64
|
+
return filterTransactionUpdate(visibleKeys, update)
|
|
65
|
+
}
|
|
66
|
+
return filter
|
|
67
|
+
},
|
|
68
|
+
})
|
|
69
|
+
export const redactedPerspectiveUpdateSelectors = selectorFamily<
|
|
70
|
+
Pick<
|
|
71
|
+
TransactionUpdate<JsonIO>,
|
|
72
|
+
`epoch` | `id` | `key` | `output` | `updates`
|
|
73
|
+
> | null,
|
|
74
|
+
{ userId: string; syncGroupKey: string; updateId: string }
|
|
75
|
+
>({
|
|
76
|
+
key: `redactedPerspectiveUpdate`,
|
|
77
|
+
get:
|
|
78
|
+
({ userId, syncGroupKey, updateId }) =>
|
|
79
|
+
({ get, find }) => {
|
|
80
|
+
const updateState = find(completeUpdateAtoms, updateId)
|
|
81
|
+
const update = get(updateState)
|
|
82
|
+
const redactorKey = { userId, syncGroupKey }
|
|
83
|
+
const redactorState = find(redactorAtoms, redactorKey)
|
|
84
|
+
const redact = get(redactorState)
|
|
85
|
+
if (update) {
|
|
86
|
+
return redact(update)
|
|
87
|
+
}
|
|
88
|
+
return null
|
|
89
|
+
},
|
|
90
|
+
})
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { ChildProcessWithoutNullStreams } from "child_process"
|
|
2
|
+
import { spawn } from "child_process"
|
|
3
|
+
|
|
4
|
+
import * as AtomIO from "atom.io"
|
|
5
|
+
import type { Loadable } from "atom.io/data"
|
|
6
|
+
import { join } from "atom.io/data"
|
|
7
|
+
import { SetRTX } from "atom.io/transceivers/set-rtx"
|
|
8
|
+
|
|
9
|
+
export type RoomArguments =
|
|
10
|
+
| [script: string, options: string[]]
|
|
11
|
+
| [script: string]
|
|
12
|
+
|
|
13
|
+
export const roomIndex = AtomIO.atom({
|
|
14
|
+
key: `roomIndex`,
|
|
15
|
+
default: () => new SetRTX<string>(),
|
|
16
|
+
mutable: true,
|
|
17
|
+
toJson: (set) => set.toJSON(),
|
|
18
|
+
fromJson: (json) => SetRTX.fromJSON(json),
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
export type UserInRoomMeta = {
|
|
22
|
+
enteredAtEpoch: number
|
|
23
|
+
}
|
|
24
|
+
export const DEFAULT_USER_IN_ROOM_META: UserInRoomMeta = {
|
|
25
|
+
enteredAtEpoch: 0,
|
|
26
|
+
}
|
|
27
|
+
export const usersInRooms = join(
|
|
28
|
+
{
|
|
29
|
+
key: `usersInRooms`,
|
|
30
|
+
between: [`room`, `user`],
|
|
31
|
+
cardinality: `1:n`,
|
|
32
|
+
},
|
|
33
|
+
DEFAULT_USER_IN_ROOM_META,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
export const roomArgumentsAtoms = AtomIO.atomFamily<RoomArguments, string>({
|
|
37
|
+
key: `roomArguments`,
|
|
38
|
+
default: [`echo Hello World!`],
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
export const roomSelectors = AtomIO.selectorFamily<
|
|
42
|
+
Loadable<ChildProcessWithoutNullStreams>,
|
|
43
|
+
string
|
|
44
|
+
>({
|
|
45
|
+
key: `room`,
|
|
46
|
+
get:
|
|
47
|
+
(roomId) =>
|
|
48
|
+
({ get, find }) => {
|
|
49
|
+
const argumentsState = find(roomArgumentsAtoms, roomId)
|
|
50
|
+
const args = get(argumentsState)
|
|
51
|
+
const [script, options] = args
|
|
52
|
+
return new Promise((resolve) => {
|
|
53
|
+
const room = spawn(script, options, { env: process.env })
|
|
54
|
+
const resolver = (data: Buffer) => {
|
|
55
|
+
if (data.toString() === `✨`) {
|
|
56
|
+
room.stdout.off(`data`, resolver)
|
|
57
|
+
resolve(room)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
room.stdout.on(`data`, resolver)
|
|
61
|
+
})
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
export const createRoomTX = AtomIO.transaction<
|
|
66
|
+
(
|
|
67
|
+
roomId: string,
|
|
68
|
+
script: string,
|
|
69
|
+
options?: string[],
|
|
70
|
+
) => Loadable<ChildProcessWithoutNullStreams>
|
|
71
|
+
>({
|
|
72
|
+
key: `createRoom`,
|
|
73
|
+
do: ({ get, set, find }, roomId, script, options) => {
|
|
74
|
+
const args: RoomArguments = options ? [script, options] : [script]
|
|
75
|
+
const roomArgumentsState = find(roomArgumentsAtoms, roomId)
|
|
76
|
+
set(roomArgumentsState, args)
|
|
77
|
+
set(roomIndex, (s) => s.add(roomId))
|
|
78
|
+
const roomState = find(roomSelectors, roomId)
|
|
79
|
+
const room = get(roomState)
|
|
80
|
+
return room
|
|
81
|
+
},
|
|
82
|
+
})
|
|
83
|
+
export type CreateRoomIO = AtomIO.TransactionIO<typeof createRoomTX>
|
|
84
|
+
|
|
85
|
+
export const joinRoomTX = AtomIO.transaction<
|
|
86
|
+
(roomId: string, userId: string, enteredAtEpoch: number) => UserInRoomMeta
|
|
87
|
+
>({
|
|
88
|
+
key: `joinRoom`,
|
|
89
|
+
do: (transactors, roomId, userId, enteredAtEpoch) => {
|
|
90
|
+
const meta = { enteredAtEpoch }
|
|
91
|
+
usersInRooms.transact(transactors, ({ relations }) => {
|
|
92
|
+
relations.set(roomId, userId, meta)
|
|
93
|
+
})
|
|
94
|
+
return meta
|
|
95
|
+
},
|
|
96
|
+
})
|
|
97
|
+
export type JoinRoomIO = AtomIO.TransactionIO<typeof joinRoomTX>
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import type { TransactionUpdate, TransactionUpdateContent } from "atom.io"
|
|
2
2
|
import { atomFamily, selectorFamily } from "atom.io"
|
|
3
|
-
import { SyncGroup } from "~/packages/atom.io/__unstable__/realtime-server-next/create-realtime-sync-group"
|
|
4
|
-
import { usersOfSockets } from "./server-user-store"
|
|
5
3
|
|
|
6
4
|
export const completeUpdateAtoms = atomFamily<
|
|
7
5
|
TransactionUpdate<any> | null,
|
|
@@ -38,78 +36,10 @@ export const redactedUpdateSelectors = selectorFamily<
|
|
|
38
36
|
},
|
|
39
37
|
})
|
|
40
38
|
|
|
41
|
-
export const
|
|
42
|
-
TransactionUpdate<any
|
|
39
|
+
export const userUnacknowledgedQueues = atomFamily<
|
|
40
|
+
Pick<TransactionUpdate<any>, `epoch` | `id` | `key` | `output` | `updates`>[],
|
|
43
41
|
string
|
|
44
42
|
>({
|
|
45
43
|
key: `unacknowledgedUpdates`,
|
|
46
44
|
default: () => [],
|
|
47
45
|
})
|
|
48
|
-
|
|
49
|
-
export const socketUnacknowledgedUpdatesSelectors = selectorFamily<
|
|
50
|
-
TransactionUpdate<any>[],
|
|
51
|
-
string
|
|
52
|
-
>({
|
|
53
|
-
key: `socketUnacknowledgedUpdates`,
|
|
54
|
-
get:
|
|
55
|
-
(socketId) =>
|
|
56
|
-
({ get, find }) => {
|
|
57
|
-
const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
|
|
58
|
-
const userKey = get(userKeyState)
|
|
59
|
-
if (!userKey) {
|
|
60
|
-
return []
|
|
61
|
-
}
|
|
62
|
-
const unacknowledgedUpdatesState = find(
|
|
63
|
-
userUnacknowledgedUpdatesAtoms,
|
|
64
|
-
userKey,
|
|
65
|
-
)
|
|
66
|
-
const unacknowledgedUpdates = get(unacknowledgedUpdatesState)
|
|
67
|
-
return unacknowledgedUpdates
|
|
68
|
-
},
|
|
69
|
-
set:
|
|
70
|
-
(socketId) =>
|
|
71
|
-
({ set, get, find }, newUpdates) => {
|
|
72
|
-
const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
|
|
73
|
-
const userKey = get(userKeyState)
|
|
74
|
-
if (!userKey) {
|
|
75
|
-
return
|
|
76
|
-
}
|
|
77
|
-
const unacknowledgedUpdatesState = find(
|
|
78
|
-
userUnacknowledgedUpdatesAtoms,
|
|
79
|
-
userKey,
|
|
80
|
-
)
|
|
81
|
-
set(unacknowledgedUpdatesState, newUpdates)
|
|
82
|
-
},
|
|
83
|
-
})
|
|
84
|
-
|
|
85
|
-
export const userEpochAtoms = atomFamily<number | null, string>({
|
|
86
|
-
key: `clientEpoch`,
|
|
87
|
-
default: null,
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
export const socketEpochSelectors = selectorFamily<number | null, string>({
|
|
91
|
-
key: `socketEpoch`,
|
|
92
|
-
get:
|
|
93
|
-
(socketId) =>
|
|
94
|
-
({ get, find }) => {
|
|
95
|
-
const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
|
|
96
|
-
const userKey = get(userKeyState)
|
|
97
|
-
if (!userKey) {
|
|
98
|
-
return null
|
|
99
|
-
}
|
|
100
|
-
const userEpochState = find(userEpochAtoms, userKey)
|
|
101
|
-
const userEpoch = get(userEpochState)
|
|
102
|
-
return userEpoch
|
|
103
|
-
},
|
|
104
|
-
set:
|
|
105
|
-
(socketId) =>
|
|
106
|
-
({ set, get, find }, newEpoch) => {
|
|
107
|
-
const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
|
|
108
|
-
const userKey = get(userKeyState)
|
|
109
|
-
if (!userKey) {
|
|
110
|
-
return
|
|
111
|
-
}
|
|
112
|
-
const userEpochState = find(userEpochAtoms, userKey)
|
|
113
|
-
set(userEpochState, newEpoch)
|
|
114
|
-
},
|
|
115
|
-
})
|
|
@@ -2,6 +2,20 @@ import { atom, atomFamily } from "atom.io"
|
|
|
2
2
|
import { join } from "atom.io/data"
|
|
3
3
|
import { SetRTX } from "atom.io/transceivers/set-rtx"
|
|
4
4
|
|
|
5
|
+
import type { Socket } from ".."
|
|
6
|
+
|
|
7
|
+
export const socketAtoms = atomFamily<Socket | null, string>({
|
|
8
|
+
key: `sockets`,
|
|
9
|
+
default: null,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export const socketIndex = atom({
|
|
13
|
+
key: `socketsIndex`,
|
|
14
|
+
mutable: true,
|
|
15
|
+
default: () => new SetRTX<string>(),
|
|
16
|
+
toJson: (set) => set.toJSON(),
|
|
17
|
+
fromJson: (json) => SetRTX.fromJSON(json),
|
|
18
|
+
})
|
|
5
19
|
export const userIndex = atom({
|
|
6
20
|
key: `usersIndex`,
|
|
7
21
|
mutable: true,
|
|
@@ -14,32 +28,3 @@ export const usersOfSockets = join({
|
|
|
14
28
|
between: [`user`, `socket`],
|
|
15
29
|
cardinality: `1:1`,
|
|
16
30
|
})
|
|
17
|
-
|
|
18
|
-
export const roomIndex = atom({
|
|
19
|
-
key: `conclaveIndex`,
|
|
20
|
-
default: () => new SetRTX<string>(),
|
|
21
|
-
mutable: true,
|
|
22
|
-
toJson: (set) => set.toJSON(),
|
|
23
|
-
fromJson: (json) => SetRTX.fromJSON(json),
|
|
24
|
-
})
|
|
25
|
-
export type UserInRoomMeta = {
|
|
26
|
-
enteredAtEpoch: number
|
|
27
|
-
}
|
|
28
|
-
export const DEFAULT_USER_IN_ROOM_META: UserInRoomMeta = {
|
|
29
|
-
enteredAtEpoch: 0,
|
|
30
|
-
}
|
|
31
|
-
export const usersInRooms = join(
|
|
32
|
-
{
|
|
33
|
-
key: `usersInRooms`,
|
|
34
|
-
between: [`room`, `user`],
|
|
35
|
-
cardinality: `1:n`,
|
|
36
|
-
},
|
|
37
|
-
DEFAULT_USER_IN_ROOM_META,
|
|
38
|
-
)
|
|
39
|
-
|
|
40
|
-
// export const roomStoreAtoms = atomFamily<
|
|
41
|
-
// { [key: string]: any },
|
|
42
|
-
// { conclave: string }
|
|
43
|
-
// >({
|
|
44
|
-
|
|
45
|
-
// })
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
var http = require('http');
|
|
4
4
|
var react = require('@testing-library/react');
|
|
5
5
|
var AtomIO = require('atom.io');
|
|
6
|
-
var
|
|
6
|
+
var internal = require('atom.io/internal');
|
|
7
7
|
var AR = require('atom.io/react');
|
|
8
8
|
var RTR = require('atom.io/realtime-react');
|
|
9
9
|
var RTS = require('atom.io/realtime-server');
|
|
@@ -32,7 +32,6 @@ function _interopNamespace(e) {
|
|
|
32
32
|
|
|
33
33
|
var http__namespace = /*#__PURE__*/_interopNamespace(http);
|
|
34
34
|
var AtomIO__namespace = /*#__PURE__*/_interopNamespace(AtomIO);
|
|
35
|
-
var Internal__namespace = /*#__PURE__*/_interopNamespace(Internal);
|
|
36
35
|
var AR__namespace = /*#__PURE__*/_interopNamespace(AR);
|
|
37
36
|
var RTR__namespace = /*#__PURE__*/_interopNamespace(RTR);
|
|
38
37
|
var RTS__namespace = /*#__PURE__*/_interopNamespace(RTS);
|
|
@@ -61,8 +60,10 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
|
61
60
|
|
|
62
61
|
// ../anvl/src/object/entries.ts
|
|
63
62
|
var recordToEntries = (obj) => Object.entries(obj);
|
|
63
|
+
var testNumber = 0;
|
|
64
64
|
var setupRealtimeTestServer = (options) => {
|
|
65
|
-
|
|
65
|
+
++testNumber;
|
|
66
|
+
const silo = new AtomIO__namespace.Silo(`SERVER-${testNumber}`, internal.IMPLICIT.STORE);
|
|
66
67
|
const httpServer = http__namespace.createServer((_, res) => res.end(`Hello World!`));
|
|
67
68
|
const address = httpServer.listen().address();
|
|
68
69
|
const port = typeof address === `string` ? 80 : address === null ? null : address.port;
|
|
@@ -71,26 +72,12 @@ var setupRealtimeTestServer = (options) => {
|
|
|
71
72
|
const server = new SocketIO__namespace.Server(httpServer).use((socket, next) => {
|
|
72
73
|
const { token, username } = socket.handshake.auth;
|
|
73
74
|
if (token === `test` && socket.id) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
);
|
|
79
|
-
|
|
80
|
-
RTS__namespace.usersOfSockets.core.findRelatedKeysState,
|
|
81
|
-
username,
|
|
82
|
-
silo.store
|
|
83
|
-
);
|
|
84
|
-
Internal__namespace.setIntoStore(
|
|
85
|
-
socketRelatedKeysState,
|
|
86
|
-
(keys) => (keys.clear(), keys.add(username)),
|
|
87
|
-
silo.store
|
|
88
|
-
);
|
|
89
|
-
Internal__namespace.setIntoStore(
|
|
90
|
-
clientRelatedKeysState,
|
|
91
|
-
(keys) => (keys.clear(), keys.add(socket.id)),
|
|
92
|
-
silo.store
|
|
93
|
-
);
|
|
75
|
+
const socketState = internal.findInStore(RTS__namespace.socketAtoms, socket.id, silo.store);
|
|
76
|
+
internal.setIntoStore(socketState, socket, silo.store);
|
|
77
|
+
const usersOfSockets2 = RTS__namespace.usersOfSockets.in(silo.store);
|
|
78
|
+
usersOfSockets2.relations.set(socket.id, username);
|
|
79
|
+
internal.setIntoStore(RTS__namespace.userIndex, (index) => index.add(username), silo.store);
|
|
80
|
+
internal.setIntoStore(RTS__namespace.socketIndex, (index) => index.add(socket.id), silo.store);
|
|
94
81
|
console.log(`${username} connected on ${socket.id}`);
|
|
95
82
|
next();
|
|
96
83
|
} else {
|
|
@@ -102,7 +89,15 @@ var setupRealtimeTestServer = (options) => {
|
|
|
102
89
|
});
|
|
103
90
|
const dispose = () => {
|
|
104
91
|
server.close();
|
|
105
|
-
|
|
92
|
+
const roomKeys = internal.getFromStore(RTS__namespace.roomIndex, silo.store);
|
|
93
|
+
for (const roomKey of roomKeys) {
|
|
94
|
+
const roomState = internal.findInStore(RTS__namespace.roomSelectors, roomKey, silo.store);
|
|
95
|
+
const room = internal.getFromStore(roomState, silo.store);
|
|
96
|
+
if (room && !(room instanceof Promise)) {
|
|
97
|
+
room.kill();
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
silo.store.valueMap.clear();
|
|
106
101
|
};
|
|
107
102
|
return {
|
|
108
103
|
name: `SERVER`,
|
|
@@ -116,9 +111,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
116
111
|
} };
|
|
117
112
|
const init = () => {
|
|
118
113
|
const socket = socket_ioClient.io(`http://localhost:${port}/`, {
|
|
119
|
-
auth: { token: `test`, username: name }
|
|
114
|
+
auth: { token: `test`, username: `${name}-${testNumber}` }
|
|
120
115
|
});
|
|
121
|
-
const silo = new AtomIO__namespace.Silo(name,
|
|
116
|
+
const silo = new AtomIO__namespace.Silo(name, internal.IMPLICIT.STORE);
|
|
122
117
|
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
123
118
|
if (Array.isArray(value)) {
|
|
124
119
|
silo.store.valueMap.set(key, [...value]);
|
|
@@ -134,8 +129,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
134
129
|
);
|
|
135
130
|
const prettyPrint = () => console.log(react.prettyDOM(renderResult.container));
|
|
136
131
|
const dispose = () => {
|
|
132
|
+
renderResult.unmount();
|
|
137
133
|
socket.disconnect();
|
|
138
|
-
|
|
134
|
+
internal.clearStore(silo.store);
|
|
139
135
|
};
|
|
140
136
|
testClient.dispose = dispose;
|
|
141
137
|
return {
|
|
@@ -150,7 +146,11 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
150
146
|
};
|
|
151
147
|
var singleClient = (options) => {
|
|
152
148
|
const server = setupRealtimeTestServer(options);
|
|
153
|
-
const client = setupRealtimeTestClient(
|
|
149
|
+
const client = setupRealtimeTestClient(
|
|
150
|
+
options,
|
|
151
|
+
`CLIENT-${testNumber}`,
|
|
152
|
+
server.port
|
|
153
|
+
);
|
|
154
154
|
return {
|
|
155
155
|
client,
|
|
156
156
|
server,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx","../../../anvl/src/object/entries.ts"],"names":["clients"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,YAAY,UAAU;AAEtB,
|
|
1
|
+
{"version":3,"sources":["../src/setup-realtime-test.tsx","../../../anvl/src/object/entries.ts"],"names":["usersOfSockets","clients"],"mappings":"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","sourcesContent":["import * as http from \"http\"\n\nimport { prettyDOM, render } from \"@testing-library/react\"\nimport type { RenderResult } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport {\n\tIMPLICIT,\n\tclearStore,\n\tfindInStore,\n\tgetFromStore,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport * as AR from \"atom.io/react\"\nimport * as RTR from \"atom.io/realtime-react\"\nimport * as RTS from \"atom.io/realtime-server\"\nimport * as Happy from \"happy-dom\"\nimport * as React from \"react\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nimport { recordToEntries } from \"~/packages/anvl/src/object\"\n\nlet testNumber = 0\n\nexport type TestSetupOptions = {\n\tserver: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\tsocket: ClientSocket\n}\nexport type RealtimeTestClientBuilder = {\n\tdispose: () => void\n\tinit: () => RealtimeTestClient\n}\n\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tdispose: () => void\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => void\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClientBuilder\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClientBuilder>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\t++testNumber\n\tconst silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE)\n\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen().address()\n\tconst port =\n\t\ttypeof address === `string` ? 80 : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\n\tconst server = new SocketIO.Server(httpServer).use((socket, next) => {\n\t\tconst { token, username } = socket.handshake.auth\n\t\tif (token === `test` && socket.id) {\n\t\t\tconst socketState = findInStore(RTS.socketAtoms, socket.id, silo.store)\n\t\t\tsetIntoStore(socketState, socket, silo.store)\n\t\t\tconst usersOfSockets = RTS.usersOfSockets.in(silo.store)\n\t\t\tusersOfSockets.relations.set(socket.id, username)\n\t\t\tsetIntoStore(RTS.userIndex, (index) => index.add(username), silo.store)\n\t\t\tsetIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store)\n\t\t\tconsole.log(`${username} connected on ${socket.id}`)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\toptions.server({ socket, silo })\n\t})\n\n\tconst dispose = () => {\n\t\tserver.close()\n\t\tconst roomKeys = getFromStore(RTS.roomIndex, silo.store)\n\t\tfor (const roomKey of roomKeys) {\n\t\t\tconst roomState = findInStore(RTS.roomSelectors, roomKey, silo.store)\n\t\t\tconst room = getFromStore(roomState, silo.store)\n\t\t\tif (room && !(room instanceof Promise)) {\n\t\t\t\troom.kill()\n\t\t\t}\n\t\t}\n\t\tsilo.store.valueMap.clear()\n\t}\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClientBuilder => {\n\tconst testClient = { dispose: () => {} }\n\tconst init = () => {\n\t\tconst socket: ClientSocket = io(`http://localhost:${port}/`, {\n\t\t\tauth: { token: `test`, username: `${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(name, IMPLICIT.STORE)\n\t\tfor (const [key, value] of silo.store.valueMap.entries()) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tsilo.store.valueMap.set(key, [...value])\n\t\t\t}\n\t\t}\n\n\t\tconst { document } = new Happy.Window()\n\t\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\t\tconst renderResult = render(\n\t\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t\t<RTR.RealtimeProvider socket={socket}>\n\t\t\t\t\t<options.client />\n\t\t\t\t</RTR.RealtimeProvider>\n\t\t\t</AR.StoreProvider>,\n\t\t\t{\n\t\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t\t},\n\t\t)\n\n\t\tconst prettyPrint = () => console.log(prettyDOM(renderResult.container))\n\n\t\tconst dispose = () => {\n\t\t\trenderResult.unmount()\n\t\t\tsocket.disconnect()\n\t\t\tclearStore(silo.store)\n\t\t}\n\t\ttestClient.dispose = dispose\n\n\t\treturn {\n\t\t\tname,\n\t\t\tsilo,\n\t\t\tsocket,\n\t\t\trenderResult,\n\t\t\tprettyPrint,\n\t\t}\n\t}\n\treturn Object.assign(testClient, { init })\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(\n\t\toptions,\n\t\t`CLIENT-${testNumber}`,\n\t\tserver.port,\n\t)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tclient.dispose()\n\t\t\tserver.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = recordToEntries(options.clients).reduce(\n\t\t(clients, [name, client]) => {\n\t\t\tclients[name] = setupRealtimeTestClient(\n\t\t\t\t{ ...options, client },\n\t\t\t\tname,\n\t\t\t\tserver.port,\n\t\t\t)\n\t\t\treturn clients\n\t\t},\n\t\t{} as Record<ClientNames, RealtimeTestClientBuilder>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tfor (const [, client] of recordToEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t\tserver.dispose()\n\t\t},\n\t}\n}\n","export type Entries<K extends keyof any, V> = [key: K, value: V][]\n\nexport const recordToEntries = <K extends keyof any, V>(\n\tobj: Record<K, V>,\n): Entries<K, V> => Object.entries(obj) as Entries<K, V>\n\nexport const entriesToRecord = <K extends keyof any, V>(\n\tentries: Entries<K, V>,\n): Record<K, V> => Object.fromEntries(entries) as Record<K, V>\n"]}
|
|
@@ -3,7 +3,7 @@ import { __spreadProps, __spreadValues } from '../../dist/chunk-PZLG2HP3.js';
|
|
|
3
3
|
import * as http from 'http';
|
|
4
4
|
import { render, prettyDOM } from '@testing-library/react';
|
|
5
5
|
import * as AtomIO from 'atom.io';
|
|
6
|
-
import
|
|
6
|
+
import { IMPLICIT, findInStore, setIntoStore, getFromStore, clearStore } from 'atom.io/internal';
|
|
7
7
|
import * as AR from 'atom.io/react';
|
|
8
8
|
import * as RTR from 'atom.io/realtime-react';
|
|
9
9
|
import * as RTS from 'atom.io/realtime-server';
|
|
@@ -12,8 +12,10 @@ import * as SocketIO from 'socket.io';
|
|
|
12
12
|
import { io } from 'socket.io-client';
|
|
13
13
|
import { jsx } from 'react/jsx-runtime';
|
|
14
14
|
|
|
15
|
+
var testNumber = 0;
|
|
15
16
|
var setupRealtimeTestServer = (options) => {
|
|
16
|
-
|
|
17
|
+
++testNumber;
|
|
18
|
+
const silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE);
|
|
17
19
|
const httpServer = http.createServer((_, res) => res.end(`Hello World!`));
|
|
18
20
|
const address = httpServer.listen().address();
|
|
19
21
|
const port = typeof address === `string` ? 80 : address === null ? null : address.port;
|
|
@@ -22,26 +24,12 @@ var setupRealtimeTestServer = (options) => {
|
|
|
22
24
|
const server = new SocketIO.Server(httpServer).use((socket, next) => {
|
|
23
25
|
const { token, username } = socket.handshake.auth;
|
|
24
26
|
if (token === `test` && socket.id) {
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
RTS.usersOfSockets.core.findRelatedKeysState,
|
|
32
|
-
username,
|
|
33
|
-
silo.store
|
|
34
|
-
);
|
|
35
|
-
Internal.setIntoStore(
|
|
36
|
-
socketRelatedKeysState,
|
|
37
|
-
(keys) => (keys.clear(), keys.add(username)),
|
|
38
|
-
silo.store
|
|
39
|
-
);
|
|
40
|
-
Internal.setIntoStore(
|
|
41
|
-
clientRelatedKeysState,
|
|
42
|
-
(keys) => (keys.clear(), keys.add(socket.id)),
|
|
43
|
-
silo.store
|
|
44
|
-
);
|
|
27
|
+
const socketState = findInStore(RTS.socketAtoms, socket.id, silo.store);
|
|
28
|
+
setIntoStore(socketState, socket, silo.store);
|
|
29
|
+
const usersOfSockets2 = RTS.usersOfSockets.in(silo.store);
|
|
30
|
+
usersOfSockets2.relations.set(socket.id, username);
|
|
31
|
+
setIntoStore(RTS.userIndex, (index) => index.add(username), silo.store);
|
|
32
|
+
setIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store);
|
|
45
33
|
console.log(`${username} connected on ${socket.id}`);
|
|
46
34
|
next();
|
|
47
35
|
} else {
|
|
@@ -53,7 +41,15 @@ var setupRealtimeTestServer = (options) => {
|
|
|
53
41
|
});
|
|
54
42
|
const dispose = () => {
|
|
55
43
|
server.close();
|
|
56
|
-
|
|
44
|
+
const roomKeys = getFromStore(RTS.roomIndex, silo.store);
|
|
45
|
+
for (const roomKey of roomKeys) {
|
|
46
|
+
const roomState = findInStore(RTS.roomSelectors, roomKey, silo.store);
|
|
47
|
+
const room = getFromStore(roomState, silo.store);
|
|
48
|
+
if (room && !(room instanceof Promise)) {
|
|
49
|
+
room.kill();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
silo.store.valueMap.clear();
|
|
57
53
|
};
|
|
58
54
|
return {
|
|
59
55
|
name: `SERVER`,
|
|
@@ -67,9 +63,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
67
63
|
} };
|
|
68
64
|
const init = () => {
|
|
69
65
|
const socket = io(`http://localhost:${port}/`, {
|
|
70
|
-
auth: { token: `test`, username: name }
|
|
66
|
+
auth: { token: `test`, username: `${name}-${testNumber}` }
|
|
71
67
|
});
|
|
72
|
-
const silo = new AtomIO.Silo(name,
|
|
68
|
+
const silo = new AtomIO.Silo(name, IMPLICIT.STORE);
|
|
73
69
|
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
74
70
|
if (Array.isArray(value)) {
|
|
75
71
|
silo.store.valueMap.set(key, [...value]);
|
|
@@ -85,8 +81,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
85
81
|
);
|
|
86
82
|
const prettyPrint = () => console.log(prettyDOM(renderResult.container));
|
|
87
83
|
const dispose = () => {
|
|
84
|
+
renderResult.unmount();
|
|
88
85
|
socket.disconnect();
|
|
89
|
-
|
|
86
|
+
clearStore(silo.store);
|
|
90
87
|
};
|
|
91
88
|
testClient.dispose = dispose;
|
|
92
89
|
return {
|
|
@@ -101,7 +98,11 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
101
98
|
};
|
|
102
99
|
var singleClient = (options) => {
|
|
103
100
|
const server = setupRealtimeTestServer(options);
|
|
104
|
-
const client = setupRealtimeTestClient(
|
|
101
|
+
const client = setupRealtimeTestClient(
|
|
102
|
+
options,
|
|
103
|
+
`CLIENT-${testNumber}`,
|
|
104
|
+
server.port
|
|
105
|
+
);
|
|
105
106
|
return {
|
|
106
107
|
client,
|
|
107
108
|
server,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx"],"names":["clients"],"mappings":";;;;;;;;;AAAA,YAAY,UAAU;AAEtB,
|
|
1
|
+
{"version":3,"sources":["../src/setup-realtime-test.tsx"],"names":["usersOfSockets","clients"],"mappings":"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","sourcesContent":["import * as http from \"http\"\n\nimport { prettyDOM, render } from \"@testing-library/react\"\nimport type { RenderResult } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport {\n\tIMPLICIT,\n\tclearStore,\n\tfindInStore,\n\tgetFromStore,\n\tsetIntoStore,\n} from \"atom.io/internal\"\nimport * as AR from \"atom.io/react\"\nimport * as RTR from \"atom.io/realtime-react\"\nimport * as RTS from \"atom.io/realtime-server\"\nimport * as Happy from \"happy-dom\"\nimport * as React from \"react\"\nimport * as SocketIO from \"socket.io\"\nimport type { Socket as ClientSocket } from \"socket.io-client\"\nimport { io } from \"socket.io-client\"\n\nimport { recordToEntries } from \"~/packages/anvl/src/object\"\n\nlet testNumber = 0\n\nexport type TestSetupOptions = {\n\tserver: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void\n}\nexport type TestSetupOptions__SingleClient = TestSetupOptions & {\n\tclient: React.FC\n}\nexport type TestSetupOptions__MultiClient<ClientNames extends string> =\n\tTestSetupOptions & {\n\t\tclients: {\n\t\t\t[K in ClientNames]: React.FC\n\t\t}\n\t}\n\nexport type RealtimeTestTools = {\n\tname: string\n\tsilo: AtomIO.Silo\n}\nexport type RealtimeTestClient = RealtimeTestTools & {\n\trenderResult: RenderResult\n\tprettyPrint: () => void\n\tsocket: ClientSocket\n}\nexport type RealtimeTestClientBuilder = {\n\tdispose: () => void\n\tinit: () => RealtimeTestClient\n}\n\nexport type RealtimeTestServer = RealtimeTestTools & {\n\tdispose: () => void\n\tport: number\n}\n\nexport type RealtimeTestAPI = {\n\tserver: RealtimeTestServer\n\tteardown: () => void\n}\nexport type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {\n\tclient: RealtimeTestClientBuilder\n}\nexport type RealtimeTestAPI__MultiClient<ClientNames extends string> =\n\tRealtimeTestAPI & {\n\t\tclients: Record<ClientNames, RealtimeTestClientBuilder>\n\t}\n\nexport const setupRealtimeTestServer = (\n\toptions: TestSetupOptions,\n): RealtimeTestServer => {\n\t++testNumber\n\tconst silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE)\n\n\tconst httpServer = http.createServer((_, res) => res.end(`Hello World!`))\n\tconst address = httpServer.listen().address()\n\tconst port =\n\t\ttypeof address === `string` ? 80 : address === null ? null : address.port\n\tif (port === null) throw new Error(`Could not determine port for test server`)\n\n\tconst server = new SocketIO.Server(httpServer).use((socket, next) => {\n\t\tconst { token, username } = socket.handshake.auth\n\t\tif (token === `test` && socket.id) {\n\t\t\tconst socketState = findInStore(RTS.socketAtoms, socket.id, silo.store)\n\t\t\tsetIntoStore(socketState, socket, silo.store)\n\t\t\tconst usersOfSockets = RTS.usersOfSockets.in(silo.store)\n\t\t\tusersOfSockets.relations.set(socket.id, username)\n\t\t\tsetIntoStore(RTS.userIndex, (index) => index.add(username), silo.store)\n\t\t\tsetIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store)\n\t\t\tconsole.log(`${username} connected on ${socket.id}`)\n\t\t\tnext()\n\t\t} else {\n\t\t\tnext(new Error(`Authentication error`))\n\t\t}\n\t})\n\n\tserver.on(`connection`, (socket: SocketIO.Socket) => {\n\t\toptions.server({ socket, silo })\n\t})\n\n\tconst dispose = () => {\n\t\tserver.close()\n\t\tconst roomKeys = getFromStore(RTS.roomIndex, silo.store)\n\t\tfor (const roomKey of roomKeys) {\n\t\t\tconst roomState = findInStore(RTS.roomSelectors, roomKey, silo.store)\n\t\t\tconst room = getFromStore(roomState, silo.store)\n\t\t\tif (room && !(room instanceof Promise)) {\n\t\t\t\troom.kill()\n\t\t\t}\n\t\t}\n\t\tsilo.store.valueMap.clear()\n\t}\n\n\treturn {\n\t\tname: `SERVER`,\n\t\tsilo,\n\t\tdispose,\n\t\tport,\n\t}\n}\nexport const setupRealtimeTestClient = (\n\toptions: TestSetupOptions__SingleClient,\n\tname: string,\n\tport: number,\n): RealtimeTestClientBuilder => {\n\tconst testClient = { dispose: () => {} }\n\tconst init = () => {\n\t\tconst socket: ClientSocket = io(`http://localhost:${port}/`, {\n\t\t\tauth: { token: `test`, username: `${name}-${testNumber}` },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(name, IMPLICIT.STORE)\n\t\tfor (const [key, value] of silo.store.valueMap.entries()) {\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tsilo.store.valueMap.set(key, [...value])\n\t\t\t}\n\t\t}\n\n\t\tconst { document } = new Happy.Window()\n\t\tdocument.body.innerHTML = `<div id=\"app\"></div>`\n\t\tconst renderResult = render(\n\t\t\t<AR.StoreProvider store={silo.store}>\n\t\t\t\t<RTR.RealtimeProvider socket={socket}>\n\t\t\t\t\t<options.client />\n\t\t\t\t</RTR.RealtimeProvider>\n\t\t\t</AR.StoreProvider>,\n\t\t\t{\n\t\t\t\tcontainer: document.querySelector(`#app`) as unknown as HTMLElement,\n\t\t\t},\n\t\t)\n\n\t\tconst prettyPrint = () => console.log(prettyDOM(renderResult.container))\n\n\t\tconst dispose = () => {\n\t\t\trenderResult.unmount()\n\t\t\tsocket.disconnect()\n\t\t\tclearStore(silo.store)\n\t\t}\n\t\ttestClient.dispose = dispose\n\n\t\treturn {\n\t\t\tname,\n\t\t\tsilo,\n\t\t\tsocket,\n\t\t\trenderResult,\n\t\t\tprettyPrint,\n\t\t}\n\t}\n\treturn Object.assign(testClient, { init })\n}\n\nexport const singleClient = (\n\toptions: TestSetupOptions__SingleClient,\n): RealtimeTestAPI__SingleClient => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst client = setupRealtimeTestClient(\n\t\toptions,\n\t\t`CLIENT-${testNumber}`,\n\t\tserver.port,\n\t)\n\n\treturn {\n\t\tclient,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tclient.dispose()\n\t\t\tserver.dispose()\n\t\t},\n\t}\n}\n\nexport const multiClient = <ClientNames extends string>(\n\toptions: TestSetupOptions__MultiClient<ClientNames>,\n): RealtimeTestAPI__MultiClient<ClientNames> => {\n\tconst server = setupRealtimeTestServer(options)\n\tconst clients = recordToEntries(options.clients).reduce(\n\t\t(clients, [name, client]) => {\n\t\t\tclients[name] = setupRealtimeTestClient(\n\t\t\t\t{ ...options, client },\n\t\t\t\tname,\n\t\t\t\tserver.port,\n\t\t\t)\n\t\t\treturn clients\n\t\t},\n\t\t{} as Record<ClientNames, RealtimeTestClientBuilder>,\n\t)\n\n\treturn {\n\t\tclients,\n\t\tserver,\n\t\tteardown: () => {\n\t\t\tfor (const [, client] of recordToEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t\tserver.dispose()\n\t\t},\n\t}\n}\n"]}
|