@signalwire/js 3.7.0 → 3.8.0-dev.202202021245.c33a456.0

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 (96) hide show
  1. package/dist/core/src/BaseComponent.d.ts +28 -30
  2. package/dist/core/src/BaseComponent.d.ts.map +1 -1
  3. package/dist/core/src/BaseSession.d.ts +4 -2
  4. package/dist/core/src/BaseSession.d.ts.map +1 -1
  5. package/dist/core/src/chat/BaseChat.d.ts +1 -1
  6. package/dist/core/src/chat/BaseChat.d.ts.map +1 -1
  7. package/dist/core/src/chat/ChatMessage.d.ts +2 -2
  8. package/dist/core/src/chat/ChatMessage.d.ts.map +1 -1
  9. package/dist/core/src/chat/methods.d.ts +2 -2
  10. package/dist/core/src/chat/methods.d.ts.map +1 -1
  11. package/dist/core/src/chat/workers.d.ts +2 -1
  12. package/dist/core/src/chat/workers.d.ts.map +1 -1
  13. package/dist/core/src/index.d.ts +3 -3
  14. package/dist/core/src/index.d.ts.map +1 -1
  15. package/dist/core/src/internal/BaseBackendSession.d.ts.map +1 -1
  16. package/dist/core/src/internal/InternalRPC.d.ts +7 -7
  17. package/dist/core/src/internal/InternalRPC.d.ts.map +1 -1
  18. package/dist/core/src/redux/actions.d.ts +15 -14
  19. package/dist/core/src/redux/actions.d.ts.map +1 -1
  20. package/dist/core/src/redux/features/component/componentSlice.d.ts +3952 -10
  21. package/dist/core/src/redux/features/component/componentSlice.d.ts.map +1 -1
  22. package/dist/core/src/redux/features/executeQueue/executeQueueSlice.d.ts +44 -7
  23. package/dist/core/src/redux/features/executeQueue/executeQueueSlice.d.ts.map +1 -1
  24. package/dist/core/src/redux/features/pubSub/pubSubSaga.d.ts.map +1 -1
  25. package/dist/core/src/redux/features/session/sessionSlice.d.ts +74 -8
  26. package/dist/core/src/redux/features/session/sessionSlice.d.ts.map +1 -1
  27. package/dist/core/src/redux/index.d.ts +9 -25
  28. package/dist/core/src/redux/index.d.ts.map +1 -1
  29. package/dist/core/src/redux/interfaces.d.ts +4 -3
  30. package/dist/core/src/redux/interfaces.d.ts.map +1 -1
  31. package/dist/core/src/redux/rootReducer.d.ts +417 -3
  32. package/dist/core/src/redux/rootReducer.d.ts.map +1 -1
  33. package/dist/core/src/redux/rootSaga.d.ts +11 -2
  34. package/dist/core/src/redux/rootSaga.d.ts.map +1 -1
  35. package/dist/core/src/redux/toolkit/configureStore.d.ts +77 -0
  36. package/dist/core/src/redux/toolkit/configureStore.d.ts.map +1 -0
  37. package/dist/core/src/redux/toolkit/createAction.d.ts +180 -0
  38. package/dist/core/src/redux/toolkit/createAction.d.ts.map +1 -0
  39. package/dist/core/src/redux/toolkit/createReducer.d.ts +42 -0
  40. package/dist/core/src/redux/toolkit/createReducer.d.ts.map +1 -0
  41. package/dist/core/src/redux/toolkit/createSlice.d.ts +142 -0
  42. package/dist/core/src/redux/toolkit/createSlice.d.ts.map +1 -0
  43. package/dist/core/src/redux/toolkit/devtoolsExtension.d.ts +185 -0
  44. package/dist/core/src/redux/toolkit/devtoolsExtension.d.ts.map +1 -0
  45. package/dist/core/src/redux/toolkit/getDefaultMiddleware.d.ts +12 -0
  46. package/dist/core/src/redux/toolkit/getDefaultMiddleware.d.ts.map +1 -0
  47. package/dist/core/src/redux/toolkit/index.d.ts +13 -0
  48. package/dist/core/src/redux/toolkit/index.d.ts.map +1 -0
  49. package/dist/core/src/redux/toolkit/isPlainObject.d.ts +12 -0
  50. package/dist/core/src/redux/toolkit/isPlainObject.d.ts.map +1 -0
  51. package/dist/core/src/redux/toolkit/mapBuilders.d.ts +38 -0
  52. package/dist/core/src/redux/toolkit/mapBuilders.d.ts.map +1 -0
  53. package/dist/core/src/redux/toolkit/tsHelpers.d.ts +51 -0
  54. package/dist/core/src/redux/toolkit/tsHelpers.d.ts.map +1 -0
  55. package/dist/core/src/redux/toolkit/utils.d.ts +11 -0
  56. package/dist/core/src/redux/toolkit/utils.d.ts.map +1 -0
  57. package/dist/core/src/redux/utils/createDestroyableSlice.d.ts +3 -2
  58. package/dist/core/src/redux/utils/createDestroyableSlice.d.ts.map +1 -1
  59. package/dist/core/src/testUtils.d.ts +8 -25
  60. package/dist/core/src/testUtils.d.ts.map +1 -1
  61. package/dist/core/src/types/chat.d.ts +18 -15
  62. package/dist/core/src/types/chat.d.ts.map +1 -1
  63. package/dist/core/src/types/utils.d.ts +7 -0
  64. package/dist/core/src/types/utils.d.ts.map +1 -1
  65. package/dist/core/src/utils/constants.d.ts +1 -0
  66. package/dist/core/src/utils/constants.d.ts.map +1 -1
  67. package/dist/core/src/utils/index.d.ts +6 -1
  68. package/dist/core/src/utils/index.d.ts.map +1 -1
  69. package/dist/core/src/utils/interfaces.d.ts +13 -4
  70. package/dist/core/src/utils/interfaces.d.ts.map +1 -1
  71. package/dist/index.esm.js +127 -4
  72. package/dist/index.esm.js.map +3 -3
  73. package/dist/index.js +175 -59
  74. package/dist/index.js.map +3 -3
  75. package/dist/index.umd.js +2 -2
  76. package/dist/index.umd.js.map +1 -1
  77. package/dist/js/src/BaseRoomSession.d.ts +7 -0
  78. package/dist/js/src/BaseRoomSession.d.ts.map +1 -1
  79. package/dist/js/src/JWTSession.d.ts.map +1 -1
  80. package/dist/js/src/RoomSession.d.ts.map +1 -1
  81. package/dist/js/src/features/actions.d.ts +1 -1
  82. package/dist/js/src/features/actions.d.ts.map +1 -1
  83. package/dist/js/src/testUtils.d.ts +16 -50
  84. package/dist/js/src/testUtils.d.ts.map +1 -1
  85. package/dist/js/src/video/workers.d.ts +4 -0
  86. package/dist/js/src/video/workers.d.ts.map +1 -0
  87. package/dist/js/tsconfig.build.tsbuildinfo +1 -1
  88. package/dist/webrtc/src/BaseConnection.d.ts +7 -0
  89. package/dist/webrtc/src/BaseConnection.d.ts.map +1 -1
  90. package/dist/webrtc/src/RTCPeer.d.ts.map +1 -1
  91. package/package.json +3 -3
  92. package/src/BaseRoomSession.test.ts +2 -2
  93. package/src/BaseRoomSession.ts +15 -0
  94. package/src/RoomSession.ts +16 -4
  95. package/src/chat/Client.test.ts +61 -15
  96. package/src/video/workers.ts +184 -0
