atom.io 0.18.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/dist/{chunk-OEVFAUPE.js → chunk-IZHOMSXA.js} +53 -11
  2. package/dist/chunk-IZHOMSXA.js.map +1 -0
  3. package/dist/chunk-JDUNWJFB.js +18 -0
  4. package/dist/chunk-JDUNWJFB.js.map +1 -0
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.ts +5 -1
  7. package/dist/index.js.map +1 -1
  8. package/internal/dist/index.cjs +64 -34
  9. package/internal/dist/index.cjs.map +1 -1
  10. package/internal/dist/index.d.ts +1 -1
  11. package/internal/dist/index.js +64 -34
  12. package/internal/dist/index.js.map +1 -1
  13. package/internal/src/atom/delete-atom.ts +7 -6
  14. package/internal/src/caching.ts +6 -6
  15. package/internal/src/ingest-updates/ingest-atom-update.ts +6 -2
  16. package/internal/src/set-state/copy-mutable-if-needed.ts +5 -0
  17. package/internal/src/set-state/emit-update.ts +25 -11
  18. package/internal/src/set-state/set-atom.ts +4 -3
  19. package/internal/src/transaction/apply-transaction.ts +0 -1
  20. package/internal/src/transaction/set-epoch-number.ts +0 -1
  21. package/json/src/index.ts +3 -3
  22. package/package.json +241 -241
  23. package/react-devtools/dist/index.cjs.map +1 -1
  24. package/react-devtools/dist/index.js +1 -15
  25. package/react-devtools/dist/index.js.map +1 -1
  26. package/react-devtools/src/StateEditor.tsx +6 -6
  27. package/react-devtools/src/StateIndex.tsx +2 -2
  28. package/react-devtools/src/Updates.tsx +1 -1
  29. package/react-devtools/src/index.ts +3 -3
  30. package/realtime/dist/index.cjs +50 -2
  31. package/realtime/dist/index.cjs.map +1 -1
  32. package/realtime/dist/index.d.ts +110 -3
  33. package/realtime/dist/index.js +47 -4
  34. package/realtime/dist/index.js.map +1 -1
  35. package/realtime/src/index.ts +1 -0
  36. package/realtime/src/realtime-continuity.ts +14 -4
  37. package/realtime/src/shared-room-store.ts +48 -0
  38. package/realtime-client/dist/index.cjs +113 -200
  39. package/realtime-client/dist/index.cjs.map +1 -1
  40. package/realtime-client/dist/index.d.ts +2 -5
  41. package/realtime-client/dist/index.js +17 -161
  42. package/realtime-client/dist/index.js.map +1 -1
  43. package/realtime-client/src/index.ts +0 -2
  44. package/realtime-client/src/pull-mutable-atom-family-member.ts +5 -5
  45. package/realtime-client/src/realtime-client-stores/client-main-store.ts +10 -0
  46. package/realtime-client/src/sync-continuity.ts +56 -9
  47. package/realtime-react/dist/index.cjs +51 -26
  48. package/realtime-react/dist/index.cjs.map +1 -1
  49. package/realtime-react/dist/index.d.ts +2 -6
  50. package/realtime-react/dist/index.js +2 -17
  51. package/realtime-react/dist/index.js.map +1 -1
  52. package/realtime-react/src/index.ts +0 -2
  53. package/realtime-server/dist/index.cjs +399 -327
  54. package/realtime-server/dist/index.cjs.map +1 -1
  55. package/realtime-server/dist/index.d.ts +55 -60
  56. package/realtime-server/dist/index.js +394 -319
  57. package/realtime-server/dist/index.js.map +1 -1
  58. package/realtime-server/src/index.ts +2 -4
  59. package/realtime-server/src/ipc-sockets/child-socket.ts +135 -0
  60. package/realtime-server/src/ipc-sockets/custom-socket.ts +90 -0
  61. package/realtime-server/src/ipc-sockets/index.ts +3 -0
  62. package/realtime-server/src/ipc-sockets/parent-socket.ts +185 -0
  63. package/realtime-server/src/realtime-continuity-synchronizer.ts +225 -96
  64. package/realtime-server/src/realtime-server-stores/index.ts +2 -1
  65. package/realtime-server/src/realtime-server-stores/realtime-continuity-store.ts +50 -31
  66. package/realtime-server/src/realtime-server-stores/server-room-external-actions.ts +64 -0
  67. package/realtime-server/src/realtime-server-stores/server-room-external-store.ts +42 -0
  68. package/realtime-server/src/realtime-server-stores/server-sync-store.ts +49 -26
  69. package/realtime-testing/dist/index.cjs +8 -6
  70. package/realtime-testing/dist/index.cjs.map +1 -1
  71. package/realtime-testing/dist/index.d.ts +1 -0
  72. package/realtime-testing/dist/index.js +7 -6
  73. package/realtime-testing/dist/index.js.map +1 -1
  74. package/realtime-testing/src/setup-realtime-test.tsx +8 -6
  75. package/src/logger.ts +5 -1
  76. package/dist/chunk-OEVFAUPE.js.map +0 -1
  77. package/realtime-client/src/sync-server-action.ts +0 -168
  78. package/realtime-client/src/sync-state.ts +0 -19
  79. package/realtime-react/src/use-sync-server-action.ts +0 -17
  80. package/realtime-react/src/use-sync.ts +0 -17
  81. package/realtime-server/src/ipc-socket.ts +0 -230
  82. package/realtime-server/src/realtime-action-synchronizer.ts +0 -164
  83. package/realtime-server/src/realtime-server-stores/server-room-store.ts +0 -97
@@ -1,13 +1,12 @@
1
1
  'use strict';
2
2
 
3
- var internal = require('atom.io/internal');
4
3
  var json = require('atom.io/json');
4
+ var internal = require('atom.io/internal');
5
+ var setRtx = require('atom.io/transceivers/set-rtx');
5
6
  var AtomIO = require('atom.io');
