@signalwire/js 3.26.0 → 3.27.0-dev.202404301530.94a97d7.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 (181) hide show
  1. package/dist/core/src/BaseComponent.d.ts +10 -0
  2. package/dist/core/src/BaseComponent.d.ts.map +1 -1
  3. package/dist/core/src/BaseJWTSession.d.ts.map +1 -1
  4. package/dist/core/src/BaseSession.d.ts +3 -0
  5. package/dist/core/src/BaseSession.d.ts.map +1 -1
  6. package/dist/core/src/RPCMessages/RPCConnect.d.ts +14 -0
  7. package/dist/core/src/RPCMessages/RPCConnect.d.ts.map +1 -1
  8. package/dist/core/src/index.d.ts +4 -3
  9. package/dist/core/src/index.d.ts.map +1 -1
  10. package/dist/core/src/memberPosition/workers.d.ts.map +1 -1
  11. package/dist/core/src/redux/index.d.ts +5 -0
  12. package/dist/core/src/redux/index.d.ts.map +1 -1
  13. package/dist/core/src/redux/interfaces.d.ts +2 -0
  14. package/dist/core/src/redux/interfaces.d.ts.map +1 -1
  15. package/dist/core/src/redux/utils/useInstanceMap.d.ts +2 -0
  16. package/dist/core/src/redux/utils/useInstanceMap.d.ts.map +1 -1
  17. package/dist/core/src/rooms/RoomSessionMember.d.ts +39 -0
  18. package/dist/core/src/rooms/RoomSessionMember.d.ts.map +1 -0
  19. package/dist/core/src/rooms/index.d.ts +1 -0
  20. package/dist/core/src/rooms/index.d.ts.map +1 -1
  21. package/dist/core/src/rooms/methods.d.ts +2 -2
  22. package/dist/core/src/rooms/methods.d.ts.map +1 -1
  23. package/dist/core/src/testUtils.d.ts +8 -0
  24. package/dist/core/src/testUtils.d.ts.map +1 -1
  25. package/dist/core/src/types/callSegment.d.ts +21 -0
  26. package/dist/core/src/types/callSegment.d.ts.map +1 -0
  27. package/dist/core/src/types/callfabric.d.ts +337 -16
  28. package/dist/core/src/types/callfabric.d.ts.map +1 -1
  29. package/dist/core/src/types/conversation.d.ts +24 -0
  30. package/dist/core/src/types/conversation.d.ts.map +1 -0
  31. package/dist/core/src/types/index.d.ts +15 -1
  32. package/dist/core/src/types/index.d.ts.map +1 -1
  33. package/dist/core/src/types/unified.d.ts +36 -0
  34. package/dist/core/src/types/unified.d.ts.map +1 -0
  35. package/dist/core/src/types/utils.d.ts +3 -0
  36. package/dist/core/src/types/utils.d.ts.map +1 -1
  37. package/dist/core/src/types/videoMember.d.ts +11 -1
  38. package/dist/core/src/types/videoMember.d.ts.map +1 -1
  39. package/dist/core/src/types/videoRoomSession.d.ts +3 -0
  40. package/dist/core/src/types/videoRoomSession.d.ts.map +1 -1
  41. package/dist/core/src/utils/index.d.ts +1 -0
  42. package/dist/core/src/utils/index.d.ts.map +1 -1
  43. package/dist/core/src/utils/interfaces.d.ts +16 -9
  44. package/dist/core/src/utils/interfaces.d.ts.map +1 -1
  45. package/dist/core/src/utils/mapObject.d.ts +7 -0
  46. package/dist/core/src/utils/mapObject.d.ts.map +1 -0
  47. package/dist/core/src/utils/mapObject.test.d.ts +2 -0
  48. package/dist/core/src/utils/mapObject.test.d.ts.map +1 -0
  49. package/dist/core/src/workers/executeActionWorker.d.ts.map +1 -1
  50. package/dist/index.esm.js +1352 -527
  51. package/dist/index.esm.js.map +3 -3
  52. package/dist/index.js +1448 -642
  53. package/dist/index.js.map +3 -3
  54. package/dist/index.umd.js +3 -3
  55. package/dist/index.umd.js.map +1 -1
  56. package/dist/js/src/BaseRoomSession.d.ts +6 -4
  57. package/dist/js/src/BaseRoomSession.d.ts.map +1 -1
  58. package/dist/js/src/Client.d.ts +1 -0
  59. package/dist/js/src/Client.d.ts.map +1 -1
  60. package/dist/js/src/JWTSession.d.ts.map +1 -1
  61. package/dist/js/src/UnifiedJWTSession.d.ts +16 -0
  62. package/dist/js/src/UnifiedJWTSession.d.ts.map +1 -0
  63. package/dist/js/src/fabric/CallFabricBaseRoomSession.d.ts +30 -0
  64. package/dist/js/src/fabric/CallFabricBaseRoomSession.d.ts.map +1 -0
  65. package/dist/js/src/fabric/CallSegment.d.ts +26 -0
  66. package/dist/js/src/fabric/CallSegment.d.ts.map +1 -0
  67. package/dist/js/src/fabric/Conversation.d.ts +144 -0
  68. package/dist/js/src/fabric/Conversation.d.ts.map +1 -0
  69. package/dist/js/src/fabric/ConversationAPI.d.ts +61 -0
  70. package/dist/js/src/fabric/ConversationAPI.d.ts.map +1 -0
  71. package/dist/js/src/fabric/HTTPClient.d.ts +45 -27
  72. package/dist/js/src/fabric/HTTPClient.d.ts.map +1 -1
  73. package/dist/js/src/fabric/IncomingCallManager.d.ts +14 -0
  74. package/dist/js/src/fabric/IncomingCallManager.d.ts.map +1 -0
  75. package/dist/js/src/fabric/SignalWire.d.ts +1 -16
  76. package/dist/js/src/fabric/SignalWire.d.ts.map +1 -1
  77. package/dist/js/src/fabric/WSClient.d.ts +23 -28
  78. package/dist/js/src/fabric/WSClient.d.ts.map +1 -1
  79. package/dist/js/src/fabric/createHttpClient.d.ts +1 -0
  80. package/dist/js/src/fabric/createHttpClient.d.ts.map +1 -1
  81. package/dist/js/src/fabric/index.d.ts +3 -0
  82. package/dist/js/src/fabric/index.d.ts.map +1 -1
  83. package/dist/js/src/fabric/types.d.ts +93 -0
  84. package/dist/js/src/fabric/types.d.ts.map +1 -0
  85. package/dist/js/src/fabric/workers/callFabricWorker.d.ts +7 -0
  86. package/dist/js/src/fabric/workers/callFabricWorker.d.ts.map +1 -0
  87. package/dist/js/src/fabric/workers/callJoinWorker.d.ts +4 -0
  88. package/dist/js/src/fabric/workers/callJoinWorker.d.ts.map +1 -0
  89. package/dist/js/src/fabric/workers/callLeftWorker.d.ts +4 -0
  90. package/dist/js/src/fabric/workers/callLeftWorker.d.ts.map +1 -0
  91. package/dist/js/src/fabric/workers/callStateWorker.d.ts +4 -0
  92. package/dist/js/src/fabric/workers/callStateWorker.d.ts.map +1 -0
  93. package/dist/js/src/fabric/workers/conversationWorker.d.ts +4 -0
  94. package/dist/js/src/fabric/workers/conversationWorker.d.ts.map +1 -0
  95. package/dist/js/src/fabric/workers/index.d.ts +6 -0
  96. package/dist/js/src/fabric/workers/index.d.ts.map +1 -0
  97. package/dist/js/src/fabric/workers/mappers/unifiedEventsMapper.d.ts +3 -0
  98. package/dist/js/src/fabric/workers/mappers/unifiedEventsMapper.d.ts.map +1 -0
  99. package/dist/js/src/fabric/workers/unifiedEventsWatcher.d.ts +7 -0
  100. package/dist/js/src/fabric/workers/unifiedEventsWatcher.d.ts.map +1 -0
  101. package/dist/js/src/fabric/workers/unifiedTargetWorker.d.ts +3 -0
  102. package/dist/js/src/fabric/workers/unifiedTargetWorker.d.ts.map +1 -0
  103. package/dist/js/src/fabric/{WSClientWorker.d.ts → workers/wsClientWorker.d.ts} +3 -3
  104. package/dist/js/src/fabric/workers/wsClientWorker.d.ts.map +1 -0
  105. package/dist/js/src/features/mediaElements/mediaElementsSagas.d.ts.map +1 -1
  106. package/dist/js/src/index.d.ts +7 -8
  107. package/dist/js/src/index.d.ts.map +1 -1
  108. package/dist/js/src/testUtils.d.ts +17 -0
  109. package/dist/js/src/testUtils.d.ts.map +1 -1
  110. package/dist/js/src/utils/UnifiedRequestMapper.d.ts +4 -0
  111. package/dist/js/src/utils/UnifiedRequestMapper.d.ts.map +1 -0
  112. package/dist/js/src/utils/aspectRatioListener.d.ts +8 -0
  113. package/dist/js/src/utils/aspectRatioListener.d.ts.map +1 -0
  114. package/dist/js/src/utils/interfaces.d.ts +3 -1
  115. package/dist/js/src/utils/interfaces.d.ts.map +1 -1
  116. package/dist/js/src/utils/makeQueryParamsUrl.d.ts +9 -0
  117. package/dist/js/src/utils/makeQueryParamsUrl.d.ts.map +1 -0
  118. package/dist/js/src/utils/paginatedResult.d.ts +44 -0
  119. package/dist/js/src/utils/paginatedResult.d.ts.map +1 -0
  120. package/dist/js/src/utils/videoElement.d.ts +4 -0
  121. package/dist/js/src/utils/videoElement.d.ts.map +1 -1
  122. package/dist/js/src/video/videoMemberWorker.d.ts +6 -0
  123. package/dist/js/src/video/videoMemberWorker.d.ts.map +1 -0
  124. package/dist/js/src/video/videoRoomWorker.d.ts +4 -0
  125. package/dist/js/src/video/videoRoomWorker.d.ts.map +1 -0
  126. package/dist/js/src/video/videoWorker.d.ts.map +1 -1
  127. package/dist/js/src/video/videoWorkerUnifiedEventing.d.ts +4 -0
  128. package/dist/js/src/video/videoWorkerUnifiedEventing.d.ts.map +1 -0
  129. package/dist/js/src/video/workers.d.ts +5 -0
  130. package/dist/js/src/video/workers.d.ts.map +1 -1
  131. package/dist/js/tsconfig.build.tsbuildinfo +1 -1
  132. package/dist/webrtc/src/BaseConnection.d.ts.map +1 -1
  133. package/dist/webrtc/src/RTCPeer.d.ts.map +1 -1
  134. package/dist/webrtc/src/workers/roomSubscribedWorker.d.ts.map +1 -1
  135. package/package.json +6 -3
  136. package/src/BaseRoomSession.test.ts +3 -2
  137. package/src/BaseRoomSession.ts +8 -2
  138. package/src/Client.ts +10 -2
  139. package/src/JWTSession.test.ts +2 -2
  140. package/src/JWTSession.ts +1 -1
  141. package/src/UnifiedJWTSession.ts +78 -0
  142. package/src/fabric/CallFabricBaseRoomSession.test.ts +460 -0
  143. package/src/fabric/CallFabricBaseRoomSession.ts +269 -0
  144. package/src/fabric/CallSegment.ts +83 -0
  145. package/src/fabric/Conversation.test.ts +257 -0
  146. package/src/fabric/Conversation.ts +150 -0
  147. package/src/fabric/ConversationAPI.ts +44 -0
  148. package/src/fabric/HTTPClient.test.ts +23 -18
  149. package/src/fabric/HTTPClient.ts +52 -55
  150. package/src/fabric/IncomingCallManager.test.ts +245 -0
  151. package/src/fabric/IncomingCallManager.ts +89 -0
  152. package/src/fabric/SignalWire.ts +20 -17
  153. package/src/fabric/WSClient.ts +153 -117
  154. package/src/fabric/createHttpClient.ts +2 -0
  155. package/src/fabric/index.ts +3 -0
  156. package/src/fabric/types.ts +104 -0
  157. package/src/fabric/workers/callFabricWorker.ts +121 -0
  158. package/src/fabric/workers/callJoinWorker.ts +90 -0
  159. package/src/fabric/workers/callLeftWorker.ts +47 -0
  160. package/src/fabric/workers/callStateWorker.ts +39 -0
  161. package/src/fabric/workers/conversationWorker.ts +41 -0
  162. package/src/fabric/workers/index.ts +5 -0
  163. package/src/fabric/workers/mappers/unifiedEventsMapper.ts +54 -0
  164. package/src/fabric/workers/unifiedEventsWatcher.ts +75 -0
  165. package/src/fabric/workers/unifiedTargetWorker.ts +96 -0
  166. package/src/fabric/{WSClientWorker.ts → workers/wsClientWorker.ts} +14 -18
  167. package/src/features/mediaElements/mediaElementsSagas.ts +9 -15
  168. package/src/index.ts +25 -9
  169. package/src/testUtils.ts +83 -0
  170. package/src/utils/UnifiedRequestMapper.ts +149 -0
  171. package/src/utils/aspectRatioListener.ts +40 -0
  172. package/src/utils/interfaces.ts +3 -0
  173. package/src/utils/makeQueryParamsUrl.ts +14 -0
  174. package/src/utils/paginatedResult.ts +34 -0
  175. package/src/utils/videoElement.ts +4 -0
  176. package/src/video/videoMemberWorker.ts +107 -0
  177. package/src/video/videoRoomWorker.ts +103 -0
  178. package/src/video/videoWorker.ts +8 -3
  179. package/src/video/videoWorkerUnifiedEventing.ts +95 -0
  180. package/src/video/workers.ts +5 -0
  181. package/dist/js/src/fabric/WSClientWorker.d.ts.map +0 -1
