@morgan-stanley/composeui-fdc3 0.1.0-alpha.5

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 (75) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +6 -0
  3. package/jest.config.ts +23 -0
  4. package/package.json +49 -0
  5. package/rollup.config.js +16 -0
  6. package/src/ComposeUIChannel.spec.ts +242 -0
  7. package/src/ComposeUIContextListener.spec.ts +109 -0
  8. package/src/ComposeUIDesktopAgent.spec.ts +197 -0
  9. package/src/ComposeUIDesktopAgent.ts +252 -0
  10. package/src/ComposeUIIntentHandling.spec.ts +369 -0
  11. package/src/ComposeUIMessageRouterChannelFactory.spec.ts +200 -0
  12. package/src/ComposeUIMessageRouterMetadataClient.spec.ts +240 -0
  13. package/src/ComposeUIMessageRouterOpenClient.spec.ts +239 -0
  14. package/src/index.ts +66 -0
  15. package/src/infrastructure/ChannelFactory.ts +25 -0
  16. package/src/infrastructure/ChannelItem.ts +20 -0
  17. package/src/infrastructure/ChannelType.ts +14 -0
  18. package/src/infrastructure/ComposeUIChannel.ts +87 -0
  19. package/src/infrastructure/ComposeUIContextListener.ts +154 -0
  20. package/src/infrastructure/ComposeUIErrors.ts +21 -0
  21. package/src/infrastructure/ComposeUIIntentListener.ts +105 -0
  22. package/src/infrastructure/ComposeUIIntentResolution.ts +58 -0
  23. package/src/infrastructure/ComposeUIPrivateChannel.ts +197 -0
  24. package/src/infrastructure/ComposeUITopic.ts +155 -0
  25. package/src/infrastructure/IntentsClient.ts +22 -0
  26. package/src/infrastructure/MessageRouterChannelFactory.ts +182 -0
  27. package/src/infrastructure/MessageRouterIntentsClient.ts +125 -0
  28. package/src/infrastructure/MessageRouterMetadataClient.ts +75 -0
  29. package/src/infrastructure/MessageRouterOpenClient.ts +106 -0
  30. package/src/infrastructure/MetadataClient.ts +19 -0
  31. package/src/infrastructure/OpenAppIdentifier.ts +18 -0
  32. package/src/infrastructure/OpenClient.ts +18 -0
  33. package/src/infrastructure/PrivateChannelContextListenerEventListener.ts +45 -0
  34. package/src/infrastructure/PrivateChannelDisconnectEventListener.ts +45 -0
  35. package/src/infrastructure/messages/Fdc3AddContextListenerRequest.ts +22 -0
  36. package/src/infrastructure/messages/Fdc3AddContextListenerResponse.ts +17 -0
  37. package/src/infrastructure/messages/Fdc3CreateAppChannelRequest.ts +17 -0
  38. package/src/infrastructure/messages/Fdc3CreateAppChannelResponse.ts +17 -0
  39. package/src/infrastructure/messages/Fdc3CreatePrivateChannelRequest.ts +16 -0
  40. package/src/infrastructure/messages/Fdc3CreatePrivateChannelResponse.ts +17 -0
  41. package/src/infrastructure/messages/Fdc3FindChannelRequest.ts +24 -0
  42. package/src/infrastructure/messages/Fdc3FindChannelResponse.ts +17 -0
  43. package/src/infrastructure/messages/Fdc3FindInstancesRequest.ts +17 -0
  44. package/src/infrastructure/messages/Fdc3FindInstancesResponse.ts +18 -0
  45. package/src/infrastructure/messages/Fdc3FindIntentRequest.ts +24 -0
  46. package/src/infrastructure/messages/Fdc3FindIntentResponse.ts +19 -0
  47. package/src/infrastructure/messages/Fdc3FindIntentsByContextRequest.ts +23 -0
  48. package/src/infrastructure/messages/Fdc3FindIntentsByContextResponse.ts +19 -0
  49. package/src/infrastructure/messages/Fdc3GetAppMetadataRequest.ts +17 -0
  50. package/src/infrastructure/messages/Fdc3GetAppMetadataResponse.ts +18 -0
  51. package/src/infrastructure/messages/Fdc3GetCurrentContextRequest.ts +18 -0
  52. package/src/infrastructure/messages/Fdc3GetInfoRequest.ts +17 -0
  53. package/src/infrastructure/messages/Fdc3GetInfoResponse.ts +18 -0
  54. package/src/infrastructure/messages/Fdc3GetIntentResultRequest.ts +23 -0
  55. package/src/infrastructure/messages/Fdc3GetIntentResultResponse.ts +23 -0
  56. package/src/infrastructure/messages/Fdc3GetOpenedAppContextRequest.ts +15 -0
  57. package/src/infrastructure/messages/Fdc3GetOpenedAppContextResponse.ts +18 -0
  58. package/src/infrastructure/messages/Fdc3GetUserChannelsRequest.ts +15 -0
  59. package/src/infrastructure/messages/Fdc3GetUserChannelsResponse.ts +18 -0
  60. package/src/infrastructure/messages/Fdc3IntentListenerRequest.ts +22 -0
  61. package/src/infrastructure/messages/Fdc3IntentListenerResponse.ts +17 -0
  62. package/src/infrastructure/messages/Fdc3JoinUserChannelRequest.ts +15 -0
  63. package/src/infrastructure/messages/Fdc3JoinUserChannelResponse.ts +20 -0
  64. package/src/infrastructure/messages/Fdc3OpenRequest.ts +21 -0
  65. package/src/infrastructure/messages/Fdc3OpenResponse.ts +18 -0
  66. package/src/infrastructure/messages/Fdc3PrivateChannelInternalEvent.ts +26 -0
  67. package/src/infrastructure/messages/Fdc3RaiseIntentForContextRequest.ts +20 -0
  68. package/src/infrastructure/messages/Fdc3RaiseIntentRequest.ts +24 -0
  69. package/src/infrastructure/messages/Fdc3RaiseIntentResolutionRequest.ts +20 -0
  70. package/src/infrastructure/messages/Fdc3RaiseIntentResponse.ts +21 -0
  71. package/src/infrastructure/messages/Fdc3RemoveContextListenerRequest.ts +19 -0
  72. package/src/infrastructure/messages/Fdc3RemoveContextListenerResponse.ts +17 -0
  73. package/src/infrastructure/messages/Fdc3StoreIntentResultRequest.ts +29 -0
  74. package/src/infrastructure/messages/Fdc3StoreIntentResultResponse.ts +17 -0
  75. package/tsconfig.json +15 -0
