@openfin/core 29.73.12 → 29.73.14

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfin/core",
3
- "version": "29.73.12",
3
+ "version": "29.73.14",
4
4
  "license": "Apache-2.0",
5
5
  "main": "./src/mock.js",
6
6
  "types": "./src/mock.d.ts",
@@ -5,6 +5,7 @@ const base_1 = require("../base");
5
5
  const SessionContextGroupBroker_1 = require("./SessionContextGroupBroker");
6
6
  const utils_1 = require("./utils");
7
7
  const lodash_1 = require("lodash");
8
+ const PrivateChannelProvider_1 = require("./fdc3/PrivateChannelProvider");
8
9
  let contextGroups = [
9
10
  {
10
11
  id: 'green',
@@ -1043,6 +1044,11 @@ class InteropBroker extends base_1.Base {
1043
1044
  channel.register('fdc3v2GetInfo', async (payload, clientIdentity) => {
1044
1045
  return this.fdc3HandleGetInfo.bind(this)(payload, clientIdentity);
1045
1046
  });
1047
+ channel.register('createPrivateChannelProvider', async (payload) => {
1048
+ const { channelId } = payload;
1049
+ const channelProvider = await this.fin.InterApplicationBus.Channel.create(channelId);
1050
+ PrivateChannelProvider_1.PrivateChannelProvider.init(channelProvider, channelId);
1051
+ });
1046
1052
  }
1047
1053
  /**
1048
1054
  * Can be used to completely prevent a connection. Return false to prevent connections. Allows all connections by default.
@@ -13,6 +13,7 @@ export declare class PrivateChannelClient {
13
13
  onAddContextListener(handler: (contextType?: string) => void): Listener;
14
14
  onDisconnect(handler: () => void): Listener;
15
15
  onUnsubscribe(handler: (contextType?: string) => void): Listener;
16
+ cleanUpAllSubs(): Promise<void>;
16
17
  disconnect(): Promise<void>;
17
18
  }
18
19
  export {};
@@ -69,14 +69,22 @@ class PrivateChannelClient {
69
69
  this.client.dispatch(`onUnsubscribeHandlerAdded`, { handlerId });
70
70
  return listener;
71
71
  }
72
- async disconnect() {
73
- const listenerUnsubscribers = Array.from(this.listeners.values());
74
- const promises = listenerUnsubscribers.map(async (listenerUnsubscriber) => {
75
- await listenerUnsubscriber.unsubscribe();
72
+ async cleanUpAllSubs() {
73
+ const listenerUnsubscribers = Array.from(this.listeners.keys());
74
+ listenerUnsubscribers.forEach((handlerId) => {
75
+ this.client.remove(handlerId);
76
+ this.listeners.delete(handlerId);
76
77
  });
77
- await Promise.all(promises);
78
- await this.client.dispatch('clientDisconnecting');
79
- await this.client.disconnect();
78
+ }
79
+ async disconnect() {
80
+ try {
81
+ await this.client.dispatch('clientDisconnecting');
82
+ await this.cleanUpAllSubs();
83
+ await this.client.disconnect();
84
+ }
85
+ catch (error) {
86
+ throw new Error(error.message);
87
+ }
80
88
  }
81
89
  }
82
90
  exports.PrivateChannelClient = PrivateChannelClient;
@@ -1,5 +1,14 @@
1
1
  import { ChannelProvider } from '../../interappbus/channel/provider';
2
2
  declare type HandlerId = string;
3
+ declare type ContextType = string;
4
+ interface PrivateChannelClientState {
5
+ clientIdentity: OpenFin.ClientIdentity;
6
+ handlerIdsByContextTypes: Map<ContextType, HandlerId[]>;
7
+ globalHandler: HandlerId | undefined;
8
+ onAddContextListenerHandlerId: HandlerId | undefined;
9
+ onUnsubscribeHandlerId: HandlerId | undefined;
10
+ onDisconnectHandlerId: HandlerId | undefined;
11
+ }
3
12
  export declare class PrivateChannelProvider {
4
13
  id: string;
5
14
  private provider;
@@ -34,7 +43,12 @@ export declare class PrivateChannelProvider {
34
43
  onUnsubscribeHandlerAdded(payload: {
35
44
  handlerId: HandlerId;
36
45
  }, id: OpenFin.ClientIdentity): void;
37
- clientDisconnecting(payload: {}, disconnectingClientIdentity: OpenFin.ClientIdentity): Promise<void>;
46
+ removeClient(disconnectingClientIdentity: OpenFin.ClientIdentity): void;
47
+ fireOnDisconnectForOtherClients(disconnectingClientIdentity: OpenFin.ClientIdentity): Promise<void>;
48
+ unsubscribeAll(clientIdentity: OpenFin.ClientIdentity): Promise<void>;
49
+ handleClientDisconnecting(disconnectingClientIdentity: OpenFin.ClientIdentity): Promise<void>;
38
50
  registerNewClient(clientIdentity: OpenFin.ClientIdentity): void;
51
+ getConnectedClients(): Promise<PrivateChannelClientState[]>;
52
+ static init(channelProvider: OpenFin.ChannelProvider, id: string): PrivateChannelProvider;
39
53
  }
40
54
  export {};
@@ -11,7 +11,15 @@ class PrivateChannelProvider {
11
11
  this.contextByContextType = new Map();
12
12
  this.lastContext = undefined;
13
13
  this.provider.onConnection((clientIdentity) => this.registerNewClient(clientIdentity));
14
- this.provider.onDisconnection((clientIdentity) => this.clients.delete(clientIdentity.endpointId));
14
+ this.provider.onDisconnection(async (clientIdentity) => {
15
+ const { endpointId } = clientIdentity;
16
+ if (this.clients.has(endpointId)) {
17
+ await this.handleClientDisconnecting(clientIdentity);
18
+ }
19
+ if ((await this.provider.getAllClientInfo()).length === 0) {
20
+ this.provider.destroy();
21
+ }
22
+ });
15
23
  }
16
24
  getClientState(id) {
17
25
  return this.clients.get(id.endpointId);
@@ -25,7 +33,9 @@ class PrivateChannelProvider {
25
33
  this.provider.register('onAddContextHandlerAdded', this.onAddContextHandlerAdded.bind(this));
26
34
  this.provider.register('onDisconnectHandlerAdded', this.onDisconnectHandlerAdded.bind(this));
27
35
  this.provider.register('onUnsubscribeHandlerAdded', this.onUnsubscribeHandlerAdded.bind(this));
28
- this.provider.register('clientDisconnecting', this.clientDisconnecting.bind(this));
36
+ this.provider.register('clientDisconnecting', (payload, clientIdentity) => {
37
+ this.handleClientDisconnecting(clientIdentity);
38
+ });
29
39
  }
30
40
  broadcast(payload, broadcasterClientIdentity) {
31
41
  const { context } = payload;
@@ -110,17 +120,18 @@ class PrivateChannelProvider {
110
120
  }
111
121
  }
112
122
  }
113
- const dispatchesToSend = [];
114
- const otherClientStates = Array.from(this.clients.values());
115
- for (let i = 0; i < otherClientStates.length; i++) {
116
- const otherClientState = otherClientStates[i];
117
- if (otherClientState.clientIdentity.endpointId !== removingClientIdentity.endpointId &&
118
- otherClientState.onUnsubscribeHandlerId) {
119
- dispatchesToSend.push(this.provider.dispatch(otherClientState.clientIdentity, otherClientState.onUnsubscribeHandlerId, contextType));
123
+ // getting only valid client connections here, it is possible we haven't removed a disconnected client from the map yet
124
+ // so we need to ensure we don't dispatch to any disconnected client
125
+ // TODO: Take a look at our client disconnection logic and see if we can handle client disconnection cleanly
126
+ const clientsToDispatchTo = await this.getConnectedClients();
127
+ const dispatchPromises = clientsToDispatchTo.map(async (otherClientState) => {
128
+ const { clientIdentity, clientIdentity: { endpointId }, onUnsubscribeHandlerId } = otherClientState;
129
+ if (endpointId !== removingClientIdentity.endpointId && onUnsubscribeHandlerId) {
130
+ await this.provider.dispatch(clientIdentity, onUnsubscribeHandlerId, contextType);
120
131
  }
121
- }
132
+ });
122
133
  try {
123
- await Promise.all(dispatchesToSend);
134
+ await Promise.all(dispatchPromises);
124
135
  }
125
136
  catch (error) {
126
137
  console.error(`Problem when attempting to dispatch to onUnsubscribeHandlers. Error: ${error} Removing Client: ${handlerId}. uuid: ${removingClientIdentity.uuid}. name: ${removingClientIdentity.name}. endpointId: ${removingClientIdentity.endpointId}`);
@@ -181,32 +192,68 @@ class PrivateChannelProvider {
181
192
  }
182
193
  clientState.onUnsubscribeHandlerId = handlerId;
183
194
  }
184
- async clientDisconnecting(payload, disconnectingClientIdentity) {
195
+ removeClient(disconnectingClientIdentity) {
185
196
  const disconnectingClientState = this.getClientState(disconnectingClientIdentity);
186
197
  if (!disconnectingClientState) {
187
198
  throw new Error(`Client with Identity: ${disconnectingClientIdentity.uuid} ${disconnectingClientIdentity.name}, tried to call disconnect, is not connected to this Private Channel`);
188
199
  }
189
200
  disconnectingClientState.handlerIdsByContextTypes.clear();
190
201
  this.clients.delete(disconnectingClientIdentity.endpointId);
191
- const dispatchesToSend = [];
202
+ }
203
+ async fireOnDisconnectForOtherClients(disconnectingClientIdentity) {
192
204
  // TODO: call onDisconnect Handler of the other client only.
193
205
  // CURRENTLY, just calling the onDisconnect handler for all the other clients. Once we limit it to just one other client, we can eliminate all the iteration code.
194
- const otherClientStates = Array.from(this.clients.values());
195
- for (let i = 0; i < otherClientStates.length; i++) {
196
- const otherClientState = otherClientStates[i];
197
- if (otherClientState.clientIdentity.endpointId !== disconnectingClientIdentity.endpointId &&
198
- otherClientState.onDisconnectHandlerId) {
199
- dispatchesToSend.push(this.provider.dispatch(otherClientState.clientIdentity, otherClientState.onDisconnectHandlerId));
206
+ const { endpointId } = disconnectingClientIdentity;
207
+ // getting only valid client connections here, it is possible we haven't removed a disconnected client from the map yet
208
+ // so we need to ensure we don't dispatch to any disconnected client
209
+ // TODO: Take a look at our client disconnection logic and see if we can handle client disconnection cleanly
210
+ const clientsToDispatchTo = await this.getConnectedClients();
211
+ const dispatchPromises = clientsToDispatchTo.map(async (otherClientState) => {
212
+ const { clientIdentity: { endpointId: otherClientEndpointId }, onDisconnectHandlerId } = otherClientState;
213
+ if (otherClientEndpointId !== endpointId && onDisconnectHandlerId) {
214
+ await this.provider.dispatch(otherClientState.clientIdentity, onDisconnectHandlerId);
200
215
  }
201
- }
216
+ });
202
217
  try {
203
- await Promise.all(dispatchesToSend);
218
+ await Promise.all(dispatchPromises);
204
219
  }
205
220
  catch (error) {
206
221
  console.error(`Problem when attempting to dispatch to onDisconnectHandlers. Error: ${error} Disconnecting Client: uuid: ${disconnectingClientIdentity.uuid}. name: ${disconnectingClientIdentity.name}. endpointId: ${disconnectingClientIdentity.endpointId}`);
207
222
  throw new Error(error);
208
223
  }
209
224
  }
225
+ async unsubscribeAll(clientIdentity) {
226
+ const { endpointId } = clientIdentity;
227
+ const state = this.clients.get(endpointId);
228
+ if (state) {
229
+ const contextTypeHandlerIds = Array.from(state.handlerIdsByContextTypes.values()).flat();
230
+ const globalHandlerId = state.globalHandler;
231
+ if (contextTypeHandlerIds.length > 0) {
232
+ const unsubPromises = contextTypeHandlerIds.map(async (handlerId) => {
233
+ return this.contextHandlerRemoved({ handlerId }, clientIdentity);
234
+ });
235
+ try {
236
+ await Promise.all(unsubPromises);
237
+ }
238
+ catch (error) {
239
+ console.error(error.message);
240
+ }
241
+ }
242
+ if (globalHandlerId) {
243
+ try {
244
+ await this.contextHandlerRemoved({ handlerId: globalHandlerId }, clientIdentity);
245
+ }
246
+ catch (error) {
247
+ console.error(error.message);
248
+ }
249
+ }
250
+ }
251
+ }
252
+ async handleClientDisconnecting(disconnectingClientIdentity) {
253
+ await this.unsubscribeAll(disconnectingClientIdentity);
254
+ this.removeClient(disconnectingClientIdentity);
255
+ await this.fireOnDisconnectForOtherClients(disconnectingClientIdentity);
256
+ }
210
257
  registerNewClient(clientIdentity) {
211
258
  if (!this.clients.has(clientIdentity.endpointId)) {
212
259
  const clientSubscriptionState = {
@@ -220,5 +267,17 @@ class PrivateChannelProvider {
220
267
  this.clients.set(clientIdentity.endpointId, clientSubscriptionState);
221
268
  }
222
269
  }
270
+ async getConnectedClients() {
271
+ const allClientInfo = await this.provider.getAllClientInfo();
272
+ return Array.from(this.clients.values()).filter((clientState) => {
273
+ const { uuid, name } = clientState.clientIdentity;
274
+ return allClientInfo.some(clientInfo => {
275
+ return name === clientInfo.name && uuid === clientInfo.uuid;
276
+ });
277
+ });
278
+ }
279
+ static init(channelProvider, id) {
280
+ return new PrivateChannelProvider(channelProvider, id);
281
+ }
223
282
  }
224
283
  exports.PrivateChannelProvider = PrivateChannelProvider;
@@ -169,11 +169,15 @@ class Fdc3Module extends base_1.Base {
169
169
  }
170
170
  catch (error) {
171
171
  if (error.message === utils_2.BROKER_ERRORS.joinSessionContextGroupWithJoinContextGroup) {
172
- throw new Error('The Channel you have tried to join is an App Channel. Custom Channels can only be defined by the Interop Broker through code or manifest configuration. Please use getOrCreateChannel.');
172
+ console.error('The Channel you have tried to join is an App Channel. Custom Channels can only be defined by the Interop Broker through code or manifest configuration. Please use getOrCreateChannel.');
173
173
  }
174
174
  else {
175
- throw new Error(error.message);
175
+ console.error(error.message);
176
176
  }
177
+ if (error.message.startsWith('Attempting to join a context group that does not exist')) {
178
+ throw new Error(utils_1.ChannelError.NoChannelFound);
179
+ }
180
+ throw new Error(utils_1.ChannelError.AccessDenied);
177
181
  }
178
182
  }
179
183
  /**
@@ -317,8 +321,19 @@ class Fdc3Module extends base_1.Base {
317
321
  this.wire.sendAction('fdc3-get-or-create-channel').catch((e) => {
318
322
  // we do not want to expose this error, just continue if this analytics-only call fails
319
323
  });
320
- const sessionContextGroup = await this.fin.me.interop.joinSessionContextGroup(channelId);
321
- return (0, utils_1.buildAppChannelObject)(sessionContextGroup);
324
+ const systemChannels = await this.getSystemChannels();
325
+ const userChannel = systemChannels.find((channel) => channel.id === channelId);
326
+ if (userChannel) {
327
+ return { ...userChannel, type: 'system', ...(0, utils_1.getUnsupportedChannelApis)() };
328
+ }
329
+ try {
330
+ const sessionContextGroup = await this.fin.me.interop.joinSessionContextGroup(channelId);
331
+ return (0, utils_1.buildAppChannelObject)(sessionContextGroup);
332
+ }
333
+ catch (error) {
334
+ console.error(error.message);
335
+ throw new Error(utils_1.ChannelError.CreationFailed);
336
+ }
322
337
  }
323
338
  /**
324
339
  * Returns metadata relating to the FDC3 object and its provider, including the supported version of the FDC3 specification and the name of the provider of the implementation.
@@ -283,7 +283,7 @@ export default class Fdc3Module2 extends Base implements FDC3v2.DesktopAgent {
283
283
  * Returns the Channel object for the current User channel membership
284
284
  * @returns { Promise<FDC3.Channel | null> }
285
285
  */
286
- getCurrentChannel(): Promise<FDC3v1.Channel | null>;
286
+ getCurrentChannel(): Promise<FDC3v2.Channel | null>;
287
287
  /**
288
288
  * Removes the app from any User channel membership.
289
289
  * @returns { Promise<void> }
@@ -6,7 +6,6 @@ const InteropClient_1 = require("../InteropClient");
6
6
  const utils_2 = require("./utils");
7
7
  const fdc3_1_2_1 = require("./fdc3-1.2");
8
8
  const PrivateChannelClient_1 = require("./PrivateChannelClient");
9
- const PrivateChannelProvider_1 = require("./PrivateChannelProvider");
10
9
  /**
11
10
  * @typedef { object } AppIdentifier
12
11
  * @summary Identifies an application, or instance of an application, and is used to target FDC3 API calls at specific applications.
@@ -349,27 +348,27 @@ class Fdc3Module2 extends base_1.Base {
349
348
  // The FDC3 Intenter handler only expects the context and contextMetadata to be passed to the handler,
350
349
  // so we wrap it here and only pass those paramaters.
351
350
  const contextHandler = async (raisedIntent) => {
351
+ let intentResult;
352
+ let intentResultToSend;
352
353
  const { context, metadata: intentMetadata } = raisedIntent;
353
354
  const { contextMetadata, metadata, ...rest } = context;
354
- let intentResult;
355
+ const intentResolutionResultId = (intentMetadata === null || intentMetadata === void 0 ? void 0 : intentMetadata.intentResolutionResultId) || (metadata === null || metadata === void 0 ? void 0 : metadata.intentResolutionResultId);
355
356
  try {
356
357
  const newContext = metadata ? { metadata, ...rest } : { ...rest };
357
358
  intentResult = await handler(newContext, contextMetadata);
359
+ intentResultToSend = intentResult;
358
360
  }
359
361
  catch (error) {
360
362
  intentResult = error;
363
+ intentResultToSend = { error: true };
361
364
  }
362
- const intentResolutionResultId = (intentMetadata === null || intentMetadata === void 0 ? void 0 : intentMetadata.intentResolutionResultId) || (metadata === null || metadata === void 0 ? void 0 : metadata.intentResolutionResultId);
363
365
  if (intentResolutionResultId) {
364
- // Send whatever the result is.
365
- fin.InterApplicationBus.publish(intentResolutionResultId, intentResult);
366
+ this.fin.InterApplicationBus.publish(intentResolutionResultId, intentResultToSend);
366
367
  }
367
368
  if (intentResult instanceof Error) {
368
369
  throw new Error(intentResult.message);
369
370
  }
370
- else {
371
- return intentResult;
372
- }
371
+ return intentResult;
373
372
  };
374
373
  return this.fin.me.interop.registerIntentHandler(contextHandler, intent, { fdc3Version: '2.0' });
375
374
  }
@@ -389,8 +388,7 @@ class Fdc3Module2 extends base_1.Base {
389
388
  */
390
389
  async createPrivateChannel() {
391
390
  const channelId = (0, utils_1.generateId)();
392
- const channelProvider = await this.fin.InterApplicationBus.Channel.create(channelId);
393
- const newPrivateChannelProvider = new PrivateChannelProvider_1.PrivateChannelProvider(channelProvider, channelId);
391
+ await InteropClient_1.InteropClient.ferryFdc3Call(this.fin.me.interop, 'createPrivateChannelProvider', { channelId });
394
392
  const channelClient = await this.fin.InterApplicationBus.Channel.connect(channelId);
395
393
  const newPrivateChannelClient = new PrivateChannelClient_1.PrivateChannelClient(channelClient, channelId);
396
394
  return (0, utils_2.buildPrivateChannelObject)(newPrivateChannelClient);
@@ -443,7 +441,15 @@ class Fdc3Module2 extends base_1.Base {
443
441
  * @returns { Promise<FDC3.Channel | null> }
444
442
  */
445
443
  async getCurrentChannel() {
446
- return this.fdc3Module.getCurrentChannel();
444
+ const currentChannel = await this.fdc3Module.getCurrentChannel();
445
+ if (!currentChannel) {
446
+ return null;
447
+ }
448
+ return {
449
+ ...currentChannel,
450
+ type: 'user',
451
+ broadcast: this.broadcast.bind(this)
452
+ };
447
453
  }
448
454
  /**
449
455
  * Removes the app from any User channel membership.
@@ -20,8 +20,25 @@ export declare enum ResultError {
20
20
  */
21
21
  IntentHandlerRejected = "IntentHandlerRejected"
22
22
  }
23
+ export declare enum ChannelError {
24
+ /** Returned if the specified channel is not found when attempting to join a
25
+ * channel via the `joinUserChannel` function of the DesktopAgent (`fdc3`).
26
+ */
27
+ NoChannelFound = "NoChannelFound",
28
+ /** SHOULD be returned when a request to join a user channel or to a retrieve
29
+ * a Channel object via the `joinUserChannel` or `getOrCreateChannel` methods
30
+ * of the DesktopAgent (`fdc3`) object is denied.
31
+ */
32
+ AccessDenied = "AccessDenied",
33
+ /** SHOULD be returned when a channel cannot be created or retrieved via the
34
+ * `getOrCreateChannel` method of the DesktopAgent (`fdc3`).
35
+ */
36
+ CreationFailed = "CreationFailed"
37
+ }
23
38
  export declare const buildPrivateChannelObject: (privateChannelClient: PrivateChannelClient) => PrivateChannel;
24
39
  export declare const buildAppChannelObject: (sessionContextGroup: OpenFin.SessionContextGroup) => Channel;
25
40
  export declare const connectPrivateChannel: (channelId: string) => Promise<PrivateChannel>;
41
+ export declare const isContext: (context: unknown) => context is Context;
42
+ export declare const isChannel: (channel: unknown) => channel is Channel;
26
43
  export declare const getIntentResolution: (interopModule: OpenFin.InteropClient, context: Context, app?: AppIdentifier | TargetApp, intent?: string) => Promise<IntentResolution>;
27
44
  export {};
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getIntentResolution = exports.connectPrivateChannel = exports.buildAppChannelObject = exports.buildPrivateChannelObject = exports.ResultError = exports.UnsupportedChannelApiError = exports.getUnsupportedChannelApis = void 0;
3
+ exports.getIntentResolution = exports.isChannel = exports.isContext = exports.connectPrivateChannel = exports.buildAppChannelObject = exports.buildPrivateChannelObject = exports.ChannelError = exports.ResultError = exports.UnsupportedChannelApiError = exports.getUnsupportedChannelApis = void 0;
4
4
  const utils_1 = require("../utils");
5
5
  const PrivateChannelClient_1 = require("./PrivateChannelClient");
6
6
  const getUnsupportedChannelApis = (channelType) => {
@@ -35,6 +35,22 @@ var ResultError;
35
35
  */
36
36
  ResultError["IntentHandlerRejected"] = "IntentHandlerRejected";
37
37
  })(ResultError = exports.ResultError || (exports.ResultError = {}));
38
+ var ChannelError;
39
+ (function (ChannelError) {
40
+ /** Returned if the specified channel is not found when attempting to join a
41
+ * channel via the `joinUserChannel` function of the DesktopAgent (`fdc3`).
42
+ */
43
+ ChannelError["NoChannelFound"] = "NoChannelFound";
44
+ /** SHOULD be returned when a request to join a user channel or to a retrieve
45
+ * a Channel object via the `joinUserChannel` or `getOrCreateChannel` methods
46
+ * of the DesktopAgent (`fdc3`) object is denied.
47
+ */
48
+ ChannelError["AccessDenied"] = "AccessDenied";
49
+ /** SHOULD be returned when a channel cannot be created or retrieved via the
50
+ * `getOrCreateChannel` method of the DesktopAgent (`fdc3`).
51
+ */
52
+ ChannelError["CreationFailed"] = "CreationFailed";
53
+ })(ChannelError = exports.ChannelError || (exports.ChannelError = {}));
38
54
  const buildPrivateChannelObject = (privateChannelClient) => {
39
55
  let clientDisconnected = false;
40
56
  const checkIfClientDisconnected = () => {
@@ -122,6 +138,22 @@ const connectPrivateChannel = async (channelId) => {
122
138
  }
123
139
  };
124
140
  exports.connectPrivateChannel = connectPrivateChannel;
141
+ const isContext = (context) => {
142
+ if (context && typeof context === 'object' && 'type' in context) {
143
+ const { type } = context;
144
+ return typeof type === 'string';
145
+ }
146
+ return false;
147
+ };
148
+ exports.isContext = isContext;
149
+ const isChannel = (channel) => {
150
+ if (channel && typeof channel === 'object' && 'type' in channel && 'id' in channel) {
151
+ const { type, id } = channel;
152
+ return typeof type === 'string' && typeof id === 'string' && (type === 'app' || type === 'private');
153
+ }
154
+ return false;
155
+ };
156
+ exports.isChannel = isChannel;
125
157
  const getIntentResolution = async (interopModule, context, app, intent) => {
126
158
  // Generate an ID to make a session context group with. We will pass that ID to the Broker.
127
159
  // The broker will then setContext on that session context group later with our Intent Result,
@@ -138,31 +170,33 @@ const getIntentResolution = async (interopModule, context, app, intent) => {
138
170
  // Set up the getResult call.
139
171
  const getResult = async () => {
140
172
  let intentResult = await getResultPromise;
141
- if (!intentResult) {
173
+ if (!intentResult || typeof intentResult !== 'object') {
142
174
  throw new Error(ResultError.NoResultReturned);
143
175
  }
144
- if (intentResult instanceof Error) {
176
+ const { error } = intentResult;
177
+ if (error) {
145
178
  throw new Error(ResultError.IntentHandlerRejected);
146
179
  }
147
- if (typeof intentResult === 'object') {
180
+ if ((0, exports.isChannel)(intentResult)) {
148
181
  const { id, type } = intentResult;
149
- if (type && id && typeof id === 'string') {
150
- switch (type) {
151
- case 'private': {
152
- intentResult = await (0, exports.connectPrivateChannel)(id);
153
- break;
154
- }
155
- case 'app': {
156
- const sessionContextGroup = await interopModule.joinSessionContextGroup(id);
157
- intentResult = (0, exports.buildAppChannelObject)(sessionContextGroup);
158
- break;
159
- }
160
- default: {
161
- break;
162
- }
182
+ switch (type) {
183
+ case 'private': {
184
+ intentResult = await (0, exports.connectPrivateChannel)(id);
185
+ break;
186
+ }
187
+ case 'app': {
188
+ const sessionContextGroup = await interopModule.joinSessionContextGroup(id);
189
+ intentResult = (0, exports.buildAppChannelObject)(sessionContextGroup);
190
+ break;
191
+ }
192
+ default: {
193
+ break;
163
194
  }
164
195
  }
165
196
  }
197
+ else if (!(0, exports.isContext)(intentResult)) {
198
+ throw new Error(ResultError.NoResultReturned);
199
+ }
166
200
  return intentResult;
167
201
  };
168
202
  // Finally fire the intent.
@@ -455,6 +455,10 @@ export declare class View extends WebContents<ViewEvents> {
455
455
  * **NOTE**: Internal use only.
456
456
  * Attaches this view to an HTML element in the current context. The view will resize responsively when the element bounds change.
457
457
  *
458
+ * **Known issue**: View.bindToElement does not track position changes, if the element has fixed px width and height values it is possible for the view to not update responsively.
459
+ *
460
+ * **Known issue**: When View.bindToElement is used on a element that takes up the entire page in a platform window, the bound view will not respond responsively when the window is resized to be smaller.
461
+ *
458
462
  * @param {HTMLElement} element - HTML element to attach the view to.
459
463
  * @return {Function} - Cleanup function that will disconnect the element resize observer.
460
464
  * @internal
@@ -460,6 +460,10 @@ class View extends main_1.WebContents {
460
460
  * **NOTE**: Internal use only.
461
461
  * Attaches this view to an HTML element in the current context. The view will resize responsively when the element bounds change.
462
462
  *
463
+ * **Known issue**: View.bindToElement does not track position changes, if the element has fixed px width and height values it is possible for the view to not update responsively.
464
+ *
465
+ * **Known issue**: When View.bindToElement is used on a element that takes up the entire page in a platform window, the bound view will not respond responsively when the window is resized to be smaller.
466
+ *
463
467
  * @param {HTMLElement} element - HTML element to attach the view to.
464
468
  * @return {Function} - Cleanup function that will disconnect the element resize observer.
465
469
  * @internal