@openfin/core 31.74.31 → 31.75.2

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 (62) hide show
  1. package/package.json +1 -1
  2. package/src/OpenFin.d.ts +57 -13
  3. package/src/api/application/Instance.js +23 -5
  4. package/src/api/base.d.ts +1 -2
  5. package/src/api/base.js +1 -2
  6. package/src/api/events/system.d.ts +6 -3
  7. package/src/api/fin.js +1 -2
  8. package/src/api/interappbus/channel/index.d.ts +1 -0
  9. package/src/api/interappbus/channel/index.js +47 -44
  10. package/src/api/interappbus/channel/protocols/classic/strategy.js +24 -6
  11. package/src/api/interappbus/index.js +1 -1
  12. package/src/api/interop/InteropClient.d.ts +1 -1
  13. package/src/api/interop/InteropClient.js +1 -1
  14. package/src/api/interop/SessionContextGroupBroker.d.ts +1 -1
  15. package/src/api/interop/SessionContextGroupBroker.js +5 -4
  16. package/src/api/interop/SessionContextGroupClient.js +1 -1
  17. package/src/api/interop/fdc3/PrivateChannelProvider.d.ts +1 -1
  18. package/src/api/interop/fdc3/PrivateChannelProvider.js +1 -8
  19. package/src/api/interop/fdc3/fdc3-1.2.js +34 -1
  20. package/src/api/interop/fdc3/utils.js +24 -4
  21. package/src/api/me.d.ts +1 -1
  22. package/src/api/me.js +2 -1
  23. package/src/api/platform/Factory.d.ts +2 -1
  24. package/src/api/platform/Instance.d.ts +5 -4
  25. package/src/api/platform/Instance.js +2 -1
  26. package/src/api/platform/layout/Factory.js +5 -3
  27. package/src/api/platform/layout/Instance.js +3 -0
  28. package/src/api/platform/layout/controllers/layout-entities-controller.d.ts +6 -2
  29. package/src/api/platform/layout/controllers/layout-entities-controller.js +40 -8
  30. package/src/api/platform/layout/controllers/tab-drag-controller.d.ts +2 -1
  31. package/src/api/platform/layout/entities/layout-entities.d.ts +143 -42
  32. package/src/api/platform/layout/entities/layout-entities.js +151 -43
  33. package/src/api/platform/layout/utils/layout-traversal.d.ts +1 -0
  34. package/src/api/platform/layout/utils/layout-traversal.js +11 -11
  35. package/src/api/platform/provider.d.ts +2 -1
  36. package/src/api/system/index.d.ts +9 -0
  37. package/src/api/system/index.js +78 -40
  38. package/src/api/view/Instance.d.ts +6 -3
  39. package/src/api/view/Instance.js +9 -7
  40. package/src/api/webcontents/main.d.ts +2 -22
  41. package/src/api/webcontents/main.js +2 -1
  42. package/src/api/window/Instance.d.ts +10 -0
  43. package/src/api/window/Instance.js +22 -0
  44. package/src/environment/mockEnvironment.d.ts +27 -0
  45. package/src/environment/mockEnvironment.js +61 -0
  46. package/src/mock.js +4 -83
  47. package/src/shapes/protocol.d.ts +17 -0
  48. package/src/transport/mockWire.d.ts +11 -0
  49. package/src/transport/mockWire.js +26 -0
  50. package/src/transport/transport-errors.d.ts +9 -1
  51. package/src/transport/transport-errors.js +45 -2
  52. package/src/transport/transport.d.ts +15 -5
  53. package/src/transport/transport.js +48 -20
  54. package/src/util/channel-api-relay.js +11 -1
  55. package/src/util/errors.d.ts +1 -0
  56. package/src/util/errors.js +1 -0
  57. package/src/util/lazy.d.ts +18 -0
  58. package/src/util/lazy.js +29 -1
  59. package/src/util/ref-counter.d.ts +1 -1
  60. package/src/util/ref-counter.js +3 -2
  61. package/src/transport/fin_store.d.ts +0 -4
  62. package/src/transport/fin_store.js +0 -16
