atom.io 0.17.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 (153) hide show
  1. package/data/dist/index.cjs +62 -40
  2. package/data/dist/index.cjs.map +1 -1
  3. package/data/dist/index.d.ts +8 -2
  4. package/data/dist/index.js +64 -42
  5. package/data/dist/index.js.map +1 -1
  6. package/data/src/dict.ts +8 -4
  7. package/data/src/join.ts +74 -33
  8. package/data/src/struct-family.ts +18 -17
  9. package/dist/chunk-IZHOMSXA.js +331 -0
  10. package/dist/chunk-IZHOMSXA.js.map +1 -0
  11. package/dist/chunk-JDUNWJFB.js +18 -0
  12. package/dist/chunk-JDUNWJFB.js.map +1 -0
  13. package/dist/index.cjs +4 -10
  14. package/dist/index.cjs.map +1 -1
  15. package/dist/index.d.ts +66 -51
  16. package/dist/index.js +5 -11
  17. package/dist/index.js.map +1 -1
  18. package/internal/dist/index.cjs +187 -58
  19. package/internal/dist/index.cjs.map +1 -1
  20. package/internal/dist/index.d.ts +95 -71
  21. package/internal/dist/index.js +179 -53
  22. package/internal/dist/index.js.map +1 -1
  23. package/internal/src/arbitrary.ts +3 -0
  24. package/internal/src/atom/delete-atom.ts +7 -6
  25. package/internal/src/caching.ts +6 -4
  26. package/internal/src/families/find-in-store.ts +16 -0
  27. package/internal/src/get-environment-data.ts +4 -7
  28. package/internal/src/index.ts +6 -5
  29. package/internal/src/ingest-updates/ingest-atom-update.ts +6 -2
  30. package/internal/src/ingest-updates/ingest-transaction-update.ts +0 -1
  31. package/internal/src/selector/create-standalone-selector.ts +0 -2
  32. package/internal/src/set-state/copy-mutable-if-needed.ts +5 -0
  33. package/internal/src/set-state/emit-update.ts +25 -11
  34. package/internal/src/set-state/set-atom.ts +15 -18
  35. package/internal/src/store/store.ts +14 -2
  36. package/internal/src/store/withdraw.ts +72 -2
  37. package/internal/src/subscribe/subscribe-to-timeline.ts +2 -2
  38. package/internal/src/subscribe/subscribe-to-transaction.ts +2 -2
  39. package/internal/src/timeline/create-timeline.ts +12 -1
  40. package/internal/src/transaction/act-upon-store.ts +19 -0
  41. package/internal/src/transaction/apply-transaction.ts +6 -1
  42. package/internal/src/transaction/assign-transaction-to-continuity.ts +18 -0
  43. package/internal/src/transaction/build-transaction.ts +7 -6
  44. package/internal/src/transaction/create-transaction.ts +1 -1
  45. package/internal/src/transaction/get-epoch-number.ts +40 -0
  46. package/internal/src/transaction/index.ts +10 -1
  47. package/internal/src/transaction/set-epoch-number.ts +30 -0
  48. package/introspection/dist/index.cjs.map +1 -1
  49. package/introspection/dist/index.d.ts +3 -3
  50. package/introspection/dist/index.js.map +1 -1
  51. package/introspection/src/attach-introspection-states.ts +6 -2
  52. package/introspection/src/attach-timeline-family.ts +5 -2
  53. package/introspection/src/attach-transaction-logs.ts +2 -2
  54. package/json/dist/index.d.ts +3 -1
  55. package/json/src/index.ts +4 -0
  56. package/package.json +241 -230
  57. package/react/dist/index.cjs.map +1 -1
  58. package/react/dist/index.d.ts +1 -1
  59. package/react/dist/index.js.map +1 -1
  60. package/react/src/use-json.ts +1 -1
  61. package/react-devtools/dist/index.cjs +131 -134
  62. package/react-devtools/dist/index.cjs.map +1 -1
  63. package/react-devtools/dist/index.css +2 -2
  64. package/react-devtools/dist/index.css.map +1 -1
  65. package/react-devtools/dist/index.d.ts +3 -3
  66. package/react-devtools/dist/index.js +91 -108
  67. package/react-devtools/dist/index.js.map +1 -1
  68. package/react-devtools/src/StateEditor.tsx +4 -4
  69. package/react-devtools/src/StateIndex.tsx +1 -4
  70. package/react-devtools/src/TimelineIndex.tsx +3 -3
  71. package/react-devtools/src/TransactionIndex.tsx +9 -8
  72. package/react-devtools/src/index.ts +2 -2
  73. package/realtime/dist/index.cjs +120 -0
  74. package/realtime/dist/index.cjs.map +1 -0
  75. package/realtime/dist/index.d.ts +146 -0
  76. package/realtime/dist/index.js +111 -0
  77. package/realtime/dist/index.js.map +1 -0
  78. package/realtime/package.json +16 -0
  79. package/realtime/src/index.ts +2 -0
  80. package/realtime/src/realtime-continuity.ts +162 -0
  81. package/realtime/src/shared-room-store.ts +48 -0
  82. package/realtime-client/dist/index.cjs +424 -170
  83. package/realtime-client/dist/index.cjs.map +1 -1
  84. package/realtime-client/dist/index.d.ts +15 -11
  85. package/realtime-client/dist/index.js +96 -177
  86. package/realtime-client/dist/index.js.map +1 -1
  87. package/realtime-client/src/index.ts +8 -7
  88. package/realtime-client/src/{pull-family-member.ts → pull-atom-family-member.ts} +2 -2
  89. package/realtime-client/src/{pull-state.ts → pull-atom.ts} +2 -2
  90. package/realtime-client/src/{pull-mutable-family-member.ts → pull-mutable-atom-family-member.ts} +6 -6
  91. package/realtime-client/src/{pull-mutable.ts → pull-mutable-atom.ts} +1 -1
  92. package/realtime-client/src/pull-selector-family-member.ts +42 -0
  93. package/realtime-client/src/pull-selector.ts +38 -0
  94. package/realtime-client/src/realtime-client-stores/client-main-store.ts +12 -2
  95. package/realtime-client/src/realtime-client-stores/client-sync-store.ts +7 -7
  96. package/realtime-client/src/sync-continuity.ts +368 -0
  97. package/realtime-react/dist/index.cjs +367 -27
  98. package/realtime-react/dist/index.cjs.map +1 -1
  99. package/realtime-react/dist/index.d.ts +24 -8
  100. package/realtime-react/dist/index.js +38 -22
  101. package/realtime-react/dist/index.js.map +1 -1
  102. package/realtime-react/src/index.ts +6 -5
  103. package/realtime-react/src/use-pull-atom-family-member.ts +21 -0
  104. package/realtime-react/src/{use-sync.ts → use-pull-atom.ts} +4 -4
  105. package/realtime-react/src/{use-pull-mutable.ts → use-pull-mutable-atom.ts} +4 -3
  106. package/realtime-react/src/use-pull-mutable-family-member.ts +9 -4
  107. package/realtime-react/src/use-pull-selector-family-member.ts +21 -0
  108. package/realtime-react/src/{use-pull.ts → use-pull-selector.ts} +7 -5
  109. package/realtime-react/src/use-push.ts +3 -2
  110. package/realtime-react/src/use-server-action.ts +3 -2
  111. package/realtime-react/src/use-sync-continuity.ts +12 -0
  112. package/realtime-server/dist/index.cjs +769 -371
  113. package/realtime-server/dist/index.cjs.map +1 -1
  114. package/realtime-server/dist/index.d.ts +130 -60
  115. package/realtime-server/dist/index.js +753 -361
  116. package/realtime-server/dist/index.js.map +1 -1
  117. package/realtime-server/src/index.ts +17 -3
  118. package/realtime-server/src/ipc-sockets/child-socket.ts +135 -0
  119. package/realtime-server/src/ipc-sockets/custom-socket.ts +90 -0
  120. package/realtime-server/src/ipc-sockets/index.ts +3 -0
  121. package/realtime-server/src/ipc-sockets/parent-socket.ts +185 -0
  122. package/realtime-server/src/realtime-action-receiver.ts +8 -5
  123. package/realtime-server/src/realtime-continuity-synchronizer.ts +376 -0
  124. package/realtime-server/src/realtime-family-provider.ts +30 -71
  125. package/realtime-server/src/realtime-mutable-family-provider.ts +24 -86
  126. package/realtime-server/src/realtime-server-stores/index.ts +4 -1
  127. package/realtime-server/src/realtime-server-stores/realtime-continuity-store.ts +109 -0
  128. package/realtime-server/src/realtime-server-stores/server-room-external-actions.ts +64 -0
  129. package/realtime-server/src/realtime-server-stores/server-room-external-store.ts +42 -0
  130. package/realtime-server/src/realtime-server-stores/server-sync-store.ts +51 -98
  131. package/realtime-server/src/realtime-server-stores/server-user-store.ts +14 -29
  132. package/realtime-server/src/realtime-state-receiver.ts +0 -1
  133. package/realtime-testing/dist/index.cjs +34 -32
  134. package/realtime-testing/dist/index.cjs.map +1 -1
  135. package/realtime-testing/dist/index.d.ts +1 -0
  136. package/realtime-testing/dist/index.js +33 -31
  137. package/realtime-testing/dist/index.js.map +1 -1
  138. package/realtime-testing/src/setup-realtime-test.tsx +44 -32
  139. package/src/atom.ts +49 -31
  140. package/src/logger.ts +14 -5
  141. package/src/selector.ts +44 -25
  142. package/src/subscribe.ts +2 -1
  143. package/src/timeline.ts +4 -4
  144. package/src/transaction.ts +13 -17
  145. package/src/validators.ts +15 -9
  146. package/dist/chunk-H4Q5FTPZ.js +0 -11
  147. package/dist/chunk-H4Q5FTPZ.js.map +0 -1
  148. package/internal/src/set-state/copy-mutable-in-transaction.ts +0 -19
  149. package/realtime-client/src/sync-server-action.ts +0 -170
  150. package/realtime-client/src/sync-state.ts +0 -19
  151. package/realtime-react/src/use-pull-family-member.ts +0 -16
  152. package/realtime-react/src/use-sync-server-action.ts +0 -16
  153. package/realtime-server/src/realtime-action-synchronizer.ts +0 -152
