atom.io 0.40.6 → 0.40.8

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