@@ -23,13 +23,56 @@ exports.NotImplementedError = NotImplementedError;
23
23
  class NotSupportedError extends Error {
24
24
  }
25
25
  exports.NotSupportedError = NotSupportedError;
26
+ class InternalError extends Error {
27
+ constructor(err) {
28
+ const { message, name, stack, ...rest } = err;
29
+ super(message);
30
+ this.name = name || 'Error';
31
+ this.stack = stack !== null && stack !== void 0 ? stack : this.toString();
32
+ Object.keys(rest).forEach(key => {
33
+ this[key] = rest[key];
34
+ });
35
+ }
36
+ }
37
+ // For documentation of the error methods being used see here: https://v8.dev/docs/stack-trace-api
26
38
  class RuntimeError extends Error {
27
- constructor(payload) {
39
+ static getCallSite(callsToRemove = 0) {
40
+ var _a, _b;
41
+ const length = Error.stackTraceLimit;
42
+ const realCallsToRemove = callsToRemove + 1; // remove this call;
43
+ Error.stackTraceLimit = length + realCallsToRemove;
44
+ // eslint-disable-next-line no-underscore-dangle
45
+ const _prepareStackTrace = Error.prepareStackTrace;
46
+ // This will be called when we access the `stack` property
47
+ Error.prepareStackTrace = (_, stack) => stack;
48
+ // stack is optional in non chromium contexts
49
+ const stack = (_b = (_a = new Error().stack) === null || _a === void 0 ? void 0 : _a.slice(realCallsToRemove)) !== null && _b !== void 0 ? _b : [];
50
+ Error.prepareStackTrace = _prepareStackTrace;
51
+ Error.stackTraceLimit = length;
52
+ return stack;
53
+ }
54
+ static prepareStackTrace(err, callSites) {
55
+ if (typeof Error.prepareStackTrace === 'function') {
56
+ return Error.prepareStackTrace(err, callSites);
57
+ }
58
+ let string = "";
59
+ string += err.name || "Error";
60
+ string += `: ${err.message || ""}`;
61
+ for (const callSite of callSites) {
62
+ string += `\n at ${callSite.toString()}`;
63
+ }
64
+ return string;
65
+ }
66
+ ;
67
+ constructor(payload, callSites) {
28
68
  const { reason, error } = payload;
29
69
  super(reason);
30
70
  this.name = 'RuntimeError';
31
71
  if (error === null || error === void 0 ? void 0 : error.stack) {
32
- this.stack = error.stack;
72
+ this.cause = new InternalError(error);
73
+ }
74
+ if (callSites) {
75
+ this.stack = RuntimeError.prepareStackTrace(this, callSites);
33
76
  }
34
77
  }
35
78
  }
@@ -1,20 +1,29 @@
1
1
  /// <reference types="node" />
2
+ /// <reference types="node" />
2
3
  import { EventEmitter } from 'events';
3
4
  import type * as OpenFin from '../OpenFin';
4
5
  import { ExistingConnectConfig, InternalConnectConfig, RemoteConfig, Wire, WireConstructor } from './wire';
5
6
  import { Environment } from '../environment/environment';
7
+ import { RuntimeErrorPayload } from './transport-errors';
6
8
  import EventAggregator from '../api/events/eventAggregator';
7
9
  import { EntityTypeHelpers } from '../api/me';
8
10
  import { ProtocolMap } from '../shapes/protocol';
9
11
  import { NamedEvent } from '../api/events/base';
10
12
  import { ErrorPlainObject } from '../util/errors';
11
13
  type EntityType = OpenFin.EntityType;
14
+ type SendActionResponse<T extends keyof ProtocolMap> = Message<{
15
+ data: ProtocolMap[T]['response'];
16
+ } & ProtocolMap[T]['specialResponse']>;
12
17
  export type MessageHandler = (data: any) => boolean;
18
+ export type CancellablePromise<T> = Promise<T> & {
19
+ cancel: (reason?: any) => void;
20
+ };
21
+ type NackHandler = (payloadOrMessage: RuntimeErrorPayload | string) => void;
13
22
  export declare class Transport<MeType extends EntityType = EntityType> extends EventEmitter {
14
23
  #private;
15
24
  protected wireListeners: Map<number, {
16
25
  resolve: Function;
17
- reject: Function;
26
+ handleNack: (payload: RuntimeErrorPayload) => void;
18
27
  }>;
19
28
  protected uncorrelatedListener: Function;
20
29
  me: OpenFin.EntityInfo & EntityTypeHelpers<MeType>;
@@ -24,6 +33,8 @@ export declare class Transport<MeType extends EntityType = EntityType> extends E
24
33
  eventAggregator: EventAggregator;
25
34
  protected messageHandlers: MessageHandler[];
26
35
  constructor(WireType: WireConstructor, environment: Environment, config: OpenFin.Identity);
36
+ getFin(): OpenFin.Fin<MeType>;
37
+ registerFin(_fin: OpenFin.Fin<MeType>): void;
27
38
  connectSync: () => void;
28
39
  getPort: () => string;
29
40
  shutdown(): Promise<void>;
@@ -31,12 +42,11 @@ export declare class Transport<MeType extends EntityType = EntityType> extends E
31
42
  private connectRemote;
32
43
  connectByPort(config: ExistingConnectConfig): Promise<void>;
33
44
  private authorize;
34
- sendAction<T extends keyof ProtocolMap = string>(action: T, payload?: ProtocolMap[T]['request'], uncorrelated?: boolean): Promise<Message<{
35
- data: ProtocolMap[T]['response'];
36
- } & ProtocolMap[T]['specialResponse']>>;
45
+ sendAction<T extends keyof ProtocolMap = string>(action: T, payload?: ProtocolMap[T]['request'], uncorrelated?: boolean): CancellablePromise<SendActionResponse<T>>;
46
+ protected nackHandler(payloadOrMessage: RuntimeErrorPayload | string, reject: Function, callSites?: NodeJS.CallSite[]): void;
37
47
  ferryAction(origData: any): Promise<Message<any>>;
38
48
  registerMessageHandler(handler: MessageHandler): void;
39
- protected addWireListener(id: number, resolve: Function, reject: Function, uncorrelated: boolean): void;
49
+ protected addWireListener(id: number, resolve: Function, handleNack: NackHandler, uncorrelated: boolean): void;
40
50
  protected onmessage(data: Message<Payload>): void;
41
51
  protected handleMessage(data: Message<Payload>): boolean;
42
52
  }
@@ -10,7 +10,7 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
10
10
  if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
11
11
  return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
12
12
  };
