@openfin/cloud-interop 0.40.35 → 0.40.37
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/out/index.js +239 -8
- package/out/logger.d.ts +17 -0
- package/out/override.d.ts +34 -2
- package/out/utils.d.ts +2 -0
- package/package.json +4 -3
package/out/index.js
CHANGED
@@ -4055,22 +4055,88 @@ class CloudInteropAPI {
|
|
4055
4055
|
};
|
4056
4056
|
}
|
4057
4057
|
|
4058
|
+
/* eslint-disable no-console */
|
4059
|
+
var LogLevel;
|
4060
|
+
(function (LogLevel) {
|
4061
|
+
LogLevel[LogLevel["DEBUG"] = 0] = "DEBUG";
|
4062
|
+
LogLevel[LogLevel["INFO"] = 1] = "INFO";
|
4063
|
+
LogLevel[LogLevel["WARN"] = 2] = "WARN";
|
4064
|
+
// TODO: eventually support NONE = 3
|
4065
|
+
})(LogLevel || (LogLevel = {}));
|
4066
|
+
const levelToStr = new Map([
|
4067
|
+
[LogLevel.DEBUG, 'debug'],
|
4068
|
+
[LogLevel.INFO, 'info'],
|
4069
|
+
[LogLevel.WARN, 'warn']
|
4070
|
+
]);
|
4071
|
+
const strToLevel = new Map([
|
4072
|
+
['debug', LogLevel.DEBUG],
|
4073
|
+
['info', LogLevel.INFO],
|
4074
|
+
['warn', LogLevel.WARN],
|
4075
|
+
// reduce 'error' and 'log' to warn/info
|
4076
|
+
['error', LogLevel.WARN],
|
4077
|
+
['log', LogLevel.INFO]
|
4078
|
+
]);
|
4079
|
+
const getTimestamp = () => new Date().toISOString().replace('T', ' ').replace('Z', '');
|
4080
|
+
/**
|
4081
|
+
* This logger retrofits on top of the CloudAPILogger function signature so it must use CloudAPILogLevel inputs
|
4082
|
+
*/
|
4083
|
+
class Logger {
|
4084
|
+
logLevel;
|
4085
|
+
// eslint-disable-next-line no-useless-constructor
|
4086
|
+
constructor(level = 'warn') {
|
4087
|
+
this.logLevel = strToLevel.get(level) ?? LogLevel.WARN;
|
4088
|
+
}
|
4089
|
+
log(logLevel, message, ...args) {
|
4090
|
+
const level = strToLevel.get(logLevel) ?? this.logLevel;
|
4091
|
+
if (this.logLevel <= level) {
|
4092
|
+
// always write to console.debug to avoid cluttering client logs
|
4093
|
+
// TODO(RUN-9370): Change this to console.debug after this runtime ticket is fixed
|
4094
|
+
console.log(`${getTimestamp()} | CloudInteropOverride [${levelToStr.get(level)}] ${message}`, ...args);
|
4095
|
+
}
|
4096
|
+
}
|
4097
|
+
}
|
4098
|
+
|
4099
|
+
const isContext = (chan) => {
|
4100
|
+
const c = chan;
|
4101
|
+
return c && typeof c === 'object' && 'type' in c && !('broadcast' in c);
|
4102
|
+
};
|
4103
|
+
|
4104
|
+
const DEFAULT_TIMEOUT = 3000;
|
4058
4105
|
/**
|
4059
4106
|
* Enhances InteropBroker with Cloud Interop functionality
|
4107
|
+
*
|
4108
|
+
* Ensure that CloudInteropOverride comes first in the list of composable overrides, for example:
|
4109
|
+
* ```
|
4110
|
+
* const CloudInteropOverride = await cloudInteropOverride(settings);
|
4111
|
+
* await fin.Platform.init({
|
4112
|
+
* ...,
|
4113
|
+
* interopOverride: [
|
4114
|
+
* CloudInteropOverride, // <--- must come first
|
4115
|
+
* (BaseProvider) => class MyCustomProvider extends BaseProvider { ... }
|
4116
|
+
* ]
|
4117
|
+
* });
|
4118
|
+
* ```
|
4119
|
+
*
|
4060
4120
|
* @param {CloudInteropOverrideParams} config Configuration to connect to the Cloud Interop service
|
4061
4121
|
*/
|
4062
4122
|
async function cloudInteropOverride(config) {
|
4063
|
-
const { url, ...settings } = config;
|
4123
|
+
const { url, findIntentTimeout = DEFAULT_TIMEOUT, logLevel = 'warn', logger = new Logger(logLevel), ...settings } = config;
|
4064
4124
|
const client = new CloudInteropAPI({ url });
|
4125
|
+
// create closure to use computed settings above in the CloudInteropOverride::reconnect function below
|
4126
|
+
const initConnect = async (connectParams = settings) => client.connect({
|
4127
|
+
...connectParams,
|
4128
|
+
// shim our logSink onto cloud-api logger func
|
4129
|
+
logger: (level, msg) => logger.log(level, msg)
|
4130
|
+
});
|
4065
4131
|
try {
|
4066
|
-
await
|
4132
|
+
await initConnect();
|
4067
4133
|
}
|
4068
4134
|
catch (err) {
|
4069
4135
|
// eslint-disable-next-line no-console
|
4070
|
-
|
4136
|
+
logger.log('warn', `Failed to connect to Cloud Interop Service. Call interopBroker.cloudReconnect() to attempt reconnection`, err);
|
4071
4137
|
}
|
4072
|
-
return (
|
4073
|
-
return class CloudInteropOverride extends
|
4138
|
+
return (BaseProvider) => {
|
4139
|
+
return class CloudInteropOverride extends BaseProvider {
|
4074
4140
|
contextListener;
|
4075
4141
|
setContextFilter = (context) => true;
|
4076
4142
|
constructor() {
|
@@ -4085,10 +4151,169 @@ async function cloudInteropOverride(config) {
|
|
4085
4151
|
}
|
4086
4152
|
};
|
4087
4153
|
client.addEventListener('context', this.contextListener);
|
4154
|
+
client.addEventListener('report-intents', async ({ discoveryId, initiatingSessionId, findOptions }) => {
|
4155
|
+
logger.log('debug', `Received report-intents request from ${initiatingSessionId}`);
|
4156
|
+
let appIntents = [];
|
4157
|
+
try {
|
4158
|
+
if (findOptions.type === 'find-intent') {
|
4159
|
+
const intent = (await super.handleInfoForIntent({
|
4160
|
+
name: findOptions.intent,
|
4161
|
+
metadata: { resultType: findOptions.resultType },
|
4162
|
+
context: findOptions.context
|
4163
|
+
}, null));
|
4164
|
+
appIntents = [intent];
|
4165
|
+
}
|
4166
|
+
else {
|
4167
|
+
appIntents = (await super.handleInfoForIntentsByContext({ context: findOptions.context, metadata: { resultType: findOptions.resultType } }, null));
|
4168
|
+
}
|
4169
|
+
}
|
4170
|
+
catch (e) {
|
4171
|
+
logger.log('warn', `Error in report-intents listener, proceeding with an empty response: ${e}`);
|
4172
|
+
}
|
4173
|
+
logger.log('debug', `Reporting intents :\n${JSON.stringify(appIntents, null, 2)}`);
|
4174
|
+
await this.#maybeReconnect();
|
4175
|
+
await client.reportAppIntents(discoveryId, appIntents);
|
4176
|
+
});
|
4177
|
+
client.addEventListener('raise-intent', async ({ initiatingSessionId, raiseOptions }) => {
|
4178
|
+
logger.log('debug', `Received raise-intent request from ${initiatingSessionId}`);
|
4179
|
+
if ('metadata' in raiseOptions.context && raiseOptions.context.metadata.target) {
|
4180
|
+
const { target } = raiseOptions.context.metadata;
|
4181
|
+
// parse the actual app id from the cloud-app-id string
|
4182
|
+
raiseOptions.context.metadata.target = client.parseAppId(target);
|
4183
|
+
}
|
4184
|
+
let result;
|
4185
|
+
try {
|
4186
|
+
const intentResolution = (raiseOptions.type === 'raise-intent'
|
4187
|
+
? await super.handleFiredIntent({ name: raiseOptions.intent, context: raiseOptions.context }, null)
|
4188
|
+
: await super.handleFiredIntentForContext(raiseOptions.context, null));
|
4189
|
+
const intentResult = await intentResolution.getResult();
|
4190
|
+
const { intent, source, version } = intentResolution;
|
4191
|
+
result = { intent, source, version };
|
4192
|
+
if (isContext(intentResult)) {
|
4193
|
+
// currently only supporting Contexts as results
|
4194
|
+
result.getResult = intentResult;
|
4195
|
+
}
|
4196
|
+
}
|
4197
|
+
catch (e) {
|
4198
|
+
logger.log('warn', `Error in raise-intent, forwarding error response to the cloud: ${e}`);
|
4199
|
+
// TODO: maybe set the message as a separate key to carry-forward the actual fdc3 error string
|
4200
|
+
result = { error: `Error raising intent: ${e}` };
|
4201
|
+
}
|
4202
|
+
logger.log('debug', `Sending intent result to ${initiatingSessionId}:\n${JSON.stringify(result, null, 2)}`);
|
4203
|
+
await this.#maybeReconnect();
|
4204
|
+
await client.sendIntentResult(initiatingSessionId, result);
|
4205
|
+
});
|
4206
|
+
}
|
4207
|
+
async handleInfoForIntent(options, clientIdentity) {
|
4208
|
+
logger.log('debug', `in handleInfoForIntent`, options);
|
4209
|
+
const { name, context, metadata } = options;
|
4210
|
+
return this.#handleInfoForIntent(name, context, metadata?.resultType);
|
4211
|
+
}
|
4212
|
+
async handleInfoForIntentsByContext(context, clientIdentity) {
|
4213
|
+
logger.log('debug', `in handleInfoForIntentsByContext`, context);
|
4214
|
+
return ('type' in context
|
4215
|
+
? this.#handleInfoForIntent(undefined, context, undefined)
|
4216
|
+
: this.#handleInfoForIntent(undefined, context.context, context.metadata?.resultType));
|
4217
|
+
}
|
4218
|
+
async handleFiredIntent(intent, clientIdentity) {
|
4219
|
+
logger.log('debug', `in handleFiredIntent`, intent);
|
4220
|
+
return this.#handleFiredIntent(intent);
|
4221
|
+
}
|
4222
|
+
async handleFiredIntentForContext(contextForIntent, clientIdentity) {
|
4223
|
+
logger.log('debug', `in handleFiredIntentForContext`, contextForIntent);
|
4224
|
+
return this.#handleFiredIntent(undefined, contextForIntent);
|
4225
|
+
}
|
4226
|
+
async #handleInfoForIntent(intent, context, resultType) {
|
4227
|
+
logger.log('debug', `in #handleInfoForIntent`, { intent, context, resultType });
|
4228
|
+
await this.#maybeReconnect();
|
4229
|
+
if (!intent && !context) {
|
4230
|
+
throw new Error('[CloudInteropOverride] #handleInfoForIntent requires intent or context');
|
4231
|
+
}
|
4232
|
+
if (context?.metadata?.target) {
|
4233
|
+
const targetSessionId = client.parseSessionId(context?.metadata?.target);
|
4234
|
+
if (targetSessionId && targetSessionId === client.sessionDetails?.sessionId) {
|
4235
|
+
throw new Error('[CloudInteropOverride] handleInfoForIntent cannot be called on the same session');
|
4236
|
+
}
|
4237
|
+
}
|
4238
|
+
const appIntentsMap = new Map();
|
4239
|
+
let aggregateResolve;
|
4240
|
+
const aggregatePromise = new Promise((resolve) => {
|
4241
|
+
aggregateResolve = resolve;
|
4242
|
+
});
|
4243
|
+
client.once('aggregate-intent-details', ({ responses }) => {
|
4244
|
+
logger.log('debug', `Received aggregate intent details, length: ${responses.length}`);
|
4245
|
+
responses.forEach(({ intents }) => {
|
4246
|
+
intents.forEach((intent) => {
|
4247
|
+
const appIntentList = appIntentsMap.get(intent.intent.name) || [];
|
4248
|
+
appIntentList.push(intent);
|
4249
|
+
appIntentsMap.set(intent.intent.name, appIntentList);
|
4250
|
+
});
|
4251
|
+
});
|
4252
|
+
aggregateResolve();
|
4253
|
+
});
|
4254
|
+
const options = {
|
4255
|
+
timeout: findIntentTimeout,
|
4256
|
+
findOptions: intent
|
4257
|
+
? { type: 'find-intent', intent, context, resultType }
|
4258
|
+
: { type: 'find-intents-by-context', context: context, resultType }
|
4259
|
+
};
|
4260
|
+
logger.log('debug', 'Starting intent discovery');
|
4261
|
+
await client.startIntentDiscovery(options);
|
4262
|
+
await aggregatePromise;
|
4263
|
+
logger.log('debug', 'Intent discovery completed');
|
4264
|
+
const appIntents = intent
|
4265
|
+
? appIntentsMap.get(intent) || []
|
4266
|
+
: Array.from(appIntentsMap.entries()).map(([intent, appIntents]) => ({
|
4267
|
+
intent: { name: intent, displayName: intent },
|
4268
|
+
apps: appIntents.flatMap(({ apps }) => apps)
|
4269
|
+
}));
|
4270
|
+
return appIntents;
|
4271
|
+
}
|
4272
|
+
async #handleFiredIntent(intent, context) {
|
4273
|
+
logger.log('debug', `in #handleFiredIntent`, { intent, context });
|
4274
|
+
await this.#maybeReconnect();
|
4275
|
+
const targetApp = intent?.metadata?.target ?? context?.metadata?.target;
|
4276
|
+
if (!targetApp) {
|
4277
|
+
throw new Error(`[CloudInteropOverride] handleFiredIntent requires intent.metadata.target or context.metadata.target to be an appId`);
|
4278
|
+
}
|
4279
|
+
// safeguard MQ traffic by short circuiting here
|
4280
|
+
const targetSessionId = client.parseSessionId(targetApp);
|
4281
|
+
if (targetSessionId === client.sessionDetails?.sessionId) {
|
4282
|
+
throw new Error('[CloudInteropOverride] handleFiredIntent cannot be called on the same session');
|
4283
|
+
}
|
4284
|
+
let intentResolve;
|
4285
|
+
const intentResultPromise = new Promise((resolve) => {
|
4286
|
+
intentResolve = resolve;
|
4287
|
+
});
|
4288
|
+
client.once('intent-result', ({ result, source }) => {
|
4289
|
+
logger.log('debug', `Received intent-result`, JSON.stringify({ source, result }, null, 2));
|
4290
|
+
intentResolve(result);
|
4291
|
+
});
|
4292
|
+
const raiseOptions = intent
|
4293
|
+
? { type: 'raise-intent', intent: intent.name, context: intent.context }
|
4294
|
+
: { type: 'raise-intent-for-context', context: context };
|
4295
|
+
await client.raiseIntent({ appId: targetApp, raiseOptions });
|
4296
|
+
// TODO: raise-intent timeout via promise.race?
|
4297
|
+
const intentResult = await intentResultPromise;
|
4298
|
+
if ('error' in intentResult) {
|
4299
|
+
logger.log('warn', `#handleFiredIntent could not raise intent for AppId: ${targetApp}`);
|
4300
|
+
// Presumably, the error is FDC3 compliant, so throw it as is
|
4301
|
+
// TODO: use the message key instead of the entire error string
|
4302
|
+
throw new Error(intentResult.error);
|
4303
|
+
}
|
4304
|
+
const source = typeof intentResult.source === 'string' ? { appId: intentResult.source } : intentResult.source;
|
4305
|
+
return {
|
4306
|
+
intent: intentResult.intent,
|
4307
|
+
version: intentResult.version,
|
4308
|
+
source,
|
4309
|
+
// Currently only supporting contexts as results
|
4310
|
+
getResult: async () => intentResult.getResult
|
4311
|
+
};
|
4088
4312
|
}
|
4089
4313
|
async setContextForGroup({ context }, contextGroupId) {
|
4314
|
+
// TODO: is this right? should we attempt a reconnect instead of check connected state?
|
4090
4315
|
if (this.cloudConnectionState === 'connected' && this.setContextFilter(context)) {
|
4091
|
-
client.setContext(contextGroupId, context);
|
4316
|
+
await client.setContext(contextGroupId, context);
|
4092
4317
|
}
|
4093
4318
|
super.setContextForGroup({ context }, contextGroupId);
|
4094
4319
|
}
|
@@ -4105,10 +4330,10 @@ async function cloudInteropOverride(config) {
|
|
4105
4330
|
if (this.cloudConnectionState === 'connected') {
|
4106
4331
|
await client.disconnect();
|
4107
4332
|
}
|
4108
|
-
await
|
4333
|
+
await initConnect(settings);
|
4109
4334
|
}
|
4110
4335
|
catch (err) {
|
4111
|
-
|
4336
|
+
logger.log('warn', `Failed reconnection to Cloud Interop Service.`, err);
|
4112
4337
|
}
|
4113
4338
|
}
|
4114
4339
|
/**
|
@@ -4140,6 +4365,12 @@ async function cloudInteropOverride(config) {
|
|
4140
4365
|
}
|
4141
4366
|
return 'disconnected';
|
4142
4367
|
}
|
4368
|
+
#maybeReconnect = async () => {
|
4369
|
+
// TODO: Remove this helper when SAAS-1588 is solved
|
4370
|
+
if (this.cloudConnectionState !== 'connected') {
|
4371
|
+
await this.cloudReconnect();
|
4372
|
+
}
|
4373
|
+
};
|
4143
4374
|
};
|
4144
4375
|
};
|
4145
4376
|
}
|
package/out/logger.d.ts
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
import { LogLevel as CloudAPILogLevel } from '@openfin/cloud-interop-core-api';
|
2
|
+
export declare const enum LogLevel {
|
3
|
+
DEBUG = 0,
|
4
|
+
INFO = 1,
|
5
|
+
WARN = 2
|
6
|
+
}
|
7
|
+
export interface LogSink {
|
8
|
+
log: (logLevel: CloudAPILogLevel, message: string, ...args: unknown[]) => void;
|
9
|
+
}
|
10
|
+
/**
|
11
|
+
* This logger retrofits on top of the CloudAPILogger function signature so it must use CloudAPILogLevel inputs
|
12
|
+
*/
|
13
|
+
export declare class Logger implements LogSink {
|
14
|
+
private readonly logLevel;
|
15
|
+
constructor(level?: CloudAPILogLevel);
|
16
|
+
log(logLevel: CloudAPILogLevel, message: string, ...args: unknown[]): void;
|
17
|
+
}
|
package/out/override.d.ts
CHANGED
@@ -1,11 +1,43 @@
|
|
1
|
-
import { ConnectParameters } from '@openfin/cloud-interop-core-api';
|
1
|
+
import { LogLevel as CloudAPILogLevel, ConnectParameters } from '@openfin/cloud-interop-core-api';
|
2
2
|
import type OpenFin from '@openfin/core';
|
3
|
-
|
3
|
+
import { LogSink } from './logger';
|
4
|
+
type ConnectParametersNoLogger = Omit<ConnectParameters, 'logger'>;
|
5
|
+
export type CloudInteropOverrideParams = ConnectParametersNoLogger & {
|
6
|
+
/**
|
7
|
+
* URL of the Cloud Interop service
|
8
|
+
*/
|
4
9
|
url: string;
|
10
|
+
/**
|
11
|
+
* How long to wait for connected clients to respond, defaults to 3 seconds.
|
12
|
+
* Do not make this number too high, as it will block findIntent/findIntentsByContext calls
|
13
|
+
*/
|
14
|
+
findIntentTimeout?: number;
|
15
|
+
/**
|
16
|
+
* If provided will defer to this logger, otherwise logs to console.debug, reduced by LogLevel
|
17
|
+
*/
|
18
|
+
logger?: LogSink;
|
19
|
+
/**
|
20
|
+
* The level which cloud-interop override will log. Defaults to 'warn'
|
21
|
+
*/
|
22
|
+
logLevel?: CloudAPILogLevel;
|
5
23
|
};
|
6
24
|
export type CloudInteropConnectionStates = 'connected' | 'reconnecting' | 'disconnected';
|
7
25
|
/**
|
8
26
|
* Enhances InteropBroker with Cloud Interop functionality
|
27
|
+
*
|
28
|
+
* Ensure that CloudInteropOverride comes first in the list of composable overrides, for example:
|
29
|
+
* ```
|
30
|
+
* const CloudInteropOverride = await cloudInteropOverride(settings);
|
31
|
+
* await fin.Platform.init({
|
32
|
+
* ...,
|
33
|
+
* interopOverride: [
|
34
|
+
* CloudInteropOverride, // <--- must come first
|
35
|
+
* (BaseProvider) => class MyCustomProvider extends BaseProvider { ... }
|
36
|
+
* ]
|
37
|
+
* });
|
38
|
+
* ```
|
39
|
+
*
|
9
40
|
* @param {CloudInteropOverrideParams} config Configuration to connect to the Cloud Interop service
|
10
41
|
*/
|
11
42
|
export declare function cloudInteropOverride(config: CloudInteropOverrideParams): Promise<OpenFin.ConstructorOverride<OpenFin.InteropBroker>>;
|
43
|
+
export {};
|
package/out/utils.d.ts
ADDED
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@openfin/cloud-interop",
|
3
|
-
"version": "0.40.
|
3
|
+
"version": "0.40.37",
|
4
4
|
"description": "",
|
5
5
|
"private": false,
|
6
6
|
"files": [
|
@@ -11,6 +11,7 @@
|
|
11
11
|
"scripts": {
|
12
12
|
"prebuild": "rimraf out",
|
13
13
|
"build": "rollup -c",
|
14
|
+
"watch": "rollup -c --watch",
|
14
15
|
"ci:prepublish": "of-npm prepublish",
|
15
16
|
"ci:postpublish": "of-npm postpublish",
|
16
17
|
"ci:publish": "npm publish",
|
@@ -19,9 +20,9 @@
|
|
19
20
|
"author": "",
|
20
21
|
"license": "SEE LICENSE IN LICENSE.md",
|
21
22
|
"peerDependencies": {
|
22
|
-
"@openfin/core": "40.
|
23
|
+
"@openfin/core": "40.103.1"
|
23
24
|
},
|
24
25
|
"dependencies": {
|
25
|
-
"@openfin/cloud-interop-core-api": "
|
26
|
+
"@openfin/cloud-interop-core-api": "0.0.1-alpha.a27677b"
|
26
27
|
}
|
27
28
|
}
|