@@ -14,7 +14,7 @@ function getGlobalThis() {
14
14
}
15
15
16
16
/**
17
- * @returns {{ ee: EventEmitter; sink: Sink; } }
17
+ * @returns {{ ee: EventEmitter; sink: Sink; bridge?: import("@podium/bridge").PodiumBridge } }
18
18
*/
19
19
function getGlobalObjects ( ) {
20
20
let objs = getGlobalThis ( ) [ '@podium' ] ;
@@ -38,9 +38,10 @@ function getGlobalObjects() {
38
38
39
39
export default class MessageBus {
40
40
constructor ( ) {
41
- const { ee, sink } = getGlobalObjects ( ) ;
41
+ const { ee, sink, bridge } = getGlobalObjects ( ) ;
42
42
this . ee = ee ;
43
43
this . sink = sink ;
44
+ this . bridge = bridge ;
44
45
}
45
46
46
47
/**
@@ -81,9 +82,35 @@ export default class MessageBus {
81
82
const event = new Event ( channel , topic , payload ) ;
82
83
this . ee . emit ( event . toKey ( ) , event ) ;
83
84
this . sink . push ( event ) ;
85
+ if ( this . bridge ) {
86
+ /** @type {T | T[] } */
87
+ let params = payload ;
88
+
89
+ if ( typeof payload !== 'undefined' ) {
90
+ // JSON RPC 2.0 requires that params is either an object or an array. Wrap primitives in an an array.
91
+ const isPrimitive =
92
+ typeof params === 'string' ||
93
+ typeof params === 'boolean' ||
94
+ typeof params === 'number' ;
95
+ if ( isPrimitive ) {
96
+ params = [ payload ] ;
97
+ }
98
+ }
99
+
100
+ this . bridge . notification ( {
101
+ method : `${ channel } /${ topic } ` ,
102
+ params,
103
+ } ) ;
104
+ }
84
105
return event ;
85
106
}
86
107
108
+ /**
109
+ * Saves a reference to the event handlers that wrap the API for @podium/bridge, so we can unsubscribe later.
110
+ * @type {Map<MessageHandler<any>, import('@podium/bridge').EventHandler<any>> }
111
+ */
112
+ #bridgeMap = new Map ( ) ;
113
+
87
114
/**
88
115
* Subscribe to messages for a channel and topic.
89
116
*
@@ -101,6 +128,28 @@ export default class MessageBus {
101
128
* ```
102
129
*/
103
130
subscribe ( channel , topic , listener ) {
131
+ if ( this . bridge ) {
132
+ // If there's a bridge, add a listener for the channel and topic there
133
+ // and translate incoming messages to a @podium /browser Event for the
134
+ // same API surface in userland.
135
+
136
+ /** @type {import('@podium/bridge').EventHandler<T> } */
137
+ const bridgeListener = ( message ) => {
138
+ const request =
139
+ /** @type {import("@podium/bridge").RpcRequest<T> } */ (
140
+ message
141
+ ) ;
142
+
143
+ const event = new Event ( channel , topic , request . params ) ;
144
+ this . sink . push ( event ) ;
145
+ listener ( event ) ;
146
+ } ;
147
+ this . bridge . on ( `${ channel } /${ topic } ` , bridgeListener ) ;
148
+
149
+ // Save a reference to the bridgeListener so we can unsubscribe later.
150
+ this . #bridgeMap. set ( listener , bridgeListener ) ;
151
+ }
152
+
104
153
this . ee . on ( toKey ( channel , topic ) , listener ) ;
105
154
}
106
155
@@ -126,5 +175,12 @@ export default class MessageBus {
126
175
*/
127
176
unsubscribe ( channel , topic , listener ) {
128
177
this . ee . off ( toKey ( channel , topic ) , listener ) ;
178
+
179
+ if ( this . bridge ) {
180
+ const bridgeListener = this . #bridgeMap. get ( listener ) ;
181
+ if ( bridgeListener ) {
182
+ this . bridge . off ( `${ channel } /${ topic } ` , bridgeListener ) ;
183
+ }
184
+ }
129
185
}
130
186
}
0 commit comments