@@ -0,0 +1,89 @@
1
+ import { BaseRoomSession } from '../BaseRoomSession'
2
+ import { RoomSession } from '../RoomSession'
3
+ import {
4
+ CallOptions,
5
+ IncomingCallHandlers,
6
+ IncomingCallNotification,
7
+ IncomingInvite,
8
+ } from './types'
9
+
10
+ export class IncomingCallManager {
11
+ private _pendingInvites: Record<string, IncomingInvite> = {}
12
+ private _handlers: IncomingCallHandlers = {}
13
+
14
+ constructor(
15
+ private _buildCallObject: (
16
+ invite: IncomingInvite,
17
+ params: CallOptions
18
+ ) => BaseRoomSession<RoomSession>,
19
+ private _executeReject: (callId: string, nodeId: string) => Promise<void>
20
+ ) {}
21
+
22
+ private _buildNotification(invite: IncomingInvite): IncomingCallNotification {
23
+ const accept = async (params: CallOptions) => {
24
+ return new Promise<BaseRoomSession<RoomSession>>((resolve, reject) => {
25
+ delete this._pendingInvites[invite.callID]
26
+ try {
27
+ const call = this._buildCallObject(invite, params)
28
+ //@ts-expect-error
29
+ call.answer()
30
+
31
+ resolve(call)
32
+ } catch (e) {
33
+ reject(e)
34
+ }
35
+ })
36
+ }
37
+
38
+ const reject = () => {
39
+ delete this._pendingInvites[invite.callID]
40
+ return this._executeReject(invite.callID, invite.nodeId)
41
+ }
42
+
43
+ return {
44
+ invite: {
45
+ details: invite,
46
+ accept: (params) => accept(params),
47
+ reject: () => reject(),
48
+ },
49
+ }
50
+ }
51
+
52
+ setNotificationHandlers(handlers: IncomingCallHandlers) {
53
+ this._handlers.all = handlers.all
54
+ if (
55
+ (handlers.pushNotification &&
56
+ this._handlers.all != handlers.pushNotification) ||
57
+ !handlers.pushNotification
58
+ ) {
59
+ this._handlers.pushNotification = handlers.pushNotification
60
+ }
61
+ if (
62
+ (handlers.websocket && this._handlers.all != handlers.websocket) ||
63
+ !handlers.websocket
64
+ ) {
65
+ this._handlers.websocket = handlers.websocket
66
+ }
67
+ }
68
+
69
+ handleIncomingInvite(incomingInvite: IncomingInvite) {
70
+ if (incomingInvite.callID in this._pendingInvites) {
71
+ console.log(
72
+ `skiping nottification for pending invite to callID: ${incomingInvite.callID}`
73
+ )
74
+ return
75
+ }
76
+ this._pendingInvites[incomingInvite.callID] = incomingInvite
77
+
78
+ if (!(this._handlers.all || this._handlers[incomingInvite.source])) {
79
+ console.log('skiping nottification no listeners:')
80
+ return
81
+ }
82
+
83
+ const notification = this._buildNotification(incomingInvite)
84
+
85
+ this._handlers.all?.(notification)
86
+ const handler = this._handlers[incomingInvite.source]
87
+ handler?.(notification)
88
+ }
89
+ }
@@ -1,20 +1,7 @@
1
- import { type UserOptions } from '@signalwire/core'
2
1
  import { HTTPClient } from './HTTPClient'