13
- var _Transport_wire;
13
+ var _Transport_wire, _Transport_fin;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.Transport = void 0;
16
16
  const events_1 = require("events");
@@ -18,6 +18,7 @@ const wire_1 = require("./wire");
18
18
  const transport_errors_1 = require("./transport-errors");
19
19
  const eventAggregator_1 = require("../api/events/eventAggregator");
20
20
  const me_1 = require("../api/me");
21
+ const errors_1 = require("../util/errors");
21
22
  class Transport extends events_1.EventEmitter {
22
23
  constructor(WireType, environment, config) {
23
24
  super();
@@ -26,6 +27,8 @@ class Transport extends events_1.EventEmitter {
26
27
  this.eventAggregator = new eventAggregator_1.default();
27
28
  this.messageHandlers = [this.eventAggregator.dispatchEvent];
28
29
  _Transport_wire.set(this, void 0);
30
+ // Typing as unknown to avoid circular dependency, should not be used directly.
31
+ _Transport_fin.set(this, void 0);
29
32
  this.connectSync = () => {
30
33
  const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
31
34
  wire.connectSync();
@@ -40,8 +43,8 @@ class Transport extends events_1.EventEmitter {
40
43
  this.sendRaw = __classPrivateFieldGet(this, _Transport_wire, "f").send.bind(__classPrivateFieldGet(this, _Transport_wire, "f"));
41
44
  this.registerMessageHandler(this.handleMessage.bind(this));
42
45
  __classPrivateFieldGet(this, _Transport_wire, "f").on('disconnected', () => {
43
- for (const [, { reject }] of this.wireListeners) {
44
- reject('Remote connection has closed');
46
+ for (const [, { handleNack }] of this.wireListeners) {
47
+ handleNack({ reason: 'Remote connection has closed' });
45
48
  }
46
49
  this.wireListeners.clear();
47
50
  this.emit('disconnected');
@@ -50,6 +53,18 @@ class Transport extends events_1.EventEmitter {
50
53
  const entityType = this.environment.getCurrentEntityType();
51
54
  this.me = (0, me_1.getBaseMe)(entityType, uuid, name);
52
55
  }
56
+ getFin() {
57
+ if (!__classPrivateFieldGet(this, _Transport_fin, "f")) {
58
+ throw new Error("No Fin object registered for this transport");
59
+ }
60
+ return __classPrivateFieldGet(this, _Transport_fin, "f");
61
+ }
62
+ registerFin(_fin) {
63
+ if (__classPrivateFieldGet(this, _Transport_fin, "f")) {
64
+ throw new Error("Fin object has already been registered for this transport");
65
+ }
66
+ __classPrivateFieldSet(this, _Transport_fin, _fin, "f");
67
+ }
53
68
  shutdown() {
54
69
  const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
55
70
  return wire.shutdown();
@@ -95,20 +110,33 @@ class Transport extends events_1.EventEmitter {
95
110
  throw new transport_errors_1.RuntimeError(requestAuthRet.payload);
96
111
  }
97
112
  }
98
- sendAction(action, payload = {}, uncorrelated = false
99
- // specialResponse type is only used for 'requestAuthorization'
100
- ) {
101
- return new Promise((resolve, reject) => {
102
- const id = this.environment.getNextMessageId();
113
+ sendAction(action, payload = {}, uncorrelated = false) {
114
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
115
+ let cancel = () => { };
116
+ // We want the callsite from the caller of this function, not from here.
117
+ const callSites = transport_errors_1.RuntimeError.getCallSite(1);
118
+ const prom = new Promise((resolve, reject) => {
119
+ cancel = reject;
120
+ const messageId = this.environment.getNextMessageId();
103
121
  const msg = {
104
122
  action,
105
123
  payload,
106
- messageId: id
124
+ messageId
107
125
  };
108
126
  const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
109
- this.addWireListener(id, resolve, reject, uncorrelated);
127
+ this.addWireListener(messageId, resolve, (payload) => this.nackHandler(payload, reject, callSites), uncorrelated);
110
128
  return wire.send(msg).catch(reject);
111
129
  });
130
+ return Object.assign(prom, { cancel });
131
+ }
132
+ nackHandler(payloadOrMessage, reject, callSites) {
133
+ if (typeof payloadOrMessage === 'string') {
134
+ // NOTE: this is for backwards compatibility to support plain string rejections
135
+ reject(payloadOrMessage);
136
+ }
137
+ else {
138
+ reject(new transport_errors_1.RuntimeError(payloadOrMessage, callSites));
139
+ }
112
140
  }
113
141
  ferryAction(origData) {
114
142
  return new Promise((resolve, reject) => {
@@ -120,22 +148,22 @@ class Transport extends events_1.EventEmitter {
120
148
  const wire = __classPrivateFieldGet(this, _Transport_wire, "f");
121
149
  return wire
122
150
  .send(origData)
123
- .then(() => this.addWireListener(id, resolver, reject, false))
151
+ .then(() => this.addWireListener(id, resolver, (payload) => this.nackHandler(payload, reject), false))
124
152
  .catch(reject);
125
153
  });
126
154
  }
127
155
  registerMessageHandler(handler) {
128
156
  this.messageHandlers.push(handler);
129
157
  }
130
- addWireListener(id, resolve, reject, uncorrelated) {
158
+ addWireListener(id, resolve, handleNack, uncorrelated) {
131
159
  if (uncorrelated) {
132
160
  this.uncorrelatedListener = resolve;
133
161
  }
134
162
  else if (this.wireListeners.has(id)) {
135
- reject(new transport_errors_1.DuplicateCorrelationError(String(id)));
163
+ handleNack({ reason: 'Duplicate handler id', error: (0, errors_1.errorToPOJO)(new transport_errors_1.DuplicateCorrelationError(String(id))) });
136
164
  }
137
165
  else {
138
- this.wireListeners.set(id, { resolve, reject });
166
+ this.wireListeners.set(id, { resolve, handleNack });
139
167
  }
140
168
  // Timeout and reject()?
141
169
  }
@@ -161,23 +189,23 @@ class Transport extends events_1.EventEmitter {
161
189
  else {
162
190
  // We just checked for existence above
163
191
  // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
164
- const { resolve, reject } = this.wireListeners.get(id);
192
+ const { resolve, handleNack } = this.wireListeners.get(id);
165
193
  if (data.action !== 'ack') {
166
- reject(new transport_errors_1.NoAckError(data.action));
194
+ handleNack({ reason: 'Did not receive ack action', error: (0, errors_1.errorToPOJO)(new transport_errors_1.NoAckError(data.action)) });
167
195
  }
168
196
  else if (!('payload' in data)) {
169
197
  // I'm not sure when this code would actually run, but passing in something that doeesn't have a reason to the runtimeerror constructor will not end well.
170
198
  // @ts-expect-error
171
199
  if (typeof data.reason === 'string') {
172
- reject(new transport_errors_1.RuntimeError(data));
200
+ handleNack(data);
173
201
  }
174
202
  else {
175
203
  console.warn('Received invalid response from core', data);
176
- reject(new Error('Invalid response'));
204
+ handleNack({ reason: 'invalid response shape' });
177
205
  }
178
206
  }
179
207
  else if (!data.payload.success) {
180
- reject(new transport_errors_1.RuntimeError(data.payload));
208
+ handleNack(data.payload);
181
209
  }
182
210
  else {
183
211
  resolve.call(null, data);
@@ -188,4 +216,4 @@ class Transport extends events_1.EventEmitter {
188
216
  }
189
217
  }
190
218
  exports.Transport = Transport;
191
- _Transport_wire = new WeakMap();
219
+ _Transport_wire = new WeakMap(), _Transport_fin = new WeakMap();
@@ -1,6 +1,16 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createRelayedDispatch = exports.relayChannelClientApi = void 0;
4
+ const EXPECTED_ERRORS = [
5
+ 'no longer connected',
6
+ 'RTCDataChannel closed unexpectedly',
7
+ 'The client you are trying to dispatch from is disconnected from the target provider',
8
+ ];
9
+ // Checks possible error messages that we want to trap, client error message can originate
10
+ // from ChannelProvider::dispatch OR ClassicStrategy::closeEndpoint OR RTCEndPoint::dataChannel::onclose
11
+ const isDisconnectedError = (errorMsg) => {
12
+ return EXPECTED_ERRORS.some(e => errorMsg.includes(e));
13
+ };
4
14
  /**
5
15
  * @internal
6
16
  * Create a channel relay for a given channel exposition, allowing a single provider to route
@@ -27,7 +37,7 @@ const createRelayedDispatch = (client, target, relayId, relayErrorMsg) => async
27
37
  });
28
38
  }
29
39
  catch (e) {
30
- if (e.message.includes('no longer connected') && relayErrorMsg) {
40
+ if (isDisconnectedError(e.message) && relayErrorMsg) {
31
41
  throw new Error(relayErrorMsg);
32
42
  }
33
43
  ;
@@ -4,6 +4,7 @@
4
4
  export type ErrorPlainObject = {
5
5
  stack?: string;
6
6
  message: string;
7
+ name?: string;
7
8
  toString(): string;
8
9
  };
9
10
  export declare function errorToPOJO(error: Error): ErrorPlainObject;
@@ -4,6 +4,7 @@ exports.errorToPOJO = void 0;
4
4
  function errorToPOJO(error) {
5
5
  return {
6
6
  stack: error.stack,
7
+ name: error.name,
7
8
  message: error.message,
8
9
  toString: error.toString
9
10
  };
@@ -14,3 +14,21 @@ export declare class Lazy<T> {
14
14
  */
15
15
  getValue(): T;
16
16
  }
17
+ /**
18
+ * Handy class for managing asynchronous dependencies of classes.
19
+ *
20
+ * Will call asynchronous producer only after `getValue` is called. If the
21
+ * deferred code errors, we can try it again by re-calling `getValue` after
22
+ * the promise rejects.
23
+ */
24
+ export declare class AsyncRetryableLazy<T> {
25
+ private producerFn;
26
+ constructor(producerFn: () => Promise<T>);
27
+ private promise?;
28
+ /**
29
+ * Lazily get the value returned by the async producer.
30
+ *
31
+ * @returns The value returned from the producer function
32
+ */
33
+ getValue(): Promise<T>;
34
+ }
package/src/util/lazy.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Lazy = void 0;
3
+ exports.AsyncRetryableLazy = exports.Lazy = void 0;
4
4
  /**
5
5
  * Handy class for managing asynchronous dependencies of classes.
6
6
  *
@@ -24,3 +24,31 @@ class Lazy {
24
24
  }
25
25
  }
26
26
  exports.Lazy = Lazy;
27
+ /**
28
+ * Handy class for managing asynchronous dependencies of classes.
29
+ *
30
+ * Will call asynchronous producer only after `getValue` is called. If the
31
+ * deferred code errors, we can try it again by re-calling `getValue` after
32
+ * the promise rejects.
33
+ */
34
+ class AsyncRetryableLazy {
35
+ // eslint-disable-next-line
36
+ constructor(producerFn) {
37
+ this.producerFn = producerFn;
38
+ }
39
+ /**
40
+ * Lazily get the value returned by the async producer.
41
+ *
42
+ * @returns The value returned from the producer function
43
+ */
44
+ async getValue() {
45
+ if (!this.promise) {
46
+ this.promise = this.producerFn().catch((e) => {
47
+ delete this.promise;
48
+ throw e;
49
+ });
50
+ }
51
+ return this.promise;
52
+ }
53
+ }
54
+ exports.AsyncRetryableLazy = AsyncRetryableLazy;
@@ -1,4 +1,4 @@
1
- export default class RefCoutner {
1
+ export declare class RefCounter {
2
2
  topicRefMap: Map<any, any>;
3
3
  incRefCount(key: string): number;
4
4
  decRefCount(key: string): number;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- class RefCoutner {
3
+ exports.RefCounter = void 0;
4
+ class RefCounter {
4
5
  constructor() {
5
6
  this.topicRefMap = new Map();
6
7
  }
@@ -48,4 +49,4 @@ class RefCoutner {
48
49
  return isLastRef ? lastAction() : nonLastAction();
49
50
  }
50
51
  }
51
- exports.default = RefCoutner;
52
+ exports.RefCounter = RefCounter;
@@ -1,4 +0,0 @@
1
- import Fin from '../api/fin';
2
- import { Transport } from './transport';
3
- export declare function registerFin(wire: Transport, fin: Fin): void;
4
- export declare function getFin(wire: Transport): Fin;
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getFin = exports.registerFin = void 0;
4
- const finMap = new WeakMap();
5
- function registerFin(wire, fin) {
6
- finMap.set(wire, fin);
7
- }
8
- exports.registerFin = registerFin;
9
- function getFin(wire) {
10
- const fin = finMap.get(wire);
11
- if (!fin) {
12
- throw new Error('Could not locate fin api for given transport');
13
- }
14
- return fin;
15
- }
16
- exports.getFin = getFin;