atom.io 0.40.6 → 0.40.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/data/index.d.ts +1 -1
- package/dist/employ-socket-D6wgByWh.js +12 -0
- package/dist/employ-socket-D6wgByWh.js.map +1 -0
- package/dist/has-role-hv4-hJMw.js +1149 -0
- package/dist/has-role-hv4-hJMw.js.map +1 -0
- package/dist/internal/index.d.ts +248 -248
- package/dist/internal/index.d.ts.map +1 -1
- package/dist/internal/index.js +570 -1712
- package/dist/internal/index.js.map +1 -1
- package/dist/introspection/index.d.ts +1 -1
- package/dist/is-fn-DY1wZ-md.js +10 -0
- package/dist/is-fn-DY1wZ-md.js.map +1 -0
- package/dist/main/index.d.ts +33 -33
- package/dist/main/index.d.ts.map +1 -1
- package/dist/main/index.js +2 -2
- package/dist/main/index.js.map +1 -1
- package/dist/mutex-store-CSvxY9i3.js +11 -0
- package/dist/mutex-store-CSvxY9i3.js.map +1 -0
- package/dist/react/index.d.ts +5 -5
- package/dist/react/index.d.ts.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/dist/react-devtools/index.js +7 -7
- package/dist/react-devtools/index.js.map +1 -1
- package/dist/realtime/index.d.ts +7 -15
- package/dist/realtime/index.d.ts.map +1 -1
- package/dist/realtime/index.js +3 -33
- package/dist/realtime/index.js.map +1 -1
- package/dist/realtime-client/index.d.ts +5 -5
- package/dist/realtime-client/index.d.ts.map +1 -1
- package/dist/realtime-client/index.js +92 -69
- package/dist/realtime-client/index.js.map +1 -1
- package/dist/realtime-react/index.d.ts +17 -10
- package/dist/realtime-react/index.d.ts.map +1 -1
- package/dist/realtime-react/index.js +41 -41
- package/dist/realtime-react/index.js.map +1 -1
- package/dist/realtime-server/index.d.ts +60 -53
- package/dist/realtime-server/index.d.ts.map +1 -1
- package/dist/realtime-server/index.js +592 -485
- package/dist/realtime-server/index.js.map +1 -1
- package/dist/realtime-testing/index.d.ts +1 -2
- package/dist/realtime-testing/index.d.ts.map +1 -1
- package/dist/realtime-testing/index.js +25 -18
- package/dist/realtime-testing/index.js.map +1 -1
- package/dist/shared-room-store-COGGKqes.js +32 -0
- package/dist/shared-room-store-COGGKqes.js.map +1 -0
- package/dist/shared-room-store-D2o4ZLjC.d.ts +15 -0
- package/dist/shared-room-store-D2o4ZLjC.d.ts.map +1 -0
- package/dist/web/index.d.ts +3 -3
- package/dist/web/index.d.ts.map +1 -1
- package/dist/web/index.js +4 -3
- package/dist/web/index.js.map +1 -1
- package/package.json +12 -12
- package/src/internal/atom/create-regular-atom.ts +5 -4
- package/src/internal/atom/dispose-atom.ts +7 -2
- package/src/internal/atom/has-role.ts +3 -3
- package/src/internal/caching.ts +4 -2
- package/src/internal/families/create-readonly-held-selector-family.ts +2 -1
- package/src/internal/families/create-readonly-pure-selector-family.ts +5 -2
- package/src/internal/families/create-regular-atom-family.ts +2 -1
- package/src/internal/families/create-writable-held-selector-family.ts +2 -1
- package/src/internal/families/create-writable-pure-selector-family.ts +5 -2
- package/src/internal/families/dispose-from-store.ts +4 -4
- package/src/internal/families/find-in-store.ts +10 -10
- package/src/internal/families/get-family-of-token.ts +2 -2
- package/src/internal/families/index.ts +1 -0
- package/src/internal/families/mint-in-store.ts +54 -19
- package/src/internal/families/seek-in-store.ts +1 -1
- package/src/internal/get-state/get-fallback.ts +2 -2
- package/src/internal/get-state/get-from-store.ts +5 -5
- package/src/internal/get-state/read-or-compute-value.ts +1 -1
- package/src/internal/get-state/reduce-reference.ts +8 -6
- package/src/internal/index.ts +2 -220
- package/src/internal/molecule.ts +1 -2
- package/src/internal/mutable/create-mutable-atom-family.ts +3 -2
- package/src/internal/mutable/create-mutable-atom.ts +4 -2
- package/src/internal/mutable/get-json-family.ts +1 -1
- package/src/internal/mutable/get-update-family.ts +1 -1
- package/src/internal/mutable/tracker-family.ts +2 -1
- package/src/internal/mutable/tracker.ts +5 -8
- package/src/internal/safe-compute.ts +1 -1
- package/src/internal/selector/create-readonly-held-selector.ts +2 -1
- package/src/internal/selector/create-readonly-pure-selector.ts +2 -1
- package/src/internal/selector/create-writable-held-selector.ts +2 -1
- package/src/internal/selector/create-writable-pure-selector.ts +2 -1
- package/src/internal/selector/dispose-selector.ts +3 -2
- package/src/internal/selector/register-selector.ts +8 -5
- package/src/internal/selector/trace-selector-atoms.ts +2 -1
- package/src/internal/set-state/dispatch-state-update.ts +3 -2
- package/src/internal/set-state/evict-downstream.ts +1 -1
- package/src/internal/set-state/operate-on-store.ts +16 -22
- package/src/internal/set-state/reset-atom-or-selector.ts +5 -3
- package/src/internal/set-state/reset-in-store.ts +5 -5
- package/src/internal/set-state/set-atom-or-selector.ts +2 -2
- package/src/internal/set-state/set-atom.ts +4 -2
- package/src/internal/set-state/set-into-store.ts +21 -39
- package/src/internal/set-state/set-selector.ts +3 -2
- package/src/internal/state-types.ts +228 -0
- package/src/internal/store/deposit.ts +4 -4
- package/src/internal/store/index.ts +0 -1
- package/src/internal/store/store.ts +9 -9
- package/src/internal/store/withdraw.ts +4 -4
- package/src/internal/subscribe/recall-state.ts +1 -1
- package/src/internal/subscribe/subscribe-to-root-atoms.ts +1 -12
- package/src/internal/subscribe/subscribe-to-transaction.ts +3 -2
- package/src/internal/transaction/build-transaction.ts +3 -2
- package/src/internal/transaction/index.ts +1 -23
- package/src/internal/transaction/is-root-store.ts +4 -1
- package/src/internal/transaction/transaction-meta-progress.ts +22 -0
- package/src/main/atom.ts +1 -2
- package/src/main/find-state.ts +5 -5
- package/src/main/get-state.ts +4 -4
- package/src/main/realm.ts +2 -2
- package/src/main/set-state.ts +10 -10
- package/src/react/parse-state-overloads.ts +3 -3
- package/src/react/use-i.ts +6 -4
- package/src/react/use-loadable.ts +4 -10
- package/src/react/use-o.ts +6 -4
- package/src/react-devtools/store.ts +6 -6
- package/src/realtime/index.ts +1 -0
- package/src/realtime/mutex-store.ts +11 -0
- package/src/realtime/realtime-continuity.ts +1 -5
- package/src/realtime-client/pull-atom-family-member.ts +14 -17
- package/src/realtime-client/pull-atom.ts +1 -1
- package/src/realtime-client/pull-mutable-atom-family-member.ts +16 -12
- package/src/realtime-client/pull-selector-family-member.ts +8 -35
- package/src/realtime-client/pull-selector-roots.ts +90 -0
- package/src/realtime-client/pull-selector.ts +2 -27
- package/src/realtime-client/push-state.ts +33 -5
- package/src/realtime-client/realtime-client-stores/client-main-store.ts +2 -5
- package/src/realtime-react/index.ts +2 -1
- package/src/realtime-react/realtime-context.tsx +9 -5
- package/src/realtime-react/use-pull-atom-family-member.ts +2 -3
- package/src/realtime-react/use-pull-mutable-family-member.ts +2 -3
- package/src/realtime-react/use-pull-selector-family-member.ts +5 -6
- package/src/realtime-react/use-push.ts +7 -3
- package/src/realtime-react/use-realtime-service.ts +11 -11
- package/src/realtime-react/use-single-effect.ts +11 -14
- package/src/realtime-server/{realtime-server-stores/server-sync-store.ts → continuity/continuity-store.ts} +1 -1
- package/src/realtime-server/continuity/prepare-to-sync-realtime-continuity.ts +1 -1
- package/src/realtime-server/continuity/prepare-to-track-client-acknowledgement.ts +3 -5
- package/src/realtime-server/continuity/subscribe-to-continuity-actions.ts +1 -1
- package/src/realtime-server/employ-socket.ts +14 -0
- package/src/realtime-server/index.ts +2 -20
- package/src/realtime-server/ipc-sockets/child-socket.ts +125 -66
- package/src/realtime-server/ipc-sockets/custom-socket.ts +16 -14
- package/src/realtime-server/ipc-sockets/parent-socket.ts +81 -58
- package/src/realtime-server/realtime-family-provider.ts +78 -29
- package/src/realtime-server/realtime-mutable-family-provider.ts +80 -31
- package/src/realtime-server/realtime-mutable-provider.ts +30 -22
- package/src/realtime-server/realtime-server-stores/index.ts +0 -2
- package/src/realtime-server/realtime-server-stores/server-room-external-store.ts +77 -36
- package/src/realtime-server/realtime-server-stores/server-user-store.ts +12 -1
- package/src/realtime-server/realtime-state-provider.ts +30 -29
- package/src/realtime-server/realtime-state-receiver.ts +62 -16
- package/src/realtime-server/server-config.ts +9 -0
- package/src/realtime-server/socket-interface.ts +14 -0
- package/src/realtime-testing/setup-realtime-test.tsx +56 -23
- package/src/web/index.ts +1 -1
- package/src/web/{persist-sync.ts → storage-sync.ts} +5 -2
- package/src/internal/store/mint-or-counterfeit.ts +0 -108
- package/src/realtime-react/on-mount.ts +0 -5
- package/src/realtime-server/realtime-server-stores/server-room-external-actions.ts +0 -79
|
@@ -1,17 +1,20 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream"
|
|
2
|
+
|
|
1
3
|
import { Subject } from "atom.io/internal"
|
|
2
4
|
import type { Json } from "atom.io/json"
|
|
3
5
|
import { parseJson, stringifyJson } from "atom.io/json"
|
|
4
6
|
import { SetRTX } from "atom.io/transceivers/set-rtx"
|
|
5
7
|
|
|
6
|
-
import type {
|
|
8
|
+
import type { StderrLog } from "./child-socket"
|
|
9
|
+
import type { EventBuffer, EventPayload, Events } from "./custom-socket"
|
|
7
10
|
import { CustomSocket } from "./custom-socket"
|
|
8
11
|
|
|
9
12
|
export class SubjectSocket<
|
|
10
13
|
I extends Events,
|
|
11
14
|
O extends Events,
|
|
12
15
|
> extends CustomSocket<I, O> {
|
|
13
|
-
public in: Subject<
|
|
14
|
-
public out: Subject<
|
|
16
|
+
public in: Subject<EventPayload<I>>
|
|
17
|
+
public out: Subject<EventPayload<O>>
|
|
15
18
|
public id = `no_id_retrieved`
|
|
16
19
|
public disposalFunctions: (() => void)[] = []
|
|
17
20
|
|
|
@@ -24,7 +27,7 @@ export class SubjectSocket<
|
|
|
24
27
|
this.in = new Subject()
|
|
25
28
|
this.out = new Subject()
|
|
26
29
|
this.in.subscribe(`socket`, (event) => {
|
|
27
|
-
this.handleEvent(...
|
|
30
|
+
this.handleEvent(...event)
|
|
28
31
|
})
|
|
29
32
|
}
|
|
30
33
|
|
|
@@ -35,18 +38,27 @@ export class SubjectSocket<
|
|
|
35
38
|
}
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
export type ParentProcess = {
|
|
42
|
+
pid?: number | undefined
|
|
43
|
+
stdin: Readable
|
|
44
|
+
stdout: Writable
|
|
45
|
+
stderr: Writable
|
|
46
|
+
exit: (code?: number) => void
|
|
47
|
+
}
|
|
48
|
+
|
|
38
49
|
export class ParentSocket<
|
|
39
50
|
I extends Events & {
|
|
40
|
-
[id in string as `relay:${id}`]: [string, ...Json.
|
|
51
|
+
[id in string as `relay:${id}`]: [string, ...Json.Array[]]
|
|
41
52
|
},
|
|
42
53
|
O extends Events & {
|
|
43
|
-
[id in string as `user:${id}`]: [string, ...Json.
|
|
54
|
+
[id in string as `user:${id}`]: [string, ...Json.Array[]]
|
|
44
55
|
} & {
|
|
45
56
|
/* eslint-disable quotes */
|
|
46
57
|
"user-joins": [string]
|
|
47
58
|
"user-leaves": [string]
|
|
48
59
|
/* eslint-enable quotes */
|
|
49
60
|
},
|
|
61
|
+
P extends ParentProcess = ParentProcess,
|
|
50
62
|
> extends CustomSocket<I, O> {
|
|
51
63
|
protected incompleteData = ``
|
|
52
64
|
protected unprocessedEvents: string[] = []
|
|
@@ -54,12 +66,12 @@ export class ParentSocket<
|
|
|
54
66
|
protected relayServices: ((
|
|
55
67
|
socket: SubjectSocket<any, any>,
|
|
56
68
|
) => (() => void) | void)[]
|
|
57
|
-
|
|
69
|
+
public proc: P
|
|
58
70
|
|
|
59
71
|
public id = `#####`
|
|
60
72
|
|
|
61
|
-
protected log(...args:
|
|
62
|
-
this.
|
|
73
|
+
protected log(...args: StderrLog): void {
|
|
74
|
+
this.proc.stderr.write(
|
|
63
75
|
stringifyJson(
|
|
64
76
|
args.map((arg) =>
|
|
65
77
|
arg instanceof SetRTX
|
|
@@ -70,82 +82,93 @@ export class ParentSocket<
|
|
|
70
82
|
)
|
|
71
83
|
}
|
|
72
84
|
public logger = {
|
|
73
|
-
info: (...args:
|
|
85
|
+
info: (...args: Json.Array): void => {
|
|
74
86
|
this.log(`i`, ...args)
|
|
75
87
|
},
|
|
76
|
-
warn: (...args:
|
|
88
|
+
warn: (...args: Json.Array): void => {
|
|
77
89
|
this.log(`w`, ...args)
|
|
78
90
|
},
|
|
79
|
-
error: (...args:
|
|
91
|
+
error: (...args: Json.Array): void => {
|
|
80
92
|
this.log(`e`, ...args)
|
|
81
93
|
},
|
|
82
94
|
}
|
|
83
95
|
|
|
84
|
-
public constructor() {
|
|
96
|
+
public constructor(proc: P) {
|
|
85
97
|
super((event, ...args) => {
|
|
86
98
|
const stringifiedEvent = JSON.stringify([event, ...args])
|
|
87
|
-
this.
|
|
99
|
+
this.proc.stdout.write(stringifiedEvent + `\x03`)
|
|
88
100
|
return this
|
|
89
101
|
})
|
|
90
|
-
this.
|
|
91
|
-
this.
|
|
102
|
+
this.proc = proc
|
|
103
|
+
this.proc.stdin.resume()
|
|
92
104
|
this.relays = new Map()
|
|
93
105
|
this.relayServices = []
|
|
94
|
-
// this.logger.info(`🔗`, `uplink`, process.pid)
|
|
95
106
|
|
|
96
|
-
this.
|
|
107
|
+
this.proc.stdin.on(
|
|
97
108
|
`data`,
|
|
98
|
-
<
|
|
109
|
+
<K extends string & keyof I>(buffer: EventBuffer<I, K>) => {
|
|
99
110
|
const chunk = buffer.toString()
|
|
100
|
-
|
|
101
|
-
const
|
|
102
|
-
this.incompleteData
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
const pieces = chunk.split(`\x03`)
|
|
112
|
+
const initialMaybeWellFormed = pieces[0]
|
|
113
|
+
pieces[0] = this.incompleteData + initialMaybeWellFormed
|
|
114
|
+
let idx = 0
|
|
115
|
+
for (const piece of pieces) {
|
|
116
|
+
if (piece === ``) {
|
|
117
|
+
continue
|
|
118
|
+
}
|
|
119
|
+
try {
|
|
120
|
+
const jsonPiece = parseJson(piece)
|
|
121
|
+
this.logger.info(`🎰`, `received`, jsonPiece)
|
|
122
|
+
this.handleEvent(...(jsonPiece as EventPayload<I>))
|
|
123
|
+
this.incompleteData = ``
|
|
124
|
+
} catch (thrown0) {
|
|
125
|
+
if (thrown0 instanceof Error) {
|
|
126
|
+
this.logger.error(
|
|
127
|
+
[
|
|
128
|
+
`received malformed data from parent process:`,
|
|
129
|
+
``,
|
|
130
|
+
piece,
|
|
131
|
+
``,
|
|
132
|
+
thrown0.message,
|
|
133
|
+
].join(`\n❌\t`),
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
try {
|
|
137
|
+
if (idx === 0) {
|
|
138
|
+
this.incompleteData = piece
|
|
139
|
+
const maybeActualJsonPiece = parseJson(initialMaybeWellFormed)
|
|
140
|
+
this.logger.info(`🎰`, `received`, maybeActualJsonPiece)
|
|
141
|
+
this.handleEvent(...(maybeActualJsonPiece as EventPayload<I>))
|
|
142
|
+
this.incompleteData = ``
|
|
143
|
+
} else {
|
|
144
|
+
this.incompleteData += piece
|
|
145
|
+
}
|
|
146
|
+
} catch (thrown1) {
|
|
147
|
+
if (thrown1 instanceof Error) {
|
|
148
|
+
this.logger.error(
|
|
149
|
+
[
|
|
150
|
+
`received malformed data from parent process:`,
|
|
151
|
+
``,
|
|
152
|
+
initialMaybeWellFormed,
|
|
153
|
+
``,
|
|
154
|
+
thrown1.message,
|
|
155
|
+
].join(`\n❌\t`),
|
|
156
|
+
)
|
|
113
157
|
}
|
|
114
|
-
const parsedEvent = parseJson(event)
|
|
115
|
-
this.handleEvent(...(parsedEvent as [string, ...I[keyof I]]))
|
|
116
158
|
}
|
|
117
159
|
}
|
|
118
|
-
|
|
119
|
-
} catch (thrown) {
|
|
120
|
-
if (thrown instanceof Error) {
|
|
121
|
-
this.logger.error(`❗`, thrown.message, thrown.cause, thrown.stack)
|
|
122
|
-
}
|
|
160
|
+
++idx
|
|
123
161
|
}
|
|
124
162
|
},
|
|
125
163
|
)
|
|
126
164
|
|
|
127
165
|
this.on(`exit`, () => {
|
|
128
166
|
this.logger.info(`🔥`, this.id, `received "exit"`)
|
|
129
|
-
|
|
130
|
-
})
|
|
131
|
-
process.on(`exit`, (code) => {
|
|
132
|
-
this.logger.info(`🔥`, this.id, `exited with code ${code}`)
|
|
133
|
-
})
|
|
134
|
-
process.on(`end`, () => {
|
|
135
|
-
this.logger.info(`🔥`, this.id, `ended`)
|
|
136
|
-
process.exit(0)
|
|
137
|
-
})
|
|
138
|
-
process.on(`SIGTERM`, () => {
|
|
139
|
-
this.logger.error(`🔥`, this.id, `terminated`)
|
|
140
|
-
process.exit(0)
|
|
141
|
-
})
|
|
142
|
-
process.on(`SIGINT`, () => {
|
|
143
|
-
this.logger.error(`🔥`, this.id, `interrupted`)
|
|
144
|
-
process.exit(0)
|
|
167
|
+
this.proc.exit(0)
|
|
145
168
|
})
|
|
146
169
|
|
|
147
|
-
if (
|
|
148
|
-
this.id =
|
|
170
|
+
if (this.proc.pid) {
|
|
171
|
+
this.id = this.proc.pid?.toString()
|
|
149
172
|
}
|
|
150
173
|
|
|
151
174
|
this.on(`user-joins`, (username) => {
|
|
@@ -180,7 +203,7 @@ export class ParentSocket<
|
|
|
180
203
|
}
|
|
181
204
|
})
|
|
182
205
|
|
|
183
|
-
|
|
206
|
+
this.proc.stdout.write(`ALIVE`)
|
|
184
207
|
}
|
|
185
208
|
|
|
186
209
|
public relay(
|
|
@@ -5,10 +5,11 @@ import {
|
|
|
5
5
|
IMPLICIT,
|
|
6
6
|
subscribeToState,
|
|
7
7
|
} from "atom.io/internal"
|
|
8
|
-
import type { Canonical, Json } from "atom.io/json"
|
|
8
|
+
import type { Canonical, Json, stringified } from "atom.io/json"
|
|
9
9
|
import { stringifyJson } from "atom.io/json"
|
|
10
10
|
|
|
11
11
|
import type { ServerConfig } from "."
|
|
12
|
+
import { employSocket } from "./employ-socket"
|
|
12
13
|
|
|
13
14
|
export type FamilyProvider = ReturnType<typeof realtimeAtomFamilyProvider>
|
|
14
15
|
export function realtimeAtomFamilyProvider({
|
|
@@ -22,49 +23,97 @@ export function realtimeAtomFamilyProvider({
|
|
|
22
23
|
family: AtomIO.RegularAtomFamilyToken<J, K>,
|
|
23
24
|
index: AtomIO.ReadableToken<Iterable<K>>,
|
|
24
25
|
): () => void {
|
|
25
|
-
const
|
|
26
|
+
const coreSubscriptions = new Set<() => void>()
|
|
27
|
+
const clearCoreSubscriptions = () => {
|
|
28
|
+
for (const unsub of coreSubscriptions) unsub()
|
|
29
|
+
coreSubscriptions.clear()
|
|
30
|
+
}
|
|
31
|
+
const familyMemberSubscriptionsWanted = new Set<stringified<K>>()
|
|
32
|
+
const familyMemberSubscriptions = new Map<string, () => void>()
|
|
33
|
+
const clearFamilySubscriptions = () => {
|
|
34
|
+
for (const unsub of familyMemberSubscriptions.values()) unsub()
|
|
35
|
+
familyMemberSubscriptions.clear()
|
|
36
|
+
}
|
|
26
37
|
|
|
27
38
|
const fillUnsubRequest = (key: string) => {
|
|
28
|
-
|
|
29
|
-
|
|
39
|
+
const unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`)
|
|
40
|
+
if (unsubUnsub) {
|
|
41
|
+
unsubUnsub()
|
|
42
|
+
familyMemberSubscriptions.delete(`${key}:unsub`)
|
|
43
|
+
}
|
|
44
|
+
const unsub = familyMemberSubscriptions.get(key)
|
|
30
45
|
if (unsub) {
|
|
31
46
|
unsub()
|
|
32
|
-
|
|
47
|
+
familyMemberSubscriptions.delete(key)
|
|
33
48
|
}
|
|
34
49
|
}
|
|
35
50
|
|
|
36
|
-
const
|
|
37
|
-
const
|
|
51
|
+
const exposeFamilyMembers = (subKey: K) => {
|
|
52
|
+
const token = findInStore(store, family, subKey)
|
|
53
|
+
getFromStore(store, token)
|
|
54
|
+
socket.emit(`serve:${token.key}`, getFromStore(store, token))
|
|
55
|
+
familyMemberSubscriptions.set(
|
|
56
|
+
token.key,
|
|
57
|
+
subscribeToState(
|
|
58
|
+
store,
|
|
59
|
+
token,
|
|
60
|
+
`expose-family:${family.key}:${socket.id}`,
|
|
61
|
+
({ newValue }) => {
|
|
62
|
+
socket.emit(`serve:${token.key}`, newValue)
|
|
63
|
+
},
|
|
64
|
+
),
|
|
65
|
+
)
|
|
66
|
+
familyMemberSubscriptions.set(
|
|
67
|
+
`${token.key}:unsub`,
|
|
68
|
+
employSocket(socket, `unsub:${token.key}`, () => {
|
|
69
|
+
fillUnsubRequest(token.key)
|
|
70
|
+
}),
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const isAvailable = (exposedSubKeys: Iterable<K>, subKey: K): boolean => {
|
|
38
75
|
for (const exposedSubKey of exposedSubKeys) {
|
|
39
76
|
if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {
|
|
40
|
-
|
|
41
|
-
socket.emit(`serve:${token.key}`, getFromStore(store, token))
|
|
42
|
-
const unsubscribe = subscribeToState(
|
|
43
|
-
store,
|
|
44
|
-
token,
|
|
45
|
-
`expose-family:${family.key}:${socket.id}`,
|
|
46
|
-
({ newValue }) => {
|
|
47
|
-
socket.emit(`serve:${token.key}`, newValue)
|
|
48
|
-
},
|
|
49
|
-
)
|
|
50
|
-
unsubCallbacksByKey.set(token.key, unsubscribe)
|
|
51
|
-
socket.on(`unsub:${token.key}`, () => {
|
|
52
|
-
fillUnsubRequest(token.key)
|
|
53
|
-
})
|
|
54
|
-
break
|
|
77
|
+
return true
|
|
55
78
|
}
|
|
56
79
|
}
|
|
80
|
+
return false
|
|
57
81
|
}
|
|
58
82
|
|
|
59
|
-
|
|
83
|
+
const start = () => {
|
|
84
|
+
coreSubscriptions.add(
|
|
85
|
+
employSocket(socket, `sub:${family.key}`, (subKey: K) => {
|
|
86
|
+
const exposedSubKeys = getFromStore(store, index)
|
|
87
|
+
const shouldExpose = isAvailable(exposedSubKeys, subKey)
|
|
88
|
+
if (shouldExpose) {
|
|
89
|
+
exposeFamilyMembers(subKey)
|
|
90
|
+
} else {
|
|
91
|
+
familyMemberSubscriptionsWanted.add(stringifyJson(subKey))
|
|
92
|
+
socket.emit(`unavailable:${family.key}`, subKey)
|
|
93
|
+
}
|
|
94
|
+
}),
|
|
95
|
+
)
|
|
96
|
+
coreSubscriptions.add(
|
|
97
|
+
subscribeToState(
|
|
98
|
+
store,
|
|
99
|
+
index,
|
|
100
|
+
`expose-family:${family.key}:${socket.id}`,
|
|
101
|
+
({ newValue: newExposedSubKeys }) => {
|
|
102
|
+
for (const subKey of newExposedSubKeys) {
|
|
103
|
+
if (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {
|
|
104
|
+
exposeFamilyMembers(subKey)
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
),
|
|
109
|
+
)
|
|
110
|
+
}
|
|
60
111
|
|
|
61
|
-
|
|
62
|
-
socket.off(`sub:${family.key}`, fillSubRequest)
|
|
112
|
+
start()
|
|
63
113
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
unsubCallbacksByKey.clear()
|
|
114
|
+
return () => {
|
|
115
|
+
clearCoreSubscriptions()
|
|
116
|
+
clearFamilySubscriptions()
|
|
68
117
|
}
|
|
69
118
|
}
|
|
70
119
|
}
|
|
@@ -8,10 +8,11 @@ import {
|
|
|
8
8
|
IMPLICIT,
|
|
9
9
|
subscribeToState,
|
|
10
10
|
} from "atom.io/internal"
|
|
11
|
-
import type { Canonical } from "atom.io/json"
|
|
11
|
+
import type { Canonical, stringified } from "atom.io/json"
|
|
12
12
|
import { stringifyJson } from "atom.io/json"
|
|
13
13
|
|
|
14
14
|
import type { ServerConfig } from "."
|
|
15
|
+
import { employSocket } from "./employ-socket"
|
|
15
16
|
|
|
16
17
|
export type MutableFamilyProvider = ReturnType<
|
|
17
18
|
typeof realtimeMutableFamilyProvider
|
|
@@ -27,51 +28,99 @@ export function realtimeMutableFamilyProvider({
|
|
|
27
28
|
family: AtomIO.MutableAtomFamilyToken<T, K>,
|
|
28
29
|
index: AtomIO.ReadableToken<Iterable<K>>,
|
|
29
30
|
): () => void {
|
|
30
|
-
const
|
|
31
|
+
const coreSubscriptions = new Set<() => void>()
|
|
32
|
+
const clearCoreSubscriptions = () => {
|
|
33
|
+
for (const unsub of coreSubscriptions) unsub()
|
|
34
|
+
coreSubscriptions.clear()
|
|
35
|
+
}
|
|
36
|
+
const familyMemberSubscriptionsWanted = new Set<stringified<K>>()
|
|
37
|
+
const familyMemberSubscriptions = new Map<string, () => void>()
|
|
38
|
+
const clearFamilySubscriptions = () => {
|
|
39
|
+
for (const unsub of familyMemberSubscriptions.values()) unsub()
|
|
40
|
+
familyMemberSubscriptions.clear()
|
|
41
|
+
}
|
|
31
42
|
|
|
32
43
|
const fillUnsubRequest = (key: string) => {
|
|
33
|
-
|
|
34
|
-
|
|
44
|
+
const unsubUnsub = familyMemberSubscriptions.get(`${key}:unsub`)
|
|
45
|
+
if (unsubUnsub) {
|
|
46
|
+
unsubUnsub()
|
|
47
|
+
familyMemberSubscriptions.delete(`${key}:unsub`)
|
|
48
|
+
}
|
|
49
|
+
const unsub = familyMemberSubscriptions.get(key)
|
|
35
50
|
if (unsub) {
|
|
36
51
|
unsub()
|
|
37
|
-
|
|
52
|
+
familyMemberSubscriptions.delete(key)
|
|
38
53
|
}
|
|
39
54
|
}
|
|
40
55
|
|
|
41
|
-
const
|
|
42
|
-
const
|
|
56
|
+
const exposeFamilyMembers = (subKey: K) => {
|
|
57
|
+
const token = findInStore(store, family, subKey)
|
|
58
|
+
getFromStore(store, token)
|
|
59
|
+
const jsonToken = getJsonToken(store, token)
|
|
60
|
+
const updateToken = getUpdateToken(token)
|
|
61
|
+
socket.emit(`init:${token.key}`, getFromStore(store, jsonToken))
|
|
62
|
+
familyMemberSubscriptions.set(
|
|
63
|
+
token.key,
|
|
64
|
+
subscribeToState(
|
|
65
|
+
store,
|
|
66
|
+
updateToken,
|
|
67
|
+
`expose-family:${family.key}:${socket.id}`,
|
|
68
|
+
({ newValue }) => {
|
|
69
|
+
socket.emit(`next:${token.key}`, newValue)
|
|
70
|
+
},
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
familyMemberSubscriptions.set(
|
|
74
|
+
`${token.key}:unsub`,
|
|
75
|
+
employSocket(socket, `unsub:${token.key}`, () => {
|
|
76
|
+
fillUnsubRequest(token.key)
|
|
77
|
+
}),
|
|
78
|
+
)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const isAvailable = (exposedSubKeys: Iterable<K>, subKey: K): boolean => {
|
|
43
82
|
for (const exposedSubKey of exposedSubKeys) {
|
|
44
83
|
if (stringifyJson(exposedSubKey) === stringifyJson(subKey)) {
|
|
45
|
-
|
|
46
|
-
getFromStore(store, token)
|
|
47
|
-
const jsonToken = getJsonToken(store, token)
|
|
48
|
-
const updateToken = getUpdateToken(token)
|
|
49
|
-
socket.emit(`init:${token.key}`, getFromStore(store, jsonToken))
|
|
50
|
-
const unsubscribe = subscribeToState(
|
|
51
|
-
store,
|
|
52
|
-
updateToken,
|
|
53
|
-
`expose-family:${family.key}:${socket.id}`,
|
|
54
|
-
({ newValue }) => {
|
|
55
|
-
socket.emit(`next:${token.key}`, newValue)
|
|
56
|
-
},
|
|
57
|
-
)
|
|
58
|
-
unsubCallbacksByKey.set(token.key, unsubscribe)
|
|
59
|
-
socket.on(`unsub:${token.key}`, () => {
|
|
60
|
-
fillUnsubRequest(token.key)
|
|
61
|
-
})
|
|
62
|
-
break
|
|
84
|
+
return true
|
|
63
85
|
}
|
|
64
86
|
}
|
|
87
|
+
return false
|
|
65
88
|
}
|
|
66
89
|
|
|
67
|
-
|
|
90
|
+
const start = () => {
|
|
91
|
+
coreSubscriptions.add(
|
|
92
|
+
employSocket(socket, `sub:${family.key}`, (subKey: K) => {
|
|
93
|
+
const exposedSubKeys = getFromStore(store, index)
|
|
94
|
+
const shouldExpose = isAvailable(exposedSubKeys, subKey)
|
|
95
|
+
if (shouldExpose) {
|
|
96
|
+
exposeFamilyMembers(subKey)
|
|
97
|
+
} else {
|
|
98
|
+
familyMemberSubscriptionsWanted.add(stringifyJson(subKey))
|
|
99
|
+
socket.emit(`unavailable:${family.key}`, subKey)
|
|
100
|
+
}
|
|
101
|
+
}),
|
|
102
|
+
)
|
|
103
|
+
coreSubscriptions.add(
|
|
104
|
+
subscribeToState(
|
|
105
|
+
store,
|
|
106
|
+
index,
|
|
107
|
+
`expose-family:${family.key}:${socket.id}`,
|
|
108
|
+
({ newValue: newExposedSubKeys }) => {
|
|
109
|
+
for (const subKey of newExposedSubKeys) {
|
|
110
|
+
if (familyMemberSubscriptionsWanted.has(stringifyJson(subKey))) {
|
|
111
|
+
exposeFamilyMembers(subKey)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
),
|
|
116
|
+
)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
start()
|
|
68
120
|
|
|
69
121
|
return () => {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
unsub()
|
|
73
|
-
}
|
|
74
|
-
unsubCallbacksByKey.clear()
|
|
122
|
+
clearCoreSubscriptions()
|
|
123
|
+
clearFamilySubscriptions()
|
|
75
124
|
}
|
|
76
125
|
}
|
|
77
126
|
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import type { Json } from "atom.io/json"
|
|
11
11
|
|
|
12
12
|
import type { ServerConfig } from "."
|
|
13
|
+
import { employSocket } from "./employ-socket"
|
|
13
14
|
|
|
14
15
|
export type MutableProvider = ReturnType<typeof realtimeMutableProvider>
|
|
15
16
|
export function realtimeMutableProvider({
|
|
@@ -19,35 +20,42 @@ export function realtimeMutableProvider({
|
|
|
19
20
|
return function mutableProvider<
|
|
20
21
|
Core extends Transceiver<any, Json.Serializable, Json.Serializable>,
|
|
21
22
|
>(token: AtomIO.MutableAtomToken<Core>): () => void {
|
|
22
|
-
|
|
23
|
+
const subscriptions = new Set<() => void>()
|
|
24
|
+
const clearSubscriptions = () => {
|
|
25
|
+
for (const unsub of subscriptions) unsub()
|
|
26
|
+
subscriptions.clear()
|
|
27
|
+
}
|
|
23
28
|
|
|
24
29
|
const jsonToken = getJsonToken(store, token)
|
|
25
30
|
const trackerToken = getUpdateToken(token)
|
|
26
31
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
32
|
+
const start = () => {
|
|
33
|
+
subscriptions.add(
|
|
34
|
+
employSocket(socket, `sub:${token.key}`, () => {
|
|
35
|
+
clearSubscriptions()
|
|
36
|
+
socket.emit(`init:${token.key}`, getFromStore(store, jsonToken))
|
|
37
|
+
subscriptions.add(
|
|
38
|
+
subscribeToState(
|
|
39
|
+
store,
|
|
40
|
+
trackerToken,
|
|
41
|
+
`expose-single:${socket.id}`,
|
|
42
|
+
({ newValue }) => {
|
|
43
|
+
socket.emit(`next:${token.key}`, newValue)
|
|
44
|
+
},
|
|
45
|
+
),
|
|
46
|
+
)
|
|
47
|
+
subscriptions.add(
|
|
48
|
+
employSocket(socket, `unsub:${token.key}`, () => {
|
|
49
|
+
clearSubscriptions()
|
|
50
|
+
start()
|
|
51
|
+
}),
|
|
52
|
+
)
|
|
53
|
+
}),
|
|
42
54
|
)
|
|
43
|
-
socket.on(`unsub:${token.key}`, fillUnsubRequest)
|
|
44
55
|
}
|
|
45
56
|
|
|
46
|
-
|
|
57
|
+
start()
|
|
47
58
|
|
|
48
|
-
return
|
|
49
|
-
socket.off(`sub:${token.key}`, fillSubRequest)
|
|
50
|
-
unsubscribeFromStateUpdates?.()
|
|
51
|
-
}
|
|
59
|
+
return clearSubscriptions
|
|
52
60
|
}
|
|
53
61
|
}
|