atom.io 0.40.6 → 0.40.7
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/README.md +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/employ-socket-D6wgByWh.js +12 -0
- package/dist/employ-socket-D6wgByWh.js.map +1 -0
- package/dist/has-role-hv4-hJMw.js +1149 -0
- package/dist/has-role-hv4-hJMw.js.map +1 -0
- package/dist/internal/index.d.ts +248 -248
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +570 -1712
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.d.ts +1 -1
- package/dist/is-fn-DY1wZ-md.js +10 -0
- package/dist/is-fn-DY1wZ-md.js.map +1 -0
- package/dist/main/index.d.ts +33 -33
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js +2 -2
- package/dist/main/index.js.map +1 -1
- package/dist/mutex-store-CSvxY9i3.js +11 -0
- package/dist/mutex-store-CSvxY9i3.js.map +1 -0
- package/dist/react/index.d.ts +5 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.js +7 -7
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.d.ts +7 -15
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js +3 -33
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.d.ts +5 -5
- package/dist/realtime-client/index.d.ts.map +1 -1
- package/dist/realtime-client/index.js +92 -69
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-react/index.d.ts +17 -10
- package/dist/realtime-react/index.d.ts.map +1 -1
- package/dist/realtime-react/index.js +41 -41
- package/dist/realtime-react/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts +60 -53
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/dist/realtime-server/index.js +592 -485
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.d.ts +1 -2
- package/dist/realtime-testing/index.d.ts.map +1 -1
- package/dist/realtime-testing/index.js +25 -18
- package/dist/realtime-testing/index.js.map +1 -1
- package/dist/shared-room-store-COGGKqes.js +32 -0
- package/dist/shared-room-store-COGGKqes.js.map +1 -0
- package/dist/shared-room-store-D2o4ZLjC.d.ts +15 -0
- package/dist/shared-room-store-D2o4ZLjC.d.ts.map +1 -0
- package/dist/web/index.d.ts +3 -3
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +4 -3
- package/dist/web/index.js.map +1 -1
- package/package.json +12 -12
- package/src/internal/atom/create-regular-atom.ts +5 -4
- package/src/internal/atom/dispose-atom.ts +7 -2
- package/src/internal/atom/has-role.ts +3 -3
- package/src/internal/caching.ts +4 -2
- package/src/internal/families/create-readonly-held-selector-family.ts +2 -1
- package/src/internal/families/create-readonly-pure-selector-family.ts +5 -2
- package/src/internal/families/create-regular-atom-family.ts +2 -1
- package/src/internal/families/create-writable-held-selector-family.ts +2 -1
- package/src/internal/families/create-writable-pure-selector-family.ts +5 -2
- package/src/internal/families/dispose-from-store.ts +4 -4
- package/src/internal/families/find-in-store.ts +10 -10
- package/src/internal/families/get-family-of-token.ts +2 -2
- package/src/internal/families/index.ts +1 -0
- package/src/internal/families/mint-in-store.ts +54 -19
- package/src/internal/families/seek-in-store.ts +1 -1
- package/src/internal/get-state/get-fallback.ts +2 -2
- package/src/internal/get-state/get-from-store.ts +5 -5
- package/src/internal/get-state/read-or-compute-value.ts +1 -1
- package/src/internal/get-state/reduce-reference.ts +8 -6
- package/src/internal/index.ts +2 -220
- package/src/internal/molecule.ts +1 -2
- package/src/internal/mutable/create-mutable-atom-family.ts +3 -2
- package/src/internal/mutable/create-mutable-atom.ts +4 -2
- package/src/internal/mutable/get-json-family.ts +1 -1
- package/src/internal/mutable/get-update-family.ts +1 -1
- package/src/internal/mutable/tracker-family.ts +2 -1
- package/src/internal/mutable/tracker.ts +5 -8
- package/src/internal/safe-compute.ts +1 -1
- package/src/internal/selector/create-readonly-held-selector.ts +2 -1
- package/src/internal/selector/create-readonly-pure-selector.ts +2 -1
- package/src/internal/selector/create-writable-held-selector.ts +2 -1
- package/src/internal/selector/create-writable-pure-selector.ts +2 -1
- package/src/internal/selector/dispose-selector.ts +3 -2
- package/src/internal/selector/register-selector.ts +8 -5
- package/src/internal/selector/trace-selector-atoms.ts +2 -1
- package/src/internal/set-state/dispatch-state-update.ts +3 -2
- package/src/internal/set-state/evict-downstream.ts +1 -1
- package/src/internal/set-state/operate-on-store.ts +16 -22
- package/src/internal/set-state/reset-atom-or-selector.ts +5 -3
- package/src/internal/set-state/reset-in-store.ts +5 -5
- package/src/internal/set-state/set-atom-or-selector.ts +2 -2
- package/src/internal/set-state/set-atom.ts +4 -2
- package/src/internal/set-state/set-into-store.ts +21 -39
- package/src/internal/set-state/set-selector.ts +3 -2
- package/src/internal/state-types.ts +228 -0
- package/src/internal/store/deposit.ts +4 -4
- package/src/internal/store/index.ts +0 -1
- package/src/internal/store/store.ts +9 -9
- package/src/internal/store/withdraw.ts +4 -4
- package/src/internal/subscribe/recall-state.ts +1 -1
- package/src/internal/subscribe/subscribe-to-root-atoms.ts +1 -12
- package/src/internal/subscribe/subscribe-to-transaction.ts +3 -2
- package/src/internal/transaction/build-transaction.ts +3 -2
- package/src/internal/transaction/index.ts +1 -23
- package/src/internal/transaction/is-root-store.ts +4 -1
- package/src/internal/transaction/transaction-meta-progress.ts +22 -0
- package/src/main/atom.ts +1 -2
- package/src/main/find-state.ts +5 -5
- package/src/main/get-state.ts +4 -4
- package/src/main/realm.ts +2 -2
- package/src/main/set-state.ts +10 -10
- package/src/react/parse-state-overloads.ts +3 -3
- package/src/react/use-i.ts +6 -4
- package/src/react/use-loadable.ts +4 -10
- package/src/react/use-o.ts +6 -4
- package/src/react-devtools/store.ts +6 -6
- package/src/realtime/index.ts +1 -0
- package/src/realtime/mutex-store.ts +11 -0
- package/src/realtime/realtime-continuity.ts +1 -5
- package/src/realtime-client/pull-atom-family-member.ts +14 -17
- package/src/realtime-client/pull-atom.ts +1 -1
- package/src/realtime-client/pull-mutable-atom-family-member.ts +16 -12
- package/src/realtime-client/pull-selector-family-member.ts +8 -35
- package/src/realtime-client/pull-selector-roots.ts +90 -0
- package/src/realtime-client/pull-selector.ts +2 -27
- package/src/realtime-client/push-state.ts +33 -5
- package/src/realtime-client/realtime-client-stores/client-main-store.ts +2 -5
- package/src/realtime-react/index.ts +2 -1
- package/src/realtime-react/realtime-context.tsx +9 -5
- package/src/realtime-react/use-pull-atom-family-member.ts +2 -3
- package/src/realtime-react/use-pull-mutable-family-member.ts +2 -3
- package/src/realtime-react/use-pull-selector-family-member.ts +5 -6
- package/src/realtime-react/use-push.ts +7 -3
- package/src/realtime-react/use-realtime-service.ts +11 -11
- package/src/realtime-react/use-single-effect.ts +11 -14
- package/src/realtime-server/{realtime-server-stores/server-sync-store.ts → continuity/continuity-store.ts} +1 -1
- package/src/realtime-server/continuity/prepare-to-sync-realtime-continuity.ts +1 -1
- package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +3 -5
- package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
- package/src/realtime-server/employ-socket.ts +14 -0
- package/src/realtime-server/index.ts +2 -20
- package/src/realtime-server/ipc-sockets/child-socket.ts +125 -66
- package/src/realtime-server/ipc-sockets/custom-socket.ts +16 -14
- package/src/realtime-server/ipc-sockets/parent-socket.ts +81 -58
- package/src/realtime-server/realtime-family-provider.ts +78 -29
- package/src/realtime-server/realtime-mutable-family-provider.ts +80 -31
- package/src/realtime-server/realtime-mutable-provider.ts +30 -22
- package/src/realtime-server/realtime-server-stores/index.ts +0 -2
- package/src/realtime-server/realtime-server-stores/server-room-external-store.ts +77 -36
- package/src/realtime-server/realtime-server-stores/server-user-store.ts +12 -1
- package/src/realtime-server/realtime-state-provider.ts +30 -29
- package/src/realtime-server/realtime-state-receiver.ts +62 -16
- package/src/realtime-server/server-config.ts +9 -0
- package/src/realtime-server/socket-interface.ts +14 -0
- package/src/realtime-testing/setup-realtime-test.tsx +56 -23
- package/src/web/index.ts +1 -1
- package/src/web/{persist-sync.ts → storage-sync.ts} +5 -2
- package/src/internal/store/mint-or-counterfeit.ts +0 -108
- package/src/realtime-react/on-mount.ts +0 -5
- package/src/realtime-server/realtime-server-stores/server-room-external-actions.ts +0 -79
|
@@ -1,357 +1,15 @@
|
|
|
1
|
+
import { OWN_OP, operateOnStore } from "../has-role-hv4-hJMw.js";
|
|
2
|
+
import "../is-fn-DY1wZ-md.js";
|
|
3
|
+
import { mutexAtoms } from "../mutex-store-CSvxY9i3.js";
|
|
4
|
+
import { roomIndex, usersInRooms } from "../shared-room-store-COGGKqes.js";
|
|
5
|
+
import { employSocket } from "../employ-socket-D6wgByWh.js";
|
|
1
6
|
import { IMPLICIT, Subject, actUponStore, editRelationsInStore, findInStore, findRelationsInStore, getFromStore, getJsonToken, getUpdateToken, isRootStore, setIntoStore, subscribeToState, subscribeToTransaction } from "atom.io/internal";
|
|
7
|
+
import { atomFamily, join, mutableAtom, selectorFamily, transaction } from "atom.io";
|
|
2
8
|
import { parseJson, stringifyJson } from "atom.io/json";
|
|
3
|
-
import * as AtomIO from "atom.io";
|
|
4
|
-
import { atomFamily, join, mutableAtom, selectorFamily } from "atom.io";
|
|
5
9
|
import { SetRTX } from "atom.io/transceivers/set-rtx";
|
|
6
|
-
import { roomIndex, usersInRooms } from "atom.io/realtime";
|
|
7
10
|
import { spawn } from "node:child_process";
|
|
8
11
|
|
|
9
|
-
//#region src/realtime-server/
|
|
10
|
-
var CustomSocket = class {
|
|
11
|
-
listeners;
|
|
12
|
-
globalListeners;
|
|
13
|
-
handleEvent(event, ...args) {
|
|
14
|
-
for (const listener of this.globalListeners) listener(event, ...args);
|
|
15
|
-
const listeners = this.listeners.get(event);
|
|
16
|
-
if (listeners) for (const listener of listeners) listener(...args);
|
|
17
|
-
}
|
|
18
|
-
id = `no_id_retrieved`;
|
|
19
|
-
emit;
|
|
20
|
-
constructor(emit) {
|
|
21
|
-
this.emit = emit;
|
|
22
|
-
this.listeners = /* @__PURE__ */ new Map();
|
|
23
|
-
this.globalListeners = /* @__PURE__ */ new Set();
|
|
24
|
-
}
|
|
25
|
-
on(event, listener) {
|
|
26
|
-
const listeners = this.listeners.get(event);
|
|
27
|
-
if (listeners) listeners.add(listener);
|
|
28
|
-
else this.listeners.set(event, new Set([listener]));
|
|
29
|
-
return this;
|
|
30
|
-
}
|
|
31
|
-
onAny(listener) {
|
|
32
|
-
this.globalListeners.add(listener);
|
|
33
|
-
return this;
|
|
34
|
-
}
|
|
35
|
-
off(event, listener) {
|
|
36
|
-
const listeners = this.listeners.get(event);
|
|
37
|
-
if (listeners) if (listener) listeners.delete(listener);
|
|
38
|
-
else this.listeners.delete(event);
|
|
39
|
-
return this;
|
|
40
|
-
}
|
|
41
|
-
offAny(listener) {
|
|
42
|
-
this.globalListeners.delete(listener);
|
|
43
|
-
return this;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/realtime-server/ipc-sockets/child-socket.ts
|
|
49
|
-
var ChildSocket = class extends CustomSocket {
|
|
50
|
-
incompleteData = ``;
|
|
51
|
-
unprocessedEvents = [];
|
|
52
|
-
incompleteLog = ``;
|
|
53
|
-
unprocessedLogs = [];
|
|
54
|
-
id = `#####`;
|
|
55
|
-
process;
|
|
56
|
-
key;
|
|
57
|
-
logger;
|
|
58
|
-
handleLog(arg) {
|
|
59
|
-
if (Array.isArray(arg)) {
|
|
60
|
-
const [level, ...rest] = arg;
|
|
61
|
-
switch (level) {
|
|
62
|
-
case `i`:
|
|
63
|
-
this.logger.info(...rest);
|
|
64
|
-
break;
|
|
65
|
-
case `w`:
|
|
66
|
-
this.logger.warn(...rest);
|
|
67
|
-
break;
|
|
68
|
-
case `e`:
|
|
69
|
-
this.logger.error(...rest);
|
|
70
|
-
break;
|
|
71
|
-
default: return;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
constructor(process$1, key, logger) {
|
|
76
|
-
super((event, ...args) => {
|
|
77
|
-
const stringifiedEvent = JSON.stringify([event, ...args]) + `\x03`;
|
|
78
|
-
const errorHandler = (err) => {
|
|
79
|
-
if (err.code === `EPIPE`) console.error(`EPIPE error during write`, this.process.stdin);
|
|
80
|
-
this.process.stdin.removeListener(`error`, errorHandler);
|
|
81
|
-
};
|
|
82
|
-
this.process.stdin.once(`error`, errorHandler);
|
|
83
|
-
this.process.stdin.write(stringifiedEvent);
|
|
84
|
-
return this;
|
|
85
|
-
});
|
|
86
|
-
this.process = process$1;
|
|
87
|
-
this.key = key;
|
|
88
|
-
this.logger = logger ?? {
|
|
89
|
-
info: (...args) => {
|
|
90
|
-
console.info(this.id, this.key, ...args);
|
|
91
|
-
},
|
|
92
|
-
warn: (...args) => {
|
|
93
|
-
console.warn(this.id, this.key, ...args);
|
|
94
|
-
},
|
|
95
|
-
error: (...args) => {
|
|
96
|
-
console.error(this.id, this.key, ...args);
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
this.process.stdout.on(`data`, (buffer) => {
|
|
100
|
-
const chunk = buffer.toString();
|
|
101
|
-
if (chunk === `ALIVE`) return;
|
|
102
|
-
this.unprocessedEvents.push(...chunk.split(`\x03`));
|
|
103
|
-
const newInput = this.unprocessedEvents.shift();
|
|
104
|
-
this.incompleteData += newInput ?? ``;
|
|
105
|
-
try {
|
|
106
|
-
if (this.incompleteData.startsWith(`error`)) console.log(`❗`, this.incompleteData);
|
|
107
|
-
let parsedEvent = parseJson(this.incompleteData);
|
|
108
|
-
this.handleEvent(...parsedEvent);
|
|
109
|
-
while (this.unprocessedEvents.length > 0) {
|
|
110
|
-
const event = this.unprocessedEvents.shift();
|
|
111
|
-
if (event) {
|
|
112
|
-
if (this.unprocessedEvents.length === 0) this.incompleteData = event;
|
|
113
|
-
parsedEvent = parseJson(event);
|
|
114
|
-
this.handleEvent(...parsedEvent);
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
this.incompleteData = ``;
|
|
118
|
-
} catch (error) {
|
|
119
|
-
console.warn(`⚠️----------------⚠️`);
|
|
120
|
-
console.warn(this.incompleteData);
|
|
121
|
-
console.warn(`⚠️----------------⚠️`);
|
|
122
|
-
console.error(error);
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
this.process.stderr.on(`data`, (buf) => {
|
|
126
|
-
const chunk = buf.toString();
|
|
127
|
-
this.unprocessedLogs.push(...chunk.split(`\x03`));
|
|
128
|
-
const newInput = this.unprocessedLogs.shift();
|
|
129
|
-
this.incompleteLog += newInput ?? ``;
|
|
130
|
-
try {
|
|
131
|
-
let parsedLog = parseJson(this.incompleteLog);
|
|
132
|
-
this.handleLog(parsedLog);
|
|
133
|
-
while (this.unprocessedLogs.length > 0) {
|
|
134
|
-
this.incompleteLog = this.unprocessedLogs.shift() ?? ``;
|
|
135
|
-
if (this.incompleteLog) {
|
|
136
|
-
parsedLog = parseJson(this.incompleteLog);
|
|
137
|
-
this.handleLog(parsedLog);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
} catch (error) {
|
|
141
|
-
console.error(`❌❌❌`);
|
|
142
|
-
console.error(this.incompleteLog);
|
|
143
|
-
console.error(error);
|
|
144
|
-
console.error(`❌❌❌️`);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
147
|
-
if (process$1.pid) this.id = process$1.pid.toString();
|
|
148
|
-
}
|
|
149
|
-
};
|
|
150
|
-
|
|
151
|
-
//#endregion
|
|
152
|
-
//#region src/realtime-server/ipc-sockets/parent-socket.ts
|
|
153
|
-
var SubjectSocket = class extends CustomSocket {
|
|
154
|
-
in;
|
|
155
|
-
out;
|
|
156
|
-
id = `no_id_retrieved`;
|
|
157
|
-
disposalFunctions = [];
|
|
158
|
-
constructor(id) {
|
|
159
|
-
super((...args) => {
|
|
160
|
-
this.out.next(args);
|
|
161
|
-
return this;
|
|
162
|
-
});
|
|
163
|
-
this.id = id;
|
|
164
|
-
this.in = new Subject();
|
|
165
|
-
this.out = new Subject();
|
|
166
|
-
this.in.subscribe(`socket`, (event) => {
|
|
167
|
-
this.handleEvent(...event);
|
|
168
|
-
});
|
|
169
|
-
}
|
|
170
|
-
dispose() {
|
|
171
|
-
for (const dispose of this.disposalFunctions) dispose();
|
|
172
|
-
}
|
|
173
|
-
};
|
|
174
|
-
var ParentSocket = class extends CustomSocket {
|
|
175
|
-
incompleteData = ``;
|
|
176
|
-
unprocessedEvents = [];
|
|
177
|
-
relays;
|
|
178
|
-
relayServices;
|
|
179
|
-
process;
|
|
180
|
-
id = `#####`;
|
|
181
|
-
log(...args) {
|
|
182
|
-
this.process.stderr.write(stringifyJson(args.map((arg) => arg instanceof SetRTX ? `{ ${arg.toJSON().members.join(` | `)} }` : arg)) + `\x03`);
|
|
183
|
-
}
|
|
184
|
-
logger = {
|
|
185
|
-
info: (...args) => {
|
|
186
|
-
this.log(`i`, ...args);
|
|
187
|
-
},
|
|
188
|
-
warn: (...args) => {
|
|
189
|
-
this.log(`w`, ...args);
|
|
190
|
-
},
|
|
191
|
-
error: (...args) => {
|
|
192
|
-
this.log(`e`, ...args);
|
|
193
|
-
}
|
|
194
|
-
};
|
|
195
|
-
constructor() {
|
|
196
|
-
super((event, ...args) => {
|
|
197
|
-
const stringifiedEvent = JSON.stringify([event, ...args]);
|
|
198
|
-
this.process.stdout.write(stringifiedEvent + `\x03`);
|
|
199
|
-
return this;
|
|
200
|
-
});
|
|
201
|
-
this.process = process;
|
|
202
|
-
this.process.stdin.resume();
|
|
203
|
-
this.relays = /* @__PURE__ */ new Map();
|
|
204
|
-
this.relayServices = [];
|
|
205
|
-
this.process.stdin.on(`data`, (buffer) => {
|
|
206
|
-
const chunk = buffer.toString();
|
|
207
|
-
this.unprocessedEvents.push(...chunk.split(`\x03`));
|
|
208
|
-
const newInput = this.unprocessedEvents.shift();
|
|
209
|
-
this.incompleteData += newInput ?? ``;
|
|
210
|
-
try {
|
|
211
|
-
const parsedData = parseJson(this.incompleteData);
|
|
212
|
-
this.logger.info(`🎰`, `received`, parsedData);
|
|
213
|
-
this.handleEvent(...parsedData);
|
|
214
|
-
while (this.unprocessedEvents.length > 0) {
|
|
215
|
-
const event = this.unprocessedEvents.shift();
|
|
216
|
-
if (event) {
|
|
217
|
-
if (this.unprocessedEvents.length === 0) this.incompleteData = event;
|
|
218
|
-
const parsedEvent = parseJson(event);
|
|
219
|
-
this.handleEvent(...parsedEvent);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
this.incompleteData = ``;
|
|
223
|
-
} catch (thrown) {
|
|
224
|
-
if (thrown instanceof Error) this.logger.error(`❗`, thrown.message, thrown.cause, thrown.stack);
|
|
225
|
-
}
|
|
226
|
-
});
|
|
227
|
-
this.on(`exit`, () => {
|
|
228
|
-
this.logger.info(`🔥`, this.id, `received "exit"`);
|
|
229
|
-
process.exit(0);
|
|
230
|
-
});
|
|
231
|
-
process.on(`exit`, (code) => {
|
|
232
|
-
this.logger.info(`🔥`, this.id, `exited with code ${code}`);
|
|
233
|
-
});
|
|
234
|
-
process.on(`end`, () => {
|
|
235
|
-
this.logger.info(`🔥`, this.id, `ended`);
|
|
236
|
-
process.exit(0);
|
|
237
|
-
});
|
|
238
|
-
process.on(`SIGTERM`, () => {
|
|
239
|
-
this.logger.error(`🔥`, this.id, `terminated`);
|
|
240
|
-
process.exit(0);
|
|
241
|
-
});
|
|
242
|
-
process.on(`SIGINT`, () => {
|
|
243
|
-
this.logger.error(`🔥`, this.id, `interrupted`);
|
|
244
|
-
process.exit(0);
|
|
245
|
-
});
|
|
246
|
-
if (process.pid) this.id = process.pid?.toString();
|
|
247
|
-
this.on(`user-joins`, (username) => {
|
|
248
|
-
this.logger.info(`👤`, `user`, username, `joined`);
|
|
249
|
-
const relay = new SubjectSocket(`user:${username}`);
|
|
250
|
-
this.relays.set(username, relay);
|
|
251
|
-
this.logger.info(`🔗`, `attaching services:`, `[${[...this.relayServices.keys()].join(`, `)}]`);
|
|
252
|
-
for (const attachServices of this.relayServices) {
|
|
253
|
-
const cleanup = attachServices(relay);
|
|
254
|
-
if (cleanup) relay.disposalFunctions.push(cleanup);
|
|
255
|
-
}
|
|
256
|
-
this.on(`user:${username}`, (...data) => {
|
|
257
|
-
relay.in.next(data);
|
|
258
|
-
});
|
|
259
|
-
relay.out.subscribe(`socket`, (data) => {
|
|
260
|
-
this.emit(...data);
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
this.on(`user-leaves`, (username) => {
|
|
264
|
-
const relay = this.relays.get(username);
|
|
265
|
-
this.off(`relay:${username}`);
|
|
266
|
-
if (relay) {
|
|
267
|
-
relay.dispose();
|
|
268
|
-
this.relays.delete(username);
|
|
269
|
-
}
|
|
270
|
-
});
|
|
271
|
-
process.stdout.write(`ALIVE`);
|
|
272
|
-
}
|
|
273
|
-
relay(attachServices) {
|
|
274
|
-
this.logger.info(`🔗`, `running relay method`);
|
|
275
|
-
this.relayServices.push(attachServices);
|
|
276
|
-
}
|
|
277
|
-
};
|
|
278
|
-
|
|
279
|
-
//#endregion
|
|
280
|
-
//#region src/realtime-server/realtime-server-stores/server-room-external-store.ts
|
|
281
|
-
const roomArgumentsAtoms = atomFamily({
|
|
282
|
-
key: `roomArguments`,
|
|
283
|
-
default: [`echo`, [`Hello World!`]]
|
|
284
|
-
});
|
|
285
|
-
const roomSelectors = selectorFamily({
|
|
286
|
-
key: `room`,
|
|
287
|
-
get: (roomId) => async ({ get, find }) => {
|
|
288
|
-
const argumentsState = find(roomArgumentsAtoms, roomId);
|
|
289
|
-
const args = get(argumentsState);
|
|
290
|
-
const [script, options] = args;
|
|
291
|
-
const child = await new Promise((resolve) => {
|
|
292
|
-
const room = spawn(script, options, { env: process.env });
|
|
293
|
-
const resolver = (data) => {
|
|
294
|
-
if (data.toString() === `ALIVE`) {
|
|
295
|
-
room.stdout.off(`data`, resolver);
|
|
296
|
-
resolve(room);
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
room.stdout.on(`data`, resolver);
|
|
300
|
-
});
|
|
301
|
-
return new ChildSocket(child, roomId);
|
|
302
|
-
}
|
|
303
|
-
});
|
|
304
|
-
|
|
305
|
-
//#endregion
|
|
306
|
-
//#region src/realtime-server/realtime-server-stores/server-room-external-actions.ts
|
|
307
|
-
const createRoomTX = AtomIO.transaction({
|
|
308
|
-
key: `createRoom`,
|
|
309
|
-
do: ({ get, set, find }, roomId, script, options) => {
|
|
310
|
-
const args = options ? [script, options] : [script];
|
|
311
|
-
const roomArgumentsState = find(roomArgumentsAtoms, roomId);
|
|
312
|
-
set(roomArgumentsState, args);
|
|
313
|
-
set(roomIndex, (s) => s.add(roomId));
|
|
314
|
-
const roomState = find(roomSelectors, roomId);
|
|
315
|
-
const room = get(roomState);
|
|
316
|
-
return room;
|
|
317
|
-
}
|
|
318
|
-
});
|
|
319
|
-
const joinRoomTX = AtomIO.transaction({
|
|
320
|
-
key: `joinRoom`,
|
|
321
|
-
do: (tools, roomId, userId, enteredAtEpoch) => {
|
|
322
|
-
const meta = { enteredAtEpoch };
|
|
323
|
-
editRelationsInStore(usersInRooms, (relations) => {
|
|
324
|
-
relations.set({
|
|
325
|
-
room: roomId,
|
|
326
|
-
user: userId
|
|
327
|
-
}, meta);
|
|
328
|
-
}, tools.env().store);
|
|
329
|
-
return meta;
|
|
330
|
-
}
|
|
331
|
-
});
|
|
332
|
-
const leaveRoomTX = AtomIO.transaction({
|
|
333
|
-
key: `leaveRoom`,
|
|
334
|
-
do: (tools, roomId, userId) => {
|
|
335
|
-
editRelationsInStore(usersInRooms, (relations) => {
|
|
336
|
-
relations.delete({
|
|
337
|
-
room: roomId,
|
|
338
|
-
user: userId
|
|
339
|
-
});
|
|
340
|
-
}, tools.env().store);
|
|
341
|
-
}
|
|
342
|
-
});
|
|
343
|
-
const destroyRoomTX = AtomIO.transaction({
|
|
344
|
-
key: `destroyRoom`,
|
|
345
|
-
do: (tools, roomKey) => {
|
|
346
|
-
editRelationsInStore(usersInRooms, (relations) => {
|
|
347
|
-
relations.delete({ room: roomKey });
|
|
348
|
-
}, tools.env().store);
|
|
349
|
-
tools.set(roomIndex, (s) => (s.delete(roomKey), s));
|
|
350
|
-
}
|
|
351
|
-
});
|
|
352
|
-
|
|
353
|
-
//#endregion
|
|
354
|
-
//#region src/realtime-server/realtime-server-stores/server-sync-store.ts
|
|
12
|
+
//#region src/realtime-server/continuity/continuity-store.ts
|
|
355
13
|
function redactTransactionUpdateContent(visibleStateKeys, updates) {
|
|
356
14
|
return updates.map((update) => {
|
|
357
15
|
switch (update.type) {
|
|
@@ -390,28 +48,6 @@ const userUnacknowledgedQueues = atomFamily({
|
|
|
390
48
|
default: () => []
|
|
391
49
|
});
|
|
392
50
|
|
|
393
|
-
//#endregion
|
|
394
|
-
//#region src/realtime-server/realtime-server-stores/server-user-store.ts
|
|
395
|
-
const socketAtoms = atomFamily({
|
|
396
|
-
key: `sockets`,
|
|
397
|
-
default: null
|
|
398
|
-
});
|
|
399
|
-
const socketIndex = mutableAtom({
|
|
400
|
-
key: `socketsIndex`,
|
|
401
|
-
class: SetRTX
|
|
402
|
-
});
|
|
403
|
-
const userIndex = mutableAtom({
|
|
404
|
-
key: `usersIndex`,
|
|
405
|
-
class: SetRTX
|
|
406
|
-
});
|
|
407
|
-
const usersOfSockets = join({
|
|
408
|
-
key: `usersOfSockets`,
|
|
409
|
-
between: [`user`, `socket`],
|
|
410
|
-
cardinality: `1:1`,
|
|
411
|
-
isAType: (s) => s.startsWith(`user::`),
|
|
412
|
-
isBType: (s) => s.startsWith(`socket::`)
|
|
413
|
-
});
|
|
414
|
-
|
|
415
51
|
//#endregion
|
|
416
52
|
//#region src/realtime-server/continuity/prepare-to-send-initial-payload.ts
|
|
417
53
|
function prepareToSendInitialPayload(store, continuity, userKey, socket) {
|
|
@@ -489,8 +125,8 @@ function prepareToTrackClientAcknowledgement(store, continuity, userKey, userUna
|
|
|
489
125
|
function subscribeToContinuityActions(store, continuity, userKey, socket) {
|
|
490
126
|
const continuityKey = continuity.key;
|
|
491
127
|
const unsubscribeFunctions = [];
|
|
492
|
-
for (const transaction of continuity.actions) {
|
|
493
|
-
const unsubscribeFromTransaction = subscribeToTransaction(store, transaction, `sync-continuity:${continuityKey}:${userKey}`, (update) => {
|
|
128
|
+
for (const transaction$1 of continuity.actions) {
|
|
129
|
+
const unsubscribeFromTransaction = subscribeToTransaction(store, transaction$1, `sync-continuity:${continuityKey}:${userKey}`, (update) => {
|
|
494
130
|
try {
|
|
495
131
|
const visibleKeys = continuity.globals.map((atom) => {
|
|
496
132
|
if (atom.type === `atom`) return atom.key;
|
|
@@ -519,7 +155,7 @@ function subscribeToContinuityActions(store, continuity, userKey, socket) {
|
|
|
519
155
|
});
|
|
520
156
|
socket?.emit(`tx-new:${continuityKey}`, redactedUpdate);
|
|
521
157
|
} catch (thrown) {
|
|
522
|
-
if (thrown instanceof Error) store.logger.error(`❌`, `continuity`, continuityKey, `${userKey} failed to send update from transaction ${transaction.key} to ${userKey}`, thrown.message);
|
|
158
|
+
if (thrown instanceof Error) store.logger.error(`❌`, `continuity`, continuityKey, `${userKey} failed to send update from transaction ${transaction$1.key} to ${userKey}`, thrown.message);
|
|
523
159
|
}
|
|
524
160
|
});
|
|
525
161
|
unsubscribeFunctions.push(unsubscribeFromTransaction);
|
|
@@ -605,17 +241,329 @@ function prepareToExposeRealtimeContinuity({ socket: initialSocket, store = IMPL
|
|
|
605
241
|
}
|
|
606
242
|
|
|
607
243
|
//#endregion
|
|
608
|
-
//#region src/realtime-server/
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
244
|
+
//#region src/realtime-server/ipc-sockets/custom-socket.ts
|
|
245
|
+
var CustomSocket = class {
|
|
246
|
+
listeners;
|
|
247
|
+
globalListeners;
|
|
248
|
+
handleEvent(...args) {
|
|
249
|
+
const [event, ...rest] = args;
|
|
250
|
+
for (const listener of this.globalListeners) listener(event, ...rest);
|
|
251
|
+
const listeners = this.listeners.get(event);
|
|
252
|
+
if (listeners) for (const listener of listeners) listener(...rest);
|
|
253
|
+
}
|
|
254
|
+
id = `no_id_retrieved`;
|
|
255
|
+
emit;
|
|
256
|
+
constructor(emit) {
|
|
257
|
+
this.emit = emit;
|
|
258
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
259
|
+
this.globalListeners = /* @__PURE__ */ new Set();
|
|
260
|
+
}
|
|
261
|
+
on(event, listener) {
|
|
262
|
+
const listeners = this.listeners.get(event);
|
|
263
|
+
if (listeners) listeners.add(listener);
|
|
264
|
+
else this.listeners.set(event, new Set([listener]));
|
|
265
|
+
return this;
|
|
266
|
+
}
|
|
267
|
+
onAny(listener) {
|
|
268
|
+
this.globalListeners.add(listener);
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
off(event, listener) {
|
|
272
|
+
const listeners = this.listeners.get(event);
|
|
273
|
+
if (listeners) if (listener) listeners.delete(listener);
|
|
274
|
+
else this.listeners.delete(event);
|
|
275
|
+
return this;
|
|
276
|
+
}
|
|
277
|
+
offAny(listener) {
|
|
278
|
+
this.globalListeners.delete(listener);
|
|
279
|
+
return this;
|
|
280
|
+
}
|
|
281
|
+
};
|
|
282
|
+
|
|
283
|
+
//#endregion
|
|
284
|
+
//#region src/realtime-server/ipc-sockets/child-socket.ts
|
|
285
|
+
var ChildSocket = class extends CustomSocket {
|
|
286
|
+
incompleteData = ``;
|
|
287
|
+
unprocessedEvents = [];
|
|
288
|
+
incompleteLog = ``;
|
|
289
|
+
unprocessedLogs = [];
|
|
290
|
+
id = `#####`;
|
|
291
|
+
proc;
|
|
292
|
+
key;
|
|
293
|
+
logger;
|
|
294
|
+
handleLog(log) {
|
|
295
|
+
if (Array.isArray(log)) {
|
|
296
|
+
const [level, ...rest] = log;
|
|
297
|
+
switch (level) {
|
|
298
|
+
case `i`:
|
|
299
|
+
this.logger.info(...rest);
|
|
300
|
+
break;
|
|
301
|
+
case `w`:
|
|
302
|
+
this.logger.warn(...rest);
|
|
303
|
+
break;
|
|
304
|
+
case `e`:
|
|
305
|
+
this.logger.error(...rest);
|
|
306
|
+
break;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
constructor(proc, key, logger) {
|
|
311
|
+
super((event, ...args) => {
|
|
312
|
+
const stringifiedEvent = JSON.stringify([event, ...args]) + `\x03`;
|
|
313
|
+
const errorHandler = (err) => {
|
|
314
|
+
if (err.code === `EPIPE`) console.error(`EPIPE error during write`, this.proc.stdin);
|
|
315
|
+
this.proc.stdin.removeListener(`error`, errorHandler);
|
|
316
|
+
};
|
|
317
|
+
this.proc.stdin.once(`error`, errorHandler);
|
|
318
|
+
this.proc.stdin.write(stringifiedEvent);
|
|
319
|
+
return this;
|
|
320
|
+
});
|
|
321
|
+
this.proc = proc;
|
|
322
|
+
this.key = key;
|
|
323
|
+
this.logger = logger ?? {
|
|
324
|
+
info: (...args) => {
|
|
325
|
+
console.info(this.id, this.key, ...args);
|
|
326
|
+
},
|
|
327
|
+
warn: (...args) => {
|
|
328
|
+
console.warn(this.id, this.key, ...args);
|
|
329
|
+
},
|
|
330
|
+
error: (...args) => {
|
|
331
|
+
console.error(this.id, this.key, ...args);
|
|
332
|
+
}
|
|
333
|
+
};
|
|
334
|
+
this.proc.stdout.on(`data`, (buffer) => {
|
|
335
|
+
const chunk = buffer.toString();
|
|
336
|
+
if (chunk === `ALIVE`) {
|
|
337
|
+
this.logger.info(chunk);
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
const pieces = chunk.split(`\x03`);
|
|
341
|
+
const initialMaybeWellFormed = pieces[0];
|
|
342
|
+
pieces[0] = this.incompleteData + initialMaybeWellFormed;
|
|
343
|
+
let idx = 0;
|
|
344
|
+
for (const piece of pieces) {
|
|
345
|
+
if (piece === ``) continue;
|
|
346
|
+
try {
|
|
347
|
+
const jsonPiece = parseJson(piece);
|
|
348
|
+
this.handleEvent(...jsonPiece);
|
|
349
|
+
this.incompleteData = ``;
|
|
350
|
+
} catch (thrown0) {
|
|
351
|
+
if (thrown0 instanceof Error) console.error([
|
|
352
|
+
`❌ Malformed data received from child process`,
|
|
353
|
+
``,
|
|
354
|
+
piece,
|
|
355
|
+
``,
|
|
356
|
+
thrown0.message
|
|
357
|
+
].join(`\n❌\t`));
|
|
358
|
+
try {
|
|
359
|
+
if (idx === 0) {
|
|
360
|
+
this.incompleteData = piece;
|
|
361
|
+
const maybeActualJsonPiece = parseJson(initialMaybeWellFormed);
|
|
362
|
+
this.handleEvent(...maybeActualJsonPiece);
|
|
363
|
+
this.incompleteData = ``;
|
|
364
|
+
} else this.incompleteData += piece;
|
|
365
|
+
} catch (thrown1) {
|
|
366
|
+
if (thrown1 instanceof Error) console.error([
|
|
367
|
+
`❌ Malformed data received from child process`,
|
|
368
|
+
``,
|
|
369
|
+
initialMaybeWellFormed,
|
|
370
|
+
``,
|
|
371
|
+
thrown1.message
|
|
372
|
+
].join(`\n❌\t`));
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
++idx;
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
this.proc.stderr.on(`data`, (buffer) => {
|
|
379
|
+
const chunk = buffer.toString();
|
|
380
|
+
const pieces = chunk.split(`\x03`);
|
|
381
|
+
const initialMaybeWellFormed = pieces[0];
|
|
382
|
+
pieces[0] = this.incompleteData + initialMaybeWellFormed;
|
|
383
|
+
let idx = 0;
|
|
384
|
+
for (const piece of pieces) {
|
|
385
|
+
if (piece === ``) continue;
|
|
386
|
+
try {
|
|
387
|
+
const jsonPiece = parseJson(piece);
|
|
388
|
+
this.handleLog(jsonPiece);
|
|
389
|
+
this.incompleteData = ``;
|
|
390
|
+
} catch (thrown0) {
|
|
391
|
+
if (thrown0 instanceof Error) console.error([
|
|
392
|
+
`❌ Malformed log received from child process`,
|
|
393
|
+
``,
|
|
394
|
+
piece,
|
|
395
|
+
``,
|
|
396
|
+
thrown0.message
|
|
397
|
+
].join(`\n❌\t`));
|
|
398
|
+
try {
|
|
399
|
+
if (idx === 0) {
|
|
400
|
+
this.incompleteData = piece;
|
|
401
|
+
const maybeActualJsonPiece = parseJson(initialMaybeWellFormed);
|
|
402
|
+
this.handleLog(maybeActualJsonPiece);
|
|
403
|
+
this.incompleteData = ``;
|
|
404
|
+
} else this.incompleteData += piece;
|
|
405
|
+
} catch (thrown1) {
|
|
406
|
+
if (thrown1 instanceof Error) console.error([
|
|
407
|
+
`❌ Malformed log received from child process...`,
|
|
408
|
+
``,
|
|
409
|
+
initialMaybeWellFormed,
|
|
410
|
+
``,
|
|
411
|
+
thrown1.message
|
|
412
|
+
].join(`\n❌\t`));
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
++idx;
|
|
416
|
+
}
|
|
417
|
+
});
|
|
418
|
+
if (proc.pid) this.id = proc.pid.toString();
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
|
|
422
|
+
//#endregion
|
|
423
|
+
//#region src/realtime-server/ipc-sockets/parent-socket.ts
|
|
424
|
+
var SubjectSocket = class extends CustomSocket {
|
|
425
|
+
in;
|
|
426
|
+
out;
|
|
427
|
+
id = `no_id_retrieved`;
|
|
428
|
+
disposalFunctions = [];
|
|
429
|
+
constructor(id) {
|
|
430
|
+
super((...args) => {
|
|
431
|
+
this.out.next(args);
|
|
432
|
+
return this;
|
|
433
|
+
});
|
|
434
|
+
this.id = id;
|
|
435
|
+
this.in = new Subject();
|
|
436
|
+
this.out = new Subject();
|
|
437
|
+
this.in.subscribe(`socket`, (event) => {
|
|
438
|
+
this.handleEvent(...event);
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
dispose() {
|
|
442
|
+
for (const dispose of this.disposalFunctions) dispose();
|
|
443
|
+
}
|
|
444
|
+
};
|
|
445
|
+
var ParentSocket = class extends CustomSocket {
|
|
446
|
+
incompleteData = ``;
|
|
447
|
+
unprocessedEvents = [];
|
|
448
|
+
relays;
|
|
449
|
+
relayServices;
|
|
450
|
+
proc;
|
|
451
|
+
id = `#####`;
|
|
452
|
+
log(...args) {
|
|
453
|
+
this.proc.stderr.write(stringifyJson(args.map((arg) => arg instanceof SetRTX ? `{ ${arg.toJSON().members.join(` | `)} }` : arg)) + `\x03`);
|
|
454
|
+
}
|
|
455
|
+
logger = {
|
|
456
|
+
info: (...args) => {
|
|
457
|
+
this.log(`i`, ...args);
|
|
458
|
+
},
|
|
459
|
+
warn: (...args) => {
|
|
460
|
+
this.log(`w`, ...args);
|
|
461
|
+
},
|
|
462
|
+
error: (...args) => {
|
|
463
|
+
this.log(`e`, ...args);
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
constructor(proc) {
|
|
467
|
+
super((event, ...args) => {
|
|
468
|
+
const stringifiedEvent = JSON.stringify([event, ...args]);
|
|
469
|
+
this.proc.stdout.write(stringifiedEvent + `\x03`);
|
|
470
|
+
return this;
|
|
471
|
+
});
|
|
472
|
+
this.proc = proc;
|
|
473
|
+
this.proc.stdin.resume();
|
|
474
|
+
this.relays = /* @__PURE__ */ new Map();
|
|
475
|
+
this.relayServices = [];
|
|
476
|
+
this.proc.stdin.on(`data`, (buffer) => {
|
|
477
|
+
const chunk = buffer.toString();
|
|
478
|
+
const pieces = chunk.split(`\x03`);
|
|
479
|
+
const initialMaybeWellFormed = pieces[0];
|
|
480
|
+
pieces[0] = this.incompleteData + initialMaybeWellFormed;
|
|
481
|
+
let idx = 0;
|
|
482
|
+
for (const piece of pieces) {
|
|
483
|
+
if (piece === ``) continue;
|
|
484
|
+
try {
|
|
485
|
+
const jsonPiece = parseJson(piece);
|
|
486
|
+
this.logger.info(`🎰`, `received`, jsonPiece);
|
|
487
|
+
this.handleEvent(...jsonPiece);
|
|
488
|
+
this.incompleteData = ``;
|
|
489
|
+
} catch (thrown0) {
|
|
490
|
+
if (thrown0 instanceof Error) this.logger.error([
|
|
491
|
+
`received malformed data from parent process:`,
|
|
492
|
+
``,
|
|
493
|
+
piece,
|
|
494
|
+
``,
|
|
495
|
+
thrown0.message
|
|
496
|
+
].join(`\n❌\t`));
|
|
497
|
+
try {
|
|
498
|
+
if (idx === 0) {
|
|
499
|
+
this.incompleteData = piece;
|
|
500
|
+
const maybeActualJsonPiece = parseJson(initialMaybeWellFormed);
|
|
501
|
+
this.logger.info(`🎰`, `received`, maybeActualJsonPiece);
|
|
502
|
+
this.handleEvent(...maybeActualJsonPiece);
|
|
503
|
+
this.incompleteData = ``;
|
|
504
|
+
} else this.incompleteData += piece;
|
|
505
|
+
} catch (thrown1) {
|
|
506
|
+
if (thrown1 instanceof Error) this.logger.error([
|
|
507
|
+
`received malformed data from parent process:`,
|
|
508
|
+
``,
|
|
509
|
+
initialMaybeWellFormed,
|
|
510
|
+
``,
|
|
511
|
+
thrown1.message
|
|
512
|
+
].join(`\n❌\t`));
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
++idx;
|
|
516
|
+
}
|
|
517
|
+
});
|
|
518
|
+
this.on(`exit`, () => {
|
|
519
|
+
this.logger.info(`🔥`, this.id, `received "exit"`);
|
|
520
|
+
this.proc.exit(0);
|
|
521
|
+
});
|
|
522
|
+
if (this.proc.pid) this.id = this.proc.pid?.toString();
|
|
523
|
+
this.on(`user-joins`, (username) => {
|
|
524
|
+
this.logger.info(`👤`, `user`, username, `joined`);
|
|
525
|
+
const relay = new SubjectSocket(`user:${username}`);
|
|
526
|
+
this.relays.set(username, relay);
|
|
527
|
+
this.logger.info(`🔗`, `attaching services:`, `[${[...this.relayServices.keys()].join(`, `)}]`);
|
|
528
|
+
for (const attachServices of this.relayServices) {
|
|
529
|
+
const cleanup = attachServices(relay);
|
|
530
|
+
if (cleanup) relay.disposalFunctions.push(cleanup);
|
|
531
|
+
}
|
|
532
|
+
this.on(`user:${username}`, (...data) => {
|
|
533
|
+
relay.in.next(data);
|
|
534
|
+
});
|
|
535
|
+
relay.out.subscribe(`socket`, (data) => {
|
|
536
|
+
this.emit(...data);
|
|
537
|
+
});
|
|
538
|
+
});
|
|
539
|
+
this.on(`user-leaves`, (username) => {
|
|
540
|
+
const relay = this.relays.get(username);
|
|
541
|
+
this.off(`relay:${username}`);
|
|
542
|
+
if (relay) {
|
|
543
|
+
relay.dispose();
|
|
544
|
+
this.relays.delete(username);
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
this.proc.stdout.write(`ALIVE`);
|
|
548
|
+
}
|
|
549
|
+
relay(attachServices) {
|
|
550
|
+
this.logger.info(`🔗`, `running relay method`);
|
|
551
|
+
this.relayServices.push(attachServices);
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
|
|
555
|
+
//#endregion
|
|
556
|
+
//#region src/realtime-server/realtime-action-receiver.ts
|
|
557
|
+
function realtimeActionReceiver({ socket, store = IMPLICIT.STORE }) {
|
|
558
|
+
return function actionReceiver(tx) {
|
|
559
|
+
const fillTransactionRequest = (update) => {
|
|
560
|
+
const performanceKey = `tx-run:${tx.key}:${update.id}`;
|
|
561
|
+
const performanceKeyStart = `${performanceKey}:start`;
|
|
562
|
+
const performanceKeyEnd = `${performanceKey}:end`;
|
|
563
|
+
performance.mark(performanceKeyStart);
|
|
564
|
+
actUponStore(store, tx, update.id)(...update.params);
|
|
565
|
+
performance.mark(performanceKeyEnd);
|
|
566
|
+
const metric = performance.measure(performanceKey, performanceKeyStart, performanceKeyEnd);
|
|
619
567
|
store?.logger.info(`🚀`, `transaction`, tx.key, update.id, metric.duration);
|
|
620
568
|
};
|
|
621
569
|
socket.on(`tx-run:${tx.key}`, fillTransactionRequest);
|
|
@@ -629,35 +577,62 @@ function realtimeActionReceiver({ socket, store = IMPLICIT.STORE }) {
|
|
|
629
577
|
//#region src/realtime-server/realtime-family-provider.ts
|
|
630
578
|
function realtimeAtomFamilyProvider({ socket, store = IMPLICIT.STORE }) {
|
|
631
579
|
return function familyProvider(family, index) {
|
|
632
|
-
const
|
|
580
|
+
const coreSubscriptions = /* @__PURE__ */ new Set();
|
|
581
|
+
const clearCoreSubscriptions = () => {
|
|
582
|
+
for (const unsub of coreSubscriptions) unsub();
|
|
583
|
+
coreSubscriptions.clear();
|
|
584
|
+
};
|
|
585
|
+
const familyMemberSubscriptionsWanted = /* @__PURE__ */ new Set();
|
|
586
|
+
const familyMemberSubscriptions = /* @__PURE__ */ new Map();
|
|
587
|
+
const clearFamilySubscriptions = () => {
|
|
588
|
+
for (const unsub of familyMemberSubscriptions.values()) unsub();
|
|
589
|
+
familyMemberSubscriptions.clear();
|
|
590
|
+
};
|
|
633
591
|
const fillUnsubRequest = (key) => {
|
|
634
|
-
|
|
635
|
-
|
|
592
|
+
const unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`);
|
|
593
|
+
if (unsubUnsub) {
|
|
594
|
+
unsubUnsub();
|
|
595
|
+
familyMemberSubscriptions.delete(`${key}:unsub`);
|
|
596
|
+
}
|
|
597
|
+
const unsub = familyMemberSubscriptions.get(key);
|
|
636
598
|
if (unsub) {
|
|
637
599
|
unsub();
|
|
638
|
-
|
|
600
|
+
familyMemberSubscriptions.delete(key);
|
|
639
601
|
}
|
|
640
602
|
};
|
|
641
|
-
const
|
|
642
|
-
const
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
603
|
+
const exposeFamilyMembers = (subKey) => {
|
|
604
|
+
const token = findInStore(store, family, subKey);
|
|
605
|
+
getFromStore(store, token);
|
|
606
|
+
socket.emit(`serve:${token.key}`, getFromStore(store, token));
|
|
607
|
+
familyMemberSubscriptions.set(token.key, subscribeToState(store, token, `expose-family:${family.key}:${socket.id}`, ({ newValue }) => {
|
|
608
|
+
socket.emit(`serve:${token.key}`, newValue);
|
|
609
|
+
}));
|
|
610
|
+
familyMemberSubscriptions.set(`${token.key}:unsub`, employSocket(socket, `unsub:${token.key}`, () => {
|
|
611
|
+
fillUnsubRequest(token.key);
|
|
612
|
+
}));
|
|
613
|
+
};
|
|
614
|
+
const isAvailable = (exposedSubKeys, subKey) => {
|
|
615
|
+
for (const exposedSubKey of exposedSubKeys) if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) return true;
|
|
616
|
+
return false;
|
|
655
617
|
};
|
|
656
|
-
|
|
618
|
+
const start = () => {
|
|
619
|
+
coreSubscriptions.add(employSocket(socket, `sub:${family.key}`, (subKey) => {
|
|
620
|
+
const exposedSubKeys = getFromStore(store, index);
|
|
621
|
+
const shouldExpose = isAvailable(exposedSubKeys, subKey);
|
|
622
|
+
if (shouldExpose) exposeFamilyMembers(subKey);
|
|
623
|
+
else {
|
|
624
|
+
familyMemberSubscriptionsWanted.add(stringifyJson(subKey));
|
|
625
|
+
socket.emit(`unavailable:${family.key}`, subKey);
|
|
626
|
+
}
|
|
627
|
+
}));
|
|
628
|
+
coreSubscriptions.add(subscribeToState(store, index, `expose-family:${family.key}:${socket.id}`, ({ newValue: newExposedSubKeys }) => {
|
|
629
|
+
for (const subKey of newExposedSubKeys) if (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) exposeFamilyMembers(subKey);
|
|
630
|
+
}));
|
|
631
|
+
};
|
|
632
|
+
start();
|
|
657
633
|
return () => {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
unsubCallbacksByKey.clear();
|
|
634
|
+
clearCoreSubscriptions();
|
|
635
|
+
clearFamilySubscriptions();
|
|
661
636
|
};
|
|
662
637
|
};
|
|
663
638
|
}
|
|
@@ -666,38 +641,64 @@ function realtimeAtomFamilyProvider({ socket, store = IMPLICIT.STORE }) {
|
|
|
666
641
|
//#region src/realtime-server/realtime-mutable-family-provider.ts
|
|
667
642
|
function realtimeMutableFamilyProvider({ socket, store = IMPLICIT.STORE }) {
|
|
668
643
|
return function mutableFamilyProvider(family, index) {
|
|
669
|
-
const
|
|
644
|
+
const coreSubscriptions = /* @__PURE__ */ new Set();
|
|
645
|
+
const clearCoreSubscriptions = () => {
|
|
646
|
+
for (const unsub of coreSubscriptions) unsub();
|
|
647
|
+
coreSubscriptions.clear();
|
|
648
|
+
};
|
|
649
|
+
const familyMemberSubscriptionsWanted = /* @__PURE__ */ new Set();
|
|
650
|
+
const familyMemberSubscriptions = /* @__PURE__ */ new Map();
|
|
651
|
+
const clearFamilySubscriptions = () => {
|
|
652
|
+
for (const unsub of familyMemberSubscriptions.values()) unsub();
|
|
653
|
+
familyMemberSubscriptions.clear();
|
|
654
|
+
};
|
|
670
655
|
const fillUnsubRequest = (key) => {
|
|
671
|
-
|
|
672
|
-
|
|
656
|
+
const unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`);
|
|
657
|
+
if (unsubUnsub) {
|
|
658
|
+
unsubUnsub();
|
|
659
|
+
familyMemberSubscriptions.delete(`${key}:unsub`);
|
|
660
|
+
}
|
|
661
|
+
const unsub = familyMemberSubscriptions.get(key);
|
|
673
662
|
if (unsub) {
|
|
674
663
|
unsub();
|
|
675
|
-
|
|
664
|
+
familyMemberSubscriptions.delete(key);
|
|
676
665
|
}
|
|
677
666
|
};
|
|
678
|
-
const
|
|
679
|
-
const
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
socket.emit(`
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
}
|
|
667
|
+
const exposeFamilyMembers = (subKey) => {
|
|
668
|
+
const token = findInStore(store, family, subKey);
|
|
669
|
+
getFromStore(store, token);
|
|
670
|
+
const jsonToken = getJsonToken(store, token);
|
|
671
|
+
const updateToken = getUpdateToken(token);
|
|
672
|
+
socket.emit(`init:${token.key}`, getFromStore(store, jsonToken));
|
|
673
|
+
familyMemberSubscriptions.set(token.key, subscribeToState(store, updateToken, `expose-family:${family.key}:${socket.id}`, ({ newValue }) => {
|
|
674
|
+
socket.emit(`next:${token.key}`, newValue);
|
|
675
|
+
}));
|
|
676
|
+
familyMemberSubscriptions.set(`${token.key}:unsub`, employSocket(socket, `unsub:${token.key}`, () => {
|
|
677
|
+
fillUnsubRequest(token.key);
|
|
678
|
+
}));
|
|
679
|
+
};
|
|
680
|
+
const isAvailable = (exposedSubKeys, subKey) => {
|
|
681
|
+
for (const exposedSubKey of exposedSubKeys) if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) return true;
|
|
682
|
+
return false;
|
|
695
683
|
};
|
|
696
|
-
|
|
684
|
+
const start = () => {
|
|
685
|
+
coreSubscriptions.add(employSocket(socket, `sub:${family.key}`, (subKey) => {
|
|
686
|
+
const exposedSubKeys = getFromStore(store, index);
|
|
687
|
+
const shouldExpose = isAvailable(exposedSubKeys, subKey);
|
|
688
|
+
if (shouldExpose) exposeFamilyMembers(subKey);
|
|
689
|
+
else {
|
|
690
|
+
familyMemberSubscriptionsWanted.add(stringifyJson(subKey));
|
|
691
|
+
socket.emit(`unavailable:${family.key}`, subKey);
|
|
692
|
+
}
|
|
693
|
+
}));
|
|
694
|
+
coreSubscriptions.add(subscribeToState(store, index, `expose-family:${family.key}:${socket.id}`, ({ newValue: newExposedSubKeys }) => {
|
|
695
|
+
for (const subKey of newExposedSubKeys) if (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) exposeFamilyMembers(subKey);
|
|
696
|
+
}));
|
|
697
|
+
};
|
|
698
|
+
start();
|
|
697
699
|
return () => {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
unsubCallbacksByKey.clear();
|
|
700
|
+
clearCoreSubscriptions();
|
|
701
|
+
clearFamilySubscriptions();
|
|
701
702
|
};
|
|
702
703
|
};
|
|
703
704
|
}
|
|
@@ -706,82 +707,188 @@ function realtimeMutableFamilyProvider({ socket, store = IMPLICIT.STORE }) {
|
|
|
706
707
|
//#region src/realtime-server/realtime-mutable-provider.ts
|
|
707
708
|
function realtimeMutableProvider({ socket, store = IMPLICIT.STORE }) {
|
|
708
709
|
return function mutableProvider(token) {
|
|
709
|
-
|
|
710
|
+
const subscriptions = /* @__PURE__ */ new Set();
|
|
711
|
+
const clearSubscriptions = () => {
|
|
712
|
+
for (const unsub of subscriptions) unsub();
|
|
713
|
+
subscriptions.clear();
|
|
714
|
+
};
|
|
710
715
|
const jsonToken = getJsonToken(store, token);
|
|
711
716
|
const trackerToken = getUpdateToken(token);
|
|
712
|
-
const
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
socket.on(`sub:${token.key}`, fillSubRequest);
|
|
725
|
-
return () => {
|
|
726
|
-
socket.off(`sub:${token.key}`, fillSubRequest);
|
|
727
|
-
unsubscribeFromStateUpdates?.();
|
|
717
|
+
const start = () => {
|
|
718
|
+
subscriptions.add(employSocket(socket, `sub:${token.key}`, () => {
|
|
719
|
+
clearSubscriptions();
|
|
720
|
+
socket.emit(`init:${token.key}`, getFromStore(store, jsonToken));
|
|
721
|
+
subscriptions.add(subscribeToState(store, trackerToken, `expose-single:${socket.id}`, ({ newValue }) => {
|
|
722
|
+
socket.emit(`next:${token.key}`, newValue);
|
|
723
|
+
}));
|
|
724
|
+
subscriptions.add(employSocket(socket, `unsub:${token.key}`, () => {
|
|
725
|
+
clearSubscriptions();
|
|
726
|
+
start();
|
|
727
|
+
}));
|
|
728
|
+
}));
|
|
728
729
|
};
|
|
730
|
+
start();
|
|
731
|
+
return clearSubscriptions;
|
|
729
732
|
};
|
|
730
733
|
}
|
|
731
734
|
|
|
735
|
+
//#endregion
|
|
736
|
+
//#region src/realtime-server/realtime-server-stores/server-room-external-store.ts
|
|
737
|
+
const ROOMS = /* @__PURE__ */ new Map();
|
|
738
|
+
async function spawnRoom(roomId, script, options) {
|
|
739
|
+
const child = await new Promise((resolve) => {
|
|
740
|
+
const room = spawn(script, options, { env: process.env });
|
|
741
|
+
const resolver = (data) => {
|
|
742
|
+
if (data.toString() === `ALIVE`) {
|
|
743
|
+
room.stdout.off(`data`, resolver);
|
|
744
|
+
resolve(room);
|
|
745
|
+
}
|
|
746
|
+
};
|
|
747
|
+
room.stdout.on(`data`, resolver);
|
|
748
|
+
});
|
|
749
|
+
ROOMS.set(roomId, new ChildSocket(child, roomId));
|
|
750
|
+
return new ChildSocket(child, roomId);
|
|
751
|
+
}
|
|
752
|
+
const joinRoomTX = transaction({
|
|
753
|
+
key: `joinRoom`,
|
|
754
|
+
do: (tools, roomId, userId, enteredAtEpoch) => {
|
|
755
|
+
const meta = { enteredAtEpoch };
|
|
756
|
+
editRelationsInStore(usersInRooms, (relations) => {
|
|
757
|
+
relations.set({
|
|
758
|
+
room: roomId,
|
|
759
|
+
user: userId
|
|
760
|
+
}, meta);
|
|
761
|
+
}, tools.env().store);
|
|
762
|
+
return meta;
|
|
763
|
+
}
|
|
764
|
+
});
|
|
765
|
+
const leaveRoomTX = transaction({
|
|
766
|
+
key: `leaveRoom`,
|
|
767
|
+
do: ({ env }, roomId, userId) => {
|
|
768
|
+
editRelationsInStore(usersInRooms, (relations) => {
|
|
769
|
+
relations.delete({
|
|
770
|
+
room: roomId,
|
|
771
|
+
user: userId
|
|
772
|
+
});
|
|
773
|
+
}, env().store);
|
|
774
|
+
}
|
|
775
|
+
});
|
|
776
|
+
const destroyRoomTX = transaction({
|
|
777
|
+
key: `destroyRoom`,
|
|
778
|
+
do: ({ set, env }, roomId) => {
|
|
779
|
+
editRelationsInStore(usersInRooms, (relations) => {
|
|
780
|
+
relations.delete({ room: roomId });
|
|
781
|
+
}, env().store);
|
|
782
|
+
set(roomIndex, (s) => (s.delete(roomId), s));
|
|
783
|
+
const room = ROOMS.get(roomId);
|
|
784
|
+
if (room) {
|
|
785
|
+
room.emit(`exit`);
|
|
786
|
+
ROOMS.delete(roomId);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
//#endregion
|
|
792
|
+
//#region src/realtime-server/realtime-server-stores/server-user-store.ts
|
|
793
|
+
const socketAtoms = atomFamily({
|
|
794
|
+
key: `sockets`,
|
|
795
|
+
default: null
|
|
796
|
+
});
|
|
797
|
+
const socketIndex = mutableAtom({
|
|
798
|
+
key: `socketsIndex`,
|
|
799
|
+
class: SetRTX
|
|
800
|
+
});
|
|
801
|
+
const userIndex = mutableAtom({
|
|
802
|
+
key: `usersIndex`,
|
|
803
|
+
class: SetRTX
|
|
804
|
+
});
|
|
805
|
+
const usersOfSockets = join({
|
|
806
|
+
key: `usersOfSockets`,
|
|
807
|
+
between: [`user`, `socket`],
|
|
808
|
+
cardinality: `1:1`,
|
|
809
|
+
isAType: (s) => s.startsWith(`user::`),
|
|
810
|
+
isBType: (s) => s.startsWith(`socket::`)
|
|
811
|
+
});
|
|
812
|
+
const userMutualSituationalAwarenessIndexes = selectorFamily({
|
|
813
|
+
key: `userMutualSituationalAwarenessIndexes`,
|
|
814
|
+
get: (userId) => () => {
|
|
815
|
+
return [userId];
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
|
|
732
819
|
//#endregion
|
|
733
820
|
//#region src/realtime-server/realtime-state-provider.ts
|
|
734
821
|
function realtimeStateProvider({ socket, store = IMPLICIT.STORE }) {
|
|
735
822
|
return function stateProvider(token) {
|
|
736
|
-
|
|
737
|
-
const
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
socket.emit(`serve:${token.key}`, newValue);
|
|
741
|
-
});
|
|
742
|
-
const fillUnsubRequest = () => {
|
|
743
|
-
socket.off(`unsub:${token.key}`, fillUnsubRequest);
|
|
744
|
-
if (unsubscribeFromStateUpdates) {
|
|
745
|
-
unsubscribeFromStateUpdates();
|
|
746
|
-
unsubscribeFromStateUpdates = void 0;
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
socket.on(`unsub:${token.key}`, fillUnsubRequest);
|
|
823
|
+
const subscriptions = /* @__PURE__ */ new Set();
|
|
824
|
+
const clearSubscriptions = () => {
|
|
825
|
+
for (const unsub of subscriptions) unsub();
|
|
826
|
+
subscriptions.clear();
|
|
750
827
|
};
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
828
|
+
const start = () => {
|
|
829
|
+
subscriptions.add(employSocket(socket, `sub:${token.key}`, () => {
|
|
830
|
+
clearSubscriptions();
|
|
831
|
+
socket.emit(`serve:${token.key}`, getFromStore(store, token));
|
|
832
|
+
subscriptions.add(subscribeToState(store, token, `expose-single:${socket.id}`, ({ newValue }) => {
|
|
833
|
+
socket.emit(`serve:${token.key}`, newValue);
|
|
834
|
+
}));
|
|
835
|
+
subscriptions.add(employSocket(socket, `unsub:${token.key}`, () => {
|
|
836
|
+
clearSubscriptions();
|
|
837
|
+
start();
|
|
838
|
+
}));
|
|
839
|
+
}));
|
|
758
840
|
};
|
|
841
|
+
start();
|
|
842
|
+
return clearSubscriptions;
|
|
759
843
|
};
|
|
760
844
|
}
|
|
761
845
|
|
|
762
846
|
//#endregion
|
|
763
847
|
//#region src/realtime-server/realtime-state-receiver.ts
|
|
764
848
|
function realtimeStateReceiver({ socket, store = IMPLICIT.STORE }) {
|
|
765
|
-
return function stateReceiver(
|
|
766
|
-
const
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
socket.off(`unclaim:${token.key}`, fillPubUnclaim);
|
|
849
|
+
return function stateReceiver(clientToken, serverToken = clientToken) {
|
|
850
|
+
const mutexAtom = findInStore(store, mutexAtoms, serverToken.key);
|
|
851
|
+
const subscriptions = /* @__PURE__ */ new Set();
|
|
852
|
+
const clearSubscriptions = () => {
|
|
853
|
+
for (const unsub of subscriptions) unsub();
|
|
854
|
+
subscriptions.clear();
|
|
772
855
|
};
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
856
|
+
const permitPublish = () => {
|
|
857
|
+
clearSubscriptions();
|
|
858
|
+
subscriptions.add(employSocket(socket, `pub:${clientToken.key}`, (newValue) => {
|
|
859
|
+
setIntoStore(store, serverToken, newValue);
|
|
860
|
+
}));
|
|
861
|
+
subscriptions.add(employSocket(socket, `unclaim:${clientToken.key}`, () => {
|
|
862
|
+
setIntoStore(store, mutexAtom, false);
|
|
863
|
+
clearSubscriptions();
|
|
864
|
+
start();
|
|
865
|
+
}));
|
|
776
866
|
};
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
867
|
+
const start = () => {
|
|
868
|
+
subscriptions.add(employSocket(socket, `claim:${clientToken.key}`, () => {
|
|
869
|
+
if (getFromStore(store, mutexAtom)) {
|
|
870
|
+
clearSubscriptions();
|
|
871
|
+
subscriptions.add(subscribeToState(store, mutexAtom, socket.id, () => {
|
|
872
|
+
const currentValue = getFromStore(store, mutexAtom);
|
|
873
|
+
if (currentValue === false) {
|
|
874
|
+
operateOnStore(OWN_OP, store, mutexAtom, true);
|
|
875
|
+
permitPublish();
|
|
876
|
+
socket.emit(`claim-result:${clientToken.key}`, true);
|
|
877
|
+
}
|
|
878
|
+
}));
|
|
879
|
+
socket.emit(`claim-result:${clientToken.key}`, false);
|
|
880
|
+
return;
|
|
881
|
+
}
|
|
882
|
+
setIntoStore(store, mutexAtom, true);
|
|
883
|
+
permitPublish();
|
|
884
|
+
socket.emit(`claim-result:${clientToken.key}`, true);
|
|
885
|
+
}));
|
|
781
886
|
};
|
|
887
|
+
start();
|
|
888
|
+
return clearSubscriptions;
|
|
782
889
|
};
|
|
783
890
|
}
|
|
784
891
|
|
|
785
892
|
//#endregion
|
|
786
|
-
export { ChildSocket, CustomSocket, ParentSocket,
|
|
893
|
+
export { ChildSocket, CustomSocket, ParentSocket, ROOMS, SubjectSocket, destroyRoomTX, joinRoomTX, leaveRoomTX, prepareToExposeRealtimeContinuity, realtimeActionReceiver, realtimeAtomFamilyProvider, realtimeMutableFamilyProvider, realtimeMutableProvider, realtimeStateProvider, realtimeStateReceiver, socketAtoms, socketIndex, spawnRoom, userIndex, userMutualSituationalAwarenessIndexes, usersOfSockets };
|
|
787
894
|
//# sourceMappingURL=index.js.map
|