6
7
  var realtime = require('atom.io/realtime');
7
- var realtimeServer = require('atom.io/realtime-server');
8
8
  var child_process = require('child_process');
9
9
  var data = require('atom.io/data');
10
- var setRtx = require('atom.io/transceivers/set-rtx');
11
10
 
12
11
  function _interopNamespace(e) {
13
12
  if (e && e.__esModule) return e;
@@ -48,6 +47,8 @@ var __spreadValues = (a, b) => {
48
47
  return a;
49
48
  };
50
49
  var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
50
+
51
+ // realtime-server/src/ipc-sockets/custom-socket.ts
51
52
  var CustomSocket = class {
52
53
  constructor(emit) {
53
54
  this.emit = emit;
@@ -82,7 +83,11 @@ var CustomSocket = class {
82
83
  off(event, listener) {
83
84
  const listeners = this.listeners.get(event);
84
85
  if (listeners) {
85
- listeners.delete(listener);
86
+ if (listener) {
87
+ listeners.delete(listener);
88
+ } else {
89
+ this.listeners.delete(event);
90
+ }
86
91
  }
87
92
  return this;
88
93
  }
@@ -91,28 +96,109 @@ var CustomSocket = class {
91
96
  return this;
92
97
  }
93
98
  };
99
+
100
+ // realtime-server/src/ipc-sockets/child-socket.ts
94
101
  var ChildSocket = class extends CustomSocket {
95
- constructor(process2) {
102
+ constructor(process2, key, logger = console) {
96
103
  super((event, ...args) => {
97
- const stringifiedEvent = JSON.stringify([event, ...args]) + `
98
- `;
104
+ const stringifiedEvent = JSON.stringify([event, ...args]) + ``;
105
+ const errorHandler = (err) => {
106
+ if (err.code === `EPIPE`) {
107
+ console.error(`EPIPE error during write`, this.process.stdin);
108
+ }
109
+ this.process.stdin.removeListener(`error`, errorHandler);
110
+ };
111
+ this.process.stdin.once(`error`, errorHandler);
99
112
  this.process.stdin.write(stringifiedEvent);
100
113
  return this;
101
114
  });
102
- this.id = `no_id_retrieved`;
115
+ this.process = process2;
116
+ this.key = key;
117
+ this.logger = logger;
118
+ this.incompleteData = ``;
119
+ this.unprocessedEvents = [];
120
+ this.incompleteLog = ``;
121
+ this.unprocessedLogs = [];
122
+ this.id = `#####`;
103
123
  this.process = process2;
104
124
  this.process.stdout.on(
105
125
  `data`,
106
126
  (buffer) => {
107
- const stringifiedEvent = buffer.toString();
108
- const parsedEvent = json.parseJson(stringifiedEvent);
109
- this.handleEvent(...parsedEvent);
127
+ const chunk = buffer.toString();
128
+ if (chunk === `\u2728`) {
129
+ return;
130
+ }
131
+ this.unprocessedEvents.push(...chunk.split(``));
132
+ const newInput = this.unprocessedEvents.shift();
133
+ this.incompleteData += newInput || ``;
134
+ try {
135
+ if (this.incompleteData.startsWith(`error`)) {
136
+ console.log(`\u2757`, this.incompleteData);
137
+ }
138
+ const parsedEvent = json.parseJson(this.incompleteData);
139
+ this.handleEvent(...parsedEvent);
140
+ while (this.unprocessedEvents.length > 0) {
141
+ const event = this.unprocessedEvents.shift();
142
+ if (event) {
143
+ if (this.unprocessedEvents.length === 0) {
144
+ this.incompleteData = event;
145
+ }
146
+ const parsedEvent2 = json.parseJson(event);
147
+ this.handleEvent(...parsedEvent2);
148
+ }
149
+ }
150
+ this.incompleteData = ``;
151
+ } catch (error) {
152
+ console.warn(`\u26A0\uFE0F----------------\u26A0\uFE0F`);
153
+ console.warn(this.incompleteData);
154
+ console.warn(`\u26A0\uFE0F----------------\u26A0\uFE0F`);
155
+ console.error(error);
156
+ }
110
157
  }
111
158
  );
159
+ this.process.stderr.on(`data`, (buf) => {
160
+ var _a;
161
+ const chunk = buf.toString();
162
+ this.unprocessedLogs.push(...chunk.split(``));
163
+ const newInput = this.unprocessedLogs.shift();
164
+ this.incompleteLog += newInput || ``;
165
+ try {
166
+ const parsedLog = json.parseJson(this.incompleteLog);
167
+ this.handleLog(parsedLog);
168
+ while (this.unprocessedLogs.length > 0) {
169
+ this.incompleteLog = (_a = this.unprocessedLogs.shift()) != null ? _a : ``;
170
+ if (this.incompleteLog) {
171
+ const parsedLog2 = json.parseJson(this.incompleteLog);
172
+ this.handleLog(parsedLog2);
173
+ }
174
+ }
175
+ } catch (error) {
176
+ console.error(`\u274C\u274C\u274C`);
177
+ console.error(this.incompleteLog);
178
+ console.error(error);
179
+ console.error(`\u274C\u274C\u274C\uFE0F`);
180
+ }
181
+ });
112
182
  if (process2.pid) {
113
183
  this.id = process2.pid.toString();
114
184
  }
115
185
  }
186
+ handleLog(arg) {
187
+ if (Array.isArray(arg)) {
188
+ const [level, ...rest] = arg;
189
+ switch (level) {
190
+ case `i`:
191
+ this.logger.info(this.id, this.key, ...rest);
192
+ break;
193
+ case `w`:
194
+ this.logger.warn(this.id, this.key, ...rest);
195
+ break;
196
+ case `e`:
197
+ this.logger.error(this.id, this.key, ...rest);
198
+ break;
199
+ }
200
+ }
201
+ }
116
202
  };
117
203
  var SubjectSocket = class extends CustomSocket {
118
204
  constructor(id) {
@@ -121,6 +207,7 @@ var SubjectSocket = class extends CustomSocket {
121
207
  return this;
122
208
  });
123
209
  this.id = `no_id_retrieved`;
210
+ this.disposalFunctions = [];
124
211
  this.id = id;
125
212
  this.in = new internal.Subject();
126
213
  this.out = new internal.Subject();
@@ -128,69 +215,130 @@ var SubjectSocket = class extends CustomSocket {
128
215
  this.handleEvent(...event);
129
216
  });
130
217
  }
218
+ dispose() {
219
+ for (const dispose of this.disposalFunctions) {
220
+ dispose();
221
+ }
222
+ }
131
223
  };
132
224
  var ParentSocket = class extends CustomSocket {
133
225
  constructor() {
134
226
  var _a;
135
227
  super((event, ...args) => {
136
228
  const stringifiedEvent = JSON.stringify([event, ...args]);
137
- this.process.stdout.write(stringifiedEvent);
229
+ this.process.stdout.write(stringifiedEvent + ``);
138
230
  return this;
139
231
  });
140
- this.id = `no_id_retrieved`;
232
+ this.incompleteData = ``;
233
+ this.unprocessedEvents = [];
234
+ this.id = `#####`;
235
+ this.logger = {
236
+ info: (...args) => this.log(`i`, ...args),
237
+ warn: (...args) => this.log(`w`, ...args),
238
+ error: (...args) => this.log(`e`, ...args)
239
+ };
141
240
  this.process = process;
142
241
  this.process.stdin.resume();
143
- this.queue = [];
144
242
  this.relays = /* @__PURE__ */ new Map();
145
243
  this.relayServices = [];
146
244
  this.process.stdin.on(
147
245
  `data`,
148
- (chunk) => {
149
- const buffer = chunk.toString();
150
- this.queue.push(...buffer.split(`
151
- `));
152
- while (this.queue.length > 0) {
153
- try {
154
- const event = this.queue.shift();
155
- if (event === ``)
156
- continue;
157
- const parsedEvent = json.parseJson(event);
158
- this.handleEvent(...parsedEvent);
159
- } catch (error) {
160
- this.process.stderr.write(`\u274C ${error}
161
- `);
162
- break;
246
+ (buffer) => {
247
+ const chunk = buffer.toString();
248
+ this.unprocessedEvents.push(...chunk.split(``));
249
+ const newInput = this.unprocessedEvents.shift();
250
+ this.incompleteData += newInput || ``;
251
+ try {
252
+ const parsedEvent = json.parseJson(this.incompleteData);
253
+ this.logger.info(`\u{1F3B0}`, `received`, parsedEvent);
254
+ this.handleEvent(...parsedEvent);
255
+ while (this.unprocessedEvents.length > 0) {
256
+ const event = this.unprocessedEvents.shift();
257
+ if (event) {
258
+ if (this.unprocessedEvents.length === 0) {
259
+ this.incompleteData = event;
260
+ }
261
+ const parsedEvent2 = json.parseJson(event);
262
+ this.handleEvent(...parsedEvent2);
263
+ }
264
+ }
265
+ this.incompleteData = ``;
266
+ } catch (thrown) {
267
+ if (thrown instanceof Error) {
268
+ this.logger.error(`\u2757`, thrown.message, thrown.cause, thrown.stack);
163
269
  }
164
270
  }
165
271
  }
166
272
  );
167
- process.on(`SIGINT`, () => process.exit(0));
273
+ this.on(`exit`, () => {
274
+ process.exit(0);
275
+ });
276
+ process.on(`exit`, () => {
277
+ this.logger.info(`\u{1F525}`, this.id, `exited`);
278
+ process.exit(0);
279
+ });
280
+ process.on(`end`, () => {
281
+ this.logger.info(`\u{1F525}`, this.id, `ended`);
282
+ process.exit(0);
283
+ });
284
+ process.on(`SIGTERM`, () => {
285
+ this.logger.error(`\u{1F525}`, this.id, `terminated`);
286
+ process.exit(0);
287
+ });
288
+ process.on(`SIGINT`, () => {
289
+ this.logger.error(`\u{1F525}`, this.id, `interrupted`);
290
+ process.exit(0);
291
+ });
168
292
  if (process.pid) {
169
293
  this.id = (_a = process.pid) == null ? void 0 : _a.toString();
170
294
  }
171
- this.on(`setup-relay`, (id) => {
172
- const relay = new SubjectSocket(`relay:${id}`);
173
- this.relays.set(id, relay);
295
+ this.on(`user-joins`, (username) => {
296
+ this.logger.info(`\u{1F464}`, `user`, username, `joined`);
297
+ const relay = new SubjectSocket(`user:${username}`);
298
+ this.relays.set(username, relay);
299
+ this.logger.info(
300
+ `\u{1F517}`,
301
+ `attaching services:`,
302
+ `[${[...this.relayServices.keys()].join(`, `)}]`
303
+ );
174
304
  for (const attachServices of this.relayServices) {
175
- attachServices(relay);
305
+ const cleanup = attachServices(relay);
306
+ if (cleanup) {
307
+ relay.disposalFunctions.push(cleanup);
308
+ }
176
309
  }
177
- this.on(`relay:${id}`, (...data) => {
310
+ this.on(`user:${username}`, (...data) => {
178
311
  relay.in.next(data);
179
312
  });
180
313
  relay.out.subscribe(`socket`, (data) => {
181
314
  this.emit(...data);
182
315
  });
183
316
  });
317
+ this.on(`user-leaves`, (username) => {
318
+ const relay = this.relays.get(username);
319
+ this.off(`relay:${username}`);
320
+ if (relay) {
321
+ relay.dispose();
322
+ this.relays.delete(username);
323
+ }
324
+ });
325
+ process.stdout.write(`\u2728`);
326
+ }
327
+ log(...args) {
328
+ this.process.stderr.write(
329
+ json.stringifyJson(
330
+ args.map(
331
+ (arg) => arg instanceof setRtx.SetRTX ? `{ ${arg.toJSON().members.join(` | `)} }` : arg
332
+ )
333
+ ) + ``
334
+ );
184
335
  }
185
336
  relay(attachServices) {
337
+ this.logger.info(`\u{1F517}`, `running relay method`);
186
338
  this.relayServices.push(attachServices);
187
- const relays = this.relays.values();
188
- for (const relay of relays) {
189
- attachServices(relay);
190
- }
191
339
  }
192
340
  };
193
- var redactorAtoms = AtomIO.selectorFamily({
341
+ AtomIO.selectorFamily({
194
342
  key: `perspectiveRedactor`,
195
343
  get: ({ userId, syncGroupKey }) => ({ get, find }) => {
196
344
  const syncGroup = realtime.SyncGroup.existing.get(syncGroupKey);
@@ -200,17 +348,31 @@ var redactorAtoms = AtomIO.selectorFamily({
200
348
  );
201
349
  }
202
350
  const userPerspectiveTokens = syncGroup.perspectives.flatMap(
203
- ({ perspectiveAtoms, resourceAtoms }) => {
204
- const userPerspectiveToken = find(perspectiveAtoms, userId);
351
+ ({ viewAtoms }) => {
352
+ const userPerspectiveToken = find(viewAtoms, userId);
205
353
  const userPerspective = get(userPerspectiveToken);
206
- const visibleTokens = [...userPerspective].map((subKey) => {
207
- const resourceToken = find(resourceAtoms, subKey);
208
- return resourceToken.key;
354
+ const visibleTokens = [...userPerspective].map((token) => {
355
+ return token.type === `mutable_atom` ? internal.getUpdateToken(token).key : token.key;
209
356
  });
357
+ internal.IMPLICIT.STORE.logger.info(
358
+ `\u{1F52D}`,
359
+ `continuity`,
360
+ syncGroupKey,
361
+ `${userId} can see ${visibleTokens.length} tokens in ${viewAtoms.key}`,
362
+ visibleTokens
363
+ );
210
364
  return visibleTokens;
211
365
  }
212
366
  );
213
367
  const filterTransactionUpdate = (visible, transactionUpdate) => {
368
+ internal.IMPLICIT.STORE.logger.info(
369
+ `\u{1F58C}`,
370
+ `continuity`,
371
+ syncGroupKey,
372
+ `redacting updates from ${transactionUpdate.epoch}:${transactionUpdate.key}:${transactionUpdate.id}`,
373
+ visible,
374
+ transactionUpdate.updates
375
+ );
214
376
  const updates = transactionUpdate.updates.filter((update) => {
215
377
  if (`newValue` in update) {
216
378
  return visible.includes(update.key);
@@ -229,7 +391,7 @@ var redactorAtoms = AtomIO.selectorFamily({
229
391
  };
230
392
  const filter = (update) => {
231
393
  const visibleKeys = syncGroup.globals.map(
232
- (atomToken) => atomToken.key
394
+ (atomToken) => atomToken.type === `mutable_atom` ? internal.getUpdateToken(atomToken).key : atomToken.key
233
395
  );
234
396
  visibleKeys.push(...userPerspectiveTokens);
235
397
  return filterTransactionUpdate(visibleKeys, update);
@@ -237,67 +399,40 @@ var redactorAtoms = AtomIO.selectorFamily({
237
399
  return filter;
238
400
  }
239
401
  });
240
- var redactedPerspectiveUpdateSelectors = AtomIO.selectorFamily({
241
- key: `redactedPerspectiveUpdate`,
242
- get: ({ userId, syncGroupKey, updateId }) => ({ get, find }) => {
243
- const updateState = find(realtimeServer.completeUpdateAtoms, updateId);
244
- const update = get(updateState);
245
- const redactorKey = { userId, syncGroupKey };
246
- const redactorState = find(redactorAtoms, redactorKey);
247
- const redact = get(redactorState);
248
- if (update) {
249
- return redact(update);
250
- }
251
- return null;
252
- }
253
- });
254
- var roomIndex = AtomIO__namespace.atom({
255
- key: `roomIndex`,
256
- default: () => new setRtx.SetRTX(),
257
- mutable: true,
258
- toJson: (set) => set.toJSON(),
259
- fromJson: (json) => setRtx.SetRTX.fromJSON(json)
260
- });
261
- var DEFAULT_USER_IN_ROOM_META = {
262
- enteredAtEpoch: 0
263
- };
264
- var usersInRooms = data.join(
265
- {
266
- key: `usersInRooms`,
267
- between: [`room`, `user`],
268
- cardinality: `1:n`
269
- },
270
- DEFAULT_USER_IN_ROOM_META
271
- );
272
- var roomArgumentsAtoms = AtomIO__namespace.atomFamily({
402
+ var roomArgumentsAtoms = AtomIO.atomFamily({
273
403
  key: `roomArguments`,
274
- default: [`echo Hello World!`]
404
+ default: [`echo`, [`Hello World!`]]
275
405
  });
276
- var roomSelectors = AtomIO__namespace.selectorFamily({
406
+ var roomSelectors = AtomIO.selectorFamily({
277
407
  key: `room`,
278
- get: (roomId) => ({ get, find }) => {
408
+ get: (roomId) => async ({ get, find }) => {
279
409
  const argumentsState = find(roomArgumentsAtoms, roomId);
280
410
  const args = get(argumentsState);
281
411
  const [script, options] = args;
282
- return new Promise((resolve) => {
283
- const room = child_process.spawn(script, options, { env: process.env });
284
- const resolver = (data) => {
285
- if (data.toString() === `\u2728`) {
286
- room.stdout.off(`data`, resolver);
287
- resolve(room);
288
- }
289
- };
290
- room.stdout.on(`data`, resolver);
291
- });
412
+ const child = await new Promise(
413
+ (resolve) => {
414
+ const room = child_process.spawn(script, options, { env: process.env });
415
+ const resolver = (data) => {
416
+ if (data.toString() === `\u2728`) {
417
+ room.stdout.off(`data`, resolver);
418
+ resolve(room);
419
+ }
420
+ };
421
+ room.stdout.on(`data`, resolver);
422
+ }
423
+ );
424
+ return new ChildSocket(child, roomId);
292
425
  }
293
426
  });
427
+
428
+ // realtime-server/src/realtime-server-stores/server-room-external-actions.ts
294
429
  var createRoomTX = AtomIO__namespace.transaction({
295
430
  key: `createRoom`,
296
431
  do: ({ get, set, find }, roomId, script, options) => {
297
432
  const args = options ? [script, options] : [script];
298
433
  const roomArgumentsState = find(roomArgumentsAtoms, roomId);
299
434
  set(roomArgumentsState, args);
300
- set(roomIndex, (s) => s.add(roomId));
435
+ set(realtime.roomIndex, (s) => s.add(roomId));
301
436
  const roomState = find(roomSelectors, roomId);
302
437
  const room = get(roomState);
303
438
  return room;
@@ -307,30 +442,49 @@ var joinRoomTX = AtomIO__namespace.transaction({
307
442
  key: `joinRoom`,
308
443
  do: (transactors, roomId, userId, enteredAtEpoch) => {
309
444
  const meta = { enteredAtEpoch };
310
- usersInRooms.transact(transactors, ({ relations }) => {
445
+ realtime.usersInRooms.transact(transactors, ({ relations }) => {
311
446
  relations.set(roomId, userId, meta);
312
447
  });
313
448
  return meta;
314
449
  }
315
450
  });
316
- var completeUpdateAtoms2 = AtomIO.atomFamily({
317
- key: `completeUpdate`,
318
- default: null
451
+ var leaveRoomTX = AtomIO__namespace.transaction({
452
+ key: `leaveRoom`,
453
+ do: (transactors, roomId, userId) => {
454
+ realtime.usersInRooms.transact(transactors, ({ relations }) => {
455
+ relations.delete({ room: roomId, user: userId });
456
+ });
457
+ }
319
458
  });
320
- var transactionRedactorAtoms = AtomIO.atomFamily({
321
- key: `transactionRedactor`,
322
- default: { filter: (updates) => updates }
459
+ var destroyRoomTX = AtomIO__namespace.transaction({
460
+ key: `destroyRoom`,
461
+ do: (transactors, roomId) => {
462
+ realtime.usersInRooms.transact(transactors, ({ relations }) => {
463
+ relations.delete({ room: roomId });
464
+ });
465
+ transactors.set(realtime.roomIndex, (s) => (s.delete(roomId), s));
466
+ }
323
467
  });
324
- var redactedUpdateSelectors = AtomIO.selectorFamily({
325
- key: `redactedUpdate`,
326
- get: ([transactionKey, updateId]) => ({ get, find }) => {
327
- const update = get(find(completeUpdateAtoms2, updateId));
328
- const { filter } = get(find(transactionRedactorAtoms, transactionKey));
329
- if (update && filter) {
330
- return __spreadProps(__spreadValues({}, update), { updates: filter(update.updates) });
468
+ function redactTransactionUpdateContent(visibleStateKeys, updates) {
469
+ return updates.map((update) => {
470
+ if (`newValue` in update) {
471
+ return update;
331
472
  }
332
- return null;
333
- }
473
+ const redacted = redactTransactionUpdateContent(
474
+ visibleStateKeys,
475
+ update.updates
476
+ );
477
+ return __spreadProps(__spreadValues({}, update), { updates: redacted });
478
+ }).filter((update) => {
479
+ if (`newValue` in update) {
480
+ return visibleStateKeys.includes(update.key);
481
+ }
482
+ return true;
483
+ });
484
+ }
485
+ var actionOcclusionAtoms = AtomIO.atomFamily({
486
+ key: `transactionRedactor`,
487
+ default: { occlude: (updates) => updates }
334
488
  });
335
489
  var userUnacknowledgedQueues = AtomIO.atomFamily({
336
490
  key: `unacknowledgedUpdates`,
@@ -419,27 +573,74 @@ function realtimeContinuitySynchronizer({
419
573
  userKey,
420
574
  store
421
575
  );
422
- const userUnacknowledgedUpdates = internal.getFromStore(
576
+ internal.getFromStore(
423
577
  userUnacknowledgedQueue,
424
578
  store
425
579
  );
426
580
  const unsubscribeFunctions = [];
581
+ const revealPerspectives = () => {
582
+ const unsubscribeFunctions2 = [];
583
+ for (const perspective of continuity.perspectives) {
584
+ const { viewAtoms } = perspective;
585
+ const userViewState = internal.findInStore(viewAtoms, userKey, store);
586
+ const unsubscribe = internal.subscribeToState(
587
+ userViewState,
588
+ ({ oldValue, newValue }) => {
589
+ const oldKeys = oldValue.map((token) => token.key);
590
+ const newKeys = newValue.map((token) => token.key);
591
+ const concealed = oldValue.filter(
592
+ (token) => !newKeys.includes(token.key)
593
+ );
594
+ const revealed = newValue.filter((token) => !oldKeys.includes(token.key)).flatMap((token) => {
595
+ const resourceToken = token.type === `mutable_atom` ? internal.getJsonToken(token) : token;
596
+ const resource = internal.getFromStore(resourceToken, store);
597
+ return [resourceToken, resource];
598
+ });
599
+ store.logger.info(
600
+ `\u{1F441}`,
601
+ `atom`,
602
+ perspective.resourceAtoms.key,
603
+ `${userKey} has a new perspective`,
604
+ { oldKeys, newKeys, revealed, concealed }
605
+ );
606
+ if (revealed.length > 0) {
607
+ socket == null ? void 0 : socket.emit(`reveal:${continuityKey}`, revealed);
608
+ }
609
+ if (concealed.length > 0) {
610
+ socket == null ? void 0 : socket.emit(`conceal:${continuityKey}`, concealed);
611
+ }
612
+ },
613
+ `sync-continuity:${continuityKey}:${userKey}:perspective:${perspective.resourceAtoms.key}`,
614
+ store
615
+ );
616
+ unsubscribeFunctions2.push(unsubscribe);
617
+ }
618
+ return () => {
619
+ for (const unsubscribe of unsubscribeFunctions2)
620
+ unsubscribe();
621
+ };
622
+ };
623
+ const unsubscribeFromPerspectives = revealPerspectives();
427
624
  const sendInitialPayload = () => {
428
625
  var _a;
429
626
  const initialPayload = [];
430
- for (const atom3 of continuity.globals) {
431
- initialPayload.push(atom3, internal.getFromStore(atom3, store));
627
+ for (const atom2 of continuity.globals) {
628
+ const resourceToken = atom2.type === `mutable_atom` ? internal.getJsonToken(atom2) : atom2;
629
+ initialPayload.push(resourceToken, internal.getFromStore(atom2, store));
432
630
  }
433
- for (const { perspectiveAtoms } of continuity.perspectives) {
434
- const perspectiveTokensState = internal.findInStore(
435
- perspectiveAtoms,
436
- userKey,
437
- store
438
- );
439
- const perspectiveTokens = internal.getFromStore(perspectiveTokensState, store);
440
- for (const perspectiveToken of perspectiveTokens) {
441
- const resource = internal.getFromStore(perspectiveToken, store);
442
- initialPayload.push(perspectiveToken, resource);
631
+ for (const perspective of continuity.perspectives) {
632
+ const { viewAtoms, resourceAtoms } = perspective;
633
+ const userViewState = internal.findInStore(viewAtoms, userKey, store);
634
+ const userView = internal.getFromStore(userViewState, store);
635
+ store.logger.info(`\u{1F441}`, `atom`, resourceAtoms.key, `${userKey} can see`, {
636
+ viewAtoms,
637
+ resourceAtoms,
638
+ userView
639
+ });
640
+ for (const visibleToken of userView) {
641
+ const resourceToken = visibleToken.type === `mutable_atom` ? internal.getJsonToken(visibleToken) : visibleToken;
642
+ const resource = internal.getFromStore(resourceToken, store);
643
+ initialPayload.push(resourceToken, resource);
443
644
  }
444
645
  }
445
646
  const epoch = internal.isRootStore(store) ? (_a = store.transactionMeta.epoch.get(continuityKey)) != null ? _a : null : null;
@@ -448,38 +649,47 @@ function realtimeContinuitySynchronizer({
448
649
  const unsubscribeFromTransaction = internal.subscribeToTransaction(
449
650
  transaction2,
450
651
  (update) => {
451
- const updateState = internal.findInStore(
452
- completeUpdateAtoms2,
453
- update.id,
454
- store
455
- );
456
- internal.setIntoStore(updateState, update, store);
457
- const redactedUpdateKey = {
458
- userId: userKey,
459
- syncGroupKey: continuityKey,
460
- updateId: update.id
461
- };
462
- const redactedUpdateState = internal.findInStore(
463
- redactedPerspectiveUpdateSelectors,
464
- redactedUpdateKey,
465
- store
466
- );
467
- const redactedUpdate = internal.getFromStore(redactedUpdateState, store);
468
- internal.setIntoStore(
469
- userUnacknowledgedQueue,
470
- (updates) => {
471
- if (redactedUpdate) {
472
- updates.push(redactedUpdate);
473
- updates.sort((a, b) => a.epoch - b.epoch);
474
- }
475
- return updates;
476
- },
477
- store
478
- );
479
- socket == null ? void 0 : socket.emit(
480
- `tx-new:${continuityKey}`,
481
- redactedUpdate
482
- );
652
+ try {
653
+ const visibleKeys = continuity.globals.map((atom2) => atom2.key).concat(
654
+ continuity.perspectives.flatMap((perspective) => {
655
+ const { viewAtoms } = perspective;
656
+ const userPerspectiveTokenState = internal.findInStore(
657
+ viewAtoms,
658
+ userKey,
659
+ store
660
+ );
661
+ const visibleTokens = internal.getFromStore(
662
+ userPerspectiveTokenState,
663
+ store
664
+ );
665
+ return visibleTokens.map((token) => {
666
+ const key = token.type === `mutable_atom` ? `*` + token.key : token.key;
667
+ return key;
668
+ });
669
+ })
670
+ );
671
+ const redactedUpdates = redactTransactionUpdateContent(
672
+ visibleKeys,
673
+ update.updates
674
+ );
675
+ const redactedUpdate = __spreadProps(__spreadValues({}, update), {
676
+ updates: redactedUpdates
677
+ });
678
+ socket == null ? void 0 : socket.emit(
679
+ `tx-new:${continuityKey}`,
680
+ redactedUpdate
681
+ );
682
+ } catch (thrown) {
683
+ if (thrown instanceof Error) {
684
+ store.logger.error(
685
+ `\u274C`,
686
+ `continuity`,
687
+ continuityKey,
688
+ `failed to send update from transaction ${transaction2.key} to ${userKey}`,
689
+ thrown.message
690
+ );
691
+ }
692
+ }
483
693
  },
484
694
  `sync-continuity:${continuityKey}:${userKey}`,
485
695
  store
@@ -490,17 +700,30 @@ function realtimeContinuitySynchronizer({
490
700
  socket.off(`get:${continuityKey}`, sendInitialPayload);
491
701
  socket.on(`get:${continuityKey}`, sendInitialPayload);
492
702
  const fillTransactionRequest = (update) => {
703
+ store.logger.info(`\u{1F6CE}\uFE0F`, `continuity`, continuityKey, `received`, update);
493
704
  const transactionKey = update.key;
494
705
  const updateId = update.id;
495
706
  const performanceKey = `tx-run:${transactionKey}:${updateId}`;
496
707
  const performanceKeyStart = `${performanceKey}:start`;
497
708
  const performanceKeyEnd = `${performanceKey}:end`;
498
709
  performance.mark(performanceKeyStart);
499
- internal.actUponStore(
500
- { type: `transaction`, key: transactionKey },
501
- updateId,
502
- store
503
- )(...update.params);
710
+ try {
711
+ internal.actUponStore(
712
+ { type: `transaction`, key: transactionKey },
713
+ updateId,
714
+ store
715
+ )(...update.params);
716
+ } catch (thrown) {
717
+ if (thrown instanceof Error) {
718
+ store.logger.error(
719
+ `\u274C`,
720
+ `continuity`,
721
+ continuityKey,
722
+ `failed to run transaction ${transactionKey} with update ${updateId}`,
723
+ thrown.message
724
+ );
725
+ }
726
+ }
504
727
  performance.mark(performanceKeyEnd);
505
728
  const metric = performance.measure(
506
729
  performanceKey,
@@ -514,56 +737,27 @@ function realtimeContinuitySynchronizer({
514
737
  updateId,
515
738
  metric.duration
516
739
  );
517
- };
518
- socket.off(`tx-run:${continuityKey}`, fillTransactionRequest);
519
- socket.on(`tx-run:${continuityKey}`, fillTransactionRequest);
520
- let i = 1;
521
- let next = 1;
522
- const retry = setInterval(() => {
523
- const toEmit = userUnacknowledgedUpdates[0];
740
+ const valuesOfCardsViewKey = `valuesOfCardsView("${userKey}")`;
741
+ const rootsOfCardValueView = store.selectorAtoms.getRelatedKeys(valuesOfCardsViewKey);
742
+ const myCardValueView = store.valueMap.get(valuesOfCardsViewKey);
524
743
  store.logger.info(
525
- `\u{1F504}`,
744
+ `\u{1F441}`,
526
745
  `continuity`,
527
746
  continuityKey,
528
- `${store.config.name} retrying ${userKey} (${i}/${next})`,
529
- socket == null ? void 0 : socket.id,
530
- userUnacknowledgedUpdates
531
- );
532
- if (toEmit && i === next) {
533
- socket == null ? void 0 : socket.emit(`tx-new:${continuityKey}`, toEmit);
534
- next *= 2;
535
- }
536
- i++;
537
- }, 250);
538
- const trackClientAcknowledgement = (epoch) => {
539
- var _a;
540
- store.logger.info(
541
- `\u{1F44D}`,
542
- `continuity`,
543
- continuityKey,
544
- `${userKey} acknowledged epoch ${epoch}`
747
+ `seeing ${userKey} card values`,
748
+ {
749
+ valuesOfCardsViewKey,
750
+ rootsOfCardValueView,
751
+ myCardValueView
752
+ }
545
753
  );
546
- i = 1;
547
- next = 1;
548
- const isUnacknowledged = ((_a = userUnacknowledgedUpdates[0]) == null ? void 0 : _a.epoch) === epoch;
549
- if (isUnacknowledged) {
550
- internal.setIntoStore(
551
- userUnacknowledgedQueue,
552
- (updates) => {
553
- updates.shift();
554
- return updates;
555
- },
556
- store
557
- );
558
- }
559
754
  };
560
- socket.off(`ack:${continuityKey}`, trackClientAcknowledgement);
561
- socket.on(`ack:${continuityKey}`, trackClientAcknowledgement);
755
+ socket.off(`tx-run:${continuityKey}`, fillTransactionRequest);
756
+ socket.on(`tx-run:${continuityKey}`, fillTransactionRequest);
562
757
  return () => {
563
- clearInterval(retry);
564
758
  for (const unsubscribe of unsubscribeFunctions)
565
759
  unsubscribe();
566
- socket == null ? void 0 : socket.off(`ack:${continuityKey}`, trackClientAcknowledgement);
760
+ unsubscribeFromPerspectives();
567
761
  socket == null ? void 0 : socket.off(`get:${continuityKey}`, sendInitialPayload);
568
762
  socket == null ? void 0 : socket.off(`tx-run:${continuityKey}`, fillTransactionRequest);
569
763
  };
@@ -788,135 +982,17 @@ function realtimeActionReceiver({
788
982
  return () => socket.off(`tx-run:${tx.key}`, fillTransactionRequest);
789
983
  };
790
984
  }
791
- function realtimeActionSynchronizer({
792
- socket,
793
- store = internal.IMPLICIT.STORE
794
- }) {
795
- return function actionSynchronizer(tx, filter) {
796
- internal.assignTransactionToContinuity(`default`, tx.key, store);
797
- const userKeyState = internal.findInStore(
798
- usersOfSockets.states.userKeyOfSocket,
799
- socket.id,
800
- store
801
- );
802
- const userKey = internal.getFromStore(userKeyState, store);
803
- if (!userKey) {
804
- store.logger.error(
805
- `\u274C`,
806
- `transaction`,
807
- tx.key,
808
- `Tried to create a synchronizer for a socket (${socket.id}) that is not connected to a user.`
809
- );
810
- return () => {
811
- };
812
- }
813
- const userUnacknowledgedQueue = internal.findInStore(
814
- userUnacknowledgedQueues,
815
- userKey,
816
- store
817
- );
818
- const userUnacknowledgedUpdates = internal.getFromStore(
819
- userUnacknowledgedQueue,
820
- store
821
- );
822
- if (filter) {
823
- const redactorState = internal.findInStore(transactionRedactorAtoms, tx.key, store);
824
- internal.setIntoStore(redactorState, { filter }, store);
825
- }
826
- const fillTransactionRequest = (update) => {
827
- const performanceKey = `tx-run:${tx.key}:${update.id}`;
828
- const performanceKeyStart = `${performanceKey}:start`;
829
- const performanceKeyEnd = `${performanceKey}:end`;
830
- performance.mark(performanceKeyStart);
831
- internal.actUponStore(tx, update.id, store)(...update.params);
832
- performance.mark(performanceKeyEnd);
833
- const metric = performance.measure(
834
- performanceKey,
835
- performanceKeyStart,
836
- performanceKeyEnd
837
- );
838
- store == null ? void 0 : store.logger.info(`\u{1F680}`, `transaction`, tx.key, update.id, metric.duration);
839
- };
840
- socket.off(`tx-run:${tx.key}`, fillTransactionRequest);
841
- socket.on(`tx-run:${tx.key}`, fillTransactionRequest);
842
- let unsubscribeFromTransaction;
843
- const fillTransactionSubscriptionRequest = () => {
844
- unsubscribeFromTransaction = internal.subscribeToTransaction(
845
- tx,
846
- (update) => {
847
- const updateState = internal.findInStore(completeUpdateAtoms2, update.id, store);
848
- internal.setIntoStore(updateState, update, store);
849
- const toEmit = filter ? internal.getFromStore(
850
- internal.findInStore(redactedUpdateSelectors, [tx.key, update.id], store),
851
- store
852
- ) : update;
853
- internal.setIntoStore(
854
- userUnacknowledgedQueue,
855
- (updates) => {
856
- if (toEmit) {
857
- updates.push(toEmit);
858
- updates.sort((a, b) => a.epoch - b.epoch);
859
- }
860
- return updates;
861
- },
862
- store
863
- );
864
- socket.emit(`tx-new:${tx.key}`, toEmit);
865
- },
866
- `tx-sub:${tx.key}:${socket.id}`,
867
- store
868
- );
869
- socket.on(`tx-unsub:${tx.key}`, unsubscribeFromTransaction);
870
- };
871
- socket.on(`tx-sub:${tx.key}`, fillTransactionSubscriptionRequest);
872
- let i = 1;
873
- let next = 1;
874
- const retry = setInterval(() => {
875
- const toEmit = userUnacknowledgedUpdates[0];
876
- if (toEmit && i === next) {
877
- socket.emit(`tx-new:${tx.key}`, toEmit);
878
- next *= 2;
879
- }
880
- i++;
881
- }, 250);
882
- const trackClientAcknowledgement = (epoch) => {
883
- var _a;
884
- i = 1;
885
- next = 1;
886
- if (((_a = userUnacknowledgedUpdates[0]) == null ? void 0 : _a.epoch) === epoch) {
887
- internal.setIntoStore(
888
- userUnacknowledgedQueue,
889
- (updates) => {
890
- updates.shift();
891
- return updates;
892
- },
893
- store
894
- );
895
- }
896
- };
897
- socket.on(`tx-ack:${tx.key}`, trackClientAcknowledgement);
898
- return () => {
899
- if (unsubscribeFromTransaction) {
900
- unsubscribeFromTransaction();
901
- unsubscribeFromTransaction = void 0;
902
- }
903
- clearInterval(retry);
904
- socket.off(`tx-run:${tx.key}`, fillTransactionRequest);
905
- socket.off(`tx-sub:${tx.key}`, fillTransactionSubscriptionRequest);
906
- };
907
- };
908
- }
909
985
 
910
986
  exports.ChildSocket = ChildSocket;
911
987
  exports.CustomSocket = CustomSocket;
912
- exports.DEFAULT_USER_IN_ROOM_META = DEFAULT_USER_IN_ROOM_META;
913
988
  exports.ParentSocket = ParentSocket;
914
989
  exports.SubjectSocket = SubjectSocket;
915
- exports.completeUpdateAtoms = completeUpdateAtoms2;
990
+ exports.actionOcclusionAtoms = actionOcclusionAtoms;
916
991
  exports.createRoomTX = createRoomTX;
992
+ exports.destroyRoomTX = destroyRoomTX;
917
993
  exports.joinRoomTX = joinRoomTX;
994
+ exports.leaveRoomTX = leaveRoomTX;
918
995
  exports.realtimeActionReceiver = realtimeActionReceiver;
919
- exports.realtimeActionSynchronizer = realtimeActionSynchronizer;
920
996
  exports.realtimeAtomFamilyProvider = realtimeAtomFamilyProvider;
921
997
  exports.realtimeContinuitySynchronizer = realtimeContinuitySynchronizer;
922
998
  exports.realtimeMutableFamilyProvider = realtimeMutableFamilyProvider;
@@ -924,17 +1000,13 @@ exports.realtimeMutableProvider = realtimeMutableProvider;
924
1000
  exports.realtimeStateProvider = realtimeStateProvider;
925
1001
  exports.realtimeStateReceiver = realtimeStateReceiver;
926
1002
  exports.realtimeStateSynchronizer = realtimeStateSynchronizer;
927
- exports.redactedPerspectiveUpdateSelectors = redactedPerspectiveUpdateSelectors;
928
- exports.redactedUpdateSelectors = redactedUpdateSelectors;
1003
+ exports.redactTransactionUpdateContent = redactTransactionUpdateContent;
929
1004
  exports.roomArgumentsAtoms = roomArgumentsAtoms;
930
- exports.roomIndex = roomIndex;
931
1005
  exports.roomSelectors = roomSelectors;
932
1006
  exports.socketAtoms = socketAtoms;
933
1007
  exports.socketIndex = socketIndex;
934
- exports.transactionRedactorAtoms = transactionRedactorAtoms;
935
1008
  exports.userIndex = userIndex;
936
1009
  exports.userUnacknowledgedQueues = userUnacknowledgedQueues;
937
- exports.usersInRooms = usersInRooms;
938
1010
  exports.usersOfSockets = usersOfSockets;
939
1011
  //# sourceMappingURL=out.js.map
940
1012
  //# sourceMappingURL=index.cjs.map