@openfin/cloud-interop 0.41.107 → 0.42.0

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 (2) hide show
  1. package/out/index.js +102 -52
  2. package/package.json +2 -2
package/out/index.js CHANGED
@@ -726,11 +726,18 @@ async function cloudInteropOverride(config) {
726
726
  const { url, findIntentTimeout = DEFAULT_TIMEOUT, logLevel = 'warn', logger = new Logger(logLevel), ...settings } = config;
727
727
  const client = new CloudInteropAPI({ url });
728
728
  // create closure to use computed settings above in the CloudInteropOverride::reconnect function below
729
- const initConnect = async (connectParams = settings) => client.connect({
730
- ...connectParams,
731
- // shim our logSink onto cloud-api logger func
732
- logger: (level, msg) => logger.log(level, msg)
733
- });
729
+ const initConnect = async (connectParams = settings) => {
730
+ client.connect({
731
+ ...connectParams,
732
+ // shim our logSink onto cloud-api logger func
733
+ logger: (level, msg) => logger.log(level, msg)
734
+ });
735
+ };
736
+ const isLocalTargetSession = (targetAppId) => {
737
+ const target = typeof targetAppId === 'string' ? targetAppId : targetAppId.appId;
738
+ const targetSessionId = client.parseSessionId(target);
739
+ return !targetSessionId || targetSessionId === client.sessionDetails?.sessionId;
740
+ };
734
741
  try {
735
742
  await initConnect();
736
743
  }
@@ -780,9 +787,10 @@ async function cloudInteropOverride(config) {
780
787
  client.addEventListener('raise-intent', async ({ initiatingSessionId, raiseOptions }) => {
781
788
  logger.log('debug', `Received raise-intent request from ${initiatingSessionId}`);
782
789
  if ('metadata' in raiseOptions.context && raiseOptions.context.metadata.target) {
783
- const { target } = raiseOptions.context.metadata;
784
- // parse the actual app id from the cloud-app-id string
785
- raiseOptions.context.metadata.target = client.parseAppId(target);
790
+ raiseOptions.context.metadata.target = {
791
+ ...raiseOptions.context.metadata.target,
792
+ appId: client.parseAppId(raiseOptions.context.metadata.target)
793
+ };
786
794
  }
787
795
  let result;
788
796
  try {
@@ -792,15 +800,15 @@ async function cloudInteropOverride(config) {
792
800
  const intentResult = await intentResolution.getResult();
793
801
  const { intent, source, version } = intentResolution;
794
802
  result = { intent, source, version };
803
+ logger.log('debug', `Intent result: ${JSON.stringify(intentResult, null, 2)}`);
795
804
  if (isContext(intentResult)) {
796
805
  // currently only supporting Contexts as results
797
806
  result.getResult = intentResult;
798
807
  }
799
808
  }
800
809
  catch (e) {
801
- logger.log('warn', `Error in raise-intent, forwarding error response to the cloud: ${e}`);
802
- // TODO: maybe set the message as a separate key to carry-forward the actual fdc3 error string
803
- result = { error: `Error raising intent: ${e}` };
810
+ logger.log('warn', `Error in raise-intent, forwarding error response to the cloud: ${e}`, e.stack);
811
+ result = { error: e.message };
804
812
  }
805
813
  logger.log('debug', `Sending intent result to ${initiatingSessionId}:\n${JSON.stringify(result, null, 2)}`);
806
814
  await this.#maybeReconnect();
@@ -810,48 +818,64 @@ async function cloudInteropOverride(config) {
810
818
  async handleInfoForIntent(options, clientIdentity) {
811
819
  logger.log('debug', `in handleInfoForIntent`, options);
812
820
  const { name, context, metadata } = options;
813
- return this.#handleInfoForIntent(name, context, metadata?.resultType);
821
+ const intentsPromise = super.handleInfoForIntent(options, clientIdentity);
822
+ return this.#handleInfoForIntent(intentsPromise, name, context, metadata?.resultType);
814
823
  }
815
824
  async handleInfoForIntentsByContext(context, clientIdentity) {
816
825
  logger.log('debug', `in handleInfoForIntentsByContext`, context);
817
- return ('type' in context
818
- ? this.#handleInfoForIntent(undefined, context, undefined)
819
- : this.#handleInfoForIntent(undefined, context.context, context.metadata?.resultType));
826
+ const intentsPromise = super.handleInfoForIntentsByContext(context, clientIdentity);
827
+ return 'type' in context
828
+ ? this.#handleInfoForIntent(intentsPromise, undefined, context, undefined)
829
+ : this.#handleInfoForIntent(intentsPromise, undefined, context.context, context.metadata?.resultType);
820
830
  }
821
831
  async handleFiredIntent(intent, clientIdentity) {
822
832
  logger.log('debug', `in handleFiredIntent`, intent);
823
- return this.#handleFiredIntent(intent);
833
+ return this.#handleFiredIntent(clientIdentity, intent);
824
834
  }
825
835
  async handleFiredIntentForContext(contextForIntent, clientIdentity) {
826
836
  logger.log('debug', `in handleFiredIntentForContext`, contextForIntent);
827
- return this.#handleFiredIntent(undefined, contextForIntent);
837
+ return this.#handleFiredIntent(clientIdentity, contextForIntent);
828
838
  }
829
- async #handleInfoForIntent(intent, context, resultType) {
839
+ async #handleInfoForIntent(
840
+ /**
841
+ * Promise to execute in parallel with intent discovery
842
+ */
843
+ localIntentsPromise,
844
+ /**
845
+ * if present -> findIntent
846
+ */
847
+ intent,
848
+ /**
849
+ * if present -> findIntentsByContext
850
+ */
851
+ context, resultType) {
830
852
  logger.log('debug', `in #handleInfoForIntent`, { intent, context, resultType });
831
- await this.#maybeReconnect();
832
853
  if (!intent && !context) {
833
854
  throw new Error('[CloudInteropOverride] #handleInfoForIntent requires intent or context');
834
855
  }
835
856
  if (context?.metadata?.target) {
836
- const targetSessionId = client.parseSessionId(context?.metadata?.target);
837
- if (targetSessionId && targetSessionId === client.sessionDetails?.sessionId) {
838
- throw new Error('[CloudInteropOverride] handleInfoForIntent cannot be called on the same session');
857
+ // safeguard MQ traffic by short circuiting here
858
+ // if session id not parsable, it's a local intent, also if session id
859
+ // is parsed and matches the current session, treat it as a local findIntent action
860
+ if (isLocalTargetSession(context.metadata.target)) {
861
+ logger.log('debug', `#handleInfoForIntent received an appId for the same session, returning local intent results only`);
862
+ return localIntentsPromise;
839
863
  }
840
864
  }
841
- const appIntentsMap = new Map();
865
+ await this.#maybeReconnect();
866
+ const appIntentMap = new Map();
867
+ const upsertToMap = ({ intent, apps }) => {
868
+ // merge all apps for the same intent
869
+ const existingApps = appIntentMap.get(intent.name) ?? [];
870
+ appIntentMap.set(intent.name, [...existingApps, ...apps]);
871
+ };
842
872
  let aggregateResolve;
843
873
  const aggregatePromise = new Promise((resolve) => {
844
874
  aggregateResolve = resolve;
845
875
  });
846
876
  client.once('aggregate-intent-details', ({ responses }) => {
847
877
  logger.log('debug', `Received aggregate intent details, length: ${responses.length}`);
848
- responses.forEach(({ intents }) => {
849
- intents.forEach((intent) => {
850
- const appIntentList = appIntentsMap.get(intent.intent.name) || [];
851
- appIntentList.push(intent);
852
- appIntentsMap.set(intent.intent.name, appIntentList);
853
- });
854
- });
878
+ responses.forEach(({ intents }) => intents.forEach(upsertToMap));
855
879
  aggregateResolve();
856
880
  });
857
881
  const options = {
@@ -864,25 +888,35 @@ async function cloudInteropOverride(config) {
864
888
  await client.startIntentDiscovery(options);
865
889
  await aggregatePromise;
866
890
  logger.log('debug', 'Intent discovery completed');
867
- const appIntents = intent
868
- ? appIntentsMap.get(intent) || []
869
- : Array.from(appIntentsMap.entries()).map(([intent, appIntents]) => ({
870
- intent: { name: intent, displayName: intent },
871
- apps: appIntents.flatMap(({ apps }) => apps)
872
- }));
873
- return appIntents;
874
- }
875
- async #handleFiredIntent(intent, context) {
876
- logger.log('debug', `in #handleFiredIntent`, { intent, context });
891
+ const localAppIntents = (await localIntentsPromise
892
+ .then((intents) => (Array.isArray(intents) ? intents : [intents]))
893
+ .catch(() => []));
894
+ localAppIntents.forEach(upsertToMap);
895
+ const appIntents = Array.from(appIntentMap.entries()).map(([intent, apps]) => ({
896
+ intent: { name: intent, displayName: intent },
897
+ apps
898
+ }));
899
+ if (appIntents.length === 0) {
900
+ throw new Error('NoAppsFound');
901
+ }
902
+ return (intent ? appIntents[0] : appIntents);
903
+ }
904
+ async #handleFiredIntent(clientIdentity, input) {
905
+ logger.log('debug', `in #handleFiredIntent`, { input });
877
906
  await this.#maybeReconnect();
878
- const targetApp = intent?.metadata?.target ?? context?.metadata?.target;
907
+ const targetApp = input?.metadata?.target;
879
908
  if (!targetApp) {
880
909
  throw new Error(`[CloudInteropOverride] handleFiredIntent requires intent.metadata.target or context.metadata.target to be an appId`);
881
910
  }
911
+ const isIntent = (input) => 'name' in input;
882
912
  // safeguard MQ traffic by short circuiting here
883
- const targetSessionId = client.parseSessionId(targetApp);
884
- if (targetSessionId === client.sessionDetails?.sessionId) {
885
- throw new Error('[CloudInteropOverride] handleFiredIntent cannot be called on the same session');
913
+ // if session id not parsable, it's a local intent, also if session id
914
+ // is parsed and matches the current session, treat it as a local intent
915
+ if (isLocalTargetSession(targetApp)) {
916
+ logger.log('debug', `#handleFiredIntent received an appId for the same session, firing intent locally`);
917
+ return (isIntent(input)
918
+ ? super.handleFiredIntent(input, clientIdentity)
919
+ : super.handleFiredIntentForContext(input, clientIdentity));
886
920
  }
887
921
  let intentResolve;
888
922
  const intentResultPromise = new Promise((resolve) => {
@@ -892,25 +926,41 @@ async function cloudInteropOverride(config) {
892
926
  logger.log('debug', `Received intent-result`, JSON.stringify({ source, result }, null, 2));
893
927
  intentResolve(result);
894
928
  });
895
- const raiseOptions = intent
896
- ? { type: 'raise-intent', intent: intent.name, context: intent.context }
897
- : { type: 'raise-intent-for-context', context: context };
929
+ const raiseOptions = isIntent(input)
930
+ ? { type: 'raise-intent', intent: input.name, context: input.context }
931
+ : { type: 'raise-intent-for-context', context: input };
898
932
  await client.raiseIntent({ appId: targetApp, raiseOptions });
899
933
  // TODO: raise-intent timeout via promise.race?
900
934
  const intentResult = await intentResultPromise;
935
+ const publishLocalResult = async (result) => {
936
+ // NOTE: since we aren't changing getIntentResolution in the fdc3 impl code,
937
+ // we "fake" a local intent result to ensure getResult resolves correctly, see:
938
+ // js-adapter/src/api/interop/fdc3/utils.ts::getIntentResolution::fin.InterApplicationBus.subscribe
939
+ const intentResolutionResultId = input.metadata?.intentResolutionResultId;
940
+ // skip for web/external connections
941
+ if (!this.fin.me.isOpenFin) {
942
+ return;
943
+ }
944
+ if (intentResolutionResultId) {
945
+ this.fin.InterApplicationBus.publish(intentResolutionResultId, result).catch(() => {
946
+ logger.log('warn', `#handleFiredIntent could not create an intent resolution for AppId: ${targetApp}, getResult call will not work.`, intentResult);
947
+ });
948
+ }
949
+ };
901
950
  if ('error' in intentResult) {
902
951
  logger.log('warn', `#handleFiredIntent could not raise intent for AppId: ${targetApp}`);
952
+ // matching { error: Boolean } type of js-adapter/src/api/interop/fdc3/utils.ts::IntentResultPromisePayload
953
+ publishLocalResult({ error: true });
903
954
  // Presumably, the error is FDC3 compliant, so throw it as is
904
- // TODO: use the message key instead of the entire error string
905
955
  throw new Error(intentResult.error);
906
956
  }
907
957
  const source = typeof intentResult.source === 'string' ? { appId: intentResult.source } : intentResult.source;
958
+ const finalResult = { ...intentResult, source };
959
+ publishLocalResult(finalResult.getResult);
908
960
  return {
909
- intent: intentResult.intent,
910
- version: intentResult.version,
911
- source,
961
+ ...finalResult,
912
962
  // Currently only supporting contexts as results
913
- getResult: async () => intentResult.getResult
963
+ getResult: async () => finalResult.getResult
914
964
  };
915
965
  }
916
966
  async setContextForGroup({ context }, contextGroupId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openfin/cloud-interop",
3
- "version": "0.41.107",
3
+ "version": "0.42.0",
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": "41.100.105"
23
+ "@openfin/core": "42.100.1"
24
24
  },
25
25
  "dependencies": {
26
26
  "@openfin/cloud-interop-core-api": "0.0.1-alpha.a27677b"