3
- import { WSClient, WSClientOptions } from './WSClient'
4
-
5
- export interface SignalWireOptions extends UserOptions, WSClientOptions {}
6
-
7
- export interface SignalWireContract {
8
- httpHost: HTTPClient['httpHost']
9
- getAddresses: HTTPClient['getAddresses']
10
- registerDevice: HTTPClient['registerDevice']
11
- unregisterDevice: HTTPClient['unregisterDevice']
12
- connect: WSClient['connect']
13
- disconnect: WSClient['disconnect']
14
- dial: WSClient['dial']
15
- handlePushNotification: WSClient['handlePushNotification']
16
- updateToken: WSClient['updateToken']
17
- }
2
+ import { WSClient } from './WSClient'
3
+ import { Conversation } from './Conversation'
4
+ import { SignalWireContract, SignalWireOptions } from './types'
18
5
 
19
6
  export const SignalWire = (
20
7
  options: SignalWireOptions
@@ -24,16 +11,32 @@ export const SignalWire = (
24
11
  const httpClient = new HTTPClient(options)
25
12
  const wsClient = new WSClient(options)
26
13
 
14
+ const conversation = new Conversation({ httpClient, wsClient })
15
+
27
16
  resolve({
28
17
  httpHost: httpClient.httpHost,
29
- getAddresses: httpClient.getAddresses.bind(httpClient),
30
18
  registerDevice: httpClient.registerDevice.bind(httpClient),
31
19
  unregisterDevice: httpClient.unregisterDevice.bind(httpClient),
20
+ getSubscriberInfo: httpClient.getSubscriberInfo.bind(httpClient),
32
21
  connect: wsClient.connect.bind(wsClient),
33
22
  disconnect: wsClient.disconnect.bind(wsClient),
23
+ online: wsClient.online.bind(wsClient),
24
+ offline: wsClient.offline.bind(wsClient),
34
25
  dial: wsClient.dial.bind(wsClient),
35
26
  handlePushNotification: wsClient.handlePushNotification.bind(wsClient),
36
27
  updateToken: wsClient.updateToken.bind(wsClient),
28
+ address: {
29
+ getAddresses: httpClient.getAddresses.bind(httpClient),
30
+ getAddress: httpClient.getAddress.bind(httpClient),
31
+ },
32
+ conversation: {
33
+ getConversations: conversation.getConversations.bind(conversation),
34
+ getMessages: conversation.getMessages.bind(conversation),
35
+ getConversationMessages:
36
+ conversation.getConversationMessages.bind(conversation),
37
+ subscribe: conversation.subscribe.bind(conversation),
38
+ sendMessage: conversation.sendMessage.bind(conversation),
39
+ },
37
40
  // @ts-expect-error
38
41
  __httpClient: httpClient,
39
42
  __wsClient: wsClient,
@@ -1,85 +1,71 @@
1
- import { type UserOptions, getLogger, VertoSubscribe } from '@signalwire/core'
1
+ import { getLogger, VertoSubscribe, VertoBye } from '@signalwire/core'
2
+ import { Client } from '../Client'
3
+ import { RoomSession } from '../RoomSession'
2
4
  import { createClient } from '../createClient'
3
- import { WSClientWorker } from './WSClientWorker'
4
-
5
- interface PushNotification {
6
- encryption_type: 'aes_256_gcm'
7
- notification_uuid: string
8
- with_video: 'true' | 'false'
9
- incoming_caller_name: string
10
- incoming_caller_id: string
11
- tag: string
12
- invite: string
13
- title: string
14
- type: 'call_invite'
15
- iv: string
16
- version: string
17
- decrypted: Record<string, any>
18
- }
19
-
20
- export interface WSClientOptions extends UserOptions {
21
- /** HTML element in which to display the video stream */
22
- rootElement?: HTMLElement
23
- /** Disable ICE UDP transport policy */
24
- disableUdpIceServers?: boolean
25
- }
5
+ import { wsClientWorker } from './workers'
6
+ import {
7
+ CallOptions,
8
+ DialParams,
9
+ InboundCallSource,
10
+ IncomingInvite,
11
+ OnlineParams,
12
+ PushNotificationPayload,
13
+ WSClientOptions,
14
+ } from './types'
15
+ import { IncomingCallManager } from './IncomingCallManager'
26
16
 
27
17
  export class WSClient {
28
- private wsClient: ReturnType<typeof createClient>
18
+ private wsClient: Client<RoomSession>
29
19
  private logger = getLogger()
20
+ private _incomingCallManager: IncomingCallManager
30
21
 
31
22
  constructor(public options: WSClientOptions) {
32
- this.wsClient = createClient({
33
- host: this.options.host,
34
- token: this.options.token,
35
- debug: {
36
- logWsTraffic: true,
37
- },
38
- logLevel: 'debug',
23
+ this.wsClient = createClient<RoomSession>({
24
+ ...this.options,
25
+ unifiedEventing: true,
39
26
  })
27
+ this._incomingCallManager = new IncomingCallManager(
28
+ (payload: IncomingInvite, params: CallOptions) =>
29
+ this.buildInboundCall(payload, params),
30
+ (callId: string, nodeId: string) => this.executeVertoBye(callId, nodeId)
31
+ )
32
+ }
33
+
34
+ /** @internal */
35
+ get clientApi() {
36
+ return this.wsClient
40
37
  }
41
38
 
42
- connect() {
39
+ async connect() {
43
40
  // @ts-ignore
44
- this.wsClient.runWorker('WSClientWorker', {
45
- worker: WSClientWorker,
46
- })
47
- return this.wsClient.connect()
41
+ if (!this.wsClient.connected) {
42
+ // @ts-ignore
43
+ this.wsClient.runWorker('wsClientWorker', {
44
+ worker: wsClientWorker,
45
+ initialState: {
46
+ buildInboundCall: (incomingInvite: Omit<IncomingInvite, 'source'>) =>
47
+ this.notifyIncomingInvite('websocket', incomingInvite),
48
+ },
49
+ })
50
+ await this.wsClient.connect()
51
+ }
48
52
  }
49
53
 
50
54
  disconnect() {
51
55
  return this.wsClient.disconnect()
52
56
  }
53
57
 
54
- async dial(params: { to: string; nodeId?: string }) {
58
+ async dial(params: DialParams) {
55
59
  return new Promise(async (resolve, reject) => {
56
60
  try {
57
- console.log('WSClient dial with:', params)
58
-
59
61
  await this.connect()
60
-
61
- // const {
62
- // audio: audioFromConstructor = true,
63
- // video: videoFromConstructor = true,
64
- // iceServers,
65
- // rootElement,
66
- // applyLocalVideoOverlay = true,
67
- // stopCameraWhileMuted = true,
68
- // stopMicrophoneWhileMuted = true,
69
- // speakerId,
70
- // destinationNumber,
71
- // watchMediaPackets,
72
- // watchMediaPacketsTimeout,
73
- // ...userOptions
74
- // } = params
75
-
76
62
  const call = this.wsClient.rooms.makeRoomObject({
77
- // audio,
78
- // video: video === true ? VIDEO_CONSTRAINTS : video,
63
+ audio: params.audio ?? true,
64
+ video: params.video ?? true,
79
65
  negotiateAudio: true,
80
66
  negotiateVideo: true,
81
67
  // iceServers,
82
- rootElement: this.options.rootElement,
68
+ rootElement: params.rootElement,
83
69
  applyLocalVideoOverlay: true,
84
70
  stopCameraWhileMuted: true,
85
71
  stopMicrophoneWhileMuted: true,
@@ -88,7 +74,8 @@ export class WSClient {
88
74
  watchMediaPackets: false,
89
75
  // watchMediaPacketsTimeout:,
90
76
  nodeId: params.nodeId,
91
- disableUdpIceServers: this.options.disableUdpIceServers || false,
77
+ disableUdpIceServers: params.disableUdpIceServers || false,
78
+ unifiedEventing: true,
92
79
  })
93
80
 
94
81
  // WebRTC connection left the room.
@@ -107,14 +94,11 @@ export class WSClient {
107
94
  call.start = () => {
108
95
  return new Promise(async (resolve, reject) => {
109
96
  try {
110
- // @ts-expect-error
111
- call.once('verto.display', () => resolve(call))
112
97
  call.once('room.subscribed', () => resolve(call))
113
98
 
114
99
  await call.join()
115
100
  } catch (error) {
116
101
  getLogger().error('WSClient call start', error)
117
-
118
102
  reject(error)
119
103
  }
120
104
  })
@@ -129,7 +113,7 @@ export class WSClient {
129
113
  })
130
114
  }
131
115
 
132
- handlePushNotification(payload: PushNotification) {
116
+ handlePushNotification(payload: PushNotificationPayload) {
133
117
  return new Promise(async (resolve, reject) => {
134
118
  const { decrypted, type } = payload
135
119
  if (type !== 'call_invite') {
@@ -149,15 +133,6 @@ export class WSClient {
149
133
  display_direction,
150
134
  },
151
135
  } = jsonrpc
152
- this.logger.debug('handlePushNotification data', {
153
- callID,
154
- sdp,
155
- caller_id_name,
156
- caller_id_number,
157
- callee_id_name,
158
- callee_id_number,
159
- display_direction,
160
- })
161
136
  try {
162
137
  // Connect the client first
163
138
  await this.connect()
@@ -170,58 +145,54 @@ export class WSClient {
170
145
  this.logger.warn('Verto Subscribe', error)
171
146
  }
172
147
 
173
- // Build the Call object and return to the user
174
-
175
- // const {
176
- // audio: audioFromConstructor = true,
177
- // video: videoFromConstructor = true,
178
- // iceServers,
179
- // rootElement,
180
- // applyLocalVideoOverlay = true,
181
- // stopCameraWhileMuted = true,
182
- // stopMicrophoneWhileMuted = true,
183
- // speakerId,
184
- // destinationNumber,
185
- // watchMediaPackets,
186
- // watchMediaPacketsTimeout,
187
- // ...userOptions
188
- // } = params
189
-
190
- const call = this.wsClient.rooms.makeRoomObject({
191
- negotiateAudio: true,
192
- negotiateVideo: true,
193
- rootElement: this.options.rootElement,
194
- applyLocalVideoOverlay: true,
195
- stopCameraWhileMuted: true,
196
- stopMicrophoneWhileMuted: true,
197
- // speakerId,
198
- watchMediaPackets: false,
199
- // watchMediaPacketsTimeout:,
200
-
201
- remoteSdp: sdp,
202
- prevCallId: callID,
148
+ this.notifyIncomingInvite('pushNotification', {
149
+ callID,
150
+ sdp,
151
+ caller_id_name,
152
+ caller_id_number,
153
+ callee_id_name,
154
+ callee_id_number,
155
+ display_direction,
203
156
  nodeId,
204
157
  })
205
-
206
- // WebRTC connection left the room.
207
- call.once('destroy', () => {
208
- getLogger().debug('RTC Connection Destroyed')
209
- })
210
-
211
- // @ts-expect-error
212
- call.attachPreConnectWorkers()
213
-
214
- // // @ts-expect-error
215
- // call.attachOnSubscribedWorkers(payload)
216
-
217
- getLogger().debug('Resolving Call', call)
218
- resolve({ resultType: 'inboundCall', resultObject: call })
158
+ resolve({ resultType: 'inboundCall' })
219
159
  } catch (error) {
220
160
  reject(error)
221
161
  }
222
162
  })
223
163
  }
224
164
 
165
+ private notifyIncomingInvite(
166
+ source: InboundCallSource,
167
+ buildCallParams: Omit<IncomingInvite, 'source'>
168
+ ) {
169
+ this._incomingCallManager.handleIncomingInvite({
170
+ source,
171
+ ...buildCallParams,
172
+ })
173
+ }
174
+
175
+ private async executeVertoBye(callId: string, nodeId: string) {
176
+ try {
177
+ // @ts-expect-error
178
+ return await this.wsClient.execute({
179
+ method: 'webrtc.verto',
180
+ params: {
181
+ callID: callId,
182
+ node_id: nodeId,
183
+ message: VertoBye({
184
+ cause: 'USER_BUSY',
185
+ causeCode: '17',
186
+ dialogParams: { callID: callId },
187
+ }),
188
+ },
189
+ })
190
+ } catch (error) {
191
+ this.logger.warn('The call is not available anymore', callId)
192
+ throw error
193
+ }
194
+ }
195
+
225
196
  private async executeVertoSubscribe(callId: string, nodeId: string) {
226
197
  try {
227
198
  // @ts-expect-error
@@ -243,6 +214,44 @@ export class WSClient {
243
214
  }
244
215
  }
245
216
 
217
+ private buildInboundCall(payload: IncomingInvite, params: CallOptions) {
218
+ getLogger().debug('Build new call to answer')
219
+
220
+ const { callID, nodeId, sdp } = payload
221
+
222
+ const call = this.wsClient.rooms.makeRoomObject({
223
+ audio: params.audio ?? true,
224
+ video: params.video ?? true,
225
+ negotiateAudio: true,
226
+ negotiateVideo: true,
227
+ rootElement: params.rootElement,
228
+ applyLocalVideoOverlay: true,
229
+ stopCameraWhileMuted: true,
230
+ stopMicrophoneWhileMuted: true,
231
+ watchMediaPackets: false,
232
+ remoteSdp: sdp,
233
+ prevCallId: callID,
234
+ nodeId,
235
+ disableUdpIceServers: params.disableUdpIceServers || false,
236
+ unifiedEventing: true,
237
+ })
238
+
239
+ // WebRTC connection left the room.
240
+ call.once('destroy', () => {
241
+ getLogger().debug('RTC Connection Destroyed')
242
+ })
243
+
244
+ // @ts-expect-error
245
+ call.attachPreConnectWorkers()
246
+
247
+ getLogger().debug('Resolving Call', call)
248
+
249
+ return call
250
+ }
251
+
252
+ /**
253
+ * Allow user to update the auth token
254
+ */
246
255
  updateToken(token: string): Promise<void> {
247
256
  return new Promise((resolve, reject) => {
248
257
  this.wsClient.once('session.auth_error', (error) => {
@@ -256,4 +265,31 @@ export class WSClient {
256
265
  this.wsClient.reauthenticate(token)
257
266
  })
258
267
  }
268
+
269
+ /**
270
+ * Mark the client as 'online' to receive calls over WebSocket
271
+ */
272
+ async online({ incomingCallHandlers }: OnlineParams) {
273
+ this._incomingCallManager.setNotificationHandlers(incomingCallHandlers)
274
+
275
+ await this.connect()
276
+
277
+ // @ts-expect-error
278
+ return this.wsClient.execute({
279
+ method: 'subscriber.online',
280
+ params: {},
281
+ })
282
+ }
283
+
284
+ /**
285
+ * Mark the client as 'offline' to receive calls over WebSocket
286
+ */
287
+ offline() {
288
+ this._incomingCallManager.setNotificationHandlers({})
289
+ // @ts-expect-error
290
+ return this.wsClient.execute({
291
+ method: 'subscriber.offline',
292
+ params: {},
293
+ })
294
+ }
259
295
  }
@@ -48,6 +48,8 @@ interface HttpClientRequestInit extends Omit<RequestInit, 'body'> {
48
48
  searchParams?: Record<string, any>
49
49
  }
50
50
 
51
+ export type CreateHttpClient = ReturnType<typeof createHttpClient>
52
+
51
53
  export const createHttpClient = (
52
54
  { baseUrl, timeout = 30000, ...globalOptions }: CreateHttpClientOptions,
53
55
  fetcher = http
@@ -1,4 +1,7 @@
1
1
  export * from './Client'
2
2
  export * from './SWClient'
3
3
  export * from './WSClient'
4
+ export * from './HTTPClient'
4
5
  export * from './SignalWire'
6
+ export * from './IncomingCallManager'
7
+ export * from './ConversationAPI'
@@ -0,0 +1,104 @@
1
+ import { type UserOptions } from '@signalwire/core'
2
+ import { BaseRoomSession } from '../BaseRoomSession'
3
+ import { RoomSession } from '../video'
4
+ import { HTTPClient } from './HTTPClient'
5
+ import { WSClient } from './WSClient'
6
+ import { Conversation } from './Conversation'
7
+
8
+ export interface SignalWireOptions extends WSClientOptions {}
9
+
10
+ export interface SignalWireContract {
11
+ httpHost: HTTPClient['httpHost']
12
+ registerDevice: HTTPClient['registerDevice']
13
+ unregisterDevice: HTTPClient['unregisterDevice']
14
+ getSubscriberInfo: HTTPClient['getSubscriberInfo']
15
+ connect: WSClient['connect']
16
+ disconnect: WSClient['disconnect']
17
+ online: WSClient['online']
18
+ offline: WSClient['offline']
19
+ dial: WSClient['dial']
20
+ handlePushNotification: WSClient['handlePushNotification']
21
+ updateToken: WSClient['updateToken']
22
+ address: {
23
+ getAddresses: HTTPClient['getAddresses']
24
+ getAddress: HTTPClient['getAddress']
25
+ }
26
+ conversation: {
27
+ getConversations: Conversation['getConversations']
28
+ getMessages: Conversation['getMessages']
29
+ getConversationMessages: Conversation['getConversationMessages']
30
+ subscribe: Conversation['subscribe']
31
+ sendMessage: Conversation['sendMessage']
32
+ }
33
+ }
34
+
35
+ export interface OnlineParams {
36
+ incomingCallHandlers: IncomingCallHandlers
37
+ }
38
+
39
+ export interface PushNotificationPayload {
40
+ encryption_type: 'aes_256_gcm'
41
+ notification_uuid: string
42
+ with_video: 'true' | 'false'
43
+ incoming_caller_name: string
44
+ incoming_caller_id: string
45
+ tag: string
46
+ invite: string
47
+ title: string
48
+ type: 'call_invite'
49
+ iv: string
50
+ version: string
51
+ decrypted: Record<string, any>
52
+ }
53
+
54
+ export interface CallOptions {
55
+ /** HTML element in which to display the video stream */
56
+ rootElement?: HTMLElement
57
+ /** Disable ICE UDP transport policy */
58
+ disableUdpIceServers?: boolean
59
+ /** Audio constraints to use when joining the room. Default: `true`. */
60
+ audio?: MediaStreamConstraints['audio']
61
+ /** Video constraints to use when joining the room. Default: `true`. */
62
+ video?: MediaStreamConstraints['video']
63
+ }
64
+
65
+ export interface DialParams extends CallOptions {
66
+ to: string
67
+ nodeId?: string
68
+ }
69
+
70
+ export interface WSClientOptions extends UserOptions {
71
+ /** Call back function to receive the incoming call */
72
+ incomingCallHandlers?: IncomingCallHandlers
73
+ }
74
+
75
+ export type InboundCallSource = 'websocket' | 'pushNotification'
76
+
77
+ export interface IncomingInvite {
78
+ source: InboundCallSource
79
+ callID: string
80
+ sdp: string
81
+ caller_id_name: string
82
+ caller_id_number: string
83
+ callee_id_name: string
84
+ callee_id_number: string
85
+ display_direction: string
86
+ nodeId: string
87
+ }
88
+
89
+ export interface IncomingCallNotification {
90
+ invite: {
91
+ details: IncomingInvite
92
+ accept: (param: CallOptions) => Promise<BaseRoomSession<RoomSession>>
93
+ reject: () => Promise<void>
94
+ }
95
+ }
96
+ export type IncomingCallHandler = (
97
+ notification: IncomingCallNotification
98
+ ) => Promise<void>
99
+
100
+ export interface IncomingCallHandlers {
101
+ all?: IncomingCallHandler
102
+ pushNotification?: IncomingCallHandler
103
+ websocket?: IncomingCallHandler
104
+ }