@openfin/cloud-interop 0.41.107 → 0.42.0

Sign up to get free protection for your applications and to get access to all the features.
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"