@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,150 @@
1
+ import { HTTPClient } from './HTTPClient'
2
+ import { WSClient } from './WSClient'
3
+ import {
4
+ ConversationEventParams,
5
+ FetchConversationsResponse,
6
+ GetMessagesOptions,
7
+ GetConversationsOptions,
8
+ GetConversationMessagesOptions,
9
+ FetchConversationMessagesResponse,
10
+ ConversationMessage,
11
+ SendConversationMessageOptions,
12
+ SendConversationMessageResponse,
13
+ } from '@signalwire/core'
14
+ import { conversationWorker } from './workers'
15
+ import { buildPaginatedResult } from '../utils/paginatedResult'
16
+ import { makeQueryParamsUrls } from '../utils/makeQueryParamsUrl'
17
+ import { ConversationAPI } from './ConversationAPI'
18
+
19
+ type Callback = (event: ConversationEventParams) => unknown
20
+
21
+ interface ConversationOptions {
22
+ httpClient: HTTPClient
23
+ wsClient: WSClient
24
+ }
25
+
26
+ export class Conversation {
27
+ private httpClient: HTTPClient
28
+ private wsClient: WSClient
29
+ private callbacks: Callback[] = []
30
+
31
+ constructor(options: ConversationOptions) {
32
+ this.httpClient = options.httpClient
33
+ this.wsClient = options.wsClient
34
+
35
+ // @ts-expect-error
36
+ this.wsClient.clientApi.runWorker('conversationWorker', {
37
+ worker: conversationWorker,
38
+ initialState: {
39
+ conversation: this,
40
+ },
41
+ })
42
+ }
43
+
44
+ public async sendMessage(options: SendConversationMessageOptions) {
45
+ try {
46
+ const { addressId, text } = options
47
+ const path = '/api/fabric/messages'
48
+ const { body } =
49
+ await this.httpClient.fetch<SendConversationMessageResponse>(path, {
50
+ method: 'POST',
51
+ body: {
52
+ conversation_id: addressId,
53
+ text,
54
+ },
55
+ })
56
+ return body
57
+ } catch (error) {
58
+ throw new Error('Error sending message to conversation!', error)
59
+ }
60
+ }
61
+
62
+ public async getConversations(options?: GetConversationsOptions) {
63
+ try {
64
+ const { pageSize } = options || {}
65
+
66
+ const path = '/api/fabric/conversations'
67
+ const queryParams = new URLSearchParams()
68
+ if (pageSize) {
69
+ queryParams.append('page_size', pageSize.toString())
70
+ }
71
+
72
+ const { body } = await this.httpClient.fetch<FetchConversationsResponse>(
73
+ makeQueryParamsUrls(path, queryParams)
74
+ )
75
+ const self = this
76
+ const data = body.data.map(
77
+ (conversation) => new ConversationAPI(self, conversation)
78
+ )
79
+ return buildPaginatedResult({ ...body, data }, this.httpClient.fetch)
80
+ } catch (error) {
81
+ throw new Error('Error fetching the conversation history!', error)
82
+ }
83
+ }
84
+
85
+ public async getMessages(options?: GetMessagesOptions) {
86
+ try {
87
+ const { pageSize } = options || {}
88
+
89
+ const path = '/api/fabric/messages'
90
+ const queryParams = new URLSearchParams()
91
+ if (pageSize) {
92
+ queryParams.append('page_size', pageSize.toString())
93
+ }
94
+
95
+ const { body } =
96
+ await this.httpClient.fetch<FetchConversationMessagesResponse>(
97
+ makeQueryParamsUrls(path, queryParams)
98
+ )
99
+
100
+ return buildPaginatedResult<ConversationMessage>(
101
+ body,
102
+ this.httpClient.fetch
103
+ )
104
+ } catch (error) {
105
+ throw new Error('Error fetching the conversation messages!', error)
106
+ }
107
+ }
108
+
109
+ public async getConversationMessages(
110
+ options: GetConversationMessagesOptions
111
+ ) {
112
+ try {
113
+ const { addressId, pageSize } = options || {}
114
+
115
+ const path = `/api/fabric/conversations/${addressId}/messages`
116
+ const queryParams = new URLSearchParams()
117
+ if (pageSize) {
118
+ queryParams.append('page_size', pageSize.toString())
119
+ }
120
+
121
+ const { body } =
122
+ await this.httpClient.fetch<FetchConversationMessagesResponse>(
123
+ makeQueryParamsUrls(path, queryParams)
124
+ )
125
+
126
+ return buildPaginatedResult<ConversationMessage>(
127
+ body,
128
+ this.httpClient.fetch
129
+ )
130
+ } catch (error) {
131
+ throw new Error('Error fetching the conversation messages!', error)
132
+ }
133
+ }
134
+
135
+ public async subscribe(callback: Callback) {
136
+ // Connect the websocket client first
137
+ this.wsClient.connect()
138
+
139
+ this.callbacks.push(callback)
140
+ }
141
+
142
+ /** @internal */
143
+ public handleEvent(event: ConversationEventParams) {
144
+ if (this.callbacks.length) {
145
+ this.callbacks.forEach((callback) => {
146
+ callback(event)
147
+ })
148
+ }
149
+ }
150
+ }
@@ -0,0 +1,44 @@
1
+ import { Conversation } from './Conversation'
2
+ import { Conversation as ConversationType } from '@signalwire/core'
3
+
4
+ export interface ConversationAPISendMessageOptions {
5
+ text: string
6
+ }
7
+
8
+ export interface ConversationAPIGetMessagesOptions {
9
+ pageSize?: number
10
+ }
11
+ export class ConversationAPI {
12
+
13
+ get id() {
14
+ return this.data.id
15
+ }
16
+
17
+ get created_at() {
18
+ return this.data.created_at
19
+ }
20
+
21
+ get last_message_at() {
22
+ return this.data.last_message_at
23
+ }
24
+
25
+ get metadata() {
26
+ return this.data.metadata
27
+ }
28
+
29
+ get name() {
30
+ return this.data.name
31
+ }
32
+
33
+ constructor(private conversation: Conversation, private data: ConversationType) {}
34
+
35
+ sendMessage(options: ConversationAPISendMessageOptions) {
36
+ return this.conversation.sendMessage({
37
+ addressId: this.id,
38
+ text: options.text,
39
+ })
40
+ }
41
+ getMessages(options: ConversationAPIGetMessagesOptions | undefined) {
42
+ return this.conversation.getConversationMessages({ addressId: this.id, ...options })
43
+ }
44
+ }
@@ -1,23 +1,28 @@
1
- import { HTTPClient } from "./HTTPClient";
1
+ import { HTTPClient } from './HTTPClient'
2
2
 
