atom.io 0.17.0 → 0.18.1
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-IZHOMSXA.js +331 -0
- package/dist/chunk-IZHOMSXA.js.map +1 -0
- package/dist/chunk-JDUNWJFB.js +18 -0
- package/dist/chunk-JDUNWJFB.js.map +1 -0
- package/dist/index.cjs +4 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +66 -51
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/internal/dist/index.cjs +187 -58
- package/internal/dist/index.cjs.map +1 -1
- package/internal/dist/index.d.ts +95 -71
- package/internal/dist/index.js +179 -53
- package/internal/dist/index.js.map +1 -1
- package/internal/src/arbitrary.ts +3 -0
- package/internal/src/atom/delete-atom.ts +7 -6
- package/internal/src/caching.ts +6 -4
- 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-atom-update.ts +6 -2
- 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/copy-mutable-if-needed.ts +5 -0
- package/internal/src/set-state/emit-update.ts +25 -11
- package/internal/src/set-state/set-atom.ts +15 -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 +6 -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 +30 -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 +4 -0
- package/package.json +241 -230
- 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 +91 -108
- package/react-devtools/dist/index.js.map +1 -1
- package/react-devtools/src/StateEditor.tsx +4 -4
- package/react-devtools/src/StateIndex.tsx +1 -4
- package/react-devtools/src/TimelineIndex.tsx +3 -3
- package/react-devtools/src/TransactionIndex.tsx +9 -8
- package/react-devtools/src/index.ts +2 -2
- package/realtime/dist/index.cjs +120 -0
- package/realtime/dist/index.cjs.map +1 -0
- package/realtime/dist/index.d.ts +146 -0
- package/realtime/dist/index.js +111 -0
- package/realtime/dist/index.js.map +1 -0
- package/realtime/package.json +16 -0
- package/realtime/src/index.ts +2 -0
- package/realtime/src/realtime-continuity.ts +162 -0
- package/realtime/src/shared-room-store.ts +48 -0
- package/realtime-client/dist/index.cjs +424 -170
- package/realtime-client/dist/index.cjs.map +1 -1
- package/realtime-client/dist/index.d.ts +15 -11
- package/realtime-client/dist/index.js +96 -177
- package/realtime-client/dist/index.js.map +1 -1
- package/realtime-client/src/index.ts +8 -7
- 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} +6 -6
- 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 +12 -2
- package/realtime-client/src/realtime-client-stores/client-sync-store.ts +7 -7
- package/realtime-client/src/sync-continuity.ts +368 -0
- package/realtime-react/dist/index.cjs +367 -27
- package/realtime-react/dist/index.cjs.map +1 -1
- package/realtime-react/dist/index.d.ts +24 -8
- package/realtime-react/dist/index.js +38 -22
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/src/index.ts +6 -5
- package/realtime-react/src/use-pull-atom-family-member.ts +21 -0
- package/realtime-react/src/{use-sync.ts → use-pull-atom.ts} +4 -4
- 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-server/dist/index.cjs +769 -371
- package/realtime-server/dist/index.cjs.map +1 -1
- package/realtime-server/dist/index.d.ts +130 -60
- package/realtime-server/dist/index.js +753 -361
- package/realtime-server/dist/index.js.map +1 -1
- package/realtime-server/src/index.ts +17 -3
- package/realtime-server/src/ipc-sockets/child-socket.ts +135 -0
- package/realtime-server/src/ipc-sockets/custom-socket.ts +90 -0
- package/realtime-server/src/ipc-sockets/index.ts +3 -0
- package/realtime-server/src/ipc-sockets/parent-socket.ts +185 -0
- package/realtime-server/src/realtime-action-receiver.ts +8 -5
- package/realtime-server/src/realtime-continuity-synchronizer.ts +376 -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 +4 -1
- package/realtime-server/src/realtime-server-stores/realtime-continuity-store.ts +109 -0
- package/realtime-server/src/realtime-server-stores/server-room-external-actions.ts +64 -0
- package/realtime-server/src/realtime-server-stores/server-room-external-store.ts +42 -0
- package/realtime-server/src/realtime-server-stores/server-sync-store.ts +51 -98
- 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 +34 -32
- package/realtime-testing/dist/index.cjs.map +1 -1
- package/realtime-testing/dist/index.d.ts +1 -0
- package/realtime-testing/dist/index.js +33 -31
- package/realtime-testing/dist/index.js.map +1 -1
- package/realtime-testing/src/setup-realtime-test.tsx +44 -32
- package/src/atom.ts +49 -31
- package/src/logger.ts +14 -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
- package/realtime-client/src/sync-server-action.ts +0 -170
- package/realtime-client/src/sync-state.ts +0 -19
- package/realtime-react/src/use-pull-family-member.ts +0 -16
- package/realtime-react/src/use-sync-server-action.ts +0 -16
- package/realtime-server/src/realtime-action-synchronizer.ts +0 -152
|
@@ -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,8 +3,9 @@
|
|
|
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
|
+
var RT = require('atom.io/realtime');
|
|
8
9
|
var RTR = require('atom.io/realtime-react');
|
|
9
10
|
var RTS = require('atom.io/realtime-server');
|
|
10
11
|
var Happy = require('happy-dom');
|
|
@@ -32,8 +33,8 @@ function _interopNamespace(e) {
|
|
|
32
33
|
|
|
33
34
|
var http__namespace = /*#__PURE__*/_interopNamespace(http);
|
|
34
35
|
var AtomIO__namespace = /*#__PURE__*/_interopNamespace(AtomIO);
|
|
35
|
-
var Internal__namespace = /*#__PURE__*/_interopNamespace(Internal);
|
|
36
36
|
var AR__namespace = /*#__PURE__*/_interopNamespace(AR);
|
|
37
|
+
var RT__namespace = /*#__PURE__*/_interopNamespace(RT);
|
|
37
38
|
var RTR__namespace = /*#__PURE__*/_interopNamespace(RTR);
|
|
38
39
|
var RTS__namespace = /*#__PURE__*/_interopNamespace(RTS);
|
|
39
40
|
var Happy__namespace = /*#__PURE__*/_interopNamespace(Happy);
|
|
@@ -61,36 +62,24 @@ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
|
61
62
|
|
|
62
63
|
// ../anvl/src/object/entries.ts
|
|
63
64
|
var recordToEntries = (obj) => Object.entries(obj);
|
|
65
|
+
var testNumber = 0;
|
|
64
66
|
var setupRealtimeTestServer = (options) => {
|
|
65
|
-
|
|
67
|
+
++testNumber;
|
|
68
|
+
const silo = new AtomIO__namespace.Silo(`SERVER-${testNumber}`, internal.IMPLICIT.STORE);
|
|
66
69
|
const httpServer = http__namespace.createServer((_, res) => res.end(`Hello World!`));
|
|
67
|
-
const address = httpServer.listen().address();
|
|
68
|
-
const port = typeof address === `string` ?
|
|
70
|
+
const address = httpServer.listen(options.port).address();
|
|
71
|
+
const port = typeof address === `string` ? null : address === null ? null : address.port;
|
|
69
72
|
if (port === null)
|
|
70
73
|
throw new Error(`Could not determine port for test server`);
|
|
71
74
|
const server = new SocketIO__namespace.Server(httpServer).use((socket, next) => {
|
|
72
75
|
const { token, username } = socket.handshake.auth;
|
|
73
76
|
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
|
-
);
|
|
77
|
+
const socketState = internal.findInStore(RTS__namespace.socketAtoms, socket.id, silo.store);
|
|
78
|
+
internal.setIntoStore(socketState, socket, silo.store);
|
|
79
|
+
const usersOfSockets2 = RTS__namespace.usersOfSockets.in(silo.store);
|
|
80
|
+
usersOfSockets2.relations.set(socket.id, username);
|
|
81
|
+
internal.setIntoStore(RTS__namespace.userIndex, (index) => index.add(username), silo.store);
|
|
82
|
+
internal.setIntoStore(RTS__namespace.socketIndex, (index) => index.add(socket.id), silo.store);
|
|
94
83
|
console.log(`${username} connected on ${socket.id}`);
|
|
95
84
|
next();
|
|
96
85
|
} else {
|
|
@@ -102,7 +91,15 @@ var setupRealtimeTestServer = (options) => {
|
|
|
102
91
|
});
|
|
103
92
|
const dispose = () => {
|
|
104
93
|
server.close();
|
|
105
|
-
|
|
94
|
+
const roomKeys = internal.getFromStore(RT__namespace.roomIndex, silo.store);
|
|
95
|
+
for (const roomKey of roomKeys) {
|
|
96
|
+
const roomState = internal.findInStore(RTS__namespace.roomSelectors, roomKey, silo.store);
|
|
97
|
+
const room = internal.getFromStore(roomState, silo.store);
|
|
98
|
+
if (room && !(room instanceof Promise)) {
|
|
99
|
+
room.process.kill();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
silo.store.valueMap.clear();
|
|
106
103
|
};
|
|
107
104
|
return {
|
|
108
105
|
name: `SERVER`,
|
|
@@ -116,9 +113,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
116
113
|
} };
|
|
117
114
|
const init = () => {
|
|
118
115
|
const socket = socket_ioClient.io(`http://localhost:${port}/`, {
|
|
119
|
-
auth: { token: `test`, username: name }
|
|
116
|
+
auth: { token: `test`, username: `${name}-${testNumber}` }
|
|
120
117
|
});
|
|
121
|
-
const silo = new AtomIO__namespace.Silo(name,
|
|
118
|
+
const silo = new AtomIO__namespace.Silo(name, internal.IMPLICIT.STORE);
|
|
122
119
|
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
123
120
|
if (Array.isArray(value)) {
|
|
124
121
|
silo.store.valueMap.set(key, [...value]);
|
|
@@ -134,8 +131,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
134
131
|
);
|
|
135
132
|
const prettyPrint = () => console.log(react.prettyDOM(renderResult.container));
|
|
136
133
|
const dispose = () => {
|
|
134
|
+
renderResult.unmount();
|
|
137
135
|
socket.disconnect();
|
|
138
|
-
|
|
136
|
+
internal.clearStore(silo.store);
|
|
139
137
|
};
|
|
140
138
|
testClient.dispose = dispose;
|
|
141
139
|
return {
|
|
@@ -150,13 +148,17 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
150
148
|
};
|
|
151
149
|
var singleClient = (options) => {
|
|
152
150
|
const server = setupRealtimeTestServer(options);
|
|
153
|
-
const client = setupRealtimeTestClient(
|
|
151
|
+
const client = setupRealtimeTestClient(
|
|
152
|
+
options,
|
|
153
|
+
`CLIENT-${testNumber}`,
|
|
154
|
+
server.port
|
|
155
|
+
);
|
|
154
156
|
return {
|
|
155
157
|
client,
|
|
156
158
|
server,
|
|
157
159
|
teardown: () => {
|
|
158
|
-
client.dispose();
|
|
159
160
|
server.dispose();
|
|
161
|
+
client.dispose();
|
|
160
162
|
}
|
|
161
163
|
};
|
|
162
164
|
};
|
|
@@ -177,10 +179,10 @@ var multiClient = (options) => {
|
|
|
177
179
|
clients,
|
|
178
180
|
server,
|
|
179
181
|
teardown: () => {
|
|
182
|
+
server.dispose();
|
|
180
183
|
for (const [, client] of recordToEntries(clients)) {
|
|
181
184
|
client.dispose();
|
|
182
185
|
}
|
|
183
|
-
server.dispose();
|
|
184
186
|
}
|
|
185
187
|
};
|
|
186
188
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx","../../../anvl/src/object/entries.ts"],"names":["clients"],"mappings":"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","sourcesContent":["import * as http from \"http\"\n\nimport { type RenderResult, prettyDOM, render } from \"@testing-library/react\"\nimport * as AtomIO from \"atom.io\"\nimport * as Internal 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\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\tconst silo = new AtomIO.Silo(`SERVER`, Internal.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\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 socketRelatedKeysState = Internal.findInStore(\n\t\t\t\tRTS.usersOfSockets.core.findRelatedKeysState,\n\t\t\t\tsocket.id,\n\t\t\t\tsilo.store,\n\t\t\t)\n\t\t\tconst clientRelatedKeysState = Internal.findInStore(\n\t\t\t\tRTS.usersOfSockets.core.findRelatedKeysState,\n\t\t\t\tusername,\n\t\t\t\tsilo.store,\n\t\t\t)\n\t\t\tInternal.setIntoStore(\n\t\t\t\tsocketRelatedKeysState,\n\t\t\t\t(keys) => (keys.clear(), keys.add(username)),\n\t\t\t\tsilo.store,\n\t\t\t)\n\t\t\tInternal.setIntoStore(\n\t\t\t\tclientRelatedKeysState,\n\t\t\t\t(keys) => (keys.clear(), keys.add(socket.id)),\n\t\t\t\tsilo.store,\n\t\t\t)\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\tInternal.clearStore(silo.store)\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 },\n\t\t})\n\t\tconst silo = new AtomIO.Silo(name, Internal.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\tsocket.disconnect()\n\t\t\tInternal.clearStore(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(options, `CLIENT`, server.port)\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"]}
|
|
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 RT from \"atom.io/realtime\"\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\tport: number\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(options.port).address()\n\tconst port =\n\t\ttypeof address === `string` ? null : 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(RT.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.process.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\tserver.dispose()\n\t\t\tclient.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\tserver.dispose()\n\t\t\tfor (const [, client] of recordToEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\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,8 +3,9 @@ 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
|
+
import * as RT from 'atom.io/realtime';
|
|
8
9
|
import * as RTR from 'atom.io/realtime-react';
|
|
9
10
|
import * as RTS from 'atom.io/realtime-server';
|
|
10
11
|
import * as Happy from 'happy-dom';
|
|
@@ -12,36 +13,24 @@ import * as SocketIO from 'socket.io';
|
|
|
12
13
|
import { io } from 'socket.io-client';
|
|
13
14
|
import { jsx } from 'react/jsx-runtime';
|
|
14
15
|
|
|
16
|
+
var testNumber = 0;
|
|
15
17
|
var setupRealtimeTestServer = (options) => {
|
|
16
|
-
|
|
18
|
+
++testNumber;
|
|
19
|
+
const silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE);
|
|
17
20
|
const httpServer = http.createServer((_, res) => res.end(`Hello World!`));
|
|
18
|
-
const address = httpServer.listen().address();
|
|
19
|
-
const port = typeof address === `string` ?
|
|
21
|
+
const address = httpServer.listen(options.port).address();
|
|
22
|
+
const port = typeof address === `string` ? null : address === null ? null : address.port;
|
|
20
23
|
if (port === null)
|
|
21
24
|
throw new Error(`Could not determine port for test server`);
|
|
22
25
|
const server = new SocketIO.Server(httpServer).use((socket, next) => {
|
|
23
26
|
const { token, username } = socket.handshake.auth;
|
|
24
27
|
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
|
-
);
|
|
28
|
+
const socketState = findInStore(RTS.socketAtoms, socket.id, silo.store);
|
|
29
|
+
setIntoStore(socketState, socket, silo.store);
|
|
30
|
+
const usersOfSockets2 = RTS.usersOfSockets.in(silo.store);
|
|
31
|
+
usersOfSockets2.relations.set(socket.id, username);
|
|
32
|
+
setIntoStore(RTS.userIndex, (index) => index.add(username), silo.store);
|
|
33
|
+
setIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store);
|
|
45
34
|
console.log(`${username} connected on ${socket.id}`);
|
|
46
35
|
next();
|
|
47
36
|
} else {
|
|
@@ -53,7 +42,15 @@ var setupRealtimeTestServer = (options) => {
|
|
|
53
42
|
});
|
|
54
43
|
const dispose = () => {
|
|
55
44
|
server.close();
|
|
56
|
-
|
|
45
|
+
const roomKeys = getFromStore(RT.roomIndex, silo.store);
|
|
46
|
+
for (const roomKey of roomKeys) {
|
|
47
|
+
const roomState = findInStore(RTS.roomSelectors, roomKey, silo.store);
|
|
48
|
+
const room = getFromStore(roomState, silo.store);
|
|
49
|
+
if (room && !(room instanceof Promise)) {
|
|
50
|
+
room.process.kill();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
silo.store.valueMap.clear();
|
|
57
54
|
};
|
|
58
55
|
return {
|
|
59
56
|
name: `SERVER`,
|
|
@@ -67,9 +64,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
67
64
|
} };
|
|
68
65
|
const init = () => {
|
|
69
66
|
const socket = io(`http://localhost:${port}/`, {
|
|
70
|
-
auth: { token: `test`, username: name }
|
|
67
|
+
auth: { token: `test`, username: `${name}-${testNumber}` }
|
|
71
68
|
});
|
|
72
|
-
const silo = new AtomIO.Silo(name,
|
|
69
|
+
const silo = new AtomIO.Silo(name, IMPLICIT.STORE);
|
|
73
70
|
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
74
71
|
if (Array.isArray(value)) {
|
|
75
72
|
silo.store.valueMap.set(key, [...value]);
|
|
@@ -85,8 +82,9 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
85
82
|
);
|
|
86
83
|
const prettyPrint = () => console.log(prettyDOM(renderResult.container));
|
|
87
84
|
const dispose = () => {
|
|
85
|
+
renderResult.unmount();
|
|
88
86
|
socket.disconnect();
|
|
89
|
-
|
|
87
|
+
clearStore(silo.store);
|
|
90
88
|
};
|
|
91
89
|
testClient.dispose = dispose;
|
|
92
90
|
return {
|
|
@@ -101,13 +99,17 @@ var setupRealtimeTestClient = (options, name, port) => {
|
|
|
101
99
|
};
|
|
102
100
|
var singleClient = (options) => {
|
|
103
101
|
const server = setupRealtimeTestServer(options);
|
|
104
|
-
const client = setupRealtimeTestClient(
|
|
102
|
+
const client = setupRealtimeTestClient(
|
|
103
|
+
options,
|
|
104
|
+
`CLIENT-${testNumber}`,
|
|
105
|
+
server.port
|
|
106
|
+
);
|
|
105
107
|
return {
|
|
106
108
|
client,
|
|
107
109
|
server,
|
|
108
110
|
teardown: () => {
|
|
109
|
-
client.dispose();
|
|
110
111
|
server.dispose();
|
|
112
|
+
client.dispose();
|
|
111
113
|
}
|
|
112
114
|
};
|
|
113
115
|
};
|
|
@@ -128,10 +130,10 @@ var multiClient = (options) => {
|
|
|
128
130
|
clients,
|
|
129
131
|
server,
|
|
130
132
|
teardown: () => {
|
|
133
|
+
server.dispose();
|
|
131
134
|
for (const [, client] of recordToEntries(clients)) {
|
|
132
135
|
client.dispose();
|
|
133
136
|
}
|
|
134
|
-
server.dispose();
|
|
135
137
|
}
|
|
136
138
|
};
|
|
137
139
|
};
|
|
@@ -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 RT from \"atom.io/realtime\"\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\tport: number\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(options.port).address()\n\tconst port =\n\t\ttypeof address === `string` ? null : 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(RT.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.process.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\tserver.dispose()\n\t\t\tclient.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\tserver.dispose()\n\t\t\tfor (const [, client] of recordToEntries(clients)) {\n\t\t\t\tclient.dispose()\n\t\t\t}\n\t\t},\n\t}\n}\n"]}
|
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
import * as http from "http"
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { prettyDOM, render } from "@testing-library/react"
|
|
4
|
+
import type { RenderResult } from "@testing-library/react"
|
|
4
5
|
import * as AtomIO from "atom.io"
|
|
5
|
-
import
|
|
6
|
+
import {
|
|
7
|
+
IMPLICIT,
|
|
8
|
+
clearStore,
|
|
9
|
+
findInStore,
|
|
10
|
+
getFromStore,
|
|
11
|
+
setIntoStore,
|
|
12
|
+
} from "atom.io/internal"
|
|
6
13
|
import * as AR from "atom.io/react"
|
|
14
|
+
import * as RT from "atom.io/realtime"
|
|
7
15
|
import * as RTR from "atom.io/realtime-react"
|
|
8
16
|
import * as RTS from "atom.io/realtime-server"
|
|
9
17
|
import * as Happy from "happy-dom"
|
|
@@ -14,7 +22,10 @@ import { io } from "socket.io-client"
|
|
|
14
22
|
|
|
15
23
|
import { recordToEntries } from "~/packages/anvl/src/object"
|
|
16
24
|
|
|
25
|
+
let testNumber = 0
|
|
26
|
+
|
|
17
27
|
export type TestSetupOptions = {
|
|
28
|
+
port: number
|
|
18
29
|
server: (tools: { socket: SocketIO.Socket; silo: AtomIO.Silo }) => void
|
|
19
30
|
}
|
|
20
31
|
export type TestSetupOptions__SingleClient = TestSetupOptions & {
|
|
@@ -61,36 +72,24 @@ export type RealtimeTestAPI__MultiClient<ClientNames extends string> =
|
|
|
61
72
|
export const setupRealtimeTestServer = (
|
|
62
73
|
options: TestSetupOptions,
|
|
63
74
|
): RealtimeTestServer => {
|
|
64
|
-
|
|
75
|
+
++testNumber
|
|
76
|
+
const silo = new AtomIO.Silo(`SERVER-${testNumber}`, IMPLICIT.STORE)
|
|
65
77
|
|
|
66
78
|
const httpServer = http.createServer((_, res) => res.end(`Hello World!`))
|
|
67
|
-
const address = httpServer.listen().address()
|
|
79
|
+
const address = httpServer.listen(options.port).address()
|
|
68
80
|
const port =
|
|
69
|
-
typeof address === `string` ?
|
|
81
|
+
typeof address === `string` ? null : address === null ? null : address.port
|
|
70
82
|
if (port === null) throw new Error(`Could not determine port for test server`)
|
|
83
|
+
|
|
71
84
|
const server = new SocketIO.Server(httpServer).use((socket, next) => {
|
|
72
85
|
const { token, username } = socket.handshake.auth
|
|
73
86
|
if (token === `test` && socket.id) {
|
|
74
|
-
const
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
)
|
|
79
|
-
|
|
80
|
-
RTS.usersOfSockets.core.findRelatedKeysState,
|
|
81
|
-
username,
|
|
82
|
-
silo.store,
|
|
83
|
-
)
|
|
84
|
-
Internal.setIntoStore(
|
|
85
|
-
socketRelatedKeysState,
|
|
86
|
-
(keys) => (keys.clear(), keys.add(username)),
|
|
87
|
-
silo.store,
|
|
88
|
-
)
|
|
89
|
-
Internal.setIntoStore(
|
|
90
|
-
clientRelatedKeysState,
|
|
91
|
-
(keys) => (keys.clear(), keys.add(socket.id)),
|
|
92
|
-
silo.store,
|
|
93
|
-
)
|
|
87
|
+
const socketState = findInStore(RTS.socketAtoms, socket.id, silo.store)
|
|
88
|
+
setIntoStore(socketState, socket, silo.store)
|
|
89
|
+
const usersOfSockets = RTS.usersOfSockets.in(silo.store)
|
|
90
|
+
usersOfSockets.relations.set(socket.id, username)
|
|
91
|
+
setIntoStore(RTS.userIndex, (index) => index.add(username), silo.store)
|
|
92
|
+
setIntoStore(RTS.socketIndex, (index) => index.add(socket.id), silo.store)
|
|
94
93
|
console.log(`${username} connected on ${socket.id}`)
|
|
95
94
|
next()
|
|
96
95
|
} else {
|
|
@@ -104,7 +103,15 @@ export const setupRealtimeTestServer = (
|
|
|
104
103
|
|
|
105
104
|
const dispose = () => {
|
|
106
105
|
server.close()
|
|
107
|
-
|
|
106
|
+
const roomKeys = getFromStore(RT.roomIndex, silo.store)
|
|
107
|
+
for (const roomKey of roomKeys) {
|
|
108
|
+
const roomState = findInStore(RTS.roomSelectors, roomKey, silo.store)
|
|
109
|
+
const room = getFromStore(roomState, silo.store)
|
|
110
|
+
if (room && !(room instanceof Promise)) {
|
|
111
|
+
room.process.kill()
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
silo.store.valueMap.clear()
|
|
108
115
|
}
|
|
109
116
|
|
|
110
117
|
return {
|
|
@@ -122,9 +129,9 @@ export const setupRealtimeTestClient = (
|
|
|
122
129
|
const testClient = { dispose: () => {} }
|
|
123
130
|
const init = () => {
|
|
124
131
|
const socket: ClientSocket = io(`http://localhost:${port}/`, {
|
|
125
|
-
auth: { token: `test`, username: name },
|
|
132
|
+
auth: { token: `test`, username: `${name}-${testNumber}` },
|
|
126
133
|
})
|
|
127
|
-
const silo = new AtomIO.Silo(name,
|
|
134
|
+
const silo = new AtomIO.Silo(name, IMPLICIT.STORE)
|
|
128
135
|
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
129
136
|
if (Array.isArray(value)) {
|
|
130
137
|
silo.store.valueMap.set(key, [...value])
|
|
@@ -147,8 +154,9 @@ export const setupRealtimeTestClient = (
|
|
|
147
154
|
const prettyPrint = () => console.log(prettyDOM(renderResult.container))
|
|
148
155
|
|
|
149
156
|
const dispose = () => {
|
|
157
|
+
renderResult.unmount()
|
|
150
158
|
socket.disconnect()
|
|
151
|
-
|
|
159
|
+
clearStore(silo.store)
|
|
152
160
|
}
|
|
153
161
|
testClient.dispose = dispose
|
|
154
162
|
|
|
@@ -167,14 +175,18 @@ export const singleClient = (
|
|
|
167
175
|
options: TestSetupOptions__SingleClient,
|
|
168
176
|
): RealtimeTestAPI__SingleClient => {
|
|
169
177
|
const server = setupRealtimeTestServer(options)
|
|
170
|
-
const client = setupRealtimeTestClient(
|
|
178
|
+
const client = setupRealtimeTestClient(
|
|
179
|
+
options,
|
|
180
|
+
`CLIENT-${testNumber}`,
|
|
181
|
+
server.port,
|
|
182
|
+
)
|
|
171
183
|
|
|
172
184
|
return {
|
|
173
185
|
client,
|
|
174
186
|
server,
|
|
175
187
|
teardown: () => {
|
|
176
|
-
client.dispose()
|
|
177
188
|
server.dispose()
|
|
189
|
+
client.dispose()
|
|
178
190
|
},
|
|
179
191
|
}
|
|
180
192
|
}
|
|
@@ -199,10 +211,10 @@ export const multiClient = <ClientNames extends string>(
|
|
|
199
211
|
clients,
|
|
200
212
|
server,
|
|
201
213
|
teardown: () => {
|
|
214
|
+
server.dispose()
|
|
202
215
|
for (const [, client] of recordToEntries(clients)) {
|
|
203
216
|
client.dispose()
|
|
204
217
|
}
|
|
205
|
-
server.dispose()
|
|
206
218
|
},
|
|
207
219
|
}
|
|
208
220
|
}
|