@@ -0,0 +1,240 @@
1
+ /*
2
+ * Morgan Stanley makes this available to you under the Apache License,
3
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
4
+ * http://www.apache.org/licenses/LICENSE-2.0.
5
+ * See the NOTICE file distributed with this work for additional information
6
+ * regarding copyright ownership. Unless required by applicable law or agreed
7
+ * to in writing, software distributed under the License is distributed on an
8
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9
+ * or implied. See the License for the specific language governing permissions
10
+ * and limitations under the License.
11
+ */
12
+
13
+ import { ImplementationMetadata } from "@finos/fdc3";
14
+ import { ComposeUIDesktopAgent } from "./ComposeUIDesktopAgent";
15
+ import { ComposeUIErrors } from "./infrastructure/ComposeUIErrors";
16
+ import { Fdc3GetInfoResponse } from "./infrastructure/messages/Fdc3GetInfoResponse";
17
+ import { Fdc3FindInstancesResponse } from "./infrastructure/messages/Fdc3FindInstancesResponse";
18
+ import { Fdc3GetAppMetadataResponse } from "./infrastructure/messages/Fdc3GetAppMetadataResponse";
19
+
20
+ describe('MessageRouterMetadataClient tests', () => {
21
+ beforeEach(() => {
22
+ window.composeui = {
23
+ fdc3: {
24
+ config: {
25
+ appId: "testAppId",
26
+ instanceId: "testInstanceId"
27
+ },
28
+ channelId: "test",
29
+ openAppIdentifier: {
30
+ openedAppContextId: "test"
31
+ }
32
+ }
33
+ };
34
+ });
35
+
36
+ it('getInfo returns no payload', async () => {
37
+ const messageRouterClientMock = {
38
+ clientId: "dummy",
39
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
40
+ publish: jest.fn(() => { return Promise.resolve() }),
41
+ connect: jest.fn(() => { return Promise.resolve() }),
42
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
43
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
44
+ registerService: jest.fn(() => { return Promise.resolve() }),
45
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
46
+ invoke: jest.fn(() => { return Promise.resolve(undefined) })
47
+ };
48
+
49
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
50
+
51
+ await expect(desktopAgent.getInfo())
52
+ .rejects
53
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
54
+ });
55
+
56
+ it('getInfo returns error', async() => {
57
+ const messageRouterClientMock = {
58
+ clientId: "dummy",
59
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
60
+ publish: jest.fn(() => { return Promise.resolve() }),
61
+ connect: jest.fn(() => { return Promise.resolve() }),
62
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
63
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
64
+ registerService: jest.fn(() => { return Promise.resolve() }),
65
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
66
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify({ error: "dummyError" })}`) })
67
+ };
68
+
69
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
70
+
71
+ await expect(desktopAgent.getInfo())
72
+ .rejects
73
+ .toThrow('dummyError');
74
+ });
75
+
76
+ it('getInfo returns ImplemetationMetadata', async() => {
77
+ const implementationMetadata: ImplementationMetadata = {
78
+ fdc3Version: '2.0.0',
79
+ provider: 'ComposeUI',
80
+ providerVersion: '1.0.0',
81
+ optionalFeatures: {
82
+ OriginatingAppMetadata: false,
83
+ UserChannelMembershipAPIs: true
84
+ },
85
+ appMetadata: {
86
+ appId: 'dummyAppId'
87
+ }
88
+ };
89
+
90
+ const response : Fdc3GetInfoResponse = {
91
+ implementationMetadata: implementationMetadata
92
+ };
93
+
94
+ const messageRouterClientMock = {
95
+ clientId: "dummy",
96
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
97
+ publish: jest.fn(() => { return Promise.resolve() }),
98
+ connect: jest.fn(() => { return Promise.resolve() }),
99
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
100
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
101
+ registerService: jest.fn(() => { return Promise.resolve() }),
102
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
103
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
104
+ };
105
+
106
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
107
+
108
+ var result = await desktopAgent.getInfo();
109
+ expect(result).toMatchObject(implementationMetadata);
110
+ });
111
+
112
+
113
+ it('findInstances returns no payload', async () => {
114
+ const messageRouterClientMock = {
115
+ clientId: "dummy",
116
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
117
+ publish: jest.fn(() => { return Promise.resolve() }),
118
+ connect: jest.fn(() => { return Promise.resolve() }),
119
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
120
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
121
+ registerService: jest.fn(() => { return Promise.resolve() }),
122
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
123
+ invoke: jest.fn(() => { return Promise.resolve(undefined) })
124
+ };
125
+
126
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
127
+
128
+ await expect(desktopAgent.findInstances({appId: "test"}))
129
+ .rejects
130
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
131
+ });
132
+
133
+ it('findInstances returns error', async() => {
134
+ const messageRouterClientMock = {
135
+ clientId: "dummy",
136
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
137
+ publish: jest.fn(() => { return Promise.resolve() }),
138
+ connect: jest.fn(() => { return Promise.resolve() }),
139
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
140
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
141
+ registerService: jest.fn(() => { return Promise.resolve() }),
142
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
143
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify({ error: "dummyError" })}`) })
144
+ };
145
+
146
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
147
+
148
+ await expect(desktopAgent.findInstances({appId: "test"}))
149
+ .rejects
150
+ .toThrow('dummyError');
151
+ });
152
+
153
+ it('findInstances return instances', async() => {
154
+
155
+ const response : Fdc3FindInstancesResponse = {
156
+ instances: [{appId: "test", instanceId: "id"}]
157
+ };
158
+
159
+ const messageRouterClientMock = {
160
+ clientId: "dummy",
161
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
162
+ publish: jest.fn(() => { return Promise.resolve() }),
163
+ connect: jest.fn(() => { return Promise.resolve() }),
164
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
165
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
166
+ registerService: jest.fn(() => { return Promise.resolve() }),
167
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
168
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
169
+ };
170
+
171
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
172
+
173
+ var result = await desktopAgent.findInstances({appId: "test"});
174
+ expect(result).toMatchObject([{appId: "test", instanceId: "id"}]);
175
+ });
176
+
177
+ it('getAppMetadata returns no payload', async () => {
178
+ const messageRouterClientMock = {
179
+ clientId: "dummy",
180
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
181
+ publish: jest.fn(() => { return Promise.resolve() }),
182
+ connect: jest.fn(() => { return Promise.resolve() }),
183
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
184
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
185
+ registerService: jest.fn(() => { return Promise.resolve() }),
186
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
187
+ invoke: jest.fn(() => { return Promise.resolve(undefined) })
188
+ };
189
+
190
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
191
+
192
+ await expect(desktopAgent.getAppMetadata({appId: "test"}))
193
+ .rejects
194
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
195
+ });
196
+
197
+ it('getAppMetadata returns error', async() => {
198
+ const messageRouterClientMock = {
199
+ clientId: "dummy",
200
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
201
+ publish: jest.fn(() => { return Promise.resolve() }),
202
+ connect: jest.fn(() => { return Promise.resolve() }),
203
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
204
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
205
+ registerService: jest.fn(() => { return Promise.resolve() }),
206
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
207
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify({ error: "dummyError" })}`) })
208
+ };
209
+
210
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
211
+
212
+ await expect(desktopAgent.getAppMetadata({appId: "test"}))
213
+ .rejects
214
+ .toThrow('dummyError');
215
+ });
216
+
217
+ it('getAppMetadata return instances', async() => {
218
+
219
+ const response : Fdc3GetAppMetadataResponse = {
220
+ appMetadata: { appId: "test" }
221
+ };
222
+
223
+ const messageRouterClientMock = {
224
+ clientId: "dummy",
225
+ subscribe: jest.fn(() => { return Promise.resolve({unsubscribe: () => {}});}),
226
+ publish: jest.fn(() => { return Promise.resolve() }),
227
+ connect: jest.fn(() => { return Promise.resolve() }),
228
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
229
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
230
+ registerService: jest.fn(() => { return Promise.resolve() }),
231
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
232
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
233
+ };
234
+
235
+ const desktopAgent = new ComposeUIDesktopAgent(messageRouterClientMock);
236
+
237
+ var result = await desktopAgent.getAppMetadata({appId: "test"});
238
+ expect(result).toMatchObject({appId: "test"});
239
+ });
240
+ });
@@ -0,0 +1,239 @@
1
+ /*
2
+ * Morgan Stanley makes this available to you under the Apache License,
3
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
4
+ * http://www.apache.org/licenses/LICENSE-2.0.
5
+ * See the NOTICE file distributed with this work for additional information
6
+ * regarding copyright ownership. Unless required by applicable law or agreed
7
+ * to in writing, software distributed under the License is distributed on an
8
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9
+ * or implied. See the License for the specific language governing permissions
10
+ * and limitations under the License.
11
+ */
12
+
13
+ import { getCurrentChannel, OpenError } from "@finos/fdc3";
14
+ import { MessageRouterOpenClient } from "./infrastructure/MessageRouterOpenClient";
15
+ import { ComposeUIErrors } from "./infrastructure/ComposeUIErrors";
16
+ import { Fdc3OpenResponse } from "./infrastructure/messages/Fdc3OpenResponse";
17
+ import { MessageRouter } from "@morgan-stanley/composeui-messaging-client";
18
+ import { Fdc3GetOpenedAppContextResponse } from "./infrastructure/messages/Fdc3GetOpenedAppContextResponse";
19
+ import { OpenAppIdentifier } from "./infrastructure/OpenAppIdentifier";
20
+ import { rejects } from "assert";
21
+
22
+ describe('MessageRouter OpenClient tests', () => {
23
+ let client: MessageRouterOpenClient;
24
+ let messageRouterClient: MessageRouter;
25
+ const openAppIdentifier: OpenAppIdentifier = { openedAppContextId: "contextId" };
26
+
27
+ beforeEach(() => {
28
+ window.composeui = {
29
+ fdc3: {
30
+ config: {
31
+ appId: "testAppId",
32
+ instanceId: "testInstanceId"
33
+ },
34
+ channelId: "test",
35
+ openAppIdentifier: {
36
+ openedAppContextId: "contextId"
37
+ }
38
+ }
39
+ };
40
+
41
+ messageRouterClient = {
42
+ clientId: "dummy",
43
+ subscribe: jest.fn(() => {
44
+ return Promise.resolve({ unsubscribe: () => { } });
45
+ }),
46
+
47
+ publish: jest.fn(() => { return Promise.resolve() }),
48
+ connect: jest.fn(() => { return Promise.resolve() }),
49
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
50
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
51
+ registerService: jest.fn(() => { return Promise.resolve() }),
52
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
53
+ invoke: jest.fn(() => { return Promise.resolve(undefined) })
54
+ };
55
+
56
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
57
+ });
58
+
59
+ it('open throws AppNotFound error as AppIdentifier not set', async() => {
60
+ await expect(client.open())
61
+ .rejects
62
+ .toThrow(OpenError.AppNotFound);
63
+ });
64
+
65
+ it('open throws NoAnswerWasProvided error as no response received by the MessageRouter server', async() => {
66
+ await expect(client.open("appId1"))
67
+ .rejects
68
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
69
+ });
70
+
71
+ it('open throws error as error response received by the MessageRouter server', async() => {
72
+ const response: Fdc3OpenResponse = {
73
+ error: "testError"
74
+ };
75
+
76
+ messageRouterClient = {
77
+ clientId: "dummy",
78
+ subscribe: jest.fn(() => {
79
+ return Promise.resolve({ unsubscribe: () => { } });
80
+ }),
81
+
82
+ publish: jest.fn(() => { return Promise.resolve() }),
83
+ connect: jest.fn(() => { return Promise.resolve() }),
84
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
85
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
86
+ registerService: jest.fn(() => { return Promise.resolve() }),
87
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
88
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
89
+ };
90
+
91
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
92
+ await expect(client.open("appId1"))
93
+ .rejects
94
+ .toThrow("testError");
95
+ });
96
+
97
+ it('open returns AppIdentifier response received by the MessageRouter server', async() => {
98
+ const response: Fdc3OpenResponse = {
99
+ appIdentifier: {
100
+ appId: "appId1",
101
+ instanceId: "instanceId1"
102
+ }
103
+ };
104
+
105
+ messageRouterClient = {
106
+ clientId: "dummy",
107
+ subscribe: jest.fn(() => {
108
+ return Promise.resolve({ unsubscribe: () => { } });
109
+ }),
110
+
111
+ publish: jest.fn(() => { return Promise.resolve() }),
112
+ connect: jest.fn(() => { return Promise.resolve() }),
113
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
114
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
115
+ registerService: jest.fn(() => { return Promise.resolve() }),
116
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
117
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
118
+ }
119
+
120
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
121
+ const result = await client.open({appId: "appId1"}, {type: "fdc3.instrument"});
122
+ expect(result).toMatchObject({appId: "appId1", instanceId: "instanceId1"});
123
+ });
124
+
125
+ it('getOpenedAppContext throws error as context id is not set', async() => {
126
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient);
127
+ await expect(client.getOpenedAppContext())
128
+ .rejects
129
+ .toThrow("Context id is not defined on the window object.");
130
+ });
131
+
132
+ it('getOpenedAppContext throws NoAnswerWasProvided error as no response received from the MessageRouter server', async() => {
133
+ await expect(client.getOpenedAppContext())
134
+ .rejects
135
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
136
+ });
137
+
138
+ it('getOpenedAppContext throws NoAnswerWasProvided error as not correct response received from the MessageRouter server', async() => {
139
+ const response = {
140
+ payload: "wrongPayload"
141
+ };
142
+
143
+ messageRouterClient = {
144
+ clientId: "dummy",
145
+ subscribe: jest.fn(() => {
146
+ return Promise.resolve({ unsubscribe: () => { } });
147
+ }),
148
+
149
+ publish: jest.fn(() => { return Promise.resolve() }),
150
+ connect: jest.fn(() => { return Promise.resolve() }),
151
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
152
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
153
+ registerService: jest.fn(() => { return Promise.resolve() }),
154
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
155
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
156
+ };
157
+
158
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
159
+ await expect(client.getOpenedAppContext())
160
+ .rejects
161
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
162
+ });
163
+
164
+ it('getOpenedAppContext throws error as error response received from the MessageRouter server', async() => {
165
+ const response: Fdc3GetOpenedAppContextResponse = {
166
+ error: "testGetOpenedAppContextError"
167
+ };
168
+
169
+ messageRouterClient = {
170
+ clientId: "dummy",
171
+ subscribe: jest.fn(() => {
172
+ return Promise.resolve({ unsubscribe: () => { } });
173
+ }),
174
+
175
+ publish: jest.fn(() => { return Promise.resolve() }),
176
+ connect: jest.fn(() => { return Promise.resolve() }),
177
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
178
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
179
+ registerService: jest.fn(() => { return Promise.resolve() }),
180
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
181
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
182
+ };
183
+
184
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
185
+ await expect(client.getOpenedAppContext())
186
+ .rejects
187
+ .toThrow("testGetOpenedAppContextError");
188
+ });
189
+
190
+ it('getOpenedAppContext throws NoAnswerWasProvided error as no context response received from the MessageRouter server', async() => {
191
+ const response: Fdc3GetOpenedAppContextResponse = { };
192
+
193
+ messageRouterClient = {
194
+ clientId: "dummy",
195
+ subscribe: jest.fn(() => {
196
+ return Promise.resolve({ unsubscribe: () => { } });
197
+ }),
198
+
199
+ publish: jest.fn(() => { return Promise.resolve() }),
200
+ connect: jest.fn(() => { return Promise.resolve() }),
201
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
202
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
203
+ registerService: jest.fn(() => { return Promise.resolve() }),
204
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
205
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
206
+ };
207
+
208
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
209
+ await expect(client.getOpenedAppContext())
210
+ .rejects
211
+ .toThrow(ComposeUIErrors.NoAnswerWasProvided);
212
+ });
213
+
214
+ it('getOpenedAppContext returns context', async() => {
215
+ const response: Fdc3GetOpenedAppContextResponse = {
216
+ context: {type: "fdc3.instrument"}
217
+ };
218
+
219
+ messageRouterClient = {
220
+ clientId: "dummy",
221
+ subscribe: jest.fn(() => {
222
+ return Promise.resolve({ unsubscribe: () => { } });
223
+ }),
224
+
225
+ publish: jest.fn(() => { return Promise.resolve() }),
226
+ connect: jest.fn(() => { return Promise.resolve() }),
227
+ registerEndpoint: jest.fn(() => { return Promise.resolve() }),
228
+ unregisterEndpoint: jest.fn(() => { return Promise.resolve() }),
229
+ registerService: jest.fn(() => { return Promise.resolve() }),
230
+ unregisterService: jest.fn(() => { return Promise.resolve() }),
231
+ invoke: jest.fn(() => { return Promise.resolve(`${JSON.stringify(response)}`) })
232
+ };
233
+
234
+ client = new MessageRouterOpenClient("fdc3InstanceId", messageRouterClient, openAppIdentifier);
235
+ const result = await client.getOpenedAppContext();
236
+
237
+ expect(result.type).toBe("fdc3.instrument");
238
+ });
239
+ });
package/src/index.ts ADDED
@@ -0,0 +1,66 @@
1
+ /*
2
+ * Morgan Stanley makes this available to you under the Apache License,
3
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
4
+ * http://www.apache.org/licenses/LICENSE-2.0.
5
+ * See the NOTICE file distributed with this work for additional information
6
+ * regarding copyright ownership. Unless required by applicable law or agreed
7
+ * to in writing, software distributed under the License is distributed on an
8
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9
+ * or implied. See the License for the specific language governing permissions
10
+ * and limitations under the License.
11
+ *
12
+ */
13
+
14
+
15
+ import { AppIdentifier, DesktopAgent } from "@finos/fdc3";
16
+ import { ComposeUIDesktopAgent } from "./ComposeUIDesktopAgent";
17
+ import { createMessageRouter } from "@morgan-stanley/composeui-messaging-client";
18
+ import { OpenAppIdentifier } from "./infrastructure/OpenAppIdentifier";
19
+
20
+ declare global {
21
+ interface Window {
22
+ composeui: {
23
+ fdc3: {
24
+ config: AppIdentifier | undefined;
25
+ channelId : string | undefined;
26
+ openAppIdentifier: OpenAppIdentifier | undefined;
27
+ }
28
+ }
29
+ fdc3: DesktopAgent;
30
+ }
31
+ }
32
+
33
+ async function initialize(): Promise<void> {
34
+ //TODO: decide if we want to join to a channel by default.
35
+ let channelId: string | undefined = window.composeui.fdc3.channelId;
36
+ const openAppIdentifier: OpenAppIdentifier | undefined = window.composeui.fdc3.openAppIdentifier;
37
+ const fdc3 = new ComposeUIDesktopAgent(createMessageRouter());
38
+
39
+ if (channelId) {
40
+ await fdc3.joinUserChannel(channelId)
41
+ .then(async() => {
42
+ if (openAppIdentifier) {
43
+ await fdc3.getOpenedAppContext()
44
+ .then(() => {
45
+ window.fdc3 = fdc3;
46
+ window.dispatchEvent(new Event("fdc3Ready"));
47
+ })
48
+ } else {
49
+ window.fdc3 = fdc3;
50
+ window.dispatchEvent(new Event("fdc3Ready"));
51
+ }
52
+ });
53
+ } else {
54
+ if (openAppIdentifier) {
55
+ await fdc3.getOpenedAppContext().then(() => {
56
+ window.fdc3 = fdc3;
57
+ window.dispatchEvent(new Event("fdc3Ready"));
58
+ })
59
+ } else {
60
+ window.fdc3 = fdc3;
61
+ window.dispatchEvent(new Event("fdc3Ready"));
62
+ }
63
+ }
64
+ }
65
+
66
+ initialize();
@@ -0,0 +1,25 @@
1
+ /*
2
+ * Morgan Stanley makes this available to you under the Apache License,
3
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
4
+ * http://www.apache.org/licenses/LICENSE-2.0.
5
+ * See the NOTICE file distributed with this work for additional information
6
+ * regarding copyright ownership. Unless required by applicable law or agreed
7
+ * to in writing, software distributed under the License is distributed on an
8
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9
+ * or implied. See the License for the specific language governing permissions
10
+ * and limitations under the License.
11
+ *
12
+ */
13
+
14
+ import { Channel, ContextHandler, IntentHandler, Listener, PrivateChannel } from "@finos/fdc3";
15
+ import { ChannelType } from "./ChannelType";
16
+
17
+ export interface ChannelFactory {
18
+ getChannel(channelId: string, channelType: ChannelType): Promise<Channel>;
19
+ createPrivateChannel(): Promise<PrivateChannel>;
20
+ createAppChannel(channelId: string): Promise<Channel>;
21
+ joinUserChannel(channelId: string): Promise<Channel>;
22
+ getUserChannels(): Promise<Channel[]>;
23
+ getIntentListener(intent: string, handler: IntentHandler): Promise<Listener>;
24
+ getContextListener(openHandled: boolean, channel?: Channel, handler?: ContextHandler, contextType?: string | null): Promise<Listener>;
25
+ }
@@ -0,0 +1,20 @@
1
+ /*
2
+ * Morgan Stanley makes this available to you under the Apache License,
3
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
4
+ * http://www.apache.org/licenses/LICENSE-2.0.
5
+ * See the NOTICE file distributed with this work for additional information
6
+ * regarding copyright ownership. Unless required by applicable law or agreed
7
+ * to in writing, software distributed under the License is distributed on an
8
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9
+ * or implied. See the License for the specific language governing permissions
10
+ * and limitations under the License.
11
+ */
12
+
13
+ import { DisplayMetadata } from "@finos/fdc3";
14
+ import { ChannelType } from "./ChannelType";
15
+
16
+ export interface ChannelItem {
17
+ id: string;
18
+ type: ChannelType;
19
+ displayMetadata?: DisplayMetadata;
20
+ }
@@ -0,0 +1,14 @@
1
+ /*
2
+ * Morgan Stanley makes this available to you under the Apache License,
3
+ * Version 2.0 (the "License"). You may obtain a copy of the License at
4
+ * http://www.apache.org/licenses/LICENSE-2.0.
5
+ * See the NOTICE file distributed with this work for additional information
6
+ * regarding copyright ownership. Unless required by applicable law or agreed
7
+ * to in writing, software distributed under the License is distributed on an
8
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
9
+ * or implied. See the License for the specific language governing permissions
10
+ * and limitations under the License.
11
+ *
12
+ */
13
+
14
+ export type ChannelType = "user" | "app" | "private"