@@ -1 +1 @@
1
- {"version":3,"file":"RTCPeer.d.ts","sourceRoot":"","sources":["../../../../webrtc/src/RTCPeer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAa,MAAM,kBAAkB,CAAA;AAO1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AASjD,MAAM,CAAC,OAAO,OAAO,OAAO,CAAC,UAAU,SAAS,YAAY,CAAC,eAAe;IAmBjE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC;IAChC,IAAI,EAAE,UAAU;IAnBlB,QAAQ,EAAE,iBAAiB,CAAA;IAElC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAQ;IAC5B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAA2B;IACtD,OAAO,CAAC,kBAAkB,CAA0B;IAEpD,OAAO,KAAK,MAAM,GAEjB;gBAGQ,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,IAAI,EAAE,UAAU;IAazB,IAAI,OAAO,YAEV;IAED,IAAI,QAAQ,YAEX;IAED,IAAI,WAAW,YAEd;IAED,IAAI,KAAK,YAER;IAED,IAAI,eAAe,4BAGlB;IAED,IAAI,eAAe,4BAGlB;IAED,IAAI,cAAc,YAEjB;IAED,IAAI,cAAc,YAEjB;IAED,IAAI,gBAAgB,YAEnB;IAED,IAAI,gBAAgB,YAEnB;IAED,IAAI,MAAM,IAAI,gBAAgB,CAW7B;IAED,IAAI,QAAQ,uBAEX;IAED,eAAe,CAAC,IAAI,EAAE,MAAM;IAetB,kBAAkB,CAAC,IAAI,EAAE,MAAM;IAwBrC,WAAW,CAAC,IAAI,EAAE,MAAM;IAcxB,gBAAgB,CAAC,IAAI,EAAE,MAAM;IAa7B,cAAc,CAAC,IAAI,EAAE,MAAM;IAa3B,uBAAuB;IAoBjB,qBAAqB,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,qBAAqB;IAgCpC,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,kBAAkB;IAUpB,gBAAgB,CAAC,KAAK,UAAQ;IAyD9B,WAAW,CAAC,GAAG,EAAE,MAAM;IAsB7B,OAAO,CAAC,uBAAuB;IAOzB,KAAK;IAoGX,OAAO,CAAC,sBAAsB;YAShB,SAAS;IAsBvB,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,oBAAoB;IAiC5B,OAAO,CAAC,qBAAqB;YAoBf,oBAAoB;IAQlC,OAAO,CAAC,gBAAgB;CAsDzB"}
1
+ {"version":3,"file":"RTCPeer.d.ts","sourceRoot":"","sources":["../../../../webrtc/src/RTCPeer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAa,MAAM,kBAAkB,CAAA;AAO1D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AASjD,MAAM,CAAC,OAAO,OAAO,OAAO,CAAC,UAAU,SAAS,YAAY,CAAC,eAAe;IAmBjE,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC;IAChC,IAAI,EAAE,UAAU;IAnBlB,QAAQ,EAAE,iBAAiB,CAAA;IAElC,OAAO,CAAC,OAAO,CAAmB;IAClC,OAAO,CAAC,WAAW,CAAK;IACxB,OAAO,CAAC,YAAY,CAAQ;IAC5B;;;;OAIG;IACH,OAAO,CAAC,mBAAmB,CAA2B;IACtD,OAAO,CAAC,kBAAkB,CAA0B;IAEpD,OAAO,KAAK,MAAM,GAEjB;gBAGQ,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,EAChC,IAAI,EAAE,UAAU;IAazB,IAAI,OAAO,YAEV;IAED,IAAI,QAAQ,YAEX;IAED,IAAI,WAAW,YAEd;IAED,IAAI,KAAK,YAER;IAED,IAAI,eAAe,4BAGlB;IAED,IAAI,eAAe,4BAGlB;IAED,IAAI,cAAc,YAEjB;IAED,IAAI,cAAc,YAEjB;IAED,IAAI,gBAAgB,YAEnB;IAED,IAAI,gBAAgB,YAEnB;IAED,IAAI,MAAM,IAAI,gBAAgB,CAW7B;IAED,IAAI,QAAQ,uBAEX;IAED,eAAe,CAAC,IAAI,EAAE,MAAM;IAetB,kBAAkB,CAAC,IAAI,EAAE,MAAM;IAwBrC,WAAW,CAAC,IAAI,EAAE,MAAM;IAcxB,gBAAgB,CAAC,IAAI,EAAE,MAAM;IAa7B,cAAc,CAAC,IAAI,EAAE,MAAM;IAa3B,uBAAuB;IAoBjB,qBAAqB,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,qBAAqB;IAgCpC,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,kBAAkB;IAUpB,gBAAgB,CAAC,KAAK,UAAQ;IAyD9B,WAAW,CAAC,GAAG,EAAE,MAAM;IAsB7B,OAAO,CAAC,uBAAuB;IAOzB,KAAK;IAoGX,OAAO,CAAC,sBAAsB;YAWhB,SAAS;IAsBvB,OAAO,CAAC,MAAM;IAgBd,OAAO,CAAC,oBAAoB;IAiC5B,OAAO,CAAC,qBAAqB;YAoBf,oBAAoB;IAQlC,OAAO,CAAC,gBAAgB;CAsDzB"}
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "SignalWire JS SDK",
4
4
  "author": "SignalWire Team <open.source@signalwire.com>",
5
5
  "license": "MIT",
6
- "version": "3.7.0",
6
+ "version": "3.8.0-dev.202202021245.c33a456.0",
7
7
  "main": "dist/index.js",
8
8
  "module": "dist/index.esm.js",
9
9
  "unpkg": "dist/index.umd.js",
@@ -43,8 +43,8 @@
43
43
  "prepublishOnly": "npm run build"
44
44
  },
45
45
  "dependencies": {
46
- "@signalwire/core": "3.4.1",
47
- "@signalwire/webrtc": "3.3.0"
46
+ "@signalwire/core": "3.5.0-dev.202202021245.c33a456.0",
47
+ "@signalwire/webrtc": "3.3.1-dev.202202021245.c33a456.0"
48
48
  },
49
49
  "types": "dist/js/src/index.d.ts"
50
50
  }