3
3
  describe('HTTPClient Class', () => {
4
- it('Should return the host value from the token ch header', () => {
5
- const client = new HTTPClient({
6
- token: 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiY2giOiJwdWMuc3dpcmUuaW8iLCJ0eXAiOiJTQVQifQ..WI4IT6Bny7lfcU8-.lV5QlKfnONM-5FGwmkllyv747du_UB2nLGqGz3WcB4jemGjofhCzLDhJIiMzp7_xtVjHkV-K2DxiiftxWEgwo3cMn3Eo8ICqA0tZ227tGVEuOztOopsmM3CAMUDej5aovPyznw6grkQ3e7VbzwByDFxs0rS9__c1_bZrAHET1PE8AmigjN35ggY2axEHhSpo7P-vtS321Nv4qURQIococCkWhcUIr0NIbOzTDMJqGLfP2AWSFOtVd9tuyamGMZ0tSUC-JICaS-A4-JdHpKLHbaRn6XTyYj0CKeW1DdrI7uvcglVVN2ooLyWAtv__1MnGdnBoDuXKgzqd2JuiCcN3oIYLt9I3bEu2PWPu1nxumP1aJpk6VXrci0x_nRamRtr9zjVsjzK3RdhYY5Gi1q6Pf1UZvNAPv1-hF1vgthG_QLs-T76HCRm6AN0r_wS97xvBAFbSZ5rCbUR2_1fMG4YOz8dfrlF19WIzY7zaAhMhXiuX.AMbl6Ha3VmKkD40vuz3q6Q'
7
- })
8
- expect(client.httpHost).toEqual('fabric.swire.io');
4
+ it('Should return the host value from the token ch header', () => {
5
+ const client = new HTTPClient({
6
+ token:
7
+ 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiY2giOiJwdWMuc3dpcmUuaW8iLCJ0eXAiOiJTQVQifQ..WI4IT6Bny7lfcU8-.lV5QlKfnONM-5FGwmkllyv747du_UB2nLGqGz3WcB4jemGjofhCzLDhJIiMzp7_xtVjHkV-K2DxiiftxWEgwo3cMn3Eo8ICqA0tZ227tGVEuOztOopsmM3CAMUDej5aovPyznw6grkQ3e7VbzwByDFxs0rS9__c1_bZrAHET1PE8AmigjN35ggY2axEHhSpo7P-vtS321Nv4qURQIococCkWhcUIr0NIbOzTDMJqGLfP2AWSFOtVd9tuyamGMZ0tSUC-JICaS-A4-JdHpKLHbaRn6XTyYj0CKeW1DdrI7uvcglVVN2ooLyWAtv__1MnGdnBoDuXKgzqd2JuiCcN3oIYLt9I3bEu2PWPu1nxumP1aJpk6VXrci0x_nRamRtr9zjVsjzK3RdhYY5Gi1q6Pf1UZvNAPv1-hF1vgthG_QLs-T76HCRm6AN0r_wS97xvBAFbSZ5rCbUR2_1fMG4YOz8dfrlF19WIzY7zaAhMhXiuX.AMbl6Ha3VmKkD40vuz3q6Q',
9
8
  })
10
- it('Should return the host value from the host option', () => {
11
- const client = new HTTPClient({
12
- host: 'server.custom.io',
13
- token: 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiY2giOiJwdWMuc3dpcmUuaW8iLCJ0eXAiOiJTQVQifQ..WI4IT6Bny7lfcU8-.lV5QlKfnONM-5FGwmkllyv747du_UB2nLGqGz3WcB4jemGjofhCzLDhJIiMzp7_xtVjHkV-K2DxiiftxWEgwo3cMn3Eo8ICqA0tZ227tGVEuOztOopsmM3CAMUDej5aovPyznw6grkQ3e7VbzwByDFxs0rS9__c1_bZrAHET1PE8AmigjN35ggY2axEHhSpo7P-vtS321Nv4qURQIococCkWhcUIr0NIbOzTDMJqGLfP2AWSFOtVd9tuyamGMZ0tSUC-JICaS-A4-JdHpKLHbaRn6XTyYj0CKeW1DdrI7uvcglVVN2ooLyWAtv__1MnGdnBoDuXKgzqd2JuiCcN3oIYLt9I3bEu2PWPu1nxumP1aJpk6VXrci0x_nRamRtr9zjVsjzK3RdhYY5Gi1q6Pf1UZvNAPv1-hF1vgthG_QLs-T76HCRm6AN0r_wS97xvBAFbSZ5rCbUR2_1fMG4YOz8dfrlF19WIzY7zaAhMhXiuX.AMbl6Ha3VmKkD40vuz3q6Q'
14
- })
15
- expect(client.httpHost).toEqual('fabric.custom.io');
9
+ expect(client.httpHost).toEqual('fabric.swire.io')
10
+ })
11
+
12
+ it('Should return the host value from the host option', () => {
13
+ const client = new HTTPClient({
14
+ host: 'server.custom.io',
15
+ token:
16
+ 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwiY2giOiJwdWMuc3dpcmUuaW8iLCJ0eXAiOiJTQVQifQ..WI4IT6Bny7lfcU8-.lV5QlKfnONM-5FGwmkllyv747du_UB2nLGqGz3WcB4jemGjofhCzLDhJIiMzp7_xtVjHkV-K2DxiiftxWEgwo3cMn3Eo8ICqA0tZ227tGVEuOztOopsmM3CAMUDej5aovPyznw6grkQ3e7VbzwByDFxs0rS9__c1_bZrAHET1PE8AmigjN35ggY2axEHhSpo7P-vtS321Nv4qURQIococCkWhcUIr0NIbOzTDMJqGLfP2AWSFOtVd9tuyamGMZ0tSUC-JICaS-A4-JdHpKLHbaRn6XTyYj0CKeW1DdrI7uvcglVVN2ooLyWAtv__1MnGdnBoDuXKgzqd2JuiCcN3oIYLt9I3bEu2PWPu1nxumP1aJpk6VXrci0x_nRamRtr9zjVsjzK3RdhYY5Gi1q6Pf1UZvNAPv1-hF1vgthG_QLs-T76HCRm6AN0r_wS97xvBAFbSZ5rCbUR2_1fMG4YOz8dfrlF19WIzY7zaAhMhXiuX.AMbl6Ha3VmKkD40vuz3q6Q',
16
17
  })
17
- it('Should base the host value from default value', () => {
18
- const client = new HTTPClient({
19
- token: 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwidHlwIjoiU0FUIn0..HV7ITWNVgpVAXymg.7SchDC_tOtLy860sMcSpLhBjN1oBHU8ImVc6sZJBGSyDSflZoGi4sVogyK47R9sNaWS0zNBKZFBNfoFE3AeHZTIgcMgYZqS3kUsdLxZv6dNuHvO_pXOJns5OWf2B5MSHyQrNrVv-WDAaFTo2q4AIHitn5o05SEEoEB8zz52BCfFb9NmuN5MpQHH9GZBcBpRAc-fbKLgG17GqYIpRfoGCgzpvcWOCa_Auwfz9WUdSvjEcO6ZDkOsUJVx6N5oA003gwbdWtX4gMU-lBWKSmkN8o6XTPjfn5wV9X5stdA_A_n4K2qW6gtySdxBZMoP3SrY-t0VKDE00l8Yoy7-e8sV7YH4dXSPfMxvEmhYcHiQIF9je5Urwgy6dwMCVi9KaSCBniHeD9-LK--E2gXeCPCFTN5dpvOtyYidXSRAJbeeGM_iaDnphV9-10dpAMtWcFxtxOxZzzpCgG_w30r6_6wMvGNXrIY0NFgQy1w1371s3mmZs.8uiq7Gl0W4YQHYniuBetoA'
20
- })
21
- expect(client.httpHost).toEqual('fabric.signalwire.com');
18
+ expect(client.httpHost).toEqual('fabric.custom.io')
19
+ })
20
+
21
+ it('Should base the host value from default value', () => {
22
+ const client = new HTTPClient({
23
+ token:
24
+ 'eyJhbGciOiJkaXIiLCJlbmMiOiJBMjU2R0NNIiwidHlwIjoiU0FUIn0..HV7ITWNVgpVAXymg.7SchDC_tOtLy860sMcSpLhBjN1oBHU8ImVc6sZJBGSyDSflZoGi4sVogyK47R9sNaWS0zNBKZFBNfoFE3AeHZTIgcMgYZqS3kUsdLxZv6dNuHvO_pXOJns5OWf2B5MSHyQrNrVv-WDAaFTo2q4AIHitn5o05SEEoEB8zz52BCfFb9NmuN5MpQHH9GZBcBpRAc-fbKLgG17GqYIpRfoGCgzpvcWOCa_Auwfz9WUdSvjEcO6ZDkOsUJVx6N5oA003gwbdWtX4gMU-lBWKSmkN8o6XTPjfn5wV9X5stdA_A_n4K2qW6gtySdxBZMoP3SrY-t0VKDE00l8Yoy7-e8sV7YH4dXSPfMxvEmhYcHiQIF9je5Urwgy6dwMCVi9KaSCBniHeD9-LK--E2gXeCPCFTN5dpvOtyYidXSRAJbeeGM_iaDnphV9-10dpAMtWcFxtxOxZzzpCgG_w30r6_6wMvGNXrIY0NFgQy1w1371s3mmZs.8uiq7Gl0W4YQHYniuBetoA',
22
25
  })
23
- });
26
+ expect(client.httpHost).toEqual('fabric.signalwire.com')
27
+ })
28
+ })
@@ -1,22 +1,26 @@
1
+ import jwtDecode from 'jwt-decode'
1
2
  import {
2
- FetchAddressResponse,
3
- GetAddressesOptions,
4
3
  getLogger,
4
+ type Address,
5
+ type FetchAddressResponse,
6
+ type GetAddressesOptions,
5
7
  type UserOptions,
8
+ type SubscriberInfoResponse,
9
+ type RegisterDeviceParams,
10
+ type UnregisterDeviceParams,
11
+ type RegisterDeviceResponse,
12
+ GetAddressOptions,
13
+ GetAddressResponse,
6
14
  } from '@signalwire/core'
7
- import { createHttpClient } from './createHttpClient'
8
- import jwtDecode from 'jwt-decode'
15
+ import { CreateHttpClient, createHttpClient } from './createHttpClient'
16
+ import { buildPaginatedResult } from '../utils/paginatedResult'
17
+ import { makeQueryParamsUrls } from '../utils/makeQueryParamsUrl'
9
18
 
10
19
  type JWTHeader = { ch?: string; typ?: string }
11
20
 
12
- interface RegisterDeviceParams {
13
- deviceType: 'iOS' | 'Android' | 'Desktop'
14
- deviceToken: string
15
- }
16
-
17
21
  // TODO: extends from a Base class to share from core
18
22
  export class HTTPClient {
19
- private httpClient: ReturnType<typeof createHttpClient>
23
+ private httpClient: CreateHttpClient
20
24
 
21
25
  constructor(public options: UserOptions) {
22
26
  this.httpClient = createHttpClient({
@@ -27,11 +31,14 @@ export class HTTPClient {
27
31
  })
28
32
  }
29
33
 
34
+ get fetch(): CreateHttpClient {
35
+ return this.httpClient
36
+ }
37
+
30
38
  get httpHost() {
31
-
32
39
  let decodedJwt: JWTHeader = {}
33
40
  try {
34
- decodedJwt = jwtDecode<JWTHeader>(this.options.token, {
41
+ decodedJwt = jwtDecode<JWTHeader>(this.options.token, {
35
42
  header: true,
36
43
  })
37
44
  } catch (e) {
@@ -46,53 +53,35 @@ export class HTTPClient {
46
53
  return `fabric.${host.split('.').splice(1).join('.')}`
47
54
  }
48
55
 
49
- public async getAddresses(options?: GetAddressesOptions) {
50
- const { type, displayName } = options || {}
51
-
52
- let path = '/addresses' as const
53
-
54
- if (type || displayName) {
55
- const queryParams = new URLSearchParams()
56
+ public async getAddress(options: GetAddressOptions) {
57
+ const { id } = options
58
+ let path = `/api/fabric/addresses/${id}`
59
+
60
+ const { body } = await this.httpClient<GetAddressResponse>(path)
61
+ return body
62
+ }
56
63
 
57
- if (type) {
58
- queryParams.append('type', type)
59
- }
64
+ public async getAddresses(options?: GetAddressesOptions) {
65
+ const { type, displayName, pageSize } = options || {}
60
66
 
61
- if (displayName) {
62
- queryParams.append('display_name', displayName)
63
- }
67
+ let path = '/api/fabric/addresses'
64
68
 
65
- path += `?${queryParams.toString()}`
69
+ const queryParams = new URLSearchParams()
70
+ if (type) {
71
+ queryParams.append('type', type)
66
72
  }
67
-
68
- const { body } = await this.httpClient<FetchAddressResponse>(path)
69
-
70
- const anotherPage = async (url: string) => {
71
- const { body } = await this.httpClient<FetchAddressResponse>(url)
72
- return buildResult(body)
73
+ if (displayName) {
74
+ queryParams.append('display_name', displayName)
73
75
  }
74
-
75
- const buildResult = (body: FetchAddressResponse) => {
76
- return {
77
- addresses: body.data,
78
- nextPage: async () => {
79
- const { next } = body.links
80
- return next ? anotherPage(next) : undefined
81
- },
82
- prevPage: async () => {
83
- const { prev } = body.links
84
- return prev ? anotherPage(prev) : undefined
85
- },
86
- firstPage: async () => {
87
- const { first } = body.links
88
- return first ? anotherPage(first) : undefined
89
- },
90
- hasNext: Boolean(body.links.next),
91
- hasPrev: Boolean(body.links.prev),
92
- }
76
+ if (pageSize) {
77
+ queryParams.append('page_size', pageSize.toString())
93
78
  }
94
79
 
95
- return buildResult(body)
80
+ const { body } = await this.httpClient<FetchAddressResponse>(
81
+ makeQueryParamsUrls(path, queryParams)
82
+ )
83
+
84
+ return buildPaginatedResult<Address>(body, this.httpClient)
96
85
  }
97
86
 
98
87
  public async registerDevice({
@@ -100,7 +89,7 @@ export class HTTPClient {
100
89
  deviceToken,
101
90
  }: RegisterDeviceParams) {
102
91
  const path = '/subscriber/devices' as const
103
- const { body } = await this.httpClient<any>(path, {
92
+ const { body } = await this.httpClient<RegisterDeviceResponse>(path, {
104
93
  method: 'POST',
105
94
  body: {
106
95
  device_type: deviceType,
@@ -111,10 +100,18 @@ export class HTTPClient {
111
100
  return body
112
101
  }
113
102
 
114
- public async unregisterDevice({ id }: { id: string }) {
103
+ public async unregisterDevice({ id }: UnregisterDeviceParams) {
115
104
  const path = `/subscriber/devices/${id}` as const
116
- return await this.httpClient<any>(path, {
105
+ return await this.httpClient<void>(path, {
117
106
  method: 'DELETE',
118
107
  })
119
108
  }
109
+
110
+ public async getSubscriberInfo() {
111
+ let path = '/api/fabric/subscriber/info'
112
+
113
+ const { body } = await this.httpClient<SubscriberInfoResponse>(path)
114
+
115
+ return body
116
+ }
120
117
  }
@@ -0,0 +1,245 @@
1
+ import { IncomingCallManager, IncomingCallNotification } from './IncomingCallManager'
2
+
3
+ describe('IncomingCallManager', () => {
4
+ const answer = jest.fn()
5
+ const buildCall = () => ({ answer })
6
+ const rejectCall = jest.fn().mockResolvedValue(null)
7
+
8
+ beforeAll(() => {
9
+ jest.resetAllMocks()
10
+ })
11
+
12
+ test('It should invoke the proper listeners', () => {
13
+ //@ts-ignore
14
+ const manager = new IncomingCallManager(buildCall, rejectCall)
15
+ const allNotificationListerner = jest.fn()
16
+ const pnNotificationListerner = jest.fn()
17
+ const wsNotificationListerner = jest.fn()
18
+
19
+ manager.setNotificationHandlers({
20
+ all: allNotificationListerner,
21
+ websocket: wsNotificationListerner,
22
+ pushNotification: pnNotificationListerner,
23
+ })
24
+
25
+ manager.handleIncomingInvite({
26
+ source: 'websocket',
27
+ callID: 'foo1',
28
+ callee_id_name: 'foo',
29
+ callee_id_number: 'foo',
30
+ caller_id_name: 'foo',
31
+ caller_id_number: 'foo',
32
+ sdp: 'foo',
33
+ display_direction: 'foo',
34
+ nodeId: 'foo'
35
+ })
36
+
37
+ expect(allNotificationListerner).toHaveBeenCalledTimes(1)
38
+ expect(wsNotificationListerner).toHaveBeenCalledTimes(1)
39
+ expect(pnNotificationListerner).toHaveBeenCalledTimes(0)
40
+
41
+ manager.handleIncomingInvite({
42
+ source: 'pushNotification',
43
+ callID: 'foo2',
44
+ callee_id_name: 'foo',
45
+ callee_id_number: 'foo',
46
+ caller_id_name: 'foo',
47
+ caller_id_number: 'foo',
48
+ sdp: 'foo',
49
+ display_direction: 'foo',
50
+ nodeId: 'foo'
51
+ })
52
+
53
+ expect(allNotificationListerner).toHaveBeenCalledTimes(2)
54
+ expect(wsNotificationListerner).toHaveBeenCalledTimes(1)
55
+ expect(pnNotificationListerner).toHaveBeenCalledTimes(1)
56
+
57
+ })
58
+
59
+ test('It should not answer the call when the invite is rejected', () => {
60
+ //@ts-ignore
61
+ const manager = new IncomingCallManager(buildCall, rejectCall)
62
+ const allNotificationListerner = jest.fn((notification: IncomingCallNotification) => {notification.invite.reject()})
63
+
64
+ manager.setNotificationHandlers({
65
+ //@ts-ignore
66
+ all: allNotificationListerner,
67
+ })
68
+
69
+ manager.handleIncomingInvite({
70
+ source: 'websocket',
71
+ callID: 'foo1',
72
+ callee_id_name: 'foo',
73
+ callee_id_number: 'foo',
74
+ caller_id_name: 'foo',
75
+ caller_id_number: 'foo',
76
+ sdp: 'foo',
77
+ display_direction: 'foo',
78
+ nodeId: 'foo'
79
+ })
80
+
81
+ expect(allNotificationListerner).toHaveBeenCalledTimes(1)
82
+ expect(answer).toBeCalledTimes(0)
83
+ })
84
+
85
+ test('It should answer the call when the invite is accepted', () => {
86
+ //@ts-ignore
87
+ const manager = new IncomingCallManager(buildCall, rejectCall)
88
+ //@ts-ignore
89
+ const allNotificationListerner = jest.fn((notification: IncomingCallNotification) => {notification.invite.accept({})})
90
+
91
+ manager.setNotificationHandlers({
92
+ //@ts-ignore
93
+ all: allNotificationListerner,
94
+ })
95
+
96
+ manager.handleIncomingInvite({
97
+ source: 'websocket',
98
+ callID: 'foo1',
99
+ callee_id_name: 'foo',
100
+ callee_id_number: 'foo',
101
+ caller_id_name: 'foo',
102
+ caller_id_number: 'foo',
103
+ sdp: 'foo',
104
+ display_direction: 'foo',
105
+ nodeId: 'foo'
106
+ })
107
+
108
+ expect(allNotificationListerner).toHaveBeenCalledTimes(1)
109
+ expect(answer).toBeCalledTimes(1)
110
+ })
111
+
112
+ test('It should dedupe overlaping listeners', () => {
113
+ //@ts-ignore
114
+ const manager = new IncomingCallManager(buildCall, rejectCall)
115
+ const notificationListerner = jest.fn()
116
+ manager.setNotificationHandlers({
117
+ all: notificationListerner,
118
+ websocket: notificationListerner,
119
+ pushNotification: notificationListerner,
120
+ })
121
+
122
+ manager.handleIncomingInvite({
123
+ source: 'websocket',
124
+ callID: 'foo',
125
+ callee_id_name: 'foo',
126
+ callee_id_number: 'foo',
127
+ caller_id_name: 'foo',
128
+ caller_id_number: 'foo',
129
+ sdp: 'foo',
130
+ display_direction: 'foo',
131
+ nodeId: 'foo'
132
+ })
133
+
134
+ expect(notificationListerner).toHaveBeenCalledTimes(1)
135
+ })
136
+
137
+ test('It should dedupe invites', () => {
138
+ //@ts-ignore
139
+ const manager = new IncomingCallManager(buildCall, rejectCall)
140
+ const notificationListerner = jest.fn()
141
+ manager.setNotificationHandlers({
142
+ all: notificationListerner,
143
+ })
144
+
145
+ manager.handleIncomingInvite({
146
+ source: 'websocket',
147
+ callID: 'same-id',
148
+ callee_id_name: 'foo',
149
+ callee_id_number: 'foo',
150
+ caller_id_name: 'foo',
151
+ caller_id_number: 'foo',
152
+ sdp: 'foo',
153
+ display_direction: 'foo',
154
+ nodeId: 'foo'
155
+ })
156
+
157
+ manager.handleIncomingInvite({
158
+ source: 'websocket',
159
+ callID: 'same-id',
160
+ callee_id_name: 'foo',
161
+ callee_id_number: 'foo',
162
+ caller_id_name: 'foo',
163
+ caller_id_number: 'foo',
164
+ sdp: 'foo',
165
+ display_direction: 'foo',
166
+ nodeId: 'foo'
167
+ })
168
+
169
+ expect(notificationListerner).toHaveBeenCalledTimes(1)
170
+ })
171
+
172
+ test('It should clean up invites after reject', () => {
173
+ //@ts-ignore
174
+ const manager = new IncomingCallManager(buildCall, rejectCall)
175
+ const notificationListerner = jest.fn((notification: IncomingCallNotification) => {notification.invite.reject()})
176
+ manager.setNotificationHandlers({
177
+ //@ts-ignore
178
+ all: notificationListerner,
179
+ })
180
+
181
+ manager.handleIncomingInvite({
182
+ source: 'websocket',
183
+ callID: 'same-id',
184
+ callee_id_name: 'foo',
185
+ callee_id_number: 'foo',
186
+ caller_id_name: 'foo',
187
+ caller_id_number: 'foo',
188
+ sdp: 'foo',
189
+ display_direction: 'foo',
190
+ nodeId: 'foo'
191
+ })
192
+
193
+ manager.handleIncomingInvite({
194
+ source: 'websocket',
195
+ callID: 'same-id',
196
+ callee_id_name: 'foo',
197
+ callee_id_number: 'foo',
198
+ caller_id_name: 'foo',
199
+ caller_id_number: 'foo',
200
+ sdp: 'foo',
201
+ display_direction: 'foo',
202
+ nodeId: 'foo'
203
+ })
204
+
205
+ expect(notificationListerner).toHaveBeenCalledTimes(2)
206
+ })
207
+
208
+ test('It should clean up invites after accept', () => {
209
+ //@ts-ignore
210
+ const manager = new IncomingCallManager(buildCall, rejectCall)
211
+ //@ts-ignore
212
+ const notificationListerner = jest.fn((notification: IncomingCallNotification) => {notification.invite.accept({})})
213
+ manager.setNotificationHandlers({
214
+ //@ts-ignore
215
+ all: notificationListerner,
216
+ })
217
+
218
+ manager.handleIncomingInvite({
219
+ source: 'websocket',
220
+ callID: 'same-id',
221
+ callee_id_name: 'foo',
222
+ callee_id_number: 'foo',
223
+ caller_id_name: 'foo',
224
+ caller_id_number: 'foo',
225
+ sdp: 'foo',
226
+ display_direction: 'foo',
227
+ nodeId: 'foo'
228
+ })
229
+
230
+ manager.handleIncomingInvite({
231
+ source: 'websocket',
232
+ callID: 'same-id',
233
+ callee_id_name: 'foo',
234
+ callee_id_number: 'foo',
235
+ caller_id_name: 'foo',
236
+ caller_id_number: 'foo',
237
+ sdp: 'foo',
238
+ display_direction: 'foo',
239
+ nodeId: 'foo'
240
+ })
241
+
242
+ expect(notificationListerner).toHaveBeenCalledTimes(2)
243
+ })
244
+
245
+ })