@openfin/cloud-interop 0.40.37 → 0.40.39
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/README.md +20 -1
- package/out/index.js +101 -51
- package/package.json +2 -2
package/README.md
CHANGED
@@ -4,7 +4,26 @@ This package contains an override that enables Cloud Interop for `InteropBroker`
|
|
4
4
|
|
5
5
|
Overrides are passed to `fin.Platform.init` when initializing a platform or to `fin.Interop.init` when creating an `InteropBroker` directly.
|
6
6
|
|
7
|
-
Once overriden the `InteropBroker` will connect to the given Cloud Interop Service upon initialization. `Context` will be sent to the Cloud Interop
|
7
|
+
Once overriden the `InteropBroker` will connect to the given Cloud Interop Service upon initialization. `Context` will be sent to the Cloud Interop Service when the override broker calls `setContext` and the broker will also subscribe `Context` updates from other any other connected brokers in the shared session.
|
8
|
+
|
9
|
+
The Cloud Interop Service also supports `Intent`'s. Connected `InteropBroker`'s info calls (`handleInfoForIntent`, `handleInfoForIntentsByContext`, `fdc3.findIntent`, `fdc3.findIntentsByContext`) will include results for remote sessions and decorate those app identifiers with additional metadata which can then be used to raise `Intent`'s on remote sessions.
|
10
|
+
|
11
|
+
## Override Options
|
12
|
+
|
13
|
+
| Option | Type | Description | Default Value | Required |
|
14
|
+
|------------------------------------|----------------------------------------------------------------|-----------------------------------------------------------------------------------------------|-------------------|----------|
|
15
|
+
| `url` | `string` | URL of the Cloud Interop service | N/A | Yes |
|
16
|
+
| `platformId` | `string` | Platform ID | N/A | Yes |
|
17
|
+
| `sourceId` | `string` | Source ID | N/A | Yes |
|
18
|
+
| `reconnectRetryLimit` | `number` (optional) | Limit for reconnect retries | N/A | No |
|
19
|
+
| `keepAliveIntervalSeconds` | `number` (optional) | Interval in seconds to keep the connection alive | N/A | No |
|
20
|
+
| `findIntentTimeout` | `number` (optional) | How long to wait for connected clients to respond. Do not make this too high. | `3 seconds` | No |
|
21
|
+
| `authenticationType` | ``'jwt' \| 'basic' \| 'default'`` (optional) | Type of authentication to use | N/A | No |
|
22
|
+
| `basicAuthenticationParameters` | `{ username: string, password: string }` (optional) | Parameters for basic authentication | N/A | No |
|
23
|
+
| `jwtAuthenticationParameters` | `{ jwtRequestCallback: () => string \| object, authenticationId: string }` (optional) | Parameters for JWT authentication | N/A | No |
|
24
|
+
| `logger` | ``(logLevel: 'log' \| 'debug' \| 'info' \| 'warn' \| 'error', message: string, ...args: unknown[]) => void`` (optional) | If provided, will defer to this logger, otherwise logs to `console.debug`, reduced by LogLevel | `console.debug` | No |
|
25
|
+
| `logLevel` | ``'log' \| 'debug' \| 'info' \| 'warn' \| 'error'`` (optional) | The level at which cloud-interop override will log. | `'warn'` | No |
|
26
|
+
|
8
27
|
|
9
28
|
## Usage
|
10
29
|
|
package/out/index.js
CHANGED
@@ -4123,11 +4123,18 @@ async function cloudInteropOverride(config) {
|
|
4123
4123
|
const { url, findIntentTimeout = DEFAULT_TIMEOUT, logLevel = 'warn', logger = new Logger(logLevel), ...settings } = config;
|
4124
4124
|
const client = new CloudInteropAPI({ url });
|
4125
4125
|
// create closure to use computed settings above in the CloudInteropOverride::reconnect function below
|
4126
|
-
const initConnect = async (connectParams = settings) =>
|
4127
|
-
|
4128
|
-
|
4129
|
-
|
4130
|
-
|
4126
|
+
const initConnect = async (connectParams = settings) => {
|
4127
|
+
client.connect({
|
4128
|
+
...connectParams,
|
4129
|
+
// shim our logSink onto cloud-api logger func
|
4130
|
+
logger: (level, msg) => logger.log(level, msg)
|
4131
|
+
});
|
4132
|
+
};
|
4133
|
+
const isLocalTargetSession = (targetAppId) => {
|
4134
|
+
const target = typeof targetAppId === 'string' ? targetAppId : targetAppId.appId;
|
4135
|
+
const targetSessionId = client.parseSessionId(target);
|
4136
|
+
return !targetSessionId || targetSessionId === client.sessionDetails?.sessionId;
|
4137
|
+
};
|
4131
4138
|
try {
|
4132
4139
|
await initConnect();
|
4133
4140
|
}
|
@@ -4177,9 +4184,10 @@ async function cloudInteropOverride(config) {
|
|
4177
4184
|
client.addEventListener('raise-intent', async ({ initiatingSessionId, raiseOptions }) => {
|
4178
4185
|
logger.log('debug', `Received raise-intent request from ${initiatingSessionId}`);
|
4179
4186
|
if ('metadata' in raiseOptions.context && raiseOptions.context.metadata.target) {
|
4180
|
-
|
4181
|
-
|
4182
|
-
|
4187
|
+
raiseOptions.context.metadata.target = {
|
4188
|
+
...raiseOptions.context.metadata.target,
|
4189
|
+
appId: client.parseAppId(raiseOptions.context.metadata.target)
|
4190
|
+
};
|
4183
4191
|
}
|
4184
4192
|
let result;
|
4185
4193
|
try {
|
@@ -4189,15 +4197,15 @@ async function cloudInteropOverride(config) {
|
|
4189
4197
|
const intentResult = await intentResolution.getResult();
|
4190
4198
|
const { intent, source, version } = intentResolution;
|
4191
4199
|
result = { intent, source, version };
|
4200
|
+
logger.log('debug', `Intent result: ${JSON.stringify(intentResult, null, 2)}`);
|
4192
4201
|
if (isContext(intentResult)) {
|
4193
4202
|
// currently only supporting Contexts as results
|
4194
4203
|
result.getResult = intentResult;
|
4195
4204
|
}
|
4196
4205
|
}
|
4197
4206
|
catch (e) {
|
4198
|
-
logger.log('warn', `Error in raise-intent, forwarding error response to the cloud: ${e}
|
4199
|
-
|
4200
|
-
result = { error: `Error raising intent: ${e}` };
|
4207
|
+
logger.log('warn', `Error in raise-intent, forwarding error response to the cloud: ${e}`, e.stack);
|
4208
|
+
result = { error: e.message };
|
4201
4209
|
}
|
4202
4210
|
logger.log('debug', `Sending intent result to ${initiatingSessionId}:\n${JSON.stringify(result, null, 2)}`);
|
4203
4211
|
await this.#maybeReconnect();
|
@@ -4207,48 +4215,64 @@ async function cloudInteropOverride(config) {
|
|
4207
4215
|
async handleInfoForIntent(options, clientIdentity) {
|
4208
4216
|
logger.log('debug', `in handleInfoForIntent`, options);
|
4209
4217
|
const { name, context, metadata } = options;
|
4210
|
-
|
4218
|
+
const intentsPromise = super.handleInfoForIntent(options, clientIdentity);
|
4219
|
+
return this.#handleInfoForIntent(intentsPromise, name, context, metadata?.resultType);
|
4211
4220
|
}
|
4212
4221
|
async handleInfoForIntentsByContext(context, clientIdentity) {
|
4213
4222
|
logger.log('debug', `in handleInfoForIntentsByContext`, context);
|
4214
|
-
|
4215
|
-
|
4216
|
-
|
4223
|
+
const intentsPromise = super.handleInfoForIntentsByContext(context, clientIdentity);
|
4224
|
+
return 'type' in context
|
4225
|
+
? this.#handleInfoForIntent(intentsPromise, undefined, context, undefined)
|
4226
|
+
: this.#handleInfoForIntent(intentsPromise, undefined, context.context, context.metadata?.resultType);
|
4217
4227
|
}
|
4218
4228
|
async handleFiredIntent(intent, clientIdentity) {
|
4219
4229
|
logger.log('debug', `in handleFiredIntent`, intent);
|
4220
|
-
return this.#handleFiredIntent(intent);
|
4230
|
+
return this.#handleFiredIntent(clientIdentity, intent);
|
4221
4231
|
}
|
4222
4232
|
async handleFiredIntentForContext(contextForIntent, clientIdentity) {
|
4223
4233
|
logger.log('debug', `in handleFiredIntentForContext`, contextForIntent);
|
4224
|
-
return this.#handleFiredIntent(
|
4234
|
+
return this.#handleFiredIntent(clientIdentity, contextForIntent);
|
4225
4235
|
}
|
4226
|
-
async #handleInfoForIntent(
|
4236
|
+
async #handleInfoForIntent(
|
4237
|
+
/**
|
4238
|
+
* Promise to execute in parallel with intent discovery
|
4239
|
+
*/
|
4240
|
+
localIntentsPromise,
|
4241
|
+
/**
|
4242
|
+
* if present -> findIntent
|
4243
|
+
*/
|
4244
|
+
intent,
|
4245
|
+
/**
|
4246
|
+
* if present -> findIntentsByContext
|
4247
|
+
*/
|
4248
|
+
context, resultType) {
|
4227
4249
|
logger.log('debug', `in #handleInfoForIntent`, { intent, context, resultType });
|
4228
|
-
await this.#maybeReconnect();
|
4229
4250
|
if (!intent && !context) {
|
4230
4251
|
throw new Error('[CloudInteropOverride] #handleInfoForIntent requires intent or context');
|
4231
4252
|
}
|
4232
4253
|
if (context?.metadata?.target) {
|
4233
|
-
|
4234
|
-
if
|
4235
|
-
|
4254
|
+
// safeguard MQ traffic by short circuiting here
|
4255
|
+
// if session id not parsable, it's a local intent, also if session id
|
4256
|
+
// is parsed and matches the current session, treat it as a local findIntent action
|
4257
|
+
if (isLocalTargetSession(context.metadata.target)) {
|
4258
|
+
logger.log('debug', `#handleInfoForIntent received an appId for the same session, returning local intent results only`);
|
4259
|
+
return localIntentsPromise;
|
4236
4260
|
}
|
4237
4261
|
}
|
4238
|
-
|
4262
|
+
await this.#maybeReconnect();
|
4263
|
+
const appIntentMap = new Map();
|
4264
|
+
const upsertToMap = ({ intent, apps }) => {
|
4265
|
+
// merge all apps for the same intent
|
4266
|
+
const existingApps = appIntentMap.get(intent.name) ?? [];
|
4267
|
+
appIntentMap.set(intent.name, [...existingApps, ...apps]);
|
4268
|
+
};
|
4239
4269
|
let aggregateResolve;
|
4240
4270
|
const aggregatePromise = new Promise((resolve) => {
|
4241
4271
|
aggregateResolve = resolve;
|
4242
4272
|
});
|
4243
4273
|
client.once('aggregate-intent-details', ({ responses }) => {
|
4244
4274
|
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
|
-
});
|
4275
|
+
responses.forEach(({ intents }) => intents.forEach(upsertToMap));
|
4252
4276
|
aggregateResolve();
|
4253
4277
|
});
|
4254
4278
|
const options = {
|
@@ -4261,25 +4285,35 @@ async function cloudInteropOverride(config) {
|
|
4261
4285
|
await client.startIntentDiscovery(options);
|
4262
4286
|
await aggregatePromise;
|
4263
4287
|
logger.log('debug', 'Intent discovery completed');
|
4264
|
-
const
|
4265
|
-
|
4266
|
-
|
4267
|
-
|
4268
|
-
|
4269
|
-
}
|
4270
|
-
|
4288
|
+
const localAppIntents = (await localIntentsPromise
|
4289
|
+
.then((intents) => (Array.isArray(intents) ? intents : [intents]))
|
4290
|
+
.catch(() => []));
|
4291
|
+
localAppIntents.forEach(upsertToMap);
|
4292
|
+
const appIntents = Array.from(appIntentMap.entries()).map(([intent, apps]) => ({
|
4293
|
+
intent: { name: intent, displayName: intent },
|
4294
|
+
apps
|
4295
|
+
}));
|
4296
|
+
if (appIntents.length === 0) {
|
4297
|
+
throw new Error('NoAppsFound');
|
4298
|
+
}
|
4299
|
+
return (intent ? appIntents[0] : appIntents);
|
4271
4300
|
}
|
4272
|
-
async #handleFiredIntent(
|
4273
|
-
logger.log('debug', `in #handleFiredIntent`, {
|
4301
|
+
async #handleFiredIntent(clientIdentity, input) {
|
4302
|
+
logger.log('debug', `in #handleFiredIntent`, { input });
|
4274
4303
|
await this.#maybeReconnect();
|
4275
|
-
const targetApp =
|
4304
|
+
const targetApp = input?.metadata?.target;
|
4276
4305
|
if (!targetApp) {
|
4277
4306
|
throw new Error(`[CloudInteropOverride] handleFiredIntent requires intent.metadata.target or context.metadata.target to be an appId`);
|
4278
4307
|
}
|
4308
|
+
const isIntent = (input) => 'name' in input;
|
4279
4309
|
// safeguard MQ traffic by short circuiting here
|
4280
|
-
|
4281
|
-
|
4282
|
-
|
4310
|
+
// if session id not parsable, it's a local intent, also if session id
|
4311
|
+
// is parsed and matches the current session, treat it as a local intent
|
4312
|
+
if (isLocalTargetSession(targetApp)) {
|
4313
|
+
logger.log('debug', `#handleFiredIntent received an appId for the same session, firing intent locally`);
|
4314
|
+
return (isIntent(input)
|
4315
|
+
? super.handleFiredIntent(input, clientIdentity)
|
4316
|
+
: super.handleFiredIntentForContext(input, clientIdentity));
|
4283
4317
|
}
|
4284
4318
|
let intentResolve;
|
4285
4319
|
const intentResultPromise = new Promise((resolve) => {
|
@@ -4289,25 +4323,41 @@ async function cloudInteropOverride(config) {
|
|
4289
4323
|
logger.log('debug', `Received intent-result`, JSON.stringify({ source, result }, null, 2));
|
4290
4324
|
intentResolve(result);
|
4291
4325
|
});
|
4292
|
-
const raiseOptions =
|
4293
|
-
? { type: 'raise-intent', intent:
|
4294
|
-
: { type: 'raise-intent-for-context', context:
|
4326
|
+
const raiseOptions = isIntent(input)
|
4327
|
+
? { type: 'raise-intent', intent: input.name, context: input.context }
|
4328
|
+
: { type: 'raise-intent-for-context', context: input };
|
4295
4329
|
await client.raiseIntent({ appId: targetApp, raiseOptions });
|
4296
4330
|
// TODO: raise-intent timeout via promise.race?
|
4297
4331
|
const intentResult = await intentResultPromise;
|
4332
|
+
const publishLocalResult = async (result) => {
|
4333
|
+
// NOTE: since we aren't changing getIntentResolution in the fdc3 impl code,
|
4334
|
+
// we "fake" a local intent result to ensure getResult resolves correctly, see:
|
4335
|
+
// js-adapter/src/api/interop/fdc3/utils.ts::getIntentResolution::fin.InterApplicationBus.subscribe
|
4336
|
+
const intentResolutionResultId = input.metadata?.intentResolutionResultId;
|
4337
|
+
// skip for web/external connections
|
4338
|
+
if (!this.fin.me.isOpenFin) {
|
4339
|
+
return;
|
4340
|
+
}
|
4341
|
+
if (intentResolutionResultId) {
|
4342
|
+
this.fin.InterApplicationBus.publish(intentResolutionResultId, result).catch(() => {
|
4343
|
+
logger.log('warn', `#handleFiredIntent could not create an intent resolution for AppId: ${targetApp}, getResult call will not work.`, intentResult);
|
4344
|
+
});
|
4345
|
+
}
|
4346
|
+
};
|
4298
4347
|
if ('error' in intentResult) {
|
4299
4348
|
logger.log('warn', `#handleFiredIntent could not raise intent for AppId: ${targetApp}`);
|
4349
|
+
// matching { error: Boolean } type of js-adapter/src/api/interop/fdc3/utils.ts::IntentResultPromisePayload
|
4350
|
+
publishLocalResult({ error: true });
|
4300
4351
|
// Presumably, the error is FDC3 compliant, so throw it as is
|
4301
|
-
// TODO: use the message key instead of the entire error string
|
4302
4352
|
throw new Error(intentResult.error);
|
4303
4353
|
}
|
4304
4354
|
const source = typeof intentResult.source === 'string' ? { appId: intentResult.source } : intentResult.source;
|
4355
|
+
const finalResult = { ...intentResult, source };
|
4356
|
+
publishLocalResult(finalResult.getResult);
|
4305
4357
|
return {
|
4306
|
-
|
4307
|
-
version: intentResult.version,
|
4308
|
-
source,
|
4358
|
+
...finalResult,
|
4309
4359
|
// Currently only supporting contexts as results
|
4310
|
-
getResult: async () =>
|
4360
|
+
getResult: async () => finalResult.getResult
|
4311
4361
|
};
|
4312
4362
|
}
|
4313
4363
|
async setContextForGroup({ context }, contextGroupId) {
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@openfin/cloud-interop",
|
3
|
-
"version": "0.40.
|
3
|
+
"version": "0.40.39",
|
4
4
|
"description": "",
|
5
5
|
"private": false,
|
6
6
|
"files": [
|
@@ -20,7 +20,7 @@
|
|
20
20
|
"author": "",
|
21
21
|
"license": "SEE LICENSE IN LICENSE.md",
|
22
22
|
"peerDependencies": {
|
23
|
-
"@openfin/core": "40.103.
|
23
|
+
"@openfin/core": "40.103.5"
|
24
24
|
},
|
25
25
|
"dependencies": {
|
26
26
|
"@openfin/cloud-interop-core-api": "0.0.1-alpha.a27677b"
|