@@ -1,11 +1,11 @@
1
1
  import { EventEmitter, actions } from '@signalwire/core'
2
- import { createBaseRoomSessionObject } from './BaseRoomSession'
2
+ import { BaseRoomSession, createBaseRoomSessionObject } from './BaseRoomSession'
3
3
  import type { RoomSession } from './RoomSession'
4
4
  import { configureJestStore, configureFullStack } from './testUtils'
5
5
 
6
6
  describe('Room Object', () => {
7
7
  let store: any
8
- let room: RoomSession
8
+ let room: BaseRoomSession<RoomSession>
9
9
 
10
10
  beforeEach(() => {
11
11
  store = configureJestStore()
@@ -41,6 +41,7 @@ import {
41
41
  RoomSessionDeviceConnection,
42
42
  RoomSessionDevice,
43
43
  } from './RoomSessionDevice'
44
+ import * as workers from './video/workers'
44
45
 
45
46
  export interface BaseRoomSession<T>
46
47
  extends RoomMethods,
@@ -120,6 +121,20 @@ export class RoomSessionConnection
120
121
  ])
121
122
  }
122
123
 
124
+ /**
125
+ * This method will be called by `join()` right before the
126
+ * `connect()` happens and it's a way for us to control
127
+ * exactly when the workers are attached.
128
+ * @internal
129
+ */
130
+ protected attachPreConnectWorkers() {
131
+ this.setWorker('memberListUpdated', {
132
+ worker: workers.memberListUpdatedWorker,
133
+ })
134
+
135
+ this.attachWorkers()
136
+ }
137
+
123
138
  /** @deprecated Use {@link startScreenShare} instead. */
124
139
  async createScreenShareObject(opts: CreateScreenShareObjectOptions = {}) {
125
140
  return this.startScreenShare(opts)
@@ -1,4 +1,8 @@
1
- import { UserOptions, AssertSameType, getLogger } from '@signalwire/core'
1
+ import {
2
+ UserOptions,
3
+ AssertSameType,
4
+ getLogger,
5
+ } from '@signalwire/core'
2
6
  import { createClient } from './createClient'
3
7
  import type { MakeRoomOptions } from './Client'
4
8
  import { BaseRoomSession } from './BaseRoomSession'
@@ -123,6 +127,9 @@ export const RoomSession = function (roomOptions: RoomSessionOptions) {
123
127
  const join = () => {
124
128
  return new Promise(async (resolve, reject) => {
125
129
  try {
130
+ // @ts-expect-error
131
+ room.attachPreConnectWorkers()
132
+
126
133
  await client.connect()
127
134
 
128
135
  room.once('room.subscribed', () => {
@@ -137,10 +144,15 @@ export const RoomSession = function (roomOptions: RoomSessionOptions) {
137
144
  })
138
145
  }
139
146
 
147
+ const interceptors = {
148
+ join,
149
+ } as const
150
+
140
151
  return new Proxy<Omit<RoomSession, 'new'>>(room, {
141
- get(target: RoomSession, prop: any, receiver: any) {
142
- if (prop === 'join') {
143
- return join
152
+ get(target: RoomSession, prop: keyof RoomSession, receiver: any) {
153
+ if (prop in interceptors) {
154
+ // @ts-expect-error
155
+ return interceptors[prop]
144
156
  }
145
157
 
146
158
  if (!target.active && UNSAFE_PROP_ACCESS.includes(prop)) {
@@ -69,7 +69,7 @@ describe('ChatClient Object', () => {
69
69
  },
70
70
  })
71
71
  )
72
- } else if (parsedData.method === 'chat.presence.set_state') {
72
+ } else if (parsedData.method === 'chat.member.set_state') {
73
73
  socket.send(
74
74
  JSON.stringify({
75
75
  jsonrpc: '2.0',
@@ -80,7 +80,7 @@ describe('ChatClient Object', () => {
80
80
  },
81
81
  })
82
82
  )
83
- } else if (parsedData.method === 'chat.presence.get_state') {
83
+ } else if (parsedData.method === 'chat.member.get_state') {
84
84
  socket.send(
85
85
  JSON.stringify({
86
86
  jsonrpc: '2.0',
@@ -128,7 +128,7 @@ describe('ChatClient Object', () => {
128
128
  await chat.subscribe(['test'])
129
129
  await chat.publish({
130
130
  channel: 'test',
131
- message: 'test',
131
+ content: 'test',
132
132
  })
133
133
 
134
134
  const connectMsg = JSON.parse(server.messages[0].toString())
@@ -147,7 +147,7 @@ describe('ChatClient Object', () => {
147
147
  chat.subscribe(['test']),
148
148
  chat.publish({
149
149
  channel: 'test',
150
- message: 'test',
150
+ content: 'test',
151
151
  }),
152
152
  ])
153
153
 
@@ -190,7 +190,11 @@ describe('ChatClient Object', () => {
190
190
  channel: 'lobby',
191
191
  message: {
192
192
  id: 'f5511ad5-4dc2-4d28-a449-cc39909093b9',
193
- sender_id: '1507e5f9-075c-463d-94ba-a8f9ec0c7d4e',
193
+ member: {
194
+ id: '1507e5f9-075c-463d-94ba-a8f9ec0c7d4e',
195
+ channel: 'lobby',
196
+ state: { active: true },
197
+ },
194
198
  content: 'Hello World!',
195
199
  published_at: 1641405257.795,
196
200
  },
@@ -210,7 +214,11 @@ describe('ChatClient Object', () => {
210
214
  chat.on('message', (message) => {
211
215
  expect(message.channel).toBe('lobby')
212
216
  expect(message.id).toBe('f5511ad5-4dc2-4d28-a449-cc39909093b9')
213
- expect(message.senderId).toBe('1507e5f9-075c-463d-94ba-a8f9ec0c7d4e')
217
+ expect(message.member).toStrictEqual({
218
+ id: '1507e5f9-075c-463d-94ba-a8f9ec0c7d4e',
219
+ channel: 'lobby',
220
+ state: { active: true },
221
+ })
214
222
  expect(message.content).toBe('Hello World!')
215
223
  expect(message.publishedAt).toStrictEqual(
216
224
  new Date(1641405257.795 * 1000)
@@ -256,6 +264,8 @@ describe('ChatClient Object', () => {
256
264
  channel: 'lobby',
257
265
  member: {
258
266
  id: '1507e5f9-075c-463d-94ba-a8f9ec0c7d4e',
267
+ channel: 'lobby',
268
+ state: { init: 1 },
259
269
  },
260
270
  },
261
271
  timestamp: 1641468229.28,
@@ -269,6 +279,7 @@ describe('ChatClient Object', () => {
269
279
  chat.on('member.joined', (member) => {
270
280
  expect(member.channel).toBe('lobby')
271
281
  expect(member.id).toBe('1507e5f9-075c-463d-94ba-a8f9ec0c7d4e')
282
+ expect(member.state).toStrictEqual({ init: 1 })
272
283
 
273
284
  done()
274
285
  })
@@ -288,9 +299,10 @@ describe('ChatClient Object', () => {
288
299
  channel: 'lobby',
289
300
  member: {
290
301
  id: '1507e5f9-075c-463d-94ba-a8f9ec0c7d4e',
291
- },
292
- state: {
293
- typing: true,
302
+ channel: 'lobby',
303
+ state: {
304
+ typing: true,
305
+ },
294
306
  },
295
307
  },
296
308
  timestamp: 1641468242.538,
@@ -326,6 +338,8 @@ describe('ChatClient Object', () => {
326
338
  channel: 'lobby',
327
339
  member: {
328
340
  id: '1507e5f9-075c-463d-94ba-a8f9ec0c7d4e',
341
+ channel: 'lobby',
342
+ state: {},
329
343
  },
330
344
  },
331
345
  timestamp: 1641468229.28,
@@ -339,6 +353,7 @@ describe('ChatClient Object', () => {
339
353
  chat.on('member.left', (member) => {
340
354
  expect(member.channel).toBe('lobby')
341
355
  expect(member.id).toBe('1507e5f9-075c-463d-94ba-a8f9ec0c7d4e')
356
+ expect(member.state).toStrictEqual({})
342
357
 
343
358
  done()
344
359
  })
@@ -375,7 +390,7 @@ describe('ChatClient Object', () => {
375
390
 
376
391
  const params = {
377
392
  channel: 'test',
378
- message: 'test',
393
+ content: 'test',
379
394
  }
380
395
 
381
396
  await chat.publish(params)
@@ -461,7 +476,7 @@ describe('ChatClient Object', () => {
461
476
  // calling unsubscribe()
462
477
  await chat.publish({
463
478
  channel: 'test',
464
- message: 'test',
479
+ content: 'test',
465
480
  })
466
481
 
467
482
  await expect(() => chat.unsubscribe(['test1_error'])).rejects.toBeTruthy()
@@ -555,14 +570,16 @@ describe('ChatClient Object', () => {
555
570
  chat.on('message', () => {})
556
571
  await chat.subscribe(['test1'])
557
572
 
558
- const response = await chat.setState({
573
+ const response = await chat.setMemberState({
574
+ memberId: 'memberUuid1',
559
575
  channels: 'test1',
560
576
  state: { typing: true },
561
577
  })
562
578
 
563
579
  const request = JSON.parse(server.messages[2].toString())
564
- expect(request.method).toEqual('chat.presence.set_state')
580
+ expect(request.method).toEqual('chat.member.set_state')
565
581
  expect(request.params).toStrictEqual({
582
+ member_id: 'memberUuid1',
566
583
  channels: [{ name: 'test1' }],
567
584
  state: { typing: true },
568
585
  })
@@ -580,13 +597,13 @@ describe('ChatClient Object', () => {
580
597
  chat.on('message', () => {})
581
598
  await chat.subscribe(['test1'])
582
599
 
583
- const response = await chat.getState({
600
+ const response = await chat.getMemberState({
584
601
  memberId: 'memberId',
585
602
  channels: 'test1',
586
603
  })
587
604
 
588
605
  const request = JSON.parse(server.messages[2].toString())
589
- expect(request.method).toEqual('chat.presence.get_state')
606
+ expect(request.method).toEqual('chat.member.get_state')
590
607
  expect(request.params).toStrictEqual({
591
608
  channels: [{ name: 'test1' }],
592
609
  member_id: 'memberId',
@@ -602,5 +619,34 @@ describe('ChatClient Object', () => {
602
619
  },
603
620
  })
604
621
  })
622
+
623
+ it('should send the proper RPC without (optional) channels', async () => {
624
+ const chat = new Client({
625
+ host,
626
+ token,
627
+ })
628
+ chat.on('message', () => {})
629
+ await chat.subscribe(['test1'])
630
+
631
+ const response = await chat.getMemberState({
632
+ memberId: 'memberId',
633
+ })
634
+
635
+ const request = JSON.parse(server.messages[2].toString())
636
+ expect(request.method).toEqual('chat.member.get_state')
637
+ expect(request.params).toStrictEqual({
638
+ member_id: 'memberId',
639
+ })
640
+
641
+ expect(response).toStrictEqual({
642
+ channels: {
643
+ lobby: {
644
+ state: {
645
+ typing: true,
646
+ },
647
+ },
648
+ },
649
+ })
650
+ })
605
651
  })
606
652
  })
@@ -0,0 +1,184 @@
1
+ import {
2
+ sagaEffects,
3
+ SagaIterator,
4
+ SDKWorker,
5
+ toSyntheticEvent,
6
+ validateEventsToSubscribe,
7
+ toInternalEventName,
8
+ PubSubChannel,
9
+ InternalVideoMemberEntity,
10
+ } from '@signalwire/core'
11
+ import { RoomSession } from '../RoomSession'
12
+
13
+ const noop = () => {}
14
+
15
+ const EXTERNAL_MEMBER_LIST_UPDATED_EVENT = 'video.memberList.updated'
16
+
17
+ const INTERNAL_MEMBER_LIST_UPDATED_EVENT = toInternalEventName({
18
+ event: EXTERNAL_MEMBER_LIST_UPDATED_EVENT,
19
+ })
20
+
21
+ const SYNTHETIC_MEMBER_LIST_UPDATED_EVENT = toSyntheticEvent(
22
+ INTERNAL_MEMBER_LIST_UPDATED_EVENT
23
+ )
24
+
25
+ const MEMBER_LIST_EVENTS = [
26
+ /** Alias to `video.room.subscribed` */
27
+ 'video.room.joined',
28
+ 'video.member.joined',
29
+ 'video.member.left',
30
+ 'video.member.updated',
31
+ ]
32
+
33
+ type MemberList = Map<string, InternalVideoMemberEntity>
34
+
35
+ const isMemberListEvent = (event: string) => {
36
+ return MEMBER_LIST_EVENTS.includes(event)
37
+ }
38
+
39
+ const getMemberListEventsToSubscribe = (subscriptions: string[]) => {
40
+ return validateEventsToSubscribe(MEMBER_LIST_EVENTS).filter((event) => {
41
+ return !subscriptions.includes(event as string)
42
+ })
43
+ }
44
+
45
+ const shouldHandleMemberList = (subscriptions: string[]) => {
46
+ return subscriptions.some((event) =>
47
+ event.includes(INTERNAL_MEMBER_LIST_UPDATED_EVENT)
48
+ )
49
+ }
50
+
51
+ const getMembersFromAction = (action: any) => {
52
+ if (action.type === 'video.room.joined') {
53
+ return action.payload.room_session.members
54
+ }
55
+
56
+ return [action.payload.member]
57
+ }
58
+
59
+ const getUpdatedMembers = ({
60
+ action,
61
+ memberList,
62
+ }: {
63
+ action: any
64
+ memberList: MemberList
65
+ }) => {
66
+ const actionMembers = getMembersFromAction(action)
67
+
68
+ switch (action.type) {
69
+ case 'video.member.left':
70
+ actionMembers.forEach((member: InternalVideoMemberEntity) => {
71
+ memberList.delete(member.id)
72
+ })
73
+ break
74
+ default:
75
+ actionMembers.forEach((member: InternalVideoMemberEntity) => {
76
+ memberList.set(member.id, member)
77
+ })
78
+ }
79
+
80
+ return Array.from(memberList.values())
81
+ }
82
+
83
+ const initMemberListSubscriptions = (
84
+ room: RoomSession,
85
+ subscriptions: string[]
86
+ ) => {
87
+ const events = getMemberListEventsToSubscribe(subscriptions)
88
+
89
+ events.forEach((event) => {
90
+ /**
91
+ * Params to `subscribe` come from the event handlers
92
+ * the user has attached so to make sure we subscribe to
93
+ * all the appropiate events needed for
94
+ * `memberList.updated` to work, we must subscribe to
95
+ * the required events. We don't need to act upon the
96
+ * event (that's why we attach a `noop`), just to
97
+ * register it (`subscribe` gets its values from
98
+ * `BaseComponent.getSubscriptions`, which gets
99
+ * populated by each of the event handlers the user
100
+ * attached).
101
+ */
102
+ room.once(event as any, noop)
103
+ })
104
+
105
+ /**
106
+ * This handler will act as a simple bridge between
107
+ * synthetic events and external events.
108
+ */
109
+ const eventBridgeHandler = (payload: any) => {
110
+ // @ts-expect-error
111
+ room.emit(EXTERNAL_MEMBER_LIST_UPDATED_EVENT, payload)
112
+ }
113
+
114
+ room.on(SYNTHETIC_MEMBER_LIST_UPDATED_EVENT as any, eventBridgeHandler)
115
+
116
+ /**
117
+ * Any events attached by the saga should be specified
118
+ * here so it can be cleaned up when needed.
119
+ */
120
+ const cleanup = () => {
121
+ room.off(SYNTHETIC_MEMBER_LIST_UPDATED_EVENT as any, eventBridgeHandler)
122
+ }
123
+
124
+ return {
125
+ cleanup,
126
+ }
127
+ }
128
+
129
+ function* membersListUpdatedWatcher({
130
+ pubSubChannel,
131
+ }: {
132
+ pubSubChannel: PubSubChannel
133
+ }): SagaIterator {
134
+ const memberList: MemberList = new Map()
135
+
136
+ function* worker(pubSubAction: any) {
137
+ const { payload } = pubSubAction
138
+ const members = getUpdatedMembers({ action: pubSubAction, memberList })
139
+ const memberListPayload = {
140
+ room_session_id: payload.room_session_id || payload.room_session.id,
141
+ members,
142
+ }
143
+
144
+ // TODO: add typings
145
+ yield sagaEffects.put(pubSubChannel, {
146
+ type: SYNTHETIC_MEMBER_LIST_UPDATED_EVENT as any,
147
+ payload: memberListPayload as any,
148
+ })
149
+ }
150
+
151
+ while (true) {
152
+ const pubSubAction = yield sagaEffects.take(
153
+ pubSubChannel,
154
+ ({ type }: any) => {
155
+ return isMemberListEvent(type)
156
+ }
157
+ )
158
+
159
+ yield sagaEffects.fork(worker, pubSubAction)
160
+ }
161
+ }
162
+
163
+ export const memberListUpdatedWorker: SDKWorker<RoomSession> =
164
+ function* membersChangedWorker({
165
+ channels: { pubSubChannel },
166
+ instance,
167
+ }): SagaIterator {
168
+ // @ts-expect-error
169
+ const subscriptions = instance.getSubscriptions()
170
+
171
+ if (!shouldHandleMemberList(subscriptions)) {
172
+ return
173
+ }
174
+
175
+ const { cleanup } = initMemberListSubscriptions(instance, subscriptions)
176
+
177
+ yield sagaEffects.fork(membersListUpdatedWatcher, {
178
+ pubSubChannel,
179
+ })
180
+
181
+ instance.once('destroy', () => {
182
+ cleanup()
183
+ })
184
+ }