@@ -5,13 +5,12 @@ import {
5
5
  getFromStore,
6
6
  subscribeToState,
7
7
  } from "atom.io/internal"
8
- import type { Json } from "atom.io/json"
9
- import { parseJson } from "atom.io/json"
8
+ import { type Json, stringifyJson } from "atom.io/json"
10
9
 
11
10
  import type { ServerConfig } from "."
12
11
 
13
- export type FamilyProvider = ReturnType<typeof realtimeFamilyProvider>
14
- export function realtimeFamilyProvider({
12
+ export type FamilyProvider = ReturnType<typeof realtimeAtomFamilyProvider>
13
+ export function realtimeAtomFamilyProvider({
15
14
  socket,
16
15
  store = IMPLICIT.STORE,
17
16
  }: ServerConfig) {
@@ -19,77 +18,40 @@ export function realtimeFamilyProvider({
19
18
  J extends Json.Serializable,
20
19
  K extends Json.Serializable,
21
20
  >(
22
- family: AtomIO.RegularAtomFamily<J, K>,
21
+ family: AtomIO.RegularAtomFamilyToken<J, K>,
23
22
  index: AtomIO.ReadableToken<Iterable<K>>,
24
23
  ): () => void {
25
- const unsubSingleCallbacksByKey = new Map<string, () => void>()
26
- const unsubFamilyCallbacksByKey = new Map<string, () => void>()
24
+ const unsubCallbacksByKey = new Map<string, () => void>()
27
25
 
28
- const fillFamilyUnsubRequest = () => {
29
- for (const [, unsub] of unsubFamilyCallbacksByKey) {
30
- unsub()
31
- }
32
- unsubFamilyCallbacksByKey.clear()
33
- socket.off(`unsub:${family.key}`, fillFamilyUnsubRequest)
34
- }
35
-
36
- const fillSingleUnsubRequest = (key: string) => {
37
- socket.off(`unsub:${key}`, fillSingleUnsubRequest)
38
- const unsub = unsubSingleCallbacksByKey.get(key)
26
+ const fillUnsubRequest = (key: string) => {
27
+ socket.off(`unsub:${key}`, fillUnsubRequest)
28
+ const unsub = unsubCallbacksByKey.get(key)
39
29
  if (unsub) {
40
30
  unsub()
41
- unsubSingleCallbacksByKey.delete(key)
31
+ unsubCallbacksByKey.delete(key)
42
32
  }
43
33
  }
44
34
 
45
- const fillSubRequest = (subKey?: K) => {
46
- if (subKey === undefined) {
47
- const keys = getFromStore(index, store)
48
- for (const key of keys) {
49
- const token = findInStore(family, key, store)
50
- socket.emit(
51
- `serve:${family.key}`,
52
- parseJson(token.family?.subKey || `null`),
53
- getFromStore(token, store),
35
+ const fillSubRequest = (subKey: K) => {
36
+ const exposedSubKeys = getFromStore(index, store)
37
+ for (const exposedSubKey of exposedSubKeys) {
38
+ if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {
39
+ const token = findInStore(family, subKey, store)
40
+ socket.emit(`serve:${token.key}`, getFromStore(token, store))
41
+ const unsubscribe = subscribeToState(
42
+ token,
43
+ ({ newValue }) => {
44
+ socket.emit(`serve:${token.key}`, newValue)
45
+ },
46
+ `expose-family:${family.key}:${socket.id}`,
47
+ store,
54
48
  )
49
+ unsubCallbacksByKey.set(token.key, unsubscribe)
50
+ socket.on(`unsub:${token.key}`, () => {
51
+ fillUnsubRequest(token.key)
52
+ })
53
+ break
55
54
  }
56
-
57
- const unsubscribeFromTokenCreation = family.subject.subscribe(
58
- `expose-family:${socket.id}`,
59
- (token: AtomIO.WritableToken<J>) => {
60
- const unsub = subscribeToState(
61
- token,
62
- ({ newValue }) => {
63
- socket.emit(
64
- `serve:${family.key}`,
65
- parseJson(token.family?.subKey || `null`),
66
- newValue,
67
- )
68
- },
69
- `expose-family:${family.key}:${socket.id}`,
70
- store,
71
- )
72
- unsubFamilyCallbacksByKey.set(token.key, unsub)
73
- },
74
- )
75
- unsubFamilyCallbacksByKey.set(family.key, unsubscribeFromTokenCreation)
76
-
77
- socket.on(`unsub:${family.key}`, fillFamilyUnsubRequest)
78
- } else {
79
- const token = family(subKey)
80
- socket.emit(`serve:${token.key}`, getFromStore(token, store))
81
- const unsubscribe = subscribeToState(
82
- token,
83
- ({ newValue }) => {
84
- socket.emit(`serve:${token.key}`, newValue)
85
- },
86
- `expose-family:${family.key}:${socket.id}`,
87
- store,
88
- )
89
- unsubSingleCallbacksByKey.set(token.key, unsubscribe)
90
- socket.on(`unsub:${token.key}`, () => {
91
- fillSingleUnsubRequest(token.key)
92
- })
93
55
  }
94
56
  }
95
57
 
@@ -97,14 +59,11 @@ export function realtimeFamilyProvider({
97
59
 
98
60
  return () => {
99
61
  socket.off(`sub:${family.key}`, fillSubRequest)
100
- for (const [, unsub] of unsubFamilyCallbacksByKey) {
101
- unsub()
102
- }
103
- for (const [, unsub] of unsubSingleCallbacksByKey) {
62
+
63
+ for (const [, unsub] of unsubCallbacksByKey) {
104
64
  unsub()
105
65
  }
106
- unsubFamilyCallbacksByKey.clear()
107
- unsubSingleCallbacksByKey.clear()
66
+ unsubCallbacksByKey.clear()
108
67
  }
109
68
  }
110
69
  }
@@ -9,7 +9,7 @@ import {
9
9
  subscribeToState,
10
10
  } from "atom.io/internal"
11
11
  import type { Json } from "atom.io/json"
12
- import { parseJson } from "atom.io/json"
12
+ import { stringifyJson } from "atom.io/json"
13
13
 
14
14
  import type { ServerConfig } from "."
15
15
 
@@ -25,100 +25,42 @@ export function realtimeMutableFamilyProvider({
25
25
  J extends Json.Serializable,
26
26
  K extends Json.Serializable,
27
27
  >(
28
- family: AtomIO.MutableAtomFamily<T, J, K>,
28
+ family: AtomIO.MutableAtomFamilyToken<T, J, K>,
29
29
  index: AtomIO.ReadableToken<Iterable<K>>,
30
30
  ): () => void {
31
- const unsubSingleCallbacksByKey = new Map<string, () => void>()
32
- const unsubFamilyCallbacksByKey = new Map<string, () => void>()
31
+ const unsubCallbacksByKey = new Map<string, () => void>()
33
32
 
34
- const fillFamilyUnsubRequest = () => {
35
- for (const [, unsub] of unsubFamilyCallbacksByKey) {
36
- unsub()
37
- }
38
- unsubFamilyCallbacksByKey.clear()
39
- socket.off(`unsub:${family.key}`, fillFamilyUnsubRequest)
40
- }
41
-
42
- const fillSingleUnsubRequest = (key: string) => {
43
- socket.off(`unsub:${key}`, fillSingleUnsubRequest)
44
- const unsub = unsubSingleCallbacksByKey.get(key)
33
+ const fillUnsubRequest = (key: string) => {
34
+ socket.off(`unsub:${key}`, fillUnsubRequest)
35
+ const unsub = unsubCallbacksByKey.get(key)
45
36
  if (unsub) {
46
37
  unsub()
47
- unsubSingleCallbacksByKey.delete(key)
38
+ unsubCallbacksByKey.delete(key)
48
39
  }
49
40
  }
50
41
 
51
- const fillSubRequest = (subKey?: K) => {
52
- if (subKey === undefined) {
53
- const keys = getFromStore(index, store)
54
- for (const key of keys) {
55
- const token = findInStore(family, key, store)
42
+ const fillSubRequest = (subKey: K) => {
43
+ const exposedSubKeys = getFromStore(index, store)
44
+ for (const exposedSubKey of exposedSubKeys) {
45
+ if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {
46
+ const token = findInStore(family, subKey, store)
56
47
  const jsonToken = getJsonToken(token)
57
- const trackerToken = getUpdateToken(token)
58
- socket.emit(
59
- `init:${family.key}`,
60
- parseJson(jsonToken.family?.subKey || `null`),
61
- getFromStore(jsonToken, store),
62
- )
63
- const unsubFromUpdates = subscribeToState(
64
- trackerToken,
48
+ const updateToken = getUpdateToken(token)
49
+ socket.emit(`init:${token.key}`, getFromStore(jsonToken, store))
50
+ const unsubscribe = subscribeToState(
51
+ updateToken,
65
52
  ({ newValue }) => {
66
- socket.emit(
67
- `next:${token.key}`,
68
- parseJson(jsonToken.family?.subKey || `null`),
69
- newValue,
70
- )
53
+ socket.emit(`next:${token.key}`, newValue)
71
54
  },
72
55
  `expose-family:${family.key}:${socket.id}`,
73
56
  store,
74
57
  )
75
- unsubFamilyCallbacksByKey.set(token.key, unsubFromUpdates)
58
+ unsubCallbacksByKey.set(token.key, unsubscribe)
59
+ socket.on(`unsub:${token.key}`, () => {
60
+ fillUnsubRequest(token.key)
61
+ })
62
+ break
76
63
  }
77
- const unsubscribeFromTokenCreation = family.subject.subscribe(
78
- `expose-family:${socket.id}`,
79
- (token) => {
80
- const jsonToken = getJsonToken(token)
81
- const trackerToken = getUpdateToken(token)
82
- socket.emit(
83
- `init:${family.key}`,
84
- parseJson(jsonToken.family?.subKey || `null`),
85
- getFromStore(jsonToken, store),
86
- )
87
- const unsubFromUpdates = subscribeToState(
88
- trackerToken,
89
- ({ newValue }) => {
90
- socket.emit(
91
- `next:${token.key}`,
92
- parseJson(jsonToken.family?.subKey || `null`),
93
- newValue,
94
- )
95
- },
96
- `expose-family:${family.key}:${socket.id}`,
97
- store,
98
- )
99
- unsubFamilyCallbacksByKey.set(token.key, unsubFromUpdates)
100
- },
101
- )
102
- unsubFamilyCallbacksByKey.set(family.key, unsubscribeFromTokenCreation)
103
-
104
- socket.on(`unsub:${family.key}`, fillFamilyUnsubRequest)
105
- } else {
106
- const token = family(subKey)
107
- const jsonToken = getJsonToken(token)
108
- const updateToken = getUpdateToken(token)
109
- socket.emit(`init:${token.key}`, getFromStore(jsonToken, store))
110
- const unsubscribe = subscribeToState(
111
- updateToken,
112
- ({ newValue }) => {
113
- socket.emit(`next:${token.key}`, newValue)
114
- },
115
- `expose-family:${family.key}:${socket.id}`,
116
- store,
117
- )
118
- unsubSingleCallbacksByKey.set(token.key, unsubscribe)
119
- socket.on(`unsub:${token.key}`, () => {
120
- fillSingleUnsubRequest(token.key)
121
- })
122
64
  }
123
65
  }
124
66
 
@@ -126,14 +68,10 @@ export function realtimeMutableFamilyProvider({
126
68
 
127
69
  return () => {
128
70
  socket.off(`sub:${family.key}`, fillSubRequest)
129
- for (const [, unsub] of unsubFamilyCallbacksByKey) {
130
- unsub()
131
- }
132
- for (const [, unsub] of unsubSingleCallbacksByKey) {
71
+ for (const [, unsub] of unsubCallbacksByKey) {
133
72
  unsub()
134
73
  }
135
- unsubFamilyCallbacksByKey.clear()
136
- unsubSingleCallbacksByKey.clear()
74
+ unsubCallbacksByKey.clear()
137
75
  }
138
76
  }
139
77
  }
@@ -1,2 +1,5 @@
1
- export * from "./server-user-store"
1
+ export * from "./realtime-continuity-store"
2
+ export * from "./server-room-external-actions"
3
+ export * from "./server-room-external-store"
2
4
  export * from "./server-sync-store"
5
+ export * from "./server-user-store"
@@ -0,0 +1,109 @@
1
+ import { selectorFamily } from "atom.io"
2
+ import type { TransactionUpdate } from "atom.io"
3
+ import { IMPLICIT, getJsonToken, getUpdateToken } from "atom.io/internal"
4
+ import type { JsonIO } from "atom.io/json"
5
+ import { SyncGroup } from "atom.io/realtime"
6
+ // import { completeUpdateAtoms } from "atom.io/realtime-server"
7
+
8
+ const redactorAtoms = selectorFamily<
9
+ (update: TransactionUpdate<any>) => TransactionUpdate<any>,
10
+ { userId: string; syncGroupKey: string }
11
+ >({
12
+ key: `perspectiveRedactor`,
13
+ get:
14
+ ({ userId, syncGroupKey }) =>
15
+ ({ get, find }) => {
16
+ const syncGroup = SyncGroup.existing.get(syncGroupKey)
17
+ if (!syncGroup) {
18
+ throw new Error(
19
+ `Tried to create a synchronizer for a sync group that does not exist.`,
20
+ )
21
+ }
22
+
23
+ const userPerspectiveTokens = syncGroup.perspectives.flatMap(
24
+ ({ viewAtoms }) => {
25
+ const userPerspectiveToken = find(viewAtoms, userId)
26
+ const userPerspective = get(userPerspectiveToken)
27
+ const visibleTokens = [...userPerspective].map((token) => {
28
+ return token.type === `mutable_atom`
29
+ ? getUpdateToken(token).key
30
+ : token.key
31
+ })
32
+ IMPLICIT.STORE.logger.info(
33
+ `🔭`,
34
+ `continuity`,
35
+ syncGroupKey,
36
+ `${userId} can see ${visibleTokens.length} tokens in ${viewAtoms.key}`,
37
+ visibleTokens,
38
+ )
39
+ return visibleTokens
40
+ },
41
+ )
42
+
43
+ const filterTransactionUpdate = (
44
+ visible: string[],
45
+ transactionUpdate: TransactionUpdate<any>,
46
+ ): TransactionUpdate<any> => {
47
+ IMPLICIT.STORE.logger.info(
48
+ `🖌`,
49
+ `continuity`,
50
+ syncGroupKey,
51
+ `redacting updates from ${transactionUpdate.epoch}:${transactionUpdate.key}:${transactionUpdate.id}`,
52
+ visible,
53
+ transactionUpdate.updates,
54
+ )
55
+ const updates = transactionUpdate.updates
56
+ .filter((update) => {
57
+ if (`newValue` in update) {
58
+ return visible.includes(update.key)
59
+ }
60
+ return true
61
+ })
62
+ .map((update) => {
63
+ if (`updates` in update) {
64
+ return filterTransactionUpdate(visible, update)
65
+ }
66
+ return update
67
+ })
68
+ const filtered: TransactionUpdate<any> = {
69
+ ...transactionUpdate,
70
+ updates,
71
+ }
72
+ return filtered
73
+ }
74
+ const filter: (updates: TransactionUpdate<any>) => TransactionUpdate<any> =
75
+ (update) => {
76
+ const visibleKeys: string[] = syncGroup.globals.map((atomToken) =>
77
+ atomToken.type === `mutable_atom`
78
+ ? getUpdateToken(atomToken).key
79
+ : atomToken.key,
80
+ )
81
+ visibleKeys.push(...userPerspectiveTokens)
82
+ return filterTransactionUpdate(visibleKeys, update)
83
+ }
84
+ return filter
85
+ },
86
+ })
87
+ // export const occludedUpdateSelectors = selectorFamily<
88
+ // Pick<
89
+ // TransactionUpdate<JsonIO>,
90
+ // `epoch` | `id` | `key` | `output` | `updates`
91
+ // > | null,
92
+ // { userId: string; syncGroupKey: string; updateId: string }
93
+ // >({
94
+ // key: `occludedUpdate`,
95
+ // get:
96
+ // ({ userId, syncGroupKey, updateId }) =>
97
+ // ({ get, find }) => {
98
+ // const updateState = find(completeUpdateAtoms, updateId)
99
+ // const update = get(updateState)
100
+ // const redactorKey = { userId, syncGroupKey }
101
+ // const redactorState = find(redactorAtoms, redactorKey)
102
+ // const redact = get(redactorState)
103
+ // if (update) {
104
+ // // return redact(update)
105
+ // return update
106
+ // }
107
+ // return null
108
+ // },
109
+ // })
@@ -0,0 +1,64 @@
1
+ import * as AtomIO from "atom.io"
2
+ import type { Loadable } from "atom.io/data"
3
+ import type { UserInRoomMeta } from "atom.io/realtime"
4
+ import { roomIndex, usersInRooms } from "atom.io/realtime"
5
+
6
+ import type { ChildSocket } from "../ipc-sockets"
7
+ import type { RoomArguments } from "./server-room-external-store"
8
+ import { roomArgumentsAtoms, roomSelectors } from "./server-room-external-store"
9
+
10
+ export const createRoomTX = AtomIO.transaction<
11
+ (
12
+ roomId: string,
13
+ script: string,
14
+ options?: string[],
15
+ ) => Loadable<ChildSocket<any, any>>
16
+ >({
17
+ key: `createRoom`,
18
+ do: ({ get, set, find }, roomId, script, options) => {
19
+ const args: RoomArguments = options ? [script, options] : [script]
20
+ const roomArgumentsState = find(roomArgumentsAtoms, roomId)
21
+ set(roomArgumentsState, args)
22
+ set(roomIndex, (s) => s.add(roomId))
23
+ const roomState = find(roomSelectors, roomId)
24
+ const room = get(roomState)
25
+ return room
26
+ },
27
+ })
28
+ export type CreateRoomIO = AtomIO.TransactionIO<typeof createRoomTX>
29
+
30
+ export const joinRoomTX = AtomIO.transaction<
31
+ (roomId: string, userId: string, enteredAtEpoch: number) => UserInRoomMeta
32
+ >({
33
+ key: `joinRoom`,
34
+ do: (transactors, roomId, userId, enteredAtEpoch) => {
35
+ const meta = { enteredAtEpoch }
36
+ usersInRooms.transact(transactors, ({ relations }) => {
37
+ relations.set(roomId, userId, meta)
38
+ })
39
+ return meta
40
+ },
41
+ })
42
+ export type JoinRoomIO = AtomIO.TransactionIO<typeof joinRoomTX>
43
+
44
+ export const leaveRoomTX = AtomIO.transaction<
45
+ (roomId: string, userId: string) => void
46
+ >({
47
+ key: `leaveRoom`,
48
+ do: (transactors, roomId, userId) => {
49
+ usersInRooms.transact(transactors, ({ relations }) => {
50
+ relations.delete({ room: roomId, user: userId })
51
+ })
52
+ },
53
+ })
54
+ export type LeaveRoomIO = AtomIO.TransactionIO<typeof leaveRoomTX>
55
+
56
+ export const destroyRoomTX = AtomIO.transaction<(roomId: string) => void>({
57
+ key: `destroyRoom`,
58
+ do: (transactors, roomId) => {
59
+ usersInRooms.transact(transactors, ({ relations }) => {
60
+ relations.delete({ room: roomId })
61
+ })
62
+ transactors.set(roomIndex, (s) => (s.delete(roomId), s))
63
+ },
64
+ })
@@ -0,0 +1,42 @@
1
+ import type { ChildProcessWithoutNullStreams } from "child_process"
2
+ import { spawn } from "child_process"
3
+
4
+ import { atomFamily, selectorFamily } from "atom.io"
5
+ import type { Loadable } from "atom.io/data"
6
+ import { ChildSocket } from "../ipc-sockets"
7
+
8
+ export type RoomArguments =
9
+ | [script: string, options: string[]]
10
+ | [script: string]
11
+
12
+ export const roomArgumentsAtoms = atomFamily<RoomArguments, string>({
13
+ key: `roomArguments`,
14
+ default: [`echo`, [`Hello World!`]],
15
+ })
16
+
17
+ export const roomSelectors = selectorFamily<
18
+ Loadable<ChildSocket<any, any>>,
19
+ string
20
+ >({
21
+ key: `room`,
22
+ get:
23
+ (roomId) =>
24
+ async ({ get, find }) => {
25
+ const argumentsState = find(roomArgumentsAtoms, roomId)
26
+ const args = get(argumentsState)
27
+ const [script, options] = args
28
+ const child = await new Promise<ChildProcessWithoutNullStreams>(
29
+ (resolve) => {
30
+ const room = spawn(script, options, { env: process.env })
31
+ const resolver = (data: Buffer) => {
32
+ if (data.toString() === `✨`) {
33
+ room.stdout.off(`data`, resolver)
34
+ resolve(room)
35
+ }
36
+ }
37
+ room.stdout.on(`data`, resolver)
38
+ },
39
+ )
40
+ return new ChildSocket(child, roomId)
41
+ },
42
+ })
@@ -1,115 +1,68 @@
1
1
  import type { TransactionUpdate, TransactionUpdateContent } from "atom.io"
2
2
  import { atomFamily, selectorFamily } from "atom.io"
3
- import { SyncGroup } from "~/packages/atom.io/__unstable__/realtime-server-next/create-realtime-sync-group"
4
- import { usersOfSockets } from "./server-user-store"
5
3
 
6
- export const completeUpdateAtoms = atomFamily<
7
- TransactionUpdate<any> | null,
8
- string
9
- >({
10
- key: `completeUpdate`,
11
- default: null,
12
- })
4
+ // export const completeUpdateAtoms = atomFamily<
5
+ // TransactionUpdate<any> | null,
6
+ // string
7
+ // >({
8
+ // key: `completeUpdate`,
9
+ // default: null,
10
+ // })
11
+
12
+ export function redactTransactionUpdateContent(
13
+ visibleStateKeys: string[],
14
+ updates: TransactionUpdateContent[],
15
+ ): TransactionUpdateContent[] {
16
+ return updates
17
+ .map((update): TransactionUpdateContent => {
18
+ if (`newValue` in update) {
19
+ return update
20
+ }
21
+ const redacted = redactTransactionUpdateContent(
22
+ visibleStateKeys,
23
+ update.updates,
24
+ )
25
+ return { ...update, updates: redacted }
26
+ })
27
+ .filter((update) => {
28
+ if (`newValue` in update) {
29
+ return visibleStateKeys.includes(update.key)
30
+ }
31
+ return true
32
+ })
33
+ }
13
34
 
14
- export const transactionRedactorAtoms = atomFamily<
35
+ export const actionOcclusionAtoms = atomFamily<
15
36
  {
16
- filter: (updates: TransactionUpdateContent[]) => TransactionUpdateContent[]
37
+ occlude: (updates: TransactionUpdateContent[]) => TransactionUpdateContent[]
17
38
  },
18
39
  string
19
40
  >({
20
41
  key: `transactionRedactor`,
21
- default: { filter: (updates) => updates },
42
+ default: { occlude: (updates) => updates },
22
43
  })
23
- export const redactedUpdateSelectors = selectorFamily<
24
- TransactionUpdate<any> | null,
25
- [transactionKey: string, updateId: string]
26
- >({
27
- key: `redactedUpdate`,
28
- get:
29
- ([transactionKey, updateId]) =>
30
- ({ get, find }) => {
31
- const update = get(find(completeUpdateAtoms, updateId))
32
- const { filter } = get(find(transactionRedactorAtoms, transactionKey))
44
+ // export const redactedUpdateSelectors = selectorFamily<
45
+ // TransactionUpdate<any> | null,
46
+ // [transactionKey: string, updateId: string]
47
+ // >({
48
+ // key: `redactedUpdate`,
49
+ // get:
50
+ // ([transactionKey, updateId]) =>
51
+ // ({ get, find }) => {
52
+ // const update = get(find(completeUpdateAtoms, updateId))
53
+ // const { filter } = get(find(transactionRedactorAtoms, transactionKey))
33
54
 
34
- if (update && filter) {
35
- return { ...update, updates: filter(update.updates) }
36
- }
37
- return null
38
- },
39
- })
55
+ // if (update && filter) {
56
+ // return { ...update, updates: filter(update.updates) }
57
+ // }
58
+ // return null
59
+ // },
60
+ // })
40
61
 
41
- export const userUnacknowledgedUpdatesAtoms = atomFamily<
42
- TransactionUpdate<any>[],
62
+ export const userUnacknowledgedQueues = atomFamily<
63
+ Pick<TransactionUpdate<any>, `epoch` | `id` | `key` | `output` | `updates`>[],
43
64
  string
44
65
  >({
45
66
  key: `unacknowledgedUpdates`,
46
67
  default: () => [],
47
68
  })
48
-
49
- export const socketUnacknowledgedUpdatesSelectors = selectorFamily<
50
- TransactionUpdate<any>[],
51
- string
52
- >({
53
- key: `socketUnacknowledgedUpdates`,
54
- get:
55
- (socketId) =>
56
- ({ get, find }) => {
57
- const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
58
- const userKey = get(userKeyState)
59
- if (!userKey) {
60
- return []
61
- }
62
- const unacknowledgedUpdatesState = find(
63
- userUnacknowledgedUpdatesAtoms,
64
- userKey,
65
- )
66
- const unacknowledgedUpdates = get(unacknowledgedUpdatesState)
67
- return unacknowledgedUpdates
68
- },
69
- set:
70
- (socketId) =>
71
- ({ set, get, find }, newUpdates) => {
72
- const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
73
- const userKey = get(userKeyState)
74
- if (!userKey) {
75
- return
76
- }
77
- const unacknowledgedUpdatesState = find(
78
- userUnacknowledgedUpdatesAtoms,
79
- userKey,
80
- )
81
- set(unacknowledgedUpdatesState, newUpdates)
82
- },
83
- })
84
-
85
- export const userEpochAtoms = atomFamily<number | null, string>({
86
- key: `clientEpoch`,
87
- default: null,
88
- })
89
-
90
- export const socketEpochSelectors = selectorFamily<number | null, string>({
91
- key: `socketEpoch`,
92
- get:
93
- (socketId) =>
94
- ({ get, find }) => {
95
- const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
96
- const userKey = get(userKeyState)
97
- if (!userKey) {
98
- return null
99
- }
100
- const userEpochState = find(userEpochAtoms, userKey)
101
- const userEpoch = get(userEpochState)
102
- return userEpoch
103
- },
104
- set:
105
- (socketId) =>
106
- ({ set, get, find }, newEpoch) => {
107
- const userKeyState = find(usersOfSockets.states.userKeyOfSocket, socketId)
108
- const userKey = get(userKeyState)
109
- if (!userKey) {
110
- return
111
- }
112
- const userEpochState = find(userEpochAtoms, userKey)
113
- set(userEpochState, newEpoch)
114
- },
115
- })