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.
Files changed (163) hide show
  1. package/README.md +1 -1
  2. package/dist/data/index.d.ts +1 -1
  3. package/dist/employ-socket-D6wgByWh.js +12 -0
  4. package/dist/employ-socket-D6wgByWh.js.map +1 -0
  5. package/dist/has-role-hv4-hJMw.js +1149 -0
  6. package/dist/has-role-hv4-hJMw.js.map +1 -0
  7. package/dist/internal/index.d.ts +248 -248
  8. package/dist/internal/index.d.ts.map +1 -1
  9. package/dist/internal/index.js +570 -1712
  10. package/dist/internal/index.js.map +1 -1
  11. package/dist/introspection/index.d.ts +1 -1
  12. package/dist/is-fn-DY1wZ-md.js +10 -0
  13. package/dist/is-fn-DY1wZ-md.js.map +1 -0
  14. package/dist/main/index.d.ts +33 -33
  15. package/dist/main/index.d.ts.map +1 -1
  16. package/dist/main/index.js +2 -2
  17. package/dist/main/index.js.map +1 -1
  18. package/dist/mutex-store-CSvxY9i3.js +11 -0
  19. package/dist/mutex-store-CSvxY9i3.js.map +1 -0
  20. package/dist/react/index.d.ts +5 -5
  21. package/dist/react/index.d.ts.map +1 -1
  22. package/dist/react/index.js.map +1 -1
  23. package/dist/react-devtools/index.js +7 -7
  24. package/dist/react-devtools/index.js.map +1 -1
  25. package/dist/realtime/index.d.ts +7 -15
  26. package/dist/realtime/index.d.ts.map +1 -1
  27. package/dist/realtime/index.js +3 -33
  28. package/dist/realtime/index.js.map +1 -1
  29. package/dist/realtime-client/index.d.ts +5 -5
  30. package/dist/realtime-client/index.d.ts.map +1 -1
  31. package/dist/realtime-client/index.js +92 -69
  32. package/dist/realtime-client/index.js.map +1 -1
  33. package/dist/realtime-react/index.d.ts +17 -10
  34. package/dist/realtime-react/index.d.ts.map +1 -1
  35. package/dist/realtime-react/index.js +41 -41
  36. package/dist/realtime-react/index.js.map +1 -1
  37. package/dist/realtime-server/index.d.ts +60 -53
  38. package/dist/realtime-server/index.d.ts.map +1 -1
  39. package/dist/realtime-server/index.js +592 -485
  40. package/dist/realtime-server/index.js.map +1 -1
  41. package/dist/realtime-testing/index.d.ts +1 -2
  42. package/dist/realtime-testing/index.d.ts.map +1 -1
  43. package/dist/realtime-testing/index.js +25 -18
  44. package/dist/realtime-testing/index.js.map +1 -1
  45. package/dist/shared-room-store-COGGKqes.js +32 -0
  46. package/dist/shared-room-store-COGGKqes.js.map +1 -0
  47. package/dist/shared-room-store-D2o4ZLjC.d.ts +15 -0
  48. package/dist/shared-room-store-D2o4ZLjC.d.ts.map +1 -0
  49. package/dist/web/index.d.ts +3 -3
  50. package/dist/web/index.d.ts.map +1 -1
  51. package/dist/web/index.js +4 -3
  52. package/dist/web/index.js.map +1 -1
  53. package/package.json +12 -12
  54. package/src/internal/atom/create-regular-atom.ts +5 -4
  55. package/src/internal/atom/dispose-atom.ts +7 -2
  56. package/src/internal/atom/has-role.ts +3 -3
  57. package/src/internal/caching.ts +4 -2
  58. package/src/internal/families/create-readonly-held-selector-family.ts +2 -1
  59. package/src/internal/families/create-readonly-pure-selector-family.ts +5 -2
  60. package/src/internal/families/create-regular-atom-family.ts +2 -1
  61. package/src/internal/families/create-writable-held-selector-family.ts +2 -1
  62. package/src/internal/families/create-writable-pure-selector-family.ts +5 -2
  63. package/src/internal/families/dispose-from-store.ts +4 -4
  64. package/src/internal/families/find-in-store.ts +10 -10
  65. package/src/internal/families/get-family-of-token.ts +2 -2
  66. package/src/internal/families/index.ts +1 -0
  67. package/src/internal/families/mint-in-store.ts +54 -19
  68. package/src/internal/families/seek-in-store.ts +1 -1
  69. package/src/internal/get-state/get-fallback.ts +2 -2
  70. package/src/internal/get-state/get-from-store.ts +5 -5
  71. package/src/internal/get-state/read-or-compute-value.ts +1 -1
  72. package/src/internal/get-state/reduce-reference.ts +8 -6
  73. package/src/internal/index.ts +2 -220
  74. package/src/internal/molecule.ts +1 -2
  75. package/src/internal/mutable/create-mutable-atom-family.ts +3 -2
  76. package/src/internal/mutable/create-mutable-atom.ts +4 -2
  77. package/src/internal/mutable/get-json-family.ts +1 -1
  78. package/src/internal/mutable/get-update-family.ts +1 -1
  79. package/src/internal/mutable/tracker-family.ts +2 -1
  80. package/src/internal/mutable/tracker.ts +5 -8
  81. package/src/internal/safe-compute.ts +1 -1
  82. package/src/internal/selector/create-readonly-held-selector.ts +2 -1
  83. package/src/internal/selector/create-readonly-pure-selector.ts +2 -1
  84. package/src/internal/selector/create-writable-held-selector.ts +2 -1
  85. package/src/internal/selector/create-writable-pure-selector.ts +2 -1
  86. package/src/internal/selector/dispose-selector.ts +3 -2
  87. package/src/internal/selector/register-selector.ts +8 -5
  88. package/src/internal/selector/trace-selector-atoms.ts +2 -1
  89. package/src/internal/set-state/dispatch-state-update.ts +3 -2
  90. package/src/internal/set-state/evict-downstream.ts +1 -1
  91. package/src/internal/set-state/operate-on-store.ts +16 -22
  92. package/src/internal/set-state/reset-atom-or-selector.ts +5 -3
  93. package/src/internal/set-state/reset-in-store.ts +5 -5
  94. package/src/internal/set-state/set-atom-or-selector.ts +2 -2
  95. package/src/internal/set-state/set-atom.ts +4 -2
  96. package/src/internal/set-state/set-into-store.ts +21 -39
  97. package/src/internal/set-state/set-selector.ts +3 -2
  98. package/src/internal/state-types.ts +228 -0
  99. package/src/internal/store/deposit.ts +4 -4
  100. package/src/internal/store/index.ts +0 -1
  101. package/src/internal/store/store.ts +9 -9
  102. package/src/internal/store/withdraw.ts +4 -4
  103. package/src/internal/subscribe/recall-state.ts +1 -1
  104. package/src/internal/subscribe/subscribe-to-root-atoms.ts +1 -12
  105. package/src/internal/subscribe/subscribe-to-transaction.ts +3 -2
  106. package/src/internal/transaction/build-transaction.ts +3 -2
  107. package/src/internal/transaction/index.ts +1 -23
  108. package/src/internal/transaction/is-root-store.ts +4 -1
  109. package/src/internal/transaction/transaction-meta-progress.ts +22 -0
  110. package/src/main/atom.ts +1 -2
  111. package/src/main/find-state.ts +5 -5
  112. package/src/main/get-state.ts +4 -4
  113. package/src/main/realm.ts +2 -2
  114. package/src/main/set-state.ts +10 -10
  115. package/src/react/parse-state-overloads.ts +3 -3
  116. package/src/react/use-i.ts +6 -4
  117. package/src/react/use-loadable.ts +4 -10
  118. package/src/react/use-o.ts +6 -4
  119. package/src/react-devtools/store.ts +6 -6
  120. package/src/realtime/index.ts +1 -0
  121. package/src/realtime/mutex-store.ts +11 -0
  122. package/src/realtime/realtime-continuity.ts +1 -5
  123. package/src/realtime-client/pull-atom-family-member.ts +14 -17
  124. package/src/realtime-client/pull-atom.ts +1 -1
  125. package/src/realtime-client/pull-mutable-atom-family-member.ts +16 -12
  126. package/src/realtime-client/pull-selector-family-member.ts +8 -35
  127. package/src/realtime-client/pull-selector-roots.ts +90 -0
  128. package/src/realtime-client/pull-selector.ts +2 -27
  129. package/src/realtime-client/push-state.ts +33 -5
  130. package/src/realtime-client/realtime-client-stores/client-main-store.ts +2 -5
  131. package/src/realtime-react/index.ts +2 -1
  132. package/src/realtime-react/realtime-context.tsx +9 -5
  133. package/src/realtime-react/use-pull-atom-family-member.ts +2 -3
  134. package/src/realtime-react/use-pull-mutable-family-member.ts +2 -3
  135. package/src/realtime-react/use-pull-selector-family-member.ts +5 -6
  136. package/src/realtime-react/use-push.ts +7 -3
  137. package/src/realtime-react/use-realtime-service.ts +11 -11
  138. package/src/realtime-react/use-single-effect.ts +11 -14
  139. package/src/realtime-server/{realtime-server-stores/server-sync-store.ts → continuity/continuity-store.ts} +1 -1
  140. package/src/realtime-server/continuity/prepare-to-sync-realtime-continuity.ts +1 -1
  141. package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +3 -5
  142. package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
  143. package/src/realtime-server/employ-socket.ts +14 -0
  144. package/src/realtime-server/index.ts +2 -20
  145. package/src/realtime-server/ipc-sockets/child-socket.ts +125 -66
  146. package/src/realtime-server/ipc-sockets/custom-socket.ts +16 -14
  147. package/src/realtime-server/ipc-sockets/parent-socket.ts +81 -58
  148. package/src/realtime-server/realtime-family-provider.ts +78 -29
  149. package/src/realtime-server/realtime-mutable-family-provider.ts +80 -31
  150. package/src/realtime-server/realtime-mutable-provider.ts +30 -22
  151. package/src/realtime-server/realtime-server-stores/index.ts +0 -2
  152. package/src/realtime-server/realtime-server-stores/server-room-external-store.ts +77 -36
  153. package/src/realtime-server/realtime-server-stores/server-user-store.ts +12 -1
  154. package/src/realtime-server/realtime-state-provider.ts +30 -29
  155. package/src/realtime-server/realtime-state-receiver.ts +62 -16
  156. package/src/realtime-server/server-config.ts +9 -0
  157. package/src/realtime-server/socket-interface.ts +14 -0
  158. package/src/realtime-testing/setup-realtime-test.tsx +56 -23
  159. package/src/web/index.ts +1 -1
  160. package/src/web/{persist-sync.ts → storage-sync.ts} +5 -2
  161. package/src/internal/store/mint-or-counterfeit.ts +0 -108
  162. package/src/realtime-react/on-mount.ts +0 -5
  163. 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/ipc-sockets/custom-socket.ts
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/realtime-action-receiver.ts
609
- function realtimeActionReceiver({ socket, store = IMPLICIT.STORE }) {
610
- return function actionReceiver(tx) {
611
- const fillTransactionRequest = (update) => {
612
- const performanceKey = `tx-run:${tx.key}:${update.id}`;
613
- const performanceKeyStart = `${performanceKey}:start`;
614
- const performanceKeyEnd = `${performanceKey}:end`;
615
- performance.mark(performanceKeyStart);
616
- actUponStore(store, tx, update.id)(...update.params);
617
- performance.mark(performanceKeyEnd);
618
- const metric = performance.measure(performanceKey, performanceKeyStart, performanceKeyEnd);
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 unsubCallbacksByKey = /* @__PURE__ */ new Map();
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
- socket.off(`unsub:${key}`, fillUnsubRequest);
635
- const unsub = unsubCallbacksByKey.get(key);
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
- unsubCallbacksByKey.delete(key);
600
+ familyMemberSubscriptions.delete(key);
639
601
  }
640
602
  };
641
- const fillSubRequest = (subKey) => {
642
- const exposedSubKeys = getFromStore(store, index);
643
- for (const exposedSubKey of exposedSubKeys) if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {
644
- const token = findInStore(store, family, subKey);
645
- socket.emit(`serve:${token.key}`, getFromStore(store, token));
646
- const unsubscribe = subscribeToState(store, token, `expose-family:${family.key}:${socket.id}`, ({ newValue }) => {
647
- socket.emit(`serve:${token.key}`, newValue);
648
- });
649
- unsubCallbacksByKey.set(token.key, unsubscribe);
650
- socket.on(`unsub:${token.key}`, () => {
651
- fillUnsubRequest(token.key);
652
- });
653
- break;
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
- socket.on(`sub:${family.key}`, fillSubRequest);
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
- socket.off(`sub:${family.key}`, fillSubRequest);
659
- for (const [, unsub] of unsubCallbacksByKey) unsub();
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 unsubCallbacksByKey = /* @__PURE__ */ new Map();
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
- socket.off(`unsub:${key}`, fillUnsubRequest);
672
- const unsub = unsubCallbacksByKey.get(key);
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
- unsubCallbacksByKey.delete(key);
664
+ familyMemberSubscriptions.delete(key);
676
665
  }
677
666
  };
678
- const fillSubRequest = (subKey) => {
679
- const exposedSubKeys = getFromStore(store, index);
680
- for (const exposedSubKey of exposedSubKeys) if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {
681
- const token = findInStore(store, family, subKey);
682
- getFromStore(store, token);
683
- const jsonToken = getJsonToken(store, token);
684
- const updateToken = getUpdateToken(token);
685
- socket.emit(`init:${token.key}`, getFromStore(store, jsonToken));
686
- const unsubscribe = subscribeToState(store, updateToken, `expose-family:${family.key}:${socket.id}`, ({ newValue }) => {
687
- socket.emit(`next:${token.key}`, newValue);
688
- });
689
- unsubCallbacksByKey.set(token.key, unsubscribe);
690
- socket.on(`unsub:${token.key}`, () => {
691
- fillUnsubRequest(token.key);
692
- });
693
- break;
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
- socket.on(`sub:${family.key}`, fillSubRequest);
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
- socket.off(`sub:${family.key}`, fillSubRequest);
699
- for (const [, unsub] of unsubCallbacksByKey) unsub();
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
- let unsubscribeFromStateUpdates = null;
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 fillUnsubRequest = () => {
713
- socket.off(`unsub:${token.key}`, fillUnsubRequest);
714
- unsubscribeFromStateUpdates?.();
715
- unsubscribeFromStateUpdates = null;
716
- };
717
- const fillSubRequest = () => {
718
- socket.emit(`init:${token.key}`, getFromStore(store, jsonToken));
719
- unsubscribeFromStateUpdates = subscribeToState(store, trackerToken, `expose-single:${socket.id}`, ({ newValue }) => {
720
- socket.emit(`next:${token.key}`, newValue);
721
- });
722
- socket.on(`unsub:${token.key}`, fillUnsubRequest);
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
- let unsubscribeFromStateUpdates;
737
- const fillSubRequest = () => {
738
- socket.emit(`serve:${token.key}`, getFromStore(store, token));
739
- unsubscribeFromStateUpdates = subscribeToState(store, token, `expose-single:${socket.id}`, ({ newValue }) => {
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
- socket.on(`sub:${token.key}`, fillSubRequest);
752
- return () => {
753
- socket.off(`sub:${token.key}`, fillSubRequest);
754
- if (unsubscribeFromStateUpdates) {
755
- unsubscribeFromStateUpdates();
756
- unsubscribeFromStateUpdates = void 0;
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(token) {
766
- const publish = (newValue) => {
767
- setIntoStore(store, token, newValue);
768
- };
769
- const fillPubUnclaim = () => {
770
- socket.off(`pub:${token.key}`, publish);
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 fillPubClaim = () => {
774
- socket.on(`pub:${token.key}`, publish);
775
- socket.on(`unclaim:${token.key}`, fillPubUnclaim);
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
- socket.on(`claim:${token.key}`, fillPubClaim);
778
- return () => {
779
- socket.off(`claim:${token.key}`, fillPubClaim);
780
- socket.off(`pub:${token.key}`, publish);
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, SubjectSocket, createRoomTX, destroyRoomTX, joinRoomTX, leaveRoomTX, prepareToExposeRealtimeContinuity, realtimeActionReceiver, realtimeAtomFamilyProvider, realtimeMutableFamilyProvider, realtimeMutableProvider, realtimeStateProvider, realtimeStateReceiver, redactTransactionUpdateContent, redactorAtoms, roomArgumentsAtoms, roomSelectors, socketAtoms, socketIndex, userIndex, userUnacknowledgedQueues, usersOfSockets };
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