atom.io 0.16.2 → 0.17.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/dist/chunk-H4Q5FTPZ.js +11 -0
- package/dist/chunk-H4Q5FTPZ.js.map +1 -0
- package/dist/index.cjs +35 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +12 -36
- package/dist/index.js.map +1 -1
- package/internal/dist/index.cjs +268 -195
- package/internal/dist/index.cjs.map +1 -1
- package/internal/dist/index.d.ts +36 -11
- package/internal/dist/index.js +258 -195
- package/internal/dist/index.js.map +1 -1
- package/internal/src/atom/create-regular-atom.ts +2 -3
- package/internal/src/families/find-in-store.ts +74 -0
- package/internal/src/families/index.ts +1 -0
- package/internal/src/get-state/get-from-store.ts +14 -0
- package/internal/src/get-state/index.ts +2 -0
- package/internal/src/{read-or-compute-value.ts → get-state/read-or-compute-value.ts} +3 -3
- package/internal/src/index.ts +1 -1
- package/internal/src/ingest-updates/ingest-atom-update.ts +2 -2
- package/internal/src/ingest-updates/ingest-transaction-update.ts +1 -0
- package/internal/src/mutable/create-mutable-atom.ts +3 -4
- package/internal/src/mutable/tracker.ts +43 -35
- package/internal/src/mutable/transceiver.ts +1 -1
- package/internal/src/not-found-error.ts +14 -3
- package/internal/src/operation.ts +2 -1
- package/internal/src/selector/create-writable-selector.ts +2 -1
- package/internal/src/selector/register-selector.ts +6 -5
- package/internal/src/set-state/index.ts +1 -0
- package/internal/src/set-state/set-atom.ts +17 -3
- package/internal/src/set-state/set-into-store.ts +24 -0
- package/internal/src/set-state/stow-update.ts +2 -4
- package/internal/src/store/store.ts +13 -4
- package/internal/src/subscribe/subscribe-to-root-atoms.ts +1 -1
- package/internal/src/timeline/add-atom-to-timeline.ts +5 -5
- package/internal/src/transaction/abort-transaction.ts +2 -1
- package/internal/src/transaction/apply-transaction.ts +5 -3
- package/internal/src/transaction/build-transaction.ts +20 -11
- package/internal/src/transaction/create-transaction.ts +2 -3
- package/internal/src/transaction/index.ts +3 -2
- package/internal/src/transaction/is-root-store.ts +23 -0
- package/package.json +10 -10
- package/react/dist/index.cjs +27 -21
- package/react/dist/index.cjs.map +1 -1
- package/react/dist/index.d.ts +8 -2
- package/react/dist/index.js +28 -22
- package/react/dist/index.js.map +1 -1
- package/react/src/index.ts +4 -1
- package/react/src/use-i.ts +35 -0
- package/react/src/use-json.ts +38 -0
- package/react/src/use-o.ts +33 -0
- package/react/src/use-tl.ts +45 -0
- package/realtime-client/dist/index.cjs +167 -64
- package/realtime-client/dist/index.cjs.map +1 -1
- package/realtime-client/dist/index.d.ts +10 -6
- package/realtime-client/dist/index.js +158 -63
- package/realtime-client/dist/index.js.map +1 -1
- package/realtime-client/src/index.ts +2 -1
- package/realtime-client/src/pull-family-member.ts +3 -3
- package/realtime-client/src/pull-mutable-family-member.ts +4 -4
- package/realtime-client/src/pull-mutable.ts +4 -4
- package/realtime-client/src/pull-state.ts +7 -6
- package/realtime-client/src/{realtime-client-store.ts → realtime-client-stores/client-main-store.ts} +0 -8
- package/realtime-client/src/realtime-client-stores/client-sync-store.ts +15 -0
- package/realtime-client/src/realtime-client-stores/index.ts +2 -0
- package/realtime-client/src/sync-server-action.ts +134 -40
- package/realtime-client/src/sync-state.ts +19 -0
- package/realtime-react/dist/index.cjs +43 -26
- package/realtime-react/dist/index.cjs.map +1 -1
- package/realtime-react/dist/index.d.ts +3 -1
- package/realtime-react/dist/index.js +41 -25
- package/realtime-react/dist/index.js.map +1 -1
- package/realtime-react/src/index.ts +1 -0
- package/realtime-react/src/on-mount.ts +3 -21
- package/realtime-react/src/use-realtime-service.ts +1 -1
- package/realtime-react/src/use-single-effect.ts +29 -0
- package/realtime-react/src/use-sync-server-action.ts +4 -7
- package/realtime-react/src/use-sync.ts +17 -0
- package/realtime-server/dist/index.cjs +239 -56
- package/realtime-server/dist/index.cjs.map +1 -1
- package/realtime-server/dist/index.d.ts +140 -9
- package/realtime-server/dist/index.js +228 -58
- package/realtime-server/dist/index.js.map +1 -1
- package/realtime-server/src/index.ts +2 -0
- package/realtime-server/src/realtime-action-synchronizer.ts +95 -14
- package/realtime-server/src/realtime-family-provider.ts +11 -6
- package/realtime-server/src/realtime-mutable-family-provider.ts +8 -6
- package/realtime-server/src/realtime-mutable-provider.ts +3 -2
- package/realtime-server/src/realtime-server-stores/index.ts +2 -0
- package/realtime-server/src/realtime-server-stores/server-sync-store.ts +115 -0
- package/realtime-server/src/realtime-server-stores/server-user-store.ts +45 -0
- package/realtime-server/src/realtime-state-provider.ts +18 -11
- package/realtime-server/src/realtime-state-receiver.ts +2 -2
- package/realtime-server/src/realtime-state-synchronizer.ts +23 -0
- package/realtime-testing/dist/index.cjs +65 -26
- package/realtime-testing/dist/index.cjs.map +1 -1
- package/realtime-testing/dist/index.d.ts +11 -7
- package/realtime-testing/dist/index.js +64 -26
- package/realtime-testing/dist/index.js.map +1 -1
- package/realtime-testing/src/setup-realtime-test.tsx +83 -43
- package/src/find-state.ts +8 -16
- package/src/get-state.ts +2 -11
- package/src/logger.ts +1 -0
- package/src/set-state.ts +1 -13
- package/src/silo.ts +7 -3
- package/src/transaction.ts +3 -3
- package/react/src/store-hooks.ts +0 -87
- package/realtime-server/src/realtime-server-store.ts +0 -39
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx","../../../anvl/src/object/entries.ts"],"names":["clients"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAAA,YAAY,UAAU;AAEtB,SAA4B,WAAW,cAAc;AACrD,YAAY,YAAY;AACxB,YAAY,cAAc;AAC1B,YAAY,QAAQ;AACpB,YAAY,SAAS;AACrB,YAAY,WAAW;AAEvB,YAAY,cAAc;AAE1B,SAAS,UAAU;;;
|
|
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"]}
|
|
@@ -2,6 +2,7 @@ import { RenderResult } from '@testing-library/react';
|
|
|
2
2
|
import * as AtomIO from 'atom.io';
|
|
3
3
|
import * as React from 'react';
|
|
4
4
|
import * as SocketIO from 'socket.io';
|
|
5
|
+
import { Socket } from 'socket.io-client';
|
|
5
6
|
|
|
6
7
|
type TestSetupOptions = {
|
|
7
8
|
server: (tools: {
|
|
@@ -20,15 +21,18 @@ type TestSetupOptions__MultiClient<ClientNames extends string> = TestSetupOption
|
|
|
20
21
|
type RealtimeTestTools = {
|
|
21
22
|
name: string;
|
|
22
23
|
silo: AtomIO.Silo;
|
|
23
|
-
dispose: () => void;
|
|
24
24
|
};
|
|
25
25
|
type RealtimeTestClient = RealtimeTestTools & {
|
|
26
26
|
renderResult: RenderResult;
|
|
27
27
|
prettyPrint: () => void;
|
|
28
|
-
|
|
29
|
-
|
|
28
|
+
socket: Socket;
|
|
29
|
+
};
|
|
30
|
+
type RealtimeTestClientBuilder = {
|
|
31
|
+
dispose: () => void;
|
|
32
|
+
init: () => RealtimeTestClient;
|
|
30
33
|
};
|
|
31
34
|
type RealtimeTestServer = RealtimeTestTools & {
|
|
35
|
+
dispose: () => void;
|
|
32
36
|
port: number;
|
|
33
37
|
};
|
|
34
38
|
type RealtimeTestAPI = {
|
|
@@ -36,14 +40,14 @@ type RealtimeTestAPI = {
|
|
|
36
40
|
teardown: () => void;
|
|
37
41
|
};
|
|
38
42
|
type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {
|
|
39
|
-
client:
|
|
43
|
+
client: RealtimeTestClientBuilder;
|
|
40
44
|
};
|
|
41
45
|
type RealtimeTestAPI__MultiClient<ClientNames extends string> = RealtimeTestAPI & {
|
|
42
|
-
clients: Record<ClientNames,
|
|
46
|
+
clients: Record<ClientNames, RealtimeTestClientBuilder>;
|
|
43
47
|
};
|
|
44
48
|
declare const setupRealtimeTestServer: (options: TestSetupOptions) => RealtimeTestServer;
|
|
45
|
-
declare const setupRealtimeTestClient: (options: TestSetupOptions__SingleClient, name: string, port: number) =>
|
|
49
|
+
declare const setupRealtimeTestClient: (options: TestSetupOptions__SingleClient, name: string, port: number) => RealtimeTestClientBuilder;
|
|
46
50
|
declare const singleClient: (options: TestSetupOptions__SingleClient) => RealtimeTestAPI__SingleClient;
|
|
47
51
|
declare const multiClient: <ClientNames extends string>(options: TestSetupOptions__MultiClient<ClientNames>) => RealtimeTestAPI__MultiClient<ClientNames>;
|
|
48
52
|
|
|
49
|
-
export { type RealtimeTestAPI, type RealtimeTestAPI__MultiClient, type RealtimeTestAPI__SingleClient, type RealtimeTestClient, type RealtimeTestServer, type RealtimeTestTools, type TestSetupOptions, type TestSetupOptions__MultiClient, type TestSetupOptions__SingleClient, multiClient, setupRealtimeTestClient, setupRealtimeTestServer, singleClient };
|
|
53
|
+
export { type RealtimeTestAPI, type RealtimeTestAPI__MultiClient, type RealtimeTestAPI__SingleClient, type RealtimeTestClient, type RealtimeTestClientBuilder, type RealtimeTestServer, type RealtimeTestTools, type TestSetupOptions, type TestSetupOptions__MultiClient, type TestSetupOptions__SingleClient, multiClient, setupRealtimeTestClient, setupRealtimeTestServer, singleClient };
|
|
@@ -6,19 +6,48 @@ import * as AtomIO from 'atom.io';
|
|
|
6
6
|
import * as Internal from 'atom.io/internal';
|
|
7
7
|
import * as AR from 'atom.io/react';
|
|
8
8
|
import * as RTR from 'atom.io/realtime-react';
|
|
9
|
+
import * as RTS from 'atom.io/realtime-server';
|
|
9
10
|
import * as Happy from 'happy-dom';
|
|
10
11
|
import * as SocketIO from 'socket.io';
|
|
11
12
|
import { io } from 'socket.io-client';
|
|
12
13
|
import { jsx } from 'react/jsx-runtime';
|
|
13
14
|
|
|
14
15
|
var setupRealtimeTestServer = (options) => {
|
|
16
|
+
const silo = new AtomIO.Silo(`SERVER`, Internal.IMPLICIT.STORE);
|
|
15
17
|
const httpServer = http.createServer((_, res) => res.end(`Hello World!`));
|
|
16
18
|
const address = httpServer.listen().address();
|
|
17
19
|
const port = typeof address === `string` ? 80 : address === null ? null : address.port;
|
|
18
20
|
if (port === null)
|
|
19
21
|
throw new Error(`Could not determine port for test server`);
|
|
20
|
-
const server = new SocketIO.Server(httpServer)
|
|
21
|
-
|
|
22
|
+
const server = new SocketIO.Server(httpServer).use((socket, next) => {
|
|
23
|
+
const { token, username } = socket.handshake.auth;
|
|
24
|
+
if (token === `test` && socket.id) {
|
|
25
|
+
const socketRelatedKeysState = Internal.findInStore(
|
|
26
|
+
RTS.usersOfSockets.core.findRelatedKeysState,
|
|
27
|
+
socket.id,
|
|
28
|
+
silo.store
|
|
29
|
+
);
|
|
30
|
+
const clientRelatedKeysState = Internal.findInStore(
|
|
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
|
+
);
|
|
45
|
+
console.log(`${username} connected on ${socket.id}`);
|
|
46
|
+
next();
|
|
47
|
+
} else {
|
|
48
|
+
next(new Error(`Authentication error`));
|
|
49
|
+
}
|
|
50
|
+
});
|
|
22
51
|
server.on(`connection`, (socket) => {
|
|
23
52
|
options.server({ socket, silo });
|
|
24
53
|
});
|
|
@@ -34,32 +63,41 @@ var setupRealtimeTestServer = (options) => {
|
|
|
34
63
|
};
|
|
35
64
|
};
|
|
36
65
|
var setupRealtimeTestClient = (options, name, port) => {
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
66
|
+
const testClient = { dispose: () => {
|
|
67
|
+
} };
|
|
68
|
+
const init = () => {
|
|
69
|
+
const socket = io(`http://localhost:${port}/`, {
|
|
70
|
+
auth: { token: `test`, username: name }
|
|
71
|
+
});
|
|
72
|
+
const silo = new AtomIO.Silo(name, Internal.IMPLICIT.STORE);
|
|
73
|
+
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
74
|
+
if (Array.isArray(value)) {
|
|
75
|
+
silo.store.valueMap.set(key, [...value]);
|
|
76
|
+
}
|
|
45
77
|
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
78
|
+
const { document } = new Happy.Window();
|
|
79
|
+
document.body.innerHTML = `<div id="app"></div>`;
|
|
80
|
+
const renderResult = render(
|
|
81
|
+
/* @__PURE__ */ jsx(AR.StoreProvider, { store: silo.store, children: /* @__PURE__ */ jsx(RTR.RealtimeProvider, { socket, children: /* @__PURE__ */ jsx(options.client, {}) }) }),
|
|
82
|
+
{
|
|
83
|
+
container: document.querySelector(`#app`)
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
const prettyPrint = () => console.log(prettyDOM(renderResult.container));
|
|
87
|
+
const dispose = () => {
|
|
88
|
+
socket.disconnect();
|
|
89
|
+
Internal.clearStore(silo.store);
|
|
90
|
+
};
|
|
91
|
+
testClient.dispose = dispose;
|
|
92
|
+
return {
|
|
93
|
+
name,
|
|
94
|
+
silo,
|
|
95
|
+
socket,
|
|
96
|
+
renderResult,
|
|
97
|
+
prettyPrint
|
|
98
|
+
};
|
|
62
99
|
};
|
|
100
|
+
return Object.assign(testClient, { init });
|
|
63
101
|
};
|
|
64
102
|
var singleClient = (options) => {
|
|
65
103
|
const server = setupRealtimeTestServer(options);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/setup-realtime-test.tsx"],"names":["clients"],"mappings":";;;;;;;;;AAAA,YAAY,UAAU;AAEtB,SAA4B,WAAW,cAAc;AACrD,YAAY,YAAY;AACxB,YAAY,cAAc;AAC1B,YAAY,QAAQ;AACpB,YAAY,SAAS;AACrB,YAAY,WAAW;AAEvB,YAAY,cAAc;AAE1B,SAAS,UAAU;
|
|
1
|
+
{"version":3,"sources":["../src/setup-realtime-test.tsx"],"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"]}
|
|
@@ -5,6 +5,7 @@ import * as AtomIO from "atom.io"
|
|
|
5
5
|
import * as Internal from "atom.io/internal"
|
|
6
6
|
import * as AR from "atom.io/react"
|
|
7
7
|
import * as RTR from "atom.io/realtime-react"
|
|
8
|
+
import * as RTS from "atom.io/realtime-server"
|
|
8
9
|
import * as Happy from "happy-dom"
|
|
9
10
|
import * as React from "react"
|
|
10
11
|
import * as SocketIO from "socket.io"
|
|
@@ -29,15 +30,19 @@ export type TestSetupOptions__MultiClient<ClientNames extends string> =
|
|
|
29
30
|
export type RealtimeTestTools = {
|
|
30
31
|
name: string
|
|
31
32
|
silo: AtomIO.Silo
|
|
32
|
-
dispose: () => void
|
|
33
33
|
}
|
|
34
34
|
export type RealtimeTestClient = RealtimeTestTools & {
|
|
35
35
|
renderResult: RenderResult
|
|
36
36
|
prettyPrint: () => void
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
socket: ClientSocket
|
|
38
|
+
}
|
|
39
|
+
export type RealtimeTestClientBuilder = {
|
|
40
|
+
dispose: () => void
|
|
41
|
+
init: () => RealtimeTestClient
|
|
39
42
|
}
|
|
43
|
+
|
|
40
44
|
export type RealtimeTestServer = RealtimeTestTools & {
|
|
45
|
+
dispose: () => void
|
|
41
46
|
port: number
|
|
42
47
|
}
|
|
43
48
|
|
|
@@ -46,24 +51,52 @@ export type RealtimeTestAPI = {
|
|
|
46
51
|
teardown: () => void
|
|
47
52
|
}
|
|
48
53
|
export type RealtimeTestAPI__SingleClient = RealtimeTestAPI & {
|
|
49
|
-
client:
|
|
54
|
+
client: RealtimeTestClientBuilder
|
|
50
55
|
}
|
|
51
56
|
export type RealtimeTestAPI__MultiClient<ClientNames extends string> =
|
|
52
57
|
RealtimeTestAPI & {
|
|
53
|
-
clients: Record<ClientNames,
|
|
58
|
+
clients: Record<ClientNames, RealtimeTestClientBuilder>
|
|
54
59
|
}
|
|
55
60
|
|
|
56
61
|
export const setupRealtimeTestServer = (
|
|
57
62
|
options: TestSetupOptions,
|
|
58
63
|
): RealtimeTestServer => {
|
|
64
|
+
const silo = new AtomIO.Silo(`SERVER`, Internal.IMPLICIT.STORE)
|
|
65
|
+
|
|
59
66
|
const httpServer = http.createServer((_, res) => res.end(`Hello World!`))
|
|
60
67
|
const address = httpServer.listen().address()
|
|
61
68
|
const port =
|
|
62
69
|
typeof address === `string` ? 80 : address === null ? null : address.port
|
|
63
70
|
if (port === null) throw new Error(`Could not determine port for test server`)
|
|
64
|
-
const server = new SocketIO.Server(httpServer)
|
|
65
|
-
|
|
66
|
-
|
|
71
|
+
const server = new SocketIO.Server(httpServer).use((socket, next) => {
|
|
72
|
+
const { token, username } = socket.handshake.auth
|
|
73
|
+
if (token === `test` && socket.id) {
|
|
74
|
+
const socketRelatedKeysState = Internal.findInStore(
|
|
75
|
+
RTS.usersOfSockets.core.findRelatedKeysState,
|
|
76
|
+
socket.id,
|
|
77
|
+
silo.store,
|
|
78
|
+
)
|
|
79
|
+
const clientRelatedKeysState = Internal.findInStore(
|
|
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
|
+
)
|
|
94
|
+
console.log(`${username} connected on ${socket.id}`)
|
|
95
|
+
next()
|
|
96
|
+
} else {
|
|
97
|
+
next(new Error(`Authentication error`))
|
|
98
|
+
}
|
|
99
|
+
})
|
|
67
100
|
|
|
68
101
|
server.on(`connection`, (socket: SocketIO.Socket) => {
|
|
69
102
|
options.server({ socket, silo })
|
|
@@ -85,42 +118,49 @@ export const setupRealtimeTestClient = (
|
|
|
85
118
|
options: TestSetupOptions__SingleClient,
|
|
86
119
|
name: string,
|
|
87
120
|
port: number,
|
|
88
|
-
):
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
{
|
|
101
|
-
container: document.querySelector(`#app`) as unknown as HTMLElement,
|
|
102
|
-
},
|
|
103
|
-
)
|
|
104
|
-
|
|
105
|
-
const prettyPrint = () => console.log(prettyDOM(renderResult.container))
|
|
106
|
-
|
|
107
|
-
const disconnect = () => socket.disconnect()
|
|
108
|
-
const reconnect = () => socket.connect()
|
|
109
|
-
|
|
110
|
-
const dispose = () => {
|
|
111
|
-
socket.disconnect()
|
|
112
|
-
Internal.clearStore(silo.store)
|
|
113
|
-
}
|
|
121
|
+
): RealtimeTestClientBuilder => {
|
|
122
|
+
const testClient = { dispose: () => {} }
|
|
123
|
+
const init = () => {
|
|
124
|
+
const socket: ClientSocket = io(`http://localhost:${port}/`, {
|
|
125
|
+
auth: { token: `test`, username: name },
|
|
126
|
+
})
|
|
127
|
+
const silo = new AtomIO.Silo(name, Internal.IMPLICIT.STORE)
|
|
128
|
+
for (const [key, value] of silo.store.valueMap.entries()) {
|
|
129
|
+
if (Array.isArray(value)) {
|
|
130
|
+
silo.store.valueMap.set(key, [...value])
|
|
131
|
+
}
|
|
132
|
+
}
|
|
114
133
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
134
|
+
const { document } = new Happy.Window()
|
|
135
|
+
document.body.innerHTML = `<div id="app"></div>`
|
|
136
|
+
const renderResult = render(
|
|
137
|
+
<AR.StoreProvider store={silo.store}>
|
|
138
|
+
<RTR.RealtimeProvider socket={socket}>
|
|
139
|
+
<options.client />
|
|
140
|
+
</RTR.RealtimeProvider>
|
|
141
|
+
</AR.StoreProvider>,
|
|
142
|
+
{
|
|
143
|
+
container: document.querySelector(`#app`) as unknown as HTMLElement,
|
|
144
|
+
},
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
const prettyPrint = () => console.log(prettyDOM(renderResult.container))
|
|
148
|
+
|
|
149
|
+
const dispose = () => {
|
|
150
|
+
socket.disconnect()
|
|
151
|
+
Internal.clearStore(silo.store)
|
|
152
|
+
}
|
|
153
|
+
testClient.dispose = dispose
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
name,
|
|
157
|
+
silo,
|
|
158
|
+
socket,
|
|
159
|
+
renderResult,
|
|
160
|
+
prettyPrint,
|
|
161
|
+
}
|
|
123
162
|
}
|
|
163
|
+
return Object.assign(testClient, { init })
|
|
124
164
|
}
|
|
125
165
|
|
|
126
166
|
export const singleClient = (
|
|
@@ -152,7 +192,7 @@ export const multiClient = <ClientNames extends string>(
|
|
|
152
192
|
)
|
|
153
193
|
return clients
|
|
154
194
|
},
|
|
155
|
-
{} as Record<ClientNames,
|
|
195
|
+
{} as Record<ClientNames, RealtimeTestClientBuilder>,
|
|
156
196
|
)
|
|
157
197
|
|
|
158
198
|
return {
|
package/src/find-state.ts
CHANGED
|
@@ -12,50 +12,42 @@ import type {
|
|
|
12
12
|
WritableSelectorToken,
|
|
13
13
|
WritableToken,
|
|
14
14
|
} from "atom.io"
|
|
15
|
-
import type {
|
|
16
|
-
import { IMPLICIT } from "atom.io/internal"
|
|
15
|
+
import type { Transceiver } from "atom.io/internal"
|
|
16
|
+
import { IMPLICIT, findInStore } from "atom.io/internal"
|
|
17
17
|
import type { Json } from "atom.io/json"
|
|
18
18
|
|
|
19
|
-
export function findInStore(
|
|
20
|
-
token: ReadableFamilyToken<any, any>,
|
|
21
|
-
key: Json.Serializable,
|
|
22
|
-
store: Store,
|
|
23
|
-
): ReadableToken<any> {
|
|
24
|
-
const familyKey = token.key
|
|
25
|
-
const family = store.families.get(familyKey)
|
|
26
|
-
if (family === undefined) {
|
|
27
|
-
throw new Error(`Family ${familyKey} not found`)
|
|
28
|
-
}
|
|
29
|
-
const state = family(key)
|
|
30
|
-
return state
|
|
31
|
-
}
|
|
32
|
-
|
|
33
19
|
export function findState<
|
|
34
20
|
T extends Transceiver<any>,
|
|
35
21
|
J extends Json.Serializable,
|
|
36
22
|
K extends Json.Serializable,
|
|
37
23
|
Key extends K,
|
|
38
24
|
>(token: MutableAtomFamilyToken<T, J, K>, key: Key): MutableAtomToken<T, J>
|
|
25
|
+
|
|
39
26
|
export function findState<T, K extends Json.Serializable, Key extends K>(
|
|
40
27
|
token: RegularAtomFamilyToken<T, K>,
|
|
41
28
|
key: Key,
|
|
42
29
|
): RegularAtomToken<T>
|
|
30
|
+
|
|
43
31
|
export function findState<T, K extends Json.Serializable, Key extends K>(
|
|
44
32
|
token: WritableSelectorFamilyToken<T, K>,
|
|
45
33
|
key: Key,
|
|
46
34
|
): WritableSelectorToken<T>
|
|
35
|
+
|
|
47
36
|
export function findState<T, K extends Json.Serializable, Key extends K>(
|
|
48
37
|
token: ReadonlySelectorFamilyToken<T, K>,
|
|
49
38
|
key: Key,
|
|
50
39
|
): ReadonlySelectorToken<T>
|
|
40
|
+
|
|
51
41
|
export function findState<T, K extends Json.Serializable, Key extends K>(
|
|
52
42
|
token: WritableFamilyToken<T, K>,
|
|
53
43
|
key: Key,
|
|
54
44
|
): WritableToken<T>
|
|
45
|
+
|
|
55
46
|
export function findState<T, K extends Json.Serializable, Key extends K>(
|
|
56
47
|
token: ReadableFamilyToken<T, K>,
|
|
57
48
|
key: Key,
|
|
58
49
|
): ReadableToken<T>
|
|
50
|
+
|
|
59
51
|
export function findState(
|
|
60
52
|
token: ReadableFamilyToken<any, any>,
|
|
61
53
|
key: Json.Serializable,
|
package/src/get-state.ts
CHANGED
|
@@ -2,15 +2,6 @@ import * as Internal from "atom.io/internal"
|
|
|
2
2
|
|
|
3
3
|
import type { ReadableToken } from "."
|
|
4
4
|
|
|
5
|
-
export function getState<T>(
|
|
6
|
-
token
|
|
7
|
-
store: Internal.Store = Internal.IMPLICIT.STORE,
|
|
8
|
-
): T {
|
|
9
|
-
const state =
|
|
10
|
-
Internal.withdraw(token, store) ??
|
|
11
|
-
Internal.withdrawNewFamilyMember(token, store)
|
|
12
|
-
if (state === undefined) {
|
|
13
|
-
throw new Internal.NotFoundError(token, store)
|
|
14
|
-
}
|
|
15
|
-
return Internal.readOrComputeValue(state, store)
|
|
5
|
+
export function getState<T>(token: ReadableToken<T>): T {
|
|
6
|
+
return Internal.getFromStore(token, Internal.IMPLICIT.STORE)
|
|
16
7
|
}
|
package/src/logger.ts
CHANGED
package/src/set-state.ts
CHANGED
|
@@ -5,18 +5,6 @@ import type { WritableToken } from "."
|
|
|
5
5
|
export function setState<T, New extends T>(
|
|
6
6
|
token: WritableToken<T>,
|
|
7
7
|
value: New | ((oldValue: T) => New),
|
|
8
|
-
store: Internal.Store = Internal.IMPLICIT.STORE,
|
|
9
8
|
): void {
|
|
10
|
-
|
|
11
|
-
if (rejection) {
|
|
12
|
-
return
|
|
13
|
-
}
|
|
14
|
-
const state =
|
|
15
|
-
Internal.withdraw(token, store) ??
|
|
16
|
-
Internal.withdrawNewFamilyMember(token, store)
|
|
17
|
-
if (state === undefined) {
|
|
18
|
-
throw new Internal.NotFoundError(token, store)
|
|
19
|
-
}
|
|
20
|
-
Internal.setAtomOrSelector(state, value, store)
|
|
21
|
-
Internal.closeOperation(store)
|
|
9
|
+
Internal.setIntoStore(token, value, Internal.IMPLICIT.STORE)
|
|
22
10
|
}
|
package/src/silo.ts
CHANGED
|
@@ -7,6 +7,8 @@ import {
|
|
|
7
7
|
createStandaloneSelector,
|
|
8
8
|
createTimeline,
|
|
9
9
|
createTransaction,
|
|
10
|
+
getFromStore,
|
|
11
|
+
setIntoStore,
|
|
10
12
|
timeTravel,
|
|
11
13
|
} from "atom.io/internal"
|
|
12
14
|
import type { Json } from "atom.io/json"
|
|
@@ -21,11 +23,13 @@ import type {
|
|
|
21
23
|
RegularAtomFamilyOptions,
|
|
22
24
|
RegularAtomOptions,
|
|
23
25
|
RegularAtomToken,
|
|
26
|
+
getState,
|
|
24
27
|
redo,
|
|
28
|
+
setState,
|
|
25
29
|
timeline,
|
|
26
30
|
undo,
|
|
27
31
|
} from "."
|
|
28
|
-
import {
|
|
32
|
+
import { subscribe } from "."
|
|
29
33
|
import type { atom, atomFamily } from "./atom"
|
|
30
34
|
import type { selector, selectorFamily } from "./selector"
|
|
31
35
|
import type { transaction } from "./transaction"
|
|
@@ -76,8 +80,8 @@ export class Silo {
|
|
|
76
80
|
this.selectorFamily = (options) => createSelectorFamily(options, s) as any
|
|
77
81
|
this.transaction = (options) => createTransaction(options, s)
|
|
78
82
|
this.timeline = (options) => createTimeline(options, s)
|
|
79
|
-
this.getState = (token) =>
|
|
80
|
-
this.setState = (token, newValue) =>
|
|
83
|
+
this.getState = (token) => getFromStore(token, s)
|
|
84
|
+
this.setState = (token, newValue) => setIntoStore(token, newValue, s)
|
|
81
85
|
this.subscribe = (token, handler, key) => subscribe(token, handler, key, s)
|
|
82
86
|
this.undo = (token) => timeTravel(`undo`, token, s)
|
|
83
87
|
this.redo = (token) => timeTravel(`redo`, token, s)
|
package/src/transaction.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { EnvironmentData, Store } from "atom.io/internal"
|
|
2
2
|
import { IMPLICIT, createTransaction, withdraw } from "atom.io/internal"
|
|
3
|
-
import type { Json } from "atom.io/json"
|
|
4
3
|
|
|
5
4
|
import type {
|
|
6
5
|
KeyedStateUpdate,
|
|
@@ -10,10 +9,10 @@ import type {
|
|
|
10
9
|
ƒn,
|
|
11
10
|
} from "."
|
|
12
11
|
|
|
13
|
-
export type TransactionToken<
|
|
12
|
+
export type TransactionToken<F> = {
|
|
14
13
|
key: string
|
|
15
14
|
type: `transaction`
|
|
16
|
-
|
|
15
|
+
__F?: F
|
|
17
16
|
}
|
|
18
17
|
|
|
19
18
|
export type TransactionUpdateContent =
|
|
@@ -23,6 +22,7 @@ export type TransactionUpdateContent =
|
|
|
23
22
|
export type TransactionUpdate<ƒ extends ƒn> = {
|
|
24
23
|
key: string
|
|
25
24
|
id: string
|
|
25
|
+
epoch: number
|
|
26
26
|
updates: TransactionUpdateContent[]
|
|
27
27
|
params: Parameters<ƒ>
|
|
28
28
|
output: ReturnType<ƒ>
|